mirror of
https://github.com/strapi/strapi.git
synced 2025-08-06 15:53:11 +00:00
166 lines
5.2 KiB
TypeScript
166 lines
5.2 KiB
TypeScript
![]() |
import { expect, type Page } from '@playwright/test';
|
||
|
import { typeMap } from './content-types';
|
||
|
import { clickAndWait, findAndClose, navToHeader } from './shared';
|
||
|
|
||
|
export type FieldValueValue = string | number | boolean | null | Array<ComponentValue>;
|
||
|
|
||
|
export interface ComponentValue {
|
||
|
category: string; // Category the component belongs to
|
||
|
name: string; // Name of the component
|
||
|
fields: FieldValue[]; // Nested fields within the component
|
||
|
}
|
||
|
|
||
|
export interface FieldValue {
|
||
|
type: keyof typeof typeMap;
|
||
|
name: string;
|
||
|
value: FieldValueValue; // Use the extracted type here
|
||
|
}
|
||
|
|
||
|
export interface CreateContentOptions {
|
||
|
publish?: boolean;
|
||
|
save: boolean;
|
||
|
verify: boolean;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Fill a single field based on its type.
|
||
|
*/
|
||
|
export const fillField = async (page: Page, field: FieldValue): Promise<void> => {
|
||
|
const { name, type, value } = field;
|
||
|
|
||
|
switch (type) {
|
||
|
case 'boolean':
|
||
|
if (typeof value === 'boolean') {
|
||
|
const isChecked = await page.getByLabel(name).isChecked();
|
||
|
if (isChecked !== value) {
|
||
|
await page.getByLabel(name).click(); // Toggle checkbox
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 'dz':
|
||
|
if (Array.isArray(value)) {
|
||
|
for (const component of value) {
|
||
|
const { fields: componentFields } = component;
|
||
|
|
||
|
// Click "Add a component to {name}"
|
||
|
await page.getByRole('button', { name: `Add a component to ${name}` }).click();
|
||
|
|
||
|
// Expand component category if not open
|
||
|
const categoryButton = page.getByRole('button', { name: component.category });
|
||
|
if ((await categoryButton.getAttribute('data-state')) !== 'open') {
|
||
|
await categoryButton.click();
|
||
|
}
|
||
|
|
||
|
// Select the component to add it to the dz
|
||
|
const componentButton = page.getByRole('button', { name: component.name });
|
||
|
if ((await componentButton.getAttribute('data-state')) !== 'open') {
|
||
|
await componentButton.click();
|
||
|
}
|
||
|
|
||
|
// check if we need to expand it now that it has been added
|
||
|
const expandButton = page.getByRole('button', { name: component.name });
|
||
|
if ((await expandButton.getAttribute('data-state')) !== 'open') {
|
||
|
await expandButton.click();
|
||
|
}
|
||
|
|
||
|
// Fill component fields
|
||
|
if (componentFields && Array.isArray(componentFields)) {
|
||
|
for (const field of componentFields) {
|
||
|
await fillField(page, field);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
// TODO: all cases that cannot be handled as text fills
|
||
|
|
||
|
// all other cases can be handled as text fills
|
||
|
default:
|
||
|
await page.getByLabel(name).fill(String(value));
|
||
|
break;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Validate that fields have been saved correctly by checking their values on the page.
|
||
|
*/
|
||
|
export const verifyFields = async (page: Page, fields: FieldValue[]): Promise<void> => {
|
||
|
for (const field of fields) {
|
||
|
const { name, type, value } = field;
|
||
|
|
||
|
switch (type) {
|
||
|
case 'boolean':
|
||
|
const isChecked = await page.getByLabel(name).isChecked();
|
||
|
expect(isChecked).toBe(value);
|
||
|
break;
|
||
|
case 'dz':
|
||
|
for (const component of value as ComponentValue[]) {
|
||
|
const { fields: componentFields, name: compName } = component;
|
||
|
|
||
|
// Validate each field within the component
|
||
|
for (const componentField of componentFields) {
|
||
|
// Ensure the category is expanded
|
||
|
const categoryButton = page
|
||
|
.locator('button[data-state]', { hasText: compName })
|
||
|
.first();
|
||
|
|
||
|
if ((await categoryButton.getAttribute('data-state')) !== 'open') {
|
||
|
await categoryButton.click();
|
||
|
}
|
||
|
|
||
|
// TODO: make this only check within the dz box so we don't have to use unique names for each field
|
||
|
await verifyFields(page, [componentField]);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
const fieldValue = await page.getByLabel(name).inputValue();
|
||
|
expect(fieldValue).toBe(String(value)); // Verify text/numeric input values
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Fill all fields in the provided order.
|
||
|
*/
|
||
|
export const fillFields = async (page: Page, fields: FieldValue[]): Promise<void> => {
|
||
|
for (const field of fields) {
|
||
|
await fillField(page, field);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Main function to create content by filling fields and optionally publishing it.
|
||
|
*/
|
||
|
export const createContent = async (
|
||
|
page: Page,
|
||
|
contentType: string,
|
||
|
fields: FieldValue[],
|
||
|
options: CreateContentOptions
|
||
|
): Promise<void> => {
|
||
|
await navToHeader(page, ['Content Manager', contentType], contentType);
|
||
|
|
||
|
await clickAndWait(page, page.getByRole('link', { name: 'Create new entry' }));
|
||
|
|
||
|
await fillFields(page, fields);
|
||
|
|
||
|
if (options.save) {
|
||
|
await clickAndWait(page, page.getByRole('button', { name: 'Save' }));
|
||
|
await findAndClose(page, 'Saved Document');
|
||
|
}
|
||
|
|
||
|
if (options.publish) {
|
||
|
await clickAndWait(page, page.getByRole('button', { name: 'Publish' }));
|
||
|
await findAndClose(page, 'Published Document');
|
||
|
}
|
||
|
|
||
|
if (options.verify) {
|
||
|
// validate that data has been created successfully by refreshing page and checking that each field still has the value
|
||
|
await page.reload();
|
||
|
await verifyFields(page, fields);
|
||
|
}
|
||
|
};
|