chore(tests): adds array row manipulation tests (#3086)
This commit is contained in:
@@ -63,7 +63,7 @@ const ArrayFieldType: React.FC<Props> = (props) => {
|
||||
const locale = useLocale();
|
||||
const operation = useOperation();
|
||||
const { t, i18n } = useTranslation('fields');
|
||||
const { localization } = useConfig();
|
||||
const { localization, collections } = useConfig();
|
||||
|
||||
const editingDefaultLocale = (() => {
|
||||
if (localization && localization.fallback) {
|
||||
@@ -95,7 +95,7 @@ const ArrayFieldType: React.FC<Props> = (props) => {
|
||||
showError,
|
||||
errorMessage,
|
||||
value,
|
||||
rows,
|
||||
rows = [],
|
||||
valid,
|
||||
} = useField<number>({
|
||||
path,
|
||||
@@ -142,8 +142,8 @@ const ArrayFieldType: React.FC<Props> = (props) => {
|
||||
dispatchFields({ type: 'SET_ROW_COLLAPSED', path, collapsed, rowID, setDocFieldPreferences });
|
||||
}, [dispatchFields, path, setDocFieldPreferences]);
|
||||
|
||||
const hasMaxRows = maxRows && rows?.length >= maxRows;
|
||||
const fieldErrorCount = (rows || []).reduce((total, row) => total + (row?.childErrorPaths?.size || 0), 0) + (valid ? 0 : 1);
|
||||
const hasMaxRows = maxRows && rows.length >= maxRows;
|
||||
const fieldErrorCount = rows.reduce((total, row) => total + (row?.childErrorPaths?.size || 0), 0) + (valid ? 0 : 1);
|
||||
const fieldHasErrors = submitted && fieldErrorCount > 0;
|
||||
|
||||
const classes = [
|
||||
@@ -152,9 +152,7 @@ const ArrayFieldType: React.FC<Props> = (props) => {
|
||||
className,
|
||||
fieldHasErrors ? `${baseClass}--has-error` : `${baseClass}--has-no-error`,
|
||||
].filter(Boolean).join(' ');
|
||||
|
||||
if (!rows) return null;
|
||||
|
||||
console.log(path, collections[0].fields, fields);
|
||||
return (
|
||||
<div
|
||||
id={`field-${path.replace(/\./gi, '__')}`}
|
||||
@@ -218,6 +216,7 @@ const ArrayFieldType: React.FC<Props> = (props) => {
|
||||
<DraggableSortable
|
||||
ids={rows.map((row) => row.id)}
|
||||
onDragEnd={({ moveFromIndex, moveToIndex }) => moveRow(moveFromIndex, moveToIndex)}
|
||||
className={`${baseClass}__draggable-rows`}
|
||||
>
|
||||
{rows.length > 0 && rows.map((row, i) => (
|
||||
<DraggableSortableItem
|
||||
|
||||
@@ -80,6 +80,7 @@ const BlocksField: React.FC<Props> = (props) => {
|
||||
|
||||
return true;
|
||||
})();
|
||||
|
||||
const memoizedValidate = useCallback((value, options) => {
|
||||
// alternative locales can be null
|
||||
if (!editingDefaultLocale && value === null) {
|
||||
@@ -88,12 +89,11 @@ const BlocksField: React.FC<Props> = (props) => {
|
||||
return validate(value, { ...options, minRows, maxRows, required });
|
||||
}, [maxRows, minRows, required, validate, editingDefaultLocale]);
|
||||
|
||||
|
||||
const {
|
||||
showError,
|
||||
errorMessage,
|
||||
value,
|
||||
rows,
|
||||
rows = [],
|
||||
valid,
|
||||
} = useField<number>({
|
||||
path,
|
||||
@@ -141,7 +141,7 @@ const BlocksField: React.FC<Props> = (props) => {
|
||||
dispatchFields({ type: 'SET_ROW_COLLAPSED', path, collapsed, rowID, setDocFieldPreferences });
|
||||
}, [dispatchFields, path, setDocFieldPreferences]);
|
||||
|
||||
const hasMaxRows = maxRows && rows?.length >= maxRows;
|
||||
const hasMaxRows = maxRows && rows.length >= maxRows;
|
||||
|
||||
const fieldErrorCount = rows.reduce((total, row) => total + (row?.childErrorPaths?.size || 0), 0);
|
||||
const fieldHasErrors = submitted && fieldErrorCount + (valid ? 0 : 1) > 0;
|
||||
@@ -153,8 +153,6 @@ const BlocksField: React.FC<Props> = (props) => {
|
||||
fieldHasErrors ? `${baseClass}--has-error` : `${baseClass}--has-no-error`,
|
||||
].filter(Boolean).join(' ');
|
||||
|
||||
if (!rows) return null;
|
||||
|
||||
return (
|
||||
<div
|
||||
id={`field-${path.replace(/\./gi, '__')}`}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useAuth } from '../../utilities/Auth';
|
||||
import { useFormProcessing, useFormSubmitted, useFormModified, useForm, useFormFields, useWatchForm } from '../Form/context';
|
||||
import { useFormProcessing, useFormSubmitted, useForm, useFormFields } from '../Form/context';
|
||||
import { Options, FieldType } from './types';
|
||||
import { useDocumentInfo } from '../../utilities/DocumentInfo';
|
||||
import { useOperation } from '../../utilities/OperationProvider';
|
||||
import useThrottledEffect from '../../../hooks/useThrottledEffect';
|
||||
import { UPDATE } from '../Form/types';
|
||||
import type { UPDATE } from '../Form/types';
|
||||
|
||||
/**
|
||||
* Get and set the value of a form field.
|
||||
*
|
||||
* @see https://payloadcms.com/docs/admin/hooks#usefield
|
||||
*/
|
||||
const useField = <T,>(options: Options): FieldType<T> => {
|
||||
const useField = <T, >(options: Options): FieldType<T> => {
|
||||
const {
|
||||
path,
|
||||
validate,
|
||||
@@ -30,7 +30,6 @@ const useField = <T,>(options: Options): FieldType<T> => {
|
||||
const field = useFormFields(([fields]) => fields[path]);
|
||||
const { t } = useTranslation();
|
||||
const dispatchField = useFormFields(([_, dispatch]) => dispatch);
|
||||
const { fields } = useWatchForm();
|
||||
|
||||
const { getData, getSiblingData, setModified } = useForm();
|
||||
|
||||
@@ -147,10 +146,6 @@ const useField = <T,>(options: Options): FieldType<T> => {
|
||||
field?.rows,
|
||||
]);
|
||||
|
||||
if (path === 'items') {
|
||||
console.log({ fieldRows: field.rows, fieldRowsFromState: fields.items.rows });
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { buildConfigWithDefaults } from '../buildConfigWithDefaults';
|
||||
import { devUser } from '../credentials';
|
||||
|
||||
export default buildConfigWithDefaults({
|
||||
collections: [
|
||||
@@ -41,4 +42,13 @@ export default buildConfigWithDefaults({
|
||||
],
|
||||
},
|
||||
],
|
||||
onInit: async (payload) => {
|
||||
await payload.create({
|
||||
collection: 'users',
|
||||
data: {
|
||||
email: devUser.email,
|
||||
password: devUser.password,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -411,6 +411,88 @@ describe('fields', () => {
|
||||
const customRowLabel = await page.locator('#rowLabelAsComponent-row-0 >> .row-label :text("custom row label")');
|
||||
await expect(customRowLabel).toHaveCSS('text-transform', 'uppercase');
|
||||
});
|
||||
|
||||
describe('row manipulation', () => {
|
||||
test('should add 2 new rows', async () => {
|
||||
await page.goto(url.create);
|
||||
|
||||
await page.locator('#field-potentiallyEmptyArray > .array-field__add-button-wrap > button').click();
|
||||
await page.locator('#field-potentiallyEmptyArray > .array-field__add-button-wrap > button').click();
|
||||
await page.locator('#field-potentiallyEmptyArray__0__text').fill('array row 1');
|
||||
await page.locator('#field-potentiallyEmptyArray__1__text').fill('array row 2');
|
||||
|
||||
await saveDocAndAssert(page);
|
||||
});
|
||||
|
||||
test('should remove 2 new rows', async () => {
|
||||
await page.goto(url.create);
|
||||
|
||||
await page.locator('#field-potentiallyEmptyArray > .array-field__add-button-wrap > button').click();
|
||||
await page.locator('#field-potentiallyEmptyArray > .array-field__add-button-wrap > button').click();
|
||||
await page.locator('#field-potentiallyEmptyArray__0__text').fill('array row 1');
|
||||
await page.locator('#field-potentiallyEmptyArray__1__text').fill('array row 2');
|
||||
|
||||
await page.locator('#potentiallyEmptyArray-row-1 .array-actions__button').click();
|
||||
await page.locator('#potentiallyEmptyArray-row-1 .popup__scroll .array-actions__remove').click();
|
||||
await page.locator('#potentiallyEmptyArray-row-0 .array-actions__button').click();
|
||||
await page.locator('#potentiallyEmptyArray-row-0 .popup__scroll .array-actions__remove').click();
|
||||
|
||||
const rowsContainer = await page.locator('#field-potentiallyEmptyArray > .array-field__draggable-rows');
|
||||
const directChildDivCount = await rowsContainer.evaluate((element) => {
|
||||
const childDivCount = element.querySelectorAll(':scope > div');
|
||||
return childDivCount.length;
|
||||
});
|
||||
|
||||
expect(directChildDivCount).toBe(0);
|
||||
});
|
||||
|
||||
test('should remove existing row', async () => {
|
||||
await page.goto(url.create);
|
||||
|
||||
await page.locator('#field-potentiallyEmptyArray > .array-field__add-button-wrap > button').click();
|
||||
await page.locator('#field-potentiallyEmptyArray__0__text').fill('array row 1');
|
||||
|
||||
await saveDocAndAssert(page);
|
||||
|
||||
await page.locator('#potentiallyEmptyArray-row-0 .array-actions__button').click();
|
||||
await page.locator('#potentiallyEmptyArray-row-0 .popup__scroll .array-actions__action.array-actions__remove').click();
|
||||
|
||||
const rowsContainer = await page.locator('#field-potentiallyEmptyArray > .array-field__draggable-rows');
|
||||
const directChildDivCount = await rowsContainer.evaluate((element) => {
|
||||
const childDivCount = element.querySelectorAll(':scope > div');
|
||||
return childDivCount.length;
|
||||
});
|
||||
|
||||
expect(directChildDivCount).toBe(0);
|
||||
});
|
||||
|
||||
test('should add row after removing existing row', async () => {
|
||||
await page.goto(url.create);
|
||||
|
||||
await page.locator('#field-potentiallyEmptyArray > .array-field__add-button-wrap > button').click();
|
||||
await page.locator('#field-potentiallyEmptyArray > .array-field__add-button-wrap > button').click();
|
||||
await page.locator('#field-potentiallyEmptyArray__0__text').fill('array row 1');
|
||||
await page.locator('#field-potentiallyEmptyArray__1__text').fill('array row 2');
|
||||
|
||||
await saveDocAndAssert(page);
|
||||
|
||||
await page.locator('#potentiallyEmptyArray-row-1 .array-actions__button').click();
|
||||
await page.locator('#potentiallyEmptyArray-row-1 .popup__scroll .array-actions__action.array-actions__remove').click();
|
||||
await page.locator('#field-potentiallyEmptyArray > .array-field__add-button-wrap > button').click();
|
||||
|
||||
await page.locator('#field-potentiallyEmptyArray__1__text').fill('updated array row 2');
|
||||
|
||||
await saveDocAndAssert(page);
|
||||
|
||||
const rowsContainer = await page.locator('#field-potentiallyEmptyArray > .array-field__draggable-rows');
|
||||
const directChildDivCount = await rowsContainer.evaluate((element) => {
|
||||
const childDivCount = element.querySelectorAll(':scope > div');
|
||||
return childDivCount.length;
|
||||
});
|
||||
|
||||
expect(directChildDivCount).toBe(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('tabs', () => {
|
||||
@@ -494,7 +576,7 @@ describe('fields', () => {
|
||||
await wait(200);
|
||||
await editLinkModal.locator('button[type="submit"]').click();
|
||||
const errorField = await page.locator('[id^=drawer_1_rich-text-link-] .render-fields > :nth-child(3)');
|
||||
const hasErrorClass = await errorField.evaluate(el => el.classList.contains('error'));
|
||||
const hasErrorClass = await errorField.evaluate((el) => el.classList.contains('error'));
|
||||
expect(hasErrorClass).toBe(true);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user