diff --git a/packages/keystone/src/fields/types/file/tests/test-fixtures.ts b/packages/keystone/src/fields/types/file/tests/test-fixtures.ts index a532e77f67a..6701d8030c9 100644 --- a/packages/keystone/src/fields/types/file/tests/test-fixtures.ts +++ b/packages/keystone/src/fields/types/file/tests/test-fixtures.ts @@ -3,7 +3,7 @@ import fs from 'fs-extra'; import { Upload } from 'graphql-upload'; import mime from 'mime'; import { file } from '..'; -import { expectResolverError } from '../../../../../../../tests/api-tests/utils'; +import { expectSingleResolverError } from '../../../../../../../tests/api-tests/utils'; const prepareFile = (_filePath: string) => { const filePath = path.resolve(`${__dirname}/../test-files/${_filePath}`); @@ -143,15 +143,7 @@ export const crudTests = (keystoneTestWrapper: any) => { }); expect(data).toEqual({ createTest: null }); const message = `Invalid file reference`; - expectResolverError('dev', false, false, errors, [ - { - path: ['createTest'], - messages: [`Test.secretFile: ${message}`], - debug: [ - { message, stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)) }, - ], - }, - ]); + expectSingleResolverError(errors, 'createTest', 'Test.secretFile', message); }) ); test( @@ -171,15 +163,7 @@ export const crudTests = (keystoneTestWrapper: any) => { }); expect(data).toEqual({ createTest: null }); const message = `Input error: Either ref or upload must be passed to FileFieldInput`; - expectResolverError('dev', false, false, errors, [ - { - path: ['createTest'], - messages: [`Test.secretFile: ${message}`], - debug: [ - { message, stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)) }, - ], - }, - ]); + expectSingleResolverError(errors, 'createTest', 'Test.secretFile', message); }) ); test( @@ -209,15 +193,7 @@ export const crudTests = (keystoneTestWrapper: any) => { }); expect(data).toEqual({ createTest: null }); const message = `Input error: Only one of ref and upload can be passed to FileFieldInput`; - expectResolverError('dev', false, false, errors, [ - { - path: ['createTest'], - messages: [`Test.secretFile: ${message}`], - debug: [ - { message, stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)) }, - ], - }, - ]); + expectSingleResolverError(errors, 'createTest', 'Test.secretFile', message); }) ); test( @@ -239,15 +215,7 @@ export const crudTests = (keystoneTestWrapper: any) => { }); expect(data).toEqual({ createTest: null }); const message = `Input error: Only one of ref and upload can be passed to FileFieldInput`; - expectResolverError('dev', false, false, errors, [ - { - path: ['createTest'], - messages: [`Test.secretFile: ${message}`], - debug: [ - { message, stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)) }, - ], - }, - ]); + expectSingleResolverError(errors, 'createTest', 'Test.secretFile', message); }) ); }); diff --git a/packages/keystone/src/fields/types/image/tests/test-fixtures.ts b/packages/keystone/src/fields/types/image/tests/test-fixtures.ts index 1cb07c31709..adbdaf5c3e9 100644 --- a/packages/keystone/src/fields/types/image/tests/test-fixtures.ts +++ b/packages/keystone/src/fields/types/image/tests/test-fixtures.ts @@ -4,7 +4,7 @@ import { Upload } from 'graphql-upload'; import mime from 'mime'; import { KeystoneContext } from '../../../../types'; import { image } from '..'; -import { expectResolverError } from '../../../../../../../tests/api-tests/utils'; +import { expectSingleResolverError } from '../../../../../../../tests/api-tests/utils'; const prepareFile = (_filePath: string) => { const filePath = path.resolve(`${__dirname}/../test-files/${_filePath}`); @@ -115,15 +115,7 @@ export const crudTests = (keystoneTestWrapper: any) => { }); expect(data).toEqual({ createTest: null }); const message = `File type not found`; - expectResolverError('dev', false, false, errors, [ - { - path: ['createTest'], - messages: [`Test.avatar: ${message}`], - debug: [ - { message, stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)) }, - ], - }, - ]); + expectSingleResolverError(errors, 'createTest', 'Test.avatar', message); }) ); }); @@ -189,15 +181,7 @@ export const crudTests = (keystoneTestWrapper: any) => { }); expect(data).toEqual({ createTest: null }); const message = `Invalid image reference`; - expectResolverError('dev', false, false, errors, [ - { - path: ['createTest'], - messages: [`Test.avatar: ${message}`], - debug: [ - { message, stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)) }, - ], - }, - ]); + expectSingleResolverError(errors, 'createTest', 'Test.avatar', message); }) ); test( @@ -217,15 +201,7 @@ export const crudTests = (keystoneTestWrapper: any) => { }); expect(data).toEqual({ createTest: null }); const message = `Input error: Either ref or upload must be passed to ImageFieldInput`; - expectResolverError('dev', false, false, errors, [ - { - path: ['createTest'], - messages: [`Test.avatar: ${message}`], - debug: [ - { message, stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)) }, - ], - }, - ]); + expectSingleResolverError(errors, 'createTest', 'Test.avatar', message); }) ); test( @@ -253,15 +229,7 @@ export const crudTests = (keystoneTestWrapper: any) => { }); expect(data).toEqual({ createTest: null }); const message = `Input error: Only one of ref and upload can be passed to ImageFieldInput`; - expectResolverError('dev', false, false, errors, [ - { - path: ['createTest'], - messages: [`Test.avatar: ${message}`], - debug: [ - { message, stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)) }, - ], - }, - ]); + expectSingleResolverError(errors, 'createTest', 'Test.avatar', message); }) ); test( @@ -283,15 +251,7 @@ export const crudTests = (keystoneTestWrapper: any) => { }); expect(data).toEqual({ createTest: null }); const message = `Input error: Only one of ref and upload can be passed to ImageFieldInput`; - expectResolverError('dev', false, false, errors, [ - { - path: ['createTest'], - messages: [`Test.avatar: ${message}`], - debug: [ - { message, stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)) }, - ], - }, - ]); + expectSingleResolverError(errors, 'createTest', 'Test.avatar', message); }) ); }); diff --git a/tests/api-tests/access-control/filter-coercion-and-validation.test.ts b/tests/api-tests/access-control/filter-coercion-and-validation.test.ts index 7ae251587ca..c72116ac848 100644 --- a/tests/api-tests/access-control/filter-coercion-and-validation.test.ts +++ b/tests/api-tests/access-control/filter-coercion-and-validation.test.ts @@ -1,7 +1,7 @@ import { text } from '@keystone-next/keystone/fields'; import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; -import { apiTestConfig } from '../utils'; +import { apiTestConfig, expectExtensionError } from '../utils'; const runner = setupTestRunner({ config: apiTestConfig({ @@ -35,20 +35,30 @@ const runner = setupTestRunner({ describe('Access control - Filter', () => { test( 'findMany - Bad function return value', - runner(async ({ graphQLRequest }) => { + runner(async ({ context }) => { // Valid name - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: `query { badAccesses { id } }`, }); // Returns null and throws an error - expect(body.data).toEqual({ badAccesses: null }); - expect(body.errors).toHaveLength(1); - expect(body.errors[0].path).toEqual(['badAccesses']); - expect(body.errors[0].message).toMatchInlineSnapshot(` -"An error occured while running \\"Access control\\". - - BadAccess.access.filter.query: Variable \\"$where\\" got invalid value \\"blah\\" at \\"where.name\\"; Expected type \\"StringFilter\\" to be an object." -`); + expect(data).toEqual({ badAccesses: null }); + const message = + 'Variable "$where" got invalid value "blah" at "where.name"; Expected type "StringFilter" to be an object.'; + expectExtensionError('dev', false, false, errors, 'Access control', [ + { + path: ['badAccesses'], + messages: [`BadAccess.access.filter.query: ${message}`], + debug: [ + { + message, + stacktrace: expect.stringMatching( + new RegExp(`GraphQLError: ${message.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}`) + ), + }, + ], + }, + ]); }) ); test( diff --git a/tests/api-tests/access-control/mutations-field.test.ts b/tests/api-tests/access-control/mutations-field.test.ts index c2baf2767fc..272d08f87ed 100644 --- a/tests/api-tests/access-control/mutations-field.test.ts +++ b/tests/api-tests/access-control/mutations-field.test.ts @@ -48,18 +48,18 @@ const runner = setupTestRunner({ describe('Access control', () => { test( 'findMany - Bad function return value', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { const item = await context .sudo() .query.User.createOne({ data: { name: 'foo', badAccess: 'bar' } }); - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: `query { users { id name badAccess } }`, }); // Returns the item, with null for the bad field, and an error message - expect(body.data).toEqual({ users: [{ id: item.id, name: 'foo', badAccess: null }] }); - expectAccessReturnError(body.errors, [ + expect(data).toEqual({ users: [{ id: item.id, name: 'foo', badAccess: null }] }); + expectAccessReturnError(errors, [ { path: ['users', 0, 'badAccess'], errors: [{ tag: 'User.badAccess.access.read', returned: 'string' }], @@ -97,19 +97,19 @@ describe('Access control', () => { test( 'createOne - Bad function return value', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { // Valid name should pass await context.query.User.createOne({ data: { name: 'good', other: 'a' } }); // Invalid name - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: `mutation ($data: UserCreateInput!) { createUser(data: $data) { id } }`, variables: { data: { name: 'fine', other: 'b', badAccess: 'bar' } }, }); // Returns null and throws an error - expect(body.data).toEqual({ createUser: null }); - expectAccessReturnError(body.errors, [ + expect(data).toEqual({ createUser: null }); + expectAccessReturnError(errors, [ { path: ['createUser'], errors: [{ tag: 'User.badAccess.access.create', returned: 'string' }], @@ -157,7 +157,7 @@ describe('Access control', () => { test( 'updateOne - Bad function return value', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { // Valid name should pass const user = await context.query.User.createOne({ data: { name: 'good', other: 'a' } }); await context.query.User.updateOne({ @@ -166,14 +166,14 @@ describe('Access control', () => { }); // Invalid name - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: `mutation ($id: ID! $data: UserUpdateInput!) { updateUser(where: { id: $id }, data: $data) { id } }`, variables: { id: user.id, data: { name: 'bad', other: 'c', badAccess: 'bar' } }, }); // Returns null and throws an error - expect(body.data).toEqual({ updateUser: null }); - expectAccessReturnError(body.errors, [ + expect(data).toEqual({ updateUser: null }); + expectAccessReturnError(errors, [ { path: ['updateUser'], errors: [{ tag: 'User.badAccess.access.update', returned: 'string' }], diff --git a/tests/api-tests/access-control/mutations-list-item.test.ts b/tests/api-tests/access-control/mutations-list-item.test.ts index 1e2b82689ba..e012c5630ca 100644 --- a/tests/api-tests/access-control/mutations-list-item.test.ts +++ b/tests/api-tests/access-control/mutations-list-item.test.ts @@ -76,16 +76,16 @@ describe('Access control - Item', () => { test( 'createOne - Bad function return value', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { // Valid name - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: `mutation ($data: BadAccessCreateInput!) { createBadAccess(data: $data) { id } }`, variables: { data: { name: 'better' } }, }); // Returns null and throws an error - expect(body.data).toEqual({ createBadAccess: null }); - expectAccessReturnError(body.errors, [ + expect(data).toEqual({ createBadAccess: null }); + expectAccessReturnError(errors, [ { path: ['createBadAccess'], errors: [{ tag: 'BadAccess.access.item.create', returned: 'object' }], @@ -128,18 +128,18 @@ describe('Access control - Item', () => { test( 'updateOne - Bad function return value', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { const item = await context.sudo().query.BadAccess.createOne({ data: { name: 'good' } }); // Valid name - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: `mutation ($id: ID! $data: BadAccessUpdateInput!) { updateBadAccess(where: { id: $id }, data: $data) { id } }`, variables: { id: item.id, data: { name: 'better' } }, }); // Returns null and throws an error - expect(body.data).toEqual({ updateBadAccess: null }); - expectAccessReturnError(body.errors, [ + expect(data).toEqual({ updateBadAccess: null }); + expectAccessReturnError(errors, [ { path: ['updateBadAccess'], errors: [{ tag: 'BadAccess.access.item.update', returned: 'object' }], @@ -183,18 +183,18 @@ describe('Access control - Item', () => { test( 'deleteOne - Bad function return value', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { const item = await context.sudo().query.BadAccess.createOne({ data: { name: 'good' } }); // Valid name - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: `mutation ($id: ID!) { deleteBadAccess(where: { id: $id }) { id } }`, variables: { id: item.id }, }); // Returns null and throws an error - expect(body.data).toEqual({ deleteBadAccess: null }); - expectAccessReturnError(body.errors, [ + expect(data).toEqual({ deleteBadAccess: null }); + expectAccessReturnError(errors, [ { path: ['deleteBadAccess'], errors: [{ tag: 'BadAccess.access.item.delete', returned: 'object' }], diff --git a/tests/api-tests/access-control/mutations-list-operation.test.ts b/tests/api-tests/access-control/mutations-list-operation.test.ts index f99273d7932..a2bc27fcda0 100644 --- a/tests/api-tests/access-control/mutations-list-operation.test.ts +++ b/tests/api-tests/access-control/mutations-list-operation.test.ts @@ -36,15 +36,15 @@ const runner = setupTestRunner({ describe('Access control - Item', () => { test( 'findMany - Bad function return value', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { // Valid name - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: `query { badAccesses { id } }`, }); // Returns null and throws an error - expect(body.data).toEqual({ badAccesses: null }); - expectAccessReturnError(body.errors, [ + expect(data).toEqual({ badAccesses: null }); + expectAccessReturnError(errors, [ { path: ['badAccesses'], errors: [{ tag: 'BadAccess.access.operation.query', returned: 'object' }], @@ -59,16 +59,16 @@ describe('Access control - Item', () => { test( 'createOne - Bad function return value', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { // Valid name - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: `mutation ($data: BadAccessCreateInput!) { createBadAccess(data: $data) { id } }`, variables: { data: { name: 'better' } }, }); // Returns null and throws an error - expect(body.data).toEqual({ createBadAccess: null }); - expectAccessReturnError(body.errors, [ + expect(data).toEqual({ createBadAccess: null }); + expectAccessReturnError(errors, [ { path: ['createBadAccess'], errors: [{ tag: 'BadAccess.access.operation.create', returned: 'object' }], @@ -83,18 +83,18 @@ describe('Access control - Item', () => { test( 'updateOne - Bad function return value', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { const item = await context.sudo().query.BadAccess.createOne({ data: { name: 'good' } }); // Valid name - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: `mutation ($id: ID! $data: BadAccessUpdateInput!) { updateBadAccess(where: { id: $id }, data: $data) { id } }`, variables: { id: item.id, data: { name: 'better' } }, }); // Returns null and throws an error - expect(body.data).toEqual({ updateBadAccess: null }); - expectAccessReturnError(body.errors, [ + expect(data).toEqual({ updateBadAccess: null }); + expectAccessReturnError(errors, [ { path: ['updateBadAccess'], errors: [{ tag: 'BadAccess.access.operation.update', returned: 'object' }], @@ -109,18 +109,18 @@ describe('Access control - Item', () => { test( 'deleteOne - Bad function return value', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { const item = await context.sudo().query.BadAccess.createOne({ data: { name: 'good' } }); // Valid name - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: `mutation ($id: ID!) { deleteBadAccess(where: { id: $id }) { id } }`, variables: { id: item.id }, }); // Returns null and throws an error - expect(body.data).toEqual({ deleteBadAccess: null }); - expectAccessReturnError(body.errors, [ + expect(data).toEqual({ deleteBadAccess: null }); + expectAccessReturnError(errors, [ { path: ['deleteBadAccess'], errors: [{ tag: 'BadAccess.access.operation.delete', returned: 'object' }], diff --git a/tests/api-tests/fields/crud.test.ts b/tests/api-tests/fields/crud.test.ts index 67b41aee908..c21f63b642c 100644 --- a/tests/api-tests/fields/crud.test.ts +++ b/tests/api-tests/fields/crud.test.ts @@ -4,7 +4,7 @@ import { text } from '@keystone-next/keystone/fields'; import { KeystoneContext } from '@keystone-next/keystone/types'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { humanize } from '@keystone-next/keystone/src/lib/utils'; -import { apiTestConfig, expectResolverError, expectValidationError } from '../utils'; +import { apiTestConfig, expectSingleResolverError, expectValidationError } from '../utils'; const testModules = globby.sync(`packages/**/src/**/test-fixtures.{js,ts}`, { absolute: true, @@ -201,20 +201,12 @@ testModules expect(data).toEqual({ [updateMutationName]: null }); if (mod.neverNull) { const message = `Input error: ${mod.name} fields cannot be set to null`; - expectResolverError('dev', false, false, errors, [ - { - path: [updateMutationName], - messages: [`Test.${fieldName}: ${message}`], - debug: [ - { - message, - stacktrace: expect.stringMatching( - new RegExp(`Error: ${message}\n`) - ), - }, - ], - }, - ]); + expectSingleResolverError( + errors, + updateMutationName, + `Test.${fieldName}`, + message + ); } else { expectValidationError(errors, [ { diff --git a/tests/api-tests/fields/unique.test.ts b/tests/api-tests/fields/unique.test.ts index 4a2972fa1c5..808f4c55f92 100644 --- a/tests/api-tests/fields/unique.test.ts +++ b/tests/api-tests/fields/unique.test.ts @@ -56,12 +56,12 @@ testModules }); test( 'uniqueness is enforced over multiple mutations', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { await context.query.Test.createOne({ data: { testField: mod.exampleValue(matrixValue) }, }); - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: ` mutation($data: TestCreateInput!) { createTest(data: $data) { id } @@ -69,8 +69,8 @@ testModules `, variables: { data: { testField: mod.exampleValue(matrixValue) } }, }); - expect(body.data).toEqual({ createTest: null }); - expectPrismaError(body.errors, [ + expect(data).toEqual({ createTest: null }); + expectPrismaError(errors, [ { path: ['createTest'], message: expect.stringMatching( @@ -85,8 +85,8 @@ testModules test( 'uniqueness is enforced over single mutation', - runner(async ({ graphQLRequest }) => { - const { body } = await graphQLRequest({ + runner(async ({ context }) => { + const { data, errors } = await context.graphql.raw({ query: ` mutation($fooData: TestCreateInput!, $barData: TestCreateInput!) { foo: createTest(data: $fooData) { id } @@ -99,8 +99,8 @@ testModules }, }); - expect(body.data).toEqual({ foo: { id: expect.any(String) }, bar: null }); - expectPrismaError(body.errors, [ + expect(data).toEqual({ foo: { id: expect.any(String) }, bar: null }); + expectPrismaError(errors, [ { path: ['bar'], message: expect.stringMatching( diff --git a/tests/api-tests/id-field.test.ts b/tests/api-tests/id-field.test.ts index 62dcb434ed0..df8413bd6fa 100644 --- a/tests/api-tests/id-field.test.ts +++ b/tests/api-tests/id-field.test.ts @@ -20,36 +20,38 @@ describe.each(['autoincrement', 'cuid', 'uuid'] as const)('%s', kind => { }); test( 'Fetching an item uniquely with an invalid id throws an error', - runner(async ({ graphQLRequest }) => { - const { body } = await graphQLRequest({ + runner(async ({ context }) => { + const { data, errors } = await context.graphql.raw({ query: `{ user(where: { id: "adskjnfasdfkjekfj"}) { id } }`, }); - expect(body.data).toEqual({ user: null }); + expect(data).toEqual({ user: null }); const s = kind === 'autoincrement' ? 'an integer' : `a ${kind}`; - expectBadUserInput(body.errors, [ + expectBadUserInput(errors, [ { path: ['user'], message: `Only ${s} can be passed to id filters` }, ]); }) ); test( 'Filtering an item with an invalid id throws an error', - runner(async ({ graphQLRequest }) => { - const { body } = await graphQLRequest({ + runner(async ({ context }) => { + const { data, errors } = await context.graphql.raw({ query: `{ users(where: { id: { equals: "adskjnfasdfkjekfj" } }) { id } }`, }); - expect(body.data).toEqual({ users: null }); + expect(data).toEqual({ users: null }); const s = kind === 'autoincrement' ? 'an integer' : `a ${kind}`; - expectBadUserInput(body.errors, [ + expectBadUserInput(errors, [ { path: ['users'], message: `Only ${s} can be passed to id filters` }, ]); }) ); test( 'Fetching an item uniquely with a null id throws an error', - runner(async ({ graphQLRequest }) => { - const { body } = await graphQLRequest({ query: `{ user(where: { id: null}) { id } }` }); - expect(body.data).toEqual({ user: null }); - expectBadUserInput(body.errors, [ + runner(async ({ context }) => { + const { data, errors } = await context.graphql.raw({ + query: `{ user(where: { id: null}) { id } }`, + }); + expect(data).toEqual({ user: null }); + expectBadUserInput(errors, [ { path: ['user'], message: `The unique value provided in a unique where input must not be null`, @@ -59,47 +61,45 @@ describe.each(['autoincrement', 'cuid', 'uuid'] as const)('%s', kind => { ); test( 'Filtering an item with a null id throws an error', - runner(async ({ graphQLRequest }) => { - const { body } = await graphQLRequest({ query: `{ users(where: { id: null }) { id } }` }); - expect(body.data).toEqual({ users: null }); - expectBadUserInput(body.errors, [{ path: ['users'], message: `id filter cannot be null` }]); + runner(async ({ context }) => { + const { data, errors } = await context.graphql.raw({ + query: `{ users(where: { id: null }) { id } }`, + }); + expect(data).toEqual({ users: null }); + expectBadUserInput(errors, [{ path: ['users'], message: `id filter cannot be null` }]); }) ); test( 'Filtering an item with { equals: null } throws an error', - runner(async ({ graphQLRequest }) => { - const { body } = await graphQLRequest({ + runner(async ({ context }) => { + const { data, errors } = await context.graphql.raw({ query: `{ users(where: { id: { equals: null } }) { id } }`, }); - expect(body.data).toEqual({ users: null }); + expect(data).toEqual({ users: null }); const s = kind === 'autoincrement' ? 'an integer' : `a ${kind}`; - expectBadUserInput(body.errors, [ + expectBadUserInput(errors, [ { path: ['users'], message: `Only ${s} can be passed to id filters` }, ]); }) ); test( 'Filtering an item with a in: null throws an error', - runner(async ({ graphQLRequest }) => { - const { body } = await graphQLRequest({ + runner(async ({ context }) => { + const { data, errors } = await context.graphql.raw({ query: `{ users(where: { id: { in: null } }) { id } }`, }); - expect(body.data).toEqual({ users: null }); - expectBadUserInput(body.errors, [ - { path: ['users'], message: `in id filter cannot be null` }, - ]); + expect(data).toEqual({ users: null }); + expectBadUserInput(errors, [{ path: ['users'], message: `in id filter cannot be null` }]); }) ); test( 'Filtering an item with a notIn: null throws an error', - runner(async ({ graphQLRequest }) => { - const { body } = await graphQLRequest({ + runner(async ({ context }) => { + const { data, errors } = await context.graphql.raw({ query: `{ users(where: { id: { notIn: null } }) { id } }`, }); - expect(body.data).toEqual({ users: null }); - expectBadUserInput(body.errors, [ - { path: ['users'], message: `notIn id filter cannot be null` }, - ]); + expect(data).toEqual({ users: null }); + expectBadUserInput(errors, [{ path: ['users'], message: `notIn id filter cannot be null` }]); }) ); test( @@ -162,17 +162,17 @@ describe.each(['autoincrement', 'cuid', 'uuid'] as const)('%s', kind => { }); test( 'searching for uppercased cuid does not work', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { const { id } = (await context.query.User.createOne({ data: { name: 'something' }, })) as { id: string }; - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: `query q($id: ID!){ user(where: { id: $id }) { id } }`, variables: { id: id.toUpperCase() }, }); - expect(body.data).toEqual({ user: null }); - expectBadUserInput(body.errors, [ + expect(data).toEqual({ user: null }); + expectBadUserInput(errors, [ { path: ['user'], message: `Only a cuid can be passed to id filters` }, ]); }) diff --git a/tests/api-tests/queries/filters.test.ts b/tests/api-tests/queries/filters.test.ts index 2f7c5e5481f..deda69c50ce 100644 --- a/tests/api-tests/queries/filters.test.ts +++ b/tests/api-tests/queries/filters.test.ts @@ -142,13 +142,13 @@ describe('filtering on field name', () => { describe('filtering on relationships', () => { test( 'findMany throws error with null relationship query', - runner(async ({ graphQLRequest }) => { - const { body } = await graphQLRequest({ + runner(async ({ context }) => { + const { data, errors } = await context.graphql.raw({ query: '{ secondaryLists(where: { otherUsers: null }) { id } }', }); // Returns null and throws an error - expect(body.data).toEqual({ secondaryLists: null }); - expectBadUserInput(body.errors, [ + expect(data).toEqual({ secondaryLists: null }); + expectBadUserInput(errors, [ { message: 'A many relation filter cannot be set to null', path: ['secondaryLists'], @@ -159,13 +159,13 @@ describe('filtering on relationships', () => { test( 'findMany throws error with null relationship query value', - runner(async ({ graphQLRequest }) => { - const { body } = await graphQLRequest({ + runner(async ({ context }) => { + const { data, errors } = await context.graphql.raw({ query: '{ secondaryLists(where: { otherUsers: { some: null } }) { id } }', }); // Returns null and throws an error - expect(body.data).toEqual({ secondaryLists: null }); - expectBadUserInput(body.errors, [ + expect(data).toEqual({ secondaryLists: null }); + expectBadUserInput(errors, [ { message: 'The key "some" in a many relation filter cannot be set to null', path: ['secondaryLists'], @@ -176,17 +176,17 @@ describe('filtering on relationships', () => { test( 'findMany returns all items with empty relationship query value', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { await context.query.SecondaryList.createOne({ data: { otherUsers: { create: [{ noDash: 'a' }, { noDash: 'b' }] } }, }); - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: '{ secondaryLists(where: { otherUsers: {} }) { otherUsers(orderBy: { noDash: asc }) { noDash } } }', }); // Returns all the data - expect(body.errors).toBe(undefined); - expect(body.data).toEqual({ + expect(errors).toBe(undefined); + expect(data).toEqual({ secondaryLists: [{ otherUsers: [{ noDash: 'a' }, { noDash: 'b' }] }], }); }) @@ -208,11 +208,13 @@ describe('searching by unique fields', () => { test( 'findOne throws error with zero where values', - runner(async ({ graphQLRequest }) => { - const { body } = await graphQLRequest({ query: '{ user(where: {}) { id email } }' }); + runner(async ({ context }) => { + const { data, errors } = await context.graphql.raw({ + query: '{ user(where: {}) { id email } }', + }); // Returns null and throws an error - expect(body.data).toEqual({ user: null }); - expectBadUserInput(body.errors, [ + expect(data).toEqual({ user: null }); + expectBadUserInput(errors, [ { message: 'Exactly one key must be passed in a unique where input but 0 keys were passed', path: ['user'], @@ -223,14 +225,14 @@ describe('searching by unique fields', () => { test( 'findOne throws error with more than one where values', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { const item = await context.query.User.createOne({ data: { email: 'test@example.com' } }); - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: `{ user(where: { id: "${item.id}" email: "test@example.com" }) { id email } }`, }); // Returns null and throws an error - expect(body.data).toEqual({ user: null }); - expectBadUserInput(body.errors, [ + expect(data).toEqual({ user: null }); + expectBadUserInput(errors, [ { message: 'Exactly one key must be passed in a unique where input but 2 keys were passed', path: ['user'], @@ -241,13 +243,13 @@ describe('searching by unique fields', () => { test( 'findOne throws error with null where values', - runner(async ({ graphQLRequest }) => { - const { body } = await graphQLRequest({ + runner(async ({ context }) => { + const { data, errors } = await context.graphql.raw({ query: '{ user(where: { email: null }) { id email } }', }); // Returns null and throws an error - expect(body.data).toEqual({ user: null }); - expectBadUserInput(body.errors, [ + expect(data).toEqual({ user: null }); + expectBadUserInput(errors, [ { message: 'The unique value provided in a unique where input must not be null', path: ['user'], @@ -275,23 +277,23 @@ describe('isFilterable', () => { test( 'isFilterable: true', - runner(async ({ graphQLRequest }) => { - const { body } = await graphQLRequest({ + runner(async ({ context }) => { + const { data, errors } = await context.graphql.raw({ query: '{ users(where: { filterTrue: { equals: 10 } }) { id } }', }); - expect(body.data.users).toHaveLength(0); - expect(body.errors).toBe(undefined); + expect(data).toEqual({ users: [] }); + expect(errors).toBe(undefined); }) ); test( 'isFilterable: () => false', - runner(async ({ graphQLRequest }) => { - const { body } = await graphQLRequest({ + runner(async ({ context }) => { + const { data, errors } = await context.graphql.raw({ query: '{ users(where: { filterFunctionFalse: { equals: 10 } }) { id } }', }); - expect(body.data).toEqual({ users: null }); - expectFilterDenied(body.errors, [ + expect(data).toEqual({ users: null }); + expectFilterDenied(errors, [ { path: ['users'], message: @@ -303,23 +305,23 @@ describe('isFilterable', () => { test( 'isFilterable: () => true', - runner(async ({ graphQLRequest }) => { - const { body } = await graphQLRequest({ + runner(async ({ context }) => { + const { data, errors } = await context.graphql.raw({ query: '{ users(where: { filterFunctionTrue: { equals: 10 } }) { id } }', }); - expect(body.data.users).toHaveLength(0); - expect(body.errors).toBe(undefined); + expect(data).toEqual({ users: [] }); + expect(errors).toBe(undefined); }) ); test( 'isFilterable: () => null', - runner(async ({ graphQLRequest }) => { - const { body } = await graphQLRequest({ + runner(async ({ context }) => { + const { data, errors } = await context.graphql.raw({ query: '{ users(where: { filterFunctionOtherFalsey: { equals: 10 } }) { id } }', }); - expect(body.data).toEqual({ users: null }); - expectAccessReturnError(body.errors, [ + expect(data).toEqual({ users: null }); + expectAccessReturnError(errors, [ { path: ['users'], errors: [{ tag: 'User.filterFunctionOtherFalsey.isFilterable', returned: 'object' }], @@ -330,12 +332,12 @@ describe('isFilterable', () => { test( 'isFilterable: () => ({})', - runner(async ({ graphQLRequest }) => { - const { body } = await graphQLRequest({ + runner(async ({ context }) => { + const { data, errors } = await context.graphql.raw({ query: '{ users(where: { filterFunctionOtherTruthy: { equals: 10 } }) { id } }', }); - expect(body.data).toEqual({ users: null }); - expectAccessReturnError(body.errors, [ + expect(data).toEqual({ users: null }); + expectAccessReturnError(errors, [ { path: ['users'], errors: [{ tag: 'User.filterFunctionOtherTruthy.isFilterable', returned: 'object' }], @@ -346,8 +348,8 @@ describe('isFilterable', () => { test( 'isFilterable: multiple () => false', - runner(async ({ graphQLRequest }) => { - const { body } = await graphQLRequest({ + runner(async ({ context }) => { + const { data, errors } = await context.graphql.raw({ query: `{ secondaryLists(where: { OR: [ { filterFunctionFalse: { gt: 10 } } @@ -356,8 +358,8 @@ describe('isFilterable', () => { ] } ) { id } }`, }); - expect(body.data).toEqual({ secondaryLists: null }); - expectFilterDenied(body.errors, [ + expect(data).toEqual({ secondaryLists: null }); + expectFilterDenied(errors, [ { path: ['secondaryLists'], message: @@ -371,12 +373,12 @@ describe('isFilterable', () => { describe('defaultIsFilterable', () => { test( 'defaultIsFilterable: undefined', - runner(async ({ graphQLRequest }) => { - const { body } = await graphQLRequest({ + runner(async ({ context }) => { + const { data, errors } = await context.graphql.raw({ query: '{ defaultFilterUndefineds(where: { a: { equals: 10 } }) { id } }', }); - expect(body.data.defaultFilterUndefineds).toHaveLength(0); - expect(body.errors).toBe(undefined); + expect(data).toEqual({ defaultFilterUndefineds: [] }); + expect(errors).toBe(undefined); }) ); @@ -397,23 +399,23 @@ describe('defaultIsFilterable', () => { test( 'defaultIsFilterable: true', - runner(async ({ graphQLRequest }) => { - const { body } = await graphQLRequest({ + runner(async ({ context }) => { + const { data, errors } = await context.graphql.raw({ query: '{ defaultFilterTrues(where: { a: { equals: 10 } }) { id } }', }); - expect(body.data.defaultFilterTrues).toHaveLength(0); - expect(body.errors).toBe(undefined); + expect(data).toEqual({ defaultFilterTrues: [] }); + expect(errors).toBe(undefined); }) ); test( 'defaultIsFilterable: () => false', - runner(async ({ graphQLRequest }) => { - const { body } = await graphQLRequest({ + runner(async ({ context }) => { + const { data, errors } = await context.graphql.raw({ query: '{ defaultFilterFunctionFalses(where: { a: { equals: 10 } }) { id } }', }); - expect(body.data).toEqual({ defaultFilterFunctionFalses: null }); - expectFilterDenied(body.errors, [ + expect(data).toEqual({ defaultFilterFunctionFalses: null }); + expectFilterDenied(errors, [ { path: ['defaultFilterFunctionFalses'], message: @@ -425,24 +427,24 @@ describe('defaultIsFilterable', () => { test( 'defaultIsFilterable: () => true', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { await initialiseData({ context }); - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: '{ defaultFilterFunctionTrues(where: { a: { equals: 10 } }) { id } }', }); - expect(body.data.defaultFilterFunctionTrues).toHaveLength(0); - expect(body.errors).toBe(undefined); + expect(data).toEqual({ defaultFilterFunctionTrues: [] }); + expect(errors).toBe(undefined); }) ); test( 'defaultIsFilterable: () => null', - runner(async ({ graphQLRequest }) => { - const { body } = await graphQLRequest({ + runner(async ({ context }) => { + const { data, errors } = await context.graphql.raw({ query: '{ defaultFilterFunctionFalseys(where: { a: { equals: 10 } }) { id } }', }); - expect(body.data).toEqual({ defaultFilterFunctionFalseys: null }); - expectAccessReturnError(body.errors, [ + expect(data).toEqual({ defaultFilterFunctionFalseys: null }); + expectAccessReturnError(errors, [ { path: ['defaultFilterFunctionFalseys'], errors: [{ tag: 'DefaultFilterFunctionFalsey.a.isFilterable', returned: 'object' }], @@ -453,12 +455,12 @@ describe('defaultIsFilterable', () => { test( 'defaultIsFilterable: () => ({})', - runner(async ({ graphQLRequest }) => { - const { body } = await graphQLRequest({ + runner(async ({ context }) => { + const { data, errors } = await context.graphql.raw({ query: '{ defaultFilterFunctionTruthies(where: { a: { equals: 10 } }) { id } }', }); - expect(body.data).toEqual({ defaultFilterFunctionTruthies: null }); - expectAccessReturnError(body.errors, [ + expect(data).toEqual({ defaultFilterFunctionTruthies: null }); + expectAccessReturnError(errors, [ { path: ['defaultFilterFunctionTruthies'], errors: [{ tag: 'DefaultFilterFunctionTruthy.a.isFilterable', returned: 'object' }], diff --git a/tests/api-tests/queries/orderBy.test.ts b/tests/api-tests/queries/orderBy.test.ts index c64916c7c26..b4cd7d5a876 100644 --- a/tests/api-tests/queries/orderBy.test.ts +++ b/tests/api-tests/queries/orderBy.test.ts @@ -298,14 +298,14 @@ describe('Ordering by Multiple', () => { test( 'Multi filter, multiple keys throws error ', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { await initialiseData({ context }); - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: 'query { users(orderBy: [{ a: asc, b: asc }]) { id } }', }); - expect(body.data).toEqual({ users: null }); - expectBadUserInput(body.errors, [ + expect(data).toEqual({ users: null }); + expectBadUserInput(errors, [ { path: ['users'], message: 'Only a single key must be passed to UserOrderByInput' }, ]); }) @@ -313,14 +313,14 @@ describe('Ordering by Multiple', () => { test( 'Multi filter, zero keys throws error ', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { await initialiseData({ context }); - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: 'query { users(orderBy: [{}]) { id } }', }); - expect(body.data).toEqual({ users: null }); - expectBadUserInput(body.errors, [ + expect(data).toEqual({ users: null }); + expectBadUserInput(errors, [ { path: ['users'], message: 'Only a single key must be passed to UserOrderByInput' }, ]); }) @@ -328,14 +328,14 @@ describe('Ordering by Multiple', () => { test( 'Multi filter, null values throws error ', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { await initialiseData({ context }); - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: 'query { users(orderBy: [{ a: null }]) { id } }', }); - expect(body.data).toEqual({ users: null }); - expectBadUserInput(body.errors, [ + expect(data).toEqual({ users: null }); + expectBadUserInput(errors, [ { path: ['users'], message: 'null cannot be passed as an order direction' }, ]); }) @@ -361,25 +361,25 @@ describe('isOrderable', () => { test( 'isOrderable: true', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { await initialiseData({ context }); - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: '{ users(orderBy: [{orderTrue: asc}]) { id } }', }); - expect(body.data.users).toHaveLength(9); - expect(body.errors).toBe(undefined); + expect(data!.users).toHaveLength(9); + expect(errors).toBe(undefined); }) ); test( 'isOrderable: () => false', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { await initialiseData({ context }); - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: '{ users(orderBy: [{orderFunctionFalse: asc}]) { id } }', }); - expect(body.data).toEqual({ users: null }); - expectFilterDenied(body.errors, [ + expect(data).toEqual({ users: null }); + expectFilterDenied(errors, [ { path: ['users'], message: @@ -391,25 +391,25 @@ describe('isOrderable', () => { test( 'isOrderable: () => true', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { await initialiseData({ context }); - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: '{ users(orderBy: [{orderFunctionTrue: asc}]) { id } }', }); - expect(body.data.users).toHaveLength(9); - expect(body.errors).toBe(undefined); + expect(data!.users).toHaveLength(9); + expect(errors).toBe(undefined); }) ); test( 'isOrderable: () => null', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { await initialiseData({ context }); - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: '{ users(orderBy: [{orderFunctionOtherFalsey: asc}]) { id } }', }); - expect(body.data).toEqual({ users: null }); - expectAccessReturnError(body.errors, [ + expect(data).toEqual({ users: null }); + expectAccessReturnError(errors, [ { path: ['users'], errors: [{ tag: 'User.orderFunctionOtherFalsey.isOrderable', returned: 'object' }], @@ -420,13 +420,13 @@ describe('isOrderable', () => { test( 'isOrderable: () => ({})', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { await initialiseData({ context }); - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: '{ users(orderBy: [{orderFunctionOtherTruthy: asc}]) { id } }', }); - expect(body.data).toEqual({ users: null }); - expectAccessReturnError(body.errors, [ + expect(data).toEqual({ users: null }); + expectAccessReturnError(errors, [ { path: ['users'], errors: [{ tag: 'User.orderFunctionOtherTruthy.isOrderable', returned: 'object' }], @@ -437,14 +437,14 @@ describe('isOrderable', () => { test( 'isOrderable: multiple () => false', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { await initialiseData({ context }); - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: '{ users(orderBy: [{orderFunctionTrue: asc}, {orderFunctionFalse: asc}, {orderFunctionFalseToo: asc}]) { id } }', }); - expect(body.data).toEqual({ users: null }); - expectFilterDenied(body.errors, [ + expect(data).toEqual({ users: null }); + expectFilterDenied(errors, [ { path: ['users'], message: @@ -458,13 +458,13 @@ describe('isOrderable', () => { describe('defaultIsOrderable', () => { test( 'defaultIsOrderable: undefined', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { await initialiseData({ context }); - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: '{ defaultOrderUndefineds(orderBy: [{a: asc}]) { id } }', }); - expect(body.data.defaultOrderUndefineds).toHaveLength(9); - expect(body.errors).toBe(undefined); + expect(data!.defaultOrderUndefineds).toHaveLength(9); + expect(errors).toBe(undefined); }) ); @@ -486,25 +486,25 @@ describe('defaultIsOrderable', () => { test( 'defaultIsOrderable: true', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { await initialiseData({ context }); - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: '{ defaultOrderTrues(orderBy: [{a: asc}]) { id } }', }); - expect(body.data.defaultOrderTrues).toHaveLength(9); - expect(body.errors).toBe(undefined); + expect(data!.defaultOrderTrues).toHaveLength(9); + expect(errors).toBe(undefined); }) ); test( 'defaultIsOrderable: () => false', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { await initialiseData({ context }); - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: '{ defaultOrderFunctionFalses(orderBy: [{a: asc}]) { id } }', }); - expect(body.data).toEqual({ defaultOrderFunctionFalses: null }); - expectFilterDenied(body.errors, [ + expect(data).toEqual({ defaultOrderFunctionFalses: null }); + expectFilterDenied(errors, [ { path: ['defaultOrderFunctionFalses'], message: @@ -516,25 +516,25 @@ describe('defaultIsOrderable', () => { test( 'defaultIsOrderable: () => true', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { await initialiseData({ context }); - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: '{ defaultOrderFunctionTrues(orderBy: [{a: asc}]) { id } }', }); - expect(body.data.defaultOrderFunctionTrues).toHaveLength(9); - expect(body.errors).toBe(undefined); + expect(data!.defaultOrderFunctionTrues).toHaveLength(9); + expect(errors).toBe(undefined); }) ); test( 'defaultIsOrderable: () => null', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { await initialiseData({ context }); - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: '{ defaultOrderFunctionFalseys(orderBy: [{a: asc}]) { id } }', }); - expect(body.data).toEqual({ defaultOrderFunctionFalseys: null }); - expectAccessReturnError(body.errors, [ + expect(data).toEqual({ defaultOrderFunctionFalseys: null }); + expectAccessReturnError(errors, [ { path: ['defaultOrderFunctionFalseys'], errors: [{ tag: 'DefaultOrderFunctionFalsey.a.isOrderable', returned: 'object' }], @@ -545,13 +545,13 @@ describe('defaultIsOrderable', () => { test( 'defaultIsOrderable: () => ({})', - runner(async ({ context, graphQLRequest }) => { + runner(async ({ context }) => { await initialiseData({ context }); - const { body } = await graphQLRequest({ + const { data, errors } = await context.graphql.raw({ query: '{ defaultOrderFunctionTruthies(orderBy: [{a: asc}]) { id } }', }); - expect(body.data).toEqual({ defaultOrderFunctionTruthies: null }); - expectAccessReturnError(body.errors, [ + expect(data).toEqual({ defaultOrderFunctionTruthies: null }); + expectAccessReturnError(errors, [ { path: ['defaultOrderFunctionTruthies'], errors: [{ tag: 'DefaultOrderFunctionTruthy.a.isOrderable', returned: 'object' }], diff --git a/tests/api-tests/relationships/nested-mutations/connect-many.test.ts b/tests/api-tests/relationships/nested-mutations/connect-many.test.ts index e2501b07ad6..a70c2937c39 100644 --- a/tests/api-tests/relationships/nested-mutations/connect-many.test.ts +++ b/tests/api-tests/relationships/nested-mutations/connect-many.test.ts @@ -2,7 +2,7 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; -import { apiTestConfig, expectRelationshipError } from '../../utils'; +import { apiTestConfig, expectSingleRelationshipError } from '../../utils'; const alphanumGenerator = gen.alphaNumString.notEmpty(); @@ -258,18 +258,7 @@ describe('non-matching filter', () => { }); expect(data).toEqual({ createUser: null }); const message = `Access denied: You cannot perform the 'connect' operation on the item '{\"id\":\"${FAKE_ID}\"}'. It may not exist.`; - expectRelationshipError('dev', false, false, errors, [ - { - path: ['createUser'], - messages: [`User.notes: ${message}`], - debug: [ - { - message, - stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)), - }, - ], - }, - ]); + expectSingleRelationshipError(errors, 'createUser', 'User.notes', message); }) ); @@ -300,18 +289,7 @@ describe('non-matching filter', () => { expect(data).toEqual({ updateUser: null }); const message = `Access denied: You cannot perform the 'connect' operation on the item '{\"id\":\"${FAKE_ID}\"}'. It may not exist.`; - expectRelationshipError('dev', false, false, errors, [ - { - path: ['updateUser'], - messages: [`User.notes: ${message}`], - debug: [ - { - message, - stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)), - }, - ], - }, - ]); + expectSingleRelationshipError(errors, 'updateUser', 'User.notes', message); }) ); @@ -337,18 +315,7 @@ describe('non-matching filter', () => { expect(data).toEqual({ updateUser: null }); const message = 'Input error: You must provide at least one of "set", "connect", "create" or "disconnect" in to-many relationship inputs for "update" operations.'; - expectRelationshipError('dev', false, false, errors, [ - { - path: ['updateUser'], - messages: [`User.notes: ${message}`], - debug: [ - { - message, - stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)), - }, - ], - }, - ]); + expectSingleRelationshipError(errors, 'updateUser', 'User.notes', message); }) ); }); @@ -379,18 +346,12 @@ describe('with access control', () => { expect(data).toEqual({ createUserToNotesNoRead: null }); const message = `Access denied: You cannot perform the 'connect' operation on the item '{\"id\":\"${createNoteNoRead.id}\"}'. It may not exist.`; - expectRelationshipError('dev', false, false, errors, [ - { - path: ['createUserToNotesNoRead'], - messages: [`UserToNotesNoRead.notes: ${message}`], - debug: [ - { - message, - stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)), - }, - ], - }, - ]); + expectSingleRelationshipError( + errors, + 'createUserToNotesNoRead', + 'UserToNotesNoRead.notes', + message + ); }) ); @@ -426,18 +387,12 @@ describe('with access control', () => { }); expect(data).toEqual({ updateUserToNotesNoRead: null }); const message = `Access denied: You cannot perform the 'connect' operation on the item '{\"id\":\"${createNote.id}\"}'. It may not exist.`; - expectRelationshipError('dev', false, false, errors, [ - { - path: ['updateUserToNotesNoRead'], - messages: [`UserToNotesNoRead.notes: ${message}`], - debug: [ - { - message, - stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)), - }, - ], - }, - ]); + expectSingleRelationshipError( + errors, + 'updateUserToNotesNoRead', + 'UserToNotesNoRead.notes', + message + ); }) ); }); diff --git a/tests/api-tests/relationships/nested-mutations/connect-singular.test.ts b/tests/api-tests/relationships/nested-mutations/connect-singular.test.ts index 55a1b4b8a21..47d7d64a951 100644 --- a/tests/api-tests/relationships/nested-mutations/connect-singular.test.ts +++ b/tests/api-tests/relationships/nested-mutations/connect-singular.test.ts @@ -2,7 +2,7 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; -import { apiTestConfig, expectRelationshipError } from '../../utils'; +import { apiTestConfig, expectSingleRelationshipError } from '../../utils'; const runner = setupTestRunner({ config: apiTestConfig({ @@ -156,18 +156,7 @@ describe('non-matching filter', () => { expect(data).toEqual({ createEvent: null }); const message = `Access denied: You cannot perform the 'connect' operation on the item '{"id":"${FAKE_ID}"}'. It may not exist.`; - expectRelationshipError('dev', false, false, errors, [ - { - path: ['createEvent'], - messages: [`Event.group: ${message}`], - debug: [ - { - message, - stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)), - }, - ], - }, - ]); + expectSingleRelationshipError(errors, 'createEvent', 'Event.group', message); }) ); @@ -197,18 +186,7 @@ describe('non-matching filter', () => { }); expect(data).toEqual({ updateEvent: null }); const message = `Access denied: You cannot perform the 'connect' operation on the item '{"id":"${FAKE_ID}"}'. It may not exist.`; - expectRelationshipError('dev', false, false, errors, [ - { - path: ['updateEvent'], - messages: [`Event.group: ${message}`], - debug: [ - { - message, - stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)), - }, - ], - }, - ]); + expectSingleRelationshipError(errors, 'updateEvent', 'Event.group', message); }) ); @@ -233,18 +211,7 @@ describe('non-matching filter', () => { expect(data).toEqual({ updateEvent: null }); const message = 'Input error: You must provide one of "connect", "create" or "disconnect" in to-one relationship inputs for "update" operations.'; - expectRelationshipError('dev', false, false, errors, [ - { - path: ['updateEvent'], - messages: [`Event.group: ${message}`], - debug: [ - { - message, - stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)), - }, - ], - }, - ]); + expectSingleRelationshipError(errors, 'updateEvent', 'Event.group', message); }) ); }); @@ -355,18 +322,12 @@ describe('with access control', () => { }); expect(data).toEqual({ [`updateEventTo${group.name}`]: null }); const message = `Access denied: You cannot perform the 'connect' operation on the item '{"id":"${groupModel.id}"}'. It may not exist.`; - expectRelationshipError('dev', false, false, errors, [ - { - path: [`updateEventTo${group.name}`], - messages: [`EventTo${group.name}.group: ${message}`], - debug: [ - { - message, - stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)), - }, - ], - }, - ]); + expectSingleRelationshipError( + errors, + `updateEventTo${group.name}`, + `EventTo${group.name}.group`, + message + ); }) ); @@ -396,18 +357,12 @@ describe('with access control', () => { expect(data).toEqual({ [`createEventTo${group.name}`]: null }); const message = `Access denied: You cannot perform the 'connect' operation on the item '{"id":"${id}"}'. It may not exist.`; - expectRelationshipError('dev', false, false, errors, [ - { - path: [`createEventTo${group.name}`], - messages: [`EventTo${group.name}.group: ${message}`], - debug: [ - { - message, - stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)), - }, - ], - }, - ]); + expectSingleRelationshipError( + errors, + `createEventTo${group.name}`, + `EventTo${group.name}.group`, + message + ); }) ); } diff --git a/tests/api-tests/relationships/nested-mutations/create-and-connect-many.test.ts b/tests/api-tests/relationships/nested-mutations/create-and-connect-many.test.ts index a8cb485bee1..8670e7eb9eb 100644 --- a/tests/api-tests/relationships/nested-mutations/create-and-connect-many.test.ts +++ b/tests/api-tests/relationships/nested-mutations/create-and-connect-many.test.ts @@ -2,7 +2,7 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; -import { apiTestConfig, expectRelationshipError } from '../../utils'; +import { apiTestConfig, expectSingleRelationshipError } from '../../utils'; const alphanumGenerator = gen.alphaNumString.notEmpty(); @@ -151,19 +151,7 @@ describe('errors on incomplete data', () => { expect(data).toEqual({ createUser: null }); const message = 'Input error: You must provide "connect" or "create" in to-many relationship inputs for "create" operations.'; - expectRelationshipError('dev', false, false, errors, [ - { - path: ['createUser'], - messages: [`User.notes: ${message}`], - - debug: [ - { - message, - stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)), - }, - ], - }, - ]); + expectSingleRelationshipError(errors, 'createUser', 'User.notes', message); }) ); }); @@ -199,18 +187,12 @@ describe('with access control', () => { expect(data).toEqual({ createUserToNotesNoRead: null }); const message = `Access denied: You cannot perform the 'connect' operation on the item '{\"id\":\"${createNoteNoRead.id}\"}'. It may not exist.`; - expectRelationshipError('dev', false, false, errors, [ - { - path: ['createUserToNotesNoRead'], - messages: [`UserToNotesNoRead.notes: ${message}`], - debug: [ - { - message, - stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)), - }, - ], - }, - ]); + expectSingleRelationshipError( + errors, + 'createUserToNotesNoRead', + 'UserToNotesNoRead.notes', + message + ); }) ); @@ -251,18 +233,12 @@ describe('with access control', () => { expect(data).toEqual({ updateUserToNotesNoRead: null }); const message = `Access denied: You cannot perform the 'connect' operation on the item '{\"id\":\"${createNote.id}\"}'. It may not exist.`; - expectRelationshipError('dev', false, false, errors, [ - { - path: ['updateUserToNotesNoRead'], - messages: [`UserToNotesNoRead.notes: ${message}`], - debug: [ - { - message, - stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)), - }, - ], - }, - ]); + expectSingleRelationshipError( + errors, + 'updateUserToNotesNoRead', + 'UserToNotesNoRead.notes', + message + ); }) ); }); diff --git a/tests/api-tests/relationships/nested-mutations/create-and-connect-singular.test.ts b/tests/api-tests/relationships/nested-mutations/create-and-connect-singular.test.ts index aba8cd257b8..84edaded570 100644 --- a/tests/api-tests/relationships/nested-mutations/create-and-connect-singular.test.ts +++ b/tests/api-tests/relationships/nested-mutations/create-and-connect-singular.test.ts @@ -1,7 +1,7 @@ import { text, relationship } from '@keystone-next/keystone/fields'; import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; -import { apiTestConfig, expectRelationshipError } from '../../utils'; +import { apiTestConfig, expectSingleRelationshipError } from '../../utils'; const runner = setupTestRunner({ config: apiTestConfig({ @@ -38,18 +38,7 @@ describe('errors on incomplete data', () => { expect(data).toEqual({ createEvent: null }); const message = 'Input error: You must provide "connect" or "create" in to-one relationship inputs for "create" operations.'; - expectRelationshipError('dev', false, false, errors, [ - { - path: ['createEvent'], - messages: [`Event.group: ${message}`], - debug: [ - { - message, - stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)), - }, - ], - }, - ]); + expectSingleRelationshipError(errors, 'createEvent', 'Event.group', message); }) ); @@ -72,18 +61,7 @@ describe('errors on incomplete data', () => { expect(data).toEqual({ createEvent: null }); const message = 'Input error: You must provide "connect" or "create" in to-one relationship inputs for "create" operations.'; - expectRelationshipError('dev', false, false, errors, [ - { - path: ['createEvent'], - messages: [`Event.group: ${message}`], - debug: [ - { - message, - stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)), - }, - ], - }, - ]); + expectSingleRelationshipError(errors, 'createEvent', 'Event.group', message); }) ); }); diff --git a/tests/api-tests/relationships/nested-mutations/create-many.test.ts b/tests/api-tests/relationships/nested-mutations/create-many.test.ts index 7c927a2dbf6..a6802dda189 100644 --- a/tests/api-tests/relationships/nested-mutations/create-many.test.ts +++ b/tests/api-tests/relationships/nested-mutations/create-many.test.ts @@ -2,7 +2,7 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; -import { apiTestConfig, expectRelationshipError } from '../../utils'; +import { apiTestConfig, expectSingleRelationshipError } from '../../utils'; const alphanumGenerator = gen.alphaNumString.notEmpty(); @@ -300,18 +300,12 @@ describe('with access control', () => { expect(data).toEqual({ createUserToNotesNoCreate: null }); const message = "Access denied: You cannot perform the 'create' operation on the list 'NoteNoCreate'."; - expectRelationshipError('dev', false, false, errors, [ - { - path: ['createUserToNotesNoCreate'], - messages: [`UserToNotesNoCreate.notes: ${message}`], - debug: [ - { - message, - stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)), - }, - ], - }, - ]); + expectSingleRelationshipError( + errors, + 'createUserToNotesNoCreate', + 'UserToNotesNoCreate.notes', + message + ); // Confirm it didn't insert either of the records anyway const allNoteNoCreates = await context.query.NoteNoCreate.findMany({ @@ -355,18 +349,12 @@ describe('with access control', () => { expect(data).toEqual({ updateUserToNotesNoCreate: null }); const message = "Access denied: You cannot perform the 'create' operation on the list 'NoteNoCreate'."; - expectRelationshipError('dev', false, false, errors, [ - { - path: ['updateUserToNotesNoCreate'], - messages: [`UserToNotesNoCreate.notes: ${message}`], - debug: [ - { - message, - stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)), - }, - ], - }, - ]); + expectSingleRelationshipError( + errors, + 'updateUserToNotesNoCreate', + 'UserToNotesNoCreate.notes', + message + ); // Confirm it didn't insert the record anyway const items = await context.query.NoteNoCreate.findMany({ diff --git a/tests/api-tests/relationships/nested-mutations/create-singular.test.ts b/tests/api-tests/relationships/nested-mutations/create-singular.test.ts index 98ef07014e1..8fd9424011a 100644 --- a/tests/api-tests/relationships/nested-mutations/create-singular.test.ts +++ b/tests/api-tests/relationships/nested-mutations/create-singular.test.ts @@ -2,7 +2,11 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; -import { apiTestConfig, expectGraphQLValidationError, expectRelationshipError } from '../../utils'; +import { + apiTestConfig, + expectGraphQLValidationError, + expectSingleRelationshipError, +} from '../../utils'; const runner = setupTestRunner({ config: apiTestConfig({ @@ -257,18 +261,12 @@ describe('with access control', () => { // Assert it throws an access denied error expect(data).toEqual({ [`createEventTo${group.name}`]: null }); const message = `Access denied: You cannot perform the 'create' operation on the list 'GroupNoCreate'.`; - expectRelationshipError('dev', false, false, errors, [ - { - path: [`createEventTo${group.name}`], - messages: [`EventTo${group.name}.group: ${message}`], - debug: [ - { - message, - stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)), - }, - ], - }, - ]); + expectSingleRelationshipError( + errors, + `createEventTo${group.name}`, + `EventTo${group.name}.group`, + message + ); } // Confirm it didn't insert either of the records anyway const data1 = await context.sudo().query[group.name].findMany({ @@ -324,18 +322,12 @@ describe('with access control', () => { const { data, errors } = await context.graphql.raw({ query }); expect(data).toEqual({ [`updateEventTo${group.name}`]: null }); const message = `Access denied: You cannot perform the 'create' operation on the list 'GroupNoCreate'.`; - expectRelationshipError('dev', false, false, errors, [ - { - path: [`updateEventTo${group.name}`], - messages: [`EventTo${group.name}.group: ${message}`], - debug: [ - { - message, - stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)), - }, - ], - }, - ]); + expectSingleRelationshipError( + errors, + `updateEventTo${group.name}`, + `EventTo${group.name}.group`, + message + ); } // Confirm it didn't insert the record anyway diff --git a/tests/api-tests/relationships/nested-mutations/disconnect-many.test.ts b/tests/api-tests/relationships/nested-mutations/disconnect-many.test.ts index 9cbb552b649..310af9ebfd0 100644 --- a/tests/api-tests/relationships/nested-mutations/disconnect-many.test.ts +++ b/tests/api-tests/relationships/nested-mutations/disconnect-many.test.ts @@ -2,7 +2,11 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; -import { apiTestConfig, expectGraphQLValidationError, expectRelationshipError } from '../../utils'; +import { + apiTestConfig, + expectGraphQLValidationError, + expectSingleRelationshipError, +} from '../../utils'; const alphanumGenerator = gen.alphaNumString.notEmpty(); @@ -132,18 +136,7 @@ describe('non-matching filter', () => { expect(data).toEqual({ updateUser: null }); const message = 'Access denied: You cannot perform the \'disconnect\' operation on the item \'{"id":"c5b84f38256d3c2df59a0d9bf"}\'. It may not exist.'; - expectRelationshipError('dev', false, false, errors, [ - { - path: ['updateUser'], - messages: [`User.notes: ${message}`], - debug: [ - { - message, - stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)), - }, - ], - }, - ]); + expectSingleRelationshipError(errors, 'updateUser', 'User.notes', message); }) ); }); @@ -183,18 +176,12 @@ describe('with access control', () => { }); expect(data).toEqual({ updateUserToNotesNoRead: null }); const message = `Access denied: You cannot perform the 'disconnect' operation on the item '{\"id\":\"${createNote.id}\"}'. It may not exist.`; - expectRelationshipError('dev', false, false, errors, [ - { - path: ['updateUserToNotesNoRead'], - messages: [`UserToNotesNoRead.notes: ${message}`], - debug: [ - { - message, - stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)), - }, - ], - }, - ]); + expectSingleRelationshipError( + errors, + 'updateUserToNotesNoRead', + 'UserToNotesNoRead.notes', + message + ); } const data = await context.sudo().query.UserToNotesNoRead.findOne({ diff --git a/tests/api-tests/relationships/nested-mutations/set-many.test.ts b/tests/api-tests/relationships/nested-mutations/set-many.test.ts index fdde798dfa3..e332792f70c 100644 --- a/tests/api-tests/relationships/nested-mutations/set-many.test.ts +++ b/tests/api-tests/relationships/nested-mutations/set-many.test.ts @@ -2,7 +2,11 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; -import { apiTestConfig, expectGraphQLValidationError, expectRelationshipError } from '../../utils'; +import { + apiTestConfig, + expectGraphQLValidationError, + expectSingleRelationshipError, +} from '../../utils'; const alphanumGenerator = gen.alphaNumString.notEmpty(); @@ -145,18 +149,7 @@ describe('no access control', () => { expect(data).toEqual({ updateUser: null }); const message = 'Input error: The "set" and "disconnect" fields cannot both be provided to to-many relationship inputs for "update" operations.'; - expectRelationshipError('dev', false, false, errors, [ - { - path: ['updateUser'], - messages: [`User.notes: ${message}`], - debug: [ - { - message, - stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)), - }, - ], - }, - ]); + expectSingleRelationshipError(errors, 'updateUser', 'User.notes', message); }) ); diff --git a/tests/api-tests/utils.ts b/tests/api-tests/utils.ts index 6cce2413484..8c42f112056 100644 --- a/tests/api-tests/utils.ts +++ b/tests/api-tests/utils.ts @@ -47,10 +47,7 @@ export const expectGraphQLValidationError = ( ) => { const unpackedErrors = unpackErrors(errors); expect(unpackedErrors).toEqual( - args.map(({ message }) => ({ - extensions: { code: 'GRAPHQL_VALIDATION_FAILED' }, - message, - })) + args.map(({ message }) => ({ extensions: { code: 'GRAPHQL_VALIDATION_FAILED' }, message })) ); }; @@ -150,12 +147,9 @@ export const expectLimitsExceededError = ( const unpackedErrors = (errors || []).map(({ locations, ...unpacked }) => ({ ...unpacked, })); + const message = 'Your request exceeded server limits'; expect(unpackedErrors).toEqual( - args.map(({ path }) => ({ - extensions: { code: 'KS_LIMITS_EXCEEDED' }, - path, - message: 'Your request exceeded server limits', - })) + args.map(({ path }) => ({ extensions: { code: 'KS_LIMITS_EXCEEDED' }, path, message })) ); }; @@ -179,13 +173,12 @@ export const expectAccessReturnError = ( ) => { const unpackedErrors = unpackErrors(errors); expect(unpackedErrors).toEqual( - args.map(({ path, errors }) => ({ - extensions: { code: 'KS_ACCESS_RETURN_ERROR' }, - path, - message: `Invalid values returned from access control function.\n${j( + args.map(({ path, errors }) => { + const message = `Invalid values returned from access control function.\n${j( errors.map(e => `${e.tag}: Returned: ${e.returned}. Expected: boolean.`) - )}`, - })) + )}`; + return { extensions: { code: 'KS_ACCESS_RETURN_ERROR' }, path, message }; + }) ); }; @@ -195,18 +188,11 @@ export const expectFilterDenied = ( ) => { const unpackedErrors = unpackErrors(errors); expect(unpackedErrors).toEqual( - args.map(({ path, message }) => ({ - extensions: { code: 'KS_FILTER_DENIED' }, - path, - message, - })) + args.map(({ path, message }) => ({ extensions: { code: 'KS_FILTER_DENIED' }, path, message })) ); }; export const expectResolverError = ( - mode: 'dev' | 'production', - httpQuery: boolean, - _debug: boolean | undefined, errors: readonly any[] | undefined, args: { path: (string | number)[]; messages: string[]; debug: any[] }[] ) => { @@ -214,38 +200,26 @@ export const expectResolverError = ( expect(unpackedErrors).toEqual( args.map(({ path, messages, debug }) => { const message = `An error occured while resolving input fields.\n${j(messages)}`; - const stacktrace = message.split('\n'); - stacktrace[0] = `Error: ${stacktrace[0]}`; - - // We expect to see debug details if: - // - httpQuery is false - // - graphql.debug is true or - // - graphql.debug is undefined and mode !== production or - const expectDebug = - _debug === true || (_debug === undefined && mode !== 'production') || !httpQuery; - // We expect to see the Apollo exception under the same conditions, but only if - // httpQuery is also true. - const expectException = httpQuery && expectDebug; - - return { - extensions: { - code: 'KS_RESOLVER_ERROR', - ...(expectException - ? { exception: { stacktrace: expect.arrayContaining(stacktrace) } } - : {}), - ...(expectDebug ? { debug } : {}), - }, - path, - message, - }; + return { extensions: { code: 'KS_RESOLVER_ERROR', debug }, path, message }; }) ); }; +export const expectSingleResolverError = ( + errors: readonly any[] | undefined, + path: string, + fieldPath: string, + message: string +) => + expectResolverError(errors, [ + { + path: [path], + messages: [`${fieldPath}: ${message}`], + debug: [{ message, stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)) }], + }, + ]); + export const expectRelationshipError = ( - mode: 'dev' | 'production', - httpQuery: boolean, - _debug: boolean | undefined, errors: readonly any[] | undefined, args: { path: (string | number)[]; messages: string[]; debug: any[] }[] ) => { @@ -253,30 +227,21 @@ export const expectRelationshipError = ( expect(unpackedErrors).toEqual( args.map(({ path, messages, debug }) => { const message = `An error occured while resolving relationship fields.\n${j(messages)}`; - const stacktrace = message.split('\n'); - stacktrace[0] = `Error: ${stacktrace[0]}`; - - // We expect to see debug details if: - // - httpQuery is false - // - graphql.debug is true or - // - graphql.debug is undefined and mode !== production or - const expectDebug = - _debug === true || (_debug === undefined && mode !== 'production') || !httpQuery; - // We expect to see the Apollo exception under the same conditions, but only if - // httpQuery is also true. - const expectException = httpQuery && expectDebug; - - return { - extensions: { - code: 'KS_RELATIONSHIP_ERROR', - ...(expectException - ? { exception: { stacktrace: expect.arrayContaining(stacktrace) } } - : {}), - ...(expectDebug ? { debug } : {}), - }, - path, - message, - }; + return { extensions: { code: 'KS_RELATIONSHIP_ERROR', debug }, path, message }; }) ); }; + +export const expectSingleRelationshipError = ( + errors: readonly any[] | undefined, + path: string, + fieldPath: string, + message: string +) => + expectRelationshipError(errors, [ + { + path: [path], + messages: [`${fieldPath}: ${message}`], + debug: [{ message, stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)) }], + }, + ]);