Ghost/apps/admin-x-settings/test/acceptance/membership/tiers.test.ts
Jono M fb7bf6d01e
Improved AdminX test coverage based on old admin tests (#18502)
refs https://github.com/TryGhost/Product/issues/3832

---

<!-- Leave the line below if you'd like GitHub Copilot to generate a
summary from your commit -->
<!--
copilot:summary
-->
### <samp>🤖 Generated by Copilot at 7eda74c</samp>

This pull request improves the validation, customization, and feedback
of various form components and modals in the admin-x-settings app. It
also adds new components for user detail modal sections and modifies the
user type to allow null values for social accounts. Additionally, it
adds `dirty` props to some integration modals and a `data-testid`
attribute to the exit settings button. It also deletes an unused file.
2023-10-06 10:06:05 +01:00

213 lines
8.5 KiB
TypeScript

import {expect, test} from '@playwright/test';
import {globalDataRequests, mockApi, responseFixtures, updatedSettingsResponse} from '../../utils/acceptance';
const settingsWithStripe = updatedSettingsResponse([
{key: 'stripe_connect_publishable_key', value: 'pk_test_123'},
{key: 'stripe_connect_secret_key', value: 'sk_test_123'},
{key: 'stripe_connect_display_name', value: 'Dummy'},
{key: 'stripe_connect_account_id', value: 'acct_123'}
]);
test.describe('Tier settings', async () => {
test('Supports creating a new tier', async ({page}) => {
await mockApi({page, requests: {
...globalDataRequests,
browseSettings: {...globalDataRequests.browseSettings, response: settingsWithStripe},
browseTiers: {method: 'GET', path: '/tiers/', response: responseFixtures.tiers}
}});
await page.goto('/');
const section = page.getByTestId('tiers');
await section.getByRole('button', {name: 'Add tier'}).click();
const modal = page.getByTestId('tier-detail-modal');
await modal.getByRole('button', {name: 'Save & close'}).click();
await expect(page.getByTestId('toast-error')).toHaveText(/Can't save tier/);
await expect(modal).toHaveText(/You must specify a name/);
await expect(modal).toHaveText(/Amount must be at least \$1/);
await modal.getByLabel('Name').fill('Plus tier');
await modal.getByLabel('Monthly price').fill('8');
await modal.getByLabel('Yearly price').fill('80');
const newTier = {
id: 'new-tier',
type: 'paid',
active: true,
name: 'Plus tier',
slug: 'plus-tier',
description: null,
monthly_price: 800,
yearly_price: 8000,
benefits: [],
welcome_page_url: null,
trial_days: 0,
visibility: 'public',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString()
};
const {lastApiRequests} = await mockApi({page, requests: {
...globalDataRequests,
addTier: {method: 'POST', path: '/tiers/', response: {tiers: [newTier]}},
// This request will be reloaded after the new tier is added
browseTiers: {method: 'GET', path: '/tiers/', response: {tiers: [...responseFixtures.tiers.tiers, newTier]}}
}});
await modal.getByRole('button', {name: 'Save & close'}).click();
await expect(section.getByTestId('tier-card').filter({hasText: /Plus/})).toHaveText(/Plus tier/);
await expect(section.getByTestId('tier-card').filter({hasText: /Plus/})).toHaveText(/\$8\/month/);
expect(lastApiRequests.addTier?.body).toMatchObject({
tiers: [{
name: 'Plus tier',
monthly_price: 800,
yearly_price: 8000,
trial_days: null
}]
});
});
test('Supports updating a tier', async ({page}) => {
const {lastApiRequests} = await mockApi({page, requests: {
...globalDataRequests,
browseSettings: {...globalDataRequests.browseSettings, response: settingsWithStripe},
browseTiers: {method: 'GET', path: '/tiers/', response: responseFixtures.tiers},
editTier: {method: 'PUT', path: `/tiers/${responseFixtures.tiers.tiers[1].id}/`, response: {
tiers: [{
...responseFixtures.tiers.tiers[1],
name: 'Supporter updated',
description: 'Supporter description',
monthly_price: 1001,
trial_days: 7,
benefits: [
'Simple benefit',
'New benefit'
]
}]
}}
}});
await page.goto('/');
const section = page.getByTestId('tiers');
await section.getByTestId('tier-card').filter({hasText: /Supporter/}).click();
const modal = page.getByTestId('tier-detail-modal');
const preview = await modal.getByTestId('tier-preview');
await expect(preview).toContainText('Basic Supporter');
await expect(preview).toContainText('$5/month');
await expect(preview).toContainText('Simple benefit');
// Failing validations
await modal.getByLabel('Name').fill('');
await modal.getByRole('button', {name: 'Save & close'}).click();
await expect(page.getByTestId('toast-error')).toHaveText(/Can't save tier/);
await expect(modal).toHaveText(/You must specify a name/);
// Valid values
await modal.getByLabel('Name').fill('Supporter updated');
await modal.getByLabel('Description').fill('Supporter description');
await modal.getByLabel('Monthly price').fill('10.01');
await modal.getByLabel('Yearly price').fill('100');
await modal.getByLabel('Add a free trial').check();
await modal.getByLabel('Trial days').fill('7');
await modal.getByLabel('New benefit').fill('New benefit');
await modal.getByRole('button', {name: 'Add'}).click();
// Check that the preview is updated
await expect(preview).toContainText('Supporter updated');
await expect(preview).toContainText('Supporter description');
await expect(preview).toContainText('$10.01/month');
await expect(preview).toContainText('New benefit');
await preview.getByRole('button', {name: 'Yearly'}).click();
await expect(preview).not.toContainText('$10.01/month');
await expect(preview).toContainText('$100/year');
await expect(preview).toContainText('17% discount');
// Save changes
await modal.getByRole('button', {name: 'Save & close'}).click();
await expect(section.getByTestId('tier-card').filter({hasText: /Supporter/})).toHaveText(/Supporter updated/);
await expect(section.getByTestId('tier-card').filter({hasText: /Supporter/})).toHaveText(/Supporter description/);
await expect(section.getByTestId('tier-card').filter({hasText: /Supporter/})).toHaveText(/\$10\.01\/month/);
expect(lastApiRequests.editTier?.body).toMatchObject({
tiers: [{
id: responseFixtures.tiers.tiers[1].id,
name: 'Supporter updated',
description: 'Supporter description',
monthly_price: 1001,
yearly_price: 10000,
trial_days: 7,
benefits: [
'Simple benefit',
'New benefit'
]
}]
});
});
test('Supports editing the free tier', async ({page}) => {
const {lastApiRequests} = await mockApi({page, requests: {
...globalDataRequests,
browseSettings: {...globalDataRequests.browseSettings, response: settingsWithStripe},
browseTiers: {method: 'GET', path: '/tiers/', response: responseFixtures.tiers},
editTier: {method: 'PUT', path: `/tiers/${responseFixtures.tiers.tiers[0].id}/`, response: {
tiers: [{
...responseFixtures.tiers.tiers[0],
description: 'Free tier description',
benefits: [
'First benefit',
'Second benefit'
]
}]
}}
}});
await page.goto('/');
const section = page.getByTestId('tiers');
await section.getByTestId('tier-card').filter({hasText: /Free/}).click();
const modal = page.getByTestId('tier-detail-modal');
await modal.getByLabel('Description').fill('Free tier description');
await modal.getByLabel('Welcome page').fill('welcome-page');
await modal.getByLabel('New benefit').fill('First benefit');
await modal.getByRole('button', {name: 'Add'}).click();
await modal.getByLabel('New benefit').fill('Second benefit');
await modal.getByRole('button', {name: 'Save & close'}).click();
await expect(section.getByTestId('tier-card').filter({hasText: /Free/})).toHaveText(/Free tier description/);
expect(lastApiRequests.editTier?.body).toMatchObject({
tiers: [{
id: responseFixtures.tiers.tiers[0].id,
description: 'Free tier description',
welcome_page_url: '/welcome-page/',
benefits: [
'First benefit',
'Second benefit'
]
}]
});
});
});