Added portal data attributes tests

closes https://github.com/TryGhost/Team/issues/1364

- extends data attributes test to cover `data-portal=*` tests
This commit is contained in:
Rishabh 2022-02-18 18:22:06 +05:30
parent 58f2025038
commit 98f212c3df
2 changed files with 267 additions and 42 deletions

View File

@ -99,9 +99,6 @@ export default class App extends React.Component {
/** Setup custom trigger buttons handling on page */
setupCustomTriggerButton() {
if (hasMode(['test'])) {
return;
}
// Handler for custom buttons
this.clickHandler = (event) => {
event.preventDefault();
@ -217,7 +214,7 @@ export default class App extends React.Component {
// Setup test mode data
if (hasMode(['test'])) {
return {
showPopup: true
showPopup: this.props.showPopup !== undefined ? this.props.showPopup : true
};
}
return {};

View File

@ -1,4 +1,8 @@
import App from '../App';
import {site as FixturesSite, member as FixtureMember} from '../utils/test-fixtures';
import {fireEvent, appRender, within} from '../utils/test-utils';
import {site as FixtureSite} from '../utils/test-fixtures';
import setupGhostApi from '../utils/api';
const {formSubmitHandler, planClickHandler} = require('../data-attributes');
// Mock data
@ -68,7 +72,7 @@ function getMockData() {
};
}
describe('Data attributes:', () => {
describe('Member Data attributes:', () => {
beforeEach(() => {
// Mock global fetch
jest.spyOn(window, 'fetch').mockImplementation((url) => {
@ -120,55 +124,279 @@ describe('Data attributes:', () => {
afterEach(() => {
jest.restoreAllMocks();
});
test('data-members-form: allows free signup', () => {
const {event, form, errorEl, siteUrl, submitHandler} = getMockData();
describe('data-members-form', () => {
test('allows free signup', () => {
const {event, form, errorEl, siteUrl, submitHandler} = getMockData();
formSubmitHandler({event, form, errorEl, siteUrl, submitHandler});
formSubmitHandler({event, form, errorEl, siteUrl, submitHandler});
expect(window.fetch).toHaveBeenCalledTimes(1);
expect(window.fetch).toHaveBeenCalledTimes(1);
expect(window.fetch).toHaveBeenCalledWith('https://portal.localhost/members/api/send-magic-link/', {body: '{"email":"jamie@example.com","emailType":"signup","labels":["Gold"],"name":"Jamie Larsen"}', headers: {'Content-Type': 'application/json'}, method: 'POST'});
expect(window.fetch).toHaveBeenCalledWith('https://portal.localhost/members/api/send-magic-link/', {body: '{"email":"jamie@example.com","emailType":"signup","labels":["Gold"],"name":"Jamie Larsen"}', headers: {'Content-Type': 'application/json'}, method: 'POST'});
});
});
test('data-members-plan: allows new member paid signup via direct checkout', async () => {
const {event, errorEl, siteUrl, clickHandler, site, member, element} = getMockData();
describe('data-members-plan', () => {
test('allows new member paid signup via direct checkout', async () => {
const {event, errorEl, siteUrl, clickHandler, site, member, element} = getMockData();
const paidTier = site.products.find(p => p.type === 'paid');
const plan = paidTier.monthlyPrice.id;
const paidTier = site.products.find(p => p.type === 'paid');
const plan = paidTier.monthlyPrice.id;
await planClickHandler({event, errorEl, siteUrl, clickHandler, site, member, el: element});
expect(window.fetch).toHaveBeenNthCalledWith(1,
'https://portal.localhost/members/api/session', {
await planClickHandler({event, errorEl, siteUrl, clickHandler, site, member, el: element});
expect(window.fetch).toHaveBeenNthCalledWith(1,
'https://portal.localhost/members/api/session', {
credentials: 'same-origin'
}
);
expect(window.fetch).toHaveBeenNthCalledWith(2,
'https://portal.localhost/members/api/create-stripe-checkout-session/', {
body: `{"priceId":"${plan}","identity":"session-identity","successUrl":"https://portal.localhost/success","cancelUrl":"https://portal.localhost/cancel","metadata":{}}`,
headers: {
'Content-Type': 'application/json'
},
method: 'POST'
}
);
});
});
describe('data-members-plan', () => {
test('allows free member upgrade via direct checkout', async () => {
let {event, errorEl, siteUrl, clickHandler, site, member, element} = getMockData();
member = FixtureMember.free;
const paidTier = site.products.find(p => p.type === 'paid');
const plan = paidTier.monthlyPrice.id;
await planClickHandler({event, errorEl, siteUrl, clickHandler, site, member, el: element});
expect(window.fetch).toHaveBeenNthCalledWith(1, 'https://portal.localhost/members/api/session', {
credentials: 'same-origin'
}
);
expect(window.fetch).toHaveBeenNthCalledWith(2,
'https://portal.localhost/members/api/create-stripe-checkout-session/', {
body: `{"priceId":"${plan}","identity":"session-identity","successUrl":"https://portal.localhost/success","cancelUrl":"https://portal.localhost/cancel","metadata":{}}`,
});
expect(window.fetch).toHaveBeenNthCalledWith(2, 'https://portal.localhost/members/api/create-stripe-checkout-session/', {
body: `{"priceId":"${plan}","identity":"session-identity","successUrl":"https://portal.localhost/success","cancelUrl":"https://portal.localhost/cancel","metadata":{"checkoutType":"upgrade"}}`,
headers: {
'Content-Type': 'application/json'
},
method: 'POST'
}
);
});
test('data-members-plan: allows free member upgrade via direct checkout', async () => {
let {event, errorEl, siteUrl, clickHandler, site, member, element} = getMockData();
member = FixtureMember.free;
const paidTier = site.products.find(p => p.type === 'paid');
const plan = paidTier.monthlyPrice.id;
await planClickHandler({event, errorEl, siteUrl, clickHandler, site, member, el: element});
expect(window.fetch).toHaveBeenNthCalledWith(1, 'https://portal.localhost/members/api/session', {
credentials: 'same-origin'
});
expect(window.fetch).toHaveBeenNthCalledWith(2, 'https://portal.localhost/members/api/create-stripe-checkout-session/', {
body: `{"priceId":"${plan}","identity":"session-identity","successUrl":"https://portal.localhost/success","cancelUrl":"https://portal.localhost/cancel","metadata":{"checkoutType":"upgrade"}}`,
headers: {
'Content-Type': 'application/json'
},
method: 'POST'
});
});
});
});
const setup = async ({site, member = null, showPopup = true}) => {
const ghostApi = setupGhostApi({siteUrl: 'https://example.com'});
ghostApi.init = jest.fn(() => {
return Promise.resolve({
site,
member
});
});
ghostApi.member.sendMagicLink = jest.fn(() => {
return Promise.resolve('success');
});
ghostApi.member.checkoutPlan = jest.fn(() => {
return Promise.resolve();
});
const utils = appRender(
<App api={ghostApi} showPopup={showPopup} />
);
const triggerButtonFrame = await utils.findByTitle(/portal-trigger/i);
const popupFrame = utils.queryByTitle(/portal-popup/i);
return {
ghostApi,
popupFrame,
triggerButtonFrame,
...utils
};
};
describe('Portal Data attributes:', () => {
beforeEach(() => {
// Mock global fetch
jest.spyOn(window, 'fetch').mockImplementation((url) => {
if (url.includes('send-magic-link')) {
return Promise.resolve({
ok: true,
json: async () => ({success: true})
});
}
if (url.includes('api/session')) {
return Promise.resolve({
ok: true,
text: async () => {
return 'session-identity';
}
});
}
if (url.includes('create-stripe-checkout-session')) {
return Promise.resolve({
ok: true,
json: async () => {
return {
publicKey: 'key-xyz'
};
}
});
}
return Promise.resolve({});
});
// Mock global Stripe
window.Stripe = () => {};
jest.spyOn(window, 'Stripe').mockImplementation(() => {
return {
redirectToCheckout: () => {
return Promise.resolve({});
}
};
});
// Mock window.location
let locationMock = jest.fn();
delete window.location;
window.location = {assign: locationMock};
window.location.href = (new URL('https://portal.localhost')).href;
window.location.hash = '';
});
afterEach(() => {
jest.restoreAllMocks();
});
describe('data-portal', () => {
test('opens default portal page', async () => {
document.body.innerHTML = `
<div data-portal> </div>
`;
let {
popupFrame, triggerButtonFrame, ...utils
} = await setup({
site: FixtureSite.singleTier.basic,
showPopup: false
});
expect(popupFrame).not.toBeInTheDocument();
expect(triggerButtonFrame).toBeInTheDocument();
const portalElement = document.querySelector('[data-portal]');
fireEvent.click(portalElement);
popupFrame = await utils.findByTitle(/portal-popup/i);
expect(popupFrame).toBeInTheDocument();
});
});
describe('data-portal=signin', () => {
test('opens Portal signin page', async () => {
document.body.innerHTML = `
<div data-portal="signin"> </div>
`;
let {
popupFrame, triggerButtonFrame, ...utils
} = await setup({
site: FixtureSite.singleTier.basic,
showPopup: false
});
expect(popupFrame).not.toBeInTheDocument();
expect(triggerButtonFrame).toBeInTheDocument();
const portalElement = document.querySelector('[data-portal]');
fireEvent.click(portalElement);
popupFrame = await utils.findByTitle(/portal-popup/i);
expect(popupFrame).toBeInTheDocument();
const loginTitle = within(popupFrame.contentDocument).queryByText(/log in/i);
expect(loginTitle).toBeInTheDocument();
});
});
describe('data-portal=signup', () => {
test('opens Portal signup page', async () => {
document.body.innerHTML = `
<div data-portal="signup"> </div>
`;
let {
popupFrame, triggerButtonFrame, ...utils
} = await setup({
site: FixtureSite.singleTier.basic,
showPopup: false
});
expect(popupFrame).not.toBeInTheDocument();
expect(triggerButtonFrame).toBeInTheDocument();
const portalElement = document.querySelector('[data-portal]');
fireEvent.click(portalElement);
popupFrame = await utils.findByTitle(/portal-popup/i);
expect(popupFrame).toBeInTheDocument();
const loginTitle = within(popupFrame.contentDocument).queryByText(/already a member/i);
expect(loginTitle).toBeInTheDocument();
});
});
describe('data-portal=account', () => {
test('opens Portal account home page', async () => {
document.body.innerHTML = `
<div data-portal="account"> </div>
`;
let {
popupFrame, triggerButtonFrame, ...utils
} = await setup({
site: FixtureSite.singleTier.basic,
member: FixtureMember.free,
showPopup: false
});
expect(popupFrame).not.toBeInTheDocument();
expect(triggerButtonFrame).toBeInTheDocument();
const portalElement = document.querySelector('[data-portal]');
fireEvent.click(portalElement);
popupFrame = await utils.findByTitle(/portal-popup/i);
expect(popupFrame).toBeInTheDocument();
const accountHomeTitle = within(popupFrame.contentDocument).queryByText(/your account/i);
expect(accountHomeTitle).toBeInTheDocument();
});
});
describe('data-portal=account/plans', () => {
test('opens Portal account plan page', async () => {
document.body.innerHTML = `
<div data-portal="account/plans"> </div>
`;
let {
popupFrame, triggerButtonFrame, ...utils
} = await setup({
site: FixtureSite.singleTier.basic,
member: FixtureMember.free,
showPopup: false
});
expect(popupFrame).not.toBeInTheDocument();
expect(triggerButtonFrame).toBeInTheDocument();
const portalElement = document.querySelector('[data-portal]');
fireEvent.click(portalElement);
popupFrame = await utils.findByTitle(/portal-popup/i);
expect(popupFrame).toBeInTheDocument();
const accountPlanTitle = within(popupFrame.contentDocument).queryByText(/choose a plan/i);
expect(accountPlanTitle).toBeInTheDocument();
});
});
describe('data-portal=account/profile', () => {
test('opens Portal account profile page', async () => {
document.body.innerHTML = `
<div data-portal="account/profile"> </div>
`;
let {
popupFrame, triggerButtonFrame, ...utils
} = await setup({
site: FixtureSite.singleTier.basic,
member: FixtureMember.free,
showPopup: false
});
expect(popupFrame).not.toBeInTheDocument();
expect(triggerButtonFrame).toBeInTheDocument();
const portalElement = document.querySelector('[data-portal]');
fireEvent.click(portalElement);
popupFrame = await utils.findByTitle(/portal-popup/i);
expect(popupFrame).toBeInTheDocument();
const accountProfileTitle = within(popupFrame.contentDocument).queryByText(/account settings/i);
expect(accountProfileTitle).toBeInTheDocument();
});
});
});