From 270ac10fb4a3fb763f16f6cc0a96046ef95cf4f7 Mon Sep 17 00:00:00 2001 From: Jacob Fletcher Date: Mon, 30 Dec 2024 16:09:42 -0500 Subject: [PATCH] test: consolidates list view e2e tests (#10263) There were a handful of list view e2e tests written into the text and email field test suite, making them hard to find as they were isolated from other related tests. A few of these tests were also duplicative across suites, making CI run them twice unnecessarily. --- test/admin/collections/Posts.ts | 14 + test/admin/e2e/list-view/e2e.spec.ts | 309 ++++++++++--- test/admin/payload-types.ts | 4 + test/fields/collections/Email/e2e.spec.ts | 63 +-- test/fields/collections/Text/e2e.spec.ts | 226 ---------- test/fields/collections/Text/index.ts | 14 - test/fields/payload-types.ts | 501 +++++++++------------- test/joins/payload-types.ts | 6 - tsconfig.base.json | 2 +- 9 files changed, 474 insertions(+), 665 deletions(-) diff --git a/test/admin/collections/Posts.ts b/test/admin/collections/Posts.ts index 4882540bb5..1078f33617 100644 --- a/test/admin/collections/Posts.ts +++ b/test/admin/collections/Posts.ts @@ -182,6 +182,20 @@ export const Posts: CollectionConfig = { }, }, }, + { + name: 'disableListColumnText', + type: 'text', + admin: { + disableListColumn: true, + }, + }, + { + name: 'disableListFilterText', + type: 'text', + admin: { + disableListFilter: true, + }, + }, { name: 'sidebarField', type: 'text', diff --git a/test/admin/e2e/list-view/e2e.spec.ts b/test/admin/e2e/list-view/e2e.spec.ts index be5d44cb21..05a3f02418 100644 --- a/test/admin/e2e/list-view/e2e.spec.ts +++ b/test/admin/e2e/list-view/e2e.spec.ts @@ -119,7 +119,37 @@ describe('List View', () => { }) }) - describe('filtering', () => { + describe('list view table', () => { + test('should link second cell', async () => { + const { id } = await createPost() + await page.reload() + const linkCell = page.locator(`${tableRowLocator} td`).nth(1).locator('a') + + await expect(linkCell).toHaveAttribute( + 'href', + `${adminRoutes.routes.admin}/collections/posts/${id}`, + ) + + await page.locator('.list-controls__toggle-columns').click() + await expect(page.locator('.list-controls__columns.rah-static--height-auto')).toBeVisible() + + await page + .locator('.column-selector .column-selector__column', { + hasText: exactText('ID'), + }) + .click() + + await page.locator('#heading-id').waitFor({ state: 'detached' }) + await page.locator('.cell-id').first().waitFor({ state: 'detached' }) + + await expect(linkCell).toHaveAttribute( + 'href', + `${adminRoutes.routes.admin}/collections/posts/${id}`, + ) + }) + }) + + describe('search', () => { test('should prefill search input from query param', async () => { await createPost({ title: 'dennis' }) await createPost({ title: 'charlie' }) @@ -191,51 +221,13 @@ describe('List View', () => { await expect(page.locator('#search-filter-input')).toHaveValue('') }) + }) - test('should toggle columns', async () => { - const columnCountLocator = 'table > thead > tr > th' - await createPost() - await openListColumns(page, {}) - const numberOfColumns = await page.locator(columnCountLocator).count() - await expect(page.locator('.column-selector')).toBeVisible() - await expect(page.locator('table > thead > tr > th:nth-child(2)')).toHaveText('ID') - await toggleColumn(page, { columnLabel: 'ID', targetState: 'off' }) - await page.locator('#heading-id').waitFor({ state: 'detached' }) - await page.locator('.cell-id').first().waitFor({ state: 'detached' }) - await expect(page.locator(columnCountLocator)).toHaveCount(numberOfColumns - 1) - await expect(page.locator('table > thead > tr > th:nth-child(2)')).toHaveText('Number') - await toggleColumn(page, { columnLabel: 'ID', targetState: 'on' }) - await expect(page.locator('.cell-id').first()).toBeVisible() - await expect(page.locator(columnCountLocator)).toHaveCount(numberOfColumns) - await expect(page.locator('table > thead > tr > th:nth-child(2)')).toHaveText('ID') - }) - - test('should link second cell', async () => { - const { id } = await createPost() - await page.reload() - const linkCell = page.locator(`${tableRowLocator} td`).nth(1).locator('a') - - await expect(linkCell).toHaveAttribute( - 'href', - `${adminRoutes.routes.admin}/collections/posts/${id}`, - ) - - await page.locator('.list-controls__toggle-columns').click() - await expect(page.locator('.list-controls__columns.rah-static--height-auto')).toBeVisible() - - await page - .locator('.column-selector .column-selector__column', { - hasText: exactText('ID'), - }) - .click() - - await page.locator('#heading-id').waitFor({ state: 'detached' }) - await page.locator('.cell-id').first().waitFor({ state: 'detached' }) - - await expect(linkCell).toHaveAttribute( - 'href', - `${adminRoutes.routes.admin}/collections/posts/${id}`, - ) + describe('filters', () => { + test('should respect base list filters', async () => { + await page.goto(baseListFiltersUrl.list) + await page.waitForURL((url) => url.toString().startsWith(baseListFiltersUrl.list)) + await expect(page.locator(tableRowLocator)).toHaveCount(1) }) test('should filter rows', async () => { @@ -452,9 +444,228 @@ describe('List View', () => { await page.waitForURL(new RegExp(`${postsUrl.list}\\?limit=5&page=1`)) await expect(page.locator('.collection-list__page-info')).toHaveText('1-3 of 3') }) + + test('should reset filter values for every additional filters', async () => { + await page.goto(postsUrl.list) + await openListFilters(page, {}) + await page.locator('.where-builder__add-first-filter').click() + const firstConditionField = page.locator('.condition__field') + const firstOperatorField = page.locator('.condition__operator') + const firstValueField = page.locator('.condition__value >> input') + + await firstConditionField.click() + await firstConditionField + .locator('.rs__option', { + hasText: exactText('Tab 1 > Title'), + }) + .click() + + await expect(firstConditionField.locator('.rs__single-value')).toContainText('Tab 1 > Title') + await firstOperatorField.click() + await firstOperatorField.locator('.rs__option').locator('text=equals').click() + await firstValueField.fill('Test') + await expect(firstValueField).toHaveValue('Test') + await page.locator('.condition__actions-add').click() + const secondLi = page.locator('.where-builder__and-filters li:nth-child(2)') + await expect(secondLi).toBeVisible() + + await expect( + secondLi.locator('.condition__field').locator('.rs__single-value'), + ).toContainText('Tab 1 > Title') + + await expect(secondLi.locator('.condition__operator >> input')).toHaveValue('') + await expect(secondLi.locator('.condition__value >> input')).toHaveValue('') + }) + + test('should not re-render page upon typing in a value in the filter value field', async () => { + await page.goto(postsUrl.list) + await openListFilters(page, {}) + await page.locator('.where-builder__add-first-filter').click() + const firstConditionField = page.locator('.condition__field') + const firstOperatorField = page.locator('.condition__operator') + const firstValueField = page.locator('.condition__value >> input') + + await firstConditionField.click() + await firstConditionField + .locator('.rs__option', { hasText: exactText('Tab 1 > Title') }) + .click() + await expect(firstConditionField.locator('.rs__single-value')).toContainText('Tab 1 > Title') + + await firstOperatorField.click() + await firstOperatorField.locator('.rs__option').locator('text=equals').click() + + // Type into the input field instead of filling it + await firstValueField.click() + await firstValueField.type('Test', { delay: 100 }) // Add a delay to simulate typing speed + + // Wait for a short period to see if the input loses focus + await page.waitForTimeout(500) + + // Check if the input still has the correct value + await expect(firstValueField).toHaveValue('Test') + }) + + test('should still show second filter if two filters exist and first filter is removed', async () => { + await page.goto(postsUrl.list) + await openListFilters(page, {}) + await page.locator('.where-builder__add-first-filter').click() + const firstConditionField = page.locator('.condition__field') + const firstOperatorField = page.locator('.condition__operator') + const firstValueField = page.locator('.condition__value >> input') + await firstConditionField.click() + await firstConditionField + .locator('.rs__option', { hasText: exactText('Tab 1 > Title') }) + .click() + await expect(firstConditionField.locator('.rs__single-value')).toContainText('Tab 1 > Title') + await firstOperatorField.click() + await firstOperatorField.locator('.rs__option').locator('text=equals').click() + await firstValueField.fill('Test 1') + await expect(firstValueField).toHaveValue('Test 1') + + await wait(500) + + await page.locator('.condition__actions-add').click() + + const secondLi = page.locator('.where-builder__and-filters li:nth-child(2)') + await expect(secondLi).toBeVisible() + const secondConditionField = secondLi.locator('.condition__field') + const secondOperatorField = secondLi.locator('.condition__operator') + const secondValueField = secondLi.locator('.condition__value >> input') + await secondConditionField.click() + + await secondConditionField + .locator('.rs__option', { hasText: exactText('Tab 1 > Title') }) + .click() + + await expect(secondConditionField.locator('.rs__single-value')).toContainText('Tab 1 > Title') + await secondOperatorField.click() + await secondOperatorField.locator('.rs__option').locator('text=equals').click() + await secondValueField.fill('Test 2') + await expect(secondValueField).toHaveValue('Test 2') + + const firstLi = page.locator('.where-builder__and-filters li:nth-child(1)') + const removeButton = firstLi.locator('.condition__actions-remove') + + await wait(500) + + // remove first filter + await removeButton.click() + const filterListItems = page.locator('.where-builder__and-filters li') + await expect(filterListItems).toHaveCount(1) + await expect(firstValueField).toHaveValue('Test 2') + }) + + test('should hide field filter when admin.disableListFilter is true', async () => { + await page.goto(postsUrl.list) + await openListFilters(page, {}) + await page.locator('.where-builder__add-first-filter').click() + + const initialField = page.locator('.condition__field') + await initialField.click() + + await expect( + initialField.locator(`.rs__option :has-text("Disable List Filter Text")`), + ).toBeHidden() + }) + + test('should simply disable field filter when admin.disableListFilter is true but still exists in the query', async () => { + await page.goto( + `${postsUrl.list}${qs.stringify( + { + where: { + or: [ + { + and: [ + { + disableListFilterText: { + equals: 'Disable List Filter Text', + }, + }, + ], + }, + ], + }, + }, + { addQueryPrefix: true }, + )}`, + ) + + await openListFilters(page, {}) + + const condition = page.locator('.condition__field') + await expect(condition.locator('input.rs__input')).toBeDisabled() + await expect(page.locator('.condition__operator input.rs__input')).toBeDisabled() + await expect(page.locator('.condition__value input.condition-value-text')).toBeDisabled() + await expect(condition.locator('.rs__single-value')).toHaveText('Disable List Filter Text') + await page.locator('button.condition__actions-add').click() + const condition2 = page.locator('.condition__field').nth(1) + await condition2.click() + await expect( + condition2?.locator('.rs__menu-list:has-text("Disable List Filter Text")'), + ).toBeHidden() + }) }) describe('table columns', () => { + test('should hide field in column selector when admin.disableListColumn is true', async () => { + await page.goto(postsUrl.list) + await page.locator('.list-controls__toggle-columns').click() + + await expect(page.locator('.column-selector')).toBeVisible() + + // Check if "Disable List Column Text" is not present in the column options + await expect( + page.locator(`.column-selector .column-selector__column`, { + hasText: exactText('Disable List Column Text'), + }), + ).toBeHidden() + }) + + test('should display field in column selector despite admin.disableListFilter', async () => { + await page.goto(postsUrl.list) + await page.locator('.list-controls__toggle-columns').click() + + await expect(page.locator('.column-selector')).toBeVisible() + + // Check if "Disable List Filter Text" is present in the column options + await expect( + page.locator(`.column-selector .column-selector__column`, { + hasText: exactText('Disable List Filter Text'), + }), + ).toBeVisible() + }) + + test('should still show field in filter when admin.disableListColumn is true', async () => { + await page.goto(postsUrl.list) + await openListFilters(page, {}) + await page.locator('.where-builder__add-first-filter').click() + + const initialField = page.locator('.condition__field') + await initialField.click() + + await expect( + initialField.locator(`.rs__menu-list:has-text("Disable List Column Text")`), + ).toBeVisible() + }) + + test('should toggle columns', async () => { + const columnCountLocator = 'table > thead > tr > th' + await createPost() + await openListColumns(page, {}) + const numberOfColumns = await page.locator(columnCountLocator).count() + await expect(page.locator('.column-selector')).toBeVisible() + await expect(page.locator('table > thead > tr > th:nth-child(2)')).toHaveText('ID') + await toggleColumn(page, { columnLabel: 'ID', targetState: 'off' }) + await page.locator('#heading-id').waitFor({ state: 'detached' }) + await page.locator('.cell-id').first().waitFor({ state: 'detached' }) + await expect(page.locator(columnCountLocator)).toHaveCount(numberOfColumns - 1) + await expect(page.locator('table > thead > tr > th:nth-child(2)')).toHaveText('Number') + await toggleColumn(page, { columnLabel: 'ID', targetState: 'on' }) + await expect(page.locator('.cell-id').first()).toBeVisible() + await expect(page.locator(columnCountLocator)).toHaveCount(numberOfColumns) + await expect(page.locator('table > thead > tr > th:nth-child(2)')).toHaveText('ID') + }) + test('should drag to reorder columns and save to preferences', async () => { await createPost() @@ -813,14 +1024,6 @@ describe('List View', () => { ).toHaveText('Title') }) }) - - describe('base list filters', () => { - test('should respect base list filters', async () => { - await page.goto(baseListFiltersUrl.list) - await page.waitForURL((url) => url.toString().startsWith(baseListFiltersUrl.list)) - await expect(page.locator(tableRowLocator)).toHaveCount(1) - }) - }) }) async function createPost(overrides?: Partial): Promise { diff --git a/test/admin/payload-types.ts b/test/admin/payload-types.ts index cca8c384a1..5b2418ee52 100644 --- a/test/admin/payload-types.ts +++ b/test/admin/payload-types.ts @@ -165,6 +165,8 @@ export interface Post { defaultValueField?: string | null; relationship?: (string | null) | Post; customCell?: string | null; + disableListColumnText?: string | null; + disableListFilterText?: string | null; sidebarField?: string | null; updatedAt: string; createdAt: string; @@ -520,6 +522,8 @@ export interface PostsSelect { defaultValueField?: T; relationship?: T; customCell?: T; + disableListColumnText?: T; + disableListFilterText?: T; sidebarField?: T; updatedAt?: T; createdAt?: T; diff --git a/test/fields/collections/Email/e2e.spec.ts b/test/fields/collections/Email/e2e.spec.ts index 37c1782010..22887772f2 100644 --- a/test/fields/collections/Email/e2e.spec.ts +++ b/test/fields/collections/Email/e2e.spec.ts @@ -9,19 +9,14 @@ import { fileURLToPath } from 'url' import type { PayloadTestSDK } from '../../../helpers/sdk/index.js' import type { Config } from '../../payload-types.js' -import { - ensureCompilationIsDone, - exactText, - initPageConsoleErrorCatch, - saveDocAndAssert, -} from '../../../helpers.js' +import { ensureCompilationIsDone, initPageConsoleErrorCatch } from '../../../helpers.js' import { AdminUrlUtil } from '../../../helpers/adminUrlUtil.js' import { initPayloadE2ENoConfig } from '../../../helpers/initPayloadE2ENoConfig.js' import { reInitializeDB } from '../../../helpers/reInitializeDB.js' import { RESTClient } from '../../../helpers/rest.js' import { TEST_TIMEOUT_LONG } from '../../../playwright.config.js' import { emailFieldsSlug } from '../../slugs.js' -import { anotherEmailDoc, emailDoc } from './shared.js' +import { emailDoc } from './shared.js' const filename = fileURLToPath(import.meta.url) const currentFolder = path.dirname(filename) @@ -74,60 +69,6 @@ describe('Email', () => { await expect(emailCell).toHaveText(emailDoc.email) }) - test('should hide field in column selector when admin.disableListColumn', async () => { - await page.goto(url.list) - await page.locator('.list-controls__toggle-columns').click() - - await expect(page.locator('.column-selector')).toBeVisible() - - // Check if "Disable List Column Text" is not present in the column options - await expect( - page.locator(`.column-selector .column-selector__column`, { - hasText: exactText('Disable List Column Text'), - }), - ).toBeHidden() - }) - - test('should show field in filter when admin.disableListColumn is true', async () => { - await page.goto(url.list) - await openListFilters(page, {}) - await page.locator('.where-builder__add-first-filter').click() - - const initialField = page.locator('.condition__field') - await initialField.click() - - await expect( - initialField.locator(`.rs__menu-list:has-text("Disable List Column Text")`), - ).toBeVisible() - }) - - test('should display field in list view column selector despite admin.disableListFilter', async () => { - await page.goto(url.list) - await page.locator('.list-controls__toggle-columns').click() - - await expect(page.locator('.column-selector')).toBeVisible() - - // Check if "Disable List Filter Text" is present in the column options - await expect( - page.locator(`.column-selector .column-selector__column`, { - hasText: exactText('Disable List Filter Text'), - }), - ).toBeVisible() - }) - - test('should hide field in filter when admin.disableListFilter is true', async () => { - await page.goto(url.list) - await openListFilters(page, {}) - await page.locator('.where-builder__add-first-filter').click() - - const initialField = page.locator('.condition__field') - await initialField.click() - - await expect( - initialField.locator(`.rs__option :has-text("Disable List Filter Text")`), - ).toBeHidden() - }) - test('should have autocomplete', async () => { await page.goto(url.create) const autoCompleteEmail = page.locator('#field-emailWithAutocomplete') diff --git a/test/fields/collections/Text/e2e.spec.ts b/test/fields/collections/Text/e2e.spec.ts index 60fe79200c..c610dd90a0 100644 --- a/test/fields/collections/Text/e2e.spec.ts +++ b/test/fields/collections/Text/e2e.spec.ts @@ -3,12 +3,9 @@ import type { GeneratedTypes } from 'helpers/sdk/types.js' import { expect, test } from '@playwright/test' import { openListColumns } from 'helpers/e2e/openListColumns.js' -import { openListFilters } from 'helpers/e2e/openListFilters.js' import { toggleColumn } from 'helpers/e2e/toggleColumn.js' import { upsertPrefs } from 'helpers/e2e/upsertPrefs.js' import path from 'path' -import { wait } from 'payload/shared' -import * as qs from 'qs-esm' import { fileURLToPath } from 'url' import type { PayloadTestSDK } from '../../../helpers/sdk/index.js' @@ -167,84 +164,6 @@ describe('Text', () => { await expect(textCell).toHaveText(textDoc.text) }) - test('should hide field in column selector when admin.disableListColumn', async () => { - await page.goto(url.list) - await page.locator('.list-controls__toggle-columns').click() - - await expect(page.locator('.column-selector')).toBeVisible() - - // Check if "Disable List Column Text" is not present in the column options - await expect( - page.locator(`.column-selector .column-selector__column`, { - hasText: exactText('Disable List Column Text'), - }), - ).toBeHidden() - }) - - test('should show field in filter when admin.disableListColumn is true', async () => { - await page.goto(url.list) - await openListFilters(page, {}) - await page.locator('.where-builder__add-first-filter').click() - - const initialField = page.locator('.condition__field') - await initialField.click() - - await expect( - initialField.locator(`.rs__menu-list:has-text("Disable List Column Text")`), - ).toBeVisible() - }) - - test('should display field in list view column selector despite admin.disableListFilter', async () => { - await page.goto(url.list) - await page.locator('.list-controls__toggle-columns').click() - - await expect(page.locator('.column-selector')).toBeVisible() - - // Check if "Disable List Filter Text" is present in the column options - await expect( - page.locator(`.column-selector .column-selector__column`, { - hasText: exactText('Disable List Filter Text'), - }), - ).toBeVisible() - }) - - test('should disable field when admin.disableListFilter is true but still exists in the query', async () => { - await page.goto( - `${url.list}${qs.stringify( - { - where: { - or: [ - { - and: [ - { - disableListFilterText: { - equals: 'Disable List Filter Text', - }, - }, - ], - }, - ], - }, - }, - { addQueryPrefix: true }, - )}`, - ) - - await openListFilters(page, {}) - - const condition = page.locator('.condition__field') - await expect(condition.locator('input.rs__input')).toBeDisabled() - await expect(page.locator('.condition__operator input.rs__input')).toBeDisabled() - await expect(page.locator('.condition__value input.condition-value-text')).toBeDisabled() - await expect(condition.locator('.rs__single-value')).toHaveText('Disable List Filter Text') - await page.locator('button.condition__actions-add').click() - const condition2 = page.locator('.condition__field').nth(1) - await condition2.click() - await expect( - condition2?.locator('.rs__menu-list:has-text("Disable List Filter Text")'), - ).toBeHidden() - }) - test('should respect admin.disableListColumn despite preferences', async () => { await upsertPrefs>({ payload, @@ -271,19 +190,6 @@ describe('Text', () => { await expect(page.locator('table .row-1 .cell-disableListColumnText')).toBeHidden() }) - test('should hide field in filter when admin.disableListFilter is true', async () => { - await page.goto(url.list) - await openListFilters(page, {}) - await page.locator('.where-builder__add-first-filter').click() - - const initialField = page.locator('.condition__field') - await initialField.click() - - await expect( - initialField.locator(`.rs__option :has-text("Disable List Filter Text")`), - ).toBeHidden() - }) - test('should display i18n label in cells when missing field data', async () => { await page.goto(url.list) await page.waitForURL(new RegExp(`${url.list}.*\\?.*`)) @@ -333,136 +239,4 @@ describe('Text', () => { await expect(field.locator('.rs__value-container')).toContainText(input) await expect(field.locator('.rs__value-container')).toContainText(furtherInput) }) - - test('should reset filter conditions when adding additional filters', async () => { - await page.goto(url.list) - - // open the first filter options - await openListFilters(page, {}) - await page.locator('.where-builder__add-first-filter').click() - - const firstInitialField = page.locator('.condition__field') - const firstOperatorField = page.locator('.condition__operator') - const firstValueField = page.locator('.condition__value >> input') - - await firstInitialField.click() - const firstInitialFieldOptions = firstInitialField.locator('.rs__option') - await firstInitialFieldOptions.locator('text=text').first().click() - await expect(firstInitialField.locator('.rs__single-value')).toContainText('Text') - - await firstOperatorField.click() - await firstOperatorField.locator('.rs__option').locator('text=equals').click() - - await firstValueField.fill('hello') - - await wait(500) - - await expect(firstValueField).toHaveValue('hello') - - // open the second filter options - await page.locator('.condition__actions-add').click() - - const secondLi = page.locator('.where-builder__and-filters li:nth-child(2)') - - await expect(secondLi).toBeVisible() - - const secondInitialField = secondLi.locator('.condition__field') - const secondOperatorField = secondLi.locator('.condition__operator >> input') - const secondValueField = secondLi.locator('.condition__value >> input') - - await expect(secondInitialField.locator('.rs__single-value')).toContainText('Text') - await expect(secondOperatorField).toHaveValue('') - await expect(secondValueField).toHaveValue('') - }) - - test('should not re-render page upon typing in a value in the filter value field', async () => { - await page.goto(url.list) - - // open the first filter options - await openListFilters(page, {}) - await page.locator('.where-builder__add-first-filter').click() - - const firstInitialField = page.locator('.condition__field') - const firstOperatorField = page.locator('.condition__operator') - const firstValueField = page.locator('.condition__value >> input') - - await firstInitialField.click() - const firstInitialFieldOptions = firstInitialField.locator('.rs__option') - await firstInitialFieldOptions.locator('text=text').first().click() - await expect(firstInitialField.locator('.rs__single-value')).toContainText('Text') - - await firstOperatorField.click() - await firstOperatorField.locator('.rs__option').locator('text=equals').click() - - // Type into the input field instead of filling it - await firstValueField.click() - await firstValueField.type('hello', { delay: 100 }) // Add a delay to simulate typing speed - - // Wait for a short period to see if the input loses focus - await page.waitForTimeout(500) - - // Check if the input still has the correct value - await expect(firstValueField).toHaveValue('hello') - }) - - test('should still show second filter if two filters exist and first filter is removed', async () => { - await page.goto(url.list) - - // open the first filter options - await openListFilters(page, {}) - await page.locator('.where-builder__add-first-filter').click() - - const firstInitialField = page.locator('.condition__field') - const firstOperatorField = page.locator('.condition__operator') - const firstValueField = page.locator('.condition__value >> input') - - await firstInitialField.click() - const firstInitialFieldOptions = firstInitialField.locator('.rs__option') - await firstInitialFieldOptions.locator('text=text').first().click() - await expect(firstInitialField.locator('.rs__single-value')).toContainText('Text') - - await firstOperatorField.click() - await firstOperatorField.locator('.rs__option').locator('text=equals').click() - - await firstValueField.fill('hello') - - await wait(500) - - await expect(firstValueField).toHaveValue('hello') - - // open the second filter options - await page.locator('.condition__actions-add').click() - - const secondLi = page.locator('.where-builder__and-filters li:nth-child(2)') - - await expect(secondLi).toBeVisible() - - const secondInitialField = secondLi.locator('.condition__field') - const secondOperatorField = secondLi.locator('.condition__operator') - const secondValueField = secondLi.locator('.condition__value >> input') - - await secondInitialField.click() - const secondInitialFieldOptions = secondInitialField.locator('.rs__option') - await secondInitialFieldOptions.locator('text=text').first().click() - await expect(secondInitialField.locator('.rs__single-value')).toContainText('Text') - - await secondOperatorField.click() - await secondOperatorField.locator('.rs__option').locator('text=equals').click() - - await secondValueField.fill('world') - await expect(secondValueField).toHaveValue('world') - - await wait(500) - - const firstLi = page.locator('.where-builder__and-filters li:nth-child(1)') - const removeButton = firstLi.locator('.condition__actions-remove') - - // remove first filter - await removeButton.click() - - const filterListItems = page.locator('.where-builder__and-filters li') - await expect(filterListItems).toHaveCount(1) - - await expect(firstValueField).toHaveValue('world') - }) }) diff --git a/test/fields/collections/Text/index.ts b/test/fields/collections/Text/index.ts index 4f3fcf4e89..f850e71c8f 100644 --- a/test/fields/collections/Text/index.ts +++ b/test/fields/collections/Text/index.ts @@ -158,20 +158,6 @@ const TextFields: CollectionConfig = { return Promise.resolve(req.context.defaultValue) }, }, - { - name: 'disableListColumnText', - type: 'text', - admin: { - disableListColumn: true, - }, - }, - { - name: 'disableListFilterText', - type: 'text', - admin: { - disableListFilter: true, - }, - }, { name: 'array', type: 'array', diff --git a/test/fields/payload-types.ts b/test/fields/payload-types.ts index 352cc72fc0..087a020485 100644 --- a/test/fields/payload-types.ts +++ b/test/fields/payload-types.ts @@ -310,6 +310,9 @@ export interface LexicalMigrateField { export interface LexicalLocalizedField { id: string; title: string; + /** + * Non-localized field with localized block subfields + */ lexicalBlocksSubLocalized?: { root: { type: string; @@ -325,6 +328,9 @@ export interface LexicalLocalizedField { }; [k: string]: unknown; } | null; + /** + * Localized field with localized block subfields + */ lexicalBlocksLocalized?: { root: { type: string; @@ -475,6 +481,9 @@ export interface ArrayField { id?: string | null; }[] | null; + /** + * Row labels rendered as react components. + */ rowLabelAsComponent?: | { title?: string | null; @@ -589,6 +598,9 @@ export interface BlockField { } )[] | null; + /** + * The purpose of this field is to test validateExistingBlockIsIdentical works with similar blocks with group fields + */ blocksWithSimilarGroup?: | ( | { @@ -777,9 +789,18 @@ export interface TextField { id: string; text: string; hiddenTextField?: string | null; + /** + * This field should be hidden + */ adminHiddenTextField?: string | null; + /** + * This field should be disabled + */ disabledTextField?: string | null; localizedText?: string | null; + /** + * en description + */ i18nText?: string | null; defaultString?: string | null; defaultEmptyString?: string | null; @@ -794,8 +815,6 @@ export interface TextField { withMinRows?: string[] | null; withMaxRows?: string[] | null; defaultValueFromReq?: string | null; - disableListColumnText?: string | null; - disableListFilterText?: string | null; array?: | { texts?: string[] | null; @@ -900,8 +919,14 @@ export interface ConditionalLogic { userConditional?: string | null; parentGroup?: { enableParentGroupFields?: boolean | null; + /** + * Ensures we can rely on nested fields within `data`. + */ siblingField?: string | null; }; + /** + * Ensures we can rely on nested fields within `siblingsData`. + */ reliesOnParentGroup?: string | null; groupSelection?: ('group1' | 'group2') | null; group1?: { @@ -981,6 +1006,9 @@ export interface EmailField { email: string; localizedEmail?: string | null; emailWithAutocomplete?: string | null; + /** + * en description + */ i18nEmail?: string | null; defaultEmail?: string | null; defaultEmptyString?: string | null; @@ -1010,6 +1038,9 @@ export interface RadioField { */ export interface GroupField { id: string; + /** + * This is a group. + */ group: { text: string; defaultParent?: string | null; @@ -1402,6 +1433,9 @@ export interface RichTextField { [k: string]: unknown; }; lexicalCustomFields_html?: string | null; + /** + * This rich text field uses the lexical editor. + */ lexical?: { root: { type: string; @@ -1417,6 +1451,9 @@ export interface RichTextField { }; [k: string]: unknown; } | null; + /** + * This select field is rendered here to ensure its options dropdown renders above the rich text toolbar. + */ selectHasMany?: ('one' | 'two' | 'three' | 'four' | 'five' | 'six')[] | null; richText: { [k: string]: unknown; @@ -1505,6 +1542,9 @@ export interface TabsFields2 { */ export interface TabsField { id: string; + /** + * This should not collapse despite there being many tabs pushing the main fields open. + */ sidebarField?: string | null; array: { text: string; @@ -2115,257 +2155,42 @@ export interface BlockFieldsSelect { blocks?: | T | { - content?: - | T - | { - text?: T; - richText?: T; - id?: T; - blockName?: T; - }; - number?: - | T - | { - number?: T; - id?: T; - blockName?: T; - }; - subBlocks?: - | T - | { - subBlocks?: - | T - | { - text?: - | T - | { - text?: T; - id?: T; - blockName?: T; - }; - number?: - | T - | { - number?: T; - id?: T; - blockName?: T; - }; - }; - id?: T; - blockName?: T; - }; - tabs?: - | T - | { - textInCollapsible?: T; - textInRow?: T; - id?: T; - blockName?: T; - }; + content?: T | ContentBlockSelect; + number?: T | NumberBlockSelect; + subBlocks?: T | SubBlocksBlockSelect; + tabs?: T | TabsBlockSelect; }; duplicate?: | T | { - content?: - | T - | { - text?: T; - richText?: T; - id?: T; - blockName?: T; - }; - number?: - | T - | { - number?: T; - id?: T; - blockName?: T; - }; - subBlocks?: - | T - | { - subBlocks?: - | T - | { - text?: - | T - | { - text?: T; - id?: T; - blockName?: T; - }; - number?: - | T - | { - number?: T; - id?: T; - blockName?: T; - }; - }; - id?: T; - blockName?: T; - }; - tabs?: - | T - | { - textInCollapsible?: T; - textInRow?: T; - id?: T; - blockName?: T; - }; + content?: T | ContentBlockSelect; + number?: T | NumberBlockSelect; + subBlocks?: T | SubBlocksBlockSelect; + tabs?: T | TabsBlockSelect; }; collapsedByDefaultBlocks?: | T | { - localizedContent?: - | T - | { - text?: T; - richText?: T; - id?: T; - blockName?: T; - }; - localizedNumber?: - | T - | { - number?: T; - id?: T; - blockName?: T; - }; - localizedSubBlocks?: - | T - | { - subBlocks?: - | T - | { - text?: - | T - | { - text?: T; - id?: T; - blockName?: T; - }; - number?: - | T - | { - number?: T; - id?: T; - blockName?: T; - }; - }; - id?: T; - blockName?: T; - }; - localizedTabs?: - | T - | { - textInCollapsible?: T; - textInRow?: T; - id?: T; - blockName?: T; - }; + localizedContent?: T | LocalizedContentBlockSelect; + localizedNumber?: T | LocalizedNumberBlockSelect; + localizedSubBlocks?: T | LocalizedSubBlocksBlockSelect; + localizedTabs?: T | LocalizedTabsBlockSelect; }; disableSort?: | T | { - localizedContent?: - | T - | { - text?: T; - richText?: T; - id?: T; - blockName?: T; - }; - localizedNumber?: - | T - | { - number?: T; - id?: T; - blockName?: T; - }; - localizedSubBlocks?: - | T - | { - subBlocks?: - | T - | { - text?: - | T - | { - text?: T; - id?: T; - blockName?: T; - }; - number?: - | T - | { - number?: T; - id?: T; - blockName?: T; - }; - }; - id?: T; - blockName?: T; - }; - localizedTabs?: - | T - | { - textInCollapsible?: T; - textInRow?: T; - id?: T; - blockName?: T; - }; + localizedContent?: T | LocalizedContentBlockSelect; + localizedNumber?: T | LocalizedNumberBlockSelect; + localizedSubBlocks?: T | LocalizedSubBlocksBlockSelect; + localizedTabs?: T | LocalizedTabsBlockSelect; }; localizedBlocks?: | T | { - localizedContent?: - | T - | { - text?: T; - richText?: T; - id?: T; - blockName?: T; - }; - localizedNumber?: - | T - | { - number?: T; - id?: T; - blockName?: T; - }; - localizedSubBlocks?: - | T - | { - subBlocks?: - | T - | { - text?: - | T - | { - text?: T; - id?: T; - blockName?: T; - }; - number?: - | T - | { - number?: T; - id?: T; - blockName?: T; - }; - }; - id?: T; - blockName?: T; - }; - localizedTabs?: - | T - | { - textInCollapsible?: T; - textInRow?: T; - id?: T; - blockName?: T; - }; + localizedContent?: T | LocalizedContentBlockSelect; + localizedNumber?: T | LocalizedNumberBlockSelect; + localizedSubBlocks?: T | LocalizedSubBlocksBlockSelect; + localizedTabs?: T | LocalizedTabsBlockSelect; }; i18nBlocks?: | T @@ -2503,6 +2328,116 @@ export interface BlockFieldsSelect { updatedAt?: T; createdAt?: T; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "ContentBlock_select". + */ +export interface ContentBlockSelect { + text?: T; + richText?: T; + id?: T; + blockName?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "NumberBlock_select". + */ +export interface NumberBlockSelect { + number?: T; + id?: T; + blockName?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "SubBlocksBlock_select". + */ +export interface SubBlocksBlockSelect { + subBlocks?: + | T + | { + text?: + | T + | { + text?: T; + id?: T; + blockName?: T; + }; + number?: + | T + | { + number?: T; + id?: T; + blockName?: T; + }; + }; + id?: T; + blockName?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "TabsBlock_select". + */ +export interface TabsBlockSelect { + textInCollapsible?: T; + textInRow?: T; + id?: T; + blockName?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "localizedContentBlock_select". + */ +export interface LocalizedContentBlockSelect { + text?: T; + richText?: T; + id?: T; + blockName?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "localizedNumberBlock_select". + */ +export interface LocalizedNumberBlockSelect { + number?: T; + id?: T; + blockName?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "localizedSubBlocksBlock_select". + */ +export interface LocalizedSubBlocksBlockSelect { + subBlocks?: + | T + | { + text?: + | T + | { + text?: T; + id?: T; + blockName?: T; + }; + number?: + | T + | { + number?: T; + id?: T; + blockName?: T; + }; + }; + id?: T; + blockName?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "localizedTabsBlock_select". + */ +export interface LocalizedTabsBlockSelect { + textInCollapsible?: T; + textInRow?: T; + id?: T; + blockName?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "checkbox-fields_select". @@ -3085,53 +3020,10 @@ export interface TabsFieldsSelect { blocks?: | T | { - content?: - | T - | { - text?: T; - richText?: T; - id?: T; - blockName?: T; - }; - number?: - | T - | { - number?: T; - id?: T; - blockName?: T; - }; - subBlocks?: - | T - | { - subBlocks?: - | T - | { - text?: - | T - | { - text?: T; - id?: T; - blockName?: T; - }; - number?: - | T - | { - number?: T; - id?: T; - blockName?: T; - }; - }; - id?: T; - blockName?: T; - }; - tabs?: - | T - | { - textInCollapsible?: T; - textInRow?: T; - id?: T; - blockName?: T; - }; + content?: T | ContentBlockSelect; + number?: T | NumberBlockSelect; + subBlocks?: T | SubBlocksBlockSelect; + tabs?: T | TabsBlockSelect; }; group?: | T @@ -3141,24 +3033,7 @@ export interface TabsFieldsSelect { textInRow?: T; numberInRow?: T; json?: T; - tab?: - | T - | { - array?: - | T - | { - text?: T; - id?: T; - }; - text?: T; - defaultValue?: T; - arrayInRow?: - | T - | { - textInArrayInRow?: T; - id?: T; - }; - }; + tab?: T | TabWithNameSelect; namedTabWithDefaultValue?: | T | { @@ -3208,6 +3083,26 @@ export interface TabsFieldsSelect { updatedAt?: T; createdAt?: T; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "TabWithName_select". + */ +export interface TabWithNameSelect { + array?: + | T + | { + text?: T; + id?: T; + }; + text?: T; + defaultValue?: T; + arrayInRow?: + | T + | { + textInArrayInRow?: T; + id?: T; + }; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "text-fields_select". @@ -3232,8 +3127,6 @@ export interface TextFieldsSelect { withMinRows?: T; withMaxRows?: T; defaultValueFromReq?: T; - disableListColumnText?: T; - disableListFilterText?: T; array?: | T | { diff --git a/test/joins/payload-types.ts b/test/joins/payload-types.ts index 241b99ec4e..394f98fffc 100644 --- a/test/joins/payload-types.ts +++ b/test/joins/payload-types.ts @@ -126,9 +126,6 @@ export interface UserAuthOperations { export interface Post { id: string; title?: string | null; - /** - * Hides posts for the `filtered` join field in categories - */ isFiltered?: boolean | null; restrictedField?: string | null; upload?: (string | null) | Upload; @@ -231,9 +228,6 @@ export interface Category { docs?: (string | Post)[] | null; hasNextPage?: boolean | null; } | null; - /** - * Static Description - */ hasManyPosts?: { docs?: (string | Post)[] | null; hasNextPage?: boolean | null; diff --git a/tsconfig.base.json b/tsconfig.base.json index 01f5644941..872fb4ed36 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -28,7 +28,7 @@ } ], "paths": { - "@payload-config": ["./test/_community/config.ts"], + "@payload-config": ["./test/admin/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"],