Added e2e tests for most simple AdminX settings

This commit is contained in:
Jono Mingard 2023-06-06 15:50:07 +12:00
parent 089a3f7aaf
commit 885531b345
29 changed files with 552 additions and 24 deletions

View File

@ -45,6 +45,7 @@
"dependencies": {
"@ebay/nice-modal-react": "^1.2.10",
"@tryghost/timezone-data": "0.3.0",
"clsx": "^1.2.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"validator": "7.2.0"

View File

@ -1,4 +1,4 @@
import React, {useEffect, useState} from 'react';
import React, {useEffect, useId, useState} from 'react';
import Heading from './Heading';
import Hint from './Hint';
@ -20,6 +20,8 @@ interface SelectProps {
}
const Select: React.FC<SelectProps> = ({title, prompt, options, onSelect, error, hint, defaultSelectedOption, clearBg = false}) => {
const id = useId();
const [selectedOption, setSelectedOption] = useState(defaultSelectedOption);
useEffect(() => {
@ -36,9 +38,9 @@ const Select: React.FC<SelectProps> = ({title, prompt, options, onSelect, error,
return (
<div className='flex flex-col'>
{title && <Heading useLabelTag={true}>{title}</Heading>}
{title && <Heading htmlFor={id} useLabelTag={true}>{title}</Heading>}
<div className={`relative w-full after:pointer-events-none after:absolute ${clearBg ? 'after:right-0' : 'after:right-4'} after:block after:h-2 after:w-2 after:rotate-45 after:border-[1px] after:border-l-0 after:border-t-0 after:border-grey-900 after:content-[''] ${title ? 'after:top-[22px]' : 'after:top-[14px]'}`}>
<select className={`w-full cursor-pointer appearance-none border-b ${!clearBg && 'bg-grey-75 px-[10px]'} py-2 outline-none ${error ? `border-red` : `border-grey-500 hover:border-grey-700 focus:border-black`} ${title && `mt-2`}`} value={selectedOption} onChange={handleOptionChange}>
<select className={`w-full cursor-pointer appearance-none border-b ${!clearBg && 'bg-grey-75 px-[10px]'} py-2 outline-none ${error ? `border-red` : `border-grey-500 hover:border-grey-700 focus:border-black`} ${title && `mt-2`}`} id={id} value={selectedOption} onChange={handleOptionChange}>
{prompt && <option value="">{prompt}</option>}
{options.map(option => (
<option
@ -55,4 +57,4 @@ const Select: React.FC<SelectProps> = ({title, prompt, options, onSelect, error,
);
};
export default Select;
export default Select;

View File

@ -1,13 +1,14 @@
import React, {useId} from 'react';
import Heading from './Heading';
import Hint from './Hint';
import React, {useId} from 'react';
import clsx from 'clsx';
type TextFieldType = 'text' | 'number' | 'email' | 'password' | 'file' | 'date' | 'time' | 'search';
interface TextFieldProps {
inputRef?: React.RefObject<HTMLInputElement>;
title?: string;
hideTitle?: boolean;
type?: TextFieldType;
value?: string;
error?: boolean;
@ -24,6 +25,7 @@ const TextField: React.FC<TextFieldProps> = ({
type = 'text',
inputRef,
title,
hideTitle,
value,
error,
placeholder,
@ -39,10 +41,16 @@ const TextField: React.FC<TextFieldProps> = ({
return (
<div className='flex flex-col'>
{title && <Heading htmlFor={id} useLabelTag={true}>{title}</Heading>}
{title && <Heading className={hideTitle ? 'sr-only' : ''} htmlFor={id} useLabelTag={true}>{title}</Heading>}
<input
ref={inputRef}
className={`border-b ${clearBg ? 'bg-transparent' : 'bg-grey-75 px-[10px]'} py-2 ${error ? `border-red` : `border-grey-500 hover:border-grey-700 focus:border-black`} ${(title && !clearBg) && `mt-2`} ${className}`}
className={clsx(
'border-b py-2',
clearBg ? 'bg-transparent' : 'bg-grey-75 px-[10px]',
error ? `border-red` : `border-grey-500 hover:border-grey-700 focus:border-black`,
(title && !hideTitle && !clearBg) && `mt-2`,
className
)}
defaultValue={value}
id={id}
maxLength={maxLength}

View File

@ -107,13 +107,13 @@ const DefaultRecipients: React.FC = () => {
defaultSelectedOption={emailRecipientValue}
hint='Who should be able to subscribe to your site?'
options={RECIPIENT_FILTER_OPTIONS}
title="Subscription access"
title="Default Newsletter recipients"
onSelect={(value) => {
setDefaultRecipientValue(value);
}}
/>
{(emailRecipientValue === 'segment') && (
<MultiSelect
<MultiSelect
defaultValues={[
{value: 'option2', label: 'Fake tier 2'}
]}
@ -139,6 +139,7 @@ const DefaultRecipients: React.FC = () => {
navid='default-recipients'
saveState={saveState}
state={currentState}
testId='default-recipients'
title='Default recipients'
onCancel={handleCancel}
onSave={handleSave}
@ -149,4 +150,4 @@ const DefaultRecipients: React.FC = () => {
);
};
export default DefaultRecipients;
export default DefaultRecipients;

View File

@ -100,6 +100,7 @@ const MailGun: React.FC = () => {
navid='mailgun'
saveState={saveState}
state={currentState}
testId='mailgun'
title='Mailgun'
onCancel={handleCancel}
onSave={handleSave}
@ -110,4 +111,4 @@ const MailGun: React.FC = () => {
);
};
export default MailGun;
export default MailGun;

View File

@ -65,7 +65,7 @@ const Facebook: React.FC = () => {
<ImageUpload
fileUploadClassName='flex cursor-pointer items-center justify-center rounded rounded-b-none border border-grey-100 border-b-0 bg-grey-75 p-3 text-sm font-semibold text-grey-800 hover:text-black'
height='300px'
id='twitter-image'
id='facebook-image'
imageURL={facebookImage}
onDelete={handleImageDelete}
onUpload={handleImageUpload}
@ -101,6 +101,7 @@ const Facebook: React.FC = () => {
navid='facebook'
saveState={saveState}
state={currentState}
testId='facebook'
title='Facebook card'
onCancel={handleCancel}
onSave={handleSave}
@ -112,4 +113,4 @@ const Facebook: React.FC = () => {
);
};
export default Facebook;
export default Facebook;

View File

@ -67,7 +67,9 @@ const LockSite: React.FC = () => {
<TextField
hint={hint}
placeholder="Enter password"
title="Site password"
value={password}
hideTitle
onChange={handlePasswordChange}
/>
}
@ -80,6 +82,7 @@ const LockSite: React.FC = () => {
navid='locksite'
saveState={saveState}
state={currentState}
testId='locksite'
title='Make site private'
onCancel={handleCancel}
onSave={handleSave}
@ -90,4 +93,4 @@ const LockSite: React.FC = () => {
);
};
export default LockSite;
export default LockSite;

View File

@ -103,6 +103,7 @@ const Metadata: React.FC = () => {
navid='metadata'
saveState={saveState}
state={currentState}
testId='metadata'
title='Metadata'
onCancel={handleCancel}
onSave={handleSave}
@ -119,4 +120,4 @@ const Metadata: React.FC = () => {
);
};
export default Metadata;
export default Metadata;

View File

@ -58,6 +58,7 @@ const PublicationLanguage: React.FC = () => {
navid='publication-language'
saveState={saveState}
state={currentState}
testId='publication-language'
title="Publication Language"
onCancel={handleCancel}
onSave={handleSave}
@ -68,4 +69,4 @@ const PublicationLanguage: React.FC = () => {
);
};
export default PublicationLanguage;
export default PublicationLanguage;

View File

@ -160,6 +160,7 @@ const SocialAccounts: React.FC = () => {
navid='social-accounts'
saveState={saveState}
state={currentState}
testId='social-accounts'
title='Social accounts'
onCancel={handleCancel}
onSave={() => {
@ -191,4 +192,4 @@ const SocialAccounts: React.FC = () => {
);
};
export default SocialAccounts;
export default SocialAccounts;

View File

@ -87,6 +87,7 @@ const TimeZone: React.FC = () => {
navid='timezone'
saveState={saveState}
state={currentState}
testId='timezone'
title='Site timezone'
onCancel={handleCancel}
onSave={handleSave}
@ -97,4 +98,4 @@ const TimeZone: React.FC = () => {
);
};
export default TimeZone;
export default TimeZone;

View File

@ -103,6 +103,7 @@ const Twitter: React.FC = () => {
navid='twitter'
saveState={saveState}
state={currentState}
testId='twitter'
title='Twitter card'
onCancel={handleCancel}
onSave={handleSave}
@ -114,4 +115,4 @@ const Twitter: React.FC = () => {
);
};
export default Twitter;
export default Twitter;

View File

@ -103,6 +103,7 @@ const Access: React.FC = () => {
navid='access'
saveState={saveState}
state={currentState}
testId='access'
title='Access'
onCancel={handleCancel}
onSave={handleSave}
@ -113,4 +114,4 @@ const Access: React.FC = () => {
);
};
export default Access;
export default Access;

View File

@ -76,6 +76,7 @@ const Analytics: React.FC = () => {
navid='analytics'
saveState={saveState}
state={currentState}
testId='analytics'
title='Analytics'
onCancel={handleCancel}
onSave={handleSave}
@ -89,4 +90,4 @@ const Analytics: React.FC = () => {
);
};
export default Analytics;
export default Analytics;

View File

@ -0,0 +1,58 @@
import {expect, test} from '@playwright/test';
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: {
settings: {
edit: updatedSettingsResponse([
{key: 'editor_default_email_recipients', value: 'filter'},
{key: 'editor_default_email_recipients_filter', value: 'status:-free'}
])
}
}});
await page.goto('/');
const section = page.getByTestId('default-recipients');
await expect(section.getByText('Whoever has access to the post')).toHaveCount(1);
await section.getByRole('button', {name: 'Edit'}).click();
await section.getByLabel('Default newsletter recipients').selectOption('All members');
await section.getByRole('button', {name: 'Save'}).click();
expect(lastApiRequest.body).toEqual({
settings: [
{key: 'editor_default_email_recipients', value: 'filter'},
{key: 'editor_default_email_recipients_filter', value: 'status:free,status:-free'}
]
});
await section.getByRole('button', {name: 'Edit'}).click();
await section.getByLabel('Default newsletter recipients').selectOption('Usually nobody');
await section.getByRole('button', {name: 'Save'}).click();
expect(lastApiRequest.body).toEqual({
settings: [
{key: 'editor_default_email_recipients', value: 'filter'},
{key: 'editor_default_email_recipients_filter', value: null}
]
});
await section.getByRole('button', {name: 'Edit'}).click();
await section.getByLabel('Default newsletter recipients').selectOption('Paid-members only');
await section.getByRole('button', {name: 'Save'}).click();
await expect(section.getByLabel('Default newsletter recipients')).toHaveCount(0);
await expect(section.getByText('Paid-members only')).toHaveCount(1);
expect(lastApiRequest.body).toEqual({
settings: [
{key: 'editor_default_email_recipients', value: 'filter'},
{key: 'editor_default_email_recipients_filter', value: 'status:-free'}
]
});
});
});

View File

@ -0,0 +1,39 @@
import {expect, test} from '@playwright/test';
import {mockApi, updatedSettingsResponse} from '../../utils/e2e';
test.describe('Mailgun settings', async () => {
test('Supports setting up mailgun', async ({page}) => {
const lastApiRequest = await mockApi({page, responses: {
settings: {
edit: updatedSettingsResponse([
{key: 'mailgun_domain', value: 'test.com'},
{key: 'mailgun_api_key', value: 'test'}
])
}
}});
await page.goto('/');
const section = page.getByTestId('mailgun');
await expect(section.getByText('Mailgun is not set up')).toHaveCount(1);
await section.getByRole('button', {name: 'Edit'}).click();
await section.getByLabel('Mailgun domain').fill('test.com');
await section.getByLabel('Mailgun private API key').fill('test');
await section.getByRole('button', {name: 'Save'}).click();
await expect(section.getByLabel('Mailgun domain')).toHaveCount(0);
await expect(section.getByText('Mailgun is set up')).toHaveCount(1);
expect(lastApiRequest.body).toEqual({
settings: [
{key: 'mailgun_domain', value: 'test.com'},
{key: 'mailgun_api_key', value: 'test'}
]
});
});
});

View File

@ -0,0 +1,42 @@
import {expect, test} from '@playwright/test';
import {mockApi} from '../../utils/e2e';
test.describe('Facebook settings', async () => {
test('Supports editing the facebook card', async ({page}) => {
const lastApiRequest = await mockApi({page, responses: {
images: {
upload: {images: [{url: 'http://example.com/image.png', ref: null}]}
}
}});
await page.goto('/');
const section = page.getByTestId('facebook');
await section.getByRole('button', {name: 'Edit'}).click();
const fileChooserPromise = page.waitForEvent('filechooser');
await page.locator('label[for="facebook-image"]').click();
const fileChooser = await fileChooserPromise;
await fileChooser.setFiles(`${__dirname}/../../utils/images/image.png`);
await expect(section.locator('[style*="background-image"]')).toHaveCSS('background-image', 'url("http://example.com/image.png")');
await section.getByLabel('Facebook title').fill('Facetitle');
await section.getByLabel('Facebook description').fill('Facescription');
await section.getByRole('button', {name: 'Save'}).click();
await expect(section.getByLabel('Facebook title')).toHaveCount(0);
expect(lastApiRequest.body).toEqual({
settings: [
{key: 'og_image', value: 'http://example.com/image.png'},
{key: 'og_title', value: 'Facetitle'},
{key: 'og_description', value: 'Facescription'}
]
});
});
});

View File

@ -0,0 +1,65 @@
import {expect, test} from '@playwright/test';
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: {
settings: {
edit: updatedSettingsResponse([
{key: 'is_private', value: true},
{key: 'password', value: 'password'}
])
}
}});
await page.goto('/');
const section = page.getByTestId('locksite');
await expect(section.getByText('Your site is not password protected')).toHaveCount(1);
// Add a site password
await section.getByRole('button', {name: 'Edit'}).click();
await section.getByLabel(/Enable password protection/).check();
await section.getByLabel('Site password').fill('password');
await section.getByRole('button', {name: 'Save'}).click();
await expect(section.getByLabel('Site password')).toHaveCount(0);
await expect(section.getByText('Your site is password protected')).toHaveCount(1);
expect(lastApiRequest.body).toEqual({
settings: [
{key: 'is_private', value: true},
{key: 'password', value: 'password'}
]
});
// Remove the site password
lastApiRequest = await mockApi({page, responses: {
settings: {
edit: updatedSettingsResponse([
{key: 'is_private', value: false}
])
}
}});
await section.getByRole('button', {name: 'Edit'}).click();
await section.getByLabel(/Enable password protection/).uncheck();
await section.getByRole('button', {name: 'Save'}).click();
await expect(section.getByText('Your site is not password protected')).toHaveCount(1);
expect(lastApiRequest.body).toEqual({
settings: [
{key: 'is_private', value: false}
]
});
});
});

View File

@ -0,0 +1,41 @@
import {expect, test} from '@playwright/test';
import {mockApi, updatedSettingsResponse} from '../../utils/e2e';
test.describe('Metadata settings', async () => {
test('Supports editing metadata', async ({page}) => {
const lastApiRequest = await mockApi({page, responses: {
settings: {
edit: updatedSettingsResponse([
{key: 'meta_title', value: 'Alternative title'},
{key: 'meta_description', value: 'Alternative description'}
])
}
}});
await page.goto('/');
const section = page.getByTestId('metadata');
await expect(section.getByText('Test Site')).toHaveCount(1);
await expect(section.getByText('Thoughts, stories and ideas.')).toHaveCount(1);
await section.getByRole('button', {name: 'Edit'}).click();
await section.getByLabel('Meta title').fill('Alternative title');
await section.getByLabel('Meta description').fill('Alternative description');
await section.getByRole('button', {name: 'Save'}).click();
await expect(section.getByLabel('Meta title')).toHaveCount(0);
await expect(section.getByText('Alternative title')).toHaveCount(1);
await expect(section.getByText('Alternative description')).toHaveCount(1);
expect(lastApiRequest.body).toEqual({
settings: [
{key: 'meta_title', value: 'Alternative title'},
{key: 'meta_description', value: 'Alternative description'}
]
});
});
});

View File

@ -0,0 +1,36 @@
import {expect, test} from '@playwright/test';
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: {
settings: {
edit: updatedSettingsResponse([
{key: 'locale', value: 'jp'}
])
}
}});
await page.goto('/');
const section = page.getByTestId('publication-language');
await expect(section.getByText('en')).toHaveCount(1);
await section.getByRole('button', {name: 'Edit'}).click();
await section.getByLabel('Site language').fill('jp');
await section.getByRole('button', {name: 'Save'}).click();
await expect(section.getByLabel('Site language')).toHaveCount(0);
await expect(section.getByText('jp')).toHaveCount(1);
expect(lastApiRequest.body).toEqual({
settings: [
{key: 'locale', value: 'jp'}
]
});
});
});

View File

@ -0,0 +1,41 @@
import {expect, test} from '@playwright/test';
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: {
settings: {
edit: updatedSettingsResponse([
{key: 'facebook', value: 'fb'},
{key: 'twitter', value: '@tw'}
])
}
}});
await page.goto('/');
const section = page.getByTestId('social-accounts');
await expect(section.getByText('https://www.facebook.com/ghost')).toHaveCount(1);
await expect(section.getByText('https://twitter.com/ghost')).toHaveCount(1);
await section.getByRole('button', {name: 'Edit'}).click();
await section.getByLabel(`URL of your publication's Facebook Page`).fill('https://www.facebook.com/fb');
await section.getByLabel('URL of your Twitter profile').fill('https://twitter.com/tw');
await section.getByRole('button', {name: 'Save'}).click();
await expect(section.getByLabel('URL of your Twitter profile')).toHaveCount(0);
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({
settings: [
{key: 'facebook', value: 'fb'},
{key: 'twitter', value: '@tw'}
]
});
});
});

