Fixed editor not loading in Admin acceptance tests

closes https://linear.app/tryghost/issue/PLG-176

The editor files were previously stubbed for testing because we didn't have a way to load the externally-hosted files. This made testing slow and difficult because the only way to test the Admin integration was via Ghost's e2e browser tests.

- unstubbed the editor globals so `fetchKoenigLexical()` actually tries to import the external assets
- updated `ember-cli-build` to copy the Koenig UMD file over to the assets directory in development/test builds
- updated `environment.js` to set the required filename for the default asset import to successfully hit the test environment hosted files
- updated lexical editor acceptance tests to demonstrate the editor loads successfully for new and existing posts
This commit is contained in:
Kevin Ansfield 2024-08-19 14:11:07 +01:00
parent 2627dd6aa0
commit fc501add94
5 changed files with 41 additions and 17 deletions

View File

@ -66,10 +66,17 @@ module.exports = function (environment) {
ENV.APP.rootElement = '#ember-testing'; ENV.APP.rootElement = '#ember-testing';
ENV.APP.autoboot = false; ENV.APP.autoboot = false;
// Withuot manually setting this, pretender won't track requests // Without manually setting this, pretender won't track requests
ENV['ember-cli-mirage'] = { ENV['ember-cli-mirage'] = {
trackRequests: true trackRequests: true
}; };
// We copy the dynamically loaded editor file into the ghost assets
// directory in the dev/test env so that tests can load it. We need to
// set the config appropriately here so that the fetchKoenigLexical
// utility creates the right URL
ENV.editorFilename = 'koenig-lexical.umd.js';
ENV.editorHash = 'test';
} }
return ENV; return ENV;

View File

@ -254,5 +254,11 @@ module.exports = function (defaults) {
app.import('vendor/codemirror/lib/codemirror.js', {type: 'test'}); app.import('vendor/codemirror/lib/codemirror.js', {type: 'test'});
} }
if (app.env === 'development' || app.env === 'test') {
// pull dynamic imports into the assets folder so that they can be lazy-loaded in tests
// also done in development env so http://localhost:4200/tests works
app.import('node_modules/@tryghost/koenig-lexical/dist/koenig-lexical.umd.js', {outputFile: 'ghost/assets/koenig-lexical/koenig-lexical.umd.js'});
}
return app.toTree(); return app.toTree();
}; };

View File

