Skip to content
This repository has been archived by the owner on Oct 1, 2024. It is now read-only.

Expose matcher operations #2697

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/graphql-testing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,9 @@ const graphQL = createGraphQL({

### Matchers

This library provides a [Jest matcher](https://jestjs.io/docs/en/using-matchers). To use this matcher, you’ll need to include `@shopify/graphql-testing/matchers` in your Jest setup file. The following matcher will then be available:
This library provides a [Jest matcher](https://jestjs.io/docs/en/using-matchers). To use this matcher, you’ll need to include `@shopify/graphql-testing/matchers-all` in your Jest setup file. The following matcher will then be available:

If you would like to import matchers without extending expect, then you can do so via `@shopify/react-testing/matchers`.

#### `toHavePerformedGraphQLOperation(operation: GraphQLOperation, variables?: object)`

Expand Down
18 changes: 15 additions & 3 deletions packages/graphql-testing/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
"typesVersions": {
"*": {
"matchers": [
"./build/ts/matchers/index.d.ts"
"./build/ts/matchers/types.d.ts"
],
"matchers-all": [
"./build/ts/matchers/types.d.ts"
]
}
},
Expand Down Expand Up @@ -47,17 +50,26 @@
"index.esnext",
"matchers.js",
"matchers.mjs",
"matchers.esnext"
"matchers.esnext",
"matchers-all.js",
"matchers-all.mjs",
"matchers-all.esnext"
],
"module": "index.mjs",
"esnext": "index.esnext",
"exports": {
"./matchers": {
"types": "./build/ts/matchers/index.d.ts",
"types": "./build/ts/matchers/types.d.ts",
"esnext": "./matchers.esnext",
"import": "./matchers.mjs",
"require": "./matchers.js"
},
"./matchers-all": {
"types": "./build/ts/matchers/types.d.ts",
"esnext": "./matchers-all.esnext",
"import": "./matchers-all.mjs",
"require": "./matchers-all.js"
},
".": {
"types": "./build/ts/index.d.ts",
"esnext": "./index.esnext",
Expand Down
7 changes: 6 additions & 1 deletion packages/graphql-testing/rollup.config.mjs
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import {buildConfig} from '../../config/rollup.mjs';

export default buildConfig(import.meta.url, {
entries: ['./src/index.ts', './src/matchers/index.ts'],
entries: [
'./src/index.ts',
'./src/matchers/index.ts',
'./src/matchers/all.ts',
],
entrypoints: {
index: './src/index.ts',
matchers: './src/matchers/index.ts',
'matchers-all': './src/matchers/all.ts',
},
});
5 changes: 5 additions & 0 deletions packages/graphql-testing/src/matchers/all.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import {toHavePerformedGraphQLOperation} from '.';

expect.extend({
toHavePerformedGraphQLOperation,
});
127 changes: 110 additions & 17 deletions packages/graphql-testing/src/matchers/index.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,112 @@
import type {GraphQLOperation} from 'graphql-typed';

import {toHavePerformedGraphQLOperation} from './operations';

declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace jest {
interface Matchers<R, T = {}> {
toHavePerformedGraphQLOperation<Variables>(
document: GraphQLOperation<any, Variables, any>,
variables?: Partial<Variables>,
): void;
}
}
import {
matcherHint,
printExpected,
EXPECTED_COLOR as expectedColor,
} from 'jest-matcher-utils';
import type {GraphQLOperation, DocumentNode} from 'graphql-typed';
import type {Operation} from '@apollo/client';

import type {GraphQL} from '../graphql-controller';
import {
operationNameFromDocument,
operationTypeFromDocument,
} from '../utilities';

import {assertIsGraphQL, diffVariablesForOperation} from './utilities';

export function toHavePerformedGraphQLOperation<Variables>(
this: jest.MatcherUtils,
graphQL: GraphQL,
document: GraphQLOperation<any, Variables, any>,
variables?: Variables,
) {
assertIsGraphQL(graphQL, {
expectation: 'toHavePerformedGraphQLOperation',
isNot: this.isNot,
});

const foundByOperation = graphQL.operations.all({
query: document as DocumentNode,
});

const foundByVariables =
variables == null
? foundByOperation
: foundByOperation.filter((operation) =>
Object.keys(variables).every((key) =>
this.equals(variables[key], operation.variables[key]),
),
);

const pass = foundByVariables.length > 0;

const type = operationTypeFromDocument(document as DocumentNode) || 'query';
const name = operationNameFromDocument(document as DocumentNode) || 'unnamed';

const message = pass
? () =>
`${matcherHint('.not.toHavePerformedGraphQLOperation')}\n\n` +
`Expected not to have performed GraphQL ${type}:\n ${expectedColor(
name,
)}\n${
variables
? `With variables matching:\n ${printExpected(variables)}\n`
: ''
}` +
`But ${foundByVariables.length} matching ${
foundByVariables.length === 1 ? 'operation was' : 'operations were'
} found.\n`
: () =>
`${
`${matcherHint('.toHavePerformedGraphQLOperation')}\n\n` +
`Expected to have performed GraphQL ${type}:\n ${expectedColor(
name,
)}\n${
variables
? `With props matching:\n ${printExpected(variables)}\n`
: ''
}`
}${
foundByVariables.length === 0
? `But no matching operations were found.\n`
: `But the ${
foundByVariables.length === 1
? 'found operation has'
: 'found operations have'
} the following variable differences:\n\n${diffs(
foundByVariables,
variables! as any,
this.expand,
)}`
}`;

return {pass, message};
}

function diffs(operations: Operation[], variables: object, expand?: boolean) {
return operations.reduce<string>(
(diffs, operation, index) =>
`${diffs}${index === 0 ? '' : '\n\n'}${normalizedDiff(
operation,
variables,
{
expand,
showLegend: index === 0,
},
)}`,
'',
);
}

expect.extend({
toHavePerformedGraphQLOperation,
});
function normalizedDiff(
operation: Operation,
variables: object,
{expand = false, showLegend = false},
) {
const result =
diffVariablesForOperation(operation, variables, {
expand,
}) || '';

return showLegend ? result : result.split('\n\n')[1];
}
112 changes: 0 additions & 112 deletions packages/graphql-testing/src/matchers/operations.ts

This file was deleted.

13 changes: 13 additions & 0 deletions packages/graphql-testing/src/matchers/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type {GraphQLOperation} from 'graphql-typed';

declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace jest {
interface Matchers<R, T = {}> {
toHavePerformedGraphQLOperation<Variables>(
document: GraphQLOperation<any, Variables, any>,
variables?: Partial<Variables>,
): void;
}
}
}
6 changes: 4 additions & 2 deletions packages/react-testing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,10 @@ describe('<ClickCounter />', () => {

### Matchers

This library ships with a few useful custom matchers for Jest. To include these matchers, import `@shopify/react-testing/matchers` in any file that is included as part of the `setupFilesAfterEnv` option passed to Jest.
This library ships with a few useful custom matchers for Jest. To include these matchers, import `@shopify/react-testing/matchers-all` in any file that is included as part of the `setupFilesAfterEnv` option passed to Jest.

```tsx
import '@shopify/react-testing/matchers';
import '@shopify/react-testing/matchers-all';
import {destroyAll} from '@shopify/react-testing';

afterEach(() => {
Expand All @@ -90,6 +90,8 @@ afterEach(() => {

This will allow you to use matchers such as [`toContainReactText`](#toContainReactText) or [`toContainReactComponent`](#toContainReactComponent) on your tree.

If you would like to import matchers without extending expect, then you can do so via `@shopify/react-testing/matchers`.

```tsx
import React from 'react';
import {mount} from '@shopify/react-testing';
Expand Down
18 changes: 15 additions & 3 deletions packages/react-testing/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
"typesVersions": {
"*": {
"matchers": [
"./build/ts/matchers/index.d.ts"
"./build/ts/matchers/types.d.ts"
],
"matchers-all": [
"./build/ts/matchers/types.d.ts"
]
}
},
Expand Down Expand Up @@ -44,7 +47,10 @@
"index.esnext",
"matchers.js",
"matchers.mjs",
"matchers.esnext"
"matchers.esnext",
"matchers-all.js",
"matchers-all.mjs",
"matchers-all.esnext"
],
"peerDependencies": {
"react": ">=16.8.0 <19.0.0",
Expand All @@ -54,11 +60,17 @@
"esnext": "index.esnext",
"exports": {
"./matchers": {
"types": "./build/ts/matchers/index.d.ts",
"types": "./build/ts/matchers/types.d.ts",
"esnext": "./matchers.esnext",
"import": "./matchers.mjs",
"require": "./matchers.js"
},
"./matchers-all": {
"types": "./build/ts/matchers/types.d.ts",
"esnext": "./matchers-all.esnext",
"import": "./matchers-all.mjs",
"require": "./matchers-all.js"
},
".": {
"types": "./build/ts/index.d.ts",
"esnext": "./index.esnext",
Expand Down
Loading
Loading