chore(tests): flakey drawer, tab, navigation tests (#5792)

This commit is contained in:
Jarrod Flesch
2024-04-11 12:57:19 -04:00
committed by GitHub
parent a4956dc649
commit c1081ccfe2
12 changed files with 79 additions and 50 deletions

View File

@@ -429,7 +429,10 @@ describe('admin', () => {
test('collection — should render `id` as `useAsTitle` fallback', async () => {
const { id } = await createPost()
await page.goto(postsUrl.edit(id))
const postURL = postsUrl.edit(id)
await page.goto(postURL)
await page.waitForURL(postURL)
await wait(500)
await page.locator('#field-title')?.fill('')
await expect(page.locator('.doc-header__title.render-title:has-text("ID:")')).toBeVisible()
await saveDocAndAssert(page)

View File

@@ -19,6 +19,7 @@ import {
ensureAutoLoginAndCompilationIsDone,
initPageConsoleErrorCatch,
openDocControls,
openDocDrawer,
saveDocAndAssert,
} from '../helpers.js'
import { AdminUrlUtil } from '../helpers/adminUrlUtil.js'
@@ -387,20 +388,15 @@ describe('fields - relationship', () => {
})
test('should open document drawer from read-only relationships', async () => {
await page.goto(url.edit(docWithExistingRelations.id))
const editURL = url.edit(docWithExistingRelations.id)
await page.goto(editURL)
await page.waitForURL(editURL)
const field = page.locator('#field-relationshipReadOnly')
const button = field.locator(
'button.relationship--single-value__drawer-toggler.doc-drawer__toggler',
await openDocDrawer(
page,
'#field-relationshipReadOnly button.relationship--single-value__drawer-toggler.doc-drawer__toggler',
)
await wait(1000)
await button.click()
await wait(1000)
const documentDrawer = page.locator('[id^=doc-drawer_relation-one_1_]')
await expect(documentDrawer).toBeVisible()
})

View File

@@ -12,6 +12,7 @@ import {
ensureAutoLoginAndCompilationIsDone,
exactText,
initPageConsoleErrorCatch,
openDocDrawer,
saveDocAndAssert,
saveDocHotkeyAndAssert,
} from '../../../helpers.js'
@@ -70,8 +71,8 @@ describe('relationship', () => {
test('should create inline relationship within field with many relations', async () => {
await page.goto(url.create)
const button = page.locator('#relationship-add-new .relationship-add-new__add-button')
await button.click()
await openDocDrawer(page, '#relationship-add-new .relationship-add-new__add-button')
await page
.locator('#field-relationship .relationship-add-new__relation-button--text-fields')
.click()
@@ -97,7 +98,7 @@ describe('relationship', () => {
await page.goto(url.create)
await page.waitForURL(`**/${url.create}`)
// Open first modal
await page.locator('#relationToSelf-add-new .relationship-add-new__add-button').click()
await openDocDrawer(page, '#relationToSelf-add-new .relationship-add-new__add-button')
// Fill first modal's required relationship field
await page.locator('[id^=doc-drawer_relationship-fields_1_] #field-relationship').click()
@@ -108,9 +109,10 @@ describe('relationship', () => {
.click()
// Open second modal
await page
.locator('[id^=doc-drawer_relationship-fields_1_] #relationToSelf-add-new button')
.click()
await openDocDrawer(
page,
'[id^=doc-drawer_relationship-fields_1_] #relationToSelf-add-new button',
)
// Fill second modal's required relationship field
await page.locator('[id^=doc-drawer_relationship-fields_2_] #field-relationship').click()
@@ -174,6 +176,7 @@ describe('relationship', () => {
// TODO: React-Select not loading things sometimes. Fix later
test.skip('should display `hasMany` polymorphic relationships', async () => {
await page.goto(url.create)
await page.waitForURL(url.create)
const field = page.locator('#field-relationHasManyPolymorphic')
await field.click()
@@ -209,6 +212,7 @@ describe('relationship', () => {
test('should populate relationship dynamic default value', async () => {
await page.goto(url.create)
await page.waitForURL(url.create)
await expect(
page.locator('#field-relationWithDynamicDefault .relationship--single-value__text'),
).toContainText('dev@payloadcms.com')
@@ -230,7 +234,7 @@ describe('relationship', () => {
await page.goto(url.create)
await page.waitForURL(`**/${url.create}`)
// First fill out the relationship field, as it's required
await page.locator('#relationship-add-new .relationship-add-new__add-button').click()
await openDocDrawer(page, '#relationship-add-new .relationship-add-new__add-button')
await page
.locator('#field-relationship .relationship-add-new__relation-button--text-fields')
.click()
@@ -245,7 +249,7 @@ describe('relationship', () => {
// Create a new doc for the `relationshipHasMany` field
await expect.poll(() => page.url(), { timeout: POLL_TOPASS_TIMEOUT }).not.toContain('create')
await page.locator('#field-relationshipHasMany .relationship-add-new__add-button').click()
await openDocDrawer(page, '#field-relationshipHasMany .relationship-add-new__add-button')
const value = 'Hello, world!'
await page.locator('.drawer__content #field-text').fill(value)
@@ -293,7 +297,8 @@ describe('relationship', () => {
// opened through the edit button can be saved using the hotkey.
test('should save using hotkey in edit document drawer', async () => {
await page.goto(url.create)
await wait(500)
// First fill out the relationship field, as it's required
await openDocDrawer(page, '#relationship-add-new .relationship-add-new__add-button')
await page.locator('#field-relationship .value-container').click()
await wait(500)
// Select "Seeded text document" relationship
@@ -334,7 +339,7 @@ describe('relationship', () => {
test.skip('should bypass min rows validation when no rows present and field is not required', async () => {
await page.goto(url.create)
// First fill out the relationship field, as it's required
await page.locator('#relationship-add-new .relationship-add-new__add-button').click()
await openDocDrawer(page, '#relationship-add-new .relationship-add-new__add-button')
await page.locator('#field-relationship .value-container').click()
await page.getByText('Seeded text document', { exact: true }).click()
@@ -344,8 +349,9 @@ describe('relationship', () => {
test('should fail min rows validation when rows are present', async () => {
await page.goto(url.create)
await page.waitForURL(url.create)
// First fill out the relationship field, as it's required
await page.locator('#relationship-add-new .relationship-add-new__add-button').click()
await openDocDrawer(page, '#relationship-add-new .relationship-add-new__add-button')
await page.locator('#field-relationship .value-container').click()
await page.getByText('Seeded text document', { exact: true }).click()
@@ -366,26 +372,28 @@ describe('relationship', () => {
test('should sort relationship options by sortOptions property (ID in ascending order)', async () => {
await page.goto(url.create)
await page.waitForURL(url.create)
const field = page.locator('#field-relationship')
await field.click()
const firstOption = page.locator('.rs__option').first()
await expect(firstOption).toBeVisible()
const firstOptionText = await firstOption.textContent()
expect(firstOptionText.trim()).toBe('Another text document')
const textDocsGroup = page.locator('.rs__group-heading:has-text("Text Fields")')
const firstTextDocOption = textDocsGroup.locator('+div .rs__option').first()
const firstOptionLabel = await firstTextDocOption.textContent()
expect(firstOptionLabel.trim()).toBe('Another text document')
})
test('should sort relationHasManyPolymorphic options by sortOptions property: text-fields collection (items in descending order)', async () => {
await page.goto(url.create)
await page.waitForURL(url.create)
const field = page.locator('#field-relationHasManyPolymorphic')
await field.click()
const firstOption = page.locator('.rs__option').first()
await expect(firstOption).toBeVisible()
const firstOptionText = await firstOption.textContent()
expect(firstOptionText.trim()).toBe('Seeded text document')
const textDocsGroup = page.locator('.rs__group-heading:has-text("Text Fields")')
const firstTextDocOption = textDocsGroup.locator('+div .rs__option').first()
const firstOptionLabel = await firstTextDocOption.textContent()
expect(firstOptionLabel).toBe('Seeded text document')
})
test('should allow filtering by relationship field / equals', async () => {
@@ -393,6 +401,7 @@ describe('relationship', () => {
await createRelationshipFieldDoc({ value: textDoc.id, relationTo: 'text-fields' })
await page.goto(url.list)
await page.waitForURL(url.list)
await page.locator('.list-controls__toggle-columns').click()
await page.locator('.list-controls__toggle-where').click()

View File

@@ -685,10 +685,7 @@ describe('fields', () => {
// enter date in default date field
await dateField.fill('02/07/2023')
await page.locator('#action-save').click()
// wait for navigation to update route
await expect.poll(() => page.url(), { timeout: 1000 }).not.toContain('create')
await saveDocAndAssert(page)
// get the ID of the doc
const routeSegments = page.url().split('/')

View File

@@ -131,8 +131,9 @@ export async function openNav(page: Page): Promise<void> {
}
export async function openDocDrawer(page: Page, selector: string): Promise<void> {
await page.locator(selector).click()
await wait(1000) // wait for drawer form state to initialize
await wait(300) // wait for parent form state to initialize
await page.locator(selector).click({ delay: 100 })
await wait(500) // wait for drawer form state to initializ
}
export async function closeNav(page: Page): Promise<void> {

View File

@@ -3,11 +3,11 @@ import type { Endpoint, PayloadHandler } from 'payload/config'
import httpStatus from 'http-status'
export const handler: PayloadHandler = async ({ payload, data, user }) => {
const method = String(data.method)
const operation = String(data.operation)
if (typeof payload[method] === 'function') {
if (typeof payload[operation] === 'function') {
try {
const result = await payload[method]({
const result = await payload[operation]({
...(typeof data.args === 'object' ? data.args : {}),
user,
})

View File

@@ -8,6 +8,7 @@ import type {
FindArgs,
GeneratedTypes,
UpdateArgs,
UpdateGlobalArgs,
} from './types.js'
type Args = {
@@ -15,7 +16,7 @@ type Args = {
}
export class PayloadTestSDK<TGeneratedTypes extends GeneratedTypes<TGeneratedTypes>> {
private fetch = async <T>({ jwt, reduceJSON, args, method }: FetchOptions): Promise<T> => {
private fetch = async <T>({ jwt, reduceJSON, args, operation }: FetchOptions): Promise<T> => {
const headers: HeadersInit = {
'Content-Type': 'application/json',
}
@@ -27,7 +28,7 @@ export class PayloadTestSDK<TGeneratedTypes extends GeneratedTypes<TGeneratedTyp
headers,
body: JSON.stringify({
args,
method,
operation,
}),
}).then((res) => res.json())
@@ -41,7 +42,7 @@ export class PayloadTestSDK<TGeneratedTypes extends GeneratedTypes<TGeneratedTyp
...args
}: CreateArgs<TGeneratedTypes, T>) => {
return this.fetch<TGeneratedTypes['collections'][T]>({
method: 'create',
operation: 'create',
args,
jwt,
})
@@ -52,7 +53,7 @@ export class PayloadTestSDK<TGeneratedTypes extends GeneratedTypes<TGeneratedTyp
...args
}: DeleteArgs<TGeneratedTypes, T>) => {
return this.fetch<PaginatedDocs<TGeneratedTypes['collections'][T]>>({
method: 'delete',
operation: 'delete',
args,
jwt,
})
@@ -63,7 +64,7 @@ export class PayloadTestSDK<TGeneratedTypes extends GeneratedTypes<TGeneratedTyp
...args
}: FindArgs<TGeneratedTypes, T>) => {
return this.fetch<PaginatedDocs<TGeneratedTypes['collections'][T]>>({
method: 'find',
operation: 'find',
args,
jwt,
})
@@ -71,7 +72,7 @@ export class PayloadTestSDK<TGeneratedTypes extends GeneratedTypes<TGeneratedTyp
sendEmail = async ({ jwt, ...args }: { jwt?: string } & SendMailOptions): Promise<unknown> => {
return this.fetch({
method: 'sendEmail',
operation: 'sendEmail',
args,
jwt,
})
@@ -84,7 +85,18 @@ export class PayloadTestSDK<TGeneratedTypes extends GeneratedTypes<TGeneratedTyp
...args
}: UpdateArgs<TGeneratedTypes, T>) => {
return this.fetch<TGeneratedTypes['collections'][T]>({
method: 'update',
operation: 'update',
args,
jwt,
})
}
updateGlobal = async <T extends keyof TGeneratedTypes['globals']>({
jwt,
...args
}: UpdateGlobalArgs<TGeneratedTypes, T>) => {
return this.fetch<TGeneratedTypes['collections'][T]>({
operation: 'updateGlobal',
args,
jwt,
})

View File

@@ -25,7 +25,7 @@ export type GeneratedTypes<T extends BaseTypes> = {
export type FetchOptions = {
args?: Record<string, unknown>
jwt?: string
method: 'create' | 'delete' | 'find' | 'sendEmail' | 'update'
operation: 'create' | 'delete' | 'find' | 'sendEmail' | 'update' | 'updateGlobal'
reduceJSON?: <R>(json: any) => R
}
@@ -94,6 +94,14 @@ export type UpdateArgs<
TSlug extends keyof TGeneratedTypes['collections'],
> = UpdateByIDArgs<TGeneratedTypes, TSlug> | UpdateManyArgs<TGeneratedTypes, TSlug>
export type UpdateGlobalArgs<
TGeneratedTypes extends GeneratedTypes<TGeneratedTypes>,
TSlug extends keyof TGeneratedTypes['globals'],
> = {
data: DeepPartial<TGeneratedTypes['globals'][TSlug]>
slug: TSlug
} & BaseArgs
export type FindArgs<
TGeneratedTypes extends GeneratedTypes<TGeneratedTypes>,
TSlug extends keyof TGeneratedTypes['collections'],

View File

@@ -3,7 +3,7 @@
import { useLivePreview } from '@payloadcms/live-preview-react'
import React from 'react'
import type { Page as PageType } from '../../../../test/live-preview/payload-types.js'
import type { Page as PageType } from '../../../../payload-types.js'
import { PAYLOAD_SERVER_URL } from '../../_api/serverURL.js'
import { Blocks } from '../../_components/Blocks/index.js'

View File

@@ -1,7 +1,7 @@
import { notFound } from 'next/navigation.js'
import React from 'react'
import type { Page } from '../../../../test/live-preview/payload-types.js'
import type { Page } from '../../../../payload-types.js'
import { fetchDoc } from '../../_api/fetchDoc.js'
import { fetchDocs } from '../../_api/fetchDocs.js'
@@ -28,6 +28,7 @@ export default async function Page({ params: { slug = 'home' } }) {
}
export async function generateStaticParams() {
process.env.PAYLOAD_DROP_DATABASE = 'false'
try {
const pages = await fetchDocs<Page>('pages')
return pages?.map(({ slug }) => slug)

View File

@@ -27,6 +27,7 @@ export default async function Post({ params: { slug = '' } }) {
}
export async function generateStaticParams() {
process.env.PAYLOAD_DROP_DATABASE = 'false'
try {
const posts = await fetchDocs<Post>('posts')
return posts?.map(({ slug }) => slug)

View File

@@ -214,6 +214,7 @@ describe('uploads', () => {
await page.waitForURL(audioURL.edit(audioDoc.id))
// remove the selection and open the list drawer
await wait(500) // flake workaround
await page.locator('.file-details__remove').click()
await openDocDrawer(page, '.upload__toggler.list-drawer__toggler')