mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-03-25 02:31:59 -05:00
Added tests for AdminX navigation settings (#17109)
- Updated test request records to be distinct per API call - Updated design tests to check preview data - Added tests for navigation settings refs https://github.com/TryGhost/Team/issues/3349
This commit is contained in:
parent
5a1dcbc9a5
commit
2d6e988017
18 changed files with 275 additions and 85 deletions
|
@ -44,6 +44,7 @@ const NavigationModal = NiceModal.create(() => {
|
|||
scrolling={true}
|
||||
size='lg'
|
||||
stickyFooter={true}
|
||||
testId='navigation-modal'
|
||||
title='Navigation'
|
||||
onOk={async () => {
|
||||
if (navigation.validate() && secondaryNavigation.validate()) {
|
||||
|
|
|
@ -108,10 +108,11 @@ const NavigationEditForm: React.FC<{
|
|||
</DndContext>
|
||||
|
||||
<NavigationItemEditor
|
||||
action={<Button color='green' icon="add" iconColorClass='text-white' size='sm' onClick={navigation.addItem} />}
|
||||
action={<Button color='green' data-testid="add-button" icon="add" iconColorClass='text-white' size='sm' onClick={navigation.addItem} />}
|
||||
baseUrl={baseUrl}
|
||||
clearError={key => navigation.clearError(navigation.newItem.id, key)}
|
||||
containerClasses="flex items-start gap-3 p-2"
|
||||
data-testid="new-navigation-item"
|
||||
dragHandleClasses="ml-2 invisible"
|
||||
item={navigation.newItem}
|
||||
labelPlaceholder="New item label"
|
||||
|
|
|
@ -21,7 +21,7 @@ export type NavigationItemEditorProps = React.HTMLAttributes<HTMLDivElement> & {
|
|||
|
||||
const NavigationItemEditor = forwardRef<HTMLDivElement, NavigationItemEditorProps>(function NavigationItemEditor({baseUrl, item, updateItem, onDelete, clearError, dragHandleProps, labelPlaceholder, unstyled, containerClasses, dragHandleClasses, textFieldClasses, action, ...props}, ref) {
|
||||
return (
|
||||
<div ref={ref} className={containerClasses} {...props}>
|
||||
<div ref={ref} className={containerClasses} data-testid='navigation-item-editor' {...props}>
|
||||
<button className={dragHandleClasses} type='button' {...dragHandleProps}>
|
||||
<Icon colorClass='text-grey-500' name='hamburger' size='sm' />
|
||||
</button>
|
||||
|
@ -33,8 +33,10 @@ const NavigationItemEditor = forwardRef<HTMLDivElement, NavigationItemEditorProp
|
|||
hint={item.errors.label}
|
||||
hintClassName="px-2"
|
||||
placeholder={labelPlaceholder}
|
||||
title='Label'
|
||||
unstyled={unstyled}
|
||||
value={item.label}
|
||||
hideTitle
|
||||
onChange={e => updateItem?.({label: e.target.value})}
|
||||
onKeyDown={() => clearError?.('label')}
|
||||
/>
|
||||
|
@ -47,8 +49,10 @@ const NavigationItemEditor = forwardRef<HTMLDivElement, NavigationItemEditorProp
|
|||
error={!!item.errors.url}
|
||||
hint={item.errors.url}
|
||||
hintClassName="px-2"
|
||||
title='URL'
|
||||
unstyled={unstyled}
|
||||
value={item.url}
|
||||
hideTitle
|
||||
onChange={value => updateItem?.({url: value})}
|
||||
onKeyDown={() => clearError?.('url')}
|
||||
/>
|
||||
|
|
|
@ -3,7 +3,7 @@ import {mockApi, updatedSettingsResponse} from '../../utils/e2e';
|
|||
|
||||
test.describe('Default recipient settings', async () => {
|
||||
test('Supports editing default recipients', async ({page}) => {
|
||||
const lastApiRequest = await mockApi({page, responses: {
|
||||
const lastApiRequests = await mockApi({page, responses: {
|
||||
settings: {
|
||||
edit: updatedSettingsResponse([
|
||||
{key: 'editor_default_email_recipients', value: 'filter'},
|
||||
|
@ -22,7 +22,7 @@ test.describe('Default recipient settings', async () => {
|
|||
await section.getByLabel('Default newsletter recipients').selectOption('All members');
|
||||
await section.getByRole('button', {name: 'Save'}).click();
|
||||
|
||||
expect(lastApiRequest.body).toEqual({
|
||||
expect(lastApiRequests.settings.edit.body).toEqual({
|
||||
settings: [
|
||||
{key: 'editor_default_email_recipients', value: 'filter'},
|
||||
{key: 'editor_default_email_recipients_filter', value: 'status:free,status:-free'}
|
||||
|
@ -33,7 +33,7 @@ test.describe('Default recipient settings', async () => {
|
|||
await section.getByLabel('Default newsletter recipients').selectOption('Usually nobody');
|
||||
await section.getByRole('button', {name: 'Save'}).click();
|
||||
|
||||
expect(lastApiRequest.body).toEqual({
|
||||
expect(lastApiRequests.settings.edit.body).toEqual({
|
||||
settings: [
|
||||
{key: 'editor_default_email_recipients', value: 'filter'},
|
||||
{key: 'editor_default_email_recipients_filter', value: null}
|
||||
|
@ -48,7 +48,7 @@ test.describe('Default recipient settings', async () => {
|
|||
|
||||
await expect(section.getByText('Paid-members only')).toHaveCount(1);
|
||||
|
||||
expect(lastApiRequest.body).toEqual({
|
||||
expect(lastApiRequests.settings.edit.body).toEqual({
|
||||
settings: [
|
||||
{key: 'editor_default_email_recipients', value: 'filter'},
|
||||
{key: 'editor_default_email_recipients_filter', value: 'status:-free'}
|
||||
|
|
|
@ -3,7 +3,7 @@ import {mockApi, updatedSettingsResponse} from '../../utils/e2e';
|
|||
|
||||
test.describe('Mailgun settings', async () => {
|
||||
test('Supports setting up mailgun', async ({page}) => {
|
||||
const lastApiRequest = await mockApi({page, responses: {
|
||||
const lastApiRequests = await mockApi({page, responses: {
|
||||
settings: {
|
||||
edit: updatedSettingsResponse([
|
||||
{key: 'mailgun_domain', value: 'test.com'},
|
||||
|
@ -29,7 +29,7 @@ test.describe('Mailgun settings', async () => {
|
|||
|
||||
await expect(section.getByText('Mailgun is set up')).toHaveCount(1);
|
||||
|
||||
expect(lastApiRequest.body).toEqual({
|
||||
expect(lastApiRequests.settings.edit.body).toEqual({
|
||||
settings: [
|
||||
{key: 'mailgun_domain', value: 'test.com'},
|
||||
{key: 'mailgun_api_key', value: 'test'}
|
||||
|
|
|
@ -3,7 +3,7 @@ import {mockApi} from '../../utils/e2e';
|
|||
|
||||
test.describe('Facebook settings', async () => {
|
||||
test('Supports editing the facebook card', async ({page}) => {
|
||||
const lastApiRequest = await mockApi({page, responses: {
|
||||
const lastApiRequests = await mockApi({page, responses: {
|
||||
images: {
|
||||
upload: {images: [{url: 'http://example.com/image.png', ref: null}]}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ test.describe('Facebook settings', async () => {
|
|||
|
||||
await expect(section.getByLabel('Facebook title')).toHaveCount(0);
|
||||
|
||||
expect(lastApiRequest.body).toEqual({
|
||||
expect(lastApiRequests.settings.edit.body).toEqual({
|
||||
settings: [
|
||||
{key: 'og_image', value: 'http://example.com/image.png'},
|
||||
{key: 'og_title', value: 'Facetitle'},
|
||||
|
|
|
@ -3,7 +3,7 @@ import {mockApi, updatedSettingsResponse} from '../../utils/e2e';
|
|||
|
||||
test.describe('Site password settings', async () => {
|
||||
test('Supports locking and unlocking the site', async ({page}) => {
|
||||
let lastApiRequest = await mockApi({page, responses: {
|
||||
let lastApiRequests = await mockApi({page, responses: {
|
||||
settings: {
|
||||
edit: updatedSettingsResponse([
|
||||
{key: 'is_private', value: true},
|
||||
|
@ -31,7 +31,7 @@ test.describe('Site password settings', async () => {
|
|||
|
||||
await expect(section.getByText('Your site is password protected')).toHaveCount(1);
|
||||
|
||||
expect(lastApiRequest.body).toEqual({
|
||||
expect(lastApiRequests.settings.edit.body).toEqual({
|
||||
settings: [
|
||||
{key: 'is_private', value: true},
|
||||
{key: 'password', value: 'password'}
|
||||
|
@ -40,7 +40,7 @@ test.describe('Site password settings', async () => {
|
|||
|
||||
// Remove the site password
|
||||
|
||||
lastApiRequest = await mockApi({page, responses: {
|
||||
lastApiRequests = await mockApi({page, responses: {
|
||||
settings: {
|
||||
edit: updatedSettingsResponse([
|
||||
{key: 'is_private', value: false}
|
||||
|
@ -56,7 +56,7 @@ test.describe('Site password settings', async () => {
|
|||
|
||||
await expect(section.getByText('Your site is not password protected')).toHaveCount(1);
|
||||
|
||||
expect(lastApiRequest.body).toEqual({
|
||||
expect(lastApiRequests.settings.edit.body).toEqual({
|
||||
settings: [
|
||||
{key: 'is_private', value: false}
|
||||
]
|
||||
|
|
|
@ -3,7 +3,7 @@ import {mockApi, updatedSettingsResponse} from '../../utils/e2e';
|
|||
|
||||
test.describe('Metadata settings', async () => {
|
||||
test('Supports editing metadata', async ({page}) => {
|
||||
const lastApiRequest = await mockApi({page, responses: {
|
||||
const lastApiRequests = await mockApi({page, responses: {
|
||||
settings: {
|
||||
edit: updatedSettingsResponse([
|
||||
{key: 'meta_title', value: 'Alternative title'},
|
||||
|
@ -31,7 +31,7 @@ test.describe('Metadata settings', async () => {
|
|||
await expect(section.getByText('Alternative title')).toHaveCount(1);
|
||||
await expect(section.getByText('Alternative description')).toHaveCount(1);
|
||||
|
||||
expect(lastApiRequest.body).toEqual({
|
||||
expect(lastApiRequests.settings.edit.body).toEqual({
|
||||
settings: [
|
||||
{key: 'meta_title', value: 'Alternative title'},
|
||||
{key: 'meta_description', value: 'Alternative description'}
|
||||
|
|
|
@ -3,7 +3,7 @@ import {mockApi, updatedSettingsResponse} from '../../utils/e2e';
|
|||
|
||||
test.describe('Publication language settings', async () => {
|
||||
test('Supports editing the locale', async ({page}) => {
|
||||
const lastApiRequest = await mockApi({page, responses: {
|
||||
const lastApiRequests = await mockApi({page, responses: {
|
||||
settings: {
|
||||
edit: updatedSettingsResponse([
|
||||
{key: 'locale', value: 'jp'}
|
||||
|
@ -27,7 +27,7 @@ test.describe('Publication language settings', async () => {
|
|||
|
||||
await expect(section.getByText('jp')).toHaveCount(1);
|
||||
|
||||
expect(lastApiRequest.body).toEqual({
|
||||
expect(lastApiRequests.settings.edit.body).toEqual({
|
||||
settings: [
|
||||
{key: 'locale', value: 'jp'}
|
||||
]
|
||||
|
|
|
@ -3,7 +3,7 @@ import {mockApi, updatedSettingsResponse} from '../../utils/e2e';
|
|||
|
||||
test.describe('Social account settings', async () => {
|
||||
test('Supports editing social URLs', async ({page}) => {
|
||||
const lastApiRequest = await mockApi({page, responses: {
|
||||
const lastApiRequests = await mockApi({page, responses: {
|
||||
settings: {
|
||||
edit: updatedSettingsResponse([
|
||||
{key: 'facebook', value: 'fb'},
|
||||
|
@ -31,7 +31,7 @@ test.describe('Social account settings', async () => {
|
|||
await expect(section.getByText('https://www.facebook.com/fb')).toHaveCount(1);
|
||||
await expect(section.getByText('https://twitter.com/tw')).toHaveCount(1);
|
||||
|
||||
expect(lastApiRequest.body).toEqual({
|
||||
expect(lastApiRequests.settings.edit.body).toEqual({
|
||||
settings: [
|
||||
{key: 'facebook', value: 'fb'},
|
||||
{key: 'twitter', value: '@tw'}
|
||||
|
|
|
@ -3,7 +3,7 @@ import {mockApi, updatedSettingsResponse} from '../../utils/e2e';
|
|||
|
||||
test.describe('Time zone settings', async () => {
|
||||
test('Supports editing the time zone', async ({page}) => {
|
||||
const lastApiRequest = await mockApi({page, responses: {
|
||||
const lastApiRequests = await mockApi({page, responses: {
|
||||
settings: {
|
||||
edit: updatedSettingsResponse([
|
||||
{key: 'timezone', value: 'Asia/Tokyo'}
|
||||
|
@ -27,7 +27,7 @@ test.describe('Time zone settings', async () => {
|
|||
|
||||
await expect(section.getByText('Asia/Tokyo')).toHaveCount(1);
|
||||
|
||||
expect(lastApiRequest.body).toEqual({
|
||||
expect(lastApiRequests.settings.edit.body).toEqual({
|
||||
settings: [
|
||||
{key: 'timezone', value: 'Asia/Tokyo'}
|
||||
]
|
||||
|
|
|
@ -3,7 +3,7 @@ import {mockApi, updatedSettingsResponse} from '../../utils/e2e';
|
|||
|
||||
test.describe('Title and description settings', async () => {
|
||||
test('Supports editing the title and description', async ({page}) => {
|
||||
const lastApiRequest = await mockApi({page, responses: {
|
||||
const lastApiRequests = await mockApi({page, responses: {
|
||||
settings: {
|
||||
edit: updatedSettingsResponse([
|
||||
{key: 'title', value: 'New Site Title'},
|
||||
|
@ -31,7 +31,7 @@ test.describe('Title and description settings', async () => {
|
|||
await expect(section.getByText('New Site Title')).toHaveCount(1);
|
||||
await expect(section.getByText('New Site Description')).toHaveCount(1);
|
||||
|
||||
expect(lastApiRequest.body).toEqual({
|
||||
expect(lastApiRequests.settings.edit.body).toEqual({
|
||||
settings: [
|
||||
{key: 'title', value: 'New Site Title'},
|
||||
{key: 'description', value: 'New Site Description'}
|
||||
|
|
|
@ -3,7 +3,7 @@ import {mockApi} from '../../utils/e2e';
|
|||
|
||||
test.describe('Twitter settings', async () => {
|
||||
test('Supports editing the twitter card', async ({page}) => {
|
||||
const lastApiRequest = await mockApi({page, responses: {
|
||||
const lastApiRequests = await mockApi({page, responses: {
|
||||
images: {
|
||||
upload: {images: [{url: 'http://example.com/image.png', ref: null}]}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ test.describe('Twitter settings', async () => {
|
|||
|
||||
await expect(section.getByLabel('Twitter title')).toHaveCount(0);
|
||||
|
||||
expect(lastApiRequest.body).toEqual({
|
||||
expect(lastApiRequests.settings.edit.body).toEqual({
|
||||
settings: [
|
||||
{key: 'twitter_image', value: 'http://example.com/image.png'},
|
||||
{key: 'twitter_title', value: 'Twititle'},
|
||||
|
|
|
@ -3,7 +3,7 @@ import {mockApi, updatedSettingsResponse} from '../../utils/e2e';
|
|||
|
||||
test.describe('Access settings', async () => {
|
||||
test('Supports editing access', async ({page}) => {
|
||||
const lastApiRequest = await mockApi({page, responses: {
|
||||
const lastApiRequests = await mockApi({page, responses: {
|
||||
settings: {
|
||||
edit: updatedSettingsResponse([
|
||||
{key: 'default_content_visibility', value: 'members'},
|
||||
|
@ -35,7 +35,7 @@ test.describe('Access settings', async () => {
|
|||
await expect(section.getByText('Members only')).toHaveCount(1);
|
||||
await expect(section.getByText('All members')).toHaveCount(1);
|
||||
|
||||
expect(lastApiRequest.body).toEqual({
|
||||
expect(lastApiRequests.settings.edit.body).toEqual({
|
||||
settings: [
|
||||
{key: 'default_content_visibility', value: 'members'},
|
||||
{key: 'members_signup_access', value: 'invite'},
|
||||
|
|
|
@ -3,7 +3,7 @@ import {mockApi, updatedSettingsResponse} from '../../utils/e2e';
|
|||
|
||||
test.describe('Analytics settings', async () => {
|
||||
test('Supports toggling analytics settings', async ({page}) => {
|
||||
const lastApiRequest = await mockApi({page, responses: {
|
||||
const lastApiRequests = await mockApi({page, responses: {
|
||||
settings: {
|
||||
edit: updatedSettingsResponse([
|
||||
{key: 'members_track_sources', value: false},
|
||||
|
@ -30,7 +30,7 @@ test.describe('Analytics settings', async () => {
|
|||
|
||||
await section.getByRole('button', {name: 'Save'}).click();
|
||||
|
||||
expect(lastApiRequest.body).toEqual({
|
||||
expect(lastApiRequests.settings.edit.body).toEqual({
|
||||
settings: [
|
||||
{key: 'members_track_sources', value: false},
|
||||
{key: 'email_track_opens', value: false},
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import {expect, test} from '@playwright/test';
|
||||
import {mockApi} from '../../utils/e2e';
|
||||
|
||||
test.describe('Theme settings', async () => {
|
||||
test.describe('Design settings', async () => {
|
||||
test('Editing brand settings', async ({page}) => {
|
||||
const lastApiRequest = await mockApi({page, responses: {
|
||||
const lastApiRequests = await mockApi({page, responses: {
|
||||
previewHtml: {
|
||||
homepage: '<html><head><style></style></head><body><div>homepage preview</div></body></html>'
|
||||
}
|
||||
|
@ -24,7 +24,9 @@ test.describe('Theme settings', async () => {
|
|||
|
||||
await expect(modal).not.toBeVisible();
|
||||
|
||||
expect(lastApiRequest.body).toEqual({
|
||||
expect(lastApiRequests.previewHtml.homepage.headers?.['x-ghost-preview']).toMatch(/&d=new\+description&/);
|
||||
|
||||
expect(lastApiRequests.settings.edit.body).toEqual({
|
||||
settings: [
|
||||
{key: 'description', value: 'new description'}
|
||||
]
|
||||
|
@ -32,7 +34,24 @@ test.describe('Theme settings', async () => {
|
|||
});
|
||||
|
||||
test('Editing custom theme settings', async ({page}) => {
|
||||
const lastApiRequest = await mockApi({page});
|
||||
const lastApiRequests = await mockApi({page, responses: {
|
||||
custom_theme_settings: {
|
||||
browse: {
|
||||
custom_theme_settings: [{
|
||||
type: 'select',
|
||||
options: [
|
||||
'Logo on cover',
|
||||
'Logo in the middle',
|
||||
'Stacked'
|
||||
],
|
||||
default: 'Logo on cover',
|
||||
id: '648047658d265b0c8b33c591',
|
||||
value: 'Stacked',
|
||||
key: 'navigation_layout'
|
||||
}]
|
||||
}
|
||||
}
|
||||
}});
|
||||
|
||||
await page.goto('/');
|
||||
|
||||
|
@ -49,13 +68,13 @@ test.describe('Theme settings', async () => {
|
|||
|
||||
await expect(modal).not.toBeVisible();
|
||||
|
||||
expect(lastApiRequest.body).toMatchObject({
|
||||
const expectedSettings = {navigation_layout: 'Logo in the middle'};
|
||||
const expectedEncoded = new URLSearchParams([['custom', JSON.stringify(expectedSettings)]]).toString();
|
||||
expect(lastApiRequests.previewHtml.homepage.headers?.['x-ghost-preview']).toMatch(new RegExp(`&${expectedEncoded.replace(/\+/g, '\\+')}`));
|
||||
|
||||
expect(lastApiRequests.custom_theme_settings.edit.body).toMatchObject({
|
||||
custom_theme_settings: [
|
||||
{key: 'navigation_color'},
|
||||
{key: 'navigation_background_image'},
|
||||
{key: 'navigation_layout', value: 'Logo in the middle'},
|
||||
{key: 'show_publication_cover'},
|
||||
{key: 'email_signup_text'}
|
||||
{key: 'navigation_layout', value: 'Logo in the middle'}
|
||||
]
|
||||
});
|
||||
});
|
||||
|
|
123
ghost/admin-x-settings/test/e2e/site/navigation.test.ts
Normal file
123
ghost/admin-x-settings/test/e2e/site/navigation.test.ts
Normal file
|
@ -0,0 +1,123 @@
|
|||
import {expect, test} from '@playwright/test';
|
||||
import {mockApi} from '../../utils/e2e';
|
||||
|
||||
test.describe('Navigation settings', async () => {
|
||||
test('Editing primary and secondary navigation', async ({page}) => {
|
||||
const lastApiRequests = await mockApi({page});
|
||||
|
||||
await page.goto('/');
|
||||
|
||||
const section = page.getByTestId('navigation');
|
||||
await section.getByRole('button', {name: 'Customize'}).click();
|
||||
|
||||
const modal = page.getByTestId('navigation-modal');
|
||||
|
||||
const primaryNavigationTab = modal.getByRole('tabpanel').first();
|
||||
|
||||
const primaryItem = primaryNavigationTab.getByTestId('navigation-item-editor').first();
|
||||
await primaryItem.getByLabel('Label').fill('existing item label');
|
||||
await primaryItem.getByLabel('URL').fill('/existing');
|
||||
|
||||
await primaryNavigationTab.getByTestId('new-navigation-item').getByLabel('Label').fill('new item label');
|
||||
await primaryNavigationTab.getByTestId('new-navigation-item').getByLabel('URL').fill('/new');
|
||||
await primaryNavigationTab.getByTestId('new-navigation-item').getByLabel('URL').blur();
|
||||
|
||||
await modal.getByRole('tab').last().click();
|
||||
|
||||
const secondaryNavigationTab = modal.getByRole('tabpanel').last();
|
||||
|
||||
const secondaryItem = secondaryNavigationTab.getByTestId('navigation-item-editor').first();
|
||||
await secondaryItem.getByLabel('Label').fill('existing item 2');
|
||||
await secondaryItem.getByLabel('URL').fill('/existing2');
|
||||
|
||||
await secondaryNavigationTab.getByTestId('new-navigation-item').getByLabel('Label').fill('new item 2');
|
||||
await secondaryNavigationTab.getByTestId('new-navigation-item').getByLabel('URL').press('Backspace');
|
||||
await secondaryNavigationTab.getByTestId('new-navigation-item').getByLabel('URL').fill('https://google.com');
|
||||
await secondaryNavigationTab.getByTestId('new-navigation-item').getByLabel('URL').blur();
|
||||
|
||||
await modal.getByRole('button', {name: 'OK'}).click();
|
||||
|
||||
await expect(modal).not.toBeVisible();
|
||||
|
||||
expect(lastApiRequests.settings.edit.body).toEqual({
|
||||
settings: [
|
||||
{key: 'navigation', value: '[{"url":"/existing/","label":"existing item label"},{"url":"/about/","label":"About"},{"url":"/new/","label":"new item label"}]'},
|
||||
{key: 'secondary_navigation', value: '[{"url":"/existing2/","label":"existing item 2"},{"url":"https://google.com","label":"new item 2"}]'}
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
test('Existing item validations', async ({page}) => {
|
||||
await mockApi({page});
|
||||
|
||||
await page.goto('/');
|
||||
|
||||
const section = page.getByTestId('navigation');
|
||||
await section.getByRole('button', {name: 'Customize'}).click();
|
||||
|
||||
const modal = page.getByTestId('navigation-modal');
|
||||
|
||||
const primaryNavigationTab = modal.getByRole('tabpanel').first();
|
||||
|
||||
const primaryItem = primaryNavigationTab.getByTestId('navigation-item-editor').first();
|
||||
await primaryItem.getByLabel('Label').fill('');
|
||||
await primaryItem.getByLabel('URL').press('Backspace');
|
||||
await primaryItem.getByLabel('URL').fill('google.com');
|
||||
|
||||
await modal.getByRole('button', {name: 'OK'}).click();
|
||||
|
||||
await expect(primaryItem.getByText('You must specify a label')).toHaveCount(1);
|
||||
await expect(primaryItem.getByText('You must specify a valid URL or relative path')).toHaveCount(1);
|
||||
|
||||
await primaryItem.getByLabel('Label').press('A');
|
||||
await expect(primaryItem.getByText('You must specify a label')).toHaveCount(0);
|
||||
|
||||
// The error should hide whenever the user types even if the URL is still not valid
|
||||
await primaryItem.getByLabel('URL').press('A');
|
||||
await expect(primaryItem.getByText('You must specify a valid URL or relative path')).toHaveCount(0);
|
||||
});
|
||||
|
||||
test('Adding a new item', async ({page}) => {
|
||||
await mockApi({page});
|
||||
|
||||
await page.goto('/');
|
||||
|
||||
const section = page.getByTestId('navigation');
|
||||
await section.getByRole('button', {name: 'Customize'}).click();
|
||||
|
||||
const modal = page.getByTestId('navigation-modal');
|
||||
|
||||
const primaryNavigationTab = modal.getByRole('tabpanel').first();
|
||||
|
||||
await expect(primaryNavigationTab.getByTestId('navigation-item-editor')).toHaveCount(2);
|
||||
|
||||
const newItem = primaryNavigationTab.getByTestId('new-navigation-item');
|
||||
await newItem.getByLabel('Label').fill('');
|
||||
await newItem.getByLabel('URL').press('Backspace');
|
||||
await newItem.getByLabel('URL').fill('google.com');
|
||||
|
||||
await newItem.getByTestId('add-button').click();
|
||||
|
||||
await expect(newItem.getByText('You must specify a label')).toHaveCount(1);
|
||||
await expect(newItem.getByText('You must specify a valid URL or relative path')).toHaveCount(1);
|
||||
|
||||
await newItem.getByLabel('Label').press('A');
|
||||
await expect(newItem.getByText('You must specify a label')).toHaveCount(0);
|
||||
|
||||
// The error should hide whenever the user types even if the URL is still not valid
|
||||
await newItem.getByLabel('URL').press('A');
|
||||
await expect(newItem.getByText('You must specify a valid URL or relative path')).toHaveCount(0);
|
||||
|
||||
await newItem.getByLabel('Label').fill('Label');
|
||||
await newItem.getByLabel('URL').fill('https://google.com');
|
||||
|
||||
await newItem.getByTestId('add-button').click();
|
||||
|
||||
await expect(primaryNavigationTab.getByTestId('navigation-item-editor')).toHaveCount(3);
|
||||
|
||||
await expect(primaryNavigationTab.getByTestId('navigation-item-editor').last().getByLabel('Label')).toHaveValue('Label');
|
||||
await expect(primaryNavigationTab.getByTestId('navigation-item-editor').last().getByLabel('URL')).toHaveValue('https://google.com/');
|
||||
await expect(newItem.getByLabel('Label')).toHaveValue('');
|
||||
await expect(newItem.getByLabel('URL')).toHaveValue('http://test.com/');
|
||||
});
|
||||
});
|
|
@ -1,11 +1,6 @@
|
|||
import {Page} from '@playwright/test';
|
||||
import {Page, Request} from '@playwright/test';
|
||||
import {readFileSync} from 'fs';
|
||||
|
||||
type LastApiRequest = {
|
||||
url: null | string
|
||||
body: null | any
|
||||
};
|
||||
|
||||
const responseFixtures = {
|
||||
settings: JSON.parse(readFileSync(`${__dirname}/responses/settings.json`).toString()),
|
||||
site: JSON.parse(readFileSync(`${__dirname}/responses/site.json`).toString()),
|
||||
|
@ -27,85 +22,132 @@ interface Responses {
|
|||
browse?: any
|
||||
edit?: any
|
||||
}
|
||||
previewHtml: {
|
||||
previewHtml?: {
|
||||
homepage?: string
|
||||
}
|
||||
}
|
||||
|
||||
interface RequestRecord {
|
||||
url?: string
|
||||
body?: any
|
||||
headers?: {[key: string]: string}
|
||||
}
|
||||
|
||||
type LastRequests = {
|
||||
settings: {
|
||||
browse: RequestRecord
|
||||
edit: RequestRecord
|
||||
}
|
||||
site: {
|
||||
browse: RequestRecord
|
||||
}
|
||||
images: {
|
||||
upload: RequestRecord
|
||||
}
|
||||
custom_theme_settings: {
|
||||
browse: RequestRecord
|
||||
edit: RequestRecord
|
||||
}
|
||||
previewHtml: {
|
||||
homepage: RequestRecord
|
||||
}
|
||||
};
|
||||
|
||||
export async function mockApi({page,responses}: {page: Page, responses?: Responses}) {
|
||||
const lastApiRequest: LastApiRequest = {
|
||||
url: null,
|
||||
body: null
|
||||
const lastApiRequests: LastRequests = {
|
||||
settings: {browse: {}, edit: {}},
|
||||
site: {browse: {}},
|
||||
images: {upload: {}},
|
||||
custom_theme_settings: {browse: {}, edit: {}},
|
||||
previewHtml: {homepage: {}}
|
||||
};
|
||||
|
||||
await mockApiResponse({
|
||||
page,
|
||||
path: /\/ghost\/api\/admin\/settings\//,
|
||||
responses: {
|
||||
GET: {body: responses?.settings?.browse ?? responseFixtures.settings},
|
||||
PUT: {body: responses?.settings?.edit ?? responseFixtures.settings}
|
||||
},
|
||||
lastApiRequest
|
||||
respondTo: {
|
||||
GET: {
|
||||
body: responses?.settings?.browse ?? responseFixtures.settings,
|
||||
updateLastRequest: lastApiRequests.settings.browse
|
||||
},
|
||||
PUT: {
|
||||
body: responses?.settings?.edit ?? responseFixtures.settings,
|
||||
updateLastRequest: lastApiRequests.settings.edit
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await mockApiResponse({
|
||||
page,
|
||||
path: /\/ghost\/api\/admin\/site\//,
|
||||
responses: {
|
||||
GET: {body: responses?.site?.browse ?? responseFixtures.site}
|
||||
},
|
||||
lastApiRequest
|
||||
respondTo: {
|
||||
GET: {
|
||||
body: responses?.site?.browse ?? responseFixtures.site,
|
||||
updateLastRequest: lastApiRequests.site.browse
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await mockApiResponse({
|
||||
page,
|
||||
path: /\/ghost\/api\/admin\/images\/upload\/$/,
|
||||
responses: {
|
||||
POST: {body: responses?.images?.upload ?? {images: [{url: 'http://example.com/image.png', ref: null}]}}
|
||||
},
|
||||
lastApiRequest
|
||||
respondTo: {
|
||||
POST: {
|
||||
body: responses?.images?.upload ?? {images: [{url: 'http://example.com/image.png', ref: null}]},
|
||||
updateLastRequest: lastApiRequests.images.upload
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await mockApiResponse({
|
||||
page,
|
||||
path: /\/ghost\/api\/admin\/custom_theme_settings\/$/,
|
||||
responses: {
|
||||
GET: {body: responses?.custom_theme_settings?.browse ?? responseFixtures.custom_theme_settings},
|
||||
PUT: {body: responses?.custom_theme_settings?.edit ?? responseFixtures.custom_theme_settings}
|
||||
},
|
||||
lastApiRequest
|
||||
});
|
||||
|
||||
await page.route(responseFixtures.site.site.url, async (route) => {
|
||||
if (!route.request().headers()['x-ghost-preview']) {
|
||||
return route.continue();
|
||||
respondTo: {
|
||||
GET: {
|
||||
body: responses?.custom_theme_settings?.browse ?? responseFixtures.custom_theme_settings,
|
||||
updateLastRequest: lastApiRequests.custom_theme_settings.browse
|
||||
},
|
||||
PUT: {
|
||||
body: responses?.custom_theme_settings?.edit ?? responseFixtures.custom_theme_settings,
|
||||
updateLastRequest: lastApiRequests.custom_theme_settings.edit
|
||||
}
|
||||
}
|
||||
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
body: responses?.previewHtml?.homepage ?? '<html><head><style></style></head><body><div>test</div></body></html>'
|
||||
});
|
||||
});
|
||||
|
||||
return lastApiRequest;
|
||||
await mockApiResponse({
|
||||
page,
|
||||
path: responseFixtures.site.site.url,
|
||||
respondTo: {
|
||||
POST: {
|
||||
condition: request => !!request.headers()['x-ghost-preview'],
|
||||
body: responses?.previewHtml?.homepage ?? '<html><head><style></style></head><body><div>test</div></body></html>',
|
||||
updateLastRequest: lastApiRequests.previewHtml.homepage
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return lastApiRequests;
|
||||
}
|
||||
|
||||
interface MockResponse {
|
||||
interface ResponseOptions {
|
||||
condition?: (request: Request) => boolean
|
||||
body: any
|
||||
status?: number
|
||||
updateLastRequest: RequestRecord
|
||||
}
|
||||
|
||||
async function mockApiResponse({page, path, lastApiRequest, responses}: { page: Page; path: string | RegExp; lastApiRequest: LastApiRequest, responses: { [method: string]: MockResponse } }) {
|
||||
async function mockApiResponse({page, path, respondTo}: { page: Page; path: string | RegExp; respondTo: { [method: string]: ResponseOptions } }) {
|
||||
await page.route(path, async (route) => {
|
||||
const response = responses[route.request().method()];
|
||||
const response = respondTo[route.request().method()];
|
||||
|
||||
if (!response) {
|
||||
if (!response || (response.condition && !response.condition(route.request()))) {
|
||||
return route.continue();
|
||||
}
|
||||
|
||||
const requestBody = JSON.parse(route.request().postData() || 'null');
|
||||
lastApiRequest.body = requestBody;
|
||||
lastApiRequest.url = route.request().url();
|
||||
response.updateLastRequest.body = requestBody;
|
||||
response.updateLastRequest.url = route.request().url();
|
||||
response.updateLastRequest.headers = route.request().headers();
|
||||
|
||||
await route.fulfill({
|
||||
status: response.status || 200,
|
||||
|
|
Loading…
Add table
Reference in a new issue