View File

@ -0,0 +1,36 @@
import {expect, test} from '@playwright/test';
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: {
settings: {
edit: updatedSettingsResponse([
{key: 'timezone', value: 'Asia/Tokyo'}
])
}
}});
await page.goto('/');
const section = page.getByTestId('timezone');
await expect(section.getByText('Etc/UTC')).toHaveCount(1);
await section.getByRole('button', {name: 'Edit'}).click();
await section.getByLabel('Site timezone').selectOption('Asia/Tokyo');
await section.getByRole('button', {name: 'Save'}).click();
await expect(section.getByLabel('Site timezone')).toHaveCount(0);
await expect(section.getByText('Asia/Tokyo')).toHaveCount(1);
expect(lastApiRequest.body).toEqual({
settings: [
{key: 'timezone', value: 'Asia/Tokyo'}
]
});
});
});

View File

@ -1,5 +1,5 @@
import {expect, test} from '@playwright/test';
import {mockApi, updatedSettingsResponse} from '../utils/e2e';
import {mockApi, updatedSettingsResponse} from '../../utils/e2e';
test.describe('Title and description settings', async () => {
test('Supports editing the title and description', async ({page}) => {

View File

@ -0,0 +1,42 @@
import {expect, test} from '@playwright/test';
import {mockApi} from '../../utils/e2e';
test.describe('Twitter settings', async () => {
test('Supports editing the twitter card', async ({page}) => {
const lastApiRequest = await mockApi({page, responses: {
images: {
upload: {images: [{url: 'http://example.com/image.png', ref: null}]}
}
}});
await page.goto('/');
const section = page.getByTestId('twitter');
await section.getByRole('button', {name: 'Edit'}).click();
const fileChooserPromise = page.waitForEvent('filechooser');
await page.locator('label[for="twitter-image"]').click();
const fileChooser = await fileChooserPromise;
await fileChooser.setFiles(`${__dirname}/../../utils/images/image.png`);
await expect(section.locator('[style*="background-image"]')).toHaveCSS('background-image', 'url("http://example.com/image.png")');
await section.getByLabel('Twitter title').fill('Twititle');
await section.getByLabel('Twitter description').fill('Twitscription');
await section.getByRole('button', {name: 'Save'}).click();
await expect(section.getByLabel('Twitter title')).toHaveCount(0);
expect(lastApiRequest.body).toEqual({
settings: [
{key: 'twitter_image', value: 'http://example.com/image.png'},
{key: 'twitter_title', value: 'Twititle'},
{key: 'twitter_description', value: 'Twitscription'}
]
});
});
});

View File

@ -0,0 +1,46 @@
import {expect, test} from '@playwright/test';
import {mockApi, updatedSettingsResponse} from '../../utils/e2e';
test.describe('Access settings', async () => {
test('Supports editing access', async ({page}) => {
const lastApiRequest = await mockApi({page, responses: {
settings: {
edit: updatedSettingsResponse([
{key: 'default_content_visibility', value: 'members'},
{key: 'members_signup_access', value: 'invite'},
{key: 'comments_enabled', value: 'all'}
])
}
}});
await page.goto('/');
const section = page.getByTestId('access');
await expect(section.getByText('Anyone can sign up')).toHaveCount(1);
await expect(section.getByText('Public')).toHaveCount(1);
await expect(section.getByText('Nobody')).toHaveCount(1);
await section.getByRole('button', {name: 'Edit'}).click();
await section.getByLabel('Subscription access').selectOption({label: 'Only people I invite'});
await section.getByLabel('Default post access').selectOption({label: 'Members only'});
await section.getByLabel('Commenting').selectOption({label: 'All members'});
await section.getByRole('button', {name: 'Save'}).click();
await expect(section.getByLabel('Subscription access')).toHaveCount(0);
await expect(section.getByText('Only people I invite')).toHaveCount(1);
await expect(section.getByText('Members only')).toHaveCount(1);
await expect(section.getByText('All members')).toHaveCount(1);
expect(lastApiRequest.body).toEqual({
settings: [
{key: 'default_content_visibility', value: 'members'},
{key: 'members_signup_access', value: 'invite'},
{key: 'comments_enabled', value: 'all'}
]
});
});
});

View File

@ -0,0 +1,42 @@
import {expect, test} from '@playwright/test';
import {mockApi, updatedSettingsResponse} from '../../utils/e2e';
test.describe('Analytics settings', async () => {
test('Supports toggling analytics settings', async ({page}) => {
const lastApiRequest = await mockApi({page, responses: {
settings: {
edit: updatedSettingsResponse([
{key: 'members_track_sources', value: false},
{key: 'email_track_opens', value: false},
{key: 'email_track_clicks', value: false},
{key: 'outbound_link_tagging', value: false}
])
}
}});
await page.goto('/');
const section = page.getByTestId('analytics');
await expect(section.getByLabel(/Newsletter opens/)).toBeChecked();
await expect(section.getByLabel(/Newsletter clicks/)).toBeChecked();
await expect(section.getByLabel(/Member sources/)).toBeChecked();
await expect(section.getByLabel(/Outbound link tagging/)).toBeChecked();
await section.getByLabel(/Newsletter opens/).uncheck();
await section.getByLabel(/Newsletter clicks/).uncheck();
await section.getByLabel(/Member sources/).uncheck();
await section.getByLabel(/Outbound link tagging/).uncheck();
await section.getByRole('button', {name: 'Save'}).click();
expect(lastApiRequest.body).toEqual({
settings: [
{key: 'members_track_sources', value: false},
{key: 'email_track_opens', value: false},
{key: 'email_track_clicks', value: false},
{key: 'outbound_link_tagging', value: false}
]
});
});
});

View File

@ -19,6 +19,9 @@ interface Responses {
site?: {
browse?: any
}
images?: {
upload?: any
}
}
export async function mockApi({page,responses}: {page: Page, responses?: Responses}) {
@ -51,6 +54,14 @@ export async function mockApi({page,responses}: {page: Page, responses?: Respons
lastApiRequest
});
await mockApiResponse({
page,
path: /\/ghost\/api\/admin\/images\/upload\/$/,
method: 'POST',
response: responses?.images?.upload ?? {images: [{url: 'http://example.com/image.png', ref: null}]},
lastApiRequest
});
return lastApiRequest;
}
@ -71,7 +82,7 @@ async function mockApiResponse({page, path, method, response, lastApiRequest}: {
});
}
export function updatedSettingsResponse(newSettings: Array<{ key: string, value: string }>) {
export function updatedSettingsResponse(newSettings: Array<{ key: string, value: string | boolean | null }>) {
return {
...responseFixtures.settings,
settings: responseFixtures.settings.settings.map((setting) => {

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

View File

@ -12782,6 +12782,11 @@ cloneable-readable@^1.0.0:
process-nextick-args "^2.0.0"
readable-stream "^2.3.5"
clsx@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
cluster-key-slot@1.1.2, cluster-key-slot@^1.1.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac"