test(e2e): text fields advanced settings (#22635)

This commit is contained in:
Ben Irvin 2025-01-15 09:19:30 +01:00 committed by GitHub
parent a4bb06d54b
commit 7f7cfa5b39
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 88 additions and 17 deletions

View File

@ -81,7 +81,7 @@ const createConfig = ({ port, testDir, appDir }) => ({
/* Default time each action such as `click()` can take */
actionTimeout: getEnvNum(process.env.PLAYWRIGHT_ACTION_TIMEOUT, 10 * 1000),
// Only record trace when retrying a test to optimize test performance
trace: 'on-first-retry',
trace: process.env.CI ? 'on-first-retry' : 'retain-on-failure',
video: getEnvBool(process.env.PLAYWRIGHT_VIDEO, false)
? {
mode: 'on-first-retry', // Only save videos when retrying a test

View File

@ -24,7 +24,9 @@ test.describe('Adding content', () => {
name: 'testrepeatablecomp2',
icon: 'moon',
categorySelect: 'product',
attributes: [{ type: 'text', name: 'testrepeatablecomp2text' }],
attributes: [
{ type: 'text', name: 'testrepeatablecomp2text', advanced: { required: true } },
],
},
},
},
@ -37,7 +39,9 @@ test.describe('Adding content', () => {
name: 'testsinglecomp2',
icon: 'moon',
categorySelect: 'product',
attributes: [{ type: 'text', name: 'testsinglecomp2text' }],
attributes: [
{ type: 'text', name: 'testsinglecomp2text', advanced: { required: true } },
],
},
},
},
@ -55,7 +59,13 @@ test.describe('Adding content', () => {
name: 'testnewcomponentrepeatable',
icon: 'moon',
categorySelect: 'product',
attributes: [{ type: 'text', name: 'testnewcomponentexistingcategorytext' }],
attributes: [
{
type: 'text',
name: 'testnewcomponentexistingcategorytext',
advanced: { required: true },
},
],
},
},
},
@ -151,4 +161,35 @@ test.describe('Adding content', () => {
const before = await isElementBefore(source, target);
expect(before).toBe(true);
});
// TODO: can this become a loop to test every field? might work best to have a create where every first attempt to enter an attribute is made without a name
test('when I publish an empty required text field inside a dz I see an error', async ({
page,
}) => {
const fields = [
{
name: 'testdz',
type: 'dz',
value: [
{
category: 'product',
name: 'newcomponentexistingcategory',
fields: [
{
type: 'text',
name: 'testnewcomponentexistingcategorytext',
value: '',
},
],
},
],
},
] satisfies FieldValue[];
await createContent(page, 'Article', fields, { save: false, publish: true, verify: false });
// TODO: check that aria-invalid=true for this input
expect(page.getByText('This value is required')).toBeVisible();
});
});

View File

@ -194,12 +194,12 @@ export const createContent = async (
if (options.save) {
await clickAndWait(page, page.getByRole('button', { name: 'Save' }));
await findAndClose(page, 'Saved Document');
await findAndClose(page, 'Saved Document', { required: options.verify });
}
if (options.publish) {
await clickAndWait(page, page.getByRole('button', { name: 'Publish' }));
await findAndClose(page, 'Published Document');
await findAndClose(page, 'Published Document', { required: options.verify });
}
if (options.verify) {

View File

@ -1,8 +1,8 @@
import { kebabCase } from 'lodash/fp';
import { isBoolean, kebabCase } from 'lodash/fp';
import { waitForRestart } from './restart';
import pluralize from 'pluralize';
import { expect, type Page } from '@playwright/test';
import { clickAndWait, findByRowColumn, navToHeader } from './shared';
import { expect, Locator, type Page } from '@playwright/test';
import { clickAndWait, ensureCheckbox, findByRowColumn, navToHeader } from './shared';
export interface AddAttribute {
type: string;
@ -364,7 +364,15 @@ export const fillAttribute = async (page: Page, attribute: AddAttribute, options
await page.locator('textarea[name="enum"]').fill(attribute.enumeration?.values.join('\n'));
}
// TODO: add support for advanced options
if (attribute.advanced) {
const adv = attribute.advanced;
await page.getByText('Advanced Settings').click();
if (isBoolean(adv.required)) {
const checkbox = page.getByRole('checkbox', { name: 'Required field' });
await ensureCheckbox(checkbox, adv.required);
}
}
};
export const addAttributes = async (

View File

@ -84,15 +84,22 @@ export const clickAndWait = async (page: Page, locator: Locator) => {
/**
* Look for an element containing text, and then click a sibling close button
*/
export const findAndClose = async (
page: Page,
text: string,
role: string = 'status',
closeLabel: string = 'Close'
) => {
interface FindAndCloseOptions {
role?: string;
closeLabel?: string;
required?: boolean;
}
export const findAndClose = async (page: Page, text: string, options: FindAndCloseOptions = {}) => {
const { role = 'status', closeLabel = 'Close', required = true } = options;
// Verify the popup text is visible.
const elements = page.locator(`:has-text("${text}")[role="${role}"]`);
await expect(elements.first()).toBeVisible(); // expect at least one element
if (required) {
await expect(elements.first()).toBeVisible(); // expect at least one element
}
// Find all 'Close' buttons that are siblings of the elements containing the specified text.
const closeBtns = page.locator(
@ -384,3 +391,18 @@ export const isElementBefore = async (firstLocator, secondLocator) => {
return !!(first.compareDocumentPosition(second) & Node.DOCUMENT_POSITION_FOLLOWING);
}, secondHandle);
};
/**
* Ensures that the specified checkbox is in the desired checked state.
* If the checkbox's current state does not match the desired state, it clicks the checkbox to toggle it.
*
* @param {Locator} locator - Playwright locator for the checkbox element.
* @param {boolean} checked - Desired checked state of the checkbox (true for checked, false for unchecked).
* @returns {Promise<void>} - Resolves when the checkbox state is correctly set.
*/
export const ensureCheckbox = async (locator: Locator, checked: boolean) => {
const isChecked = await locator.isChecked();
if (isChecked !== checked) {
await locator.click();
}
};