fix(ui): updates auth fields UI to reflect access control (#12745)

### What?
Reflects any access control restrictions applied to Auth fields in the
UI. I.e. if `email` has `update: () => false` the field should be
displayed as read-only.

### Why?
Currently any access control that is applied to auth fields is
functional but is not matched within the UI.

For example:
- `password` that does not have read access will not return data, but
the field will still be shown when it should be hidden
- `email` that does not have update access, updating the field and
saving the doc will **not** update the data, but it should be displayed
as read-only so nothing can be filled out and the updating restriction
is made clear

### How?
Passes field permissions through to the Auth fields UI and adds docs
with instructions on how to override auth field access.

#### Testing
Use `access-control` test suite and `auth` collection. Tests added to
`access-control` e2e.

Fixes #11569
This commit is contained in:
Jessica Rynkar
2025-06-25 14:55:07 +01:00
committed by GitHub
parent 0d50799b79
commit 1845669e68
9 changed files with 378 additions and 61 deletions

View File

@@ -6,7 +6,7 @@ import { devUser } from 'credentials.js'
import { openDocControls } from 'helpers/e2e/openDocControls.js'
import { openNav } from 'helpers/e2e/toggleNav.js'
import path from 'path'
import { wait } from 'payload/shared'
import { email, wait } from 'payload/shared'
import { fileURLToPath } from 'url'
import type { PayloadTestSDK } from '../helpers/sdk/index.js'
@@ -25,6 +25,7 @@ import { AdminUrlUtil } from '../helpers/adminUrlUtil.js'
import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js'
import { POLL_TOPASS_TIMEOUT, TEST_TIMEOUT_LONG } from '../playwright.config.js'
import {
authSlug,
createNotUpdateCollectionSlug,
disabledSlug,
docLevelAccessSlug,
@@ -53,7 +54,7 @@ const dirname = path.dirname(filename)
* Repeat all above for globals
*/
const { beforeAll, describe } = test
const { beforeAll, beforeEach, describe } = test
let payload: PayloadTestSDK<Config>
describe('Access Control', () => {
let page: Page
@@ -71,6 +72,7 @@ describe('Access Control', () => {
let serverURL: string
let context: BrowserContext
let logoutURL: string
let authFields: AdminUrlUtil
beforeAll(async ({ browser }, testInfo) => {
testInfo.setTimeout(TEST_TIMEOUT_LONG)
@@ -87,6 +89,7 @@ describe('Access Control', () => {
userRestrictedCollectionURL = new AdminUrlUtil(serverURL, userRestrictedCollectionSlug)
userRestrictedGlobalURL = new AdminUrlUtil(serverURL, userRestrictedGlobalSlug)
disabledFields = new AdminUrlUtil(serverURL, disabledSlug)
authFields = new AdminUrlUtil(serverURL, authSlug)
context = await browser.newContext()
page = await context.newPage()
@@ -228,7 +231,7 @@ describe('Access Control', () => {
/**
* This reproduces a bug where certain fields were incorrectly marked as read-only
*/
// eslint-disable-next-line playwright/expect-expect
test('ensure complex collection config fields show up in correct read-only state', async () => {
const regression1URL = new AdminUrlUtil(serverURL, 'regression1')
await page.goto(regression1URL.list)
@@ -272,7 +275,7 @@ describe('Access Control', () => {
/**
* This reproduces a bug where certain fields were incorrectly marked as read-only
*/
// eslint-disable-next-line playwright/expect-expect
test('ensure complex collection config fields show up in correct read-only state 2', async () => {
const regression2URL = new AdminUrlUtil(serverURL, 'regression2')
await page.goto(regression2URL.list)
@@ -733,6 +736,33 @@ describe('Access Control', () => {
await expect(page.locator('#field-array__0__text')).toBeDisabled()
})
})
describe('restricting update access to auth fields', () => {
let existingDoc: ReadOnlyCollection
beforeAll(async () => {
existingDoc = await payload.create({
collection: authSlug,
data: {
email: 'test@payloadcms.com',
password: 'test',
},
})
})
test('should show email as readonly when user does not have update permission', async () => {
await page.goto(authFields.edit(existingDoc.id))
const emailField = page.locator('#field-email')
await expect(emailField).toBeVisible()
await expect(emailField).toBeDisabled()
})
test('should hide Change Password button when user does not have update permission', async () => {
await page.goto(authFields.edit(existingDoc.id))
const passwordField = page.locator('#field-password')
await expect(passwordField).toBeHidden()
const changePasswordButton = page.locator('#change-password')
await expect(changePasswordButton).toBeHidden()
})
})
})
async function createDoc(data: any): Promise<Record<string, unknown> & TypeWithID> {