0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-10 23:36:14 -05:00

Added first basic comments test

This commit is contained in:
Simon Backx 2022-08-11 16:40:04 +02:00
parent 3b7d26154e
commit fd21a88d52
6 changed files with 85 additions and 65 deletions

View file

@ -1,8 +1,7 @@
import Frame from './components/Frame'; import Frame from './components/Frame';
import * as Sentry from '@sentry/react';
import React from 'react'; import React from 'react';
import ActionHandler from './actions'; import ActionHandler from './actions';
import {createPopupNotification,isSentryEventAllowed} from './utils/helpers'; import {createPopupNotification} from './utils/helpers';
import AppContext from './AppContext'; import AppContext from './AppContext';
import {hasMode} from './utils/check-mode'; import {hasMode} from './utils/check-mode';
import setupGhostApi from './utils/api'; import setupGhostApi from './utils/api';
@ -21,20 +20,14 @@ function AuthFrame({adminUrl, onLoad}) {
function CommentsBoxContainer({done, appVersion}) { function CommentsBoxContainer({done, appVersion}) {
return ( return (
<Frame> <Frame title="comments-box">
<CommentsBox done={done} /> <CommentsBox done={done} />
</Frame> </Frame>
); );
} }
function SentryErrorBoundary({dsn, children}) { function SentryErrorBoundary({dsn, children}) {
if (dsn) { // todo: add Sentry.ErrorBoundary wrapper if Sentry is enabled
return (
<Sentry.ErrorBoundary>
{children}
</Sentry.ErrorBoundary>
);
}
return ( return (
<> <>
{children} {children}
@ -68,11 +61,10 @@ export default class App extends React.Component {
async initSetup() { async initSetup() {
try { try {
// Fetch data from API, links, preview, dev sources // Fetch data from API, links, preview, dev sources
const {site, member} = await this.fetchApiData(); const {member} = await this.fetchApiData();
const {comments, pagination, count} = await this.fetchComments(); const {comments, pagination, count} = await this.fetchComments();
const state = { const state = {
site,
member, member,
action: 'init:success', action: 'init:success',
initStatus: 'success', initStatus: 'success',
@ -159,10 +151,10 @@ export default class App extends React.Component {
try { try {
this.GhostApi = this.props.api || setupGhostApi({siteUrl, apiUrl, apiKey}); this.GhostApi = this.props.api || setupGhostApi({siteUrl, apiUrl, apiKey});
const {site, member} = await this.GhostApi.init(); const {member} = await this.GhostApi.init();
this.setupSentry({site}); this.setupSentry();
return {site, member}; return {member};
} catch (e) { } catch (e) {
if (hasMode(['dev', 'test'], {customSiteUrl})) { if (hasMode(['dev', 'test'], {customSiteUrl})) {
return {}; return {};
@ -254,30 +246,8 @@ export default class App extends React.Component {
} }
/** Setup Sentry */ /** Setup Sentry */
setupSentry({site}) { setupSentry() {
if (hasMode(['test'])) { // Not implemented yet
return null;
}
const {portal_sentry: portalSentry, portal_version: portalVersion, version: ghostVersion} = site;
const appVersion = process.env.REACT_APP_VERSION || portalVersion;
const releaseTag = `comments@${appVersion}|ghost@${ghostVersion}`;
if (portalSentry && portalSentry.dsn) {
Sentry.init({
dsn: portalSentry.dsn,
environment: portalSentry.env || 'development',
release: releaseTag,
beforeSend: (event) => {
if (isSentryEventAllowed({event})) {
return event;
}
return null;
},
allowUrls: [
/https?:\/\/((www)\.)?unpkg\.com\/@tryghost\/comments/,
/https?:\/\/((cdn)\.)?jsdelivr\.net\/npm\/@tryghost\/comments/
]
});
}
} }
/**Get final App level context from App state*/ /**Get final App level context from App state*/

View file

@ -1,8 +1,78 @@
import {render} from '@testing-library/react'; import {render, within} from '@testing-library/react';
import App from './App'; import App from './App';
import {ROOT_DIV_ID} from './utils/constants';
test('renders the auth frame', () => { /*test('renders the auth frame', () => {
const {container} = render(<App />); const {container} = render(<App />);
const iframeElement = container.querySelector('iframe[data-frame="admin-auth"]'); const iframeElement = container.querySelector('iframe[data-frame="admin-auth"]');
expect(iframeElement).toBeInTheDocument(); expect(iframeElement).toBeInTheDocument();
});*/
describe('Dark mode', () => {
it.todo('uses dark mode when container has a dark background');
it.todo('uses light mode when container has a light background');
it.todo('uses custom mode when custom mode has been passed as a property');
});
describe('Comments', () => {
it('renders comments', async () => {
const postId = 'my-post';
const member = null;
const api = {
init: async () => {
return {
member
};
},
comments: {
count: async () => {
return {
[postId]: 1
};
},
browse: async () => {
return {
comments: [
{
id: 'test',
html: '<p>This is a comment body</p>',
replies: [],
count: {
replies: 0,
likes: 0
},
liked: false,
created_at: '2022-08-11T09:26:34.000Z',
edited_at: null,
member: {
avatar_image: '',
bio: 'Hello world codoof',
id: '62d6c6564a14e6a4b5e97c43',
name: 'dtt2',
uuid: '613e9667-4fa2-4ff4-aa62-507220103d41'
},
status: 'published'
}
],
meta: {
pagination: {
total: 1,
next: null,
prev: null,
page: 1
}
}
};
}
}
};
const stylesUrl = '';
const {container} = render(<div><div id={ROOT_DIV_ID}></div><App api={api} stylesUrl={stylesUrl}/></div>);
const iframeElement = container.querySelector('iframe[title="comments-box"]');
expect(iframeElement).toBeInTheDocument();
const iframeDocument = iframeElement.contentDocument;
const commentBody = await within(iframeDocument).findByText(/This is a comment body/i);
expect(commentBody).toBeInTheDocument();
});
}); });

View file

@ -81,7 +81,7 @@ const CommentsBoxContent = (props) => {
<> <>
<CommentsBoxTitle title={title} showCount={showCount} count={commentCount}/> <CommentsBoxTitle title={title} showCount={showCount} count={commentCount}/>
<Pagination /> <Pagination />
<div className={!pagination ? 'mt-4' : ''}> <div className={!pagination ? 'mt-4' : ''} data-test="comment-elements">
{commentsElements} {commentsElements}
</div> </div>
<div> <div>

View file

@ -49,7 +49,7 @@ const Frame = ({
}); });
}; };
const [cssLoaded, setCssLoaded] = useState(false); const [cssLoaded, setCssLoaded] = useState(!stylesUrl);
const onLoadCSS = () => { const onLoadCSS = () => {
setCssLoaded(true); setCssLoaded(true);
@ -57,7 +57,7 @@ const Frame = ({
const head = ( const head = (
<> <>
<link rel="stylesheet" href={stylesUrl} onLoad={onLoadCSS} /> {stylesUrl ? <link rel="stylesheet" href={stylesUrl} onLoad={onLoadCSS} /> : null}
<style dangerouslySetInnerHTML={{__html: styles}} /> <style dangerouslySetInnerHTML={{__html: styles}} />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
</> </>

View file

@ -259,20 +259,8 @@ function setupGhostApi({siteUrl = window.location.origin, apiUrl, apiKey}) {
let [member] = await Promise.all([ let [member] = await Promise.all([
api.member.sessionData() api.member.sessionData()
]); ]);
let site = {};
let settings = {};
try { return {member};
// for now we don't need to fetch all the settings (the ones we need are passed via the script tag data attributes)
//settings = await api.site.settings();
site = {
...settings
};
} catch (e) {
// Ignore
}
site = transformApiSiteData({site});
return {site, member};
}; };
return api; return api;

View file

@ -15,14 +15,6 @@ export const createPopupNotification = ({type, status, autoHide, duration = 2600
}; };
}; };
export function transformApiSiteData({site}) {
if (!site) {
return null;
}
return site;
}
export function isSentryEventAllowed({event: sentryEvent}) { export function isSentryEventAllowed({event: sentryEvent}) {
const frames = sentryEvent?.exception?.values?.[0]?.stacktrace?.frames || []; const frames = sentryEvent?.exception?.values?.[0]?.stacktrace?.frames || [];
const fileNames = frames.map(frame => frame.filename).filter(filename => !!filename); const fileNames = frames.map(frame => frame.filename).filter(filename => !!filename);