chore(tests): adds array row manipulation tests (#3086)

This commit is contained in:
Jarrod Flesch
2023-07-26 16:34:13 -04:00
committed by GitHub
parent 0a91950f05
commit 7542a92104
5 changed files with 105 additions and 21 deletions

View File

@@ -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

View File

@@ -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, '__')}`}

View File

@@ -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;
};

View File

@@ -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,
},
});
},
});

View File

@@ -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);
});