chore: splits out blocks and array into their own suites
This commit is contained in:
288
test/fields/collections/Array/e2e.spec.ts
Normal file
288
test/fields/collections/Array/e2e.spec.ts
Normal file
@@ -0,0 +1,288 @@
|
||||
import type { Page } from '@playwright/test'
|
||||
|
||||
import { expect, test } from '@playwright/test'
|
||||
import path from 'path'
|
||||
import { wait } from 'payload/utilities'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
import type { PayloadTestSDK } from '../../../helpers/sdk/index.js'
|
||||
import type { Config } from '../../payload-types.js'
|
||||
|
||||
import {
|
||||
ensureAutoLoginAndCompilationIsDone,
|
||||
initPageConsoleErrorCatch,
|
||||
saveDocAndAssert,
|
||||
} from '../../../helpers.js'
|
||||
import { AdminUrlUtil } from '../../../helpers/adminUrlUtil.js'
|
||||
import { initPayloadE2ENoConfig } from '../../../helpers/initPayloadE2ENoConfig.js'
|
||||
import { reInitializeDB } from '../../../helpers/reInit.js'
|
||||
import { RESTClient } from '../../../helpers/rest.js'
|
||||
|
||||
const filename = fileURLToPath(import.meta.url)
|
||||
const currentFolder = path.dirname(filename)
|
||||
const dirname = path.resolve(currentFolder, '../../')
|
||||
|
||||
const { beforeAll, beforeEach, describe } = test
|
||||
|
||||
let payload: PayloadTestSDK<Config>
|
||||
let client: RESTClient
|
||||
let page: Page
|
||||
let serverURL: string
|
||||
// If we want to make this run in parallel: test.describe.configure({ mode: 'parallel' })
|
||||
|
||||
describe('Array', () => {
|
||||
beforeAll(async ({ browser }) => {
|
||||
process.env.SEED_IN_CONFIG_ONINIT = 'false' // Makes it so the payload config onInit seed is not run. Otherwise, the seed would be run unnecessarily twice for the initial test run - once for beforeEach and once for onInit
|
||||
;({ payload, serverURL } = await initPayloadE2ENoConfig({
|
||||
dirname,
|
||||
}))
|
||||
|
||||
const context = await browser.newContext()
|
||||
page = await context.newPage()
|
||||
initPageConsoleErrorCatch(page)
|
||||
})
|
||||
beforeEach(async () => {
|
||||
await reInitializeDB({
|
||||
serverURL,
|
||||
snapshotKey: 'fieldsArrayTest',
|
||||
uploadsDir: path.resolve(dirname, '../Upload/uploads'),
|
||||
})
|
||||
|
||||
if (client) {
|
||||
await client.logout()
|
||||
}
|
||||
client = new RESTClient(null, { defaultSlug: 'users', serverURL })
|
||||
await client.login()
|
||||
|
||||
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
|
||||
})
|
||||
|
||||
let url: AdminUrlUtil
|
||||
beforeAll(() => {
|
||||
url = new AdminUrlUtil(serverURL, 'array-fields')
|
||||
})
|
||||
|
||||
test('should be readOnly', async () => {
|
||||
await page.goto(url.create)
|
||||
const field = page.locator('#field-readOnly__0__text')
|
||||
await expect(field).toBeDisabled()
|
||||
})
|
||||
|
||||
test('should have defaultValue', async () => {
|
||||
await page.goto(url.create)
|
||||
const field = page.locator('#field-readOnly__0__text')
|
||||
await expect(field).toHaveValue('defaultValue')
|
||||
})
|
||||
|
||||
test('should render RowLabel using a component', async () => {
|
||||
const label = 'custom row label as component'
|
||||
await page.goto(url.create)
|
||||
await page.locator('#field-rowLabelAsComponent >> .array-field__add-row').click()
|
||||
|
||||
await page.locator('#field-rowLabelAsComponent__0__title').fill(label)
|
||||
await wait(100)
|
||||
const customRowLabel = page.locator(
|
||||
'#rowLabelAsComponent-row-0 >> .array-field__row-header > :text("custom row label")',
|
||||
)
|
||||
await expect(customRowLabel).toHaveCSS('text-transform', 'uppercase')
|
||||
})
|
||||
|
||||
test('should bypass min rows validation when no rows present and field is not required', async () => {
|
||||
await page.goto(url.create)
|
||||
await saveDocAndAssert(page)
|
||||
await expect(page.locator('.Toastify')).toContainText('successfully')
|
||||
})
|
||||
|
||||
test('should fail min rows validation when rows are present', async () => {
|
||||
await page.goto(url.create)
|
||||
await page.locator('#field-arrayWithMinRows >> .array-field__add-row').click()
|
||||
|
||||
await page.click('#action-save', { delay: 100 })
|
||||
await expect(page.locator('.Toastify')).toContainText(
|
||||
'The following field is invalid: arrayWithMinRows',
|
||||
)
|
||||
})
|
||||
|
||||
describe('row manipulation', () => {
|
||||
test('should add, remove and duplicate rows', async () => {
|
||||
const assertText0 = 'array row 1'
|
||||
const assertGroupText0 = 'text in group in row 1'
|
||||
const assertText1 = 'array row 2'
|
||||
const assertText3 = 'array row 3'
|
||||
const assertGroupText3 = 'text in group in row 3'
|
||||
await page.goto(url.create)
|
||||
await page.mouse.wheel(0, 1750)
|
||||
await page.locator('#field-potentiallyEmptyArray').scrollIntoViewIfNeeded()
|
||||
await wait(300)
|
||||
|
||||
// Add 3 rows
|
||||
await page.locator('#field-potentiallyEmptyArray > .array-field__add-row').click()
|
||||
await wait(300)
|
||||
await page.locator('#field-potentiallyEmptyArray > .array-field__add-row').click()
|
||||
await wait(300)
|
||||
await page.locator('#field-potentiallyEmptyArray > .array-field__add-row').click()
|
||||
await wait(300)
|
||||
|
||||
// Fill out row 1
|
||||
await page.locator('#field-potentiallyEmptyArray__0__text').fill(assertText0)
|
||||
await page
|
||||
.locator('#field-potentiallyEmptyArray__0__groupInRow__textInGroupInRow')
|
||||
.fill(assertGroupText0)
|
||||
// Fill out row 2
|
||||
await page.locator('#field-potentiallyEmptyArray__1__text').fill(assertText1)
|
||||
// Fill out row 3
|
||||
await page.locator('#field-potentiallyEmptyArray__2__text').fill(assertText3)
|
||||
await page
|
||||
.locator('#field-potentiallyEmptyArray__2__groupInRow__textInGroupInRow')
|
||||
.fill(assertGroupText3)
|
||||
|
||||
// Remove row 1
|
||||
await page.locator('#potentiallyEmptyArray-row-0 .array-actions__button').click()
|
||||
await page
|
||||
.locator('#potentiallyEmptyArray-row-0 .popup__scroll-container .array-actions__remove')
|
||||
.click()
|
||||
// Remove row 2
|
||||
await page.locator('#potentiallyEmptyArray-row-0 .array-actions__button').click()
|
||||
await page
|
||||
.locator('#potentiallyEmptyArray-row-0 .popup__scroll-container .array-actions__remove')
|
||||
.click()
|
||||
|
||||
// Save document
|
||||
await saveDocAndAssert(page)
|
||||
|
||||
// Scroll to array row (fields are not rendered in DOM until on screen)
|
||||
await page.locator('#field-potentiallyEmptyArray__0__groupInRow').scrollIntoViewIfNeeded()
|
||||
|
||||
// Expect the remaining row to be the third row
|
||||
const input = page.locator('#field-potentiallyEmptyArray__0__groupInRow__textInGroupInRow')
|
||||
await expect(input).toHaveValue(assertGroupText3)
|
||||
|
||||
// Duplicate row
|
||||
await page.locator('#potentiallyEmptyArray-row-0 .array-actions__button').click()
|
||||
await page
|
||||
.locator('#potentiallyEmptyArray-row-0 .popup__scroll-container .array-actions__duplicate')
|
||||
.click()
|
||||
|
||||
// Update duplicated row group field text
|
||||
await page
|
||||
.locator('#field-potentiallyEmptyArray__1__groupInRow__textInGroupInRow')
|
||||
.fill(`${assertGroupText3} duplicate`)
|
||||
|
||||
// Save document
|
||||
await saveDocAndAssert(page)
|
||||
|
||||
// Expect the second row to be a duplicate of the remaining row
|
||||
await expect(
|
||||
page.locator('#field-potentiallyEmptyArray__1__groupInRow__textInGroupInRow'),
|
||||
).toHaveValue(`${assertGroupText3} duplicate`)
|
||||
|
||||
// Remove row 1
|
||||
await page.locator('#potentiallyEmptyArray-row-0 .array-actions__button').click()
|
||||
await page
|
||||
.locator('#potentiallyEmptyArray-row-0 .popup__scroll-container .array-actions__remove')
|
||||
.click()
|
||||
|
||||
// Save document
|
||||
await saveDocAndAssert(page)
|
||||
|
||||
// Expect the remaining row to be the copy of the duplicate row
|
||||
await expect(
|
||||
page.locator('#field-potentiallyEmptyArray__0__groupInRow__textInGroupInRow'),
|
||||
).toHaveValue(`${assertGroupText3} duplicate`)
|
||||
})
|
||||
})
|
||||
|
||||
// TODO: re-enable this test
|
||||
test.skip('should bulk update', async () => {
|
||||
await payload.create({
|
||||
collection: 'array-fields',
|
||||
data: {
|
||||
title: 'for test 1',
|
||||
items: [
|
||||
{
|
||||
text: 'test 1',
|
||||
},
|
||||
{
|
||||
text: 'test 2',
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
await payload.create({
|
||||
collection: 'array-fields',
|
||||
data: {
|
||||
title: 'for test 2',
|
||||
items: [
|
||||
{
|
||||
text: 'test 3',
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
await payload.create({
|
||||
collection: 'array-fields',
|
||||
data: {
|
||||
title: 'for test 3',
|
||||
items: [
|
||||
{
|
||||
text: 'test 4',
|
||||
},
|
||||
{
|
||||
text: 'test 5',
|
||||
},
|
||||
{
|
||||
text: 'test 6',
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
const bulkText = 'Bulk update text'
|
||||
await page.goto(url.list)
|
||||
await page.waitForSelector('.table > table > tbody > tr td.cell-title')
|
||||
const rows = page.locator('.table > table > tbody > tr', {
|
||||
has: page.locator('td.cell-title a', {
|
||||
hasText: 'for test',
|
||||
}),
|
||||
})
|
||||
const count = await rows.count()
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
await rows
|
||||
.nth(i)
|
||||
.locator('td.cell-_select .checkbox-input__input > input[type="checkbox"]')
|
||||
.click()
|
||||
}
|
||||
await page.locator('.edit-many__toggle').click()
|
||||
await page.locator('.field-select .rs__control').click()
|
||||
|
||||
const arrayOption = page.locator('.rs__option', {
|
||||
hasText: 'Items',
|
||||
})
|
||||
|
||||
await expect(arrayOption).toBeVisible()
|
||||
|
||||
await arrayOption.click()
|
||||
await wait(200)
|
||||
|
||||
const addRowButton = page.locator('#field-items > .array-field__add-row')
|
||||
|
||||
await expect(addRowButton).toBeVisible()
|
||||
|
||||
await addRowButton.click()
|
||||
await wait(200)
|
||||
|
||||
const targetInput = page.locator('#field-items__0__text')
|
||||
|
||||
await expect(targetInput).toBeVisible()
|
||||
|
||||
await targetInput.fill(bulkText)
|
||||
|
||||
await page.locator('#edit-array-fields .form-submit .edit-many__save').click()
|
||||
await expect(page.locator('.Toastify__toast--success')).toContainText(
|
||||
'Updated 3 Array Fields successfully.',
|
||||
)
|
||||
})
|
||||
})
|
||||
245
test/fields/collections/Blocks/e2e.spec.ts
Normal file
245
test/fields/collections/Blocks/e2e.spec.ts
Normal file
@@ -0,0 +1,245 @@
|
||||
import type { Page } from '@playwright/test'
|
||||
|
||||
import { expect, test } from '@playwright/test'
|
||||
import path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
import {
|
||||
ensureAutoLoginAndCompilationIsDone,
|
||||
initPageConsoleErrorCatch,
|
||||
saveDocAndAssert,
|
||||
} from '../../../helpers.js'
|
||||
import { AdminUrlUtil } from '../../../helpers/adminUrlUtil.js'
|
||||
import { initPayloadE2ENoConfig } from '../../../helpers/initPayloadE2ENoConfig.js'
|
||||
import { reInitializeDB } from '../../../helpers/reInit.js'
|
||||
import { RESTClient } from '../../../helpers/rest.js'
|
||||
|
||||
const filename = fileURLToPath(import.meta.url)
|
||||
const currentFolder = path.dirname(filename)
|
||||
const dirname = path.resolve(currentFolder, '../../')
|
||||
|
||||
const { beforeAll, beforeEach, describe } = test
|
||||
|
||||
let client: RESTClient
|
||||
let page: Page
|
||||
let serverURL: string
|
||||
// If we want to make this run in parallel: test.describe.configure({ mode: 'parallel' })
|
||||
|
||||
describe('Block fields', () => {
|
||||
beforeAll(async ({ browser }) => {
|
||||
process.env.SEED_IN_CONFIG_ONINIT = 'false' // Makes it so the payload config onInit seed is not run. Otherwise, the seed would be run unnecessarily twice for the initial test run - once for beforeEach and once for onInit
|
||||
;({ serverURL } = await initPayloadE2ENoConfig({
|
||||
dirname,
|
||||
}))
|
||||
|
||||
const context = await browser.newContext()
|
||||
page = await context.newPage()
|
||||
initPageConsoleErrorCatch(page)
|
||||
})
|
||||
beforeEach(async () => {
|
||||
await reInitializeDB({
|
||||
serverURL,
|
||||
snapshotKey: 'blockFieldsTest',
|
||||
uploadsDir: path.resolve(dirname, '../Upload/uploads'),
|
||||
})
|
||||
|
||||
if (client) {
|
||||
await client.logout()
|
||||
}
|
||||
client = new RESTClient(null, { defaultSlug: 'users', serverURL })
|
||||
await client.login()
|
||||
|
||||
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
|
||||
})
|
||||
|
||||
let url: AdminUrlUtil
|
||||
beforeAll(() => {
|
||||
url = new AdminUrlUtil(serverURL, 'block-fields')
|
||||
})
|
||||
|
||||
test('should open blocks drawer and select first block', async () => {
|
||||
await page.goto(url.create)
|
||||
const addButton = page.locator('#field-blocks > .blocks-field__drawer-toggler')
|
||||
await expect(addButton).toContainText('Add Block')
|
||||
await addButton.click()
|
||||
|
||||
const blocksDrawer = page.locator('[id^=drawer_1_blocks-drawer-]')
|
||||
await expect(blocksDrawer).toBeVisible()
|
||||
|
||||
// select the first block in the drawer
|
||||
const firstBlockSelector = blocksDrawer
|
||||
.locator('.blocks-drawer__blocks .blocks-drawer__block')
|
||||
.first()
|
||||
await expect(firstBlockSelector).toContainText('Content')
|
||||
await firstBlockSelector.click()
|
||||
|
||||
// ensure the block was appended to the rows
|
||||
const addedRow = page.locator('#field-blocks .blocks-field__row').last()
|
||||
await expect(addedRow).toBeVisible()
|
||||
await expect(addedRow.locator('.blocks-field__block-pill-content')).toContainText('Content')
|
||||
})
|
||||
|
||||
test('should open blocks drawer from block row and add below', async () => {
|
||||
await page.goto(url.create)
|
||||
const firstRow = page.locator('#field-blocks #blocks-row-0')
|
||||
const rowActions = firstRow.locator('.collapsible__actions')
|
||||
await expect(rowActions).toBeVisible()
|
||||
|
||||
await rowActions.locator('.array-actions__button').click()
|
||||
const addBelowButton = rowActions.locator('.array-actions__action.array-actions__add')
|
||||
await expect(addBelowButton).toBeVisible()
|
||||
await addBelowButton.click()
|
||||
|
||||
const blocksDrawer = page.locator('[id^=drawer_1_blocks-drawer-]')
|
||||
await expect(blocksDrawer).toBeVisible()
|
||||
|
||||
// select the first block in the drawer
|
||||
const firstBlockSelector = blocksDrawer
|
||||
.locator('.blocks-drawer__blocks .blocks-drawer__block')
|
||||
.first()
|
||||
await expect(firstBlockSelector).toContainText('Content')
|
||||
await firstBlockSelector.click()
|
||||
|
||||
// ensure the block was inserted beneath the first in the rows
|
||||
const addedRow = page.locator('#field-blocks #blocks-row-1')
|
||||
await expect(addedRow).toBeVisible()
|
||||
await expect(addedRow.locator('.blocks-field__block-pill-content')).toContainText('Content') // went from `Number` to `Content`
|
||||
})
|
||||
|
||||
test('should use i18n block labels', async () => {
|
||||
await page.goto(url.create)
|
||||
await expect(page.locator('#field-i18nBlocks .blocks-field__header')).toContainText('Block en')
|
||||
|
||||
const addButton = page.locator('#field-i18nBlocks > .blocks-field__drawer-toggler')
|
||||
await expect(addButton).toContainText('Add Block en')
|
||||
await addButton.click()
|
||||
|
||||
const blocksDrawer = page.locator('[id^=drawer_1_blocks-drawer-]')
|
||||
await expect(blocksDrawer).toBeVisible()
|
||||
|
||||
// select the first block in the drawer
|
||||
const firstBlockSelector = blocksDrawer
|
||||
.locator('.blocks-drawer__blocks .blocks-drawer__block')
|
||||
.first()
|
||||
await expect(firstBlockSelector).toContainText('Text en')
|
||||
await firstBlockSelector.click()
|
||||
|
||||
// ensure the block was appended to the rows
|
||||
const firstRow = page.locator('#field-i18nBlocks .blocks-field__row').first()
|
||||
await expect(firstRow).toBeVisible()
|
||||
await expect(firstRow.locator('.blocks-field__block-pill-text')).toContainText('Text en')
|
||||
})
|
||||
|
||||
test('should add different blocks with similar field configs', async () => {
|
||||
await page.goto(url.create)
|
||||
|
||||
async function addBlock(name: 'Block A' | 'Block B') {
|
||||
await page
|
||||
.locator('#field-blocksWithSimilarConfigs')
|
||||
.getByRole('button', { name: 'Add Blocks With Similar Config' })
|
||||
.click()
|
||||
await page.getByRole('button', { name }).click()
|
||||
}
|
||||
|
||||
await addBlock('Block A')
|
||||
|
||||
await page
|
||||
.locator('#blocksWithSimilarConfigs-row-0')
|
||||
.getByRole('button', { name: 'Add Item' })
|
||||
.click()
|
||||
await page
|
||||
.locator('input[name="blocksWithSimilarConfigs.0.items.0.title"]')
|
||||
.fill('items>0>title')
|
||||
|
||||
await expect(
|
||||
page.locator('input[name="blocksWithSimilarConfigs.0.items.0.title"]'),
|
||||
).toHaveValue('items>0>title')
|
||||
|
||||
await addBlock('Block B')
|
||||
|
||||
await page
|
||||
.locator('#blocksWithSimilarConfigs-row-1')
|
||||
.getByRole('button', { name: 'Add Item' })
|
||||
.click()
|
||||
await page
|
||||
.locator('input[name="blocksWithSimilarConfigs.1.items.0.title2"]')
|
||||
.fill('items>1>title')
|
||||
|
||||
await expect(
|
||||
page.locator('input[name="blocksWithSimilarConfigs.1.items.0.title2"]'),
|
||||
).toHaveValue('items>1>title')
|
||||
})
|
||||
|
||||
test('should bypass min rows validation when no rows present and field is not required', async () => {
|
||||
await page.goto(url.create)
|
||||
await saveDocAndAssert(page)
|
||||
await expect(page.locator('.Toastify')).toContainText('successfully')
|
||||
})
|
||||
|
||||
test('should fail min rows validation when rows are present', async () => {
|
||||
await page.goto(url.create)
|
||||
|
||||
await page
|
||||
.locator('#field-blocksWithMinRows')
|
||||
.getByRole('button', { name: 'Add Blocks With Min Row' })
|
||||
.click()
|
||||
|
||||
const blocksDrawer = page.locator('[id^=drawer_1_blocks-drawer-]')
|
||||
await expect(blocksDrawer).toBeVisible()
|
||||
|
||||
const firstBlockSelector = blocksDrawer
|
||||
.locator('.blocks-drawer__blocks .blocks-drawer__block')
|
||||
.first()
|
||||
|
||||
await firstBlockSelector.click()
|
||||
|
||||
const firstRow = page.locator('input[name="blocksWithMinRows.0.blockTitle"]')
|
||||
await expect(firstRow).toBeVisible()
|
||||
await firstRow.fill('first row')
|
||||
await expect(firstRow).toHaveValue('first row')
|
||||
|
||||
await page.click('#action-save', { delay: 100 })
|
||||
await expect(page.locator('.Toastify')).toContainText(
|
||||
'The following field is invalid: blocksWithMinRows',
|
||||
)
|
||||
})
|
||||
|
||||
describe('row manipulation', () => {
|
||||
describe('react hooks', () => {
|
||||
test('should add 2 new block rows', async () => {
|
||||
await page.goto(url.create)
|
||||
|
||||
await page
|
||||
.locator('.custom-blocks-field-management')
|
||||
.getByRole('button', { name: 'Add Block 1' })
|
||||
.click()
|
||||
|
||||
const customBlocks = page.locator(
|
||||
'#field-customBlocks input[name="customBlocks.0.block1Title"]',
|
||||
)
|
||||
|
||||
await page.mouse.wheel(0, 1750)
|
||||
|
||||
await customBlocks.scrollIntoViewIfNeeded()
|
||||
|
||||
await expect(customBlocks).toHaveValue('Block 1: Prefilled Title')
|
||||
|
||||
await page
|
||||
.locator('.custom-blocks-field-management')
|
||||
.getByRole('button', { name: 'Add Block 2' })
|
||||
.click()
|
||||
await expect(
|
||||
page.locator('#field-customBlocks input[name="customBlocks.1.block2Title"]'),
|
||||
).toHaveValue('Block 2: Prefilled Title')
|
||||
|
||||
await page
|
||||
.locator('.custom-blocks-field-management')
|
||||
.getByRole('button', { name: 'Replace Block 2' })
|
||||
.click()
|
||||
await expect(
|
||||
page.locator('#field-customBlocks input[name="customBlocks.1.block1Title"]'),
|
||||
).toHaveValue('REPLACED BLOCK')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -534,434 +534,6 @@ describe('fields', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('blocks', () => {
|
||||
let url: AdminUrlUtil
|
||||
beforeAll(() => {
|
||||
url = new AdminUrlUtil(serverURL, 'block-fields')
|
||||
})
|
||||
|
||||
test('should open blocks drawer and select first block', async () => {
|
||||
await page.goto(url.create)
|
||||
const addButton = page.locator('#field-blocks > .blocks-field__drawer-toggler')
|
||||
await expect(addButton).toContainText('Add Block')
|
||||
await addButton.click()
|
||||
|
||||
const blocksDrawer = page.locator('[id^=drawer_1_blocks-drawer-]')
|
||||
await expect(blocksDrawer).toBeVisible()
|
||||
|
||||
// select the first block in the drawer
|
||||
const firstBlockSelector = blocksDrawer
|
||||
.locator('.blocks-drawer__blocks .blocks-drawer__block')
|
||||
.first()
|
||||
await expect(firstBlockSelector).toContainText('Content')
|
||||
await firstBlockSelector.click()
|
||||
|
||||
// ensure the block was appended to the rows
|
||||
const addedRow = page.locator('#field-blocks .blocks-field__row').last()
|
||||
await expect(addedRow).toBeVisible()
|
||||
await expect(addedRow.locator('.blocks-field__block-pill-content')).toContainText('Content')
|
||||
})
|
||||
|
||||
test('should open blocks drawer from block row and add below', async () => {
|
||||
await page.goto(url.create)
|
||||
const firstRow = page.locator('#field-blocks #blocks-row-0')
|
||||
const rowActions = firstRow.locator('.collapsible__actions')
|
||||
await expect(rowActions).toBeVisible()
|
||||
|
||||
await rowActions.locator('.array-actions__button').click()
|
||||
const addBelowButton = rowActions.locator('.array-actions__action.array-actions__add')
|
||||
await expect(addBelowButton).toBeVisible()
|
||||
await addBelowButton.click()
|
||||
|
||||
const blocksDrawer = page.locator('[id^=drawer_1_blocks-drawer-]')
|
||||
await expect(blocksDrawer).toBeVisible()
|
||||
|
||||
// select the first block in the drawer
|
||||
const firstBlockSelector = blocksDrawer
|
||||
.locator('.blocks-drawer__blocks .blocks-drawer__block')
|
||||
.first()
|
||||
await expect(firstBlockSelector).toContainText('Content')
|
||||
await firstBlockSelector.click()
|
||||
|
||||
// ensure the block was inserted beneath the first in the rows
|
||||
const addedRow = page.locator('#field-blocks #blocks-row-1')
|
||||
await expect(addedRow).toBeVisible()
|
||||
await expect(addedRow.locator('.blocks-field__block-pill-content')).toContainText('Content') // went from `Number` to `Content`
|
||||
})
|
||||
|
||||
test('should use i18n block labels', async () => {
|
||||
await page.goto(url.create)
|
||||
await expect(page.locator('#field-i18nBlocks .blocks-field__header')).toContainText(
|
||||
'Block en',
|
||||
)
|
||||
|
||||
const addButton = page.locator('#field-i18nBlocks > .blocks-field__drawer-toggler')
|
||||
await expect(addButton).toContainText('Add Block en')
|
||||
await addButton.click()
|
||||
|
||||
const blocksDrawer = page.locator('[id^=drawer_1_blocks-drawer-]')
|
||||
await expect(blocksDrawer).toBeVisible()
|
||||
|
||||
// select the first block in the drawer
|
||||
const firstBlockSelector = blocksDrawer
|
||||
.locator('.blocks-drawer__blocks .blocks-drawer__block')
|
||||
.first()
|
||||
await expect(firstBlockSelector).toContainText('Text en')
|
||||
await firstBlockSelector.click()
|
||||
|
||||
// ensure the block was appended to the rows
|
||||
const firstRow = page.locator('#field-i18nBlocks .blocks-field__row').first()
|
||||
await expect(firstRow).toBeVisible()
|
||||
await expect(firstRow.locator('.blocks-field__block-pill-text')).toContainText('Text en')
|
||||
})
|
||||
|
||||
test('should add different blocks with similar field configs', async () => {
|
||||
await page.goto(url.create)
|
||||
|
||||
async function addBlock(name: 'Block A' | 'Block B') {
|
||||
await page
|
||||
.locator('#field-blocksWithSimilarConfigs')
|
||||
.getByRole('button', { name: 'Add Blocks With Similar Config' })
|
||||
.click()
|
||||
await page.getByRole('button', { name }).click()
|
||||
}
|
||||
|
||||
await addBlock('Block A')
|
||||
|
||||
await page
|
||||
.locator('#blocksWithSimilarConfigs-row-0')
|
||||
.getByRole('button', { name: 'Add Item' })
|
||||
.click()
|
||||
await page
|
||||
.locator('input[name="blocksWithSimilarConfigs.0.items.0.title"]')
|
||||
.fill('items>0>title')
|
||||
|
||||
await expect(
|
||||
page.locator('input[name="blocksWithSimilarConfigs.0.items.0.title"]'),
|
||||
).toHaveValue('items>0>title')
|
||||
|
||||
await addBlock('Block B')
|
||||
|
||||
await page
|
||||
.locator('#blocksWithSimilarConfigs-row-1')
|
||||
.getByRole('button', { name: 'Add Item' })
|
||||
.click()
|
||||
await page
|
||||
.locator('input[name="blocksWithSimilarConfigs.1.items.0.title2"]')
|
||||
.fill('items>1>title')
|
||||
|
||||
await expect(
|
||||
page.locator('input[name="blocksWithSimilarConfigs.1.items.0.title2"]'),
|
||||
).toHaveValue('items>1>title')
|
||||
})
|
||||
|
||||
test('should bypass min rows validation when no rows present and field is not required', async () => {
|
||||
await page.goto(url.create)
|
||||
await saveDocAndAssert(page)
|
||||
await expect(page.locator('.Toastify')).toContainText('successfully')
|
||||
})
|
||||
|
||||
test('should fail min rows validation when rows are present', async () => {
|
||||
await page.goto(url.create)
|
||||
|
||||
await page
|
||||
.locator('#field-blocksWithMinRows')
|
||||
.getByRole('button', { name: 'Add Blocks With Min Row' })
|
||||
.click()
|
||||
|
||||
const blocksDrawer = page.locator('[id^=drawer_1_blocks-drawer-]')
|
||||
await expect(blocksDrawer).toBeVisible()
|
||||
|
||||
const firstBlockSelector = blocksDrawer
|
||||
.locator('.blocks-drawer__blocks .blocks-drawer__block')
|
||||
.first()
|
||||
|
||||
await firstBlockSelector.click()
|
||||
|
||||
const firstRow = page.locator('input[name="blocksWithMinRows.0.blockTitle"]')
|
||||
await expect(firstRow).toBeVisible()
|
||||
await firstRow.fill('first row')
|
||||
await expect(firstRow).toHaveValue('first row')
|
||||
|
||||
await page.click('#action-save', { delay: 100 })
|
||||
await expect(page.locator('.Toastify')).toContainText(
|
||||
'The following field is invalid: blocksWithMinRows',
|
||||
)
|
||||
})
|
||||
|
||||
describe('row manipulation', () => {
|
||||
describe('react hooks', () => {
|
||||
test('should add 2 new block rows', async () => {
|
||||
await page.goto(url.create)
|
||||
|
||||
await page
|
||||
.locator('.custom-blocks-field-management')
|
||||
.getByRole('button', { name: 'Add Block 1' })
|
||||
.click()
|
||||
|
||||
const customBlocks = page.locator(
|
||||
'#field-customBlocks input[name="customBlocks.0.block1Title"]',
|
||||
)
|
||||
|
||||
await page.mouse.wheel(0, 1750)
|
||||
|
||||
await customBlocks.scrollIntoViewIfNeeded()
|
||||
|
||||
await expect(customBlocks).toHaveValue('Block 1: Prefilled Title')
|
||||
|
||||
await page
|
||||
.locator('.custom-blocks-field-management')
|
||||
.getByRole('button', { name: 'Add Block 2' })
|
||||
.click()
|
||||
await expect(
|
||||
page.locator('#field-customBlocks input[name="customBlocks.1.block2Title"]'),
|
||||
).toHaveValue('Block 2: Prefilled Title')
|
||||
|
||||
await page
|
||||
.locator('.custom-blocks-field-management')
|
||||
.getByRole('button', { name: 'Replace Block 2' })
|
||||
.click()
|
||||
await expect(
|
||||
page.locator('#field-customBlocks input[name="customBlocks.1.block1Title"]'),
|
||||
).toHaveValue('REPLACED BLOCK')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('array', () => {
|
||||
let url: AdminUrlUtil
|
||||
beforeAll(() => {
|
||||
url = new AdminUrlUtil(serverURL, 'array-fields')
|
||||
})
|
||||
|
||||
test('should be readOnly', async () => {
|
||||
await page.goto(url.create)
|
||||
const field = page.locator('#field-readOnly__0__text')
|
||||
await expect(field).toBeDisabled()
|
||||
})
|
||||
|
||||
test('should have defaultValue', async () => {
|
||||
await page.goto(url.create)
|
||||
const field = page.locator('#field-readOnly__0__text')
|
||||
await expect(field).toHaveValue('defaultValue')
|
||||
})
|
||||
|
||||
test('should render RowLabel using a component', async () => {
|
||||
const label = 'custom row label as component'
|
||||
await page.goto(url.create)
|
||||
await page.locator('#field-rowLabelAsComponent >> .array-field__add-row').click()
|
||||
|
||||
await page.locator('#field-rowLabelAsComponent__0__title').fill(label)
|
||||
await wait(100)
|
||||
const customRowLabel = page.locator(
|
||||
'#rowLabelAsComponent-row-0 >> .array-field__row-header > :text("custom row label")',
|
||||
)
|
||||
await expect(customRowLabel).toHaveCSS('text-transform', 'uppercase')
|
||||
})
|
||||
|
||||
test('should bypass min rows validation when no rows present and field is not required', async () => {
|
||||
await page.goto(url.create)
|
||||
await saveDocAndAssert(page)
|
||||
await expect(page.locator('.Toastify')).toContainText('successfully')
|
||||
})
|
||||
|
||||
test('should fail min rows validation when rows are present', async () => {
|
||||
await page.goto(url.create)
|
||||
await page.locator('#field-arrayWithMinRows >> .array-field__add-row').click()
|
||||
|
||||
await page.click('#action-save', { delay: 100 })
|
||||
await expect(page.locator('.Toastify')).toContainText(
|
||||
'The following field is invalid: arrayWithMinRows',
|
||||
)
|
||||
})
|
||||
|
||||
describe('row manipulation', () => {
|
||||
test('should add, remove and duplicate rows', async () => {
|
||||
const assertText0 = 'array row 1'
|
||||
const assertGroupText0 = 'text in group in row 1'
|
||||
const assertText1 = 'array row 2'
|
||||
const assertText3 = 'array row 3'
|
||||
const assertGroupText3 = 'text in group in row 3'
|
||||
await page.goto(url.create)
|
||||
await page.mouse.wheel(0, 1750)
|
||||
await page.locator('#field-potentiallyEmptyArray').scrollIntoViewIfNeeded()
|
||||
await wait(300)
|
||||
|
||||
// Add 3 rows
|
||||
await page.locator('#field-potentiallyEmptyArray > .array-field__add-row').click()
|
||||
await wait(300)
|
||||
await page.locator('#field-potentiallyEmptyArray > .array-field__add-row').click()
|
||||
await wait(300)
|
||||
await page.locator('#field-potentiallyEmptyArray > .array-field__add-row').click()
|
||||
await wait(300)
|
||||
|
||||
// Fill out row 1
|
||||
await page.locator('#field-potentiallyEmptyArray__0__text').fill(assertText0)
|
||||
await page
|
||||
.locator('#field-potentiallyEmptyArray__0__groupInRow__textInGroupInRow')
|
||||
.fill(assertGroupText0)
|
||||
// Fill out row 2
|
||||
await page.locator('#field-potentiallyEmptyArray__1__text').fill(assertText1)
|
||||
// Fill out row 3
|
||||
await page.locator('#field-potentiallyEmptyArray__2__text').fill(assertText3)
|
||||
await page
|
||||
.locator('#field-potentiallyEmptyArray__2__groupInRow__textInGroupInRow')
|
||||
.fill(assertGroupText3)
|
||||
|
||||
// Remove row 1
|
||||
await page.locator('#potentiallyEmptyArray-row-0 .array-actions__button').click()
|
||||
await page
|
||||
.locator('#potentiallyEmptyArray-row-0 .popup__scroll-container .array-actions__remove')
|
||||
.click()
|
||||
// Remove row 2
|
||||
await page.locator('#potentiallyEmptyArray-row-0 .array-actions__button').click()
|
||||
await page
|
||||
.locator('#potentiallyEmptyArray-row-0 .popup__scroll-container .array-actions__remove')
|
||||
.click()
|
||||
|
||||
// Save document
|
||||
await saveDocAndAssert(page)
|
||||
|
||||
// Scroll to array row (fields are not rendered in DOM until on screen)
|
||||
await page.locator('#field-potentiallyEmptyArray__0__groupInRow').scrollIntoViewIfNeeded()
|
||||
|
||||
// Expect the remaining row to be the third row
|
||||
const input = page.locator('#field-potentiallyEmptyArray__0__groupInRow__textInGroupInRow')
|
||||
await expect(input).toHaveValue(assertGroupText3)
|
||||
|
||||
// Duplicate row
|
||||
await page.locator('#potentiallyEmptyArray-row-0 .array-actions__button').click()
|
||||
await page
|
||||
.locator(
|
||||
'#potentiallyEmptyArray-row-0 .popup__scroll-container .array-actions__duplicate',
|
||||
)
|
||||
.click()
|
||||
|
||||
// Update duplicated row group field text
|
||||
await page
|
||||
.locator('#field-potentiallyEmptyArray__1__groupInRow__textInGroupInRow')
|
||||
.fill(`${assertGroupText3} duplicate`)
|
||||
|
||||
// Save document
|
||||
await saveDocAndAssert(page)
|
||||
|
||||
// Expect the second row to be a duplicate of the remaining row
|
||||
await expect(
|
||||
page.locator('#field-potentiallyEmptyArray__1__groupInRow__textInGroupInRow'),
|
||||
).toHaveValue(`${assertGroupText3} duplicate`)
|
||||
|
||||
// Remove row 1
|
||||
await page.locator('#potentiallyEmptyArray-row-0 .array-actions__button').click()
|
||||
await page
|
||||
.locator('#potentiallyEmptyArray-row-0 .popup__scroll-container .array-actions__remove')
|
||||
.click()
|
||||
|
||||
// Save document
|
||||
await saveDocAndAssert(page)
|
||||
|
||||
// Expect the remaining row to be the copy of the duplicate row
|
||||
await expect(
|
||||
page.locator('#field-potentiallyEmptyArray__0__groupInRow__textInGroupInRow'),
|
||||
).toHaveValue(`${assertGroupText3} duplicate`)
|
||||
})
|
||||
})
|
||||
|
||||
// TODO: re-enable this test
|
||||
test.skip('should bulk update', async () => {
|
||||
await payload.create({
|
||||
collection: 'array-fields',
|
||||
data: {
|
||||
title: 'for test 1',
|
||||
items: [
|
||||
{
|
||||
text: 'test 1',
|
||||
},
|
||||
{
|
||||
text: 'test 2',
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
await payload.create({
|
||||
collection: 'array-fields',
|
||||
data: {
|
||||
title: 'for test 2',
|
||||
items: [
|
||||
{
|
||||
text: 'test 3',
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
await payload.create({
|
||||
collection: 'array-fields',
|
||||
data: {
|
||||
title: 'for test 3',
|
||||
items: [
|
||||
{
|
||||
text: 'test 4',
|
||||
},
|
||||
{
|
||||
text: 'test 5',
|
||||
},
|
||||
{
|
||||
text: 'test 6',
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
const bulkText = 'Bulk update text'
|
||||
await page.goto(url.list)
|
||||
await page.waitForSelector('.table > table > tbody > tr td.cell-title')
|
||||
const rows = page.locator('.table > table > tbody > tr', {
|
||||
has: page.locator('td.cell-title a', {
|
||||
hasText: 'for test',
|
||||
}),
|
||||
})
|
||||
const count = await rows.count()
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
await rows
|
||||
.nth(i)
|
||||
.locator('td.cell-_select .checkbox-input__input > input[type="checkbox"]')
|
||||
.click()
|
||||
}
|
||||
await page.locator('.edit-many__toggle').click()
|
||||
await page.locator('.field-select .rs__control').click()
|
||||
|
||||
const arrayOption = page.locator('.rs__option', {
|
||||
hasText: 'Items',
|
||||
})
|
||||
|
||||
await expect(arrayOption).toBeVisible()
|
||||
|
||||
await arrayOption.click()
|
||||
await wait(200)
|
||||
|
||||
const addRowButton = page.locator('#field-items > .array-field__add-row')
|
||||
|
||||
await expect(addRowButton).toBeVisible()
|
||||
|
||||
await addRowButton.click()
|
||||
await wait(200)
|
||||
|
||||
const targetInput = page.locator('#field-items__0__text')
|
||||
|
||||
await expect(targetInput).toBeVisible()
|
||||
|
||||
await targetInput.fill(bulkText)
|
||||
|
||||
await page.locator('#edit-array-fields .form-submit .edit-many__save').click()
|
||||
await expect(page.locator('.Toastify__toast--success')).toContainText(
|
||||
'Updated 3 Array Fields successfully.',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('tabs', () => {
|
||||
let url: AdminUrlUtil
|
||||
beforeAll(() => {
|
||||
|
||||
Reference in New Issue
Block a user