- 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.
205 lines
5.8 KiB
TypeScript
205 lines
5.8 KiB
TypeScript
import type { Page } from '@playwright/test'
|
|
import type { SanitizedConfig } from 'payload'
|
|
|
|
import { expect, test } from '@playwright/test'
|
|
import { devUser } from 'credentials.js'
|
|
import path from 'path'
|
|
import { wait } from 'payload/shared'
|
|
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 {
|
|
ensureCompilationIsDone,
|
|
getAdminRoutes,
|
|
initPageConsoleErrorCatch,
|
|
saveDocAndAssert,
|
|
} 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'
|
|
import { apiKeysSlug, slug } from './shared.js'
|
|
|
|
const filename = fileURLToPath(import.meta.url)
|
|
const dirname = path.dirname(filename)
|
|
|
|
let payload: PayloadTestSDK<Config>
|
|
|
|
const { beforeAll, describe } = test
|
|
|
|
const headers = {
|
|
'Content-Type': 'application/json',
|
|
}
|
|
|
|
const createFirstUser = async ({
|
|
customAdminRoutes,
|
|
customRoutes,
|
|
page,
|
|
serverURL,
|
|
}: {
|
|
customAdminRoutes?: SanitizedConfig['admin']['routes']
|
|
customRoutes?: SanitizedConfig['routes']
|
|
page: Page
|
|
serverURL: string
|
|
}) => {
|
|
const {
|
|
admin: {
|
|
routes: { createFirstUser: createFirstUserRoute },
|
|
},
|
|
routes: { admin: adminRoute },
|
|
} = getAdminRoutes({
|
|
customAdminRoutes,
|
|
customRoutes,
|
|
})
|
|
|
|
await page.goto(serverURL + `${adminRoute}${createFirstUserRoute}`)
|
|
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 }, testInfo) => {
|
|
testInfo.setTimeout(TEST_TIMEOUT_LONG)
|
|
;({ payload, serverURL } = await initPayloadE2ENoConfig<Config>({ dirname }))
|
|
apiURL = `${serverURL}/api`
|
|
url = new AdminUrlUtil(serverURL, slug)
|
|
|
|
const context = await browser.newContext()
|
|
page = await context.newPage()
|
|
initPageConsoleErrorCatch(page)
|
|
|
|
await createFirstUser({ page, serverURL })
|
|
|
|
await payload.create({
|
|
collection: 'api-keys',
|
|
data: {
|
|
apiKey: uuid(),
|
|
enableAPIKey: true,
|
|
},
|
|
})
|
|
|
|
await payload.create({
|
|
collection: 'api-keys',
|
|
data: {
|
|
apiKey: uuid(),
|
|
enableAPIKey: true,
|
|
},
|
|
})
|
|
await ensureCompilationIsDone({ page, serverURL })
|
|
})
|
|
|
|
describe('authenticated users', () => {
|
|
beforeAll(({ browser }) => {
|
|
url = new AdminUrlUtil(serverURL, slug)
|
|
})
|
|
|
|
test('should allow change password', async () => {
|
|
await page.goto(url.account)
|
|
const emailBeforeSave = await page.locator('#field-email').inputValue()
|
|
await page.locator('#change-password').click()
|
|
await page.locator('#field-password').fill('password')
|
|
await page.locator('#field-confirm-password').fill('password')
|
|
await saveDocAndAssert(page)
|
|
await expect(page.locator('#field-email')).toHaveValue(emailBeforeSave)
|
|
})
|
|
|
|
test('should have up-to-date user in `useAuth` hook', async () => {
|
|
await page.goto(url.account)
|
|
await page.waitForURL(url.account)
|
|
await expect(page.locator('#users-api-result')).toHaveText('Hello, world!')
|
|
await expect(page.locator('#use-auth-result')).toHaveText('Hello, world!')
|
|
const field = page.locator('#field-custom')
|
|
await field.fill('Goodbye, world!')
|
|
await saveDocAndAssert(page)
|
|
await expect(page.locator('#users-api-result')).toHaveText('Goodbye, world!')
|
|
await expect(page.locator('#use-auth-result')).toHaveText('Goodbye, world!')
|
|
})
|
|
})
|
|
|
|
describe('api-keys', () => {
|
|
let user
|
|
|
|
beforeAll(async () => {
|
|
url = new AdminUrlUtil(serverURL, apiKeysSlug)
|
|
|
|
user = await payload.create({
|
|
collection: apiKeysSlug,
|
|
data: {
|
|
apiKey: uuid(),
|
|
enableAPIKey: true,
|
|
},
|
|
})
|
|
})
|
|
|
|
test('should enable api key', async () => {
|
|
await page.goto(url.create)
|
|
|
|
// click enable api key checkbox
|
|
await page.locator('#field-enableAPIKey').click()
|
|
|
|
// assert that the value is set
|
|
const apiKeyLocator = page.locator('#apiKey')
|
|
await expect
|
|
.poll(async () => await apiKeyLocator.inputValue(), { timeout: POLL_TOPASS_TIMEOUT })
|
|
.toBeDefined()
|
|
|
|
const apiKey = await apiKeyLocator.inputValue()
|
|
|
|
await saveDocAndAssert(page)
|
|
|
|
await expect(async () => {
|
|
const apiKeyAfterSave = await apiKeyLocator.inputValue()
|
|
expect(apiKey).toStrictEqual(apiKeyAfterSave)
|
|
}).toPass({
|
|
timeout: POLL_TOPASS_TIMEOUT,
|
|
})
|
|
})
|
|
|
|
test('should disable api key', async () => {
|
|
await page.goto(url.edit(user.id))
|
|
|
|
// click enable api key checkbox
|
|
await page.locator('#field-enableAPIKey').click()
|
|
|
|
// assert that the apiKey field is hidden
|
|
await expect(page.locator('#apiKey')).toBeHidden()
|
|
|
|
await saveDocAndAssert(page)
|
|
|
|
// use the api key in a fetch to assert that it is disabled
|
|
await expect(async () => {
|
|
const response = await fetch(`${apiURL}/${apiKeysSlug}/me`, {
|
|
headers: {
|
|
...headers,
|
|
Authorization: `${apiKeysSlug} API-Key ${user.apiKey}`,
|
|
},
|
|
}).then((res) => res.json())
|
|
|
|
expect(response.user).toBeNull()
|
|
}).toPass({
|
|
timeout: POLL_TOPASS_TIMEOUT,
|
|
})
|
|
})
|
|
})
|
|
})
|