mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-05 09:50:34 +03:00
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:
parent
58f2025038
commit
98f212c3df
@ -99,9 +99,6 @@ export default class App extends React.Component {
|
|||||||
|
|
||||||
/** Setup custom trigger buttons handling on page */
|
/** Setup custom trigger buttons handling on page */
|
||||||
setupCustomTriggerButton() {
|
setupCustomTriggerButton() {
|
||||||
if (hasMode(['test'])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Handler for custom buttons
|
// Handler for custom buttons
|
||||||
this.clickHandler = (event) => {
|
this.clickHandler = (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@ -217,7 +214,7 @@ export default class App extends React.Component {
|
|||||||
// Setup test mode data
|
// Setup test mode data
|
||||||
if (hasMode(['test'])) {
|
if (hasMode(['test'])) {
|
||||||
return {
|
return {
|
||||||
showPopup: true
|
showPopup: this.props.showPopup !== undefined ? this.props.showPopup : true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
|
import App from '../App';
|
||||||
import {site as FixturesSite, member as FixtureMember} from '../utils/test-fixtures';
|
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');
|
const {formSubmitHandler, planClickHandler} = require('../data-attributes');
|
||||||
|
|
||||||
// Mock data
|
// Mock data
|
||||||
@ -68,7 +72,7 @@ function getMockData() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('Data attributes:', () => {
|
describe('Member Data attributes:', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// Mock global fetch
|
// Mock global fetch
|
||||||
jest.spyOn(window, 'fetch').mockImplementation((url) => {
|
jest.spyOn(window, 'fetch').mockImplementation((url) => {
|
||||||
@ -120,55 +124,279 @@ describe('Data attributes:', () => {
|
|||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.restoreAllMocks();
|
jest.restoreAllMocks();
|
||||||
});
|
});
|
||||||
test('data-members-form: allows free signup', () => {
|
describe('data-members-form', () => {
|
||||||
const {event, form, errorEl, siteUrl, submitHandler} = getMockData();
|
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 () => {
|
describe('data-members-plan', () => {
|
||||||
const {event, errorEl, siteUrl, clickHandler, site, member, element} = getMockData();
|
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 paidTier = site.products.find(p => p.type === 'paid');
|
||||||
const plan = paidTier.monthlyPrice.id;
|
const plan = paidTier.monthlyPrice.id;
|
||||||
|
|
||||||
await planClickHandler({event, errorEl, siteUrl, clickHandler, site, member, el: element});
|
await planClickHandler({event, errorEl, siteUrl, clickHandler, site, member, el: element});
|
||||||
expect(window.fetch).toHaveBeenNthCalledWith(1,
|
expect(window.fetch).toHaveBeenNthCalledWith(1,
|
||||||
'https://portal.localhost/members/api/session', {
|
'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'
|
credentials: 'same-origin'
|
||||||
}
|
});
|
||||||
);
|
expect(window.fetch).toHaveBeenNthCalledWith(2, 'https://portal.localhost/members/api/create-stripe-checkout-session/', {
|
||||||
expect(window.fetch).toHaveBeenNthCalledWith(2,
|
body: `{"priceId":"${plan}","identity":"session-identity","successUrl":"https://portal.localhost/success","cancelUrl":"https://portal.localhost/cancel","metadata":{"checkoutType":"upgrade"}}`,
|
||||||
'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: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
method: 'POST'
|
method: 'POST'
|
||||||
}
|
});
|
||||||
);
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
test('data-members-plan: allows free member upgrade via direct checkout', async () => {
|
|
||||||
let {event, errorEl, siteUrl, clickHandler, site, member, element} = getMockData();
|
const setup = async ({site, member = null, showPopup = true}) => {
|
||||||
member = FixtureMember.free;
|
const ghostApi = setupGhostApi({siteUrl: 'https://example.com'});
|
||||||
const paidTier = site.products.find(p => p.type === 'paid');
|
ghostApi.init = jest.fn(() => {
|
||||||
const plan = paidTier.monthlyPrice.id;
|
return Promise.resolve({
|
||||||
|
site,
|
||||||
await planClickHandler({event, errorEl, siteUrl, clickHandler, site, member, el: element});
|
member
|
||||||
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/', {
|
ghostApi.member.sendMagicLink = jest.fn(() => {
|
||||||
body: `{"priceId":"${plan}","identity":"session-identity","successUrl":"https://portal.localhost/success","cancelUrl":"https://portal.localhost/cancel","metadata":{"checkoutType":"upgrade"}}`,
|
return Promise.resolve('success');
|
||||||
headers: {
|
});
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
ghostApi.member.checkoutPlan = jest.fn(() => {
|
||||||
method: 'POST'
|
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();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user