@ -1,5 +1,5 @@
import loginAsRole from '../../helpers/login-as-role'; import loginAsRole from '../../helpers/login-as-role';
import {blur, click, currentURL, fillIn, find, waitUntil} from '@ember/test-helpers'; import {blur, click, currentURL, fillIn, find, waitFor, waitUntil} from '@ember/test-helpers';
import {enableLabsFlag} from '../../helpers/labs-flag'; import {enableLabsFlag} from '../../helpers/labs-flag';
import {expect} from 'chai'; import {expect} from 'chai';
import {invalidateSession} from 'ember-simple-auth/test-support'; import {invalidateSession} from 'ember-simple-auth/test-support';
@ -18,15 +18,21 @@ describe('Acceptance: Lexical editor', function () {
it('redirects to signin when not authenticated', async function () { it('redirects to signin when not authenticated', async function () {
await invalidateSession(); await invalidateSession();
await visit('/editor/post/'); await visit('/editor/post/');
expect(currentURL(), 'currentURL').to.equal('/signin'); expect(currentURL(), 'currentURL').to.equal('/signin');
}); });
describe('new post', function () { describe('with new post', function () {
// TODO: test it actually loads the editor
it('loads editor', async function () { it('loads editor', async function () {
await visit('/editor/post/'); await visit('/editor/post/');
expect(currentURL(), 'currentURL').to.equal('/editor/post/'); expect(currentURL(), 'currentURL').to.equal('/editor/post/');
await waitFor('[data-secondary-instance="false"] [data-lexical-editor]');
// find the placeholder div
const xpath = '//div[text()="Begin writing your post..."]';
const match = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
expect(match.singleNodeValue).to.exist;
}); });
it('can leave editor without unsaved changes modal', async function () { it('can leave editor without unsaved changes modal', async function () {
@ -72,7 +78,16 @@ describe('Acceptance: Lexical editor', function () {
it('saves on content change'); it('saves on content change');
}); });
describe('existing post', function () { describe('with existing post', function () {
it('loads editor', async function () {
const post = this.server.create('post', {lexical: '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"This is a test","type":"extended-text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}'});
await visit(`/editor/post/${post.id}`);
expect(currentURL(), 'currentURL').to.equal(`/editor/post/${post.id}`);
await waitFor('[data-secondary-instance="false"] [data-lexical-editor]');
// find the post content
expect(find('[data-secondary-instance="false"] [data-lexical-editor]')).to.contain.text('This is a test');
});
it('does not save post on title blur', async function () { it('does not save post on title blur', async function () {
const post = this.server.create('post', {status: 'published'}); const post = this.server.create('post', {status: 'published'});
const originalTitle = post.title; const originalTitle = post.title;

View File

@ -33,7 +33,8 @@ describe('Acceptance: Post revisions', function () {
postStatus: 'draft', postStatus: 'draft',
author: post.authors.models[0], author: post.authors.models[0],
createdAt: moment(post.updatedAt).subtract(1, 'hour'), createdAt: moment(post.updatedAt).subtract(1, 'hour'),
reason: 'explicit_save' reason: 'explicit_save',
lexical: '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"New body","type":"extended-text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}'
}); });
this.server.create('post-revision', { this.server.create('post-revision', {
post, post,
@ -45,11 +46,10 @@ describe('Acceptance: Post revisions', function () {
postStatus: 'draft', postStatus: 'draft',
author: post.authors.models[0], author: post.authors.models[0],
createdAt: moment(post.updatedAt).subtract(1, 'day'), createdAt: moment(post.updatedAt).subtract(1, 'day'),
reason: 'initial_revision' reason: 'initial_revision',
lexical: '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Old body","type":"extended-text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}'
}); });
// this.timeout(0);
await visit(`/editor/post/${post.id}`); await visit(`/editor/post/${post.id}`);
// open post history menu // open post history menu
@ -109,7 +109,8 @@ describe('Acceptance: Post revisions', function () {
postStatus: 'draft', postStatus: 'draft',
author: post.authors.models[0], author: post.authors.models[0],
createdAt: moment(post.updatedAt).subtract(1, 'hour'), createdAt: moment(post.updatedAt).subtract(1, 'hour'),
reason: 'explicit_save' reason: 'explicit_save',
lexical: '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"New body","type":"extended-text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}'
}); });
this.server.create('post-revision', { this.server.create('post-revision', {
post, post,
@ -118,7 +119,8 @@ describe('Acceptance: Post revisions', function () {
postStatus: 'draft', postStatus: 'draft',
author: post.authors.models[0], author: post.authors.models[0],
createdAt: moment(post.updatedAt).subtract(1, 'day'), createdAt: moment(post.updatedAt).subtract(1, 'day'),
reason: 'initial_revision' reason: 'initial_revision',
lexical: '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Old body","type":"extended-text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}'
}); });
await visit(`/editor/post/${post.id}`); await visit(`/editor/post/${post.id}`);

View File

@ -8,12 +8,6 @@ import chai from 'chai';
import chaiDom from 'chai-dom'; import chaiDom from 'chai-dom';
chai.use(chaiDom); chai.use(chaiDom);
// stub loaded external module to avoid loading of external dep
window['@tryghost/koenig-lexical'] = {
KoenigComposer: () => null,
KoenigEditor: () => null
};
setApplication(Application.create(config.APP)); setApplication(Application.create(config.APP));
registerWaiter(); registerWaiter();