Files
payloadcms/test/field-error-states/e2e.spec.ts
Patrik f98d032617 feat: lock documents while being edited (#7970)
## Description

Adds a new property to `collection` / `global` configs called
`lockDocuments`.

Set to `true` by default - the lock is automatically triggered when a
user begins editing a document within the Admin Panel and remains in
place until the user exits the editing view or the lock expires due to
inactivity.

Set to `false` to disable document locking entirely - i.e.
`lockDocuments: false`

You can pass an object to this property to configure the `duration` in
seconds, which defines how long the document remains locked without user
interaction. If no edits are made within the specified time (default:
300 seconds), the lock expires, allowing other users to edit / update or
delete the document.

```
lockDocuments: {
  duration: 180, // 180 seconds or 3 minutes
}
```

- [x] I have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.

## Type of change

- [x] New feature (non-breaking change which adds functionality)

## Checklist:

- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] Existing test suite passes locally with my changes
- [x] I have made corresponding changes to the documentation
2024-09-17 14:04:48 -04:00

126 lines
5.0 KiB
TypeScript

import type { Page } from '@playwright/test'
import { expect, test } from '@playwright/test'
import { AdminUrlUtil } from 'helpers/adminUrlUtil.js'
import path from 'path'
import { wait } from 'payload/shared'
import { fileURLToPath } from 'url'
import { ensureCompilationIsDone, initPageConsoleErrorCatch, saveDocAndAssert } from '../helpers.js'
import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js'
import { TEST_TIMEOUT_LONG } from '../playwright.config.js'
import { collectionSlugs } from './shared.js'
const { beforeAll, describe } = test
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
describe('field error states', () => {
let serverURL: string
let page: Page
let validateDraftsOff: AdminUrlUtil
let validateDraftsOn: AdminUrlUtil
let validateDraftsOnAutosave: AdminUrlUtil
let prevValue: AdminUrlUtil
let prevValueRelation: AdminUrlUtil
beforeAll(async ({ browser }, testInfo) => {
testInfo.setTimeout(TEST_TIMEOUT_LONG)
;({ serverURL } = await initPayloadE2ENoConfig({ dirname }))
validateDraftsOff = new AdminUrlUtil(serverURL, collectionSlugs.validateDraftsOff)
validateDraftsOn = new AdminUrlUtil(serverURL, collectionSlugs.validateDraftsOn)
validateDraftsOnAutosave = new AdminUrlUtil(serverURL, collectionSlugs.validateDraftsOnAutosave)
prevValue = new AdminUrlUtil(serverURL, collectionSlugs.prevValue)
prevValueRelation = new AdminUrlUtil(serverURL, collectionSlugs.prevValueRelation)
const context = await browser.newContext()
page = await context.newPage()
initPageConsoleErrorCatch(page)
await ensureCompilationIsDone({ page, serverURL })
})
test('Remove row should remove error states from parent fields', async () => {
await page.goto(`${serverURL}/admin/collections/error-fields/create`)
// add parent array
await page.locator('#field-parentArray > .array-field__add-row').click()
// add first child array
await page.locator('#parentArray-row-0 .collapsible__content .array-field__add-row').click()
await page.locator('#field-parentArray__0__childArray__0__childArrayText').focus()
await page.keyboard.type('T1')
// add second child array
await page.locator('#parentArray-row-0 .collapsible__content .array-field__add-row').click()
await page.locator('#field-parentArray__0__childArray__1__childArrayText').focus()
await page.keyboard.type('T2')
// add third child array
await page.locator('#parentArray-row-0 .collapsible__content .array-field__add-row').click()
await page.locator('#parentArray-0-childArray-row-2 .array-actions__button').click()
await page
.locator('#parentArray-0-childArray-row-2 .array-actions__action.array-actions__remove')
.click()
await page.locator('#action-save').click()
const errorPill = await page.waitForSelector(
'#parentArray-row-0 > .collapsible > .collapsible__toggle-wrap .array-field__row-error-pill',
{ state: 'hidden', timeout: 500 },
)
expect(errorPill).toBeNull()
})
describe('draft validations', () => {
test('should not validate drafts by default', async () => {
await page.goto(validateDraftsOff.create)
await saveDocAndAssert(page, '#action-save-draft')
})
// eslint-disable-next-line playwright/expect-expect
test('should validate drafts when enabled', async () => {
await page.goto(validateDraftsOn.create)
await saveDocAndAssert(page, '#action-save-draft', 'error')
})
// eslint-disable-next-line playwright/expect-expect
test('should show validation errors when validate and autosave are enabled', async () => {
await page.goto(validateDraftsOnAutosave.create)
await page.locator('#field-title').fill('valid')
await saveDocAndAssert(page)
await page.locator('#field-title').fill('')
await saveDocAndAssert(page, '#action-save', 'error')
})
})
describe('previous values', () => {
test('should pass previous value into validate function', async () => {
// save original
await page.goto(prevValue.create)
await page.locator('#field-title').fill('original value')
await saveDocAndAssert(page)
await page.locator('#field-title').fill('original value 2')
await saveDocAndAssert(page)
await wait(500)
// create relation to doc
await page.goto(prevValueRelation.create)
await page.locator('#field-previousValueRelation .react-select').click()
await page.locator('#field-previousValueRelation .rs__option').first().click()
await saveDocAndAssert(page)
// go back to doc
await page.goto(prevValue.list)
await page.locator('.row-1 a').click()
await page.locator('#field-description').fill('some description')
await saveDocAndAssert(page)
await page.locator('#field-title').fill('changed')
await saveDocAndAssert(page, '#action-save', 'error')
// ensure value is the value before relationship association
await page.reload()
await expect(page.locator('#field-title')).toHaveValue('original value 2')
})
})
})