diff --git a/packages/next/src/views/CreateFirstUser/index.client.tsx b/packages/next/src/views/CreateFirstUser/index.client.tsx index 4abe636cd6..23d564633e 100644 --- a/packages/next/src/views/CreateFirstUser/index.client.tsx +++ b/packages/next/src/views/CreateFirstUser/index.client.tsx @@ -6,16 +6,16 @@ import { useComponentMap } from '@payloadcms/ui/providers/ComponentMap' import React from 'react' export const CreateFirstUserFields: React.FC<{ - createFirstUserFieldMap: FieldMap + baseAuthFieldMap: FieldMap userSlug: string -}> = ({ createFirstUserFieldMap, userSlug }) => { +}> = ({ baseAuthFieldMap, userSlug }) => { const { getFieldMap } = useComponentMap() const fieldMap = getFieldMap({ collectionSlug: userSlug }) return ( = async ({ initPageRe }, } = initPageResult - const fields: Field[] = [ + const baseAuthFields: Field[] = [ { name: 'email', type: 'email', @@ -52,16 +52,29 @@ export const CreateFirstUserView: React.FC = async ({ initPageRe }, ] + const ssrAuthFields = [...baseAuthFields] + const WithServerSideProps: WithServerSidePropsType = ({ Component, ...rest }) => { return } - const createFirstUserFieldMap = mapFields({ + const userFieldSchema = config.collections.find((c) => c.slug === userSlug) + ssrAuthFields.push(...userFieldSchema.fields) + + const formState = await buildStateFromSchema({ + fieldSchema: ssrAuthFields, + operation: 'create', + preferences: { + fields: undefined + }, + req, + }) + + const baseAuthFieldMap = mapFields({ WithServerSideProps, config, - fieldSchema: fields, + fieldSchema: baseAuthFields, i18n, - parentPath: userSlug, }).map((field) => { // Transform field types for the password and confirm-password fields if (field.name === 'password') { @@ -83,13 +96,6 @@ export const CreateFirstUserView: React.FC = async ({ initPageRe return field }) - const formState = await buildStateFromSchema({ - fieldSchema: fields, - operation: 'create', - preferences: { fields: {} }, - req, - }) - return (

{req.t('general:welcome')}

@@ -101,10 +107,7 @@ export const CreateFirstUserView: React.FC = async ({ initPageRe redirect={adminRoute} validationOperation="create" > - + {req.t('general:create')}
diff --git a/packages/next/src/views/Edit/Default/Auth/index.tsx b/packages/next/src/views/Edit/Default/Auth/index.tsx index a7a69edc8b..03bbeb42c6 100644 --- a/packages/next/src/views/Edit/Default/Auth/index.tsx +++ b/packages/next/src/views/Edit/Default/Auth/index.tsx @@ -105,7 +105,7 @@ export const Auth: React.FC = (props) => { name="password" required /> - + )} diff --git a/packages/next/src/views/ResetPassword/index.tsx b/packages/next/src/views/ResetPassword/index.tsx index ebe5593d1c..e68afd257d 100644 --- a/packages/next/src/views/ResetPassword/index.tsx +++ b/packages/next/src/views/ResetPassword/index.tsx @@ -85,7 +85,7 @@ export const ResetPassword: React.FC = ({ initPageResult, params name="password" required /> - + {i18n.t('authentication:resetPassword')} diff --git a/packages/ui/src/fields/ConfirmPassword/index.tsx b/packages/ui/src/fields/ConfirmPassword/index.tsx index 4eebd8069e..85fd43dd9a 100644 --- a/packages/ui/src/fields/ConfirmPassword/index.tsx +++ b/packages/ui/src/fields/ConfirmPassword/index.tsx @@ -1,8 +1,10 @@ 'use client' -import type { FormField } from 'payload/types' +import type { Description, FormField, Validate } from 'payload/types' import React, { useCallback } from 'react' +import type { FormFieldBase } from '../shared/index.js' + import { FieldError } from '../../forms/FieldError/index.js' import { FieldLabel } from '../../forms/FieldLabel/index.js' import { useFormFields } from '../../forms/Form/context.js' @@ -10,13 +12,36 @@ import { useField } from '../../forms/useField/index.js' import { useTranslation } from '../../providers/Translation/index.js' import { fieldBaseClass } from '../shared/index.js' import './index.scss' - -export type ConfirmPasswordFieldProps = { +export type ConfirmPasswordFieldProps = FormFieldBase & { + autoComplete?: string + className?: string + description?: Description disabled?: boolean + label?: string + name: string + path?: string + required?: boolean + style?: React.CSSProperties + validate?: Validate + width?: string } export const ConfirmPassword: React.FC = (props) => { - const { disabled } = props + const { + name, + CustomError, + CustomLabel, + autoComplete, + className, + disabled, + errorProps, + label, + labelProps, + path: pathFromProps, + required, + style, + width, + } = props const password = useFormFields(([fields]) => fields.password) const { t } = useTranslation() @@ -36,11 +61,8 @@ export const ConfirmPassword: React.FC = (props) => { [password, t], ) - const path = 'confirm-password' - - const { setValue, showError, value } = useField({ - disableFormData: true, - path, + const { formProcessing, path, setValue, showError, value } = useField({ + path: pathFromProps || name, validate, }) @@ -58,9 +80,9 @@ export const ConfirmPassword: React.FC = (props) => { /> = (props) => { const { path, setValue, showError, value } = useField({ path: pathFromContext || pathFromProps || name, - validate: memoizedValidate, + validate: typeof validate === 'function' ? memoizedValidate : undefined, }) return ( diff --git a/test/auth/config.ts b/test/auth/config.ts index 42dba2fc0f..15bed3b8a6 100644 --- a/test/auth/config.ts +++ b/test/auth/config.ts @@ -216,29 +216,31 @@ export default buildConfigWithDefaults({ }, ], onInit: async (payload) => { - await payload.create({ - collection: 'users', - data: { - custom: 'Hello, world!', - email: devUser.email, - password: devUser.password, - }, - }) + if (process.env.SKIP_ON_INIT !== 'true') { + await payload.create({ + collection: 'users', + data: { + custom: 'Hello, world!', + email: devUser.email, + password: devUser.password, + }, + }) - await payload.create({ - collection: 'api-keys', - data: { - apiKey: uuid(), - enableAPIKey: true, - }, - }) + await payload.create({ + collection: 'api-keys', + data: { + apiKey: uuid(), + enableAPIKey: true, + }, + }) - await payload.create({ - collection: 'api-keys', - data: { - apiKey: uuid(), - enableAPIKey: true, - }, - }) + await payload.create({ + collection: 'api-keys', + data: { + apiKey: uuid(), + enableAPIKey: true, + }, + }) + } }, }) diff --git a/test/auth/e2e.spec.ts b/test/auth/e2e.spec.ts index 8d006fd2d7..17e7c5655f 100644 --- a/test/auth/e2e.spec.ts +++ b/test/auth/e2e.spec.ts @@ -1,13 +1,16 @@ import type { Page } from '@playwright/test' import { expect, test } from '@playwright/test' +import { devUser } from 'credentials.js' import path from 'path' +import { wait } from 'payload/utilities' import { fileURLToPath } from 'url' +import { v4 as uuid } from 'uuid' import type { PayloadTestSDK } from '../helpers/sdk/index.js' import type { Config } from './payload-types.js' -import { initPageConsoleErrorCatch, login, saveDocAndAssert } from '../helpers.js' +import { initPageConsoleErrorCatch, saveDocAndAssert } from '../helpers.js' import { AdminUrlUtil } from '../helpers/adminUrlUtil.js' import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js' import { POLL_TOPASS_TIMEOUT } from '../playwright.config.js' @@ -18,25 +21,37 @@ const dirname = path.dirname(filename) let payload: PayloadTestSDK -/** - * TODO: Auth - * create first user - * unlock - * log out - */ - const { beforeAll, describe } = test const headers = { 'Content-Type': 'application/json', } +const createFirstUser = async ({ page, serverURL }: { page: Page; serverURL: string }) => { + await page.goto(serverURL + '/admin/create-first-user') + await page.locator('#field-email').fill(devUser.email) + await page.locator('#field-password').fill(devUser.password) + await page.locator('#field-confirm-password').fill(devUser.password) + await page.locator('#field-custom').fill('Hello, world!') + + await wait(500) + + await page.locator('.form-submit > button').click() + + await expect + .poll(() => page.url(), { timeout: POLL_TOPASS_TIMEOUT }) + .not.toContain('create-first-user') +} + describe('auth', () => { let page: Page let url: AdminUrlUtil let serverURL: string let apiURL: string + // Allows for testing create-first-user + process.env.SKIP_ON_INIT = 'true' + beforeAll(async ({ browser }) => { ;({ payload, serverURL } = await initPayloadE2ENoConfig({ dirname })) apiURL = `${serverURL}/api` @@ -46,11 +61,22 @@ describe('auth', () => { page = await context.newPage() initPageConsoleErrorCatch(page) - //await delayNetwork({ context, page, delay: 'Slow 4G' }) + await createFirstUser({ page, serverURL }) - await login({ - page, - serverURL, + await payload.create({ + collection: 'api-keys', + data: { + apiKey: uuid(), + enableAPIKey: true, + }, + }) + + await payload.create({ + collection: 'api-keys', + data: { + apiKey: uuid(), + enableAPIKey: true, + }, }) }) diff --git a/test/fields-relationship/e2e.spec.ts b/test/fields-relationship/e2e.spec.ts index 6260c934f5..7e111ecc97 100644 --- a/test/fields-relationship/e2e.spec.ts +++ b/test/fields-relationship/e2e.spec.ts @@ -383,9 +383,11 @@ describe('fields - relationship', () => { }) await page.goto(url.create) - + // wait for relationship options to load + const relationFilterOptionsReq = page.waitForResponse(/api\/relation-filter-true/) // select relationshipMany field that relies on siblingData field above await page.locator('#field-relationshipManyFiltered .rs__control').click() + await relationFilterOptionsReq const options = page.locator('#field-relationshipManyFiltered .rs__menu') await expect(options).toContainText('truth')