- 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.
171 lines
6.1 KiB
TypeScript
171 lines
6.1 KiB
TypeScript
import type { Page } from '@playwright/test'
|
|
|
|
import { expect, test } from '@playwright/test'
|
|
import path from 'path'
|
|
import { getFileByPath } from 'payload'
|
|
import { wait } from 'payload/shared'
|
|
import { fileURLToPath } from 'url'
|
|
|
|
import type { Config, Page as PayloadPage } from './payload-types.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'
|
|
import { mediaSlug } from './shared.js'
|
|
|
|
const filename = fileURLToPath(import.meta.url)
|
|
const dirname = path.dirname(filename)
|
|
|
|
const { beforeAll, describe } = test
|
|
|
|
let url: AdminUrlUtil
|
|
let page: Page
|
|
let id: string
|
|
|
|
describe('SEO Plugin', () => {
|
|
beforeAll(async ({ browser }, testInfo) => {
|
|
testInfo.setTimeout(TEST_TIMEOUT_LONG)
|
|
const { serverURL, payload } = await initPayloadE2ENoConfig<Config>({ dirname })
|
|
url = new AdminUrlUtil(serverURL, 'pages')
|
|
|
|
const context = await browser.newContext()
|
|
page = await context.newPage()
|
|
initPageConsoleErrorCatch(page)
|
|
|
|
const filePath = path.resolve(dirname, './image-1.jpg')
|
|
const file = await getFileByPath(filePath)
|
|
|
|
const mediaDoc = await payload.create({
|
|
collection: mediaSlug,
|
|
data: {},
|
|
file,
|
|
})
|
|
|
|
const createdPage = (await payload.create({
|
|
collection: 'pages',
|
|
data: {
|
|
slug: 'test-page',
|
|
meta: {
|
|
description: 'This is a test meta description',
|
|
image: mediaDoc.id,
|
|
ogTitle: 'This is a custom og:title field',
|
|
title: 'This is a test meta title',
|
|
},
|
|
title: 'Test Page',
|
|
},
|
|
})) as unknown as PayloadPage
|
|
id = createdPage.id
|
|
|
|
await ensureCompilationIsDone({ page, serverURL })
|
|
})
|
|
|
|
describe('Core functionality', () => {
|
|
test('Config tab should be merged in correctly', async () => {
|
|
await page.goto(url.edit(id))
|
|
const contentTabsClass = '.tabs-field__tabs .tabs-field__tab-button'
|
|
|
|
const firstTab = page.locator(contentTabsClass).nth(0)
|
|
await expect(firstTab).toContainText('General')
|
|
})
|
|
|
|
test('Should auto-generate meta title when button is clicked in tabs', async () => {
|
|
const contentTabsClass = '.tabs-field__tabs .tabs-field__tab-button'
|
|
const autoGenerateButtonClass = '.group-field__wrap .render-fields div:nth-of-type(1) button'
|
|
const metaTitleClass = '#field-meta__title'
|
|
|
|
const secondTab = page.locator(contentTabsClass).nth(1)
|
|
await secondTab.click()
|
|
|
|
const metaTitle = page.locator(metaTitleClass)
|
|
|
|
await expect(metaTitle).toHaveValue('This is a test meta title')
|
|
|
|
const autoGenButton = page.locator(autoGenerateButtonClass).nth(0)
|
|
await expect(autoGenButton).toContainText('Auto-generate')
|
|
await autoGenButton.click()
|
|
|
|
await expect(metaTitle).toHaveValue('Website.com — Test Page')
|
|
})
|
|
|
|
// todo: Re-enable this test once required attributes are fixed
|
|
/* test('Title should be required as per custom override', async () => {
|
|
const metaTitleClass = '#field-title'
|
|
|
|
const metaTitle = page.locator(metaTitleClass).nth(0)
|
|
|
|
await expect(metaTitle).toHaveAttribute('required', '')
|
|
}) */
|
|
|
|
test('Indicator should be orangered and characters counted', async () => {
|
|
const indicatorClass =
|
|
'#field-meta > div > div.render-fields.render-fields--margins-small > div:nth-child(2) > div:nth-child(3) > div > div:nth-child(3) > div'
|
|
const indicatorLabelClass =
|
|
'#field-meta > div > div.render-fields.render-fields--margins-small > div:nth-child(2) > div:nth-child(3) > div > div:nth-child(2)'
|
|
|
|
const indicator = page.locator(indicatorClass)
|
|
const indicatorLabel = page.locator(indicatorLabelClass)
|
|
|
|
await expect(indicatorLabel).toContainText('23/50-60 chars, 27 to go')
|
|
await expect(indicator).toHaveCSS('background-color', 'rgb(255, 69, 0)')
|
|
})
|
|
|
|
test('Should generate a search result preview based on content', async () => {
|
|
await page.goto(url.edit(id))
|
|
const contentTabsClass = '.tabs-field__tabs .tabs-field__tab-button'
|
|
const autoGenerateButtonClass = '.group-field__wrap .render-fields div:nth-of-type(1) button'
|
|
const metaDescriptionClass = '#field-meta__description'
|
|
const previewClass =
|
|
'#field-meta > div > div.render-fields.render-fields--margins-small > div:nth-child(6)'
|
|
|
|
const secondTab = page.locator(contentTabsClass).nth(1)
|
|
await secondTab.click()
|
|
|
|
const metaDescription = page.locator(metaDescriptionClass)
|
|
await metaDescription.fill('My new amazing SEO description')
|
|
|
|
const preview = page.locator(previewClass)
|
|
await expect(preview).toContainText('https://yoursite.com/en/')
|
|
await expect(preview).toContainText('This is a test meta title')
|
|
await expect(preview).toContainText('My new amazing SEO description')
|
|
})
|
|
})
|
|
|
|
describe('i18n', () => {
|
|
test('support for another language', async () => {
|
|
await page.goto(url.edit(id))
|
|
const contentTabsClass = '.tabs-field__tabs .tabs-field__tab-button'
|
|
const autoGenerateButtonClass = '.group-field__wrap .render-fields div:nth-of-type(1) button'
|
|
|
|
const secondTab = page.locator(contentTabsClass).nth(1)
|
|
await secondTab.click()
|
|
|
|
const autoGenButton = page.locator(autoGenerateButtonClass).nth(0)
|
|
|
|
await expect(autoGenButton).toContainText('Auto-generate')
|
|
|
|
// Go to account page
|
|
await page.goto(url.account)
|
|
|
|
const languageField = page.locator('.payload-settings__language .react-select')
|
|
const options = page.locator('.rs__option')
|
|
|
|
// Change language to Spanish
|
|
await languageField.click()
|
|
await wait(200)
|
|
await options.locator('text=Español').click()
|
|
await expect(languageField).toContainText('Español')
|
|
await wait(600)
|
|
|
|
// Navigate back to the page
|
|
await page.goto(url.edit(id))
|
|
await wait(600)
|
|
|
|
await secondTab.click()
|
|
await wait(600)
|
|
|
|
await expect(autoGenButton).toContainText('Auto-génerar')
|
|
})
|
|
})
|
|
})
|