0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-06 22:40:14 -05:00

Refactored comments-ui admin moderation tests

no issue

- expanded e2e test behaviour to route Admin requests through our MockedApi instance so we have the same test experience for normal and admin comments requests
- extracted page route method bodies to enable request methods to be spied on
- updated admin moderation tests to properly use admin requests
This commit is contained in:
Kevin Ansfield 2024-11-26 14:26:35 +00:00
parent 6c064b73e4
commit cdea73b873
7 changed files with 349 additions and 439 deletions

View file

@ -126,11 +126,11 @@ const App: React.FC<AppProps> = ({scriptTag}) => {
} catch (e) {
// Loading of admin failed. Could be not signed in, or a different error (not important)
// eslint-disable-next-line no-console
console.warn(`[Comments] Failed to fetch current admin user:`, e);
console.warn(`[Comments] Failed to fetch admin endpoint:`, e);
}
setState({
adminApi: adminApi,
adminApi,
admin
});
} catch (e) {

View file

@ -23,11 +23,11 @@ const AdminContextMenu: React.FC<Props> = ({comment, close}) => {
<div className="flex w-full flex-col gap-0.5">
{
isHidden ?
<button className="w-full rounded px-2.5 py-1.5 text-left text-[14px] transition-colors hover:bg-neutral-100 dark:hover:bg-neutral-700" type="button" onClick={showComment}>
<button className="w-full rounded px-2.5 py-1.5 text-left text-[14px] transition-colors hover:bg-neutral-100 dark:hover:bg-neutral-700" data-testid="show-button" type="button" onClick={showComment}>
<span className="hidden sm:inline">{t('Show comment')}</span><span className="sm:hidden">{t('Show')}</span>
</button>
:
<button className="w-full rounded px-2.5 py-1.5 text-left text-[14px] text-red-600 transition-colors hover:bg-neutral-100 dark:text-red-500 dark:hover:bg-neutral-700" type="button" onClick={hideComment}>
<button className="w-full rounded px-2.5 py-1.5 text-left text-[14px] text-red-600 transition-colors hover:bg-neutral-100 dark:text-red-500 dark:hover:bg-neutral-700" data-testid="hide-button" type="button" onClick={hideComment}>
<span className="hidden sm:inline">{t('Hide comment')}</span><span className="sm:hidden">{t('Hide')}</span>
</button>
}

View file

@ -27,7 +27,8 @@ function setupGhostApi({siteUrl = window.location.origin, apiUrl, apiKey}: {site
return fetch(url, options);
}
// To fix pagination when we create new comments (or people post comments after you loaded the page, we need to only load comments creatd AFTER the page load)
// To fix pagination when we create new comments (or people post comments
// after you loaded the page), we need to only load comments created AFTER the page load
let firstCommentCreatedAt: null | string = null;
const api = {

View file

@ -0,0 +1,173 @@
import sinon from 'sinon';
import {MOCKED_SITE_URL, MockedApi, initialize, mockAdminAuthFrame, mockAdminAuthFrame204} from '../utils/e2e';
import {expect, test} from '@playwright/test';
const admin = MOCKED_SITE_URL + '/ghost/';
test.describe('Admin moderation', async () => {
let mockedApi: MockedApi;
test.beforeEach(async ({}) => {
mockedApi = new MockedApi({});
});
type InitializeTestOptions = {
isAdmin?: boolean;
labs?: boolean;
member?: any; // eslint-disable-line @typescript-eslint/no-explicit-any
};
async function initializeTest(page, options: InitializeTestOptions = {}) {
options = {isAdmin: true, labs: false, member: {id: '1'}, ...options};
if (options.isAdmin) {
await mockAdminAuthFrame({page, admin});
} else {
await mockAdminAuthFrame204({page, admin});
}
mockedApi.setMember(options.member);
if (options.labs) {
mockedApi.setLabs({commentImprovements: true});
}
return await initialize({
mockedApi,
page,
publication: 'Publisher Weekly',
admin,
labs: {
commentImprovements: options.labs
}
});
}
test('skips rendering the auth frame with no comments', async ({page}) => {
await initializeTest(page);
const iframeElement = page.locator('iframe[data-frame="admin-auth"]');
await expect(iframeElement).toHaveCount(0);
});
test('renders the auth frame when there are comments', async ({page}) => {
mockedApi.addComment({html: '<p>This is comment 1</p>'});
await initializeTest(page);
const iframeElement = page.locator('iframe[data-frame="admin-auth"]');
await expect(iframeElement).toHaveCount(1);
});
test('has no admin options when not signed in to Ghost admin or as member', async ({page}) => {
mockedApi.addComment({html: '<p>This is comment 1</p>'});
const {frame} = await initializeTest(page, {isAdmin: false, member: null});
await expect(frame.getByTestId('more-button')).toHaveCount(0);
});
test('has no admin options when not signed in to Ghost admin but signed in as member', async ({page}) => {
mockedApi.addComment({html: '<p>This is comment 1</p>'});
const {frame} = await initializeTest(page, {isAdmin: false, member: {id: '2'}});
// more button shows because it has a report button
await expect(frame.getByTestId('more-button')).toHaveCount(1);
await frame.getByTestId('more-button').nth(0).click();
await expect(frame.getByTestId('hide-button')).not.toBeVisible();
});
test('has admin options when signed in to Ghost admin but not signed in as member', async ({page}) => {
mockedApi.addComment({html: `<p>This is comment 1</p>`});
const {frame} = await initializeTest(page, {member: null});
const moreButtons = frame.getByTestId('more-button');
await expect(moreButtons).toHaveCount(1);
// Admin buttons should be visible
await moreButtons.nth(0).click();
await expect(frame.getByTestId('hide-button')).toBeVisible();
});
test('has admin options when signed in to Ghost admin and as a member', async ({page}) => {
mockedApi.addComment({html: `<p>This is comment 1</p>`});
const {frame} = await initializeTest(page);
const moreButtons = frame.getByTestId('more-button');
await expect(moreButtons).toHaveCount(1);
// Admin buttons should be visible
await moreButtons.nth(0).click();
await expect(frame.getByTestId('hide-button')).toBeVisible();
});
test('can hide and show comments', async ({page}) => {
mockedApi.addComment({html: '<p>This is comment 1</p>'});
mockedApi.addComment({html: '<p>This is comment 2</p>'});
const {frame} = await initializeTest(page);
// Click the hide button for 2nd comment
const moreButtons = frame.getByTestId('more-button');
await moreButtons.nth(1).click();
await moreButtons.nth(1).getByTestId('hide-button').click();
// comment becomes hidden
const comments = frame.getByTestId('comment-component');
const secondComment = comments.nth(1);
await expect(secondComment).toContainText('This comment has been hidden.');
await expect(secondComment).not.toContainText('This is comment 2');
// can show it again
await moreButtons.nth(1).click();
await moreButtons.nth(1).getByTestId('show-button').click();
await expect(secondComment).toContainText('This is comment 2');
});
test.describe('commentImprovements', function () {
test('hidden comments are not displayed for non-admins', async ({page}) => {
mockedApi.addComment({html: '<p>This is comment 1</p>'});
mockedApi.addComment({html: '<p>This is comment 2</p>', status: 'hidden'});
const adminBrowseSpy = sinon.spy(mockedApi.adminRequestHandlers, 'browseComments');
const {frame} = await initializeTest(page, {isAdmin: false, labs: true});
const comments = await frame.getByTestId('comment-component');
await expect(comments).toHaveCount(1);
expect(adminBrowseSpy.called).toBe(false);
});
test('hidden comments are displayed for admins', async ({page}) => {
mockedApi.addComment({html: '<p>This is comment 1</p>'});
mockedApi.addComment({html: '<p>This is comment 2</p>', status: 'hidden'});
const adminBrowseSpy = sinon.spy(mockedApi.adminRequestHandlers, 'browseComments');
const {frame} = await initializeTest(page, {labs: true});
const comments = await frame.getByTestId('comment-component');
await expect(comments).toHaveCount(2);
await expect(comments.nth(1)).toContainText('Hidden for members');
expect(adminBrowseSpy.called).toBe(true);
});
test('can hide and show comments', async ({page}) => {
[1,2].forEach(i => mockedApi.addComment({html: `<p>This is comment ${i}</p>`}));
const {frame} = await initializeTest(page, {labs: true});
const comments = await frame.getByTestId('comment-component');
// Hide the 2nd comment
const moreButtons = frame.getByTestId('more-button');
await moreButtons.nth(1).click();
await moreButtons.nth(1).getByText('Hide comment').click();
const secondComment = comments.nth(1);
await expect(secondComment).toContainText('Hidden for members');
// Check can show it again
await moreButtons.nth(1).click();
await moreButtons.nth(1).getByText('Show comment').click();
await expect(secondComment).toContainText('This is comment 2');
});
});
});

View file

@ -1,344 +0,0 @@
import {MOCKED_SITE_URL, MockedApi, initialize, mockAdminAuthFrame, mockAdminAuthFrame204} from '../utils/e2e';
import {expect, test} from '@playwright/test';
const admin = MOCKED_SITE_URL + '/ghost/';
test.describe('Auth Frame', async () => {
test('skips rendering the auth frame with no comments', async ({page}) => {
const mockedApi = new MockedApi({});
await initialize({
mockedApi,
page,
publication: 'Publisher Weekly',
admin
});
const iframeElement = await page.locator('iframe[data-frame="admin-auth"]');
await expect(iframeElement).toHaveCount(0);
});
test('renders the auth frame when there are comments', async ({page}) => {
const mockedApi = new MockedApi({});
mockedApi.addComment({
html: '<p>This is comment 1</p>'
});
await initialize({
mockedApi,
page,
publication: 'Publisher Weekly',
admin
});
const iframeElement = await page.locator('iframe[data-frame="admin-auth"]');
await expect(iframeElement).toHaveCount(1);
});
test('has no admin options when not signed in to Ghost admin', async ({page}) => {
await mockAdminAuthFrame204({page, admin});
const mockedApi = new MockedApi({});
mockedApi.addComment({
html: '<p>This is comment 1</p>'
});
mockedApi.addComment({
html: '<p>This is comment 2</p>'
});
mockedApi.addComment({
html: '<p>This is comment 3</p>'
});
mockedApi.addComment({
html: '<p>This is comment 4</p>'
});
mockedApi.addComment({
html: '<p>This is comment 5</p>'
});
const {frame} = await initialize({
mockedApi,
page,
publication: 'Publisher Weekly',
admin
});
const iframeElement = await page.locator('iframe[data-frame="admin-auth"]');
await expect(iframeElement).toHaveCount(1);
const comments = await frame.getByTestId('comment-component');
await expect(comments).toHaveCount(5);
const moreButtons = await frame.getByTestId('more-button');
await expect(moreButtons).toHaveCount(0);
});
test('has admin options when signed in to Ghost admin', async ({page}) => {
const mockedApi = new MockedApi({});
mockedApi.addComment({
html: '<p>This is comment 1</p>'
});
mockedApi.addComment({
html: '<p>This is comment 2</p>'
});
mockedApi.addComment({
html: '<p>This is comment 3</p>'
});
mockedApi.addComment({
html: '<p>This is comment 4</p>'
});
mockedApi.addComment({
html: '<p>This is comment 5</p>'
});
await mockAdminAuthFrame({
admin,
page
});
const {frame} = await initialize({
mockedApi,
page,
publication: 'Publisher Weekly',
admin
});
const iframeElement = await page.locator('iframe[data-frame="admin-auth"]');
await expect(iframeElement).toHaveCount(1);
// Check if more actions button is visible on each comment
const comments = await frame.getByTestId('comment-component');
await expect(comments).toHaveCount(5);
const moreButtons = await frame.getByTestId('more-button');
await expect(moreButtons).toHaveCount(5);
// Click the 2nd button
await moreButtons.nth(1).click();
await moreButtons.nth(1).getByText('Hide comment').click();
// Check comment2 is replaced with a hidden message
const secondComment = comments.nth(1);
await expect(secondComment).toContainText('This comment has been hidden.');
await expect(secondComment).not.toContainText('This is comment 2');
// Check can show it again
await moreButtons.nth(1).click();
await moreButtons.nth(1).getByText('Show comment').click();
await expect(secondComment).toContainText('This is comment 2');
});
test('has admin options when signed in to Ghost admin and as a member', async ({page}) => {
const mockedApi = new MockedApi({});
mockedApi.setMember({});
mockedApi.addComment({
html: '<p>This is comment 1</p>'
});
mockedApi.addComment({
html: '<p>This is comment 2</p>'
});
mockedApi.addComment({
html: '<p>This is comment 3</p>'
});
mockedApi.addComment({
html: '<p>This is comment 4</p>'
});
mockedApi.addComment({
html: '<p>This is comment 5</p>'
});
await mockAdminAuthFrame({
admin,
page
});
const {frame} = await initialize({
mockedApi,
page,
publication: 'Publisher Weekly',
admin
});
const iframeElement = await page.locator('iframe[data-frame="admin-auth"]');
await expect(iframeElement).toHaveCount(1);
// Check if more actions button is visible on each comment
const comments = await frame.getByTestId('comment-component');
await expect(comments).toHaveCount(5);
const moreButtons = await frame.getByTestId('more-button');
await expect(moreButtons).toHaveCount(5);
// Click the 2nd button
await moreButtons.nth(1).click();
await moreButtons.nth(1).getByText('Hide comment').click();
// Check comment2 is replaced with a hidden message
const secondComment = comments.nth(1);
await expect(secondComment).toContainText('This comment has been hidden.');
await expect(secondComment).not.toContainText('This is comment 2');
// Check can show it again
await moreButtons.nth(1).click();
await moreButtons.nth(1).getByText('Show comment').click();
await expect(secondComment).toContainText('This is comment 2');
});
test('Hidden comment is displayed for admins - needs flags enabled', async ({page}) => {
const mockedApi = new MockedApi({});
mockedApi.addComment({
html: '<p>This is comment 1</p>'
});
mockedApi.addComment({
html: '<p>This is comment 2</p>'
});
mockedApi.addComment({
html: '<p>This is comment 3</p>'
});
mockedApi.addComment({
html: '<p>This is comment 4</p>'
});
mockedApi.addComment({
html: '<p>This is comment 5</p>'
});
await mockAdminAuthFrame({
admin,
page
});
const {frame} = await initialize({
mockedApi,
page,
publication: 'Publisher Weekly',
admin,
labs: {
commentImprovements: true
}
});
const iframeElement = await page.locator('iframe[data-frame="admin-auth"]');
await expect(iframeElement).toHaveCount(1);
// Check if more actions button is visible on each comment
const comments = await frame.getByTestId('comment-component');
await expect(comments).toHaveCount(5);
const moreButtons = await frame.getByTestId('more-button');
await expect(moreButtons).toHaveCount(5);
// Click the 2nd button
await moreButtons.nth(1).click();
await moreButtons.nth(1).getByText('Hide comment').click();
const secondComment = comments.nth(1);
// expect "hidden for members" message
await expect(secondComment).toContainText('Hidden for members');
// Check can show it again
await moreButtons.nth(1).click();
await moreButtons.nth(1).getByText('Show comment').click();
await expect(secondComment).toContainText('This is comment 2');
});
test('authFrameMain fires getUser (exposed function)', async ({page}) => {
const mockedApi = new MockedApi({});
mockedApi.addComment({
html: '<p>This is comment 1</p>'
});
mockedApi.addComment({
html: '<p>This is comment 2</p>'
});
mockedApi.addComment({
html: '<p>This is comment 3</p>'
});
mockedApi.addComment({
html: '<p>This is comment 4</p>'
});
mockedApi.addComment({
html: '<p>This is comment 5</p>'
});
const actions: string[] = [];
await page.exposeFunction('__testHelper', (action: string) => {
actions.push(action);
});
await mockAdminAuthFrame({
admin,
page
});
await initialize({
mockedApi,
page,
publication: 'Publisher Weekly',
admin,
labs: {
commentImprovements: true
}
});
// Trigger the message event
await page.evaluate(() => {
const event = new MessageEvent('message', {
data: JSON.stringify({uid: 'test', action: 'getUser'}),
origin: 'https://localhost:1234'
});
window.dispatchEvent(event);
});
// Validate that "getUser" was captured
expect(actions).toContain('getUser');
});
test('fires admin read when making a hidden comment visible', async ({page}) => {
const mockedApi = new MockedApi({});
mockedApi.addComment({
html: '<p>This is comment 1</p>'
});
mockedApi.addComment({
html: '<p>This is comment 2</p>',
status: 'hidden'
});
const actions: string[] = [];
await page.exposeFunction('__testHelper', (action: string) => {
actions.push(action);
});
await mockAdminAuthFrame({
admin,
page
});
const {frame} = await initialize({
mockedApi,
page,
publication: 'Publisher Weekly',
admin,
labs: {
commentImprovements: true
}
});
const iframeElement = await page.locator('iframe[data-frame="admin-auth"]');
await expect(iframeElement).toHaveCount(1);
// Check if more actions button is visible on each comment
const comments = await frame.getByTestId('comment-component');
await expect(comments).toHaveCount(2);
const moreButtons = await frame.getByTestId('more-button');
await expect(moreButtons).toHaveCount(2);
// Click the 2nd button
await moreButtons.nth(1).click();
await moreButtons.nth(1).getByText('Show comment').click();
await expect(actions).toContain('readComment');
});
});

View file

@ -7,6 +7,8 @@ const htmlToPlaintext = (html) => {
return html.replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').trim();
};
/* eslint-disable @typescript-eslint/no-explicit-any */
export class MockedApi {
comments: any[];
postId: string;
@ -15,19 +17,22 @@ export class MockedApi {
members: any[];
delay: number;
labs: any;
#lastCommentDate = new Date('2021-01-01T00:00:00.000Z');
#findReplyById(id: string) {
return this.comments.flatMap(c => c.replies).find(r => r.id === id);
}
constructor({postId = 'ABC', comments = [], member = undefined, settings = {}, members = []}: {postId?: string, comments?: any[], member?: any, settings?: any, members?: any[]}) {
constructor({postId = 'ABC', comments = [], member = undefined, settings = {}, members = [], labs = {}}: {postId?: string, comments?: any[], member?: any, settings?: any, members?: any[], labs?: any}) {
this.postId = postId;
this.comments = comments;
this.member = member;
this.settings = settings;
this.members = [];
this.delay = 0;
this.labs = labs;
}
setDelay(delay: number) {
@ -77,7 +82,11 @@ export class MockedApi {
}
setMember(overrides) {
this.member = buildMember(overrides);
if (overrides === null) {
this.member = null;
} else {
this.member = buildMember(overrides);
}
}
logoutMember() {
@ -88,13 +97,17 @@ export class MockedApi {
this.settings = buildSettings(overrides);
}
setLabs(overrides) {
this.labs = overrides;
}
commentsCounts() {
return {
[this.postId]: this.comments.length
};
}
browseComments({limit = 5, filter, page, order}: {limit?: number, filter?: string, page: number, order?: string}) {
browseComments({limit = 5, filter, page, order, admin}: {limit?: number, filter?: string, page: number, order?: string, admin?: boolean}) {
// Sort comments on created at + id
const setOrder = order || 'default';
@ -145,10 +158,20 @@ export class MockedApi {
let filteredComments = this.comments;
if (this.labs.commentImprovements && !admin) {
function filterPublishedComments(comments: any[] = []) {
return comments
.filter(comment => comment.status === 'published')
.map(comment => ({...comment, replies: filterPublishedComments(comment.replies)}));
}
filteredComments = filterPublishedComments(this.comments);
}
// Parse NQL filter
if (filter) {
const parsed = nql(filter);
filteredComments = this.comments.filter((comment) => {
filteredComments = filteredComments.filter((comment) => {
return parsed.queryJSON(comment);
});
}
@ -232,8 +255,11 @@ export class MockedApi {
});
}
async listen({page, path}: {page: any, path: string}) {
await page.route(`${path}/members/api/member/`, async (route) => {
// Request handlers ------------------------------------------------------
// (useful to spy on these methods in tests)
requestHandlers = {
async getMember(route) {
await this.#delayResponse();
if (!this.member) {
return await route.fulfill({
@ -254,9 +280,9 @@ export class MockedApi {
status: 200,
body: JSON.stringify(this.member)
});
});
},
await page.route(`${path}/members/api/comments/*`, async (route) => {
async addComment(route) {
await this.#delayResponse();
const payload = JSON.parse(route.request().postData());
@ -273,9 +299,9 @@ export class MockedApi {
]
})
});
});
},
await page.route(`${path}/members/api/comments/post/*/*`, async (route) => {
async browseComments(route) {
await this.#delayResponse();
const url = new URL(route.request().url());
@ -292,10 +318,25 @@ export class MockedApi {
order
}))
});
});
},
// LIKE a single comment
await page.route(`${path}/members/api/comments/*/like/`, async (route) => {
async getComment(route) {
await this.#delayResponse();
const url = new URL(route.request().url());
const commentId = url.pathname.split('/').reverse()[1];
await route.fulfill({
status: 200,
body: JSON.stringify(this.browseComments({
limit: 1,
filter: `id:'${commentId}'`,
page: 1,
order: ''
}))
});
},
async likeComment(route) {
await this.#delayResponse();
const url = new URL(route.request().url());
const commentId = url.pathname.split('/').reverse()[2];
@ -327,26 +368,9 @@ export class MockedApi {
order: ''
}))
});
});
},
// GET a single comment
await page.route(`${path}/members/api/comments/*/`, async (route) => {
await this.#delayResponse();
const url = new URL(route.request().url());
const commentId = url.pathname.split('/').reverse()[1];
await route.fulfill({
status: 200,
body: JSON.stringify(this.browseComments({
limit: 1,
filter: `id:'${commentId}'`,
page: 1,
order: ''
}))
});
});
await page.route(`${path}/members/api/comments/*/replies/*`, async (route) => {
async getReplies(route) {
await this.#delayResponse();
const url = new URL(route.request().url());
@ -362,9 +386,9 @@ export class MockedApi {
commentId
}))
});
});
},
await page.route(`${path}/members/api/comments/counts/*`, async (route) => {
async getCommentCounts(route) {
await this.#delayResponse();
await route.fulfill({
status: 200,
@ -372,16 +396,89 @@ export class MockedApi {
this.commentsCounts()
)
});
});
},
// get settings from content api
await page.route(`${path}/settings/*`, async (route) => {
async getSettings(route) {
await this.#delayResponse();
await route.fulfill({
status: 200,
body: JSON.stringify(this.settings)
});
});
}
};
adminRequestHandlers = {
async getUser(route) {
await this.#delayResponse();
await route.fulfill({
status: 200,
body: JSON.stringify({
users: [{
id: '1'
}]
})
});
},
async browseComments(route) {
await this.#delayResponse();
const url = new URL(route.request().url());
const p = parseInt(url.searchParams.get('page') ?? '1');
const limit = parseInt(url.searchParams.get('limit') ?? '5');
const filter = url.searchParams.get('filter') ?? '';
const order = url.searchParams.get('order') ?? '';
await route.fulfill({
status: 200,
body: JSON.stringify(this.browseComments({
page: p,
limit,
filter,
order,
admin: true
}))
});
},
async updateComment(route) {
await this.#delayResponse();
const url = new URL(route.request().url());
if (route.request().method() === 'PUT') {
const commentId = url.pathname.split('/').reverse()[1];
const payload = JSON.parse(route.request().postData());
const comment = this.comments.find(c => c.id === commentId);
comment.status = payload.status;
await route.fulfill({
status: 200,
body: JSON.stringify(this.browseComments({
limit: 1,
filter: `id:'${commentId}'`,
page: 1,
order: ''
}))
});
}
}
};
async listen({page, path}: {page: any, path: string}) {
// Public API ----------------------------------------------------------
await page.route(`${path}/members/api/member/`, this.requestHandlers.getMember.bind(this));
await page.route(`${path}/members/api/comments/*`, this.requestHandlers.addComment.bind(this));
await page.route(`${path}/members/api/comments/post/*/*`, this.requestHandlers.browseComments.bind(this));
await page.route(`${path}/members/api/comments/*/`, this.requestHandlers.getComment.bind(this));
await page.route(`${path}/members/api/comments/*/like/`, this.requestHandlers.likeComment.bind(this));
await page.route(`${path}/members/api/comments/*/replies/*`, this.requestHandlers.getReplies.bind(this));
await page.route(`${path}/members/api/comments/counts/*`, this.requestHandlers.getCommentCounts.bind(this));
await page.route(`${path}/settings/*`, this.requestHandlers.getSettings.bind(this));
// Admin API -----------------------------------------------------------
await page.route(`${path}/ghost/api/admin/users/me/`, this.adminRequestHandlers.getUser.bind(this));
await page.route(`${path}/ghost/api/admin/comments/post/*/*`, this.adminRequestHandlers.browseComments.bind(this));
await page.route(`${path}/ghost/api/admin/comments/*/`, this.adminRequestHandlers.updateComment.bind(this));
}
}

