From 694c76d51a88e42d42f9c529c0b2c1cf3cb8a134 Mon Sep 17 00:00:00 2001 From: Jacob Fletcher Date: Wed, 5 Feb 2025 17:03:35 -0500 Subject: [PATCH] test: cleans up fields-relationship test suite (#11003) The `fields-relationship` test suite is disorganized to the point of being unusable. This makes it very difficult to digest at a high level and add new tests. This PR cleans it up in the following ways: - Moves collection configs to their own standalone files - Moves the seed function to its own file - Consolidates collection slugs in their own file - Uses generated types instead of defining them statically - Wraps the `filterOptions` e2e tests within a describe block Related, there are three distinct test suites where we manage relationships: `relationships`, `fields-relationship`, and `fields > relationships`. In the future we ought to consolidate at least two of these. IMO the `fields > relationship` suite should remain in place for general _component level_ UI tests for the field itself, whereas the other suite could run the integration tests and test the more complex UI patterns that exist outside of the field component. --- .../PrePopulateFieldUI/index.tsx | 2 +- test/fields-relationship/baseFields.ts | 8 + .../collections/Collection1/index.ts | 16 + .../collections/Collection2/index.ts | 13 + .../collections/FilterFalse/index.ts | 12 + .../collections/FilterTrue/index.ts | 12 + .../collections/MixedMedia/index.ts | 19 + .../collections/Podcast/index.ts | 21 + .../collections/Relation1/index.ts | 9 + .../collections/Relation2/index.ts | 9 + .../collections/RelationWithTitle/index.ts | 25 + .../collections/Relationship/index.ts | 130 +++++ .../collections/RelationshipFiltered/index.ts | 16 + .../collections/Restricted/index.ts | 16 + .../collections/UpdatedExternally/index.ts | 99 ++++ .../index.ts | 4 +- .../collections/Video/index.ts | 21 + test/fields-relationship/config.ts | 550 +----------------- test/fields-relationship/e2e.spec.ts | 166 +++--- test/fields-relationship/int.spec.ts | 2 +- test/fields-relationship/payload-types.ts | 12 +- test/fields-relationship/seed.ts | 191 ++++++ .../{collectionSlugs.ts => slugs.ts} | 16 + test/fields/payload-types.ts | 4 + test/uploads/e2e.spec.ts | 106 ++-- tsconfig.base.json | 2 +- 26 files changed, 821 insertions(+), 660 deletions(-) create mode 100644 test/fields-relationship/baseFields.ts create mode 100644 test/fields-relationship/collections/Collection1/index.ts create mode 100644 test/fields-relationship/collections/Collection2/index.ts create mode 100644 test/fields-relationship/collections/FilterFalse/index.ts create mode 100644 test/fields-relationship/collections/FilterTrue/index.ts create mode 100644 test/fields-relationship/collections/MixedMedia/index.ts create mode 100644 test/fields-relationship/collections/Podcast/index.ts create mode 100644 test/fields-relationship/collections/Relation1/index.ts create mode 100644 test/fields-relationship/collections/Relation2/index.ts create mode 100644 test/fields-relationship/collections/RelationWithTitle/index.ts create mode 100644 test/fields-relationship/collections/Relationship/index.ts create mode 100644 test/fields-relationship/collections/RelationshipFiltered/index.ts create mode 100644 test/fields-relationship/collections/Restricted/index.ts create mode 100644 test/fields-relationship/collections/UpdatedExternally/index.ts rename test/fields-relationship/collections/{VersionedRelationshipField => Versions}/index.ts (80%) create mode 100644 test/fields-relationship/collections/Video/index.ts create mode 100644 test/fields-relationship/seed.ts rename test/fields-relationship/{collectionSlugs.ts => slugs.ts} (67%) diff --git a/test/fields-relationship/PrePopulateFieldUI/index.tsx b/test/fields-relationship/PrePopulateFieldUI/index.tsx index c92d8c5f80..1ed66a3c2a 100644 --- a/test/fields-relationship/PrePopulateFieldUI/index.tsx +++ b/test/fields-relationship/PrePopulateFieldUI/index.tsx @@ -2,7 +2,7 @@ import { useField } from '@payloadcms/ui' import * as React from 'react' -import { collection1Slug } from '../collectionSlugs.js' +import { collection1Slug } from '../slugs.js' export const PrePopulateFieldUI: React.FC<{ hasMany?: boolean diff --git a/test/fields-relationship/baseFields.ts b/test/fields-relationship/baseFields.ts new file mode 100644 index 0000000000..b0a2bf540f --- /dev/null +++ b/test/fields-relationship/baseFields.ts @@ -0,0 +1,8 @@ +import type { CollectionConfig } from 'payload' + +export const baseRelationshipFields: CollectionConfig['fields'] = [ + { + name: 'name', + type: 'text', + }, +] diff --git a/test/fields-relationship/collections/Collection1/index.ts b/test/fields-relationship/collections/Collection1/index.ts new file mode 100644 index 0000000000..01288a6ccb --- /dev/null +++ b/test/fields-relationship/collections/Collection1/index.ts @@ -0,0 +1,16 @@ +import type { CollectionConfig } from 'payload' + +import { collection1Slug } from '../../slugs.js' + +export const Collection1: CollectionConfig = { + fields: [ + { + name: 'name', + type: 'text', + }, + ], + slug: collection1Slug, + admin: { + useAsTitle: 'name', + }, +} diff --git a/test/fields-relationship/collections/Collection2/index.ts b/test/fields-relationship/collections/Collection2/index.ts new file mode 100644 index 0000000000..818976985e --- /dev/null +++ b/test/fields-relationship/collections/Collection2/index.ts @@ -0,0 +1,13 @@ +import type { CollectionConfig } from 'payload' + +import { collection2Slug } from '../../slugs.js' + +export const Collection2: CollectionConfig = { + fields: [ + { + name: 'name', + type: 'text', + }, + ], + slug: collection2Slug, +} diff --git a/test/fields-relationship/collections/FilterFalse/index.ts b/test/fields-relationship/collections/FilterFalse/index.ts new file mode 100644 index 0000000000..c657cec057 --- /dev/null +++ b/test/fields-relationship/collections/FilterFalse/index.ts @@ -0,0 +1,12 @@ +import type { CollectionConfig } from 'payload' + +import { baseRelationshipFields } from '../../baseFields.js' +import { relationFalseFilterOptionSlug } from '../../slugs.js' + +export const RelationshipFilterFalse: CollectionConfig = { + admin: { + useAsTitle: 'name', + }, + fields: baseRelationshipFields, + slug: relationFalseFilterOptionSlug, +} diff --git a/test/fields-relationship/collections/FilterTrue/index.ts b/test/fields-relationship/collections/FilterTrue/index.ts new file mode 100644 index 0000000000..9adb2d734d --- /dev/null +++ b/test/fields-relationship/collections/FilterTrue/index.ts @@ -0,0 +1,12 @@ +import type { CollectionConfig } from 'payload' + +import { baseRelationshipFields } from '../../baseFields.js' +import { relationTrueFilterOptionSlug } from '../../slugs.js' + +export const RelationshipFilterTrue: CollectionConfig = { + admin: { + useAsTitle: 'name', + }, + fields: baseRelationshipFields, + slug: relationTrueFilterOptionSlug, +} diff --git a/test/fields-relationship/collections/MixedMedia/index.ts b/test/fields-relationship/collections/MixedMedia/index.ts new file mode 100644 index 0000000000..4a9acab8c6 --- /dev/null +++ b/test/fields-relationship/collections/MixedMedia/index.ts @@ -0,0 +1,19 @@ +import type { CollectionConfig } from 'payload' + +import { + mixedMediaCollectionSlug, + podcastCollectionSlug, + videoCollectionSlug, +} from '../../slugs.js' + +export const MixedMedia: CollectionConfig = { + slug: mixedMediaCollectionSlug, + fields: [ + { + type: 'relationship', + name: 'relatedMedia', + relationTo: [videoCollectionSlug, podcastCollectionSlug], + hasMany: true, + }, + ], +} diff --git a/test/fields-relationship/collections/Podcast/index.ts b/test/fields-relationship/collections/Podcast/index.ts new file mode 100644 index 0000000000..008338cabd --- /dev/null +++ b/test/fields-relationship/collections/Podcast/index.ts @@ -0,0 +1,21 @@ +import type { CollectionConfig } from 'payload' + +import { podcastCollectionSlug } from '../../slugs.js' + +export const Podcast: CollectionConfig = { + slug: podcastCollectionSlug, + admin: { + useAsTitle: 'title', + }, + fields: [ + { + name: 'id', + type: 'number', + required: true, + }, + { + name: 'title', + type: 'text', + }, + ], +} diff --git a/test/fields-relationship/collections/Relation1/index.ts b/test/fields-relationship/collections/Relation1/index.ts new file mode 100644 index 0000000000..7290875cf1 --- /dev/null +++ b/test/fields-relationship/collections/Relation1/index.ts @@ -0,0 +1,9 @@ +import type { CollectionConfig } from 'payload' + +import { baseRelationshipFields } from '../../baseFields.js' +import { relationOneSlug } from '../../slugs.js' + +export const Relation1: CollectionConfig = { + fields: baseRelationshipFields, + slug: relationOneSlug, +} diff --git a/test/fields-relationship/collections/Relation2/index.ts b/test/fields-relationship/collections/Relation2/index.ts new file mode 100644 index 0000000000..a1519d1df2 --- /dev/null +++ b/test/fields-relationship/collections/Relation2/index.ts @@ -0,0 +1,9 @@ +import type { CollectionConfig } from 'payload' + +import { baseRelationshipFields } from '../../baseFields.js' +import { relationTwoSlug } from '../../slugs.js' + +export const Relation2: CollectionConfig = { + fields: baseRelationshipFields, + slug: relationTwoSlug, +} diff --git a/test/fields-relationship/collections/RelationWithTitle/index.ts b/test/fields-relationship/collections/RelationWithTitle/index.ts new file mode 100644 index 0000000000..7c0f5346f3 --- /dev/null +++ b/test/fields-relationship/collections/RelationWithTitle/index.ts @@ -0,0 +1,25 @@ +import type { CollectionConfig } from 'payload' + +import { baseRelationshipFields } from '../../baseFields.js' +import { relationWithTitleSlug } from '../../slugs.js' + +export const RelationWithTitle: CollectionConfig = { + admin: { + useAsTitle: 'name', + }, + fields: [ + ...baseRelationshipFields, + { + name: 'meta', + fields: [ + { + name: 'title', + label: 'Meta Title', + type: 'text', + }, + ], + type: 'group', + }, + ], + slug: relationWithTitleSlug, +} diff --git a/test/fields-relationship/collections/Relationship/index.ts b/test/fields-relationship/collections/Relationship/index.ts new file mode 100644 index 0000000000..f23f78d632 --- /dev/null +++ b/test/fields-relationship/collections/Relationship/index.ts @@ -0,0 +1,130 @@ +import type { CollectionConfig, FilterOptionsProps } from 'payload' + +import type { FieldsRelationship } from '../../payload-types.js' + +import { + relationFalseFilterOptionSlug, + relationOneSlug, + relationRestrictedSlug, + relationTrueFilterOptionSlug, + relationTwoSlug, + relationWithTitleSlug, + slug, +} from '../../slugs.js' + +export const Relationship: CollectionConfig = { + admin: { + defaultColumns: [ + 'id', + 'relationship', + 'relationshipRestricted', + 'relationshipHasManyMultiple', + 'relationshipWithTitle', + ], + }, + fields: [ + { + name: 'relationship', + relationTo: relationOneSlug, + type: 'relationship', + }, + { + name: 'relationshipHasMany', + hasMany: true, + relationTo: relationOneSlug, + type: 'relationship', + }, + { + name: 'relationshipMultiple', + relationTo: [relationOneSlug, relationTwoSlug], + type: 'relationship', + }, + { + name: 'relationshipHasManyMultiple', + hasMany: true, + relationTo: [relationOneSlug, relationTwoSlug], + type: 'relationship', + }, + { + name: 'relationshipRestricted', + relationTo: relationRestrictedSlug, + type: 'relationship', + }, + { + name: 'relationshipWithTitle', + relationTo: relationWithTitleSlug, + type: 'relationship', + }, + { + name: 'relationshipFilteredByID', + filterOptions: (args: FilterOptionsProps) => { + return { + id: { + equals: args.data.relationship, + }, + } + }, + relationTo: relationOneSlug, + type: 'relationship', + admin: { + description: + 'This will filter the relationship options based on id, which is the same as the relationship field in this document', + }, + }, + { + name: 'relationshipFilteredAsync', + filterOptions: (args: FilterOptionsProps) => { + return { + id: { + equals: args.data.relationship, + }, + } + }, + relationTo: relationOneSlug, + type: 'relationship', + }, + { + name: 'relationshipManyFiltered', + filterOptions: ({ relationTo, siblingData }) => { + if (relationTo === relationOneSlug) { + return { name: { equals: 'include' } } + } + + if (relationTo === relationTrueFilterOptionSlug) { + return true + } + + if (relationTo === relationFalseFilterOptionSlug) { + return false + } + + if (siblingData.filter) { + return { name: { contains: siblingData.filter } } + } + + return { and: [] } + }, + hasMany: true, + relationTo: [ + relationWithTitleSlug, + relationFalseFilterOptionSlug, + relationTrueFilterOptionSlug, + relationOneSlug, + ], + type: 'relationship', + }, + { + name: 'filter', + type: 'text', + }, + { + name: 'relationshipReadOnly', + admin: { + readOnly: true, + }, + relationTo: relationOneSlug, + type: 'relationship', + }, + ], + slug, +} diff --git a/test/fields-relationship/collections/RelationshipFiltered/index.ts b/test/fields-relationship/collections/RelationshipFiltered/index.ts new file mode 100644 index 0000000000..01288a6ccb --- /dev/null +++ b/test/fields-relationship/collections/RelationshipFiltered/index.ts @@ -0,0 +1,16 @@ +import type { CollectionConfig } from 'payload' + +import { collection1Slug } from '../../slugs.js' + +export const Collection1: CollectionConfig = { + fields: [ + { + name: 'name', + type: 'text', + }, + ], + slug: collection1Slug, + admin: { + useAsTitle: 'name', + }, +} diff --git a/test/fields-relationship/collections/Restricted/index.ts b/test/fields-relationship/collections/Restricted/index.ts new file mode 100644 index 0000000000..897d1a7b7f --- /dev/null +++ b/test/fields-relationship/collections/Restricted/index.ts @@ -0,0 +1,16 @@ +import type { CollectionConfig } from 'payload' + +import { baseRelationshipFields } from '../../baseFields.js' +import { relationRestrictedSlug } from '../../slugs.js' + +export const Restricted: CollectionConfig = { + access: { + create: () => false, + read: () => false, + }, + admin: { + useAsTitle: 'name', + }, + fields: baseRelationshipFields, + slug: relationRestrictedSlug, +} diff --git a/test/fields-relationship/collections/UpdatedExternally/index.ts b/test/fields-relationship/collections/UpdatedExternally/index.ts new file mode 100644 index 0000000000..8d208a4000 --- /dev/null +++ b/test/fields-relationship/collections/UpdatedExternally/index.ts @@ -0,0 +1,99 @@ +import type { CollectionConfig } from 'payload' + +import { collection1Slug, collection2Slug, relationUpdatedExternallySlug } from '../../slugs.js' + +export const RelationshipUpdatedExternally: CollectionConfig = { + fields: [ + { + fields: [ + { + name: 'relationPrePopulate', + admin: { + width: '75%', + }, + relationTo: collection1Slug, + type: 'relationship', + }, + { + name: 'prePopulate', + admin: { + components: { + Field: { + path: '/PrePopulateFieldUI/index.js#PrePopulateFieldUI', + clientProps: { + hasMany: false, + hasMultipleRelations: false, + targetFieldPath: 'relationPrePopulate', + }, + }, + }, + width: '25%', + }, + type: 'ui', + }, + ], + type: 'row', + }, + { + fields: [ + { + name: 'relationHasMany', + admin: { + width: '75%', + }, + hasMany: true, + relationTo: collection1Slug, + type: 'relationship', + }, + { + name: 'prePopulateRelationHasMany', + admin: { + components: { + Field: { + path: '/PrePopulateFieldUI/index.js#PrePopulateFieldUI', + clientProps: { + hasMultipleRelations: false, + targetFieldPath: 'relationHasMany', + }, + }, + }, + width: '25%', + }, + type: 'ui', + }, + ], + type: 'row', + }, + { + fields: [ + { + name: 'relationToManyHasMany', + admin: { + width: '75%', + }, + hasMany: true, + relationTo: [collection1Slug, collection2Slug], + type: 'relationship', + }, + { + name: 'prePopulateToMany', + admin: { + components: { + Field: { + path: '/PrePopulateFieldUI/index.js#PrePopulateFieldUI', + clientProps: { + hasMultipleRelations: true, + targetFieldPath: 'relationToManyHasMany', + }, + }, + }, + width: '25%', + }, + type: 'ui', + }, + ], + type: 'row', + }, + ], + slug: relationUpdatedExternallySlug, +} diff --git a/test/fields-relationship/collections/VersionedRelationshipField/index.ts b/test/fields-relationship/collections/Versions/index.ts similarity index 80% rename from test/fields-relationship/collections/VersionedRelationshipField/index.ts rename to test/fields-relationship/collections/Versions/index.ts index a87e5ffb71..76bc62af12 100644 --- a/test/fields-relationship/collections/VersionedRelationshipField/index.ts +++ b/test/fields-relationship/collections/Versions/index.ts @@ -1,8 +1,8 @@ import type { CollectionConfig } from 'payload' -import { collection1Slug, versionedRelationshipFieldSlug } from '../../collectionSlugs.js' +import { collection1Slug, versionedRelationshipFieldSlug } from '../../slugs.js' -export const VersionedRelationshipFieldCollection: CollectionConfig = { +export const Versions: CollectionConfig = { slug: versionedRelationshipFieldSlug, fields: [ { diff --git a/test/fields-relationship/collections/Video/index.ts b/test/fields-relationship/collections/Video/index.ts new file mode 100644 index 0000000000..8d2baf339d --- /dev/null +++ b/test/fields-relationship/collections/Video/index.ts @@ -0,0 +1,21 @@ +import type { CollectionConfig } from 'payload' + +import { videoCollectionSlug } from '../../slugs.js' + +export const Video: CollectionConfig = { + slug: videoCollectionSlug, + admin: { + useAsTitle: 'title', + }, + fields: [ + { + name: 'id', + type: 'number', + required: true, + }, + { + name: 'title', + type: 'text', + }, + ], +} diff --git a/test/fields-relationship/config.ts b/test/fields-relationship/config.ts index b963ef0d48..2ce7562f6f 100644 --- a/test/fields-relationship/config.ts +++ b/test/fields-relationship/config.ts @@ -2,54 +2,23 @@ import { fileURLToPath } from 'node:url' import path from 'path' const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) -import type { CollectionConfig, FilterOptionsProps } from 'payload' import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js' -import { devUser } from '../credentials.js' -import { VersionedRelationshipFieldCollection } from './collections/VersionedRelationshipField/index.js' -import { - collection1Slug, - collection2Slug, - mixedMediaCollectionSlug, - podcastCollectionSlug, - relationFalseFilterOptionSlug, - relationOneSlug, - relationRestrictedSlug, - relationTrueFilterOptionSlug, - relationTwoSlug, - relationUpdatedExternallySlug, - relationWithTitleSlug, - slug, - videoCollectionSlug, -} from './collectionSlugs.js' - -export interface FieldsRelationship { - createdAt: Date - id: string - relationship: RelationOne - relationshipHasMany: RelationOne[] - relationshipHasManyMultiple: Array<{ relationTo: string; value: string } | RelationOne> - relationshipMultiple: Array - relationshipRestricted: RelationRestricted - relationshipWithTitle: RelationWithTitle - updatedAt: Date -} - -export interface RelationOne { - id: string - name: string -} - -export type RelationTwo = RelationOne -export type RelationRestricted = RelationOne -export type RelationWithTitle = RelationOne - -const baseRelationshipFields: CollectionConfig['fields'] = [ - { - name: 'name', - type: 'text', - }, -] +import { Collection1 } from './collections/Collection1/index.js' +import { Collection2 } from './collections/Collection2/index.js' +import { RelationshipFilterFalse } from './collections/FilterFalse/index.js' +import { RelationshipFilterTrue } from './collections/FilterTrue/index.js' +import { MixedMedia } from './collections/MixedMedia/index.js' +import { Podcast } from './collections/Podcast/index.js' +import { Relation1 } from './collections/Relation1/index.js' +import { Relation2 } from './collections/Relation2/index.js' +import { Relationship } from './collections/Relationship/index.js' +import { RelationWithTitle } from './collections/RelationWithTitle/index.js' +import { Restricted } from './collections/Restricted/index.js' +import { RelationshipUpdatedExternally } from './collections/UpdatedExternally/index.js' +import { Versions } from './collections/Versions/index.js' +import { Video } from './collections/Video/index.js' +import { clearAndSeedEverything } from './seed.js' export default buildConfigWithDefaults({ admin: { @@ -58,329 +27,20 @@ export default buildConfigWithDefaults({ }, }, collections: [ - { - admin: { - defaultColumns: [ - 'id', - 'relationship', - 'relationshipRestricted', - 'relationshipHasManyMultiple', - 'relationshipWithTitle', - ], - }, - fields: [ - { - name: 'relationship', - relationTo: relationOneSlug, - type: 'relationship', - }, - { - name: 'relationshipHasMany', - hasMany: true, - relationTo: relationOneSlug, - type: 'relationship', - }, - { - name: 'relationshipMultiple', - relationTo: [relationOneSlug, relationTwoSlug], - type: 'relationship', - }, - { - name: 'relationshipHasManyMultiple', - hasMany: true, - relationTo: [relationOneSlug, relationTwoSlug], - type: 'relationship', - }, - { - name: 'relationshipRestricted', - relationTo: relationRestrictedSlug, - type: 'relationship', - }, - { - name: 'relationshipWithTitle', - relationTo: relationWithTitleSlug, - type: 'relationship', - }, - { - name: 'relationshipFiltered', - filterOptions: (args: FilterOptionsProps) => { - return { - id: { - equals: args.data.relationship, - }, - } - }, - relationTo: relationOneSlug, - type: 'relationship', - }, - { - name: 'relationshipFilteredAsync', - filterOptions: (args: FilterOptionsProps) => { - return { - id: { - equals: args.data.relationship, - }, - } - }, - relationTo: relationOneSlug, - type: 'relationship', - }, - { - name: 'relationshipManyFiltered', - filterOptions: ({ relationTo, siblingData }: any) => { - if (relationTo === relationOneSlug) { - return { name: { equals: 'include' } } - } - if (relationTo === relationTrueFilterOptionSlug) { - return true - } - if (relationTo === relationFalseFilterOptionSlug) { - return false - } - if (siblingData.filter) { - return { name: { contains: siblingData.filter } } - } - return { and: [] } - }, - hasMany: true, - relationTo: [ - relationWithTitleSlug, - relationFalseFilterOptionSlug, - relationTrueFilterOptionSlug, - relationOneSlug, - ], - type: 'relationship', - }, - { - name: 'filter', - type: 'text', - }, - { - name: 'relationshipReadOnly', - admin: { - readOnly: true, - }, - relationTo: relationOneSlug, - type: 'relationship', - }, - ], - slug, - }, - { - admin: { - useAsTitle: 'name', - }, - fields: baseRelationshipFields, - slug: relationFalseFilterOptionSlug, - }, - { - admin: { - useAsTitle: 'name', - }, - fields: baseRelationshipFields, - slug: relationTrueFilterOptionSlug, - }, - { - fields: baseRelationshipFields, - slug: relationOneSlug, - }, - { - fields: baseRelationshipFields, - slug: relationTwoSlug, - }, - { - access: { - create: () => false, - read: () => false, - }, - admin: { - useAsTitle: 'name', - }, - fields: baseRelationshipFields, - slug: relationRestrictedSlug, - }, - { - admin: { - useAsTitle: 'name', - }, - fields: [ - ...baseRelationshipFields, - { - name: 'meta', - fields: [ - { - name: 'title', - label: 'Meta Title', - type: 'text', - }, - ], - type: 'group', - }, - ], - slug: relationWithTitleSlug, - }, - { - fields: [ - { - fields: [ - { - name: 'relationPrePopulate', - admin: { - width: '75%', - }, - relationTo: collection1Slug, - type: 'relationship', - }, - { - name: 'prePopulate', - admin: { - components: { - Field: { - path: '/PrePopulateFieldUI/index.js#PrePopulateFieldUI', - clientProps: { - hasMany: false, - hasMultipleRelations: false, - targetFieldPath: 'relationPrePopulate', - }, - }, - }, - width: '25%', - }, - type: 'ui', - }, - ], - type: 'row', - }, - { - fields: [ - { - name: 'relationHasMany', - admin: { - width: '75%', - }, - hasMany: true, - relationTo: collection1Slug, - type: 'relationship', - }, - { - name: 'prePopulateRelationHasMany', - admin: { - components: { - Field: { - path: '/PrePopulateFieldUI/index.js#PrePopulateFieldUI', - clientProps: { - hasMultipleRelations: false, - targetFieldPath: 'relationHasMany', - }, - }, - }, - width: '25%', - }, - type: 'ui', - }, - ], - type: 'row', - }, - { - fields: [ - { - name: 'relationToManyHasMany', - admin: { - width: '75%', - }, - hasMany: true, - relationTo: [collection1Slug, collection2Slug], - type: 'relationship', - }, - { - name: 'prePopulateToMany', - admin: { - components: { - Field: { - path: '/PrePopulateFieldUI/index.js#PrePopulateFieldUI', - clientProps: { - hasMultipleRelations: true, - targetFieldPath: 'relationToManyHasMany', - }, - }, - }, - width: '25%', - }, - type: 'ui', - }, - ], - type: 'row', - }, - ], - slug: relationUpdatedExternallySlug, - }, - { - fields: [ - { - name: 'name', - type: 'text', - }, - ], - slug: collection1Slug, - admin: { - useAsTitle: 'name', - }, - }, - { - fields: [ - { - name: 'name', - type: 'text', - }, - ], - slug: collection2Slug, - }, - { - slug: videoCollectionSlug, - admin: { - useAsTitle: 'title', - }, - fields: [ - { - name: 'id', - type: 'number', - required: true, - }, - { - name: 'title', - type: 'text', - }, - ], - }, - { - slug: podcastCollectionSlug, - admin: { - useAsTitle: 'title', - }, - fields: [ - { - name: 'id', - type: 'number', - required: true, - }, - { - name: 'title', - type: 'text', - }, - ], - }, - { - slug: mixedMediaCollectionSlug, - fields: [ - { - type: 'relationship', - name: 'relatedMedia', - relationTo: [videoCollectionSlug, podcastCollectionSlug], - hasMany: true, - }, - ], - }, - VersionedRelationshipFieldCollection, + Relationship, + RelationshipFilterFalse, + RelationshipFilterTrue, + Relation1, + Relation2, + Restricted, + RelationWithTitle, + RelationshipUpdatedExternally, + Collection1, + Collection2, + Video, + Podcast, + MixedMedia, + Versions, ], localization: { locales: ['en'], @@ -388,156 +48,8 @@ export default buildConfigWithDefaults({ fallback: true, }, onInit: async (payload) => { - await payload.create({ - collection: 'users', - data: { - email: devUser.email, - password: devUser.password, - }, - depth: 0, - overrideAccess: true, - }) - // Create docs to relate to - const { id: relationOneDocId } = await payload.create({ - collection: relationOneSlug, - data: { - name: relationOneSlug, - }, - depth: 0, - overrideAccess: true, - }) - - const relationOneIDs: string[] = [] - - for (let i = 0; i < 11; i++) { - const doc = await payload.create({ - collection: relationOneSlug, - data: { - name: relationOneSlug, - }, - depth: 0, - overrideAccess: true, - }) - relationOneIDs.push(doc.id) - } - - const relationTwoIDs: string[] = [] - for (let i = 0; i < 11; i++) { - const doc = await payload.create({ - collection: relationTwoSlug, - data: { - name: relationTwoSlug, - }, - depth: 0, - overrideAccess: true, - }) - relationTwoIDs.push(doc.id) - } - - // Existing relationships - const { id: restrictedDocId } = await payload.create({ - collection: relationRestrictedSlug, - data: { - name: 'relation-restricted', - }, - depth: 0, - overrideAccess: true, - }) - - const relationsWithTitle: string[] = [] - for (const title of ['relation-title', 'word boundary search']) { - const { id } = await payload.create({ - collection: relationWithTitleSlug, - depth: 0, - overrideAccess: true, - data: { - name: title, - meta: { - title, - }, - }, - }) - relationsWithTitle.push(id) - } - - await payload.create({ - collection: slug, - depth: 0, - overrideAccess: true, - data: { - relationship: relationOneDocId, - relationshipRestricted: restrictedDocId, - relationshipWithTitle: relationsWithTitle[0], - }, - }) - - for (let i = 0; i < 11; i++) { - await payload.create({ - collection: slug, - depth: 0, - overrideAccess: true, - data: { - relationship: relationOneDocId, - relationshipHasManyMultiple: relationOneIDs.map((id) => ({ - relationTo: relationOneSlug, - value: id, - })), - relationshipRestricted: restrictedDocId, - }, - }) - } - - for (let i = 0; i < 15; i++) { - const relationOneID = relationOneIDs[Math.floor(Math.random() * 10)] - const relationTwoID = relationTwoIDs[Math.floor(Math.random() * 10)] - await payload.create({ - collection: slug, - depth: 0, - overrideAccess: true, - data: { - relationship: relationOneDocId, - relationshipHasMany: [relationOneID], - relationshipHasManyMultiple: [{ relationTo: relationTwoSlug, value: relationTwoID }], - relationshipReadOnly: relationOneID, - relationshipRestricted: restrictedDocId, - }, - }) - } - - for (let i = 0; i < 15; i++) { - await payload.create({ - collection: collection1Slug, - depth: 0, - overrideAccess: true, - data: { - name: `relationship-test ${i}`, - }, - }) - await payload.create({ - collection: collection2Slug, - depth: 0, - overrideAccess: true, - data: { - name: `relationship-test ${i}`, - }, - }) - } - - for (let i = 0; i < 2; i++) { - await payload.create({ - collection: videoCollectionSlug, - data: { - id: i, - title: `Video ${i}`, - }, - }) - await payload.create({ - collection: podcastCollectionSlug, - data: { - id: i, - title: `Podcast ${i}`, - }, - }) + if (process.env.SEED_IN_CONFIG_ONINIT !== 'false') { + await clearAndSeedEverything(payload) } }, typescript: { diff --git a/test/fields-relationship/e2e.spec.ts b/test/fields-relationship/e2e.spec.ts index dbd97e5704..7d1f7f75f6 100644 --- a/test/fields-relationship/e2e.spec.ts +++ b/test/fields-relationship/e2e.spec.ts @@ -42,7 +42,7 @@ import { relationWithTitleSlug, slug, versionedRelationshipFieldSlug, -} from './collectionSlugs.js' +} from './slugs.js' const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) @@ -305,97 +305,99 @@ describe('Relationship Field', () => { await saveDocAndAssert(page) } - // TODO: Flaky test. Fix this! (This is an actual issue not just an e2e flake) - test('should allow dynamic filterOptions', async () => { - await runFilterOptionsTest('relationshipFiltered', 'Relationship Filtered') - }) - - // TODO: Flaky test. Fix this! (This is an actual issue not just an e2e flake) - test('should allow dynamic async filterOptions', async () => { - await runFilterOptionsTest('relationshipFilteredAsync', 'Relationship Filtered Async') - }) - - test('should allow usage of relationTo in filterOptions', async () => { - const { id: include } = (await payload.create({ - collection: relationOneSlug, - data: { - name: 'include', - }, - })) as any - const { id: exclude } = (await payload.create({ - collection: relationOneSlug, - data: { - name: 'exclude', - }, - })) as any - - await page.goto(url.create) - - // select relationshipMany field that relies on siblingData field above - await page.locator('#field-relationshipManyFiltered .rs__control').click() - - const options = page.locator('#field-relationshipManyFiltered .rs__menu') - await expect(options).toContainText(include) - await expect(options).not.toContainText(exclude) - }) - - test('should allow usage of siblingData in filterOptions', async () => { - await payload.create({ - collection: relationWithTitleSlug, - data: { - name: 'exclude', - }, + describe('filterOptions', () => { + // TODO: Flaky test. Fix this! (This is an actual issue not just an e2e flake) + test('should allow dynamic filterOptions', async () => { + await runFilterOptionsTest('relationshipFilteredByID', 'Relationship Filtered') }) - await page.goto(url.create) - - // enter a filter for relationshipManyFiltered to use - await page.locator('#field-filter').fill('include') - - // select relationshipMany field that relies on siblingData field above - await page.locator('#field-relationshipManyFiltered .rs__control').click() - - const options = page.locator('#field-relationshipManyFiltered .rs__menu') - await expect(options).not.toContainText('exclude') - }) - - // TODO: Flaky test in CI - fix. https://github.com/payloadcms/payload/actions/runs/8559547748/job/23456806365 - test.skip('should not query for a relationship when filterOptions returns false', async () => { - await payload.create({ - collection: relationFalseFilterOptionSlug, - data: { - name: 'whatever', - }, + // TODO: Flaky test. Fix this! (This is an actual issue not just an e2e flake) + test('should allow dynamic async filterOptions', async () => { + await runFilterOptionsTest('relationshipFilteredAsync', 'Relationship Filtered Async') }) - await page.goto(url.create) + test('should allow usage of relationTo in filterOptions', async () => { + const { id: include } = (await payload.create({ + collection: relationOneSlug, + data: { + name: 'include', + }, + })) as any + const { id: exclude } = (await payload.create({ + collection: relationOneSlug, + data: { + name: 'exclude', + }, + })) as any - // select relationshipMany field that relies on siblingData field above - await page.locator('#field-relationshipManyFiltered .rs__control').click() + await page.goto(url.create) - const options = page.locator('#field-relationshipManyFiltered .rs__menu') - await expect(options).toContainText('Relation With Titles') - await expect(options).not.toContainText('whatever') - }) + // select relationshipMany field that relies on siblingData field above + await page.locator('#field-relationshipManyFiltered .rs__control').click() - // TODO: Flaky test in CI - fix. - test('should show a relationship when filterOptions returns true', async () => { - await payload.create({ - collection: relationTrueFilterOptionSlug, - data: { - name: 'truth', - }, + const options = page.locator('#field-relationshipManyFiltered .rs__menu') + await expect(options).toContainText(include) + await expect(options).not.toContainText(exclude) }) - await page.goto(url.create) - // wait for relationship options to load - const relationFilterOptionsReq = page.waitForResponse(/api\/relation-filter-true/) - // select relationshipMany field that relies on siblingData field above - await page.locator('#field-relationshipManyFiltered .rs__control').click() - await relationFilterOptionsReq + test('should allow usage of siblingData in filterOptions', async () => { + await payload.create({ + collection: relationWithTitleSlug, + data: { + name: 'exclude', + }, + }) - const options = page.locator('#field-relationshipManyFiltered .rs__menu') - await expect(options).toContainText('truth') + await page.goto(url.create) + + // enter a filter for relationshipManyFiltered to use + await page.locator('#field-filter').fill('include') + + // select relationshipMany field that relies on siblingData field above + await page.locator('#field-relationshipManyFiltered .rs__control').click() + + const options = page.locator('#field-relationshipManyFiltered .rs__menu') + await expect(options).not.toContainText('exclude') + }) + + // TODO: Flaky test in CI - fix. https://github.com/payloadcms/payload/actions/runs/8559547748/job/23456806365 + test.skip('should not query for a relationship when filterOptions returns false', async () => { + await payload.create({ + collection: relationFalseFilterOptionSlug, + data: { + name: 'whatever', + }, + }) + + await page.goto(url.create) + + // select relationshipMany field that relies on siblingData field above + await page.locator('#field-relationshipManyFiltered .rs__control').click() + + const options = page.locator('#field-relationshipManyFiltered .rs__menu') + await expect(options).toContainText('Relation With Titles') + await expect(options).not.toContainText('whatever') + }) + + // TODO: Flaky test in CI - fix. + test('should show a relationship when filterOptions returns true', async () => { + await payload.create({ + collection: relationTrueFilterOptionSlug, + data: { + name: 'truth', + }, + }) + + await page.goto(url.create) + // wait for relationship options to load + const relationFilterOptionsReq = page.waitForResponse(/api\/relation-filter-true/) + // select relationshipMany field that relies on siblingData field above + await page.locator('#field-relationshipManyFiltered .rs__control').click() + await relationFilterOptionsReq + + const options = page.locator('#field-relationshipManyFiltered .rs__menu') + await expect(options).toContainText('truth') + }) }) test('should allow docs with same ID but different collections to be selectable', async () => { diff --git a/test/fields-relationship/int.spec.ts b/test/fields-relationship/int.spec.ts index 34eaeeee96..6cc4d164d2 100644 --- a/test/fields-relationship/int.spec.ts +++ b/test/fields-relationship/int.spec.ts @@ -8,7 +8,7 @@ import type { Collection1 } from './payload-types.js' import { devUser } from '../credentials.js' import { initPayloadInt } from '../helpers/initPayloadInt.js' -import { collection1Slug, versionedRelationshipFieldSlug } from './collectionSlugs.js' +import { collection1Slug, versionedRelationshipFieldSlug } from './slugs.js' let payload: Payload let restClient: NextRESTClient diff --git a/test/fields-relationship/payload-types.ts b/test/fields-relationship/payload-types.ts index 8f61712d35..6ae40d8c71 100644 --- a/test/fields-relationship/payload-types.ts +++ b/test/fields-relationship/payload-types.ts @@ -114,7 +114,14 @@ export interface FieldsRelationship { | null; relationshipRestricted?: (string | null) | RelationRestricted; relationshipWithTitle?: (string | null) | RelationWithTitle; - relationshipFiltered?: (string | null) | RelationOne; + /** + * This will filter the relationship options based on id, which is the same as the relationship field in this document + */ + relationshipFilteredByID?: (string | null) | RelationOne; + /** + * This will filter the relationship options if the filter field in this document is set to "Include me" + */ + relationshipFilteredByField?: (string | null) | RelationOne; relationshipFilteredAsync?: (string | null) | RelationOne; relationshipManyFiltered?: | ( @@ -442,7 +449,8 @@ export interface FieldsRelationshipSelect { relationshipHasManyMultiple?: T; relationshipRestricted?: T; relationshipWithTitle?: T; - relationshipFiltered?: T; + relationshipFilteredByID?: T; + relationshipFilteredByField?: T; relationshipFilteredAsync?: T; relationshipManyFiltered?: T; filter?: T; diff --git a/test/fields-relationship/seed.ts b/test/fields-relationship/seed.ts new file mode 100644 index 0000000000..3e5577b5b1 --- /dev/null +++ b/test/fields-relationship/seed.ts @@ -0,0 +1,191 @@ +import type { Payload } from 'payload' + +import path from 'path' +import { fileURLToPath } from 'url' + +import { devUser } from '../credentials.js' +import { seedDB } from '../helpers/seed.js' +import { + collection1Slug, + collection2Slug, + collectionSlugs, + podcastCollectionSlug, + relationOneSlug, + relationRestrictedSlug, + relationTwoSlug, + relationWithTitleSlug, + slug, + videoCollectionSlug, +} from './slugs.js' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export const seed = async (_payload: Payload) => { + await _payload.create({ + collection: 'users', + data: { + email: devUser.email, + password: devUser.password, + }, + depth: 0, + overrideAccess: true, + }) + + // Create docs to relate to + const { id: relationOneDocId } = await _payload.create({ + collection: relationOneSlug, + data: { + name: relationOneSlug, + }, + depth: 0, + overrideAccess: true, + }) + + const relationOneIDs: string[] = [] + + for (let i = 0; i < 11; i++) { + const doc = await _payload.create({ + collection: relationOneSlug, + data: { + name: relationOneSlug, + }, + depth: 0, + overrideAccess: true, + }) + relationOneIDs.push(doc.id) + } + + const relationTwoIDs: string[] = [] + for (let i = 0; i < 11; i++) { + const doc = await _payload.create({ + collection: relationTwoSlug, + data: { + name: relationTwoSlug, + }, + depth: 0, + overrideAccess: true, + }) + relationTwoIDs.push(doc.id) + } + + // Existing relationships + const { id: restrictedDocId } = await _payload.create({ + collection: relationRestrictedSlug, + data: { + name: 'relation-restricted', + }, + depth: 0, + overrideAccess: true, + }) + + const relationsWithTitle: string[] = [] + + for (const title of ['relation-title', 'word boundary search']) { + const { id } = await _payload.create({ + collection: relationWithTitleSlug, + depth: 0, + overrideAccess: true, + data: { + name: title, + meta: { + title, + }, + }, + }) + relationsWithTitle.push(id) + } + + await _payload.create({ + collection: slug, + depth: 0, + overrideAccess: true, + data: { + relationship: relationOneDocId, + relationshipRestricted: restrictedDocId, + relationshipWithTitle: relationsWithTitle[0], + }, + }) + + for (let i = 0; i < 11; i++) { + await _payload.create({ + collection: slug, + depth: 0, + overrideAccess: true, + data: { + relationship: relationOneDocId, + relationshipHasManyMultiple: relationOneIDs.map((id) => ({ + relationTo: relationOneSlug, + value: id, + })), + relationshipRestricted: restrictedDocId, + }, + }) + } + + for (let i = 0; i < 15; i++) { + const relationOneID = relationOneIDs[Math.floor(Math.random() * 10)] + const relationTwoID = relationTwoIDs[Math.floor(Math.random() * 10)] + + await _payload.create({ + collection: slug, + depth: 0, + overrideAccess: true, + data: { + relationship: relationOneDocId, + relationshipHasMany: [relationOneID], + relationshipHasManyMultiple: [{ relationTo: relationTwoSlug, value: relationTwoID }], + relationshipReadOnly: relationOneID, + relationshipRestricted: restrictedDocId, + }, + }) + } + + for (let i = 0; i < 15; i++) { + await _payload.create({ + collection: collection1Slug, + depth: 0, + overrideAccess: true, + data: { + name: `relationship-test ${i}`, + }, + }) + + await _payload.create({ + collection: collection2Slug, + depth: 0, + overrideAccess: true, + data: { + name: `relationship-test ${i}`, + }, + }) + } + + for (let i = 0; i < 2; i++) { + await _payload.create({ + collection: videoCollectionSlug, + data: { + id: i, + title: `Video ${i}`, + }, + }) + + await _payload.create({ + collection: podcastCollectionSlug, + data: { + id: i, + title: `Podcast ${i}`, + }, + }) + } +} + +export async function clearAndSeedEverything(_payload: Payload) { + return await seedDB({ + _payload, + collectionSlugs, + seedFunction: seed, + snapshotKey: 'fieldsTest', + uploadsDir: path.resolve(dirname, './collections/Upload/uploads'), + }) +} diff --git a/test/fields-relationship/collectionSlugs.ts b/test/fields-relationship/slugs.ts similarity index 67% rename from test/fields-relationship/collectionSlugs.ts rename to test/fields-relationship/slugs.ts index a1b637ff5c..90d2c06085 100644 --- a/test/fields-relationship/collectionSlugs.ts +++ b/test/fields-relationship/slugs.ts @@ -13,3 +13,19 @@ export const videoCollectionSlug = 'videos' export const podcastCollectionSlug = 'podcasts' export const mixedMediaCollectionSlug = 'mixed-media' export const versionedRelationshipFieldSlug = 'versioned-relationship-field' + +export const collectionSlugs = [ + relationOneSlug, + relationTrueFilterOptionSlug, + relationFalseFilterOptionSlug, + relationTwoSlug, + relationRestrictedSlug, + relationWithTitleSlug, + relationUpdatedExternallySlug, + collection1Slug, + collection2Slug, + videoCollectionSlug, + podcastCollectionSlug, + mixedMediaCollectionSlug, + versionedRelationshipFieldSlug, +] diff --git a/test/fields/payload-types.ts b/test/fields/payload-types.ts index 25952d77af..23bf60aa59 100644 --- a/test/fields/payload-types.ts +++ b/test/fields/payload-types.ts @@ -1439,6 +1439,8 @@ export interface RelationshipField { | null; relationToRow?: (string | null) | RowField; relationToRowMany?: (string | RowField)[] | null; + disableRelation?: boolean | null; + filteredRelationship?: (string | null) | RelationshipField; updatedAt: string; createdAt: string; } @@ -3028,6 +3030,8 @@ export interface RelationshipFieldsSelect { relationshipWithMinRows?: T; relationToRow?: T; relationToRowMany?: T; + disableRelation?: T; + filteredRelationship?: T; updatedAt?: T; createdAt?: T; } diff --git a/test/uploads/e2e.spec.ts b/test/uploads/e2e.spec.ts index 189eda9587..1117212fa3 100644 --- a/test/uploads/e2e.spec.ts +++ b/test/uploads/e2e.spec.ts @@ -374,71 +374,73 @@ describe('Uploads', () => { await expect(page.locator('.row-3 .cell-title')).toContainText('draft') }) - test('should restrict mimetype based on filterOptions', async () => { - const audioDoc = ( - await payload.find({ - collection: audioSlug, - depth: 0, - pagination: false, - }) - ).docs[0] + describe('filterOptions', () => { + test('should restrict mimetype based on filterOptions', async () => { + const audioDoc = ( + await payload.find({ + collection: audioSlug, + depth: 0, + pagination: false, + }) + ).docs[0] - await page.goto(audioURL.edit(audioDoc.id)) - await page.waitForURL(audioURL.edit(audioDoc.id)) + await page.goto(audioURL.edit(audioDoc.id)) + await page.waitForURL(audioURL.edit(audioDoc.id)) - // remove the selection and open the list drawer - await wait(500) // flake workaround - await page.locator('#field-audio .upload-relationship-details__remove').click() + // remove the selection and open the list drawer + await wait(500) // flake workaround + await page.locator('#field-audio .upload-relationship-details__remove').click() - await openDocDrawer(page, '#field-audio .upload__listToggler') + await openDocDrawer(page, '#field-audio .upload__listToggler') - const listDrawer = page.locator('[id^=list-drawer_1_]') - await expect(listDrawer).toBeVisible() + const listDrawer = page.locator('[id^=list-drawer_1_]') + await expect(listDrawer).toBeVisible() - await openDocDrawer(page, 'button.list-drawer__create-new-button.doc-drawer__toggler') - await expect(page.locator('[id^=doc-drawer_media_1_]')).toBeVisible() + await openDocDrawer(page, 'button.list-drawer__create-new-button.doc-drawer__toggler') + await expect(page.locator('[id^=doc-drawer_media_1_]')).toBeVisible() - // upload an image and try to select it - await page - .locator('[id^=doc-drawer_media_1_] .file-field__upload input[type="file"]') - .setInputFiles(path.resolve(dirname, './image.png')) - await page.locator('[id^=doc-drawer_media_1_] button#action-save').click() - await expect(page.locator('.payload-toast-container .toast-success')).toContainText( - 'successfully', - ) - await page - .locator('.payload-toast-container .toast-success .payload-toast-close-button') - .click() + // upload an image and try to select it + await page + .locator('[id^=doc-drawer_media_1_] .file-field__upload input[type="file"]') + .setInputFiles(path.resolve(dirname, './image.png')) + await page.locator('[id^=doc-drawer_media_1_] button#action-save').click() + await expect(page.locator('.payload-toast-container .toast-success')).toContainText( + 'successfully', + ) + await page + .locator('.payload-toast-container .toast-success .payload-toast-close-button') + .click() - // save the document and expect an error - await page.locator('button#action-save').click() - await expect(page.locator('.payload-toast-container .toast-error')).toContainText( - 'The following field is invalid: Audio', - ) - }) + // save the document and expect an error + await page.locator('button#action-save').click() + await expect(page.locator('.payload-toast-container .toast-error')).toContainText( + 'The following field is invalid: Audio', + ) + }) - test('should restrict uploads in drawer based on filterOptions', async () => { - const audioDoc = ( - await payload.find({ - collection: audioSlug, - depth: 0, - pagination: false, - }) - ).docs[0] + test('should restrict uploads in drawer based on filterOptions', async () => { + const audioDoc = ( + await payload.find({ + collection: audioSlug, + depth: 0, + pagination: false, + }) + ).docs[0] - await page.goto(audioURL.edit(audioDoc.id)) - await page.waitForURL(audioURL.edit(audioDoc.id)) + await page.goto(audioURL.edit(audioDoc.id)) + await page.waitForURL(audioURL.edit(audioDoc.id)) - // remove the selection and open the list drawer - await wait(500) // flake workaround - await page.locator('#field-audio .upload-relationship-details__remove').click() + // remove the selection and open the list drawer + await wait(500) // flake workaround + await page.locator('#field-audio .upload-relationship-details__remove').click() - await openDocDrawer(page, '.upload__listToggler') + await openDocDrawer(page, '.upload__listToggler') - const listDrawer = page.locator('[id^=list-drawer_1_]') - await expect(listDrawer).toBeVisible() + const listDrawer = page.locator('[id^=list-drawer_1_]') + await expect(listDrawer).toBeVisible() - await expect(listDrawer.locator('tbody tr')).toHaveCount(1) + await expect(listDrawer.locator('tbody tr')).toHaveCount(1) + }) }) test('should throw error when file is larger than the limit and abortOnLimit is true', async () => { diff --git a/tsconfig.base.json b/tsconfig.base.json index f5fbb754e7..16ab52137f 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -31,7 +31,7 @@ } ], "paths": { - "@payload-config": ["./test/plugin-search/config.ts"], + "@payload-config": ["./test/fields-relationship/config.ts"], "@payloadcms/live-preview": ["./packages/live-preview/src"], "@payloadcms/live-preview-react": ["./packages/live-preview-react/src/index.ts"], "@payloadcms/live-preview-vue": ["./packages/live-preview-vue/src/index.ts"],