feat!: new server-only, faster and immediate autoLogin (#7224)

- When autoLogin is enabled, it will no longer flash an unresponsive
"login" screen. Instead, it will straight up open the admin panel.
That's because, on the server, we will now always & immediately see the
user as authenticated, thus no initial login view is pushed to the
client until the client component sends the auth request anymore. Less
useless requests. Additionally, jwt verification is now completely
skipped
- No more auto-login related frontend code. autoLogin handling has been
removed from the frontend `Auth` component
- less code to maintain, this is way simpler now

**For reviewers:**
- The new logic for autoFill without prefillOnly is here: [jwt auth
strategy](https://github.com/payloadcms/payload/pull/7224/files#diff-7d40839079a8b2abb58233e5904513ab321023a70538229dfaf1dfee067dc8bfR21)
- The new logic for autoFill with prefillOnly is here: [Server Login
View](https://github.com/payloadcms/payload/pull/7224/files#diff-683770104f196196743398a698fbf8987f00e4426ca1c0ace3658d18ab80e82dL72)
=> [Client Login
Form](https://github.com/payloadcms/payload/pull/7224/files#diff-ac3504d3b3b0489455245663649bef9e84477bf0c1185da5a4d3a612450f01eeL20)

**BREAKING**
`autoLogin` without `prefillOnly` set now also affects graphQL/Rest
operations. Only the user specified in `autoLogin` will be returned.
Within the graphQL/Rest/Local API, this should still allow you to
authenticate with a different user, as the autoLogin user is only used
if no token is set.
This commit is contained in:
Alessio Gravili
2024-07-20 19:25:50 -04:00
committed by GitHub
parent 014ee1a1b2
commit a7b0f8ba36
45 changed files with 1171 additions and 1136 deletions

View File

@@ -86,19 +86,19 @@ const config = buildConfig({
The following options are available:
| Option | Description |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `autoLogin` | Used to automate admin log-in for dev and demonstration convenience. [More details](../authentication/overview). |
| `avatar` | Set account profile picture. Options: `gravatar`, `default` or a custom React component. |
| `buildPath` | Specify an absolute path for where to store the built Admin bundle used in production. Defaults to `path.resolve(process.cwd(), 'build')`. |
| `components` | Component overrides that affect the entirety of the Admin Panel. [More details](./components). |
| `custom` | Any custom properties you wish to pass to the Admin Panel. |
| `dateFormat` | The date format that will be used for all dates within the Admin Panel. Any valid [date-fns](https://date-fns.org/) format pattern can be used. |
| `disable` | If set to `true`, the entire Admin Panel will be disabled. |
| `livePreview` | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
| `meta` | Base metadata to use for the Admin Panel. Included properties are `titleSuffix`, `icons`, and `openGraph`. Can be overridden on a per Collection or per Global basis. |
| `routes` | Replace built-in Admin Panel routes with your own custom routes. [More details](#customizing-routes). |
| `user` | The `slug` of the Collection that you want to allow to login to the Admin Panel. [More details](#the-admin-user-collection). |
| Option | Description |
|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `avatar` | Set account profile picture. Options: `gravatar`, `default` or a custom React component. |
| `autoLogin` | Used to automate log-in for dev and demonstration convenience. [More details](../authentication/overview). |
| `buildPath` | Specify an absolute path for where to store the built Admin bundle used in production. Defaults to `path.resolve(process.cwd(), 'build')`. |
| `components` | Component overrides that affect the entirety of the Admin Panel. [More details](./components). |
| `custom` | Any custom properties you wish to pass to the Admin Panel. |
| `dateFormat` | The date format that will be used for all dates within the Admin Panel. Any valid [date-fns](https://date-fns.org/) format pattern can be used. |
| `disable` | If set to `true`, the entire Admin Panel will be disabled. |
| `livePreview` | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
| `meta` | Base metadata to use for the Admin Panel. Included properties are `titleSuffix`, `icons`, and `openGraph`. Can be overridden on a per Collection or per Global basis. |
| `routes` | Replace built-in Admin Panel routes with your own custom routes. [More details](#customizing-routes). |
| `user` | The `slug` of the Collection that you want to allow to login to the Admin Panel. [More details](#the-admin-user-collection). |
<Banner type="success">
<strong>Reminder:</strong>

View File

@@ -127,30 +127,27 @@ If set to `true`, users can log in with either their username or email address.
If set to `true`, an email address is required when creating a new user. If set to `false`, email is not required upon creation.
## Admin Auto-Login
## Auto-Login
For testing and demo purposes you may want to skip forcing the admin user to login in order to access the [Admin Panel](../admin/overview). Typically, all users should be required to login to access the Admin Panel, however, you can speed up local development time by enabling auto-login.
For testing and demo purposes you may want to skip forcing the user to login in order to access your application. Typically, all users should be required to login, however, you can speed up local development time by enabling auto-login.
To enable auto-login, set the `autoLogin` property in the [Admin Config](../configuration/admin):
```ts
import { buildConfig } from 'payload/config'
import { buildConfig } from 'payload'
export default buildConfig({
// ...
admin: {
// ...
// highlight-start
autoLogin:
process.env.NEXT_PUBLIC_ENABLE_AUTOLOGIN === 'true'
? {
email: 'test@example.com',
password: 'test',
prefillOnly: true,
}
: false,
// highlight-end
},
// highlight-start
autoLogin:
process.env.NEXT_PUBLIC_ENABLE_AUTOLOGIN === 'true'
? {
email: 'test@example.com',
password: 'test',
prefillOnly: true,
}
: false,
// highlight-end
})
```
@@ -162,9 +159,10 @@ export default buildConfig({
The following options are available:
| Option | Description |
| ----------------- | --------------------------------------------------------------------------------------------------------------- |
|-------------------|-----------------------------------------------------------------------------------------------------------------|
| **`username`** | The username of the user to login as |
| **`email`** | The email address of the user to login as |
| **`password`** | The password of the user to login as |
| **`password`** | The password of the user to login as. This is only needed if `prefillOnly` is set to true |
| **`prefillOnly`** | If set to true, the login credentials will be prefilled but the user will still need to click the login button. |
## Operations

View File

@@ -64,38 +64,38 @@ export default buildConfig({
The following options are available:
| Option | Description |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`admin`** | The configuration options for the Admin Panel, including Custom Components, Live Preview, etc. [More details](../admin/overview#admin-options). |
| **`bin`** | Register custom bin scripts for Payload to execute. |
| **`editor`** | The Rich Text Editor which will be used by `richText` fields. [More details](../rich-text/overview). |
| **`db`** \* | The Database Adapter which will be used by Payload. [More details](../database/overview). |
| **`serverURL`** | A string used to define the absolute URL of your app. This includes the protocol, for example `https://example.com`. No paths allowed, only protocol, domain and (optionally) port. |
| **`collections`** | An array of Collections for Payload to manage. [More details](./collections). |
| **`globals`** | An array of Globals for Payload to manage. [More details](./globals). |
| Option | Description |
|----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`admin`** | The configuration options for the Admin Panel, including Custom Components, Live Preview, etc. [More details](../admin/overview#admin-options). |
| **`bin`** | Register custom bin scripts for Payload to execute. |
| **`editor`** | The Rich Text Editor which will be used by `richText` fields. [More details](../rich-text/overview). |
| **`db`** \* | The Database Adapter which will be used by Payload. [More details](../database/overview). |
| **`serverURL`** | A string used to define the absolute URL of your app. This includes the protocol, for example `https://example.com`. No paths allowed, only protocol, domain and (optionally) port. |
| **`collections`** | An array of Collections for Payload to manage. [More details](./collections). |
| **`globals`** | An array of Globals for Payload to manage. [More details](./globals). |
| **`cors`** | Cross-origin resource sharing (CORS) is a mechanism that accept incoming requests from given domains. You can also customize the `Access-Control-Allow-Headers` header. [More details](#cors). |
| **`localization`** | Opt-in to translate your content into multiple locales. [More details](./localization). |
| **`graphQL`** | Manage GraphQL-specific functionality, including custom queries and mutations, query complexity limits, etc. [More details](../graphql/overview#graphql-options). |
| **`cookiePrefix`** | A string that will be prefixed to all cookies that Payload sets. |
| **`csrf`** | A whitelist array of URLs to allow Payload to accept cookies from. [More details](../authentication/overview#csrf-protection). |
| **`defaultDepth`** | If a user does not specify `depth` while requesting a resource, this depth will be used. [More details](../queries/depth). |
| **`defaultMaxTextLength`** | The maximum allowed string length to be permitted application-wide. Helps to prevent malicious public document creation. |
| **`maxDepth`** | The maximum allowed depth to be permitted application-wide. This setting helps prevent against malicious queries. Defaults to `10`. [More details](../queries/depth). |
| **`indexSortableFields`** | Automatically index all sortable top-level fields in the database to improve sort performance and add database compatibility for Azure Cosmos and similar. |
| **`upload`** | Base Payload upload configuration. [More details](../upload/overview#payload-wide-upload-options). |
| **`routes`** | Control the routing structure that Payload binds itself to. [More details](../admin/overview#root-level-routes). |
| **`email`** | Configure the Email Adapter for Payload to use. [More details](../email/overview). |
| **`debug`** | Enable to expose more detailed error information. |
| **`telemetry`** | Disable Payload telemetry by passing `false`. [More details](#telemetry). |
| **`rateLimit`** | Control IP-based rate limiting for all Payload resources. Used to prevent DDoS attacks, etc. [More details](../production/preventing-abuse#rate-limiting-requests). |
| **`hooks`** | An array of Root Hooks. [More details](../hooks/overview). |
| **`plugins`** | An array of Plugins. [More details](../plugins/overview). |
| **`endpoints`** | An array of Custom Endpoints added to the Payload router. [More details](../rest-api/overview#custom-endpoints). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins). |
| **`i18n`** | Internationalization configuration. Pass all i18n languages you'd like the admin UI to support. Defaults to English-only. [More details](./i18n). |
| **`secret`** \* | A secure, unguessable string that Payload will use for any encryption workflows - for example, password salt / hashing. |
| **`sharp`** | If you would like Payload to offer cropping, focal point selection, and automatic media resizing, install and pass the Sharp module to the config here. |
| **`typescript`** | Configure TypeScript settings here. [More details](#typescript). |
| **`localization`** | Opt-in to translate your content into multiple locales. [More details](./localization). |
| **`graphQL`** | Manage GraphQL-specific functionality, including custom queries and mutations, query complexity limits, etc. [More details](../graphql/overview#graphql-options). |
| **`cookiePrefix`** | A string that will be prefixed to all cookies that Payload sets. |
| **`csrf`** | A whitelist array of URLs to allow Payload to accept cookies from. [More details](../authentication/overview#csrf-protection). |
| **`defaultDepth`** | If a user does not specify `depth` while requesting a resource, this depth will be used. [More details](../queries/depth). |
| **`defaultMaxTextLength`** | The maximum allowed string length to be permitted application-wide. Helps to prevent malicious public document creation. |
| **`maxDepth`** | The maximum allowed depth to be permitted application-wide. This setting helps prevent against malicious queries. Defaults to `10`. [More details](../queries/depth). |
| **`indexSortableFields`** | Automatically index all sortable top-level fields in the database to improve sort performance and add database compatibility for Azure Cosmos and similar. |
| **`upload`** | Base Payload upload configuration. [More details](../upload/overview#payload-wide-upload-options). |
| **`routes`** | Control the routing structure that Payload binds itself to. [More details](../admin/overview#root-level-routes). |
| **`email`** | Configure the Email Adapter for Payload to use. [More details](../email/overview). |
| **`debug`** | Enable to expose more detailed error information. |
| **`telemetry`** | Disable Payload telemetry by passing `false`. [More details](#telemetry). |
| **`rateLimit`** | Control IP-based rate limiting for all Payload resources. Used to prevent DDoS attacks, etc. [More details](../production/preventing-abuse#rate-limiting-requests). |
| **`hooks`** | An array of Root Hooks. [More details](../hooks/overview). |
| **`plugins`** | An array of Plugins. [More details](../plugins/overview). |
| **`endpoints`** | An array of Custom Endpoints added to the Payload router. [More details](../rest-api/overview#custom-endpoints). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins). |
| **`i18n`** | Internationalization configuration. Pass all i18n languages you'd like the admin UI to support. Defaults to English-only. [More details](./i18n). |
| **`secret`** \* | A secure, unguessable string that Payload will use for any encryption workflows - for example, password salt / hashing. |
| **`sharp`** | If you would like Payload to offer cropping, focal point selection, and automatic media resizing, install and pass the Sharp module to the config here. |
| **`typescript`** | Configure TypeScript settings here. [More details](#typescript). |
_\* An asterisk denotes that a property is required._

View File

@@ -17,13 +17,15 @@ import { LoginField } from '../LoginField/index.js'
import './index.scss'
export const LoginForm: React.FC<{
prefillEmail?: string
prefillPassword?: string
prefillUsername?: string
searchParams: { [key: string]: string | string[] | undefined }
}> = ({ searchParams }) => {
}> = ({ prefillEmail, prefillPassword, prefillUsername, searchParams }) => {
const config = useConfig()
const {
admin: {
autoLogin,
routes: { forgot: forgotRoute },
user: userSlug,
},
@@ -45,27 +47,25 @@ export const LoginForm: React.FC<{
const { t } = useTranslation()
const prefillForm = autoLogin && autoLogin.prefillOnly
const initialState: FormState = {
password: {
initialValue: prefillForm ? autoLogin.password : undefined,
initialValue: prefillPassword ?? undefined,
valid: true,
value: prefillForm ? autoLogin.password : undefined,
value: prefillPassword ?? undefined,
},
}
if (loginWithUsername) {
initialState.username = {
initialValue: prefillForm ? autoLogin.username : undefined,
initialValue: prefillUsername ?? undefined,
valid: true,
value: prefillForm ? autoLogin.username : undefined,
value: prefillUsername ?? undefined,
}
} else {
initialState.email = {
initialValue: prefillForm ? autoLogin.email : undefined,
initialValue: prefillEmail ?? undefined,
valid: true,
value: prefillForm ? autoLogin.email : undefined,
value: prefillEmail ?? undefined,
}
}

View File

@@ -70,6 +70,24 @@ export const LoginView: React.FC<AdminViewProps> = ({ initPageResult, params, se
const collectionConfig = collections.find(({ slug }) => slug === userSlug)
const prefillAutoLogin =
typeof config.admin?.autoLogin === 'object' && config.admin?.autoLogin.prefillOnly
const prefillUsername =
prefillAutoLogin && typeof config.admin?.autoLogin === 'object'
? config.admin?.autoLogin.username
: undefined
const prefillEmail =
prefillAutoLogin && typeof config.admin?.autoLogin === 'object'
? config.admin?.autoLogin.email
: undefined
const prefillPassword =
prefillAutoLogin && typeof config.admin?.autoLogin === 'object'
? config.admin?.autoLogin.password
: undefined
return (
<Fragment>
<div className={`${loginBaseClass}__brand`}>
@@ -84,7 +102,14 @@ export const LoginView: React.FC<AdminViewProps> = ({ initPageResult, params, se
/>
</div>
{Array.isArray(BeforeLogins) && BeforeLogins.map((Component) => Component)}
{!collectionConfig?.auth?.disableLocalStrategy && <LoginForm searchParams={searchParams} />}
{!collectionConfig?.auth?.disableLocalStrategy && (
<LoginForm
prefillEmail={prefillEmail}
prefillPassword={prefillPassword}
prefillUsername={prefillUsername}
searchParams={searchParams}
/>
)}
{Array.isArray(AfterLogins) && AfterLogins.map((Component) => Component)}
</Fragment>
)

View File

@@ -1,5 +1,6 @@
import jwt from 'jsonwebtoken'
import type { Where } from '../../types/index.js'
import type { AuthStrategyFunction, User } from '../index.js'
import { extractJWT } from '../extractJWT.js'
@@ -16,6 +17,46 @@ export const JWTAuthentication: AuthStrategyFunction = async ({
}) => {
try {
const token = extractJWT({ headers, payload })
if (
!token &&
typeof payload?.config?.admin?.autoLogin === 'object' &&
!payload.config.admin?.autoLogin.prefillOnly &&
headers.get('DisableAutologin') !== 'true'
) {
const collection = payload.collections[payload.config.admin.user]
const where: Where = {
or: [],
}
if (payload.config.admin?.autoLogin.email) {
where.or.push({
email: {
equals: payload.config.admin?.autoLogin.email,
},
})
} else if (payload.config.admin?.autoLogin.username) {
where.or.push({
username: {
equals: payload.config.admin?.autoLogin.username,
},
})
}
const user = (
await payload.find({
collection: collection.config.slug,
depth: isGraphQL ? 0 : collection.config.auth.depth,
where,
})
).docs[0]
user.collection = collection.config.slug
user._strategy = 'local-jwt'
return {
user: user as User,
}
}
const decodedPayload = jwt.verify(token, payload.secret) as JWTToken & jwt.JwtPayload
const collection = payload.collections[decodedPayload.collection]

View File

@@ -43,6 +43,27 @@ export type ClientConfig = {
globals: ClientGlobalConfig[]
} & Omit<SanitizedConfig, 'admin' | 'collections' | 'globals' | ServerOnlyRootProperties>
const serverOnlyConfigProperties: readonly Partial<ServerOnlyRootProperties>[] = [
'endpoints',
'db',
'editor',
'plugins',
'sharp',
'onInit',
'secret',
'hooks',
'bin',
'typescript',
'cors',
'csrf',
'email',
'custom',
'graphQL',
// `admin`, `onInit`, `localization`, `collections`, and `globals` are all handled separately
]
const serverOnlyAdminProperties: readonly Partial<ServerOnlyRootAdminProperties>[] = ['components']
export const createClientConfig = async ({
config,
t,
@@ -53,49 +74,28 @@ export const createClientConfig = async ({
}): Promise<ClientConfig> => {
const clientConfig: ClientConfig = { ...config }
const serverOnlyConfigProperties: Partial<ServerOnlyRootProperties>[] = [
'endpoints',
'db',
'editor',
'plugins',
'sharp',
'onInit',
'secret',
'hooks',
'bin',
'typescript',
'cors',
'csrf',
'email',
'custom',
'graphQL',
// `admin`, `onInit`, `localization`, `collections`, and `globals` are all handled separately
]
serverOnlyConfigProperties.forEach((key) => {
for (const key of serverOnlyConfigProperties) {
if (key in clientConfig) {
delete clientConfig[key]
}
})
}
if ('localization' in clientConfig && clientConfig.localization) {
clientConfig.localization = { ...clientConfig.localization }
clientConfig.localization.locales.forEach((locale) => {
for (const locale of clientConfig.localization.locales) {
delete locale.toString
})
}
}
if ('admin' in clientConfig) {
clientConfig.admin = { ...clientConfig.admin }
const serverOnlyAdminProperties: Partial<ServerOnlyRootAdminProperties>[] = ['components']
serverOnlyAdminProperties.forEach((key) => {
for (const key of serverOnlyAdminProperties) {
if (key in clientConfig.admin) {
delete clientConfig.admin[key]
}
})
}
if ('livePreview' in clientConfig.admin) {
clientConfig.admin.livePreview = { ...clientConfig.admin.livePreview }

View File

@@ -453,16 +453,15 @@ export type CORSConfig = {
export type Config = {
/** Configure admin dashboard */
admin?: {
/** Automatically log in as a user when visiting the admin dashboard. */
/** Automatically log in as a user */
autoLogin?:
| {
/**
* The email address of the user to login as
*
*/
email?: string
/** The password of the user to login as */
password: string
/** The password of the user to login as. This is only needed if `prefillOnly` is set to true */
password?: string
/**
* If set to true, the login credentials will be prefilled but the user will still need to click the login button.
*
@@ -473,9 +472,9 @@ export type Config = {
username?: string
}
| false
/** Set account profile picture. Options: gravatar, default or a custom React component. */
avatar?: 'default' | 'gravatar' | React.ComponentType<any>
/**
* Add extra and/or replace built-in components with custom components
*

View File

@@ -12,7 +12,6 @@ import { useDebounce } from '../../hooks/useDebounce.js'
import { useTranslation } from '../../providers/Translation/index.js'
import { requests } from '../../utilities/api.js'
import { useConfig } from '../Config/index.js'
import { useSearchParams } from '../SearchParams/index.js'
export type AuthContext<T = ClientUser> = {
fetchFullUser: () => Promise<void>
@@ -34,11 +33,9 @@ const Context = createContext({} as AuthContext)
const maxTimeoutTime = 2147483647
export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const { searchParams } = useSearchParams()
const [user, setUser] = useState<ClientUser | null>()
const [tokenInMemory, setTokenInMemory] = useState<string>()
const [tokenExpiration, setTokenExpiration] = useState<number>()
const [strategy, setStrategy] = useState<string>()
const pathname = usePathname()
const router = useRouter()
// const { code } = useLocale()
@@ -48,9 +45,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
const {
admin: {
autoLogin,
routes: { inactivity: logoutInactivityRoute },
routes: { login: loginRoute },
user: userSlug,
},
routes: { admin, api },
@@ -79,7 +74,6 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
const revokeTokenAndExpire = useCallback(() => {
setTokenInMemory(undefined)
setTokenExpiration(undefined)
setStrategy(undefined)
}, [])
const setTokenAndExpiration = useCallback(
@@ -88,7 +82,6 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
if (token && json?.exp) {
setTokenInMemory(token)
setTokenExpiration(json.exp)
if (json.strategy) setStrategy(json.strategy)
} else {
revokeTokenAndExpire()
}
@@ -215,36 +208,6 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
if (json?.token) {
setTokenAndExpiration(json)
}
} else if (autoLogin && autoLogin.prefillOnly !== true) {
// auto log-in with the provided autoLogin credentials. This is used in dev mode
// so you don't have to log in over and over again
const autoLoginResult = await requests.post(
`${serverURL}${api}/${userSlug}${loginRoute}`,
{
body: JSON.stringify({
email: autoLogin.email,
password: autoLogin.password,
username: autoLogin.username,
}),
headers: {
'Accept-Language': i18n.language,
'Content-Type': 'application/json',
},
},
)
if (autoLoginResult.status === 200) {
const autoLoginJson = await autoLoginResult.json()
setUser(autoLoginJson.user)
if (autoLoginJson?.token) {
setTokenAndExpiration(autoLoginJson)
}
router.replace(
typeof searchParams['redirect'] === 'string' ? searchParams['redirect'] : admin,
)
} else {
setUser(null)
revokeTokenAndExpire()
}
} else {
setUser(null)
revokeTokenAndExpire()
@@ -253,21 +216,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
} catch (e) {
toast.error(`Fetching user failed: ${e.message}`)
}
}, [
serverURL,
api,
userSlug,
i18n.language,
autoLogin,
setTokenAndExpiration,
router,
searchParams,
admin,
revokeTokenAndExpire,
strategy,
tokenExpiration,
loginRoute,
])
}, [serverURL, api, userSlug, i18n.language, setTokenAndExpiration, revokeTokenAndExpire])
// On mount, get user and set
useEffect(() => {

View File

@@ -4,7 +4,7 @@ import { expect, test } from '@playwright/test'
import * as path from 'path'
import { fileURLToPath } from 'url'
import { ensureAutoLoginAndCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js'
import { ensureCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js'
import { AdminUrlUtil } from '../helpers/adminUrlUtil.js'
import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js'
import { TEST_TIMEOUT_LONG } from '../playwright.config.js'
@@ -25,7 +25,7 @@ test.describe('Admin Panel', () => {
const context = await browser.newContext()
page = await context.newPage()
initPageConsoleErrorCatch(page)
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
test('example test', async () => {

View File

@@ -16,6 +16,9 @@ export interface Config {
'payload-preferences': PayloadPreference;
'payload-migrations': PayloadMigration;
};
db: {
defaultIDType: string;
};
globals: {
menu: Menu;
'custom-ts': CustomT;
@@ -30,13 +33,16 @@ export interface UserAuthOperations {
email: string;
};
login: {
password: string;
email: string;
password: string;
};
registerFirstUser: {
email: string;
password: string;
};
unlock: {
email: string;
};
}
/**
* This interface was referenced by `Config`'s JSON-Schema

View File

@@ -16,7 +16,7 @@ import type {
import {
closeNav,
ensureAutoLoginAndCompilationIsDone,
ensureCompilationIsDone,
exactText,
getAdminRoutes,
initPageConsoleErrorCatch,
@@ -92,7 +92,7 @@ describe('access control', () => {
initPageConsoleErrorCatch(page)
await login({ page, serverURL })
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
const {
admin: {

View File

@@ -8,7 +8,7 @@ import type { Config, Geo, Post } from '../../payload-types.js'
import {
checkBreadcrumb,
checkPageTitle,
ensureAutoLoginAndCompilationIsDone,
ensureCompilationIsDone,
exactText,
getAdminRoutes,
initPageConsoleErrorCatch,
@@ -103,7 +103,7 @@ describe('admin1', () => {
snapshotKey: 'adminTests1',
})
await ensureAutoLoginAndCompilationIsDone({ customAdminRoutes, page, serverURL })
await ensureCompilationIsDone({ customAdminRoutes, page, serverURL })
adminRoutes = getAdminRoutes({ customAdminRoutes })
@@ -115,7 +115,7 @@ describe('admin1', () => {
snapshotKey: 'adminTests1',
})
await ensureAutoLoginAndCompilationIsDone({ customAdminRoutes, page, serverURL })
await ensureCompilationIsDone({ customAdminRoutes, page, serverURL })
})
describe('metadata', () => {
@@ -294,14 +294,6 @@ describe('admin1', () => {
await expect(() => expect(page.url()).not.toContain(loginURL)).toPass({
timeout: POLL_TOPASS_TIMEOUT,
})
// Ensure auto-login logged the user back in
await expect(() => expect(page.url()).toBe(`${serverURL}${adminRoutes.routes.admin}`)).toPass(
{
timeout: POLL_TOPASS_TIMEOUT,
},
)
})
})

View File

@@ -8,7 +8,7 @@ import * as qs from 'qs-esm'
import type { Config, Geo, Post } from '../../payload-types.js'
import {
ensureAutoLoginAndCompilationIsDone,
ensureCompilationIsDone,
exactText,
getAdminRoutes,
initPageConsoleErrorCatch,
@@ -67,7 +67,7 @@ describe('admin2', () => {
snapshotKey: 'adminTests2',
})
await ensureAutoLoginAndCompilationIsDone({ customAdminRoutes, page, serverURL })
await ensureCompilationIsDone({ customAdminRoutes, page, serverURL })
adminRoutes = getAdminRoutes({ customAdminRoutes })
})
@@ -77,7 +77,7 @@ describe('admin2', () => {
snapshotKey: 'adminTests2',
})
await ensureAutoLoginAndCompilationIsDone({ customAdminRoutes, page, serverURL })
await ensureCompilationIsDone({ customAdminRoutes, page, serverURL })
})
describe('custom CSS', () => {

View File

@@ -30,6 +30,9 @@ export interface Config {
'payload-preferences': PayloadPreference;
'payload-migrations': PayloadMigration;
};
db: {
defaultIDType: string;
};
globals: {
'hidden-global': HiddenGlobal;
'global-no-api-view': GlobalNoApiView;
@@ -49,13 +52,16 @@ export interface UserAuthOperations {
email: string;
};
login: {
password: string;
email: string;
password: string;
};
registerFirstUser: {
email: string;
password: string;
};
unlock: {
email: string;
};
}
/**
* This interface was referenced by `Config`'s JSON-Schema

View File

@@ -12,7 +12,7 @@ import type { PayloadTestSDK } from '../helpers/sdk/index.js'
import type { Config } from './payload-types.js'
import {
ensureAutoLoginAndCompilationIsDone,
ensureCompilationIsDone,
getAdminRoutes,
initPageConsoleErrorCatch,
saveDocAndAssert,
@@ -105,7 +105,7 @@ describe('auth', () => {
enableAPIKey: true,
},
})
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
describe('authenticated users', () => {

View File

@@ -179,15 +179,16 @@ export async function buildConfigWithDefaults(
},
}
config.admin = {
autoLogin:
if (!config.admin) {
config.admin = {}
}
if (config.admin.autoLogin === undefined) {
config.admin.autoLogin =
process.env.PAYLOAD_PUBLIC_DISABLE_AUTO_LOGIN === 'true'
? false
: {
email: 'dev@payloadcms.com',
password: 'test',
},
...(config.admin || {}),
}
}
if (process.env.PAYLOAD_DISABLE_ADMIN === 'true') {

View File

@@ -5,11 +5,7 @@ import { AdminUrlUtil } from 'helpers/adminUrlUtil.js'
import path from 'path'
import { fileURLToPath } from 'url'
import {
ensureAutoLoginAndCompilationIsDone,
initPageConsoleErrorCatch,
saveDocAndAssert,
} from '../helpers.js'
import { ensureCompilationIsDone, initPageConsoleErrorCatch, saveDocAndAssert } from '../helpers.js'
import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js'
import { TEST_TIMEOUT_LONG } from '../playwright.config.js'
import { slugs } from './shared.js'
@@ -35,7 +31,7 @@ describe('field error states', () => {
page = await context.newPage()
initPageConsoleErrorCatch(page)
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
test('Remove row should remove error states from parent fields', async () => {

View File

@@ -16,7 +16,7 @@ import type {
} from './payload-types.js'
import {
ensureAutoLoginAndCompilationIsDone,
ensureCompilationIsDone,
initPageConsoleErrorCatch,
openCreateDocDrawer,
openDocControls,
@@ -67,7 +67,7 @@ describe('fields - relationship', () => {
page = await context.newPage()
initPageConsoleErrorCatch(page)
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
beforeEach(async () => {
@@ -137,7 +137,7 @@ describe('fields - relationship', () => {
},
})) as any
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
test('should create relationship', async () => {

View File

@@ -9,7 +9,7 @@ import type { PayloadTestSDK } from '../../../helpers/sdk/index.js'
import type { Config } from '../../payload-types.js'
import {
ensureAutoLoginAndCompilationIsDone,
ensureCompilationIsDone,
initPageConsoleErrorCatch,
saveDocAndAssert,
} from '../../../helpers.js'
@@ -48,7 +48,7 @@ describe('Array', () => {
snapshotKey: 'fieldsArrayTest',
uploadsDir: path.resolve(dirname, './collections/Upload/uploads'),
})
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
beforeEach(async () => {
await reInitializeDB({
@@ -63,7 +63,7 @@ describe('Array', () => {
client = new RESTClient(null, { defaultSlug: 'users', serverURL })
await client.login()
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
let url: AdminUrlUtil

View File

@@ -5,7 +5,7 @@ import path from 'path'
import { fileURLToPath } from 'url'
import {
ensureAutoLoginAndCompilationIsDone,
ensureCompilationIsDone,
initPageConsoleErrorCatch,
saveDocAndAssert,
} from '../../../helpers.js'
@@ -43,7 +43,7 @@ describe('Block fields', () => {
snapshotKey: 'blockFieldsTest',
uploadsDir: path.resolve(dirname, './collections/Upload/uploads'),
})
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
beforeEach(async () => {
await reInitializeDB({
@@ -58,7 +58,7 @@ describe('Block fields', () => {
client = new RESTClient(null, { defaultSlug: 'users', serverURL })
await client.login()
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
let url: AdminUrlUtil

View File

@@ -8,7 +8,7 @@ import type { PayloadTestSDK } from '../../../helpers/sdk/index.js'
import type { Config } from '../../payload-types.js'
import {
ensureAutoLoginAndCompilationIsDone,
ensureCompilationIsDone,
initPageConsoleErrorCatch,
saveDocAndAssert,
} from '../../../helpers.js'
@@ -50,7 +50,7 @@ describe('Date', () => {
snapshotKey: 'fieldsDateTest',
uploadsDir: path.resolve(dirname, './collections/Upload/uploads'),
})
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
beforeEach(async () => {
await reInitializeDB({
@@ -65,7 +65,7 @@ describe('Date', () => {
client = new RESTClient(null, { defaultSlug: 'users', serverURL })
await client.login()
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
test('should display formatted date in list view table cell', async () => {

View File

@@ -11,7 +11,7 @@ import type { PayloadTestSDK } from '../../../../../helpers/sdk/index.js'
import type { Config, LexicalField, Upload } from '../../../../payload-types.js'
import {
ensureAutoLoginAndCompilationIsDone,
ensureCompilationIsDone,
initPageConsoleErrorCatch,
saveDocAndAssert,
} from '../../../../../helpers.js'
@@ -74,7 +74,7 @@ describe('lexicalBlocks', () => {
snapshotKey: 'fieldsLexicalBlocksTest',
uploadsDir: path.resolve(dirname, './collections/Upload/uploads'),
})
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
beforeEach(async () => {
/*await throttleTest({

View File

@@ -10,7 +10,7 @@ import type { PayloadTestSDK } from '../../../../../helpers/sdk/index.js'
import type { Config, LexicalField } from '../../../../payload-types.js'
import {
ensureAutoLoginAndCompilationIsDone,
ensureCompilationIsDone,
initPageConsoleErrorCatch,
saveDocAndAssert,
} from '../../../../../helpers.js'
@@ -73,7 +73,7 @@ describe('lexicalMain', () => {
snapshotKey: 'fieldsLexicalMainTest',
uploadsDir: path.resolve(dirname, './collections/Upload/uploads'),
})
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
beforeEach(async () => {
/*await throttleTest({

View File

@@ -9,7 +9,7 @@ import type { PayloadTestSDK } from '../../../helpers/sdk/index.js'
import type { Config } from '../../payload-types.js'
import {
ensureAutoLoginAndCompilationIsDone,
ensureCompilationIsDone,
initPageConsoleErrorCatch,
saveDocAndAssert,
} from '../../../helpers.js'
@@ -51,7 +51,7 @@ describe('Number', () => {
snapshotKey: 'fieldsNumberTest',
uploadsDir: path.resolve(dirname, './collections/Upload/uploads'),
})
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
beforeEach(async () => {
await reInitializeDB({
@@ -66,7 +66,7 @@ describe('Number', () => {
client = new RESTClient(null, { defaultSlug: 'users', serverURL })
await client.login()
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
test('should display field in list view', async () => {

View File

@@ -8,7 +8,7 @@ import type { PayloadTestSDK } from '../../../helpers/sdk/index.js'
import type { Config } from '../../payload-types.js'
import {
ensureAutoLoginAndCompilationIsDone,
ensureCompilationIsDone,
initPageConsoleErrorCatch,
saveDocAndAssert,
} from '../../../helpers.js'
@@ -51,7 +51,7 @@ describe('Point', () => {
snapshotKey: 'fieldsPointTest',
uploadsDir: path.resolve(dirname, './collections/Upload/uploads'),
})
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
beforeEach(async () => {
await reInitializeDB({
@@ -66,7 +66,7 @@ describe('Point', () => {
client = new RESTClient(null, { defaultSlug: 'users', serverURL })
await client.login()
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
filledGroupPoint = await payload.create({
collection: pointFieldsSlug,

View File

@@ -9,7 +9,7 @@ import type { PayloadTestSDK } from '../../../helpers/sdk/index.js'
import type { Config, RelationshipField, TextField } from '../../payload-types.js'
import {
ensureAutoLoginAndCompilationIsDone,
ensureCompilationIsDone,
exactText,
initPageConsoleErrorCatch,
openCreateDocDrawer,
@@ -50,7 +50,7 @@ describe('relationship', () => {
snapshotKey: 'fieldsRelationshipTest',
uploadsDir: path.resolve(dirname, './collections/Upload/uploads'),
})
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
beforeEach(async () => {
await reInitializeDB({
@@ -65,7 +65,7 @@ describe('relationship', () => {
client = new RESTClient(null, { defaultSlug: 'users', serverURL })
await client.login()
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
let url: AdminUrlUtil

View File

@@ -6,7 +6,7 @@ import { wait } from 'payload/shared'
import { fileURLToPath } from 'url'
import {
ensureAutoLoginAndCompilationIsDone,
ensureCompilationIsDone,
initPageConsoleErrorCatch,
saveDocAndAssert,
} from '../../../helpers.js'
@@ -43,7 +43,7 @@ describe('Rich Text', () => {
snapshotKey: 'fieldsRichTextTest',
uploadsDir: path.resolve(dirname, './collections/Upload/uploads'),
})
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
beforeEach(async () => {
await reInitializeDB({
@@ -58,7 +58,7 @@ describe('Rich Text', () => {
client = new RESTClient(null, { defaultSlug: 'users', serverURL })
await client.login()
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
async function navigateToRichTextFields() {

View File

@@ -9,7 +9,7 @@ import type { PayloadTestSDK } from '../../../helpers/sdk/index.js'
import type { Config } from '../../payload-types.js'
import {
ensureAutoLoginAndCompilationIsDone,
ensureCompilationIsDone,
initPageConsoleErrorCatch,
navigateToListCellLink,
saveDocAndAssert,
@@ -53,7 +53,7 @@ describe('Tabs', () => {
snapshotKey: 'fieldsTabsTest',
uploadsDir: path.resolve(dirname, './collections/Upload/uploads'),
})
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
beforeEach(async () => {
await reInitializeDB({
@@ -68,7 +68,7 @@ describe('Tabs', () => {
client = new RESTClient(null, { defaultSlug: 'users', serverURL })
await client.login()
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
test('should fill and retain a new value within a tab while switching tabs', async () => {

View File

@@ -9,7 +9,7 @@ import type { PayloadTestSDK } from '../../../helpers/sdk/index.js'
import type { Config } from '../../payload-types.js'
import {
ensureAutoLoginAndCompilationIsDone,
ensureCompilationIsDone,
exactText,
initPageConsoleErrorCatch,
saveDocAndAssert,
@@ -53,7 +53,7 @@ describe('Text', () => {
snapshotKey: 'fieldsTextTest',
uploadsDir: path.resolve(dirname, './collections/Upload/uploads'),
})
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
beforeEach(async () => {
await reInitializeDB({
@@ -68,7 +68,7 @@ describe('Text', () => {
client = new RESTClient(null, { defaultSlug: 'users', serverURL })
await client.login()
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
test('should display field in list view', async () => {

View File

@@ -9,7 +9,7 @@ import type { PayloadTestSDK } from '../../../helpers/sdk/index.js'
import type { Config } from '../../payload-types.js'
import {
ensureAutoLoginAndCompilationIsDone,
ensureCompilationIsDone,
initPageConsoleErrorCatch,
openDocDrawer,
saveDocAndAssert,
@@ -52,7 +52,7 @@ describe('Upload', () => {
snapshotKey: 'fieldsUploadTest',
uploadsDir: path.resolve(dirname, './collections/Upload/uploads'),
})
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
beforeEach(async () => {
await reInitializeDB({
@@ -67,7 +67,7 @@ describe('Upload', () => {
client = new RESTClient(null, { defaultSlug: 'users', serverURL })
await client.login()
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
async function uploadImage() {

View File

@@ -8,11 +8,7 @@ import { fileURLToPath } from 'url'
import type { PayloadTestSDK } from '../helpers/sdk/index.js'
import type { Config } from './payload-types.js'
import {
ensureAutoLoginAndCompilationIsDone,
initPageConsoleErrorCatch,
saveDocAndAssert,
} from '../helpers.js'
import { ensureCompilationIsDone, initPageConsoleErrorCatch, saveDocAndAssert } from '../helpers.js'
import { AdminUrlUtil } from '../helpers/adminUrlUtil.js'
import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js'
import { reInitializeDB } from '../helpers/reInitializeDB.js'
@@ -53,7 +49,7 @@ describe('fields', () => {
snapshotKey: 'fieldsTest',
uploadsDir: path.resolve(dirname, './collections/Upload/uploads'),
})
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
beforeEach(async () => {
await reInitializeDB({
@@ -68,7 +64,7 @@ describe('fields', () => {
client = new RESTClient(null, { defaultSlug: 'users', serverURL })
await client.login()
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
describe('indexed', () => {

File diff suppressed because it is too large Load Diff

View File

@@ -48,11 +48,11 @@ const networkConditions = {
}
/**
* Load admin panel and make sure autologin has passed before running tests
* Ensure admin panel is loaded before running tests
* @param page
* @param serverURL
*/
export async function ensureAutoLoginAndCompilationIsDone({
export async function ensureCompilationIsDone({
customAdminRoutes,
customRoutes,
page,
@@ -64,9 +64,6 @@ export async function ensureAutoLoginAndCompilationIsDone({
serverURL: string
}): Promise<void> {
const {
admin: {
routes: { createFirstUser: createFirstUserRoute, login: loginRoute },
},
routes: { admin: adminRoute },
} = getAdminRoutes({ customAdminRoutes, customRoutes })
@@ -79,16 +76,6 @@ export async function ensureAutoLoginAndCompilationIsDone({
timeout: POLL_TOPASS_TIMEOUT,
})
await expect(() => expect(page.url()).not.toContain(`${adminRoute}${loginRoute}`)).toPass({
timeout: POLL_TOPASS_TIMEOUT,
})
await expect(() =>
expect(page.url()).not.toContain(`${adminRoute}${createFirstUserRoute}`),
).toPass({
timeout: POLL_TOPASS_TIMEOUT,
})
await expect(page.locator('.dashboard__label').first()).toBeVisible()
}

View File

@@ -85,6 +85,9 @@ export class NextRESTClient {
if (options.auth !== false && this.token) {
headers.set('Authorization', `JWT ${this.token}`)
}
if (options.auth === false) {
headers.set('DisableAutologin', 'true')
}
return headers
}

View File

@@ -9,7 +9,7 @@ const { beforeAll, beforeEach, describe } = test
import path from 'path'
import { fileURLToPath } from 'url'
import { ensureAutoLoginAndCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js'
import { ensureCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js'
import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js'
import { reInitializeDB } from '../helpers/reInitializeDB.js'
import { TEST_TIMEOUT_LONG } from '../playwright.config.js'
@@ -39,7 +39,7 @@ describe('i18n', () => {
serverURL,
snapshotKey: 'i18nTests',
})
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
beforeEach(async () => {
await reInitializeDB({
@@ -47,7 +47,7 @@ describe('i18n', () => {
snapshotKey: 'i18nTests',
})
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
test('ensure i18n labels and useTranslation hooks display correct translation', async () => {

View File

@@ -5,7 +5,7 @@ import path from 'path'
import { fileURLToPath } from 'url'
import {
ensureAutoLoginAndCompilationIsDone,
ensureCompilationIsDone,
exactText,
initPageConsoleErrorCatch,
saveDocAndAssert,
@@ -57,7 +57,7 @@ describe('Live Preview', () => {
initPageConsoleErrorCatch(page)
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
test('collection — has tab', async () => {

View File

@@ -10,7 +10,7 @@ import type { Config, LocalizedPost } from './payload-types.js'
import {
changeLocale,
ensureAutoLoginAndCompilationIsDone,
ensureCompilationIsDone,
initPageConsoleErrorCatch,
openDocControls,
saveDocAndAssert,
@@ -63,7 +63,7 @@ describe('Localization', () => {
initPageConsoleErrorCatch(page)
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
describe('localized text', () => {

View File

@@ -11,6 +11,16 @@
"test:int": "pnpm -C \"../\" run test:int",
"typecheck": "pnpm turbo build --filter test && tsc --project tsconfig.typecheck.json"
},
"lint-staged": {
"**/package.json": "sort-package-json",
"*.{md,mdx,yml,json}": "prettier --write",
"*.{js,jsx,ts,tsx}": [
"prettier --write",
"eslint --cache --fix"
],
"templates/website/**/*": "sh -c \"cd templates/website; pnpm install --ignore-workspace --frozen-lockfile; pnpm run lint --fix\"",
"tsconfig.json": "node scripts/reset-tsconfig.js"
},
"devDependencies": {
"@aws-sdk/client-s3": "^3.525.0",
"@lexical/headless": "0.16.1",

View File

@@ -4,7 +4,7 @@ import { expect, test } from '@playwright/test'
import * as path from 'path'
import { fileURLToPath } from 'url'
import { ensureAutoLoginAndCompilationIsDone, saveDocAndAssert } from '../helpers.js'
import { ensureCompilationIsDone, saveDocAndAssert } from '../helpers.js'
import { AdminUrlUtil } from '../helpers/adminUrlUtil.js'
import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js'
import { TEST_TIMEOUT_LONG } from '../playwright.config.js'
@@ -24,7 +24,7 @@ test.describe('Admin Panel', () => {
const context = await browser.newContext()
page = await context.newPage()
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
test('should create file upload', async () => {

View File

@@ -7,7 +7,7 @@ import { fileURLToPath } from 'url'
import type { PayloadTestSDK } from '../helpers/sdk/index.js'
import type { Config } from './payload-types.js'
import { ensureAutoLoginAndCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js'
import { ensureCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js'
import { AdminUrlUtil } from '../helpers/adminUrlUtil.js'
import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js'
import { POLL_TOPASS_TIMEOUT, TEST_TIMEOUT_LONG } from '../playwright.config.js'
@@ -35,7 +35,7 @@ test.describe('Form Builder', () => {
page = await context.newPage()
initPageConsoleErrorCatch(page)
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
test.describe('Forms collection', () => {

View File

@@ -6,7 +6,7 @@ import { fileURLToPath } from 'url'
import type { Config, Page as PayloadPage } from './payload-types.js'
import { ensureAutoLoginAndCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js'
import { ensureCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js'
import { AdminUrlUtil } from '../helpers/adminUrlUtil.js'
import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js'
import { TEST_TIMEOUT_LONG } from '../playwright.config.js'
@@ -69,7 +69,7 @@ describe('Nested Docs Plugin', () => {
})
draftChildId = draftChildPage.id
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
describe('Core functionality', () => {

View File

@@ -8,7 +8,7 @@ import { fileURLToPath } from 'url'
import type { Config, Page as PayloadPage } from './payload-types.js'
import { ensureAutoLoginAndCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js'
import { ensureCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js'
import { AdminUrlUtil } from '../helpers/adminUrlUtil.js'
import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js'
import { TEST_TIMEOUT_LONG } from '../playwright.config.js'
@@ -57,7 +57,7 @@ describe('SEO Plugin', () => {
})) as unknown as PayloadPage
id = createdPage.id
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
describe('Core functionality', () => {

View File

@@ -10,7 +10,7 @@ import type { PayloadTestSDK } from '../helpers/sdk/index.js'
import type { Config, Media } from './payload-types.js'
import {
ensureAutoLoginAndCompilationIsDone,
ensureCompilationIsDone,
initPageConsoleErrorCatch,
openDocDrawer,
saveDocAndAssert,
@@ -89,7 +89,7 @@ describe('uploads', () => {
audioDoc = findAudio.docs[0] as unknown as Media
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
})
test('should see upload filename in relation list', async () => {

View File

@@ -35,7 +35,7 @@ import type { Config } from './payload-types.js'
import { globalSlug } from '../admin/slugs.js'
import {
changeLocale,
ensureAutoLoginAndCompilationIsDone,
ensureCompilationIsDone,
exactText,
findTableCell,
initPageConsoleErrorCatch,
@@ -113,7 +113,7 @@ describe('versions', () => {
snapshotKey: 'versionsTest',
})
await ensureAutoLoginAndCompilationIsDone({ page, serverURL })
await ensureCompilationIsDone({ page, serverURL })
//await clearAndSeedEverything(payload)
})