test: adds e2e tests for auth enabled collections with trash enabled (#13317)

### What?
- Added new end-to-end tests covering trash functionality for
auth-enabled collections (e.g., `users`).
- Implemented test cases for:
  - Display of the trash tab in the list view.
  - Trashing a user and verifying its appearance in the trash view.
  - Accessing the trashed user edit view.
  - Ensuring all auth fields are properly disabled in trashed state.
  - Restoring a trashed user and verifying its status.

### Why?
- To ensure that the trash (soft-delete) feature works consistently for
collections with `auth: true`.
- To prevent regressions in user management flows, especially around
disabling and restoring trashed users.

### How?
- Added a new `Auth enabled collection` test suite in the E2E `Trash`
tests.
This commit is contained in:
Patrik
2025-07-30 17:11:02 -04:00
committed by GitHub
parent f2d4004237
commit a8b6983ab5
3 changed files with 111 additions and 0 deletions

View File

@@ -7,6 +7,7 @@ export const Users: CollectionConfig = {
admin: {
useAsTitle: 'name',
},
trash: true,
auth: true,
fields: [
{

View File

@@ -15,6 +15,7 @@ import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js'
import { TEST_TIMEOUT_LONG } from '../playwright.config.js'
import { pagesSlug } from './collections/Pages/index.js'
import { postsSlug } from './collections/Posts/index.js'
import { usersSlug } from './collections/Users/index.js'
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
@@ -26,10 +27,12 @@ let postsUrl: AdminUrlUtil
let pagesUrl: AdminUrlUtil
let payload: PayloadTestSDK<Config>
let serverURL: string
let usersUrl: AdminUrlUtil
let pagesDocOne: PageType
let postsDocOne: Post
let postsDocTwo: Post
let devUserID: number | string
describe('Trash', () => {
beforeAll(async ({ browser }, testInfo) => {
@@ -37,6 +40,7 @@ describe('Trash', () => {
;({ payload, serverURL } = await initPayloadE2ENoConfig<Config>({ dirname }))
postsUrl = new AdminUrlUtil(serverURL, postsSlug)
pagesUrl = new AdminUrlUtil(serverURL, pagesSlug)
usersUrl = new AdminUrlUtil(serverURL, usersSlug)
const context = await browser.newContext()
page = await context.newPage()
@@ -993,6 +997,110 @@ describe('Trash', () => {
})
})
})
describe('Auth enabled collection', () => {
beforeAll(async () => {
// Ensure Dev user exists and store its ID
const { docs } = await payload.find({
collection: usersSlug,
limit: 1,
where: { name: { equals: 'Dev' } },
trash: true,
})
if (docs.length === 0) {
throw new Error('Dev user not found! Ensure test seed data includes a Dev user.')
}
devUserID = docs[0]?.id as number | string
})
async function ensureDevUserTrashed() {
const { docs } = await payload.find({
collection: usersSlug,
where: {
and: [{ name: { equals: 'Dev' } }, { deletedAt: { exists: true } }],
},
limit: 1,
trash: true,
})
if (docs.length === 0) {
// Trash the user if it's not already trashed
await payload.update({
collection: usersSlug,
id: devUserID,
data: { deletedAt: new Date().toISOString() },
})
}
}
test('Should show trash tab in the list view of a collection with auth enabled', async () => {
await page.goto(usersUrl.list)
await expect(page.locator('#trash-view-pill')).toBeVisible()
})
test('Should successfully trash a user from the list view and show it in the trash view', async () => {
await page.goto(usersUrl.list)
await page.locator('.row-1 .cell-_select input').check()
await page.locator('.list-selection__button[aria-label="Delete"]').click()
// Skip the checkbox to delete permanently and default to trashing
await page.locator('#confirm-delete-many-docs #confirm-action').click()
await expect(page.locator('.payload-toast-container .toast-success')).toHaveText(
'1 User moved to trash.',
)
// Navigate to the trash view
await page.locator('#trash-view-pill').click()
await expect(page.locator('.row-1 .cell-name')).toHaveText('Dev')
})
test('Should be able to access trashed doc edit view from the trash view', async () => {
await ensureDevUserTrashed()
await page.goto(usersUrl.trash)
await expect(page.locator('.row-1 .cell-name')).toHaveText('Dev')
await page.locator('.row-1 .cell-name').click()
await expect(page).toHaveURL(/\/users\/trash\/[a-f0-9]{24}$/)
})
test('Should properly disable auth fields in the trashed user edit view', async () => {
await ensureDevUserTrashed()
await page.goto(usersUrl.trash)
await page.locator('.row-1 .cell-name').click()
await expect(page.locator('input[name="email"]')).toBeDisabled()
await expect(page.locator('#change-password')).toBeDisabled()
await expect(page.locator('#field-name')).toBeDisabled()
await expect(page.locator('#field-roles .rs__input')).toBeDisabled()
})
test('Should properly restore trashed user as draft', async () => {
await ensureDevUserTrashed()
await page.goto(usersUrl.trash)
await expect(page.locator('.row-1 .cell-name')).toHaveText('Dev')
await page.locator('.row-1 .cell-name').click()
await page.locator('.doc-controls__controls #action-restore').click()
await expect(page.locator(`#restore-${devUserID} #confirm-action`)).toBeVisible()
await expect(
page.locator(`#restore-${devUserID} .confirmation-modal__content`),
).toContainText('You are about to restore the User')
await page.locator(`#restore-${devUserID} #confirm-action`).click()
await expect(page.locator('.payload-toast-container .toast-success')).toHaveText(
'User "Dev" successfully restored.',
)
})
})
})
async function createPageDoc(data: Partial<PageType>): Promise<PageType> {

View File

@@ -162,6 +162,7 @@ export interface User {
roles?: ('is_user' | 'is_admin')[] | null;
updatedAt: string;
createdAt: string;
deletedAt?: string | null;
email: string;
resetPasswordToken?: string | null;
resetPasswordExpiration?: string | null;
@@ -284,6 +285,7 @@ export interface UsersSelect<T extends boolean = true> {
roles?: T;
updatedAt?: T;
createdAt?: T;
deletedAt?: T;
email?: T;
resetPasswordToken?: T;
resetPasswordExpiration?: T;