View file

@ -21,74 +21,57 @@ function escapeHtml(unsafe: string) {
.replace(/>/g, '&gt;');
}
declare global {
interface Window {
__testHelper?: (action: string) => void;
}
}
function authFrameMain() {
window.addEventListener('message', function (event) {
let d = null;
const endpoints = {
browseComments: ['GET', ['postId'], '/comments/post/$1/'],
getReplies: ['GET', ['commentId'], '/comments/$1/replies/'],
readComment: ['GET', ['commentId'], '/comments/$1/'],
getUser: ['GET', [], '/users/me/'],
hideComment: ['PUT', ['id'], '/comments/$1/', data => ({id: data.id, status: 'hidden'})],
showComment: ['PUT', ['id'], '/comments/$1/', data => ({id: data.id, status: 'published'})]
};
window.addEventListener('message', async function (event) {
let data: any = null; // eslint-disable-line @typescript-eslint/no-explicit-any
try {
d = JSON.parse(event.data);
data = JSON.parse(event.data) || {};
} catch (err) {
console.error(err);
console.error(err); // eslint-disable-line no-console
}
if (!d) {
if (!data) {
return;
}
const data: {uid: string, action: string} = d;
function respond(error, result) {
event.source!.postMessage(JSON.stringify({
uid: data.uid,
error: error,
result: result
error: error?.message,
result
}));
}
if (data.action === 'getUser') {
if (window.__testHelper) {
window.__testHelper('getUser');
}
if (endpoints[data.action]) {
try {
respond(null, {
users: [
{
id: 'someone'
}
]
});
const [method, routeParams, route, bodyFn] = endpoints[data.action];
const paramData = routeParams.map(param => data[param]);
const path = route.replace(/\$(\d+)/g, (_, index) => paramData[index - 1]);
const url = new URL(`/ghost/api/admin${path}`, MOCKED_SITE_URL);
if (data.params) {
url.search = new URLSearchParams(data.params).toString();
}
let body, headers;
if (method === 'PUT' || method === 'POST') {
body = JSON.stringify(bodyFn(data));
headers = {'Content-Type': 'application/json'};
}
const res = await fetch(url, {method, body, headers});
const json = await res.json();
respond(null, json);
} catch (err) {
console.log('e2e Admin endpoint error:', err); // eslint-disable-line no-console
respond(err, null);
}
return;
}
if (data.action === 'readComment') {
if (window.__testHelper) {
window.__testHelper('readComment');
}
try {
respond(null, {
comment: {
id: 'comment-id',
html: '<p>This is a comment</p>'
}
});
} catch (err) {
respond(err, null);
}
return;
}
// Other actions: return empty object
try {
respond(null, {});
} catch (err) {
respond(err, null);
}
});
}
@ -97,7 +80,7 @@ export async function mockAdminAuthFrame({admin, page}) {
await page.route(admin + 'auth-frame/', async (route) => {
await route.fulfill({
status: 200,
body: `<html><head><meta charset="UTF-8" /></head><body><script>${authFrameMain.toString()}; authFrameMain();</script></body></html>`
body: `<html><head><meta charset="UTF-8" /></head><body><script>${authFrameMain.toString().replaceAll('MOCKED_SITE_URL', `'${MOCKED_SITE_URL}'`)}; authFrameMain();</script></body></html>`
});
});
}