mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-20 22:42:53 -05:00
Added experimental Cypress tests
refs https://github.com/TryGhost/Team/issues/1780 This commit adds some Cypress tests as a POC to the project. If we decide to go with Cypress, we can add more tests to cover the rest of the codebase. The main reason to have a E2E framework is that some editor related UI is hard to test with the React tests because it uses JSDOM.
This commit is contained in:
parent
ddbc2db76d
commit
24af5ad0dd
22 changed files with 1091 additions and 90 deletions
|
@ -3,7 +3,8 @@ module.exports = {
|
|||
root: true,
|
||||
extends: [
|
||||
'react-app',
|
||||
'plugin:ghost/browser'
|
||||
'plugin:ghost/browser',
|
||||
'plugin:cypress/recommended'
|
||||
],
|
||||
plugins: [
|
||||
'ghost',
|
||||
|
|
4
apps/comments-ui/.gitignore
vendored
4
apps/comments-ui/.gitignore
vendored
|
@ -83,4 +83,6 @@ build/
|
|||
# CRA also suggests `.env` files should be checked into source control
|
||||
# Ref: https://create-react-app.dev/docs/adding-custom-environment-variables/#adding-development-environment-variables-in-env
|
||||
|
||||
public/main.css
|
||||
public/main.css
|
||||
|
||||
cypress/videos
|
||||
|
|
17
apps/comments-ui/cypress.config.js
Normal file
17
apps/comments-ui/cypress.config.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
const {defineConfig} = require('cypress');
|
||||
|
||||
module.exports = defineConfig({
|
||||
component: {
|
||||
devServer: {
|
||||
framework: 'create-react-app',
|
||||
bundler: 'webpack'
|
||||
}
|
||||
},
|
||||
|
||||
e2e: {
|
||||
baseUrl: 'http://localhost:4000',
|
||||
setupNodeEvents(on, config) {
|
||||
// implement node event listeners here
|
||||
}
|
||||
}
|
||||
});
|
64
apps/comments-ui/cypress/e2e/forms.cy.js
Normal file
64
apps/comments-ui/cypress/e2e/forms.cy.js
Normal file
|
@ -0,0 +1,64 @@
|
|||
describe('Forms', () => {
|
||||
it('Asks to fill in member name', () => {
|
||||
cy.login({name: ''}).as('login');
|
||||
cy.mockComments(10).as('getComments');
|
||||
cy.mockAddComments().as('getComments');
|
||||
|
||||
cy.visit(`/?ghostComments=${encodeURIComponent('/')}&styles=${encodeURIComponent('/main.css')}`);
|
||||
cy.wait(['@login', '@getComments', '@getCounts']);
|
||||
|
||||
let mainForm = cy.iframe().find('[data-testid="main-form"]').should('exist');
|
||||
|
||||
// Check name not visible
|
||||
mainForm.find('[data-testid="member-name"]').should('not.exist');
|
||||
|
||||
mainForm = cy.iframe().find('[data-testid="main-form"]').should('exist');
|
||||
mainForm.click();
|
||||
|
||||
// Check name not visible
|
||||
mainForm.find('[data-testid="member-name"]').should('not.exist');
|
||||
cy.popup('addDetailsPopup').should('exist');
|
||||
});
|
||||
|
||||
it('Can open main form and post a comment', () => {
|
||||
cy.login().as('login');
|
||||
cy.mockComments(10).as('getComments');
|
||||
cy.mockAddComments().as('getComments');
|
||||
|
||||
cy.visit(`/?ghostComments=${encodeURIComponent('/')}&styles=${encodeURIComponent('/main.css')}`);
|
||||
cy.wait(['@login', '@getComments', '@getCounts']);
|
||||
|
||||
let mainForm = cy.iframe().find('[data-testid="main-form"]').should('exist');
|
||||
|
||||
// Check name not visible
|
||||
mainForm.find('[data-testid="member-name"]').should('not.exist');
|
||||
|
||||
mainForm = cy.iframe().find('[data-testid="main-form"]').should('exist');
|
||||
mainForm.click();
|
||||
|
||||
// Check name visible
|
||||
mainForm.find('[data-testid="member-name"]').should('exist');
|
||||
|
||||
const form = cy.iframe().find('[data-testid="main-form"]').find('[contenteditable="true"]');
|
||||
|
||||
form.type('Hello world')
|
||||
.type('{cmd}{enter}');
|
||||
});
|
||||
|
||||
it('Hides MainForm when replying', () => {
|
||||
cy.login().as('login');
|
||||
cy.mockComments(1).as('getComments');
|
||||
cy.mockAddComments().as('getComments');
|
||||
|
||||
cy.visit(`/?ghostComments=${encodeURIComponent('/')}&styles=${encodeURIComponent('/main.css')}`);
|
||||
cy.wait(['@login', '@getComments', '@getCounts']);
|
||||
|
||||
cy.iframe().find('[data-testid="main-form"]').should('exist').as('mainForm');
|
||||
|
||||
cy.iframe()
|
||||
.find('[data-testid="comment-component"]').should('exist')
|
||||
.find('[data-testid="reply-button"]').click();
|
||||
|
||||
cy.iframe().find('[data-testid="main-form"]').should('not.exist');
|
||||
});
|
||||
});
|
60
apps/comments-ui/cypress/e2e/pagination.cy.js
Normal file
60
apps/comments-ui/cypress/e2e/pagination.cy.js
Normal file
|
@ -0,0 +1,60 @@
|
|||
describe('Pagination', () => {
|
||||
it('does not show pagination button for 0 comments', () => {
|
||||
cy.login().as('login');
|
||||
cy.mockComments(0).as('getComments');
|
||||
|
||||
cy.visit(`/?ghostComments=${encodeURIComponent('/')}&styles=${encodeURIComponent('/main.css')}`);
|
||||
cy.wait(['@login', '@getComments', '@getCounts']);
|
||||
|
||||
cy.iframe().find('[data-testid="pagination-component"]').should('not.exist');
|
||||
});
|
||||
|
||||
it('does show pagination plural', () => {
|
||||
cy.login().as('login');
|
||||
cy.mockComments(12).as('getComments');
|
||||
|
||||
cy.visit(`/?ghostComments=${encodeURIComponent('/')}&styles=${encodeURIComponent('/main.css')}`);
|
||||
cy.wait(['@login', '@getComments', '@getCounts']);
|
||||
|
||||
const button = cy.iframe().find('[data-testid="pagination-component"]').should('exist');
|
||||
button.contains('Show 7 previous comments');
|
||||
|
||||
// Should show 5 comments
|
||||
cy.iframe().find('[data-testid="comment-component"]').should('have.length', 5);
|
||||
});
|
||||
|
||||
it('does show pagination singular', () => {
|
||||
cy.login().as('login');
|
||||
cy.mockComments(6).as('getComments');
|
||||
|
||||
cy.visit(`/?ghostComments=${encodeURIComponent('/')}&styles=${encodeURIComponent('/main.css')}`);
|
||||
cy.wait(['@login', '@getComments', '@getCounts']);
|
||||
|
||||
cy.iframe().contains('Show 1 previous comment');
|
||||
|
||||
// Should show 5 comments
|
||||
cy.iframe().find('[data-testid="comment-component"]').should('have.length', 5);
|
||||
});
|
||||
|
||||
it('can load next page', () => {
|
||||
cy.login().as('login');
|
||||
cy.mockComments(6).as('getComments');
|
||||
|
||||
cy.visit(`/?ghostComments=${encodeURIComponent('/')}&styles=${encodeURIComponent('/main.css')}`);
|
||||
cy.wait(['@login', '@getComments', '@getCounts']);
|
||||
|
||||
const button = cy.iframe().contains('Show 1 previous comment');
|
||||
|
||||
// Should show 5 comments
|
||||
cy.iframe().find('[data-testid="comment-component"]').should('have.length', 5);
|
||||
|
||||
button.click();
|
||||
cy.wait(['@getCommentsPage2']);
|
||||
|
||||
// Button should be gone
|
||||
button.should('not.exist');
|
||||
|
||||
// Should show 6 comments now, instead of 5
|
||||
cy.iframe().find('[data-testid="comment-component"]').should('have.length', 6);
|
||||
});
|
||||
});
|
106
apps/comments-ui/cypress/support/commands.js
Normal file
106
apps/comments-ui/cypress/support/commands.js
Normal file
|
@ -0,0 +1,106 @@
|
|||
import {buildComment, buildMember} from '../../src/utils/test-utils';
|
||||
let loggedInMember = null;
|
||||
|
||||
Cypress.Commands.add('login', (memberData) => {
|
||||
loggedInMember = buildMember(memberData);
|
||||
return cy.intercept(
|
||||
{
|
||||
method: 'GET',
|
||||
url: '/members/api/member/'
|
||||
},
|
||||
loggedInMember
|
||||
);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('mockAddComments', () => {
|
||||
cy.intercept(
|
||||
{
|
||||
method: 'POST',
|
||||
url: '/members/api/comments/'
|
||||
},
|
||||
[] // and force the response to be: []
|
||||
).as('getCounts'); // and assign an alias
|
||||
|
||||
return cy.intercept(
|
||||
{
|
||||
method: 'POST',
|
||||
url: '/members/api/comments/'
|
||||
},
|
||||
(req) => {
|
||||
const commentData = req.body;
|
||||
req.reply({
|
||||
body: {
|
||||
comments: [
|
||||
buildComment({
|
||||
...commentData?.comments[0],
|
||||
member: loggedInMember
|
||||
})
|
||||
]
|
||||
}
|
||||
});
|
||||
}
|
||||
).as('getCounts');
|
||||
});
|
||||
Cypress.Commands.add('mockComments', (count, override = {}) => {
|
||||
const limit = 5;
|
||||
const pages = Math.max(Math.ceil(count / limit), 1);
|
||||
|
||||
cy.intercept(
|
||||
{
|
||||
method: 'POST',
|
||||
url: '/members/api/comments/counts/'
|
||||
},
|
||||
[]
|
||||
).as('getCounts');
|
||||
|
||||
return cy.intercept('GET', '/members/api/comments/*',
|
||||
(req) => {
|
||||
const page = parseInt(req.query.page ?? '1');
|
||||
|
||||
if (!page || page > pages) {
|
||||
throw new Error('Invalid page');
|
||||
}
|
||||
|
||||
if (page == 1) {
|
||||
req.alias = 'getComments';
|
||||
} else {
|
||||
req.alias = 'getCommentsPage' + page;
|
||||
}
|
||||
|
||||
req.reply({
|
||||
body: {
|
||||
comments: new Array(Math.min(count - (page - 1) * limit, limit)).fill(null).map(() => buildComment(override)),
|
||||
meta: {
|
||||
pagination: {
|
||||
limit: limit,
|
||||
total: count,
|
||||
next: page + 1 <= pages ? page + 1 : null,
|
||||
prev: page > 1 ? page - 1 : null,
|
||||
page: page
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
const getIframeDocument = (title) => {
|
||||
return cy
|
||||
.get('iframe[title="' + title + '"]')
|
||||
.its('0.contentDocument');
|
||||
};
|
||||
|
||||
const getIframeBody = (title) => {
|
||||
return getIframeDocument(title)
|
||||
.its('body')
|
||||
.then(cy.wrap);
|
||||
};
|
||||
|
||||
Cypress.Commands.add('iframe', () => {
|
||||
return getIframeBody('comments-frame');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('popup', (name) => {
|
||||
return getIframeBody(name);
|
||||
});
|
20
apps/comments-ui/cypress/support/e2e.js
Normal file
20
apps/comments-ui/cypress/support/e2e.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
// ***********************************************************
|
||||
// This example support/e2e.js is processed and
|
||||
// loaded automatically before your test files.
|
||||
//
|
||||
// This is a great place to put global configuration and
|
||||
// behavior that modifies Cypress.
|
||||
//
|
||||
// You can change the location of this file or turn off
|
||||
// automatically serving support files with the
|
||||
// 'supportFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands';
|
||||
|
||||
// Alternatively you can use CommonJS syntax:
|
||||
// require('./commands')
|
|
@ -31,8 +31,8 @@
|
|||
"react-scripts": "4.0.3"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "BROWSER=none react-scripts start",
|
||||
"start:combined": "BROWSER=none node ./scripts/start-combined.js",
|
||||
"start": "PORT=4000 BROWSER=none react-scripts start",
|
||||
"start:combined": "PORT=4000 BROWSER=none node ./scripts/start-combined.js",
|
||||
"start:dev": "PORT=4000 node ./scripts/start-mode.js",
|
||||
"dev": "node ./scripts/dev-mode.js",
|
||||
"build": "npm run build:combined",
|
||||
|
@ -40,7 +40,7 @@
|
|||
"build:combined": "node ./scripts/build-combined.js",
|
||||
"build:bundle": "webpack --config webpack.config.js",
|
||||
"test:ui": "react-scripts test",
|
||||
"test": "yarn test:ui --watchAll=false --coverage",
|
||||
"test": "yarn test:ui --watchAll=false --coverage && yarn cypress:with-server",
|
||||
"eject": "react-scripts eject",
|
||||
"lint": "eslint src --ext .js --cache",
|
||||
"preship": "yarn lint",
|
||||
|
@ -48,7 +48,10 @@
|
|||
"posttest": "yarn lint",
|
||||
"analyze": "source-map-explorer 'umd/*.js'",
|
||||
"prepublishOnly": "yarn build",
|
||||
"tailwind": "npx tailwindcss -i ./src/index.css -o ./public/main.css --watch --minify"
|
||||
"tailwind": "npx tailwindcss -i ./src/index.css -o ./public/main.css --watch --minify",
|
||||
"cypress:open": "cypress open",
|
||||
"cypress:with-server": "yarn start-server-and-test 'yarn start &>/dev/null' http://localhost:4000 cypress",
|
||||
"cypress": "cypress run"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
|
@ -71,7 +74,9 @@
|
|||
"chalk": "4.1.2",
|
||||
"chokidar": "3.5.2",
|
||||
"copy-webpack-plugin": "6.4.1",
|
||||
"cypress": "^10.7.0",
|
||||
"eslint-config-react-app": "^7.0.1",
|
||||
"eslint-plugin-cypress": "^2.12.1",
|
||||
"eslint-plugin-ghost": "2.12.0",
|
||||
"eslint-plugin-tailwindcss": "^3.6.0",
|
||||
"minimist": "1.2.5",
|
||||
|
@ -80,6 +85,7 @@
|
|||
"rewire": "6.0.0",
|
||||
"serve-handler": "6.1.3",
|
||||
"source-map-explorer": "2.5.2",
|
||||
"start-server-and-test": "^1.14.0",
|
||||
"tailwindcss": "^3.1.4",
|
||||
"webpack-cli": "3.3.12"
|
||||
},
|
||||
|
|
|
@ -9,6 +9,10 @@ import ContentBox from './components/ContentBox';
|
|||
import PopupBox from './components/PopupBox';
|
||||
|
||||
function AuthFrame({adminUrl, onLoad}) {
|
||||
if (!adminUrl) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const iframeStyle = {
|
||||
display: 'none'
|
||||
};
|
||||
|
@ -31,7 +35,6 @@ export default class App extends React.Component {
|
|||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
// Todo: this state is work in progress
|
||||
this.state = {
|
||||
action: 'init:running',
|
||||
initStatus: 'running',
|
||||
|
@ -83,6 +86,10 @@ export default class App extends React.Component {
|
|||
}
|
||||
|
||||
async initAdminAuth() {
|
||||
if (this.adminApi) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.adminApi = this.setupAdminAPI();
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ function renderApp({member = null, documentStyles = {}, props = {}} = {}) {
|
|||
};
|
||||
// In tests, we currently don't wait for the styles to have loaded. In the app we check if the styles url is set or not.
|
||||
const stylesUrl = '';
|
||||
const {container} = render(<div style={documentStyles}><div id={ROOT_DIV_ID}><App api={api} stylesUrl={stylesUrl} {...props}/></div></div>);
|
||||
const {container} = render(<div style={documentStyles}><div id={ROOT_DIV_ID}><App api={api} adminUrl="https://admin.example/" stylesUrl={stylesUrl} {...props}/></div></div>);
|
||||
const iframeElement = container.querySelector('iframe[title="comments-frame"]');
|
||||
expect(iframeElement).toBeInTheDocument();
|
||||
const iframeDocument = iframeElement.contentDocument;
|
||||
|
|
|
@ -68,7 +68,7 @@ export const CommentsFrame = ({children}) => {
|
|||
);
|
||||
};
|
||||
|
||||
export const PopupFrame = ({children}) => {
|
||||
export const PopupFrame = ({children, title}) => {
|
||||
const style = {
|
||||
zIndex: '3999999',
|
||||
position: 'fixed',
|
||||
|
@ -80,7 +80,7 @@ export const PopupFrame = ({children}) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<TailwindFrame style={style} title="popup-frame">
|
||||
<TailwindFrame style={style} title={title}>
|
||||
{children}
|
||||
</TailwindFrame>
|
||||
);
|
||||
|
|
|
@ -46,7 +46,7 @@ export default function PopupBox() {
|
|||
|
||||
return (
|
||||
<>
|
||||
<GenericPopup show={show} callback={popupProps.callback}>
|
||||
<GenericPopup show={show} callback={popupProps.callback} title={type}>
|
||||
<PageComponent {...popupProps}/>
|
||||
</GenericPopup>
|
||||
</>
|
||||
|
|
|
@ -19,7 +19,7 @@ const Pagination = () => {
|
|||
}
|
||||
|
||||
return (
|
||||
<button type="button" className="group mb-10 flex w-full items-center px-0 pt-0 pb-2 text-left font-sans text-md font-semibold text-neutral-700 dark:text-white " onClick={loadMore}>
|
||||
<button data-testid="pagination-component" type="button" className="group mb-10 flex w-full items-center px-0 pt-0 pb-2 text-left font-sans text-md font-semibold text-neutral-700 dark:text-white " onClick={loadMore}>
|
||||
<span className="flex h-[39px] w-full items-center justify-center whitespace-nowrap rounded-[6px] bg-[rgb(229,229,229,0.4)] py-2 px-3 text-center font-sans text-sm font-semibold text-neutral-700 outline-0 transition-[opacity,background] duration-150 hover:bg-[rgb(229,229,229,0.7)] dark:bg-[rgba(255,255,255,0.08)] dark:text-neutral-100 dark:hover:bg-[rgba(255,255,255,0.1)]">↑ Show {left} previous {left === 1 ? 'comment' : 'comments'}</span>
|
||||
</button>
|
||||
);
|
||||
|
|
|
@ -26,7 +26,7 @@ const MoreButton = ({comment, toggleEdit}) => {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<div className="relative" data-testid="more-button">
|
||||
{show ? <button type="button" onClick={toggleContextMenu} className="outline-0"><MoreIcon className='duration-50 gh-comments-icon gh-comments-icon-more fill-[rgba(0,0,0,0.5)] outline-0 transition ease-linear hover:fill-[rgba(0,0,0,0.75)] dark:fill-[rgba(255,255,255,0.5)] dark:hover:fill-[rgba(255,255,255,0.25)]' /></button> : null}
|
||||
{isContextMenuOpen ? <CommentContextMenu comment={comment} close={closeContextMenu} toggleEdit={toggleEdit} /> : null}
|
||||
</div>
|
||||
|
|
|
@ -11,7 +11,7 @@ const AuthorContextMenu = ({comment, close, toggleEdit}) => {
|
|||
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
<button type="button" className="mb-3 w-full text-left text-[14px]" onClick={toggleEdit}>
|
||||
<button type="button" className="mb-3 w-full text-left text-[14px]" onClick={toggleEdit} data-testid="edit">
|
||||
Edit
|
||||
</button>
|
||||
<button type="button" className="w-full text-left text-[14px] text-red-600" onClick={deleteComment}>
|
||||
|
|
|
@ -129,6 +129,7 @@ const FormHeader = ({show, name, expertise, editName, editExpertise}) => {
|
|||
<div
|
||||
className="font-sans text-[17px] font-bold tracking-tight text-[rgb(23,23,23)] dark:text-[rgba(255,255,255,0.85)]"
|
||||
onClick={editName}
|
||||
data-testid="member-name"
|
||||
>
|
||||
{name ? name : 'Anonymous'}
|
||||
</div>
|
||||
|
|
|
@ -85,7 +85,7 @@ const MainForm = ({commentsCount}) => {
|
|||
const isOpen = editor?.isFocused ?? false;
|
||||
|
||||
return (
|
||||
<div className='-mt-[4px]' ref={formEl}>
|
||||
<div className='-mt-[4px]' ref={formEl} data-testid="main-form">
|
||||
<Form editor={editor} reduced={false} isOpen={isOpen} {...submitProps} />
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -3,14 +3,14 @@ import {Transition} from '@headlessui/react';
|
|||
import {PopupFrame} from '../Frame';
|
||||
import AppContext from '../../AppContext';
|
||||
|
||||
const GenericPopup = (props) => {
|
||||
const GenericPopup = ({show, children, title, callback}) => {
|
||||
// The modal will cover the whole screen, so while it is hidden, we need to disable pointer events
|
||||
const {dispatchAction} = useContext(AppContext);
|
||||
|
||||
const close = (event) => {
|
||||
dispatchAction('closePopup');
|
||||
if (props.callback) {
|
||||
props.callback(false);
|
||||
if (callback) {
|
||||
callback(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -28,8 +28,8 @@ const GenericPopup = (props) => {
|
|||
});
|
||||
|
||||
return (
|
||||
<Transition show={props.show} appear={true}>
|
||||
<PopupFrame>
|
||||
<Transition show={show} appear={true}>
|
||||
<PopupFrame title={title}>
|
||||
<div>
|
||||
<Transition.Child
|
||||
enter="transition duration-200 linear"
|
||||
|
@ -48,7 +48,7 @@ const GenericPopup = (props) => {
|
|||
leaveFrom="translate-y-0 opacity-100"
|
||||
leaveTo="translate-y-4 opacity-0"
|
||||
>
|
||||
{props.children}
|
||||
{children}
|
||||
</Transition.Child>
|
||||
</div>
|
||||
</Transition.Child>
|
||||
|
|
|
@ -26,26 +26,32 @@ function getSiteData() {
|
|||
* @type {HTMLElement}
|
||||
*/
|
||||
const scriptTag = document.querySelector('script[data-ghost-comments]');
|
||||
if (scriptTag) {
|
||||
const siteUrl = scriptTag.dataset.ghostComments;
|
||||
const apiKey = scriptTag.dataset.key;
|
||||
const apiUrl = scriptTag.dataset.api;
|
||||
const adminUrl = scriptTag.dataset.admin;
|
||||
const sentryDsn = scriptTag.dataset.sentryDsn;
|
||||
const postId = scriptTag.dataset.postId;
|
||||
const colorScheme = scriptTag.dataset.colorScheme;
|
||||
const avatarSaturation = scriptTag.dataset.avatarSaturation;
|
||||
const accentColor = scriptTag.dataset.accentColor;
|
||||
const appVersion = scriptTag.dataset.appVersion;
|
||||
const commentsEnabled = scriptTag.dataset.commentsEnabled;
|
||||
const stylesUrl = scriptTag.dataset.styles;
|
||||
const title = scriptTag.dataset.title === 'null' ? null : scriptTag.dataset.title;
|
||||
const showCount = scriptTag.dataset.count === 'true';
|
||||
const publication = scriptTag.dataset.publication ?? ''; // TODO: replace with dynamic data from script
|
||||
let dataset = scriptTag?.dataset;
|
||||
|
||||
return {siteUrl, stylesUrl, apiKey, apiUrl, sentryDsn, postId, adminUrl, colorScheme, avatarSaturation, accentColor, appVersion, commentsEnabled, title, showCount, publication};
|
||||
if (!scriptTag && process.env.NODE_ENV === 'development') {
|
||||
// Use queryparams in test mode
|
||||
dataset = Object.fromEntries(new URLSearchParams(window.location.search).entries());
|
||||
} else if (!scriptTag) {
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
|
||||
const siteUrl = dataset.ghostComments;
|
||||
const apiKey = dataset.key;
|
||||
const apiUrl = dataset.api;
|
||||
const adminUrl = dataset.admin;
|
||||
const sentryDsn = dataset.sentryDsn;
|
||||
const postId = dataset.postId;
|
||||
const colorScheme = dataset.colorScheme;
|
||||
const avatarSaturation = dataset.avatarSaturation;
|
||||
const accentColor = dataset.accentColor;
|
||||
const appVersion = dataset.appVersion;
|
||||
const commentsEnabled = dataset.commentsEnabled;
|
||||
const stylesUrl = dataset.styles;
|
||||
const title = dataset.title === 'null' ? null : dataset.title;
|
||||
const showCount = dataset.count === 'true';
|
||||
const publication = dataset.publication ?? ''; // TODO: replace with dynamic data from script
|
||||
|
||||
return {siteUrl, stylesUrl, apiKey, apiUrl, sentryDsn, postId, adminUrl, colorScheme, avatarSaturation, accentColor, appVersion, commentsEnabled, title, showCount, publication};
|
||||
}
|
||||
|
||||
function handleTokenUrl() {
|
||||
|
@ -65,14 +71,20 @@ function init() {
|
|||
// const customSiteUrl = getSiteUrl();
|
||||
const {siteUrl: customSiteUrl, ...siteData} = getSiteData();
|
||||
const siteUrl = customSiteUrl || window.location.origin;
|
||||
setup({siteUrl});
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
{<App siteUrl={siteUrl} customSiteUrl={customSiteUrl} {...siteData} />}
|
||||
</React.StrictMode>,
|
||||
document.getElementById(ROOT_DIV_ID)
|
||||
);
|
||||
try {
|
||||
setup({siteUrl});
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
{<App siteUrl={siteUrl} customSiteUrl={customSiteUrl} {...siteData} />}
|
||||
</React.StrictMode>,
|
||||
document.getElementById(ROOT_DIV_ID)
|
||||
);
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
init();
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
const ObjectId = require('bson-objectid').default;
|
||||
let memberCounter = 0;
|
||||
|
||||
export function buildMember(override) {
|
||||
memberCounter += 1;
|
||||
|
||||
return {
|
||||
avatar_image: '',
|
||||
avatar_image: 'https://www.gravatar.com/avatar/7a68f69cc9c9e9b45d97ecad6f24184a?s=250&r=g&d=blank',
|
||||
expertise: 'Head of Testing',
|
||||
id: ObjectId(),
|
||||
name: 'Test Member',
|
||||
uuid: '613e9667-4fa2-4ff4-aa62-507220103d41',
|
||||
name: 'Test Member ' + memberCounter,
|
||||
uuid: ObjectId(),
|
||||
paid: false,
|
||||
...override
|
||||
};
|
||||
}
|
||||
|
|
15
apps/comments-ui/test-results.xml
Normal file
15
apps/comments-ui/test-results.xml
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<testsuites name="Mocha Tests" time="2.6730" tests="4" failures="0">
|
||||
<testsuite name="Root Suite" timestamp="2022-09-09T15:27:21" tests="0" file="cypress/e2e/pagination.cy.js" time="0.0000" failures="0">
|
||||
</testsuite>
|
||||
<testsuite name="Pagination" timestamp="2022-09-09T15:27:21" tests="4" time="2.6730" failures="0">
|
||||
<testcase name="Pagination does not show pagination button for 0 comments" time="0.7780" classname="does not show pagination button for 0 comments">
|
||||
</testcase>
|
||||
<testcase name="Pagination does show pagination plural" time="0.6270" classname="does show pagination plural">
|
||||
</testcase>
|
||||
<testcase name="Pagination does show pagination singular" time="0.5910" classname="does show pagination singular">
|
||||
</testcase>
|
||||
<testcase name="Pagination can load next page" time="0.6770" classname="can load next page">
|
||||
</testcase>
|
||||
</testsuite>
|
||||
</testsuites>
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue