fix(ui): issues with prevent leave and autosave when the form is submitted but invalid (#11233)

Fixes https://github.com/payloadcms/payload/issues/11224
Fixes https://github.com/payloadcms/payload/issues/10492

This PR fixes a few weird behaviours when `validate: true` is set on drafts:
- when autosave is on and you submit an invalid form it would get stuck in an infinite loop
- PreventLeave would not trigger for submitted but invalid forms leading to potential data loss

Changes:
- Adds e2e tests for the above scenarios
- Adds a new `isValid` flag on the `Form` context provider to signal globally if the form is in a valid or invalid state
  - Components like Autosave will manage this internally since it manages its own submission flow as well
- Adds PreventLeave to Autosave too for when form is invalid meaning data hasn't been actually saved so we want to prevent the user accidentally losing data by reloading or closing the page


The following tests have been added
![image](https://github.com/user-attachments/assets/db208aa4-6ed6-4287-b200-59575cd3c9d0)
This commit is contained in:
Paul
2025-02-18 19:12:41 +00:00
committed by GitHub
parent ede7bd7b4b
commit 06debf5e14
13 changed files with 441 additions and 18 deletions

View File

@@ -4,20 +4,32 @@ import { expect } from '@playwright/test'
import { wait } from 'payload/shared'
import { POLL_TOPASS_TIMEOUT } from 'playwright.config.js'
export async function waitForAutoSaveToRunAndComplete(page: Page) {
export async function waitForAutoSaveToRunAndComplete(
page: Page,
expectation: 'error' | 'success' = 'success',
) {
await expect(async () => {
await expect(page.locator('.autosave:has-text("Saving...")')).toBeVisible()
}).toPass({
timeout: POLL_TOPASS_TIMEOUT,
intervals: [50],
})
await wait(500)
await expect(async () => {
await expect(
page.locator('.autosave:has-text("Last saved less than a minute ago")'),
).toBeVisible()
}).toPass({
timeout: POLL_TOPASS_TIMEOUT,
})
if (expectation === 'success') {
await expect(async () => {
await expect(
page.locator('.autosave:has-text("Last saved less than a minute ago")'),
).toBeVisible()
}).toPass({
timeout: POLL_TOPASS_TIMEOUT,
})
} else {
await expect(async () => {
await expect(page.locator('.payload-toast-container .toast-error')).toBeVisible()
}).toPass({
timeout: POLL_TOPASS_TIMEOUT,
})
}
}