From 86ff0a434c49a4ec236783f1a8fe518dca9daba8 Mon Sep 17 00:00:00 2001 From: Jacob Fletcher Date: Thu, 16 Jan 2025 15:55:34 -0500 Subject: [PATCH] test: field level validation errors (#10614) Continuation of #10575. Field level validations error were incorrectly throwing uniqueness errors. This was fixed but lacking tests. --- .../db-mongodb/src/utilities/handleError.ts | 3 +- test/collections-rest/config.ts | 12 +- test/collections-rest/int.spec.ts | 138 +++++++++--------- test/database/config.ts | 62 +++++++- test/database/int.spec.ts | 74 ++++++++-- test/database/payload-types.ts | 20 +++ test/database/shared.ts | 1 + 7 files changed, 219 insertions(+), 91 deletions(-) create mode 100644 test/database/shared.ts diff --git a/packages/db-mongodb/src/utilities/handleError.ts b/packages/db-mongodb/src/utilities/handleError.ts index d886f679e3..8cdc20a816 100644 --- a/packages/db-mongodb/src/utilities/handleError.ts +++ b/packages/db-mongodb/src/utilities/handleError.ts @@ -19,13 +19,12 @@ export const handleError = ({ // Handle uniqueness error from MongoDB if ('code' in error && error.code === 11000 && 'keyValue' in error && error.keyValue) { - const message = req?.t ? req.t('error:valueMustBeUnique') : 'Value must be unique' throw new ValidationError( { collection, errors: [ { - message, + message: req?.t ? req.t('error:valueMustBeUnique') : 'Value must be unique', path: Object.keys(error.keyValue)[0], }, ], diff --git a/test/collections-rest/config.ts b/test/collections-rest/config.ts index d2b383621f..7b8d89d7ba 100644 --- a/test/collections-rest/config.ts +++ b/test/collections-rest/config.ts @@ -34,7 +34,7 @@ const collectionWithName = (collectionSlug: string): CollectionConfig => { } } -export const slug = 'posts' +export const postsSlug = 'posts' export const relationSlug = 'relation' export const pointSlug = 'point' export const customIdSlug = 'custom-id' @@ -51,7 +51,7 @@ export default buildConfigWithDefaults({ }, collections: [ { - slug, + slug: postsSlug, access: openAccess, fields: [ { @@ -346,14 +346,14 @@ export default buildConfigWithDefaults({ // Relation - hasMany await payload.create({ - collection: slug, + collection: postsSlug, data: { relationHasManyField: rel1.id, title: 'rel to hasMany', }, }) await payload.create({ - collection: slug, + collection: postsSlug, data: { relationHasManyField: rel2.id, title: 'rel to hasMany 2', @@ -362,7 +362,7 @@ export default buildConfigWithDefaults({ // Relation - relationTo multi await payload.create({ - collection: slug, + collection: postsSlug, data: { relationMultiRelationTo: { relationTo: relationSlug, @@ -374,7 +374,7 @@ export default buildConfigWithDefaults({ // Relation - relationTo multi hasMany await payload.create({ - collection: slug, + collection: postsSlug, data: { relationMultiRelationToHasMany: [ { diff --git a/test/collections-rest/int.spec.ts b/test/collections-rest/int.spec.ts index 74039d2a5b..fbe1caa63d 100644 --- a/test/collections-rest/int.spec.ts +++ b/test/collections-rest/int.spec.ts @@ -18,7 +18,7 @@ import { methods, pointSlug, relationSlug, - slug, + postsSlug, } from './config.js' const filename = fileURLToPath(import.meta.url) @@ -55,7 +55,7 @@ describe('collections-rest', () => { it('should find', async () => { const post1 = await createPost() const post2 = await createPost() - const response = await restClient.GET(`/${slug}`) + const response = await restClient.GET(`/${postsSlug}`) const result = await response.json() expect(response.status).toEqual(200) @@ -68,7 +68,7 @@ describe('collections-rest', () => { it('should count', async () => { await createPost() await createPost() - const response = await restClient.GET(`/${slug}/count`) + const response = await restClient.GET(`/${postsSlug}/count`) const result = await response.json() expect(response.status).toEqual(200) @@ -78,7 +78,7 @@ describe('collections-rest', () => { it('should find where id', async () => { const post1 = await createPost() await createPost() - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { id: { equals: post1.id } }, }, @@ -95,7 +95,7 @@ describe('collections-rest', () => { const post2 = await createPost() const { docs, totalDocs } = await payload.find({ - collection: slug, + collection: postsSlug, overrideAccess: false, pagination: false, }) @@ -111,7 +111,7 @@ describe('collections-rest', () => { const { id, description } = await createPost({ description: 'desc' }) const updatedTitle = 'updated-title' - const response = await restClient.PATCH(`/${slug}/${id}`, { + const response = await restClient.PATCH(`/${postsSlug}/${id}`, { body: JSON.stringify({ title: updatedTitle }), }) const { doc } = await response.json() @@ -128,7 +128,7 @@ describe('collections-rest', () => { } const description = 'updated' - const response = await restClient.PATCH(`/${slug}`, { + const response = await restClient.PATCH(`/${postsSlug}`, { body: JSON.stringify({ description, }), @@ -151,7 +151,7 @@ describe('collections-rest', () => { } const description = 'updated-description' - const response = await restClient.PATCH(`/${slug}`, { + const response = await restClient.PATCH(`/${postsSlug}`, { body: JSON.stringify({ description, }), @@ -167,7 +167,7 @@ describe('collections-rest', () => { const { docs: resDocs } = await payload.find({ limit: 10, - collection: slug, + collection: postsSlug, where: { id: { in: ids } }, }) expect(resDocs.at(-1).description).toEqual('to-update') @@ -180,7 +180,7 @@ describe('collections-rest', () => { const description = 'updated' - const response = await restClient.PATCH(`/${slug}`, { + const response = await restClient.PATCH(`/${postsSlug}`, { body: JSON.stringify({ description, }), @@ -193,7 +193,7 @@ describe('collections-rest', () => { expect(errors).toHaveLength(1) const { docs } = await payload.find({ - collection: slug, + collection: postsSlug, }) expect(docs[0].description).not.toEqual(description) @@ -206,7 +206,7 @@ describe('collections-rest', () => { } const description = 'updated' - const relationFieldResponse = await restClient.PATCH(`/${slug}`, { + const relationFieldResponse = await restClient.PATCH(`/${postsSlug}`, { body: JSON.stringify({ description, }), @@ -214,7 +214,7 @@ describe('collections-rest', () => { }) expect(relationFieldResponse.status).toEqual(400) - const relationMultiRelationToResponse = await restClient.PATCH(`/${slug}`, { + const relationMultiRelationToResponse = await restClient.PATCH(`/${postsSlug}`, { body: JSON.stringify({ description, }), @@ -223,7 +223,7 @@ describe('collections-rest', () => { expect(relationMultiRelationToResponse.status).toEqual(400) const { docs } = await payload.find({ - collection: slug, + collection: postsSlug, }) expect(docs[0].description).not.toEqual(description) @@ -232,14 +232,14 @@ describe('collections-rest', () => { it('should not bulk update with a read restricted field query', async () => { const { id } = await payload.create({ - collection: slug, + collection: postsSlug, data: { restrictedField: 'restricted', }, }) const description = 'description' - const response = await restClient.PATCH(`/${slug}`, { + const response = await restClient.PATCH(`/${postsSlug}`, { body: JSON.stringify({ description, }), @@ -249,7 +249,7 @@ describe('collections-rest', () => { const doc = await payload.findByID({ id, - collection: slug, + collection: postsSlug, }) expect(response.status).toEqual(400) @@ -301,7 +301,7 @@ describe('collections-rest', () => { await createPost({ description: `desc ${i}` }) } - const response = await restClient.DELETE(`/${slug}`, { + const response = await restClient.DELETE(`/${postsSlug}`, { query: { where: { title: { equals: 'title' } } }, }) const { docs } = await response.json() @@ -481,7 +481,7 @@ describe('collections-rest', () => { it('should delete', async () => { const { id } = await createPost() - const response = await restClient.DELETE(`/${slug}/${id}`) + const response = await restClient.DELETE(`/${postsSlug}/${id}`) const { doc } = await response.json() expect(response.status).toEqual(200) @@ -491,7 +491,7 @@ describe('collections-rest', () => { it('should include metadata', async () => { await createPosts(11) - const result = await restClient.GET(`/${slug}`).then((res) => res.json()) + const result = await restClient.GET(`/${postsSlug}`).then((res) => res.json()) expect(result.totalDocs).toBeGreaterThan(0) expect(result.limit).toBe(10) @@ -534,7 +534,7 @@ describe('collections-rest', () => { describe('regular relationship', () => { it('query by property value', async () => { - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { relationField: { equals: relation.id } }, }, @@ -547,7 +547,7 @@ describe('collections-rest', () => { }) it('should count query by property value', async () => { - const response = await restClient.GET(`/${slug}/count`, { + const response = await restClient.GET(`/${postsSlug}/count`, { query: { where: { relationField: { equals: relation.id } }, }, @@ -559,7 +559,7 @@ describe('collections-rest', () => { }) it('query by id', async () => { - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { relationField: { equals: relation.id } }, }, @@ -573,13 +573,13 @@ describe('collections-rest', () => { it('should query LIKE by ID', async () => { const post = await payload.create({ - collection: slug, + collection: postsSlug, data: { title: 'find me buddy', }, }) - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { id: { @@ -600,7 +600,7 @@ describe('collections-rest', () => { relationHasManyField: [relation.id, relation2.id], }) - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { 'relationHasManyField.name': { equals: relation.name } }, }, @@ -612,7 +612,7 @@ describe('collections-rest', () => { expect(result.totalDocs).toEqual(1) // Query second relationship - const response2 = await restClient.GET(`/${slug}`, { + const response2 = await restClient.GET(`/${postsSlug}`, { query: { where: { 'relationHasManyField.name': { equals: relation2.name } }, }, @@ -631,7 +631,7 @@ describe('collections-rest', () => { }) await createPost() - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { 'relationMultiRelationTo.value': { equals: relation.id } }, }, @@ -650,7 +650,7 @@ describe('collections-rest', () => { }) await createPost() - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { and: [ @@ -678,7 +678,7 @@ describe('collections-rest', () => { }) await createPost() - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { 'relationMultiRelationToHasMany.value': { equals: relation.id } }, }, @@ -690,7 +690,7 @@ describe('collections-rest', () => { expect(result.totalDocs).toEqual(1) // Query second relation - const response2 = await restClient.GET(`/${slug}`, { + const response2 = await restClient.GET(`/${postsSlug}`, { query: { where: { 'relationMultiRelationToHasMany.value': { equals: relation.id } }, }, @@ -711,7 +711,7 @@ describe('collections-rest', () => { const test = 'test' await createPost({ fakeLocalization: test }) - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { fakeLocalization: { equals: test } }, }, @@ -723,7 +723,7 @@ describe('collections-rest', () => { }) it('should not error when attempting to sort on a field that does not exist', async () => { - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { sort: 'fake', }, @@ -738,7 +738,7 @@ describe('collections-rest', () => { const valueToQuery = 'valueToQuery' const post1 = await createPost({ title: valueToQuery }) await createPost() - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { title: { equals: valueToQuery } }, }, @@ -754,7 +754,7 @@ describe('collections-rest', () => { const post1 = await createPost({ title: 'not-equals' }) const post2 = await createPost() const post3 = await createPost({ title: undefined }) - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { title: { not_equals: post1.title } }, }, @@ -769,7 +769,7 @@ describe('collections-rest', () => { it('in', async () => { const post1 = await createPost({ title: 'my-title' }) await createPost() - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { title: { in: [post1.title] } }, }, @@ -784,7 +784,7 @@ describe('collections-rest', () => { it('not_in', async () => { const post1 = await createPost({ title: 'not-me' }) const post2 = await createPost() - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { title: { not_in: [post1.title] } }, }, @@ -805,7 +805,7 @@ describe('collections-rest', () => { await createPost({ relationField: relationship.id, title: 'not-me' }) // await createPost({ relationMultiRelationTo: relationship.id, title: 'not-me' }) const post2 = await createPost({ title: 'me' }) - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { relationField: { not_in: [relationship.id] } }, }, @@ -817,7 +817,7 @@ describe('collections-rest', () => { expect(result.totalDocs).toEqual(1) // do not want to error for empty arrays - const emptyNotInResponse = await restClient.GET(`/${slug}`, { + const emptyNotInResponse = await restClient.GET(`/${postsSlug}`, { query: { where: { relationField: { not_in: [] } }, }, @@ -835,7 +835,7 @@ describe('collections-rest', () => { const post1 = await createPost({ relationField: relationship.id, title: 'me' }) // await createPost({ relationMultiRelationTo: relationship.id, title: 'not-me' }) await createPost({ title: 'not-me' }) - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { relationField: { in: [relationship.id] } }, }, @@ -847,7 +847,7 @@ describe('collections-rest', () => { expect(result.totalDocs).toEqual(1) // do not want to error for empty arrays - const emptyNotInResponse = await restClient.GET(`/${slug}`, { + const emptyNotInResponse = await restClient.GET(`/${postsSlug}`, { query: { where: { relationField: { in: [] } }, }, @@ -859,7 +859,7 @@ describe('collections-rest', () => { it('like', async () => { const post1 = await createPost({ title: 'prefix-value' }) - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { title: { like: 'prefix' } }, }, @@ -881,7 +881,7 @@ describe('collections-rest', () => { title: specialCharacters, }) - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { title: { @@ -902,7 +902,7 @@ describe('collections-rest', () => { it('like - cyrillic characters', async () => { const post1 = await createPost({ title: 'Тест' }) - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { title: { @@ -921,7 +921,7 @@ describe('collections-rest', () => { it('like - cyrillic characters in multiple words', async () => { const post1 = await createPost({ title: 'привет, это тест полезной нагрузки' }) - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { title: { @@ -939,7 +939,7 @@ describe('collections-rest', () => { it('like - partial word match', async () => { const post = await createPost({ title: 'separate words should partially match' }) - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { title: { @@ -958,7 +958,7 @@ describe('collections-rest', () => { it('like - id should not crash', async () => { const post = await createPost({ title: 'post' }) - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { id: { @@ -974,7 +974,7 @@ describe('collections-rest', () => { it('exists - true', async () => { const postWithDesc = await createPost({ description: 'exists' }) await createPost({ description: undefined }) - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { description: { @@ -993,7 +993,7 @@ describe('collections-rest', () => { it('exists - false', async () => { const postWithoutDesc = await createPost({ description: undefined }) await createPost({ description: 'exists' }) - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { description: { @@ -1018,7 +1018,7 @@ describe('collections-rest', () => { }) it('greater_than', async () => { - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { number: { @@ -1035,7 +1035,7 @@ describe('collections-rest', () => { }) it('greater_than_equal', async () => { - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { number: { @@ -1054,7 +1054,7 @@ describe('collections-rest', () => { }) it('less_than', async () => { - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { number: { @@ -1071,7 +1071,7 @@ describe('collections-rest', () => { }) it('less_than_equal', async () => { - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { number: { @@ -1312,7 +1312,7 @@ describe('collections-rest', () => { const post2 = await createPost({ title: 'post2' }) await createPost() - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { or: [ @@ -1342,7 +1342,7 @@ describe('collections-rest', () => { const post1 = await createPost({ title: 'post1' }) await createPost() - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { or: [ @@ -1374,7 +1374,7 @@ describe('collections-rest', () => { await createPost({ description, title: 'post2' }) // Diff title, same desc await createPost() - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { where: { and: [ @@ -1427,13 +1427,13 @@ describe('collections-rest', () => { }, }, } - let response = await restClient.GET(`/${slug}`, { query }) + let response = await restClient.GET(`/${postsSlug}`, { query }) const page1 = await response.json() - response = await restClient.GET(`/${slug}`, { query: { ...query, page: 2 } }) + response = await restClient.GET(`/${postsSlug}`, { query: { ...query, page: 2 } }) const page2 = await response.json() - response = await restClient.GET(`/${slug}`, { query: { ...query, page: 3 } }) + response = await restClient.GET(`/${postsSlug}`, { query: { ...query, page: 3 } }) const page3 = await response.json() expect(page1.hasNextPage).toStrictEqual(true) @@ -1476,13 +1476,13 @@ describe('collections-rest', () => { }, }, } - let response = await restClient.GET(`/${slug}`, { query }) + let response = await restClient.GET(`/${postsSlug}`, { query }) const page1 = await response.json() - response = await restClient.GET(`/${slug}`, { query: { ...query, page: 2 } }) + response = await restClient.GET(`/${postsSlug}`, { query: { ...query, page: 2 } }) const page2 = await response.json() - response = await restClient.GET(`/${slug}`, { query: { ...query, page: 3 } }) + response = await restClient.GET(`/${postsSlug}`, { query: { ...query, page: 3 } }) const page3 = await response.json() expect(page1.hasNextPage).toStrictEqual(true) @@ -1524,7 +1524,7 @@ describe('collections-rest', () => { }) it('should query a limited set of docs', async () => { - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { limit: 15, where: { @@ -1541,7 +1541,7 @@ describe('collections-rest', () => { }) it('should query all docs when limit=0', async () => { - const response = await restClient.GET(`/${slug}`, { + const response = await restClient.GET(`/${postsSlug}`, { query: { limit: 0, where: { @@ -1566,7 +1566,7 @@ describe('collections-rest', () => { }) const result = await restClient - .GET(`/${slug}`, { + .GET(`/${postsSlug}`, { query: { where: { 'D1.D2.D3.D4': { @@ -1641,11 +1641,11 @@ describe('collections-rest', () => { const post = await createPost({}) const response = await restClient.GET( - `/${slug}/${typeof post.id === 'number' ? 1000 : randomUUID()}`, + `/${postsSlug}/${typeof post.id === 'number' ? 1000 : randomUUID()}`, ) expect(response.status).toBe(404) - expect(collection.slug).toBe(slug) + expect(collection.slug).toBe(postsSlug) expect(err).toBeInstanceOf(NotFound) expect(errResult).toStrictEqual({ errors: [ @@ -1695,7 +1695,7 @@ describe('collections-rest', () => { async function createPost(overrides?: Partial) { const { doc } = await restClient - .POST(`/${slug}`, { + .POST(`/${postsSlug}`, { body: JSON.stringify({ title: 'title', ...overrides }), }) .then((res) => res.json()) @@ -1710,7 +1710,7 @@ async function createPosts(count: number) { async function clearDocs(): Promise { await payload.delete({ - collection: slug, + collection: postsSlug, where: { id: { exists: true } }, }) } diff --git a/test/database/config.ts b/test/database/config.ts index 7c6f06c03b..83389c7014 100644 --- a/test/database/config.ts +++ b/test/database/config.ts @@ -8,6 +8,7 @@ import { v4 as uuid } from 'uuid' import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js' import { devUser } from '../credentials.js' +import { postsSlug } from './shared.js' const defaultValueField: TextField = { name: 'defaultValue', @@ -23,13 +24,72 @@ export default buildConfigWithDefaults({ }, collections: [ { - slug: 'posts', + slug: postsSlug, fields: [ { name: 'title', type: 'text', required: true, }, + { + type: 'tabs', + tabs: [ + { + name: 'D1', + fields: [ + { + name: 'D2', + type: 'group', + fields: [ + { + type: 'row', + fields: [ + { + type: 'collapsible', + fields: [ + { + type: 'tabs', + tabs: [ + { + fields: [ + { + name: 'D3', + type: 'group', + fields: [ + { + type: 'row', + fields: [ + { + type: 'collapsible', + fields: [ + { + name: 'D4', + type: 'text', + }, + ], + label: 'Collapsible2', + }, + ], + }, + ], + }, + ], + label: 'Tab1', + }, + ], + }, + ], + label: 'Collapsible2', + }, + ], + }, + ], + }, + ], + label: 'Tab1', + }, + ], + }, { name: 'hasTransaction', type: 'checkbox', diff --git a/test/database/int.spec.ts b/test/database/int.spec.ts index 9286560d01..c739a3adf5 100644 --- a/test/database/int.spec.ts +++ b/test/database/int.spec.ts @@ -26,6 +26,7 @@ import { devUser } from '../credentials.js' import { initPayloadInt } from '../helpers/initPayloadInt.js' import { isMongoose } from '../helpers/isMongoose.js' import removeFiles from '../helpers/removeFiles.js' +import { postsSlug } from './shared.js' const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) @@ -34,7 +35,7 @@ let payload: Payload let user: Record & TypeWithID let token: string let restClient: NextRESTClient -const collection = 'posts' +const collection = postsSlug const title = 'title' process.env.PAYLOAD_CONFIG_PATH = path.join(dirname, 'config.ts') @@ -142,7 +143,7 @@ describe('database', () => { const blockID = '6764de9af79a863575c5f58c' const doc = await payload.create({ - collection: 'posts', + collection: postsSlug, data: { title: 'test', arrayWithIDs: [ @@ -168,7 +169,7 @@ describe('database', () => { const blockID = '6764dec58c68f337a758180c' const doc = await payload.create({ - collection: 'posts', + collection: postsSlug, data: { title: 'test', arrayWithIDs: [ @@ -186,7 +187,7 @@ describe('database', () => { }) const duplicate = await payload.duplicate({ - collection: 'posts', + collection: postsSlug, id: doc.id, }) @@ -198,7 +199,7 @@ describe('database', () => { describe('timestamps', () => { it('should have createdAt and updatedAt timestamps to the millisecond', async () => { const result = await payload.create({ - collection: 'posts', + collection: postsSlug, data: { title: 'hello', }, @@ -212,7 +213,7 @@ describe('database', () => { it('should allow createdAt to be set in create', async () => { const createdAt = new Date('2021-01-01T00:00:00.000Z').toISOString() const result = await payload.create({ - collection: 'posts', + collection: postsSlug, data: { createdAt, title: 'hello', @@ -221,7 +222,7 @@ describe('database', () => { const doc = await payload.findByID({ id: result.id, - collection: 'posts', + collection: postsSlug, }) expect(result.createdAt).toStrictEqual(createdAt) @@ -231,7 +232,7 @@ describe('database', () => { it('updatedAt cannot be set in create', async () => { const updatedAt = new Date('2022-01-01T00:00:00.000Z').toISOString() const result = await payload.create({ - collection: 'posts', + collection: postsSlug, data: { title: 'hello', updatedAt, @@ -875,6 +876,53 @@ describe('database', () => { }) }) + describe('Error Handler', () => { + it('should return proper top-level field validation errors', async () => { + let errorMessage: string = '' + + try { + await payload.create({ + collection: postsSlug, + data: { + // @ts-expect-error + title: undefined, + }, + }) + } catch (e: any) { + errorMessage = e.message + } + + await expect(errorMessage).toBe('The following field is invalid: title') + }) + + it('should return proper deeply nested field validation errors', async () => { + try { + await payload.create({ + collection: postsSlug, + data: { + title: 'Title', + D1: { + D2: { + D3: { + // @ts-expect-error + D4: {}, + }, + }, + }, + }, + }) + } catch (e: any) { + await expect(e.message).toMatch( + payload.db.name === 'mongoose' + ? 'posts validation failed: D1.D2.D3.D4: Cast to string failed for value "{}" (type Object) at path "D4"' + : payload.db.name === 'sqlite' + ? 'SQLite3 can only bind numbers, strings, bigints, buffers, and null' + : '', + ) + } + }) + }) + describe('defaultValue', () => { it('should set default value from db.create', async () => { // call the db adapter create directly to bypass Payload's default value assignment @@ -1257,7 +1305,7 @@ describe('database', () => { it('should upsert', async () => { const postShouldCreated = await payload.db.upsert({ req: {}, - collection: 'posts', + collection: postsSlug, data: { title: 'some-title-here', }, @@ -1272,7 +1320,7 @@ describe('database', () => { const postShouldUpdated = await payload.db.upsert({ req: {}, - collection: 'posts', + collection: postsSlug, data: { title: 'some-title-here', }, @@ -1288,9 +1336,9 @@ describe('database', () => { }) it('should enforce unique ids on db level even after delete', async () => { - const { id } = await payload.create({ collection: 'posts', data: { title: 'ASD' } }) - await payload.delete({ id, collection: 'posts' }) - const { id: id_2 } = await payload.create({ collection: 'posts', data: { title: 'ASD' } }) + const { id } = await payload.create({ collection: postsSlug, data: { title: 'ASD' } }) + await payload.delete({ id, collection: postsSlug }) + const { id: id_2 } = await payload.create({ collection: postsSlug, data: { title: 'ASD' } }) expect(id_2).not.toBe(id) }) }) diff --git a/test/database/payload-types.ts b/test/database/payload-types.ts index 4cc83ae705..b9dc6d96a0 100644 --- a/test/database/payload-types.ts +++ b/test/database/payload-types.ts @@ -88,6 +88,13 @@ export interface UserAuthOperations { export interface Post { id: string; title: string; + D1?: { + D2?: { + D3?: { + D4?: string | null; + }; + }; + }; hasTransaction?: boolean | null; throwAfterChange?: boolean | null; arrayWithIDs?: @@ -440,6 +447,19 @@ export interface PayloadMigration { */ export interface PostsSelect { title?: T; + D1?: + | T + | { + D2?: + | T + | { + D3?: + | T + | { + D4?: T; + }; + }; + }; hasTransaction?: T; throwAfterChange?: T; arrayWithIDs?: diff --git a/test/database/shared.ts b/test/database/shared.ts new file mode 100644 index 0000000000..f4dad31482 --- /dev/null +++ b/test/database/shared.ts @@ -0,0 +1 @@ +export const postsSlug = 'posts'