Skip to content

Commit a8b6983

Browse files
authored
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.
1 parent f2d4004 commit a8b6983

File tree

3 files changed

+111
-0
lines changed

3 files changed

+111
-0
lines changed

test/trash/collections/Users/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export const Users: CollectionConfig = {
77
admin: {
88
useAsTitle: 'name',
99
},
10+
trash: true,
1011
auth: true,
1112
fields: [
1213
{

test/trash/e2e.spec.ts

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js'
1515
import { TEST_TIMEOUT_LONG } from '../playwright.config.js'
1616
import { pagesSlug } from './collections/Pages/index.js'
1717
import { postsSlug } from './collections/Posts/index.js'
18+
import { usersSlug } from './collections/Users/index.js'
1819

1920
const filename = fileURLToPath(import.meta.url)
2021
const dirname = path.dirname(filename)
@@ -26,17 +27,20 @@ let postsUrl: AdminUrlUtil
2627
let pagesUrl: AdminUrlUtil
2728
let payload: PayloadTestSDK<Config>
2829
let serverURL: string
30+
let usersUrl: AdminUrlUtil
2931

3032
let pagesDocOne: PageType
3133
let postsDocOne: Post
3234
let postsDocTwo: Post
35+
let devUserID: number | string
3336

3437
describe('Trash', () => {
3538
beforeAll(async ({ browser }, testInfo) => {
3639
testInfo.setTimeout(TEST_TIMEOUT_LONG)
3740
;({ payload, serverURL } = await initPayloadE2ENoConfig<Config>({ dirname }))
3841
postsUrl = new AdminUrlUtil(serverURL, postsSlug)
3942
pagesUrl = new AdminUrlUtil(serverURL, pagesSlug)
43+
usersUrl = new AdminUrlUtil(serverURL, usersSlug)
4044

4145
const context = await browser.newContext()
4246
page = await context.newPage()
@@ -993,6 +997,110 @@ describe('Trash', () => {
993997
})
994998
})
995999
})
1000+
describe('Auth enabled collection', () => {
1001+
beforeAll(async () => {
1002+
// Ensure Dev user exists and store its ID
1003+
const { docs } = await payload.find({
1004+
collection: usersSlug,
1005+
limit: 1,
1006+
where: { name: { equals: 'Dev' } },
1007+
trash: true,
1008+
})
1009+
if (docs.length === 0) {
1010+
throw new Error('Dev user not found! Ensure test seed data includes a Dev user.')
1011+
}
1012+
devUserID = docs[0]?.id as number | string
1013+
})
1014+
1015+
async function ensureDevUserTrashed() {
1016+
const { docs } = await payload.find({
1017+
collection: usersSlug,
1018+
where: {
1019+
and: [{ name: { equals: 'Dev' } }, { deletedAt: { exists: true } }],
1020+
},
1021+
limit: 1,
1022+
trash: true,
1023+
})
1024+
1025+
if (docs.length === 0) {
1026+
// Trash the user if it's not already trashed
1027+
await payload.update({
1028+
collection: usersSlug,
1029+
id: devUserID,
1030+
data: { deletedAt: new Date().toISOString() },
1031+
})
1032+
}
1033+
}
1034+
1035+
test('Should show trash tab in the list view of a collection with auth enabled', async () => {
1036+
await page.goto(usersUrl.list)
1037+
1038+
await expect(page.locator('#trash-view-pill')).toBeVisible()
1039+
})
1040+
1041+
test('Should successfully trash a user from the list view and show it in the trash view', async () => {
1042+
await page.goto(usersUrl.list)
1043+
1044+
await page.locator('.row-1 .cell-_select input').check()
1045+
await page.locator('.list-selection__button[aria-label="Delete"]').click()
1046+
1047+
// Skip the checkbox to delete permanently and default to trashing
1048+
await page.locator('#confirm-delete-many-docs #confirm-action').click()
1049+
await expect(page.locator('.payload-toast-container .toast-success')).toHaveText(
1050+
'1 User moved to trash.',
1051+
)
1052+
// Navigate to the trash view
1053+
await page.locator('#trash-view-pill').click()
1054+
await expect(page.locator('.row-1 .cell-name')).toHaveText('Dev')
1055+
})
1056+
1057+
test('Should be able to access trashed doc edit view from the trash view', async () => {
1058+
await ensureDevUserTrashed()
1059+
1060+
await page.goto(usersUrl.trash)
1061+
1062+
await expect(page.locator('.row-1 .cell-name')).toHaveText('Dev')
1063+
await page.locator('.row-1 .cell-name').click()
1064+
1065+
await expect(page).toHaveURL(/\/users\/trash\/[a-f0-9]{24}$/)
1066+
})
1067+
1068+
test('Should properly disable auth fields in the trashed user edit view', async () => {
1069+
await ensureDevUserTrashed()
1070+
1071+
await page.goto(usersUrl.trash)
1072+
1073+
await page.locator('.row-1 .cell-name').click()
1074+
1075+
await expect(page.locator('input[name="email"]')).toBeDisabled()
1076+
await expect(page.locator('#change-password')).toBeDisabled()
1077+
1078+
await expect(page.locator('#field-name')).toBeDisabled()
1079+
await expect(page.locator('#field-roles .rs__input')).toBeDisabled()
1080+
})
1081+
1082+
test('Should properly restore trashed user as draft', async () => {
1083+
await ensureDevUserTrashed()
1084+
1085+
await page.goto(usersUrl.trash)
1086+
1087+
await expect(page.locator('.row-1 .cell-name')).toHaveText('Dev')
1088+
await page.locator('.row-1 .cell-name').click()
1089+
1090+
await page.locator('.doc-controls__controls #action-restore').click()
1091+
1092+
await expect(page.locator(`#restore-${devUserID} #confirm-action`)).toBeVisible()
1093+
await expect(
1094+
page.locator(`#restore-${devUserID} .confirmation-modal__content`),
1095+
).toContainText('You are about to restore the User')
1096+
1097+
await page.locator(`#restore-${devUserID} #confirm-action`).click()
1098+
1099+
await expect(page.locator('.payload-toast-container .toast-success')).toHaveText(
1100+
'User "Dev" successfully restored.',
1101+
)
1102+
})
1103+
})
9961104
})
9971105

9981106
async function createPageDoc(data: Partial<PageType>): Promise<PageType> {

test/trash/payload-types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ export interface User {
162162
roles?: ('is_user' | 'is_admin')[] | null;
163163
updatedAt: string;
164164
createdAt: string;
165+
deletedAt?: string | null;
165166
email: string;
166167
resetPasswordToken?: string | null;
167168
resetPasswordExpiration?: string | null;
@@ -284,6 +285,7 @@ export interface UsersSelect<T extends boolean = true> {
284285
roles?: T;
285286
updatedAt?: T;
286287
createdAt?: T;
288+
deletedAt?: T;
287289
email?: T;
288290
resetPasswordToken?: T;
289291
resetPasswordExpiration?: T;

0 commit comments

Comments
 (0)