test: fixes flaky localization e2e once and for all (#10406)

The localization e2e test is notorious for flaking, consuming a lot of
time and resources continually retrying. This was because the test was
attempting to click DOM elements using selectors that never resolve, or
attempting to click inaccessible DOM nodes such as those behind a modal.
The fix is to ensure that the dot nav, for example, is disabled while
form state loads, and that modals are properly closed prior to executing
subsequent tests, etc. Tests also needed to explicitly check for
_enabled_ states before performing click actions, rather than simply
awaiting their visibility.
This commit is contained in:
Jacob Fletcher
2025-01-06 23:45:38 -05:00
committed by GitHub
parent ef7191b39a
commit 5991a2e60f
5 changed files with 48 additions and 39 deletions

View File

@@ -13,6 +13,7 @@ import React, { Fragment, useEffect } from 'react'
import type { DocumentDrawerContextType } from '../DocumentDrawer/Provider.js'
import { useFormInitializing, useFormProcessing } from '../../forms/Form/context.js'
import { useConfig } from '../../providers/Config/index.js'
import { useEditDepth } from '../../providers/EditDepth/index.js'
import { useTranslation } from '../../providers/Translation/index.js'
@@ -111,6 +112,9 @@ export const DocumentControls: React.FC<{
const [updatedAt, setUpdatedAt] = React.useState<string>('')
const [createdAt, setCreatedAt] = React.useState<string>('')
const processing = useFormProcessing()
const initializing = useFormInitializing()
useEffect(() => {
if (data?.updatedAt) {
setUpdatedAt(formatDate({ date: data.updatedAt, i18n, pattern: dateFormat }))
@@ -255,6 +259,7 @@ export const DocumentControls: React.FC<{
</div>
}
className={`${baseClass}__popup`}
disabled={initializing || processing}
horizontalAlign="right"
size="large"
verticalAlign="bottom"

View File

@@ -63,16 +63,18 @@ export const PublishButton: React.FC<{ label?: string }> = ({ label: labelProp }
entityConfig?.versions?.drafts.schedulePublish
const hasNewerVersions = unpublishedVersionCount > 0
const canPublish =
hasPublishPermission &&
(modified || hasNewerVersions || !hasPublishedDoc) &&
uploadStatus !== 'uploading'
const operation = useOperation()
const forceDisable = operation === 'update' && !modified
const disabled = operation === 'update' && !modified
const saveDraft = useCallback(async () => {
if (forceDisable) {
if (disabled) {
return
}
@@ -99,7 +101,7 @@ export const PublishButton: React.FC<{ label?: string }> = ({ label: labelProp }
},
skipValidation: true,
})
}, [submit, collectionSlug, globalSlug, serverURL, api, localeCode, id, forceDisable])
}, [submit, collectionSlug, globalSlug, serverURL, api, localeCode, id, disabled])
useHotkey({ cmdCtrlKey: true, editDepth, keyCodes: ['s'] }, (e) => {
e.preventDefault()

View File

@@ -20,10 +20,10 @@ export const SaveButton: React.FC<{ label?: string }> = ({ label: labelProp }) =
const editDepth = useEditDepth()
const operation = useOperation()
const forceDisable = (operation === 'update' && !modified) || uploadStatus === 'uploading'
const disabled = (operation === 'update' && !modified) || uploadStatus === 'uploading'
useHotkey({ cmdCtrlKey: true, editDepth, keyCodes: ['s'] }, (e) => {
if (forceDisable) {
if (disabled) {
// absorb the event
}
@@ -45,7 +45,7 @@ export const SaveButton: React.FC<{ label?: string }> = ({ label: labelProp }) =
return (
<FormSubmit
buttonId="action-save"
disabled={forceDisable}
disabled={disabled}
onClick={handleSubmit}
ref={ref}
size="medium"

View File

@@ -23,6 +23,7 @@ export const SaveDraftButton: React.FC = () => {
} = useConfig()
const { id, collectionSlug, globalSlug, setUnpublishedVersionCount, uploadStatus } =
useDocumentInfo()
const modified = useFormModified()
const { code: locale } = useLocale()
const ref = useRef<HTMLButtonElement>(null)
@@ -31,10 +32,10 @@ export const SaveDraftButton: React.FC = () => {
const { submit } = useForm()
const operation = useOperation()
const forceDisable = (operation === 'update' && !modified) || uploadStatus === 'uploading'
const disabled = (operation === 'update' && !modified) || uploadStatus === 'uploading'
const saveDraft = useCallback(async () => {
if (forceDisable) {
if (disabled) {
return
}
@@ -71,12 +72,12 @@ export const SaveDraftButton: React.FC = () => {
api,
locale,
id,
forceDisable,
disabled,
setUnpublishedVersionCount,
])
useHotkey({ cmdCtrlKey: true, editDepth, keyCodes: ['s'] }, (e) => {
if (forceDisable) {
if (disabled) {
// absorb the event
}
@@ -92,7 +93,7 @@ export const SaveDraftButton: React.FC = () => {
buttonId="action-save-draft"
buttonStyle="secondary"
className={baseClass}
disabled={forceDisable}
disabled={disabled}
onClick={() => {
return void saveDraft()
}}

View File

@@ -1,4 +1,4 @@
import type { Page } from '@playwright/test'
import type { BrowserContext, Page } from '@playwright/test'
import { expect, test } from '@playwright/test'
import { openDocControls } from 'helpers/e2e/openDocControls.js'
@@ -14,6 +14,7 @@ import {
initPageConsoleErrorCatch,
openDocDrawer,
saveDocAndAssert,
throttleTest,
} from '../helpers.js'
import { AdminUrlUtil } from '../helpers/adminUrlUtil.js'
import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js'
@@ -28,6 +29,7 @@ import {
spanishLocale,
withRequiredLocalizedFields,
} from './shared.js'
import { navigateToDoc } from 'helpers/e2e/navigateToDoc.js'
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
@@ -40,7 +42,7 @@ const dirname = path.dirname(filename)
* Repeat above for Globals
*/
const { beforeAll, describe } = test
const { beforeAll, beforeEach, describe } = test
let url: AdminUrlUtil
let urlWithRequiredLocalizedFields: AdminUrlUtil
let urlRelationshipLocalized: AdminUrlUtil
@@ -54,6 +56,7 @@ let page: Page
let payload: PayloadTestSDK<Config>
let serverURL: string
let richTextURL: AdminUrlUtil
let context: BrowserContext
describe('Localization', () => {
beforeAll(async ({ browser }, testInfo) => {
@@ -65,7 +68,7 @@ describe('Localization', () => {
richTextURL = new AdminUrlUtil(serverURL, richTextSlug)
urlWithRequiredLocalizedFields = new AdminUrlUtil(serverURL, withRequiredLocalizedFields)
const context = await browser.newContext()
context = await browser.newContext()
page = await context.newPage()
initPageConsoleErrorCatch(page)
@@ -73,6 +76,14 @@ describe('Localization', () => {
await ensureCompilationIsDone({ page, serverURL })
})
beforeEach(async () => {
// await throttleTest({
// page,
// context,
// delay: 'Fast 4G',
// })
})
describe('localized text', () => {
test('create english post, switch to spanish', async () => {
await page.goto(url.create)
@@ -243,43 +254,30 @@ describe('Localization', () => {
})
describe('localized relationships', () => {
test('ensure relationship field fetches are localised as well', async () => {
await page.goto(url.list)
test('ensure relationship field fetches are localized as well', async () => {
await changeLocale(page, spanishLocale)
const localisedPost = page.locator('.cell-title a').first()
const localisedPostUrl = await localisedPost.getAttribute('href')
await page.goto(serverURL + localisedPostUrl)
await page.waitForURL(serverURL + localisedPostUrl)
await navigateToDoc(page, url)
const selectField = page.locator('#field-children .rs__control')
await selectField.click()
await expect(page.locator('#field-children .rs__menu')).toContainText('spanish-relation2')
})
test('ensure relationship edit drawers are opened in currently selected locale', async () => {
await page.goto(urlRelationshipLocalized.list)
await changeLocale(page, spanishLocale)
const post = page.locator('.cell-id a').first()
const postUrl = await post.getAttribute('href')
await page.goto(serverURL + postUrl)
await page.waitForURL(serverURL + postUrl)
await openDocDrawer(
page,
'#field-relationMultiRelationTo .relationship--single-value__drawer-toggler',
)
await navigateToDoc(page, urlRelationshipLocalized)
const drawerToggler =
'#field-relationMultiRelationTo .relationship--single-value__drawer-toggler'
expect(page.locator(drawerToggler)).toBeEnabled()
await openDocDrawer(page, drawerToggler)
await expect(page.locator('.doc-drawer__header-text')).toContainText('spanish-relation2')
await page.locator('.doc-drawer__header-close').click()
})
})
describe('copy localized data', () => {
test('should show Copy To Locale button and drawer', async () => {
await changeLocale(page, defaultLocale)
await createAndSaveDoc(page, url, { description, title })
await navigateToDoc(page, url)
await openCopyToLocaleDrawer(page)
await expect(page.locator('.copy-locale-data__content')).toBeVisible()
await page.locator('.drawer-close-button').click()
@@ -287,11 +285,9 @@ describe('Localization', () => {
test('should copy data to correct locale', async () => {
await createAndSaveDoc(page, url, { title })
await openCopyToLocaleDrawer(page)
await setToLocale(page, 'Spanish')
await runCopy(page)
await expect(page.locator('#field-title')).toHaveValue(title)
})
@@ -400,6 +396,9 @@ describe('Localization', () => {
await runCopy(page)
await expect(page.locator('#field-title')).toHaveValue(title)
const regexPattern = new RegExp(`locale=es`)
await expect(page).toHaveURL(regexPattern)
await openCopyToLocaleDrawer(page)
await setToLocale(page, 'Hungarian')
await runCopy(page)
@@ -445,11 +444,13 @@ async function createAndSaveDoc(page, url, values) {
}
async function openCopyToLocaleDrawer(page) {
const docControls = page.locator('.doc-controls__popup')
const docControls = page.locator('.doc-controls__popup button.popup-button')
expect(docControls).toBeEnabled()
await docControls.click()
const copyButton = page.locator('#copy-locale-data__button')
await expect(copyButton).toBeVisible()
await copyButton.click()
await expect(page.locator('#copy-locale')).toBeVisible()
await expect(page.locator('.copy-locale-data__content')).toBeVisible()
}