mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-03 23:00:14 -05:00
Switched to a shared page for each playwright worker
refs: https://github.com/TryGhost/DevOps/issues/78 This speeds up the tests by another 30 seconds on my local machine, and hopefully takes some time off in CI too
This commit is contained in:
parent
0dbfafede0
commit
ccbcba0969
16 changed files with 634 additions and 620 deletions
|
@ -2,19 +2,19 @@ const {expect} = require('@playwright/test');
|
|||
const test = require('../fixtures/ghost-test');
|
||||
|
||||
test.describe('Announcement Bar Settings', () => {
|
||||
test('Bar hidden by default', async ({page}) => {
|
||||
await page.goto('/ghost');
|
||||
await goToAnnouncementBarSettings(page);
|
||||
test('Bar hidden by default', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
await goToAnnouncementBarSettings(sharedPage);
|
||||
|
||||
await test.step('Bar should be hidden', async () => {
|
||||
const htmlFrame = getPreviewFrame(page);
|
||||
const htmlFrame = getPreviewFrame(sharedPage);
|
||||
await expect(await htmlFrame.locator('#announcement-bar-root')).toHaveCount(0);
|
||||
});
|
||||
});
|
||||
|
||||
test('Show/hide bar if visibility checked/unchecked and text filled', async ({page}) => {
|
||||
await page.goto('/ghost');
|
||||
const modal = await goToAnnouncementBarSettings(page);
|
||||
test('Show/hide bar if visibility checked/unchecked and text filled', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
const modal = await goToAnnouncementBarSettings(sharedPage);
|
||||
|
||||
await test.step('Check free members', async () => {
|
||||
const freeMembersCheckbox = modal.getByLabel('Free members');
|
||||
|
@ -25,11 +25,11 @@ test.describe('Announcement Bar Settings', () => {
|
|||
await test.step('Fill announcement text', async () => {
|
||||
await modal.locator('.koenig-react-editor').click();
|
||||
await expect(await modal.locator('[contenteditable="true"]')).toBeVisible({timeout: 30000}); // add timeout as lexical module loading can take time
|
||||
await page.keyboard.type('Announcement text');
|
||||
await sharedPage.keyboard.type('Announcement text');
|
||||
await modal.getByText('Announcement').first().click(); // defocus the editor
|
||||
});
|
||||
|
||||
const htmlFrame = getPreviewFrame(page);
|
||||
const htmlFrame = getPreviewFrame(sharedPage);
|
||||
await test.step('Announcement bar should be visible', async () => {
|
||||
await expect(await htmlFrame.getByText('Announcement text')).toBeVisible();
|
||||
});
|
||||
|
@ -47,16 +47,16 @@ test.describe('Announcement Bar Settings', () => {
|
|||
});
|
||||
});
|
||||
|
||||
async function goToAnnouncementBarSettings(page) {
|
||||
async function goToAnnouncementBarSettings(sharedPage) {
|
||||
await test.step('Navigate to the announcement bar settings', async () => {
|
||||
await page.locator('[data-test-nav="settings"]').click();
|
||||
await page.getByTestId('announcement-bar').getByRole('button', {name: 'Customize'}).click();
|
||||
await sharedPage.locator('[data-test-nav="settings"]').click();
|
||||
await sharedPage.getByTestId('announcement-bar').getByRole('button', {name: 'Customize'}).click();
|
||||
// Wait for the preview to load
|
||||
await getPreviewFrame(page).locator('body *:visible').first().waitFor();
|
||||
await getPreviewFrame(sharedPage).locator('body *:visible').first().waitFor();
|
||||
});
|
||||
return page.getByTestId('announcement-bar-modal');
|
||||
return sharedPage.getByTestId('announcement-bar-modal');
|
||||
}
|
||||
|
||||
function getPreviewFrame(page) {
|
||||
return page.frameLocator('[data-testid="announcement-bar-preview-iframe"] > iframe[data-visible=true]');
|
||||
function getPreviewFrame(sharedPage) {
|
||||
return sharedPage.frameLocator('[data-testid="announcement-bar-preview-iframe"] > iframe[data-visible=true]');
|
||||
}
|
||||
|
|
|
@ -6,115 +6,115 @@ const fs = require('fs');
|
|||
test.describe('Admin', () => {
|
||||
test.describe('Members', () => {
|
||||
test.describe.configure({retries: 1, mode: 'serial'});
|
||||
test('A member can be created', async ({page}) => {
|
||||
await page.goto('/ghost');
|
||||
await page.locator('.gh-nav a[href="#/members/"]').click();
|
||||
await page.waitForSelector('a[href="#/members/new/"] span');
|
||||
await page.locator('a[href="#/members/new/"] span:has-text("New member")').click();
|
||||
await page.waitForSelector('input[name="name"]');
|
||||
test('A member can be created', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
await sharedPage.locator('.gh-nav a[href="#/members/"]').click();
|
||||
await sharedPage.waitForSelector('a[href="#/members/new/"] span');
|
||||
await sharedPage.locator('a[href="#/members/new/"] span:has-text("New member")').click();
|
||||
await sharedPage.waitForSelector('input[name="name"]');
|
||||
let name = 'Test Member';
|
||||
let email = 'tester@testmember.com';
|
||||
let note = 'This is a test member';
|
||||
let label = 'Test Label';
|
||||
await page.fill('input[name="name"]', name);
|
||||
await page.fill('input[name="email"]', email);
|
||||
await page.fill('textarea[name="note"]', note);
|
||||
await page.locator('label:has-text("Labels") + div').click();
|
||||
await page.keyboard.type(label);
|
||||
await page.keyboard.press('Tab');
|
||||
await page.locator('button span:has-text("Save")').click();
|
||||
await page.waitForSelector('button span:has-text("Saved")');
|
||||
await page.locator('.gh-nav a[href="#/members/"]').click();
|
||||
await sharedPage.fill('input[name="name"]', name);
|
||||
await sharedPage.fill('input[name="email"]', email);
|
||||
await sharedPage.fill('textarea[name="note"]', note);
|
||||
await sharedPage.locator('label:has-text("Labels") + div').click();
|
||||
await sharedPage.keyboard.type(label);
|
||||
await sharedPage.keyboard.press('Tab');
|
||||
await sharedPage.locator('button span:has-text("Save")').click();
|
||||
await sharedPage.waitForSelector('button span:has-text("Saved")');
|
||||
await sharedPage.locator('.gh-nav a[href="#/members/"]').click();
|
||||
|
||||
// check number of members
|
||||
await expect(page.locator('[data-test-list="members-list-item"]')).toHaveCount(1);
|
||||
await expect(sharedPage.locator('[data-test-list="members-list-item"]')).toHaveCount(1);
|
||||
|
||||
const member = page.locator('tbody > tr > a > div > div > h3').nth(0);
|
||||
const member = sharedPage.locator('tbody > tr > a > div > div > h3').nth(0);
|
||||
await expect(member).toHaveText(name);
|
||||
const memberEmail = page.locator('tbody > tr > a > div > div > p').nth(0);
|
||||
const memberEmail = sharedPage.locator('tbody > tr > a > div > div > p').nth(0);
|
||||
await expect(memberEmail).toHaveText(email);
|
||||
});
|
||||
|
||||
test('A member cannot be created with invalid email', async ({page}) => {
|
||||
await page.goto('/ghost');
|
||||
await page.locator('.gh-nav a[href="#/members/"]').click();
|
||||
await page.waitForSelector('a[href="#/members/new/"] span');
|
||||
await page.locator('a[href="#/members/new/"] span:has-text("New member")').click();
|
||||
await page.waitForSelector('input[name="name"]');
|
||||
test('A member cannot be created with invalid email', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
await sharedPage.locator('.gh-nav a[href="#/members/"]').click();
|
||||
await sharedPage.waitForSelector('a[href="#/members/new/"] span');
|
||||
await sharedPage.locator('a[href="#/members/new/"] span:has-text("New member")').click();
|
||||
await sharedPage.waitForSelector('input[name="name"]');
|
||||
let name = 'Test Member';
|
||||
let email = 'tester+invalid@testmember.com<6F>';
|
||||
let note = 'This is a test member';
|
||||
let label = 'Test Label';
|
||||
await page.fill('input[name="name"]', name);
|
||||
await page.fill('input[name="email"]', email);
|
||||
await page.fill('textarea[name="note"]', note);
|
||||
await page.locator('label:has-text("Labels") + div').click();
|
||||
await page.keyboard.type(label);
|
||||
await page.keyboard.press('Tab');
|
||||
await page.locator('button span:has-text("Save")').click();
|
||||
await page.waitForSelector('button span:has-text("Retry")');
|
||||
await sharedPage.fill('input[name="name"]', name);
|
||||
await sharedPage.fill('input[name="email"]', email);
|
||||
await sharedPage.fill('textarea[name="note"]', note);
|
||||
await sharedPage.locator('label:has-text("Labels") + div').click();
|
||||
await sharedPage.keyboard.type(label);
|
||||
await sharedPage.keyboard.press('Tab');
|
||||
await sharedPage.locator('button span:has-text("Save")').click();
|
||||
await sharedPage.waitForSelector('button span:has-text("Retry")');
|
||||
|
||||
// check we are unable to save member with invalid email
|
||||
await expect(page.locator('button span:has-text("Retry")')).toBeVisible();
|
||||
await expect(page.locator('text=Invalid Email')).toBeVisible();
|
||||
await expect(sharedPage.locator('button span:has-text("Retry")')).toBeVisible();
|
||||
await expect(sharedPage.locator('text=Invalid Email')).toBeVisible();
|
||||
});
|
||||
|
||||
test('A member can be edited', async ({page}) => {
|
||||
await page.goto('/ghost');
|
||||
await page.locator('.gh-nav a[href="#/members/"]').click();
|
||||
await page.locator('tbody > tr > a').nth(0).click();
|
||||
await page.waitForSelector('input[name="name"]');
|
||||
test('A member can be edited', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
await sharedPage.locator('.gh-nav a[href="#/members/"]').click();
|
||||
await sharedPage.locator('tbody > tr > a').nth(0).click();
|
||||
await sharedPage.waitForSelector('input[name="name"]');
|
||||
let name = 'Test Member Edited';
|
||||
let email = 'tester.edited@example.com';
|
||||
let note = 'This is an edited test member';
|
||||
await page.fill('input[name="name"]', name);
|
||||
await page.fill('input[name="email"]', email);
|
||||
await page.fill('textarea[name="note"]', note);
|
||||
await page.locator('label:has-text("Labels") + div').click();
|
||||
await page.keyboard.press('Backspace');
|
||||
await page.locator('body').click(); // this is to close the dropdown & lose focus
|
||||
await page.locator('input[name="subscribed"] + span').click();
|
||||
await page.locator('button span:has-text("Save")').click();
|
||||
await page.waitForSelector('button span:has-text("Saved")');
|
||||
await page.locator('.gh-nav a[href="#/members/"]').click();
|
||||
await sharedPage.fill('input[name="name"]', name);
|
||||
await sharedPage.fill('input[name="email"]', email);
|
||||
await sharedPage.fill('textarea[name="note"]', note);
|
||||
await sharedPage.locator('label:has-text("Labels") + div').click();
|
||||
await sharedPage.keyboard.press('Backspace');
|
||||
await sharedPage.locator('body').click(); // this is to close the dropdown & lose focus
|
||||
await sharedPage.locator('input[name="subscribed"] + span').click();
|
||||
await sharedPage.locator('button span:has-text("Save")').click();
|
||||
await sharedPage.waitForSelector('button span:has-text("Saved")');
|
||||
await sharedPage.locator('.gh-nav a[href="#/members/"]').click();
|
||||
|
||||
// check number of members
|
||||
await expect(page.locator('[data-test-list="members-list-item"]')).toHaveCount(1);
|
||||
await expect(sharedPage.locator('[data-test-list="members-list-item"]')).toHaveCount(1);
|
||||
|
||||
const member = page.locator('tbody > tr > a > div > div > h3').nth(0);
|
||||
const member = sharedPage.locator('tbody > tr > a > div > div > h3').nth(0);
|
||||
await expect(member).toHaveText(name);
|
||||
const memberEmail = page.locator('tbody > tr > a > div > div > p').nth(0);
|
||||
const memberEmail = sharedPage.locator('tbody > tr > a > div > div > p').nth(0);
|
||||
await expect(memberEmail).toHaveText(email);
|
||||
});
|
||||
|
||||
test('A member can be impersonated', async ({page}) => {
|
||||
await page.goto('/ghost');
|
||||
await page.locator('.gh-nav a[href="#/members/"]').click();
|
||||
await page.locator('tbody > tr > a').nth(0).click();
|
||||
await page.waitForSelector('[data-test-button="member-actions"]');
|
||||
await page.locator('[data-test-button="member-actions"]').click();
|
||||
await page.getByRole('button', {name: 'Impersonate'}).click();
|
||||
await page.getByRole('button', {name: 'Copy link'}).click();
|
||||
await page.waitForSelector('button span:has-text("Link copied")');
|
||||
test('A member can be impersonated', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
await sharedPage.locator('.gh-nav a[href="#/members/"]').click();
|
||||
await sharedPage.locator('tbody > tr > a').nth(0).click();
|
||||
await sharedPage.waitForSelector('[data-test-button="member-actions"]');
|
||||
await sharedPage.locator('[data-test-button="member-actions"]').click();
|
||||
await sharedPage.getByRole('button', {name: 'Impersonate'}).click();
|
||||
await sharedPage.getByRole('button', {name: 'Copy link'}).click();
|
||||
await sharedPage.waitForSelector('button span:has-text("Link copied")');
|
||||
// get value from input because we don't have access to the clipboard during headless testing
|
||||
const elem = await page.$('input[name="member-signin-url"]');
|
||||
const elem = await sharedPage.$('input[name="member-signin-url"]');
|
||||
const link = await elem.inputValue();
|
||||
await page.goto(link);
|
||||
await page.frameLocator('#ghost-portal-root iframe[title="portal-trigger"]').locator('div').nth(1).click();
|
||||
const title = await page.frameLocator('#ghost-portal-root div iframe[title="portal-popup"]').locator('h2').innerText();
|
||||
await sharedPage.goto(link);
|
||||
await sharedPage.frameLocator('#ghost-portal-root iframe[title="portal-trigger"]').locator('div').nth(1).click();
|
||||
const title = await sharedPage.frameLocator('#ghost-portal-root div iframe[title="portal-popup"]').locator('h2').innerText();
|
||||
await expect(title).toEqual('Your account'); // this is the title of the popup when member is logged in
|
||||
});
|
||||
|
||||
test('A member can be deleted', async ({page}) => {
|
||||
await page.goto('/ghost');
|
||||
await page.locator('.gh-nav a[href="#/members/"]').click();
|
||||
await page.locator('tbody > tr > a').nth(0).click();
|
||||
await page.waitForSelector('[data-test-button="member-actions"]');
|
||||
await page.locator('[data-test-button="member-actions"]').click();
|
||||
await page.getByRole('button', {name: 'Delete member'}).click();
|
||||
await page.locator('button[data-test-button="confirm"] span:has-text("Delete member")').click();
|
||||
test('A member can be deleted', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
await sharedPage.locator('.gh-nav a[href="#/members/"]').click();
|
||||
await sharedPage.locator('tbody > tr > a').nth(0).click();
|
||||
await sharedPage.waitForSelector('[data-test-button="member-actions"]');
|
||||
await sharedPage.locator('[data-test-button="member-actions"]').click();
|
||||
await sharedPage.getByRole('button', {name: 'Delete member'}).click();
|
||||
await sharedPage.locator('button[data-test-button="confirm"] span:has-text("Delete member")').click();
|
||||
// should have no members now, so we should see the empty state
|
||||
expect(await page.locator('div h4:has-text("Start building your audience")')).not.toBeNull();
|
||||
expect(await sharedPage.locator('div h4:has-text("Start building your audience")')).not.toBeNull();
|
||||
});
|
||||
|
||||
const membersFixture = [
|
||||
|
@ -156,19 +156,19 @@ test.describe('Admin', () => {
|
|||
}
|
||||
];
|
||||
|
||||
test('All members can be exported', async ({page}) => {
|
||||
test('All members can be exported', async ({sharedPage}) => {
|
||||
// adds 6 members, 3 with the same label
|
||||
for (let member of membersFixture) {
|
||||
await createMember(page, member);
|
||||
await createMember(sharedPage, member);
|
||||
}
|
||||
await page.goto('/ghost');
|
||||
await page.locator('.gh-nav a[href="#/members/"]').click();
|
||||
await page.waitForSelector('button[data-test-button="members-actions"]');
|
||||
await page.locator('button[data-test-button="members-actions"]').click();
|
||||
await page.waitForSelector('button[data-test-button="export-members"]');
|
||||
await sharedPage.goto('/ghost');
|
||||
await sharedPage.locator('.gh-nav a[href="#/members/"]').click();
|
||||
await sharedPage.waitForSelector('button[data-test-button="members-actions"]');
|
||||
await sharedPage.locator('button[data-test-button="members-actions"]').click();
|
||||
await sharedPage.waitForSelector('button[data-test-button="export-members"]');
|
||||
const [download] = await Promise.all([
|
||||
page.waitForEvent('download'),
|
||||
page.locator('button[data-test-button="export-members"]').click()
|
||||
sharedPage.waitForEvent('download'),
|
||||
sharedPage.locator('button[data-test-button="export-members"]').click()
|
||||
]);
|
||||
const filename = await download.suggestedFilename();
|
||||
expect(filename).toContain('.csv');
|
||||
|
@ -192,26 +192,26 @@ test.describe('Admin', () => {
|
|||
expect(csvContents).toMatch(csvRegex);
|
||||
});
|
||||
|
||||
test('A filtered list of members can be exported', async ({page}) => {
|
||||
await page.goto('/ghost');
|
||||
await page.locator('.gh-nav a[href="#/members/"]').click();
|
||||
await page.waitForSelector('button[data-test-button="members-actions"]');
|
||||
await page.locator('button[data-test-button="members-actions"]').click();
|
||||
await page.waitForSelector('div[data-test-button="members-filter-actions"]');
|
||||
await page.locator('div[data-test-button="members-filter-actions"]').click();
|
||||
await page.locator('select[data-test-select="members-filter"]').click();
|
||||
await page.locator('select[data-test-select="members-filter"]').selectOption('label');
|
||||
await page.locator('div[data-test-members-filter="0"] > div > div').click();
|
||||
await page.locator('span[data-test-label-filter="dog"]').click();
|
||||
await page.keyboard.press('Tab');
|
||||
await page.locator('button[data-test-button="members-apply-filter"]').click();
|
||||
await page.locator('button[data-test-button="members-actions"]').click();
|
||||
const exportButton = await page.locator('button[data-test-button="export-members"] > span').innerText();
|
||||
test('A filtered list of members can be exported', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
await sharedPage.locator('.gh-nav a[href="#/members/"]').click();
|
||||
await sharedPage.waitForSelector('button[data-test-button="members-actions"]');
|
||||
await sharedPage.locator('button[data-test-button="members-actions"]').click();
|
||||
await sharedPage.waitForSelector('div[data-test-button="members-filter-actions"]');
|
||||
await sharedPage.locator('div[data-test-button="members-filter-actions"]').click();
|
||||
await sharedPage.locator('select[data-test-select="members-filter"]').click();
|
||||
await sharedPage.locator('select[data-test-select="members-filter"]').selectOption('label');
|
||||
await sharedPage.locator('div[data-test-members-filter="0"] > div > div').click();
|
||||
await sharedPage.locator('span[data-test-label-filter="dog"]').click();
|
||||
await sharedPage.keyboard.press('Tab');
|
||||
await sharedPage.locator('button[data-test-button="members-apply-filter"]').click();
|
||||
await sharedPage.locator('button[data-test-button="members-actions"]').click();
|
||||
const exportButton = await sharedPage.locator('button[data-test-button="export-members"] > span').innerText();
|
||||
expect(exportButton).toEqual('Export selected members (3)');
|
||||
await page.waitForSelector('button[data-test-button="export-members"]');
|
||||
await sharedPage.waitForSelector('button[data-test-button="export-members"]');
|
||||
const [download] = await Promise.all([
|
||||
page.waitForEvent('download'),
|
||||
page.locator('button[data-test-button="export-members"]').click()
|
||||
sharedPage.waitForEvent('download'),
|
||||
sharedPage.locator('button[data-test-button="export-members"]').click()
|
||||
]);
|
||||
const filename = await download.suggestedFilename();
|
||||
expect(filename).toContain('.csv');
|
||||
|
@ -241,50 +241,50 @@ test.describe('Admin', () => {
|
|||
// saves time by going directly to the members page with the label filter applied
|
||||
let labelFilterUrl;
|
||||
|
||||
test('A filtered list of members can have a label added to them', async ({page}) => {
|
||||
await page.goto('/ghost');
|
||||
await page.locator('.gh-nav a[href="#/members/"]').click();
|
||||
await page.waitForSelector('button[data-test-button="members-actions"]');
|
||||
await page.locator('button[data-test-button="members-actions"]').click();
|
||||
await page.waitForSelector('div[data-test-button="members-filter-actions"]');
|
||||
await page.locator('div[data-test-button="members-filter-actions"]').click();
|
||||
await page.locator('select[data-test-select="members-filter"]').click();
|
||||
await page.locator('select[data-test-select="members-filter"]').selectOption('label');
|
||||
await page.locator('div[data-test-members-filter="0"] > div > div').click();
|
||||
await page.locator('span[data-test-label-filter="old"]').click(); // this label should only be on 3 members
|
||||
await page.keyboard.press('Tab');
|
||||
await page.locator('button[data-test-button="members-apply-filter"]').click();
|
||||
await page.waitForSelector('button[data-test-button="members-actions"]');
|
||||
await page.locator('button[data-test-button="members-actions"]').click();
|
||||
await page.locator('button[data-test-button="add-label-selected"]').click();
|
||||
await page.locator('div[data-test-state="add-label-unconfirmed"] > span > select').selectOption({label: 'Test Label'});
|
||||
const members = await page.locator('div[data-test-state="add-label-unconfirmed"] > p > span[data-test-text="member-count"]').innerText();
|
||||
test('A filtered list of members can have a label added to them', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
await sharedPage.locator('.gh-nav a[href="#/members/"]').click();
|
||||
await sharedPage.waitForSelector('button[data-test-button="members-actions"]');
|
||||
await sharedPage.locator('button[data-test-button="members-actions"]').click();
|
||||
await sharedPage.waitForSelector('div[data-test-button="members-filter-actions"]');
|
||||
await sharedPage.locator('div[data-test-button="members-filter-actions"]').click();
|
||||
await sharedPage.locator('select[data-test-select="members-filter"]').click();
|
||||
await sharedPage.locator('select[data-test-select="members-filter"]').selectOption('label');
|
||||
await sharedPage.locator('div[data-test-members-filter="0"] > div > div').click();
|
||||
await sharedPage.locator('span[data-test-label-filter="old"]').click(); // this label should only be on 3 members
|
||||
await sharedPage.keyboard.press('Tab');
|
||||
await sharedPage.locator('button[data-test-button="members-apply-filter"]').click();
|
||||
await sharedPage.waitForSelector('button[data-test-button="members-actions"]');
|
||||
await sharedPage.locator('button[data-test-button="members-actions"]').click();
|
||||
await sharedPage.locator('button[data-test-button="add-label-selected"]').click();
|
||||
await sharedPage.locator('div[data-test-state="add-label-unconfirmed"] > span > select').selectOption({label: 'Test Label'});
|
||||
const members = await sharedPage.locator('div[data-test-state="add-label-unconfirmed"] > p > span[data-test-text="member-count"]').innerText();
|
||||
expect(members).toEqual('3 members');
|
||||
await page.locator('button[data-test-button="confirm"]').click();
|
||||
await page.waitForSelector('div[data-test-state="add-complete"]');
|
||||
const success = await page.locator('div[data-test-state="add-complete"] > div > p').innerText();
|
||||
await sharedPage.locator('button[data-test-button="confirm"]').click();
|
||||
await sharedPage.waitForSelector('div[data-test-state="add-complete"]');
|
||||
const success = await sharedPage.locator('div[data-test-state="add-complete"] > div > p').innerText();
|
||||
expect(success).toEqual('Label added to 3 members successfully');
|
||||
labelFilterUrl = await page.url();
|
||||
labelFilterUrl = await sharedPage.url();
|
||||
});
|
||||
|
||||
test('A filtered list of members can have a label removed from them', async ({page}) => {
|
||||
await page.goto(labelFilterUrl);
|
||||
await page.waitForSelector('button[data-test-button="members-actions"]');
|
||||
await page.locator('button[data-test-button="members-actions"]').click();
|
||||
await page.waitForSelector('button[data-test-button="remove-label-selected"]');
|
||||
await page.locator('button[data-test-button="remove-label-selected"]').click();
|
||||
await page.locator('div[data-test-state="remove-label-unconfirmed"] > span > select').selectOption({label: 'old'});
|
||||
await page.locator('button[data-test-button="confirm"]').click();
|
||||
const success = await page.locator('div[data-test-state="remove-complete"] > div > p').innerText();
|
||||
test('A filtered list of members can have a label removed from them', async ({sharedPage}) => {
|
||||
await sharedPage.goto(labelFilterUrl);
|
||||
await sharedPage.waitForSelector('button[data-test-button="members-actions"]');
|
||||
await sharedPage.locator('button[data-test-button="members-actions"]').click();
|
||||
await sharedPage.waitForSelector('button[data-test-button="remove-label-selected"]');
|
||||
await sharedPage.locator('button[data-test-button="remove-label-selected"]').click();
|
||||
await sharedPage.locator('div[data-test-state="remove-label-unconfirmed"] > span > select').selectOption({label: 'old'});
|
||||
await sharedPage.locator('button[data-test-button="confirm"]').click();
|
||||
const success = await sharedPage.locator('div[data-test-state="remove-complete"] > div > p').innerText();
|
||||
expect(success).toEqual('Label removed from 3 members successfully');
|
||||
});
|
||||
|
||||
test('A member can be granted a comp in admin', async ({page}) => {
|
||||
await page.goto('/ghost');
|
||||
await deleteAllMembers(page);
|
||||
test('A member can be granted a comp in admin', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
await deleteAllMembers(sharedPage);
|
||||
|
||||
// create a new member with a comped plan
|
||||
await createMember(page, {
|
||||
await createMember(sharedPage, {
|
||||
name: 'Test Member 1',
|
||||
email: 'test@member1.com',
|
||||
note: 'This is a test member',
|
||||
|
@ -293,54 +293,54 @@ test.describe('Admin', () => {
|
|||
});
|
||||
|
||||
// open the impersonate modal
|
||||
await page.locator('[data-test-button="member-actions"]').click();
|
||||
await page.getByRole('button', {name: 'Impersonate'}).click();
|
||||
await page.getByRole('button', {name: 'Copy link'}).click();
|
||||
await page.waitForSelector('button span:has-text("Link copied")');
|
||||
await sharedPage.locator('[data-test-button="member-actions"]').click();
|
||||
await sharedPage.getByRole('button', {name: 'Impersonate'}).click();
|
||||
await sharedPage.getByRole('button', {name: 'Copy link'}).click();
|
||||
await sharedPage.waitForSelector('button span:has-text("Link copied")');
|
||||
|
||||
// get value from input because we don't have access to the clipboard during headless testing
|
||||
const elem = await page.$('input[name="member-signin-url"]');
|
||||
const elem = await sharedPage.$('input[name="member-signin-url"]');
|
||||
const link = await elem.inputValue();
|
||||
|
||||
// go to the frontend with the impersonate link
|
||||
await page.goto(link);
|
||||
await sharedPage.goto(link);
|
||||
|
||||
// click the paid-only post
|
||||
await page.locator('.gh-card-link[href="/sell/"]').click();
|
||||
await sharedPage.locator('.gh-card-link[href="/sell/"]').click();
|
||||
|
||||
// check for content CTA and expect it to be zero
|
||||
await expect(page.locator('.gh-post-upgrade-cta')).toHaveCount(0);
|
||||
await expect(sharedPage.locator('.gh-post-upgrade-cta')).toHaveCount(0);
|
||||
});
|
||||
|
||||
test('An existing member cannot be saved with invalid email address', async ({page}) => {
|
||||
await page.goto('/ghost');
|
||||
await page.locator('.gh-nav a[href="#/members/"]').click();
|
||||
await page.waitForSelector('a[href="#/members/new/"] span');
|
||||
await page.locator('a[href="#/members/new/"] span:has-text("New member")').click();
|
||||
await page.waitForSelector('input[name="name"]');
|
||||
test('An existing member cannot be saved with invalid email address', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
await sharedPage.locator('.gh-nav a[href="#/members/"]').click();
|
||||
await sharedPage.waitForSelector('a[href="#/members/new/"] span');
|
||||
await sharedPage.locator('a[href="#/members/new/"] span:has-text("New member")').click();
|
||||
await sharedPage.waitForSelector('input[name="name"]');
|
||||
let name = 'Test Member';
|
||||
let email = 'tester+invalid@example.com';
|
||||
let note = 'This is a test member';
|
||||
let label = 'Test Label';
|
||||
await page.fill('input[name="name"]', name);
|
||||
await page.fill('input[name="email"]', email);
|
||||
await page.fill('textarea[name="note"]', note);
|
||||
await page.locator('label:has-text("Labels") + div').click();
|
||||
await page.keyboard.type(label);
|
||||
await page.keyboard.press('Tab');
|
||||
await page.locator('button span:has-text("Save")').click();
|
||||
await page.waitForSelector('button span:has-text("Saved")');
|
||||
await sharedPage.fill('input[name="name"]', name);
|
||||
await sharedPage.fill('input[name="email"]', email);
|
||||
await sharedPage.fill('textarea[name="note"]', note);
|
||||
await sharedPage.locator('label:has-text("Labels") + div').click();
|
||||
await sharedPage.keyboard.type(label);
|
||||
await sharedPage.keyboard.press('Tab');
|
||||
await sharedPage.locator('button span:has-text("Save")').click();
|
||||
await sharedPage.waitForSelector('button span:has-text("Saved")');
|
||||
|
||||
// Update email to invalid and try saving
|
||||
let updatedEmail = 'tester+invalid@example.com<6F>';
|
||||
await page.fill('input[name="email"]', updatedEmail);
|
||||
await page.waitForSelector('button span:has-text("Save")');
|
||||
await page.locator('button span:has-text("Save")').click();
|
||||
await page.waitForSelector('button span:has-text("Retry")');
|
||||
await sharedPage.fill('input[name="email"]', updatedEmail);
|
||||
await sharedPage.waitForSelector('button span:has-text("Save")');
|
||||
await sharedPage.locator('button span:has-text("Save")').click();
|
||||
await sharedPage.waitForSelector('button span:has-text("Retry")');
|
||||
|
||||
// check we are unable to save member with invalid email
|
||||
await expect(page.locator('button span:has-text("Retry")')).toBeVisible();
|
||||
await expect(page.locator('text=Invalid Email')).toBeVisible();
|
||||
await expect(sharedPage.locator('button span:has-text("Retry")')).toBeVisible();
|
||||
await expect(sharedPage.locator('text=Invalid Email')).toBeVisible();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,25 +4,25 @@ const {disconnectStripe, setupStripe, generateStripeIntegrationToken, getStripeA
|
|||
|
||||
test.describe('Membership Settings', () => {
|
||||
test.describe('Portal settings', () => {
|
||||
test('Shows free tier toggle when stripe is disconnected', async ({page}) => {
|
||||
await page.goto('/ghost');
|
||||
test('Shows free tier toggle when stripe is disconnected', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
// Disconnect stripe
|
||||
await disconnectStripe(page);
|
||||
await disconnectStripe(sharedPage);
|
||||
|
||||
// Open Portal settings
|
||||
await page.goto('/ghost');
|
||||
await page.locator('.gh-nav a[href="#/settings/"]').click();
|
||||
await page.getByTestId('portal').getByRole('button', {name: 'Customize'}).click();
|
||||
await sharedPage.goto('/ghost');
|
||||
await sharedPage.locator('.gh-nav a[href="#/settings/"]').click();
|
||||
await sharedPage.getByTestId('portal').getByRole('button', {name: 'Customize'}).click();
|
||||
|
||||
const modal = page.getByTestId('portal-modal');
|
||||
const modal = sharedPage.getByTestId('portal-modal');
|
||||
// Check free tier toggle is visible
|
||||
await expect(modal.locator('label').filter({hasText: 'Free'}).first()).toBeVisible();
|
||||
|
||||
// Reconnect Stripe for other tests
|
||||
const stripeAccountId = await getStripeAccountId();
|
||||
const stripeToken = await generateStripeIntegrationToken(stripeAccountId);
|
||||
await page.goto('/ghost');
|
||||
await setupStripe(page, stripeToken);
|
||||
await sharedPage.goto('/ghost');
|
||||
await setupStripe(sharedPage, stripeToken);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,41 +3,41 @@ const test = require('../fixtures/ghost-test');
|
|||
|
||||
test.describe('Portal Settings', () => {
|
||||
test.describe('Links', () => {
|
||||
const openPortalLinks = async (page) => {
|
||||
await page.goto('/ghost');
|
||||
await page.locator('[data-test-nav="settings"]').click();
|
||||
const openPortalLinks = async (sharedPage) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
await sharedPage.locator('[data-test-nav="settings"]').click();
|
||||
|
||||
await page.getByTestId('portal').getByRole('button', {name: 'Customize'}).click();
|
||||
await sharedPage.getByTestId('portal').getByRole('button', {name: 'Customize'}).click();
|
||||
|
||||
const modal = page.getByTestId('portal-modal');
|
||||
const modal = sharedPage.getByTestId('portal-modal');
|
||||
|
||||
await modal.getByRole('tab', {name: 'Links'}).click();
|
||||
|
||||
return modal;
|
||||
};
|
||||
|
||||
test('can open portal on default page', async ({page}) => {
|
||||
const modal = await openPortalLinks(page);
|
||||
test('can open portal on default page', async ({sharedPage}) => {
|
||||
const modal = await openPortalLinks(sharedPage);
|
||||
|
||||
// fetch portal default url from input
|
||||
const portalUrl = await modal.getByLabel('Default').inputValue();
|
||||
await page.goto(portalUrl);
|
||||
await sharedPage.goto(portalUrl);
|
||||
|
||||
const portalFrame = page.locator('[data-testid="portal-popup-frame"]');
|
||||
const portalFrame = sharedPage.locator('[data-testid="portal-popup-frame"]');
|
||||
|
||||
// check portal popup is opened
|
||||
await expect(portalFrame).toBeVisible();
|
||||
});
|
||||
|
||||
test('can open portal on signin page', async ({page}) => {
|
||||
const modal = await openPortalLinks(page);
|
||||
test('can open portal on signin page', async ({sharedPage}) => {
|
||||
const modal = await openPortalLinks(sharedPage);
|
||||
|
||||
// fetch portal signin url from input
|
||||
const portalUrl = await modal.getByLabel('Sign in').inputValue();
|
||||
await page.goto(portalUrl);
|
||||
await sharedPage.goto(portalUrl);
|
||||
|
||||
const portalFrame = page.locator('[data-testid="portal-popup-frame"]');
|
||||
const portalFrameLocator = page.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
const portalFrame = sharedPage.locator('[data-testid="portal-popup-frame"]');
|
||||
const portalFrameLocator = sharedPage.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
|
||||
// check portal popup is opened
|
||||
await expect(portalFrame).toBeVisible();
|
||||
|
@ -45,15 +45,15 @@ test.describe('Portal Settings', () => {
|
|||
await expect(portalFrameLocator.getByRole('heading', {name: 'Sign in'})).toBeVisible();
|
||||
});
|
||||
|
||||
test('can open portal on signup page', async ({page}) => {
|
||||
const modal = await openPortalLinks(page);
|
||||
test('can open portal on signup page', async ({sharedPage}) => {
|
||||
const modal = await openPortalLinks(sharedPage);
|
||||
|
||||
// fetch portal signup url from input
|
||||
const portalUrl = await modal.getByLabel('Sign up').inputValue();
|
||||
await page.goto(portalUrl);
|
||||
await sharedPage.goto(portalUrl);
|
||||
|
||||
const portalFrame = page.locator('[data-testid="portal-popup-frame"]');
|
||||
const portalFrameLocator = page.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
const portalFrame = sharedPage.locator('[data-testid="portal-popup-frame"]');
|
||||
const portalFrameLocator = sharedPage.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
|
||||
// check portal popup is opened
|
||||
await expect(portalFrame).toBeVisible();
|
||||
|
@ -61,26 +61,26 @@ test.describe('Portal Settings', () => {
|
|||
await expect(portalFrameLocator.locator('.gh-portal-signup')).toBeVisible();
|
||||
});
|
||||
|
||||
test('can open portal directly on monthly signup', async ({page}) => {
|
||||
const modal = await openPortalLinks(page);
|
||||
test('can open portal directly on monthly signup', async ({sharedPage}) => {
|
||||
const modal = await openPortalLinks(sharedPage);
|
||||
|
||||
// fetch and go to portal directly monthly signup url
|
||||
const portalUrl = await modal.getByLabel('Signup / Monthly').inputValue();
|
||||
await page.goto(portalUrl);
|
||||
await sharedPage.goto(portalUrl);
|
||||
|
||||
// expect stripe checkout to have opeened
|
||||
await page.waitForURL(/^https:\/\/checkout.stripe.com/);
|
||||
await sharedPage.waitForURL(/^https:\/\/checkout.stripe.com/);
|
||||
});
|
||||
|
||||
test('can open portal directly on yearly signup', async ({page}) => {
|
||||
const modal = await openPortalLinks(page);
|
||||
test('can open portal directly on yearly signup', async ({sharedPage}) => {
|
||||
const modal = await openPortalLinks(sharedPage);
|
||||
|
||||
// fetch and go to portal directly yearly signup url
|
||||
const portalUrl = await modal.getByLabel('Signup / Yearly').inputValue();
|
||||
await page.goto(portalUrl);
|
||||
await sharedPage.goto(portalUrl);
|
||||
|
||||
// expect stripe checkout to have opeened
|
||||
await page.waitForURL(/^https:\/\/checkout.stripe.com/);
|
||||
await sharedPage.waitForURL(/^https:\/\/checkout.stripe.com/);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,12 +3,12 @@ const test = require('../fixtures/ghost-test');
|
|||
|
||||
test.describe('Admin', () => {
|
||||
test.describe('Posts', () => {
|
||||
test('Has a set of posts', async ({page}) => {
|
||||
await page.goto('/ghost');
|
||||
await page.locator('.gh-nav a[href="#/posts/"]').click();
|
||||
await page.locator('.gh-post-list-title').first().click();
|
||||
await page.locator('.settings-menu-toggle').click();
|
||||
await expect(page.getByPlaceholder('YYYY-MM-DD')).toHaveValue(/[0-9]{4}-[0-9]{2}-[0-9]{2}/);
|
||||
test('Has a set of posts', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
await sharedPage.locator('.gh-nav a[href="#/posts/"]').click();
|
||||
await sharedPage.locator('.gh-post-list-title').first().click();
|
||||
await sharedPage.locator('.settings-menu-toggle').click();
|
||||
await expect(sharedPage.getByPlaceholder('YYYY-MM-DD')).toHaveValue(/[0-9]{4}-[0-9]{2}-[0-9]{2}/);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,13 +3,13 @@ const test = require('../fixtures/ghost-test');
|
|||
|
||||
test.describe('Site Settings', () => {
|
||||
test.describe('Privacy setting', () => {
|
||||
test('A site set to private should require a password to access it', async ({page, browser}) => {
|
||||
test('A site set to private should require a password to access it', async ({sharedPage, browser}) => {
|
||||
// set private mode in admin "on"
|
||||
await page.goto('/ghost');
|
||||
await sharedPage.goto('/ghost');
|
||||
|
||||
await page.locator('[data-test-nav="settings"]').click();
|
||||
await sharedPage.locator('[data-test-nav="settings"]').click();
|
||||
|
||||
const section = page.getByTestId('locksite');
|
||||
const section = sharedPage.getByTestId('locksite');
|
||||
|
||||
await section.getByRole('button', {name: 'Edit'}).click();
|
||||
|
||||
|
|
|
@ -135,7 +135,7 @@ const publishPost = async (page, {type = 'publish', time, date} = {}) => {
|
|||
|
||||
// set the publish type
|
||||
if (type) {
|
||||
// Type is nullable because Pages don't have a publish type button
|
||||
// Type is nullable because pages don't have a publish type button
|
||||
await page.locator('[data-test-setting="publish-type"] > button').click();
|
||||
await page.locator(`[data-test-publish-type="${type}"] + label`).click({timeout: 1000}); // If this times out, it is likely that there are no members (running a single test).
|
||||
}
|
||||
|
@ -185,109 +185,109 @@ const openPublishedPostBookmark = async (page) => {
|
|||
test.describe('Publishing', () => {
|
||||
test.describe('Publish post', () => {
|
||||
// Post should be available on web and sent as a newsletter
|
||||
test('Publish and Email', async ({page}) => {
|
||||
test('Publish and Email', async ({sharedPage}) => {
|
||||
const postData = {
|
||||
title: 'Publish and email post',
|
||||
body: 'This is my post body.'
|
||||
};
|
||||
|
||||
// Create a member to send and email to
|
||||
await createMember(page, {email: 'test+recipient1@example.com', name: 'Publishing member'});
|
||||
await createMember(sharedPage, {email: 'test+recipient1@example.com', name: 'Publishing member'});
|
||||
|
||||
await page.goto('/ghost');
|
||||
await createPostDraft(page, postData);
|
||||
await publishPost(page, {type: 'publish+send'});
|
||||
await closePublishFlow(page);
|
||||
await sharedPage.goto('/ghost');
|
||||
await createPostDraft(sharedPage, postData);
|
||||
await publishPost(sharedPage, {type: 'publish+send'});
|
||||
await closePublishFlow(sharedPage);
|
||||
|
||||
await checkPostStatus(page, 'Published');
|
||||
await checkPostPublished(page, postData);
|
||||
await checkPostStatus(sharedPage, 'Published');
|
||||
await checkPostPublished(sharedPage, postData);
|
||||
});
|
||||
|
||||
// Post should only be available on web
|
||||
test('Publish only', async ({page}) => {
|
||||
test('Publish only', async ({sharedPage}) => {
|
||||
const postData = {
|
||||
title: 'Publish post only',
|
||||
body: 'This is my post body.'
|
||||
};
|
||||
|
||||
await page.goto('/ghost');
|
||||
await createPostDraft(page, postData);
|
||||
await publishPost(page);
|
||||
await closePublishFlow(page);
|
||||
await sharedPage.goto('/ghost');
|
||||
await createPostDraft(sharedPage, postData);
|
||||
await publishPost(sharedPage);
|
||||
await closePublishFlow(sharedPage);
|
||||
|
||||
await checkPostStatus(page, 'Published');
|
||||
await checkPostPublished(page, postData);
|
||||
await checkPostStatus(sharedPage, 'Published');
|
||||
await checkPostPublished(sharedPage, postData);
|
||||
});
|
||||
|
||||
// Post should be available on web and sent as a newsletter
|
||||
test('Email only', async ({page}) => {
|
||||
test('Email only', async ({sharedPage}) => {
|
||||
const postData = {
|
||||
title: 'Email only post',
|
||||
body: 'This is my post body.'
|
||||
};
|
||||
|
||||
await createMember(page, {email: 'test+recipient2@example.com', name: 'Publishing member'});
|
||||
await createMember(sharedPage, {email: 'test+recipient2@example.com', name: 'Publishing member'});
|
||||
|
||||
await page.goto('/ghost');
|
||||
await createPostDraft(page, postData);
|
||||
await publishPost(page, {type: 'send'});
|
||||
await closePublishFlow(page);
|
||||
await checkPostStatus(page, 'Sent to '); // can't test for 1 member for now, because depends on test ordering :( (sometimes 2 members are created)
|
||||
await sharedPage.goto('/ghost');
|
||||
await createPostDraft(sharedPage, postData);
|
||||
await publishPost(sharedPage, {type: 'send'});
|
||||
await closePublishFlow(sharedPage);
|
||||
await checkPostStatus(sharedPage, 'Sent to '); // can't test for 1 member for now, because depends on test ordering :( (sometimes 2 members are created)
|
||||
|
||||
await checkPostNotPublished(page, postData);
|
||||
await checkPostNotPublished(sharedPage, postData);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Publish page', () => {
|
||||
// A page can be published and become visible on web
|
||||
test('Immediately', async ({page}) => {
|
||||
test('Immediately', async ({sharedPage}) => {
|
||||
const pageData = {
|
||||
// Title should be unique to avoid slug duplicates
|
||||
title: 'Published page test',
|
||||
body: 'This is my scheduled page body.'
|
||||
};
|
||||
|
||||
await page.goto('/ghost');
|
||||
await createPage(page, pageData);
|
||||
await publishPost(page, {type: null});
|
||||
await closePublishFlow(page);
|
||||
await checkPostStatus(page, 'Published');
|
||||
await sharedPage.goto('/ghost');
|
||||
await createPage(sharedPage, pageData);
|
||||
await publishPost(sharedPage, {type: null});
|
||||
await closePublishFlow(sharedPage);
|
||||
await checkPostStatus(sharedPage, 'Published');
|
||||
|
||||
// Check published
|
||||
await checkPostPublished(page, pageData);
|
||||
await checkPostPublished(sharedPage, pageData);
|
||||
});
|
||||
|
||||
// Page should be published at the scheduled time
|
||||
test('At the scheduled time', async ({page}) => {
|
||||
// page should be published at the scheduled time
|
||||
test('At the scheduled time', async ({sharedPage}) => {
|
||||
const pageData = {
|
||||
// Title should be unique to avoid slug duplicates
|
||||
title: 'Scheduled page test',
|
||||
body: 'This is my scheduled page body.'
|
||||
title: 'Scheduled sharedPage test',
|
||||
body: 'This is my scheduled sharedPage body.'
|
||||
};
|
||||
|
||||
await page.goto('/ghost');
|
||||
await createPage(page, pageData);
|
||||
await sharedPage.goto('/ghost');
|
||||
await createPage(sharedPage, pageData);
|
||||
|
||||
// Schedule the post to publish asap (by setting it to 00:00, it will get auto corrected to the minimum time possible - 5 seconds in the future)
|
||||
await publishPost(page, {time: '00:00', type: null});
|
||||
await closePublishFlow(page);
|
||||
await checkPostStatus(page, 'Scheduled', 'Scheduled to be published in a few seconds');
|
||||
await publishPost(sharedPage, {time: '00:00', type: null});
|
||||
await closePublishFlow(sharedPage);
|
||||
await checkPostStatus(sharedPage, 'Scheduled', 'Scheduled to be published in a few seconds');
|
||||
|
||||
// Go to the page and check if the status code is 404
|
||||
await checkPostNotPublished(page, pageData);
|
||||
await checkPostNotPublished(sharedPage, pageData);
|
||||
|
||||
// Now wait for 5 seconds
|
||||
await page.waitForTimeout(5000);
|
||||
await sharedPage.waitForTimeout(5000);
|
||||
|
||||
// Check again, now it should have been added to the page
|
||||
await checkPostPublished(page, pageData);
|
||||
await checkPostPublished(sharedPage, pageData);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Update post', () => {
|
||||
test.describe.configure({retries: 1});
|
||||
|
||||
test('Can update a published post', async ({page: adminPage}) => {
|
||||
test('Can update a published post', async ({sharedPage: adminPage}) => {
|
||||
await adminPage.goto('/ghost');
|
||||
|
||||
const date = DateTime.now();
|
||||
|
@ -328,148 +328,148 @@ test.describe('Publishing', () => {
|
|||
|
||||
test.describe('Schedule post', () => {
|
||||
// Post should be published to web and sent as a newsletter at the scheduled time
|
||||
test('Publish and Email', async ({page}) => {
|
||||
test('Publish and Email', async ({sharedPage}) => {
|
||||
const postData = {
|
||||
// This title should be unique
|
||||
title: 'Scheduled post publish+email test',
|
||||
body: 'This is my scheduled post body.'
|
||||
};
|
||||
|
||||
await createMember(page, {email: 'test+recipient3@example.com', name: 'Publishing member'});
|
||||
await createMember(sharedPage, {email: 'test+recipient3@example.com', name: 'Publishing member'});
|
||||
|
||||
await page.goto('/ghost');
|
||||
await createPostDraft(page, postData);
|
||||
await sharedPage.goto('/ghost');
|
||||
await createPostDraft(sharedPage, postData);
|
||||
|
||||
// Schedule the post to publish asap (by setting it to 00:00, it will get auto corrected to the minimum time possible - 5 seconds in the future)
|
||||
await publishPost(page, {time: '00:00', type: 'publish+send'});
|
||||
await closePublishFlow(page);
|
||||
await checkPostStatus(page, 'Scheduled', 'Scheduled to be published and sent'); // Member count can differ, hence not included here
|
||||
await checkPostStatus(page, 'Scheduled', 'in a few seconds'); // Extra test for suffix on hover
|
||||
const editorUrl = await page.url();
|
||||
await publishPost(sharedPage, {time: '00:00', type: 'publish+send'});
|
||||
await closePublishFlow(sharedPage);
|
||||
await checkPostStatus(sharedPage, 'Scheduled', 'Scheduled to be published and sent'); // Member count can differ, hence not included here
|
||||
await checkPostStatus(sharedPage, 'Scheduled', 'in a few seconds'); // Extra test for suffix on hover
|
||||
const editorUrl = await sharedPage.url();
|
||||
|
||||
// Go to the homepage and check if the post is not yet visible there
|
||||
await checkPostNotPublished(page, postData);
|
||||
await checkPostNotPublished(sharedPage, postData);
|
||||
|
||||
// Now wait 5 seconds for the scheduled post to be published
|
||||
await page.waitForTimeout(5000);
|
||||
await sharedPage.waitForTimeout(5000);
|
||||
|
||||
// Check again, now it should have been added to the page
|
||||
await checkPostPublished(page, postData);
|
||||
await checkPostPublished(sharedPage, postData);
|
||||
|
||||
// Check status
|
||||
await page.goto(editorUrl);
|
||||
await checkPostStatus(page, 'Published');
|
||||
await sharedPage.goto(editorUrl);
|
||||
await checkPostStatus(sharedPage, 'Published');
|
||||
});
|
||||
|
||||
// Post should be published to web only at the scheduled time
|
||||
test('Publish only', async ({page}) => {
|
||||
test('Publish only', async ({sharedPage}) => {
|
||||
const postData = {
|
||||
title: 'Scheduled post test',
|
||||
body: 'This is my scheduled post body.'
|
||||
};
|
||||
|
||||
await page.goto('/ghost');
|
||||
await createPostDraft(page, postData);
|
||||
await sharedPage.goto('/ghost');
|
||||
await createPostDraft(sharedPage, postData);
|
||||
|
||||
// Schedule the post to publish asap (by setting it to 00:00, it will get auto corrected to the minimum time possible - 5 seconds in the future)
|
||||
await publishPost(page, {time: '00:00'});
|
||||
await closePublishFlow(page);
|
||||
await checkPostStatus(page, 'Scheduled', 'Scheduled to be published in a few seconds');
|
||||
const editorUrl = await page.url();
|
||||
await publishPost(sharedPage, {time: '00:00'});
|
||||
await closePublishFlow(sharedPage);
|
||||
await checkPostStatus(sharedPage, 'Scheduled', 'Scheduled to be published in a few seconds');
|
||||
const editorUrl = await sharedPage.url();
|
||||
|
||||
// Check not published yet
|
||||
await checkPostNotPublished(page, postData);
|
||||
await checkPostNotPublished(sharedPage, postData);
|
||||
|
||||
// Now wait 5 seconds for the scheduled post to be published
|
||||
await page.waitForTimeout(5000);
|
||||
await sharedPage.waitForTimeout(5000);
|
||||
|
||||
// Check published
|
||||
await checkPostPublished(page, postData);
|
||||
await checkPostPublished(sharedPage, postData);
|
||||
|
||||
// Check status
|
||||
await page.goto(editorUrl);
|
||||
await checkPostStatus(page, 'Published');
|
||||
await sharedPage.goto(editorUrl);
|
||||
await checkPostStatus(sharedPage, 'Published');
|
||||
});
|
||||
|
||||
// Post should be published to web only at the scheduled time
|
||||
test('Email only', async ({page}) => {
|
||||
test('Email only', async ({sharedPage}) => {
|
||||
const postData = {
|
||||
title: 'Scheduled email only test',
|
||||
body: 'This is my scheduled post body.'
|
||||
};
|
||||
|
||||
await createMember(page, {email: 'test+recipient4@example.com', name: 'Publishing member'});
|
||||
await createMember(sharedPage, {email: 'test+recipient4@example.com', name: 'Publishing member'});
|
||||
|
||||
await page.goto('/ghost');
|
||||
await createPostDraft(page, postData);
|
||||
await sharedPage.goto('/ghost');
|
||||
await createPostDraft(sharedPage, postData);
|
||||
|
||||
// Schedule the post to publish asap (by setting it to 00:00, it will get auto corrected to the minimum time possible - 5 seconds in the future)
|
||||
await publishPost(page, {type: 'send', time: '00:00'});
|
||||
await closePublishFlow(page);
|
||||
await checkPostStatus(page, 'Scheduled', 'Scheduled to be sent to');
|
||||
const editorUrl = await page.url();
|
||||
await publishPost(sharedPage, {type: 'send', time: '00:00'});
|
||||
await closePublishFlow(sharedPage);
|
||||
await checkPostStatus(sharedPage, 'Scheduled', 'Scheduled to be sent to');
|
||||
const editorUrl = await sharedPage.url();
|
||||
|
||||
// Check not published yet
|
||||
await checkPostNotPublished(page, postData);
|
||||
await checkPostNotPublished(sharedPage, postData);
|
||||
|
||||
// Now wait 5 seconds for the scheduled post to be published
|
||||
await page.waitForTimeout(5000);
|
||||
await sharedPage.waitForTimeout(5000);
|
||||
|
||||
// Check status
|
||||
await page.goto(editorUrl);
|
||||
await checkPostStatus(page, 'Sent', 'Sent to');
|
||||
await sharedPage.goto(editorUrl);
|
||||
await checkPostStatus(sharedPage, 'Sent', 'Sent to');
|
||||
|
||||
// Stil not published yet (email only)
|
||||
await checkPostNotPublished(page, postData);
|
||||
await checkPostNotPublished(sharedPage, postData);
|
||||
});
|
||||
|
||||
// A previously scheduled post can be unscheduled, which resets it to a draft
|
||||
test('A scheduled post should be able to be unscheduled', async ({page, context}) => {
|
||||
test('A scheduled post should be able to be unscheduled', async ({sharedPage, context}) => {
|
||||
const postData = {
|
||||
title: 'Unschedule post test',
|
||||
body: 'This is my unscheduled post body.'
|
||||
};
|
||||
|
||||
await page.goto('/ghost');
|
||||
await createPostDraft(page, postData);
|
||||
await sharedPage.goto('/ghost');
|
||||
await createPostDraft(sharedPage, postData);
|
||||
|
||||
// Schedule far in the future
|
||||
await publishPost(page, {date: '2050-01-01', time: '10:09'});
|
||||
await closePublishFlow(page);
|
||||
await publishPost(sharedPage, {date: '2050-01-01', time: '10:09'});
|
||||
await closePublishFlow(sharedPage);
|
||||
|
||||
// Check status
|
||||
await checkPostStatus(page, 'Scheduled', 'Scheduled to be published at 10:09 (UTC) on 01 Jan 2050');
|
||||
await checkPostStatus(sharedPage, 'Scheduled', 'Scheduled to be published at 10:09 (UTC) on 01 Jan 2050');
|
||||
|
||||
// Check not published
|
||||
const testPage = await context.newPage();
|
||||
const testsharedPage = await context.newPage();
|
||||
|
||||
// Check not published
|
||||
await checkPostNotPublished(testPage, postData);
|
||||
await checkPostNotPublished(testsharedPage, postData);
|
||||
|
||||
// Now unschedule this post
|
||||
await page.locator('[data-test-button="update-flow"]').click();
|
||||
await page.locator('[data-test-button="revert-to-draft"]').click();
|
||||
await sharedPage.locator('[data-test-button="update-flow"]').click();
|
||||
await sharedPage.locator('[data-test-button="revert-to-draft"]').click();
|
||||
|
||||
// Check status
|
||||
await checkPostStatus(page, 'Draft - Saved');
|
||||
await checkPostStatus(sharedPage, 'Draft - Saved');
|
||||
|
||||
// Check not published
|
||||
await checkPostNotPublished(testPage, postData);
|
||||
await checkPostNotPublished(testsharedPage, postData);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Updating post access', () => {
|
||||
test.describe('Change post visibility to members-only', () => {
|
||||
test('Only logged-in members (free or paid) can see', async ({page}) => {
|
||||
await page.goto('/ghost');
|
||||
test('Only logged-in members (free or paid) can see', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
|
||||
await createPostDraft(page);
|
||||
await openPostSettingsMenu(page);
|
||||
await setPostVisibility(page, 'members');
|
||||
await createPostDraft(sharedPage);
|
||||
await openPostSettingsMenu(sharedPage);
|
||||
await setPostVisibility(sharedPage, 'members');
|
||||
|
||||
await publishPost(page);
|
||||
const frontendPage = await openPublishedPostBookmark(page);
|
||||
await publishPost(sharedPage);
|
||||
const frontendPage = await openPublishedPostBookmark(sharedPage);
|
||||
|
||||
// Check if content gate for members is present on front-end
|
||||
await expect(frontendPage.locator('.gh-post-upgrade-cta-content h2')).toHaveText('This post is for subscribers only');
|
||||
|
@ -477,15 +477,15 @@ test.describe('Updating post access', () => {
|
|||
});
|
||||
|
||||
test.describe('Change post visibility to paid-members-only', () => {
|
||||
test('Only logged-in, paid members can see', async ({page}) => {
|
||||
await page.goto('/ghost');
|
||||
test('Only logged-in, paid members can see', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
|
||||
await createPostDraft(page);
|
||||
await openPostSettingsMenu(page);
|
||||
await setPostVisibility(page, 'paid');
|
||||
await createPostDraft(sharedPage);
|
||||
await openPostSettingsMenu(sharedPage);
|
||||
await setPostVisibility(sharedPage, 'paid');
|
||||
|
||||
await publishPost(page);
|
||||
const frontendPage = await openPublishedPostBookmark(page);
|
||||
await publishPost(sharedPage);
|
||||
const frontendPage = await openPublishedPostBookmark(sharedPage);
|
||||
|
||||
// Check if content gate for paid members is present on front-end
|
||||
await expect(frontendPage.locator('.gh-post-upgrade-cta-content h2')).toHaveText('This post is for paying subscribers only');
|
||||
|
@ -493,68 +493,68 @@ test.describe('Updating post access', () => {
|
|||
});
|
||||
|
||||
test.describe('Change post visibility to public', () => {
|
||||
test('Everyone can see', async ({page}) => {
|
||||
await page.goto('/ghost');
|
||||
test('Everyone can see', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
|
||||
await createPostDraft(page);
|
||||
await openPostSettingsMenu(page);
|
||||
await setPostVisibility(page, 'public');
|
||||
await createPostDraft(sharedPage);
|
||||
await openPostSettingsMenu(sharedPage);
|
||||
await setPostVisibility(sharedPage, 'public');
|
||||
|
||||
await publishPost(page);
|
||||
const frontendPage = await openPublishedPostBookmark(page);
|
||||
await publishPost(sharedPage);
|
||||
const frontendPage = await openPublishedPostBookmark(sharedPage);
|
||||
|
||||
// Check if post content is publicly visible on front-end
|
||||
await expect(frontendPage.locator('.gh-content.gh-canvas > p')).toHaveText('This is my post body.');
|
||||
});
|
||||
});
|
||||
|
||||
test('specific tiers', async ({page}) => {
|
||||
await page.goto('/ghost');
|
||||
test('specific tiers', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
|
||||
// tiers and members are needed to test the access levels
|
||||
await createTier(page, {name: 'Silver', monthlyPrice: 5, yearlyPrice: 50});
|
||||
await createTier(page, {name: 'Gold', monthlyPrice: 10, yearlyPrice: 100});
|
||||
await createMember(page, {email: 'silver@example.com', compedPlan: 'Silver'});
|
||||
const silverMember = await page.url();
|
||||
await createMember(page, {email: 'gold@example.com', compedPlan: 'Gold'});
|
||||
const goldMember = await page.url();
|
||||
await createTier(sharedPage, {name: 'Silver', monthlyPrice: 5, yearlyPrice: 50});
|
||||
await createTier(sharedPage, {name: 'Gold', monthlyPrice: 10, yearlyPrice: 100});
|
||||
await createMember(sharedPage, {email: 'silver@example.com', compedPlan: 'Silver'});
|
||||
const silverMember = await sharedPage.url();
|
||||
await createMember(sharedPage, {email: 'gold@example.com', compedPlan: 'Gold'});
|
||||
const goldMember = await sharedPage.url();
|
||||
|
||||
await createPostDraft(page, {body: 'Only gold members can see this'});
|
||||
await createPostDraft(sharedPage, {body: 'Only gold members can see this'});
|
||||
|
||||
await openPostSettingsMenu(page);
|
||||
await setPostVisibility(page, 'tiers');
|
||||
await openPostSettingsMenu(sharedPage);
|
||||
await setPostVisibility(sharedPage, 'tiers');
|
||||
|
||||
// backspace removes existing tiers
|
||||
await expect(page.locator('[data-test-visibility-segment-select] [data-test-selected-token]')).toHaveCount(3);
|
||||
await page.locator('[data-test-visibility-segment-select] input').click();
|
||||
await page.keyboard.press('Backspace');
|
||||
await page.waitForTimeout(50);
|
||||
await page.keyboard.press('Backspace');
|
||||
await page.waitForTimeout(50);
|
||||
await page.keyboard.press('Backspace');
|
||||
await expect(page.locator('[data-test-visibility-segment-select] [data-test-selected-token]')).toHaveCount(0);
|
||||
await expect(sharedPage.locator('[data-test-visibility-segment-select] [data-test-selected-token]')).toHaveCount(3);
|
||||
await sharedPage.locator('[data-test-visibility-segment-select] input').click();
|
||||
await sharedPage.keyboard.press('Backspace');
|
||||
await sharedPage.waitForTimeout(50);
|
||||
await sharedPage.keyboard.press('Backspace');
|
||||
await sharedPage.waitForTimeout(50);
|
||||
await sharedPage.keyboard.press('Backspace');
|
||||
await expect(sharedPage.locator('[data-test-visibility-segment-select] [data-test-selected-token]')).toHaveCount(0);
|
||||
|
||||
// specific tier can be added back on
|
||||
await page.keyboard.type('Go');
|
||||
const goldOption = page.locator('[data-test-visibility-segment-option="Gold"]');
|
||||
await sharedPage.keyboard.type('Go');
|
||||
const goldOption = sharedPage.locator('[data-test-visibility-segment-option="Gold"]');
|
||||
await goldOption.click();
|
||||
|
||||
// publish
|
||||
await publishPost(page);
|
||||
const frontendPage = await openPublishedPostBookmark(page);
|
||||
await publishPost(sharedPage);
|
||||
const frontendPage = await openPublishedPostBookmark(sharedPage);
|
||||
|
||||
// non-member doesn't have access
|
||||
await expect(frontendPage.locator('.gh-post-upgrade-cta-content h2')).toContainText('on the Gold tier only');
|
||||
|
||||
// member on wrong tier doesn't have access
|
||||
await page.goto(silverMember);
|
||||
await impersonateMember(page);
|
||||
await sharedPage.goto(silverMember);
|
||||
await impersonateMember(sharedPage);
|
||||
await frontendPage.reload();
|
||||
await expect(frontendPage.locator('.gh-post-upgrade-cta-content h2')).toContainText('on the Gold tier only');
|
||||
|
||||
// member on selected tier has access
|
||||
await page.goto(goldMember);
|
||||
await impersonateMember(page);
|
||||
await sharedPage.goto(goldMember);
|
||||
await impersonateMember(sharedPage);
|
||||
await frontendPage.reload();
|
||||
await expect(frontendPage.locator('.gh-post-upgrade-cta-content')).not.toBeVisible();
|
||||
await expect(frontendPage.locator('.gh-content.gh-canvas > p')).toHaveText('Only gold members can see this');
|
||||
|
|
|
@ -3,14 +3,14 @@ const test = require('../fixtures/ghost-test');
|
|||
|
||||
test.describe('Admin', () => {
|
||||
test.describe('Setup', () => {
|
||||
test('Loads Admin', async ({page}) => {
|
||||
const response = await page.goto('/ghost');
|
||||
test('Loads Admin', async ({sharedPage}) => {
|
||||
const response = await sharedPage.goto('/ghost');
|
||||
expect(response.status()).toEqual(200);
|
||||
});
|
||||
|
||||
test('Is setup correctly', async ({page}) => {
|
||||
await page.goto('/ghost');
|
||||
await expect(page.locator('.gh-nav-menu-details-sitetitle')).toHaveText(/The Local Test/);
|
||||
test('Is setup correctly', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
await expect(sharedPage.locator('.gh-nav-menu-details-sitetitle')).toHaveText(/The Local Test/);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -29,21 +29,21 @@ const checkPortalScriptLoaded = async (page, loaded = true) => {
|
|||
|
||||
test.describe('Site Settings', () => {
|
||||
test.describe('Subscription Access', () => {
|
||||
test('Invite only', async ({page}) => {
|
||||
await page.goto('/ghost');
|
||||
await createTier(page, {
|
||||
test('Invite only', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
await createTier(sharedPage, {
|
||||
name: 'Free tier trial',
|
||||
monthlyPrice: 100,
|
||||
yearlyPrice: 1000,
|
||||
trialDays: 5
|
||||
}, true);
|
||||
|
||||
await changeSubscriptionAccess(page, 'invite');
|
||||
await changeSubscriptionAccess(sharedPage, 'invite');
|
||||
|
||||
// Go to the sigup page
|
||||
await page.goto('/#/portal/signup');
|
||||
await sharedPage.goto('/#/portal/signup');
|
||||
|
||||
const portalFrame = page.frameLocator('#ghost-portal-root div iframe');
|
||||
const portalFrame = sharedPage.frameLocator('#ghost-portal-root div iframe');
|
||||
|
||||
// Check sign up is disabled and a message is shown
|
||||
await expect(portalFrame.locator('.gh-portal-invite-only-notification')).toHaveText('This site is invite-only, contact the owner for access.');
|
||||
|
@ -52,83 +52,83 @@ test.describe('Site Settings', () => {
|
|||
await expect(portalFrame.locator('.gh-portal-free-trial-notification')).not.toBeVisible();
|
||||
});
|
||||
|
||||
test('Disabled subscription access', async ({page}) => {
|
||||
await page.goto('/ghost');
|
||||
test('Disabled subscription access', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
|
||||
await changeSubscriptionAccess(page, 'none');
|
||||
await changeSubscriptionAccess(sharedPage, 'none');
|
||||
|
||||
// Go to the signup page
|
||||
await page.goto('/#/portal/signup');
|
||||
await sharedPage.goto('/#/portal/signup');
|
||||
|
||||
// Check publishing flow is different and has membership features disabled
|
||||
await page.goto('/ghost');
|
||||
await createPostDraft(page, {
|
||||
await sharedPage.goto('/ghost');
|
||||
await createPostDraft(sharedPage, {
|
||||
title: 'Test post',
|
||||
body: 'Test post content'
|
||||
});
|
||||
await page.locator('[data-test-button="publish-flow"]').click();
|
||||
await expect(page.locator('[data-test-setting="publish-type"] > button')).toHaveCount(0);
|
||||
await expect(page.locator('[data-test-setting="email-recipients"]')).toHaveCount(0);
|
||||
await sharedPage.locator('[data-test-button="publish-flow"]').click();
|
||||
await expect(sharedPage.locator('[data-test-setting="publish-type"] > button')).toHaveCount(0);
|
||||
await expect(sharedPage.locator('[data-test-setting="email-recipients"]')).toHaveCount(0);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Portal script', () => {
|
||||
test('Portal loads if Memberships are enabled', async ({page}) => {
|
||||
await page.goto('/ghost');
|
||||
test('Portal loads if Memberships are enabled', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
|
||||
// Enable Memberships
|
||||
await changeSubscriptionAccess(page, 'all');
|
||||
await changeSubscriptionAccess(sharedPage, 'all');
|
||||
|
||||
// Go to the signup page
|
||||
await page.goto('/#/portal/signup');
|
||||
await sharedPage.goto('/#/portal/signup');
|
||||
|
||||
// Portal should load
|
||||
await expect(page.locator('#ghost-portal-root div iframe')).toHaveCount(1);
|
||||
await checkPortalScriptLoaded(page, true);
|
||||
await expect(sharedPage.locator('#ghost-portal-root div iframe')).toHaveCount(1);
|
||||
await checkPortalScriptLoaded(sharedPage, true);
|
||||
});
|
||||
|
||||
test('Portal loads if Tips & Donations are enabled (Stripe connected)', async ({page}) => {
|
||||
await page.goto('/ghost');
|
||||
test('Portal loads if Tips & Donations are enabled (Stripe connected)', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
|
||||
// Disable Memberships
|
||||
await changeSubscriptionAccess(page, 'none');
|
||||
await changeSubscriptionAccess(sharedPage, 'none');
|
||||
|
||||
// Go to the signup page
|
||||
await page.goto('/#/portal/signup');
|
||||
await sharedPage.goto('/#/portal/signup');
|
||||
|
||||
// Portal should load
|
||||
await expect(page.locator('#ghost-portal-root div iframe')).toHaveCount(1);
|
||||
await checkPortalScriptLoaded(page, true);
|
||||
await expect(sharedPage.locator('#ghost-portal-root div iframe')).toHaveCount(1);
|
||||
await checkPortalScriptLoaded(sharedPage, true);
|
||||
|
||||
// Reset
|
||||
await page.goto('/ghost');
|
||||
await changeSubscriptionAccess(page, 'all');
|
||||
await sharedPage.goto('/ghost');
|
||||
await changeSubscriptionAccess(sharedPage, 'all');
|
||||
});
|
||||
|
||||
test('Portal does not load if both Memberships and Tips & Donations are disabled', async ({page}) => {
|
||||
test('Portal does not load if both Memberships and Tips & Donations are disabled', async ({sharedPage}) => {
|
||||
// Disconnect stripe first, which will disable Tips & Donations
|
||||
await page.goto('/ghost');
|
||||
await disconnectStripe(page);
|
||||
await sharedPage.goto('/ghost');
|
||||
await disconnectStripe(sharedPage);
|
||||
|
||||
// Disable Memberships
|
||||
await page.goto('/ghost');
|
||||
await changeSubscriptionAccess(page, 'none');
|
||||
await sharedPage.goto('/ghost');
|
||||
await changeSubscriptionAccess(sharedPage, 'none');
|
||||
|
||||
// Go to the signup page
|
||||
await page.goto('/#/portal/signup');
|
||||
await sharedPage.goto('/#/portal/signup');
|
||||
|
||||
// Portal should not load
|
||||
await expect(page.locator('#ghost-portal-root div iframe')).toHaveCount(0);
|
||||
await checkPortalScriptLoaded(page, false);
|
||||
await expect(sharedPage.locator('#ghost-portal-root div iframe')).toHaveCount(0);
|
||||
await checkPortalScriptLoaded(sharedPage, false);
|
||||
|
||||
// Reset subscription access & re-connect Stripe
|
||||
await page.goto('/ghost');
|
||||
await changeSubscriptionAccess(page, 'all');
|
||||
await sharedPage.goto('/ghost');
|
||||
await changeSubscriptionAccess(sharedPage, 'all');
|
||||
|
||||
await page.goto('/ghost');
|
||||
await sharedPage.goto('/ghost');
|
||||
const stripeAccountId = await getStripeAccountId();
|
||||
const stripeToken = await generateStripeIntegrationToken(stripeAccountId);
|
||||
await setupStripe(page, stripeToken);
|
||||
await setupStripe(sharedPage, stripeToken);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,10 +4,10 @@ const {createTier, createOffer, getUniqueName, getSlug, goToMembershipPage, open
|
|||
|
||||
test.describe('Admin', () => {
|
||||
test.describe('Tiers', () => {
|
||||
test('Default tier should be $5mo / $50yr', async ({page}) => {
|
||||
test('Default tier should be $5mo / $50yr', async ({sharedPage}) => {
|
||||
const defaultTier = 'default-product';
|
||||
await goToMembershipPage(page);
|
||||
const tierModal = await openTierModal(page, {slug: defaultTier});
|
||||
await goToMembershipPage(sharedPage);
|
||||
const tierModal = await openTierModal(sharedPage, {slug: defaultTier});
|
||||
|
||||
await test.step('Default tier should be $5mo / $50yr', async () => {
|
||||
await expect(tierModal.getByLabel('Monthly price')).toHaveValue('5');
|
||||
|
@ -15,15 +15,15 @@ test.describe('Admin', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test('Can create a Tier and Offer', async ({page}) => {
|
||||
await page.goto('/ghost');
|
||||
test('Can create a Tier and Offer', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
const tierName = getUniqueName('New Test Tier');
|
||||
await createTier(page, {
|
||||
await createTier(sharedPage, {
|
||||
name: tierName,
|
||||
monthlyPrice: 5,
|
||||
yearlyPrice: 50
|
||||
});
|
||||
const offerName = await createOffer(page, {
|
||||
const offerName = await createOffer(sharedPage, {
|
||||
name: 'Get 5% Off!',
|
||||
tierName,
|
||||
offerType: 'discount',
|
||||
|
@ -31,29 +31,29 @@ test.describe('Admin', () => {
|
|||
});
|
||||
|
||||
await test.step('Check that offers and tiers are available on Offers page', async () => {
|
||||
await page.locator('[data-test-nav="offers"]').click();
|
||||
await page.waitForSelector('[data-test-offers-list]');
|
||||
await expect(page.locator('[data-test-offers-list]')).toContainText(tierName);
|
||||
await expect(page.locator('[data-test-offers-list]')).toContainText(offerName);
|
||||
await sharedPage.locator('[data-test-nav="offers"]').click();
|
||||
await sharedPage.waitForSelector('[data-test-offers-list]');
|
||||
await expect(sharedPage.locator('[data-test-offers-list]')).toContainText(tierName);
|
||||
await expect(sharedPage.locator('[data-test-offers-list]')).toContainText(offerName);
|
||||
});
|
||||
});
|
||||
|
||||
test('Can create additional Tier', async ({page}) => {
|
||||
await page.goto('/ghost');
|
||||
test('Can create additional Tier', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
const tierName = getUniqueName('New Test Tier');
|
||||
const enableInPortal = false;
|
||||
await createTier(page, {
|
||||
await createTier(sharedPage, {
|
||||
name: tierName,
|
||||
monthlyPrice: 100, // ordered by price, this should be the most expensive so we know it's last
|
||||
yearlyPrice: 1000
|
||||
}, enableInPortal);
|
||||
|
||||
await goToMembershipPage(page);
|
||||
await goToMembershipPage(sharedPage);
|
||||
|
||||
await test.step('Created tier should be in Portal settings and not selected', async () => {
|
||||
await page.getByTestId('portal').getByRole('button', {name: 'Customize'}).click();
|
||||
await sharedPage.getByTestId('portal').getByRole('button', {name: 'Customize'}).click();
|
||||
|
||||
const portalSettings = page.getByTestId('portal-modal');
|
||||
const portalSettings = sharedPage.getByTestId('portal-modal');
|
||||
|
||||
await portalSettings.getByLabel(tierName).first().waitFor();
|
||||
|
||||
|
@ -61,22 +61,22 @@ test.describe('Admin', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test('Can update Tier', async ({page}) => {
|
||||
await page.goto('/ghost');
|
||||
test('Can update Tier', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
const tierName = getUniqueName('New Test Tier');
|
||||
const slug = getSlug(tierName);
|
||||
const updatedTierName = getUniqueName('Updated Test Tier Name');
|
||||
const updatedMonthlyPrice = '66';
|
||||
const updatedYearlyPrice = '666';
|
||||
const updatedDescription = 'Updated description text';
|
||||
await createTier(page, {
|
||||
await createTier(sharedPage, {
|
||||
name: tierName,
|
||||
monthlyPrice: 5,
|
||||
yearlyPrice: 50
|
||||
});
|
||||
|
||||
await goToMembershipPage(page);
|
||||
const tierModal = await openTierModal(page, {slug});
|
||||
await goToMembershipPage(sharedPage);
|
||||
const tierModal = await openTierModal(sharedPage, {slug});
|
||||
|
||||
await test.step('Open modal and edit tier information', async () => {
|
||||
await tierModal.getByLabel('Name').fill(updatedTierName);
|
||||
|
@ -87,9 +87,9 @@ test.describe('Admin', () => {
|
|||
});
|
||||
|
||||
const portalFrame = await test.step('Go to website and open portal', async () => {
|
||||
await page.goto('/');
|
||||
const portalTriggerButton = page.frameLocator('[data-testid="portal-trigger-frame"]').locator('[data-testid="portal-trigger-button"]');
|
||||
const frame = page.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
await sharedPage.goto('/');
|
||||
const portalTriggerButton = sharedPage.frameLocator('[data-testid="portal-trigger-frame"]').locator('[data-testid="portal-trigger-button"]');
|
||||
const frame = sharedPage.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
await portalTriggerButton.click();
|
||||
|
||||
return frame;
|
||||
|
@ -116,37 +116,37 @@ test.describe('Admin', () => {
|
|||
});
|
||||
|
||||
// TODO: Add something more useful to this, e.g. checking in the portal
|
||||
test('Can archive and unarchive a Tier', async ({page}) => {
|
||||
await page.goto('/ghost');
|
||||
test('Can archive and unarchive a Tier', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
const tierName = getUniqueName('Archive Tier');
|
||||
const slug = getSlug(tierName);
|
||||
await createTier(page, {
|
||||
await createTier(sharedPage, {
|
||||
name: tierName,
|
||||
monthlyPrice: 5,
|
||||
yearlyPrice: 50
|
||||
});
|
||||
|
||||
await goToMembershipPage(page);
|
||||
await goToMembershipPage(sharedPage);
|
||||
await test.step('Archive tier', async () => {
|
||||
const tierModal = await openTierModal(page, {slug});
|
||||
const tierModal = await openTierModal(sharedPage, {slug});
|
||||
await tierModal.getByRole('button', {name: 'Archive tier'}).click();
|
||||
await page.getByTestId('confirmation-modal').getByRole('button', {name: 'Archive'}).click();
|
||||
await sharedPage.getByTestId('confirmation-modal').getByRole('button', {name: 'Archive'}).click();
|
||||
await tierModal.getByRole('button', {name: 'Save & close'}).click();
|
||||
});
|
||||
|
||||
await test.step('Archived tier should not be available in active tiers', async () => {
|
||||
await expect(page.locator(`[data-testid="tier-card"][data-tier="${slug}"]`)).toBeHidden();
|
||||
await expect(sharedPage.locator(`[data-testid="tier-card"][data-tier="${slug}"]`)).toBeHidden();
|
||||
});
|
||||
|
||||
await test.step('Archived tier should be available in archived tiers', async () => {
|
||||
await page.getByTestId('tiers').getByRole('tab', {name: 'Archived'}).click();
|
||||
await expect(page.locator(`[data-testid="tier-card"][data-tier="${slug}"]`)).toBeVisible();
|
||||
await sharedPage.getByTestId('tiers').getByRole('tab', {name: 'Archived'}).click();
|
||||
await expect(sharedPage.locator(`[data-testid="tier-card"][data-tier="${slug}"]`)).toBeVisible();
|
||||
});
|
||||
|
||||
await test.step('Archived tier should not be available in portal settings', async () => {
|
||||
await page.getByTestId('portal').getByRole('button', {name: 'Customize'}).click();
|
||||
await sharedPage.getByTestId('portal').getByRole('button', {name: 'Customize'}).click();
|
||||
|
||||
const portalSettings = page.getByTestId('portal-modal');
|
||||
const portalSettings = sharedPage.getByTestId('portal-modal');
|
||||
|
||||
await portalSettings.locator('input[type=checkbox]').first().waitFor();
|
||||
|
||||
|
@ -156,21 +156,21 @@ test.describe('Admin', () => {
|
|||
});
|
||||
|
||||
await test.step('Unarchive tier', async () => {
|
||||
const tierModal = await openTierModal(page, {slug});
|
||||
const tierModal = await openTierModal(sharedPage, {slug});
|
||||
await tierModal.getByRole('button', {name: 'Reactivate tier'}).click();
|
||||
await page.getByTestId('confirmation-modal').getByRole('button', {name: 'Reactivate'}).click();
|
||||
await sharedPage.getByTestId('confirmation-modal').getByRole('button', {name: 'Reactivate'}).click();
|
||||
await tierModal.getByRole('button', {name: 'Save & close'}).click();
|
||||
});
|
||||
|
||||
await test.step('Unarchived tier should be available in active tiers', async () => {
|
||||
await page.getByTestId('tiers').getByRole('tab', {name: 'Active'}).click();
|
||||
await expect(page.locator(`[data-testid="tier-card"][data-tier="${slug}"]`)).toBeVisible();
|
||||
await sharedPage.getByTestId('tiers').getByRole('tab', {name: 'Active'}).click();
|
||||
await expect(sharedPage.locator(`[data-testid="tier-card"][data-tier="${slug}"]`)).toBeVisible();
|
||||
});
|
||||
|
||||
await test.step('Unarchived tier should be available in portal settings', async () => {
|
||||
await page.getByTestId('portal').getByRole('button', {name: 'Customize'}).click();
|
||||
await sharedPage.getByTestId('portal').getByRole('button', {name: 'Customize'}).click();
|
||||
|
||||
const portalSettings = page.getByTestId('portal-modal');
|
||||
const portalSettings = sharedPage.getByTestId('portal-modal');
|
||||
|
||||
await portalSettings.locator('input[type=checkbox]').first().waitFor();
|
||||
|
||||
|
|
|
@ -30,6 +30,15 @@ const getWebhookSecret = async () => {
|
|||
// Global promises for webhook secret / Stripe integration token
|
||||
const webhookSecretPromise = getWebhookSecret();
|
||||
|
||||
/**
|
||||
* @type {import('@playwright/test').TestType<
|
||||
* import('@playwright/test').PlaywrightTestArgs &
|
||||
* import('@playwright/test').PlaywrightTestOptions &
|
||||
* import('@playwright/test').PlaywrightWorkerArgs &
|
||||
* import('@playwright/test').PlaywrightWorkerOptions
|
||||
* >}
|
||||
* @property {import('@playwright/test').Page} sharedPage
|
||||
*/
|
||||
module.exports = base.test.extend({
|
||||
baseURL: async ({port, baseURL}, use) => {
|
||||
// Replace the port in baseURL with the one we got from the port fixture
|
||||
|
@ -42,6 +51,11 @@ module.exports = base.test.extend({
|
|||
await use(ghost.state);
|
||||
},
|
||||
|
||||
sharedPage: [async ({browser}, use) => {
|
||||
const page = await browser.newPage();
|
||||
await use(page);
|
||||
}, {scope: 'worker'}],
|
||||
|
||||
// eslint-disable-next-line no-empty-pattern
|
||||
port: [async ({}, use, workerInfo) => {
|
||||
await use(2369 + workerInfo.parallelIndex);
|
||||
|
|
|
@ -4,67 +4,67 @@ const {createMember, impersonateMember, completeStripeSubscription} = require('.
|
|||
|
||||
test.describe('Portal', () => {
|
||||
test.describe('Donations', () => {
|
||||
test('Can donate as an anonymous member', async ({page}) => {
|
||||
test('Can donate as an anonymous member', async ({sharedPage}) => {
|
||||
// go to website and open portal
|
||||
await page.goto('/#/portal/support');
|
||||
await sharedPage.goto('/#/portal/support');
|
||||
|
||||
await page.locator('#customUnitAmount').fill('12.50');
|
||||
await page.locator('#email').fill('member-donation-test-1@ghost.org');
|
||||
await completeStripeSubscription(page);
|
||||
await sharedPage.locator('#customUnitAmount').fill('12.50');
|
||||
await sharedPage.locator('#email').fill('member-donation-test-1@ghost.org');
|
||||
await completeStripeSubscription(sharedPage);
|
||||
|
||||
// Check success message
|
||||
const portalFrame = page.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
const portalFrame = sharedPage.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
await expect(portalFrame.getByText('Thank you!')).toBeVisible();
|
||||
});
|
||||
|
||||
// This test is broken because the impersonate is not working!
|
||||
test('Can donate as a logged in free member', async ({page}) => {
|
||||
test('Can donate as a logged in free member', async ({sharedPage}) => {
|
||||
// create a new free member
|
||||
await createMember(page, {
|
||||
await createMember(sharedPage, {
|
||||
name: 'Test Member Donations',
|
||||
email: 'test.member.donations@example.com',
|
||||
note: 'Test Member'
|
||||
});
|
||||
|
||||
// impersonate the member on frontend
|
||||
await impersonateMember(page);
|
||||
await impersonateMember(sharedPage);
|
||||
|
||||
await page.goto('#/portal/support');
|
||||
await sharedPage.goto('#/portal/support');
|
||||
|
||||
// Don't need to fill email as it's already filled
|
||||
await page.locator('#customUnitAmount').fill('12.50');
|
||||
await completeStripeSubscription(page);
|
||||
await sharedPage.locator('#customUnitAmount').fill('12.50');
|
||||
await completeStripeSubscription(sharedPage);
|
||||
|
||||
// Check success message
|
||||
const portalFrame = page.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
const portalFrame = sharedPage.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
await expect(portalFrame.getByText('Thank you!')).toBeVisible();
|
||||
});
|
||||
|
||||
test('Can donate with a fixed amount set and different currency', async ({page}) => {
|
||||
await page.goto('/ghost/#/settings');
|
||||
test('Can donate with a fixed amount set and different currency', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost/#/settings');
|
||||
|
||||
const section = page.getByTestId('tips-or-donations');
|
||||
const section = sharedPage.getByTestId('tips-or-donations');
|
||||
|
||||
await section.getByRole('button', {name: 'Edit'}).click();
|
||||
await section.getByLabel('Suggested amount').fill('98');
|
||||
const select = section.getByLabel('Currency');
|
||||
await select.click();
|
||||
await page.locator(`[data-testid="select-option"][data-value="EUR"]`).click();
|
||||
await sharedPage.locator(`[data-testid="select-option"][data-value="EUR"]`).click();
|
||||
await section.getByRole('button', {name: 'Save'}).click();
|
||||
await expect(select).not.toBeVisible();
|
||||
|
||||
// go to website and open portal
|
||||
await page.goto('/#/portal/support');
|
||||
await sharedPage.goto('/#/portal/support');
|
||||
|
||||
await page.locator('#email').fill('member-donation-test-3@ghost.org');
|
||||
await sharedPage.locator('#email').fill('member-donation-test-3@ghost.org');
|
||||
|
||||
const totalAmount = page.getByTestId('product-summary-total-amount');
|
||||
const totalAmount = sharedPage.getByTestId('product-summary-total-amount');
|
||||
await expect(totalAmount).toHaveText('€98.00');
|
||||
|
||||
await completeStripeSubscription(page);
|
||||
await completeStripeSubscription(sharedPage);
|
||||
|
||||
// Check success message
|
||||
const portalFrame = page.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
const portalFrame = sharedPage.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
await expect(portalFrame.getByText('Thank you!')).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -27,20 +27,20 @@ test.describe('Portal', () => {
|
|||
// TODO: Use a `before` block to create all the requisite newsletters before the tests run
|
||||
test.describe.configure({retries: 1, mode: 'serial'});
|
||||
|
||||
test('can log out', async ({page}) => {
|
||||
test('can log out', async ({sharedPage}) => {
|
||||
// create a new free member
|
||||
await createMember(page, {
|
||||
await createMember(sharedPage, {
|
||||
name: 'Test Member Signout',
|
||||
email: 'test.member.signout@example.com',
|
||||
note: 'Test Member'
|
||||
});
|
||||
|
||||
// impersonate the member on frontend
|
||||
await impersonateMember(page);
|
||||
await impersonateMember(sharedPage);
|
||||
|
||||
// open portal
|
||||
const portalTriggerButton = page.frameLocator('[data-testid="portal-trigger-frame"]').locator('[data-testid="portal-trigger-button"]');
|
||||
const portalFrame = page.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
const portalTriggerButton = sharedPage.frameLocator('[data-testid="portal-trigger-frame"]').locator('[data-testid="portal-trigger-button"]');
|
||||
const portalFrame = sharedPage.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
|
||||
// sign out
|
||||
await portalTriggerButton.click();
|
||||
|
@ -51,21 +51,21 @@ test.describe('Portal', () => {
|
|||
await expect(portalFrame.locator('[data-test-button="signin-switch"]')).toBeVisible();
|
||||
});
|
||||
|
||||
test('can unsubscribe from newsletter from account settings', async ({page}) => {
|
||||
test('can unsubscribe from newsletter from account settings', async ({sharedPage}) => {
|
||||
// create a new free member
|
||||
await createMember(page, {
|
||||
await createMember(sharedPage, {
|
||||
name: 'Test Member',
|
||||
email: 'test.member@example.com',
|
||||
note: 'Test Member'
|
||||
});
|
||||
//get the url of the current member on admin
|
||||
const memberUrl = page.url();
|
||||
const memberUrl = sharedPage.url();
|
||||
|
||||
// impersonate the member on frontend
|
||||
await impersonateMember(page);
|
||||
await impersonateMember(sharedPage);
|
||||
|
||||
const portalTriggerButton = page.frameLocator('[data-testid="portal-trigger-frame"]').locator('[data-testid="portal-trigger-button"]');
|
||||
const portalFrame = page.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
const portalTriggerButton = sharedPage.frameLocator('[data-testid="portal-trigger-frame"]').locator('[data-testid="portal-trigger-button"]');
|
||||
const portalFrame = sharedPage.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
|
||||
// open portal
|
||||
await portalTriggerButton.click();
|
||||
|
@ -77,30 +77,30 @@ test.describe('Portal', () => {
|
|||
await expect(await defaultNewsletterToggle.isChecked()).not.toBeTruthy();
|
||||
|
||||
// check that member's newsletters was updated in Admin
|
||||
await page.waitForLoadState('networkidle');
|
||||
await page.goto(memberUrl);
|
||||
await expect(await page.locator('[data-test-member-settings-switch] input[type=checkbox]').first().isChecked()).not.toBeTruthy();
|
||||
await sharedPage.waitForLoadState('networkidle');
|
||||
await sharedPage.goto(memberUrl);
|
||||
await expect(await sharedPage.locator('[data-test-member-settings-switch] input[type=checkbox]').first().isChecked()).not.toBeTruthy();
|
||||
});
|
||||
|
||||
test('can unsubscribe from all newsletters from account settings', async ({page}) => {
|
||||
test('can unsubscribe from all newsletters from account settings', async ({sharedPage}) => {
|
||||
// create a new free member
|
||||
await createMember(page, {
|
||||
await createMember(sharedPage, {
|
||||
name: 'Test Member All Unsubscribe',
|
||||
email: 'test.member2@example.com',
|
||||
note: 'Test Member'
|
||||
});
|
||||
// get the url of the current member on admin
|
||||
const memberUrl = page.url();
|
||||
const memberUrl = sharedPage.url();
|
||||
|
||||
// add one more newsletter to have multiple
|
||||
await addNewsletter(page);
|
||||
await addNewsletter(sharedPage);
|
||||
|
||||
// impersonate the member on frontend
|
||||
await page.goto(memberUrl);
|
||||
await impersonateMember(page);
|
||||
await sharedPage.goto(memberUrl);
|
||||
await impersonateMember(sharedPage);
|
||||
|
||||
const portalTriggerButton = page.frameLocator('[data-testid="portal-trigger-frame"]').locator('[data-testid="portal-trigger-button"]');
|
||||
const portalFrame = page.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
const portalTriggerButton = sharedPage.frameLocator('[data-testid="portal-trigger-frame"]').locator('[data-testid="portal-trigger-button"]');
|
||||
const portalFrame = sharedPage.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
|
||||
// open portal
|
||||
await portalTriggerButton.click();
|
||||
|
@ -129,12 +129,12 @@ test.describe('Portal', () => {
|
|||
}
|
||||
|
||||
// check that member's newsletters was updated in Admin
|
||||
await page.waitForLoadState('networkidle');
|
||||
await page.goto(memberUrl);
|
||||
await sharedPage.waitForLoadState('networkidle');
|
||||
await sharedPage.goto(memberUrl);
|
||||
|
||||
// check amount of newsletters in member's profile in Admin
|
||||
await page.waitForSelector('[data-test-member-settings-switch]');
|
||||
const membersNewsletters = await page.locator('[data-test-member-settings-switch]');
|
||||
await sharedPage.waitForSelector('[data-test-member-settings-switch]');
|
||||
const membersNewsletters = await sharedPage.locator('[data-test-member-settings-switch]');
|
||||
const newslettersCount = await membersNewsletters.count();
|
||||
await expect(newslettersCount).toEqual(2);
|
||||
|
||||
|
|
|
@ -4,21 +4,21 @@ const {deleteAllMembers, createTier, createOffer, completeStripeSubscription} =
|
|||
|
||||
test.describe('Portal', () => {
|
||||
test.describe('Offers', () => {
|
||||
test('Creates and uses a free-trial Offer', async ({page}) => {
|
||||
test('Creates and uses a free-trial Offer', async ({sharedPage}) => {
|
||||
// reset members by deleting all existing
|
||||
await page.goto('/ghost');
|
||||
await deleteAllMembers(page);
|
||||
await sharedPage.goto('/ghost');
|
||||
await deleteAllMembers(sharedPage);
|
||||
|
||||
// add a new tier for offers
|
||||
const tierName = 'Trial Tier';
|
||||
await createTier(page, {
|
||||
await createTier(sharedPage, {
|
||||
name: tierName,
|
||||
monthlyPrice: 6,
|
||||
yearlyPrice: 60
|
||||
});
|
||||
|
||||
// add a new offer with free trial
|
||||
const offerName = await createOffer(page, {
|
||||
const offerName = await createOffer(sharedPage, {
|
||||
name: 'Black Friday Special',
|
||||
tierName,
|
||||
offerType: 'freeTrial',
|
||||
|
@ -26,17 +26,17 @@ test.describe('Portal', () => {
|
|||
});
|
||||
|
||||
// check that offer was added in the offer list screen
|
||||
await expect(page.locator(`[data-test-offer="${offerName}"]`), 'Should have free-trial offer').toBeVisible();
|
||||
await expect(sharedPage.locator(`[data-test-offer="${offerName}"]`), 'Should have free-trial offer').toBeVisible();
|
||||
|
||||
// open offer details page
|
||||
await page.locator(`[data-test-offer="${offerName}"] a`).first().click();
|
||||
await sharedPage.locator(`[data-test-offer="${offerName}"] a`).first().click();
|
||||
|
||||
// fetch offer url from portal settings and open it
|
||||
const portalUrl = await page.locator('[data-test-input="offer-portal-url"]').inputValue();
|
||||
await page.goto(portalUrl);
|
||||
const portalUrl = await sharedPage.locator('[data-test-input="offer-portal-url"]').inputValue();
|
||||
await sharedPage.goto(portalUrl);
|
||||
|
||||
const portalTriggerButton = page.frameLocator('[data-testid="portal-trigger-frame"]').locator('[data-testid="portal-trigger-button"]');
|
||||
const portalFrame = page.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
const portalTriggerButton = sharedPage.frameLocator('[data-testid="portal-trigger-frame"]').locator('[data-testid="portal-trigger-button"]');
|
||||
const portalFrame = sharedPage.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
|
||||
// check offer title is shown on portal
|
||||
await expect(portalFrame.locator('.gh-portal-offer-title'), 'URL should open Portal with free-trial offer').toBeVisible();
|
||||
|
@ -54,7 +54,7 @@ test.describe('Portal', () => {
|
|||
}
|
||||
|
||||
// complete subscription
|
||||
await completeStripeSubscription(page);
|
||||
await completeStripeSubscription(sharedPage);
|
||||
|
||||
// wait for site to load and open portal
|
||||
await portalTriggerButton.click();
|
||||
|
@ -63,34 +63,34 @@ test.describe('Portal', () => {
|
|||
await expect(portalFrame.locator('text=Free Trial – Ends'), 'Portal should show free trial info').toBeVisible();
|
||||
|
||||
// go to member list on admin
|
||||
await page.goto('/ghost');
|
||||
await page.locator('.gh-nav a[href="#/members/"]').click();
|
||||
await sharedPage.goto('/ghost');
|
||||
await sharedPage.locator('.gh-nav a[href="#/members/"]').click();
|
||||
|
||||
// 1 member, should be Testy, on Portal Tier
|
||||
await expect(page.getByRole('link', {name: 'Testy McTesterson testy+trial@example.com'}), 'Should have 1 paid member').toBeVisible();
|
||||
await expect(page.getByRole('link', {name: tierName}), `Paid member should be on ${tierName}`).toBeVisible();
|
||||
await expect(sharedPage.getByRole('link', {name: 'Testy McTesterson testy+trial@example.com'}), 'Should have 1 paid member').toBeVisible();
|
||||
await expect(sharedPage.getByRole('link', {name: tierName}), `Paid member should be on ${tierName}`).toBeVisible();
|
||||
|
||||
// Ensure the offer redemption count was bumped
|
||||
await page.locator('.gh-nav a[href="#/offers/"]').click();
|
||||
const locator = page.locator(`[data-test-offer="${offerName}"]`).locator('[data-test-list="redemption-count"]').locator('span');
|
||||
await sharedPage.locator('.gh-nav a[href="#/offers/"]').click();
|
||||
const locator = sharedPage.locator(`[data-test-offer="${offerName}"]`).locator('[data-test-list="redemption-count"]').locator('span');
|
||||
await expect(locator).toContainText('1');
|
||||
});
|
||||
|
||||
test('Creates and uses a one-time discount Offer', async ({page}) => {
|
||||
test('Creates and uses a one-time discount Offer', async ({sharedPage}) => {
|
||||
// reset members by deleting all existing
|
||||
await page.goto('/ghost');
|
||||
await deleteAllMembers(page);
|
||||
await sharedPage.goto('/ghost');
|
||||
await deleteAllMembers(sharedPage);
|
||||
|
||||
// add new tier
|
||||
const tierName = 'One-off Tier';
|
||||
await createTier(page, {
|
||||
await createTier(sharedPage, {
|
||||
name: tierName,
|
||||
monthlyPrice: 6,
|
||||
yearlyPrice: 60
|
||||
});
|
||||
|
||||
// Creates a one-time discount offer for 10% off
|
||||
const offerName = await createOffer(page, {
|
||||
const offerName = await createOffer(sharedPage, {
|
||||
name: 'Black Friday Special',
|
||||
tierName: tierName,
|
||||
offerType: 'discount',
|
||||
|
@ -98,17 +98,17 @@ test.describe('Portal', () => {
|
|||
});
|
||||
|
||||
// check that offer was added in the offer list screen
|
||||
await expect(page.locator(`[data-test-offer="${offerName}"]`), 'Should have free-trial offer').toBeVisible();
|
||||
await expect(sharedPage.locator(`[data-test-offer="${offerName}"]`), 'Should have free-trial offer').toBeVisible();
|
||||
|
||||
// open offer details page
|
||||
await page.locator(`[data-test-offer="${offerName}"] a`).first().click();
|
||||
await sharedPage.locator(`[data-test-offer="${offerName}"] a`).first().click();
|
||||
|
||||
// fetch offer url from portal settings and open it
|
||||
const portalUrl = await page.locator('[data-test-input="offer-portal-url"]').inputValue();
|
||||
await page.goto(portalUrl);
|
||||
const portalUrl = await sharedPage.locator('[data-test-input="offer-portal-url"]').inputValue();
|
||||
await sharedPage.goto(portalUrl);
|
||||
|
||||
const portalTriggerButton = page.frameLocator('[data-testid="portal-trigger-frame"]').locator('[data-testid="portal-trigger-button"]');
|
||||
const portalFrame = page.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
const portalTriggerButton = sharedPage.frameLocator('[data-testid="portal-trigger-frame"]').locator('[data-testid="portal-trigger-button"]');
|
||||
const portalFrame = sharedPage.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
|
||||
// check offer title is visible on portal page
|
||||
await expect(portalFrame.locator('.gh-portal-offer-title'), 'URL should open Portal with discount offer').toBeVisible();
|
||||
|
@ -125,7 +125,7 @@ test.describe('Portal', () => {
|
|||
}
|
||||
|
||||
// complete stripe subscription
|
||||
await completeStripeSubscription(page);
|
||||
await completeStripeSubscription(sharedPage);
|
||||
|
||||
// wait for site to load and open portal
|
||||
await portalTriggerButton.click();
|
||||
|
@ -133,29 +133,29 @@ test.describe('Portal', () => {
|
|||
await expect(portalFrame.locator('text=$5.40/month'), 'Portal should not show discounted price').not.toBeVisible();
|
||||
|
||||
// go to members list on admin
|
||||
await page.goto('/ghost');
|
||||
await page.locator('.gh-nav a[href="#/members/"]').click();
|
||||
await sharedPage.goto('/ghost');
|
||||
await sharedPage.locator('.gh-nav a[href="#/members/"]').click();
|
||||
|
||||
// 1 member, should be Testy, on Portal Tier
|
||||
await expect(page.getByRole('link', {name: 'Testy McTesterson testy+oneoff@example.com'}), 'Should have 1 paid member').toBeVisible();
|
||||
await expect(page.getByRole('link', {name: tierName}), `Paid member should be on ${tierName}`).toBeVisible();
|
||||
await expect(sharedPage.getByRole('link', {name: 'Testy McTesterson testy+oneoff@example.com'}), 'Should have 1 paid member').toBeVisible();
|
||||
await expect(sharedPage.getByRole('link', {name: tierName}), `Paid member should be on ${tierName}`).toBeVisible();
|
||||
});
|
||||
|
||||
test('Creates and uses a multiple-months discount Offer', async ({page}) => {
|
||||
test('Creates and uses a multiple-months discount Offer', async ({sharedPage}) => {
|
||||
// reset members by deleting all existing
|
||||
await page.goto('/ghost');
|
||||
await deleteAllMembers(page);
|
||||
await sharedPage.goto('/ghost');
|
||||
await deleteAllMembers(sharedPage);
|
||||
|
||||
// add new tier
|
||||
const tierName = 'Multiple-month Tier';
|
||||
await createTier(page, {
|
||||
await createTier(sharedPage, {
|
||||
name: tierName,
|
||||
monthlyPrice: 6,
|
||||
yearlyPrice: 60
|
||||
});
|
||||
|
||||
// Creates a one-time discount offer for 10% off
|
||||
const offerName = await createOffer(page, {
|
||||
const offerName = await createOffer(sharedPage, {
|
||||
name: 'Black Friday Special',
|
||||
tierName: tierName,
|
||||
offerType: 'discount',
|
||||
|
@ -165,17 +165,17 @@ test.describe('Portal', () => {
|
|||
});
|
||||
|
||||
// check that offer was added in the offer list screen
|
||||
await expect(page.locator(`[data-test-offer="${offerName}"]`), 'Should have free-trial offer').toBeVisible();
|
||||
await expect(sharedPage.locator(`[data-test-offer="${offerName}"]`), 'Should have free-trial offer').toBeVisible();
|
||||
|
||||
// open offer details page
|
||||
await page.locator(`[data-test-offer="${offerName}"] a`).first().click();
|
||||
await sharedPage.locator(`[data-test-offer="${offerName}"] a`).first().click();
|
||||
|
||||
// fetch offer url from portal settings and open it
|
||||
const portalUrl = await page.locator('[data-test-input="offer-portal-url"]').inputValue();
|
||||
await page.goto(portalUrl);
|
||||
const portalUrl = await sharedPage.locator('[data-test-input="offer-portal-url"]').inputValue();
|
||||
await sharedPage.goto(portalUrl);
|
||||
|
||||
const portalTriggerButton = page.frameLocator('[data-testid="portal-trigger-frame"]').locator('[data-testid="portal-trigger-button"]');
|
||||
const portalFrame = page.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
const portalTriggerButton = sharedPage.frameLocator('[data-testid="portal-trigger-frame"]').locator('[data-testid="portal-trigger-button"]');
|
||||
const portalFrame = sharedPage.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
|
||||
// check offer details are shown on portal page
|
||||
await expect(portalFrame.locator('.gh-portal-offer-title'), 'URL should open Portal with discount offer').toBeVisible();
|
||||
|
@ -194,36 +194,36 @@ test.describe('Portal', () => {
|
|||
}
|
||||
|
||||
// complete stripe subscription
|
||||
await completeStripeSubscription(page);
|
||||
await completeStripeSubscription(sharedPage);
|
||||
|
||||
// wait for site to load and open portal
|
||||
await portalTriggerButton.click();
|
||||
|
||||
// Discounted price should not be visible for member for one-time offers
|
||||
await expect(portalFrame.locator('text=$5.40/month'), 'Portal should show discounted price').toBeVisible();
|
||||
await page.goto('/ghost');
|
||||
await page.locator('.gh-nav a[href="#/members/"]').click();
|
||||
await sharedPage.goto('/ghost');
|
||||
await sharedPage.locator('.gh-nav a[href="#/members/"]').click();
|
||||
|
||||
// 1 member, should be Testy, on Portal Tier
|
||||
await expect(page.getByRole('link', {name: 'Testy McTesterson testy+multi@example.com'}), 'Should have 1 paid member').toBeVisible();
|
||||
await expect(page.getByRole('link', {name: tierName}), `Paid member should be on ${tierName}`).toBeVisible();
|
||||
await expect(sharedPage.getByRole('link', {name: 'Testy McTesterson testy+multi@example.com'}), 'Should have 1 paid member').toBeVisible();
|
||||
await expect(sharedPage.getByRole('link', {name: tierName}), `Paid member should be on ${tierName}`).toBeVisible();
|
||||
});
|
||||
|
||||
test('Creates and uses a forever discount Offer', async ({page}) => {
|
||||
test('Creates and uses a forever discount Offer', async ({sharedPage}) => {
|
||||
// reset members by deleting all existing
|
||||
await page.goto('/ghost');
|
||||
await deleteAllMembers(page);
|
||||
await sharedPage.goto('/ghost');
|
||||
await deleteAllMembers(sharedPage);
|
||||
|
||||
// add tier
|
||||
const tierName = 'Forever Tier';
|
||||
await createTier(page, {
|
||||
await createTier(sharedPage, {
|
||||
name: tierName,
|
||||
monthlyPrice: 6,
|
||||
yearlyPrice: 60
|
||||
});
|
||||
|
||||
// Creates a one-time discount offer for 10% off
|
||||
const offerName = await createOffer(page, {
|
||||
const offerName = await createOffer(sharedPage, {
|
||||
name: 'Black Friday Special',
|
||||
tierName: tierName,
|
||||
offerType: 'discount',
|
||||
|
@ -232,17 +232,17 @@ test.describe('Portal', () => {
|
|||
});
|
||||
|
||||
// check that offer was added in the offer list screen
|
||||
await expect(page.locator(`[data-test-offer="${offerName}"]`), 'Should have free-trial offer').toBeVisible();
|
||||
await expect(sharedPage.locator(`[data-test-offer="${offerName}"]`), 'Should have free-trial offer').toBeVisible();
|
||||
|
||||
// open offer details page
|
||||
await page.locator(`[data-test-offer="${offerName}"] a`).first().click();
|
||||
await sharedPage.locator(`[data-test-offer="${offerName}"] a`).first().click();
|
||||
|
||||
// fetch offer url from portal settings and open it
|
||||
const portalUrl = await page.locator('[data-test-input="offer-portal-url"]').inputValue();
|
||||
await page.goto(portalUrl);
|
||||
const portalUrl = await sharedPage.locator('[data-test-input="offer-portal-url"]').inputValue();
|
||||
await sharedPage.goto(portalUrl);
|
||||
|
||||
const portalTriggerButton = page.frameLocator('[data-testid="portal-trigger-frame"]').locator('[data-testid="portal-trigger-button"]');
|
||||
const portalFrame = page.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
const portalTriggerButton = sharedPage.frameLocator('[data-testid="portal-trigger-frame"]').locator('[data-testid="portal-trigger-button"]');
|
||||
const portalFrame = sharedPage.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
|
||||
// check offer details are shown on portal page
|
||||
await expect(portalFrame.locator('.gh-portal-offer-title'), 'URL should open Portal with discount offer').toBeVisible();
|
||||
|
@ -259,34 +259,34 @@ test.describe('Portal', () => {
|
|||
if (hasContinueBtn) {
|
||||
await portalFrame.getByRole('button', {name: 'Continue'}).click();
|
||||
}
|
||||
await completeStripeSubscription(page);
|
||||
await completeStripeSubscription(sharedPage);
|
||||
|
||||
// wait for site to load and open portal
|
||||
await portalTriggerButton.click();
|
||||
|
||||
// Discounted price should be visible for member for forever offers
|
||||
await expect(portalFrame.locator('text=$5.40/month'), 'Portal should show discounted price').toBeVisible();
|
||||
await page.goto('/ghost');
|
||||
await page.locator('.gh-nav a[href="#/members/"]').click();
|
||||
await sharedPage.goto('/ghost');
|
||||
await sharedPage.locator('.gh-nav a[href="#/members/"]').click();
|
||||
|
||||
// 1 member, should be Testy, on Portal Tier
|
||||
await expect(page.getByRole('link', {name: 'Testy McTesterson testy+forever@example.com'}), 'Should have 1 paid member').toBeVisible();
|
||||
await expect(page.getByRole('link', {name: tierName}), `Paid member should be on ${tierName}`).toBeVisible();
|
||||
await expect(sharedPage.getByRole('link', {name: 'Testy McTesterson testy+forever@example.com'}), 'Should have 1 paid member').toBeVisible();
|
||||
await expect(sharedPage.getByRole('link', {name: tierName}), `Paid member should be on ${tierName}`).toBeVisible();
|
||||
});
|
||||
|
||||
test('Archiving an offer', async ({page}) => {
|
||||
await page.goto('/ghost');
|
||||
test('Archiving an offer', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
|
||||
// Create a new tier to attach offer to
|
||||
const tierName = 'Archive Test Tier';
|
||||
await createTier(page, {
|
||||
await createTier(sharedPage, {
|
||||
name: tierName,
|
||||
monthlyPrice: 6,
|
||||
yearlyPrice: 60
|
||||
});
|
||||
|
||||
// Create an offer. This will be archived
|
||||
const offerName = await createOffer(page, {
|
||||
const offerName = await createOffer(sharedPage, {
|
||||
name: 'To be archived',
|
||||
tierName: tierName,
|
||||
offerType: 'discount',
|
||||
|
@ -294,7 +294,7 @@ test.describe('Portal', () => {
|
|||
});
|
||||
|
||||
// Archive all existing offers by creating a new offer. Using the createOffer util auto-archives all existing offers
|
||||
await createOffer(page, {
|
||||
await createOffer(sharedPage, {
|
||||
name: 'Dummy Active Offer',
|
||||
tierName: tierName,
|
||||
offerType: 'discount',
|
||||
|
@ -302,17 +302,17 @@ test.describe('Portal', () => {
|
|||
});
|
||||
|
||||
// Check if the offer appears in the archive list
|
||||
await page.locator('.gh-contentfilter-menu-trigger').click();
|
||||
await page.getByRole('option', {name: 'Archived offers'}).click();
|
||||
await expect(page.getByRole('link', {name: offerName}), 'Should have an archived offer').toBeVisible();
|
||||
await sharedPage.locator('.gh-contentfilter-menu-trigger').click();
|
||||
await sharedPage.getByRole('option', {name: 'Archived offers'}).click();
|
||||
await expect(sharedPage.getByRole('link', {name: offerName}), 'Should have an archived offer').toBeVisible();
|
||||
|
||||
// Go to the offer and grab the offer URL
|
||||
await page.locator('.gh-offers-list .gh-list-row').filter({hasText: offerName}).click();
|
||||
const portalUrl = await page.locator('input#url').inputValue();
|
||||
await sharedPage.locator('.gh-offers-list .gh-list-row').filter({hasText: offerName}).click();
|
||||
const portalUrl = await sharedPage.locator('input#url').inputValue();
|
||||
|
||||
// Open the offer URL and make sure portal popup doesn't load
|
||||
await page.goto(portalUrl);
|
||||
const portalPopup = await page.locator('[data-testid="portal-popup-frame"]').isVisible();
|
||||
await sharedPage.goto(portalUrl);
|
||||
const portalPopup = await sharedPage.locator('[data-testid="portal-popup-frame"]').isVisible();
|
||||
await expect(portalPopup).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,15 +4,15 @@ const {deleteAllMembers, completeStripeSubscription} = require('../utils');
|
|||
|
||||
test.describe('Portal', () => {
|
||||
test.describe('Tiers', () => {
|
||||
test('Sign up for paid plan via portal - single tier', async ({page}) => {
|
||||
test('Sign up for paid plan via portal - single tier', async ({sharedPage}) => {
|
||||
// make sure we have no members to start fresh
|
||||
await page.goto('/ghost');
|
||||
await deleteAllMembers(page);
|
||||
await sharedPage.goto('/ghost');
|
||||
await deleteAllMembers(sharedPage);
|
||||
|
||||
// go to website and open portal
|
||||
await page.goto('/');
|
||||
const portalTriggerButton = page.frameLocator('[data-testid="portal-trigger-frame"]').locator('[data-testid="portal-trigger-button"]');
|
||||
const portalFrame = page.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
await sharedPage.goto('/');
|
||||
const portalTriggerButton = sharedPage.frameLocator('[data-testid="portal-trigger-frame"]').locator('[data-testid="portal-trigger-button"]');
|
||||
const portalFrame = sharedPage.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
await portalTriggerButton.click();
|
||||
|
||||
// fill out signup form and submit
|
||||
|
@ -27,7 +27,7 @@ test.describe('Portal', () => {
|
|||
}
|
||||
|
||||
// complete the stripe checkout flow
|
||||
await completeStripeSubscription(page);
|
||||
await completeStripeSubscription(sharedPage);
|
||||
|
||||
// come back to the website, open portal and check member is logged in and has paid
|
||||
await portalTriggerButton.click();
|
||||
|
|
|
@ -10,34 +10,34 @@ test.describe('Portal', () => {
|
|||
test.describe.configure({mode: 'serial'});
|
||||
|
||||
test.describe('Upgrade: Comped Member', () => {
|
||||
test('allows comped member to upgrade to paid tier', async ({page}) => {
|
||||
test('allows comped member to upgrade to paid tier', async ({sharedPage}) => {
|
||||
// create a new member
|
||||
await page.goto('/ghost');
|
||||
await createTier(page, {
|
||||
await sharedPage.goto('/ghost');
|
||||
await createTier(sharedPage, {
|
||||
name: tierName,
|
||||
monthlyPrice: 5,
|
||||
yearlyPrice: 50
|
||||
});
|
||||
await createMember(page, {
|
||||
await createMember(sharedPage, {
|
||||
name: 'Testy McTest',
|
||||
email: 'testy+upgradecompedportal@example.com',
|
||||
note: 'Testy McTest is a test member'
|
||||
});
|
||||
|
||||
//get the url of the current member on admin
|
||||
const memberUrl = page.url();
|
||||
const memberUrl = sharedPage.url();
|
||||
|
||||
// Give member comped subscription
|
||||
await page.locator('[data-test-button="add-complimentary"]').click();
|
||||
await page.locator('[data-test-button="save-comp-tier"]').first().click({
|
||||
await sharedPage.locator('[data-test-button="add-complimentary"]').click();
|
||||
await sharedPage.locator('[data-test-button="save-comp-tier"]').first().click({
|
||||
delay: 500
|
||||
});
|
||||
|
||||
await page.waitForLoadState('networkidle');
|
||||
await impersonateMember(page);
|
||||
await sharedPage.waitForLoadState('networkidle');
|
||||
await impersonateMember(sharedPage);
|
||||
|
||||
const portalTriggerButton = page.frameLocator('[data-testid="portal-trigger-frame"]').locator('[data-testid="portal-trigger-button"]');
|
||||
const portalFrame = page.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
const portalTriggerButton = sharedPage.frameLocator('[data-testid="portal-trigger-frame"]').locator('[data-testid="portal-trigger-button"]');
|
||||
const portalFrame = sharedPage.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
|
||||
// open portal, go to plans and click continue to select the first plan(yearly)
|
||||
await portalTriggerButton.click();
|
||||
|
@ -47,7 +47,7 @@ test.describe('Portal', () => {
|
|||
await choseTierByName(portalFrame, tierName);
|
||||
|
||||
// complete stripe checkout
|
||||
await completeStripeSubscription(page);
|
||||
await completeStripeSubscription(sharedPage);
|
||||
|
||||
// open portal and check that member has been upgraded to paid tier
|
||||
await portalTriggerButton.click();
|
||||
|
@ -56,8 +56,8 @@ test.describe('Portal', () => {
|
|||
await expect(portalFrame.getByText('**** **** **** 4242')).toBeVisible();
|
||||
|
||||
// check that member has been upgraded in admin and a tier exists for them
|
||||
await page.goto(memberUrl);
|
||||
await expect(page.locator('[data-test-tier]').first()).toBeVisible();
|
||||
await sharedPage.goto(memberUrl);
|
||||
await expect(sharedPage.locator('[data-test-tier]').first()).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -72,21 +72,21 @@ test.describe('Portal', () => {
|
|||
note: 'Testy McTest is a test member'
|
||||
};
|
||||
|
||||
test('allows free member upgrade to paid tier', async ({page}) => {
|
||||
await page.goto('/ghost');
|
||||
test('allows free member upgrade to paid tier', async ({sharedPage}) => {
|
||||
await sharedPage.goto('/ghost');
|
||||
|
||||
// create a new free member
|
||||
await page.goto('/ghost');
|
||||
await createMember(page, member);
|
||||
await sharedPage.goto('/ghost');
|
||||
await createMember(sharedPage, member);
|
||||
|
||||
//store the url of the member detail page
|
||||
memberUrl = page.url();
|
||||
memberUrl = sharedPage.url();
|
||||
|
||||
// impersonate the member on frontend
|
||||
await impersonateMember(page);
|
||||
await impersonateMember(sharedPage);
|
||||
|
||||
const portalTriggerButton = page.frameLocator('[data-testid="portal-trigger-frame"]').locator('[data-testid="portal-trigger-button"]');
|
||||
const portalFrame = page.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
const portalTriggerButton = sharedPage.frameLocator('[data-testid="portal-trigger-frame"]').locator('[data-testid="portal-trigger-button"]');
|
||||
const portalFrame = sharedPage.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
|
||||
// open portal, go to plans and click continue to select the first plan(yearly)
|
||||
await portalTriggerButton.click();
|
||||
|
@ -99,7 +99,7 @@ test.describe('Portal', () => {
|
|||
await choseTierByName(portalFrame, tierName);
|
||||
|
||||
// complete stripe checkout
|
||||
await completeStripeSubscription(page);
|
||||
await completeStripeSubscription(sharedPage);
|
||||
|
||||
// open portal and check that member has been upgraded to paid tier
|
||||
await portalTriggerButton.click();
|
||||
|
@ -109,22 +109,22 @@ test.describe('Portal', () => {
|
|||
await expect(portalFrame.getByText('**** **** **** 4242')).toBeVisible();
|
||||
|
||||
// verify member's tier on member detail page in admin
|
||||
await page.goto(memberUrl);
|
||||
const tierCard = await page.locator('[data-test-tier]').first();
|
||||
await sharedPage.goto(memberUrl);
|
||||
const tierCard = await sharedPage.locator('[data-test-tier]').first();
|
||||
const tierText = await tierCard.locator('[data-test-text="tier-name"]');
|
||||
await expect(tierCard).toBeVisible();
|
||||
await expect(tierText, 'Where is tier text').toHaveText(new RegExp(tierName));
|
||||
});
|
||||
|
||||
test('allows member to switch plans', async ({page}) => {
|
||||
test('allows member to switch plans', async ({sharedPage}) => {
|
||||
// go to member detail page in admin
|
||||
await page.goto(memberUrl);
|
||||
await sharedPage.goto(memberUrl);
|
||||
|
||||
// impersonate the member on frontend
|
||||
await impersonateMember(page);
|
||||
await impersonateMember(sharedPage);
|
||||
|
||||
const portalTriggerButton = page.frameLocator('[data-testid="portal-trigger-frame"]').locator('[data-testid="portal-trigger-button"]');
|
||||
const portalFrame = page.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
const portalTriggerButton = sharedPage.frameLocator('[data-testid="portal-trigger-frame"]').locator('[data-testid="portal-trigger-button"]');
|
||||
const portalFrame = sharedPage.frameLocator('[data-testid="portal-popup-frame"]');
|
||||
|
||||
// open portal
|
||||
await portalTriggerButton.click();
|
||||
|
|
Loading…
Add table
Reference in a new issue