test: collections and new test ids and classes
This commit is contained in:
@@ -25,7 +25,9 @@ const ButtonContents = ({ children, icon, tooltip }) => {
|
||||
const BuiltInIcon = icons[icon];
|
||||
|
||||
return (
|
||||
<span className={`${baseClass}__content`}>
|
||||
<span
|
||||
className={`${baseClass}__content`}
|
||||
>
|
||||
{tooltip && (
|
||||
<Tooltip className={`${baseClass}__tooltip`}>
|
||||
{tooltip}
|
||||
@@ -49,6 +51,7 @@ const ButtonContents = ({ children, icon, tooltip }) => {
|
||||
const Button: React.FC<Props> = (props) => {
|
||||
const {
|
||||
className,
|
||||
id,
|
||||
type = 'button',
|
||||
el,
|
||||
to,
|
||||
@@ -86,6 +89,7 @@ const Button: React.FC<Props> = (props) => {
|
||||
}
|
||||
|
||||
const buttonProps = {
|
||||
id,
|
||||
type,
|
||||
className: classes,
|
||||
disabled,
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, { MouseEvent } from 'react';
|
||||
|
||||
export type Props = {
|
||||
className?: string,
|
||||
id?: string,
|
||||
type?: 'submit' | 'button',
|
||||
el?: 'link' | 'anchor' | undefined,
|
||||
to?: string,
|
||||
@@ -12,6 +13,7 @@ export type Props = {
|
||||
icon?: React.ReactNode | ['chevron' | 'x' | 'plus' | 'edit'],
|
||||
iconStyle?: 'with-border' | 'without-border' | 'none',
|
||||
buttonStyle?: 'primary' | 'secondary' | 'transparent' | 'error' | 'none' | 'icon-label',
|
||||
buttonId?: string,
|
||||
round?: boolean,
|
||||
size?: 'small' | 'medium',
|
||||
iconPosition?: 'left' | 'right',
|
||||
|
||||
@@ -18,6 +18,7 @@ const DeleteDocument: React.FC<Props> = (props) => {
|
||||
const {
|
||||
title: titleFromProps,
|
||||
id,
|
||||
buttonId,
|
||||
collection: {
|
||||
admin: {
|
||||
useAsTitle,
|
||||
@@ -78,6 +79,7 @@ const DeleteDocument: React.FC<Props> = (props) => {
|
||||
<React.Fragment>
|
||||
<button
|
||||
type="button"
|
||||
id={buttonId}
|
||||
className={`${baseClass}__toggle`}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
@@ -105,6 +107,7 @@ const DeleteDocument: React.FC<Props> = (props) => {
|
||||
". Are you sure?
|
||||
</p>
|
||||
<Button
|
||||
id="confirm-cancel"
|
||||
buttonStyle="secondary"
|
||||
type="button"
|
||||
onClick={deleting ? undefined : () => toggle(modalSlug)}
|
||||
@@ -113,6 +116,7 @@ const DeleteDocument: React.FC<Props> = (props) => {
|
||||
</Button>
|
||||
<Button
|
||||
onClick={deleting ? undefined : handleDelete}
|
||||
id="confirm-delete"
|
||||
>
|
||||
{deleting ? 'Deleting...' : 'Confirm'}
|
||||
</Button>
|
||||
|
||||
@@ -3,5 +3,6 @@ import { SanitizedCollectionConfig } from '../../../../collections/config/types'
|
||||
export type Props = {
|
||||
collection?: SanitizedCollectionConfig,
|
||||
id?: string,
|
||||
buttonId?: string,
|
||||
title?: string,
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ const Duplicate: React.FC<Props> = ({ slug }) => {
|
||||
|
||||
return (
|
||||
<Button
|
||||
id="action-duplicate"
|
||||
buttonStyle="none"
|
||||
className={baseClass}
|
||||
onClick={handleClick}
|
||||
|
||||
@@ -16,7 +16,10 @@ const Table: React.FC<Props> = ({ columns, data }) => {
|
||||
<thead>
|
||||
<tr>
|
||||
{columns.map((col, i) => (
|
||||
<th key={i}>
|
||||
<th
|
||||
key={i}
|
||||
id={`heading-${col.accessor}`}
|
||||
>
|
||||
{col.components.Heading}
|
||||
</th>
|
||||
))}
|
||||
|
||||
@@ -105,6 +105,7 @@ const Condition: React.FC<Props> = (props) => {
|
||||
<div className={`${baseClass}__actions`}>
|
||||
<Button
|
||||
icon="x"
|
||||
className={`${baseClass}__actions-remove`}
|
||||
round
|
||||
buttonStyle="icon-label"
|
||||
iconStyle="with-border"
|
||||
@@ -116,6 +117,7 @@ const Condition: React.FC<Props> = (props) => {
|
||||
/>
|
||||
<Button
|
||||
icon="plus"
|
||||
className={`${baseClass}__actions-add`}
|
||||
round
|
||||
buttonStyle="icon-label"
|
||||
iconStyle="with-border"
|
||||
|
||||
@@ -8,7 +8,7 @@ import './index.scss';
|
||||
const baseClass = 'form-submit';
|
||||
|
||||
const FormSubmit: React.FC<Props> = (props) => {
|
||||
const { children, disabled: disabledFromProps, type = 'submit' } = props;
|
||||
const { children, buttonId: id, disabled: disabledFromProps, type = 'submit' } = props;
|
||||
const processing = useFormProcessing();
|
||||
const { disabled } = useForm();
|
||||
|
||||
@@ -16,6 +16,7 @@ const FormSubmit: React.FC<Props> = (props) => {
|
||||
<div className={baseClass}>
|
||||
<Button
|
||||
{...props}
|
||||
id={id}
|
||||
type={type}
|
||||
disabled={disabledFromProps || processing || disabled ? true : undefined}
|
||||
>
|
||||
|
||||
@@ -134,7 +134,14 @@ const DefaultEditView: React.FC<Props> = (props) => {
|
||||
<ul className={`${baseClass}__collection-actions`}>
|
||||
{(permissions?.create?.permission) && (
|
||||
<React.Fragment>
|
||||
<li><Link to={`${admin}/collections/${slug}/create`}>Create New</Link></li>
|
||||
<li>
|
||||
<Link
|
||||
id="action-create"
|
||||
to={`${admin}/collections/${slug}/create`}
|
||||
>
|
||||
Create New
|
||||
</Link>
|
||||
</li>
|
||||
{!disableDuplicate && (
|
||||
<li><DuplicateDocument slug={slug} /></li>
|
||||
)}
|
||||
@@ -145,6 +152,7 @@ const DefaultEditView: React.FC<Props> = (props) => {
|
||||
<DeleteDocument
|
||||
collection={collection}
|
||||
id={id}
|
||||
buttonId="action-delete"
|
||||
/>
|
||||
</li>
|
||||
)}
|
||||
@@ -167,7 +175,7 @@ const DefaultEditView: React.FC<Props> = (props) => {
|
||||
</React.Fragment>
|
||||
)}
|
||||
{!collection.versions?.drafts && (
|
||||
<FormSubmit>Save</FormSubmit>
|
||||
<FormSubmit buttonId="action-save">Save</FormSubmit>
|
||||
)}
|
||||
</React.Fragment>
|
||||
)}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { mapAsync } from '../../../src/utilities/mapAsync';
|
||||
import { devUser } from '../../credentials';
|
||||
import { buildConfig } from '../buildConfig';
|
||||
|
||||
export const slug = 'posts';
|
||||
@@ -26,6 +27,14 @@ export default buildConfig({
|
||||
],
|
||||
}],
|
||||
onInit: async (payload) => {
|
||||
await payload.create({
|
||||
collection: 'users',
|
||||
data: {
|
||||
email: devUser.email,
|
||||
password: devUser.password,
|
||||
},
|
||||
});
|
||||
|
||||
await mapAsync([...Array(11)], async () => {
|
||||
await payload.create({
|
||||
collection: slug,
|
||||
|
||||
@@ -2,8 +2,8 @@ import type { Page } from '@playwright/test';
|
||||
import { expect, test } from '@playwright/test';
|
||||
import payload from '../../../src';
|
||||
import { AdminUrlUtil } from '../../helpers/adminUrlUtil';
|
||||
import { initPayloadTest } from '../../helpers/configHelpers';
|
||||
import { firstRegister, saveDocAndAssert } from '../helpers';
|
||||
import { initPayloadE2E } from '../../helpers/configHelpers';
|
||||
import { login, saveDocAndAssert } from '../helpers';
|
||||
import type { Post } from './config';
|
||||
import { slug } from './config';
|
||||
import { mapAsync } from '../../../src/utilities/mapAsync';
|
||||
@@ -20,19 +20,14 @@ describe('collections', () => {
|
||||
let page: Page;
|
||||
|
||||
beforeAll(async ({ browser }) => {
|
||||
const { serverURL } = await initPayloadTest({
|
||||
__dirname,
|
||||
init: {
|
||||
local: false,
|
||||
},
|
||||
});
|
||||
const { serverURL } = await initPayloadE2E(__dirname);
|
||||
await clearDocs(); // Clear any seeded data from onInit
|
||||
url = new AdminUrlUtil(serverURL, slug);
|
||||
|
||||
const context = await browser.newContext();
|
||||
page = await context.newPage();
|
||||
|
||||
await firstRegister({ page, serverURL });
|
||||
await login({ page, serverURL });
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
@@ -50,13 +45,13 @@ describe('collections', () => {
|
||||
|
||||
test('should navigate to collection - card', async () => {
|
||||
await page.goto(url.admin);
|
||||
await page.locator('a:has-text("Posts")').click();
|
||||
await page.locator(`#card-${slug}`).click();
|
||||
expect(page.url()).toContain(url.list);
|
||||
});
|
||||
|
||||
test('breadcrumbs - from card to dashboard', async () => {
|
||||
test('breadcrumbs - from list to dashboard', async () => {
|
||||
await page.goto(url.list);
|
||||
await page.locator('a:has-text("Dashboard")').click();
|
||||
await page.locator('.step-nav a[href="/admin"]').click();
|
||||
expect(page.url()).toContain(url.admin);
|
||||
});
|
||||
|
||||
@@ -64,7 +59,7 @@ describe('collections', () => {
|
||||
const { id } = await createPost();
|
||||
|
||||
await page.goto(url.edit(id));
|
||||
await page.locator('nav >> text=Posts').click();
|
||||
await page.locator(`.step-nav >> text=${slug}`).click();
|
||||
expect(page.url()).toContain(url.list);
|
||||
});
|
||||
});
|
||||
@@ -73,14 +68,14 @@ describe('collections', () => {
|
||||
describe('CRUD', () => {
|
||||
test('should create', async () => {
|
||||
await page.goto(url.create);
|
||||
await page.locator('#title').fill(title);
|
||||
await page.locator('#description').fill(description);
|
||||
await page.click('text=Save', { delay: 100 });
|
||||
await page.locator('#field-title').fill(title);
|
||||
await page.locator('#field-description').fill(description);
|
||||
await page.click('#action-save', { delay: 100 });
|
||||
|
||||
await saveDocAndAssert(page);
|
||||
|
||||
await expect(page.locator('#title')).toHaveValue(title);
|
||||
await expect(page.locator('#description')).toHaveValue(description);
|
||||
await expect(page.locator('#field-title')).toHaveValue(title);
|
||||
await expect(page.locator('#field-description')).toHaveValue(description);
|
||||
});
|
||||
|
||||
test('should read existing', async () => {
|
||||
@@ -88,8 +83,8 @@ describe('collections', () => {
|
||||
|
||||
await page.goto(url.edit(id));
|
||||
|
||||
await expect(page.locator('#title')).toHaveValue(title);
|
||||
await expect(page.locator('#description')).toHaveValue(description);
|
||||
await expect(page.locator('#field-title')).toHaveValue(title);
|
||||
await expect(page.locator('#field-description')).toHaveValue(description);
|
||||
});
|
||||
|
||||
test('should update existing', async () => {
|
||||
@@ -99,21 +94,21 @@ describe('collections', () => {
|
||||
|
||||
const newTitle = 'new title';
|
||||
const newDesc = 'new description';
|
||||
await page.locator('#title').fill(newTitle);
|
||||
await page.locator('#description').fill(newDesc);
|
||||
await page.locator('#field-title').fill(newTitle);
|
||||
await page.locator('#field-description').fill(newDesc);
|
||||
|
||||
await saveDocAndAssert(page);
|
||||
|
||||
await expect(page.locator('#title')).toHaveValue(newTitle);
|
||||
await expect(page.locator('#description')).toHaveValue(newDesc);
|
||||
await expect(page.locator('#field-title')).toHaveValue(newTitle);
|
||||
await expect(page.locator('#field-description')).toHaveValue(newDesc);
|
||||
});
|
||||
|
||||
test('should delete existing', async () => {
|
||||
const { id } = await createPost();
|
||||
|
||||
await page.goto(url.edit(id));
|
||||
await page.locator('button:has-text("Delete")').click();
|
||||
await page.locator('button:has-text("Confirm")').click();
|
||||
await page.locator('#action-delete').click();
|
||||
await page.locator('#confirm-delete').click();
|
||||
|
||||
await expect(page.locator(`text=Post "${id}" successfully deleted.`)).toBeVisible();
|
||||
expect(page.url()).toContain(url.list);
|
||||
@@ -123,10 +118,10 @@ describe('collections', () => {
|
||||
const { id } = await createPost();
|
||||
|
||||
await page.goto(url.edit(id));
|
||||
await page.locator('button:has-text("Duplicate")').click();
|
||||
await page.locator('#action-duplicate').click();
|
||||
|
||||
expect(page.url()).toContain(url.create);
|
||||
await page.locator('button:has-text("Save")').click();
|
||||
await page.locator('#action-save').click();
|
||||
expect(page.url()).not.toContain(id); // new id
|
||||
});
|
||||
});
|
||||
@@ -149,7 +144,7 @@ describe('collections', () => {
|
||||
test('toggle columns', async () => {
|
||||
const columnCountLocator = 'table >> thead >> tr >> th';
|
||||
await createPost();
|
||||
await page.locator('button:has-text("Columns")').click();
|
||||
await page.locator('.list-controls__toggle-columns').click();
|
||||
await wait(1000); // Wait for column toggle UI, should probably use waitForSelector
|
||||
|
||||
const numberOfColumns = await page.locator(columnCountLocator).count();
|
||||
@@ -170,13 +165,13 @@ describe('collections', () => {
|
||||
|
||||
await expect(page.locator(tableRowLocator)).toHaveCount(2);
|
||||
|
||||
await page.locator('button:has-text("Filters")').click();
|
||||
await page.locator('.list-controls__toggle-where').click();
|
||||
await wait(1000); // Wait for column toggle UI, should probably use waitForSelector
|
||||
|
||||
await page.locator('text=Add filter').click();
|
||||
await page.locator('.where-builder__add-first-filter').click();
|
||||
|
||||
const operatorField = page.locator('.condition >> .condition__operator');
|
||||
const valueField = page.locator('.condition >> .condition__value >> input');
|
||||
const operatorField = page.locator('.condition__operator');
|
||||
const valueField = page.locator('.condition__value >> input');
|
||||
|
||||
await operatorField.click();
|
||||
|
||||
@@ -192,7 +187,7 @@ describe('collections', () => {
|
||||
expect(firstId).toEqual(id);
|
||||
|
||||
// Remove filter
|
||||
await page.locator('.condition >> .icon--x').click();
|
||||
await page.locator('.condition__actions-remove').click();
|
||||
await wait(1000);
|
||||
await expect(page.locator(tableRowLocator)).toHaveCount(2);
|
||||
});
|
||||
@@ -237,14 +232,11 @@ describe('collections', () => {
|
||||
|
||||
await expect(getTableItems()).toHaveCount(2);
|
||||
|
||||
const chevrons = page.locator('table >> thead >> th >> button');
|
||||
const upChevron = chevrons.first();
|
||||
const downChevron = chevrons.nth(1);
|
||||
const upChevron = page.locator('#heading-id .sort-column__asc');
|
||||
const downChevron = page.locator('#heading-id .sort-column__desc');
|
||||
|
||||
const getFirstId = async () => getTableItems().first().locator('td').first()
|
||||
.innerText();
|
||||
const getSecondId = async () => getTableItems().nth(1).locator('td').first()
|
||||
.innerText();
|
||||
const getFirstId = async () => page.locator('.row-1 .cell-id').innerText();
|
||||
const getSecondId = async () => page.locator('.row-2 .cell-id').innerText();
|
||||
|
||||
const firstId = await getFirstId();
|
||||
const secondId = await getSecondId();
|
||||
|
||||
@@ -37,7 +37,7 @@ export async function login(args: LoginArgs): Promise<void> {
|
||||
}
|
||||
|
||||
export async function saveDocAndAssert(page: Page): Promise<void> {
|
||||
await page.click('text=Save', { delay: 100 });
|
||||
await page.click('#action-save', { delay: 100 });
|
||||
await expect(page.locator('.Toastify')).toContainText('successfully');
|
||||
expect(page.url()).not.toContain('create');
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import express from 'express';
|
||||
import type { CollectionConfig } from '../../src/collections/config/types';
|
||||
import type { InitOptions } from '../../src/config/types';
|
||||
import payload from '../../src';
|
||||
import { devUser } from '../credentials';
|
||||
|
||||
type Options = {
|
||||
__dirname: string
|
||||
|
||||
Reference in New Issue
Block a user