mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-19 00:11:49 +03:00
f296761577
no issue - including a body snapshot for the pages API collection card tests causes issues because the generated HTML is dynamic and contains post creation times meaning the snapshot was unstable - removed the body snapshot for the tests concerned for now as they are mostly there to catch saving issues rather than rendering issues
425 lines
15 KiB
JavaScript
425 lines
15 KiB
JavaScript
const _ = require('lodash');
|
|
const {mobiledocToLexical} = require('@tryghost/kg-converters');
|
|
const models = require('../../../core/server/models');
|
|
const {agentProvider, fixtureManager, mockManager, matchers} = require('../../utils/e2e-framework');
|
|
const {anyArray, anyBoolean, anyContentVersion, anyEtag, anyLocationFor, anyObject, anyObjectId, anyISODateTime, anyString, anyUuid} = matchers;
|
|
|
|
const tierSnapshot = {
|
|
id: anyObjectId,
|
|
created_at: anyISODateTime,
|
|
updated_at: anyISODateTime
|
|
};
|
|
|
|
const matchPageShallowIncludes = {
|
|
id: anyObjectId,
|
|
uuid: anyUuid,
|
|
comment_id: anyString,
|
|
url: anyString,
|
|
authors: anyArray,
|
|
primary_author: anyObject,
|
|
tags: anyArray,
|
|
primary_tag: anyObject,
|
|
tiers: Array(2).fill(tierSnapshot),
|
|
created_at: anyISODateTime,
|
|
updated_at: anyISODateTime,
|
|
published_at: anyISODateTime,
|
|
post_revisions: anyArray,
|
|
show_title_and_feature_image: anyBoolean
|
|
};
|
|
|
|
describe('Pages API', function () {
|
|
let agent;
|
|
|
|
before(async function () {
|
|
mockManager.mockLabsEnabled('collectionsCard');
|
|
agent = await agentProvider.getAdminAPIAgent();
|
|
await fixtureManager.init('posts');
|
|
await agent.loginAsOwner();
|
|
});
|
|
|
|
afterEach(function () {
|
|
mockManager.restore();
|
|
});
|
|
|
|
describe('Read', function () {
|
|
it('Re-renders html when null', async function () {
|
|
// "queue" an existing page for re-render as happens when a published page is updated/destroyed
|
|
const page = await models.Post.findOne({slug: 'static-page-test'});
|
|
// NOTE: re-rendering only occurs for lexical pages
|
|
const lexical = mobiledocToLexical(page.get('mobiledoc'));
|
|
await models.Base.knex.raw('UPDATE posts set html=NULL, mobiledoc=NULL, lexical=? WHERE id=?', [lexical, page.id]);
|
|
|
|
await agent
|
|
.get(`/pages/${page.id}/?formats=mobiledoc,lexical,html`)
|
|
.expectStatus(200)
|
|
.matchBodySnapshot({
|
|
pages: [Object.assign({}, matchPageShallowIncludes)]
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Browse', function () {
|
|
it('Re-renders html when null', async function () {
|
|
// convert inserted pages to lexical and set html=null so we can test re-render
|
|
const pages = await models.Post.where('type', 'page').fetchAll();
|
|
for (const page of pages) {
|
|
if (!page.get('mobiledoc')) {
|
|
continue;
|
|
}
|
|
const lexical = mobiledocToLexical(page.get('mobiledoc'));
|
|
await models.Base.knex.raw('UPDATE posts set html=NULL, mobiledoc=NULL, lexical=? WHERE id=?', [lexical, page.id]);
|
|
}
|
|
|
|
await agent
|
|
.get('/pages/?formats=mobiledoc,lexical,html')
|
|
.expectStatus(200)
|
|
.matchBodySnapshot({
|
|
pages: Array(pages.length).fill(Object.assign({}, matchPageShallowIncludes))
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Create', function () {
|
|
it('Can create a page with html', async function () {
|
|
mockManager.mockLabsDisabled('lexicalEditor');
|
|
|
|
const page = {
|
|
title: 'HTML test',
|
|
html: '<p>Testing page creation with html</p>'
|
|
};
|
|
|
|
await agent
|
|
.post('/pages/?source=html&formats=mobiledoc,lexical,html')
|
|
.body({pages: [page]})
|
|
.expectStatus(201)
|
|
.matchBodySnapshot({
|
|
pages: [Object.assign({}, matchPageShallowIncludes, {published_at: null})]
|
|
})
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag,
|
|
location: anyLocationFor('pages')
|
|
});
|
|
});
|
|
|
|
it('Can create a page with html (labs.lexicalEditor)', async function () {
|
|
mockManager.mockLabsEnabled('lexicalEditor');
|
|
|
|
const page = {
|
|
title: 'HTML test',
|
|
html: '<p>Testing page creation with html</p>'
|
|
};
|
|
|
|
await agent
|
|
.post('/pages/?source=html&formats=mobiledoc,lexical,html')
|
|
.body({pages: [page]})
|
|
.expectStatus(201)
|
|
.matchBodySnapshot({
|
|
pages: [Object.assign({}, matchPageShallowIncludes, {published_at: null})]
|
|
})
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag,
|
|
location: anyLocationFor('pages')
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Update', function () {
|
|
it('Can modify show_title_and_feature_image property', async function () {
|
|
const page = {
|
|
title: 'Test Page',
|
|
status: 'draft'
|
|
};
|
|
|
|
const {body: pageBody} = await agent
|
|
.post('/pages/?formats=mobiledoc,lexical,html', {
|
|
headers: {
|
|
'content-type': 'application/json'
|
|
}
|
|
})
|
|
.body({pages: [page]})
|
|
.expectStatus(201);
|
|
|
|
const [pageResponse] = pageBody.pages;
|
|
|
|
await agent
|
|
.put(`/pages/${pageResponse.id}/?formats=mobiledoc,lexical,html`)
|
|
.body({
|
|
pages: [{
|
|
id: pageResponse.id,
|
|
show_title_and_feature_image: false, // default is true
|
|
updated_at: pageResponse.updated_at // satisfy collision detection
|
|
}]
|
|
})
|
|
.expectStatus(200)
|
|
.matchBodySnapshot({
|
|
pages: [Object.assign({}, matchPageShallowIncludes, {
|
|
published_at: null,
|
|
show_title_and_feature_image: false
|
|
})]
|
|
})
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag,
|
|
'x-cache-invalidate': anyString
|
|
});
|
|
});
|
|
|
|
it('Works with latest collection card', async function () {
|
|
const initialLexical = {
|
|
root: {
|
|
children: [
|
|
{
|
|
type: 'collection',
|
|
version: 1,
|
|
collection: 'latest',
|
|
postCount: 3,
|
|
layout: 'grid',
|
|
columns: 3,
|
|
header: 'Latest'
|
|
}
|
|
],
|
|
direction: null,
|
|
format: '',
|
|
indent: 0,
|
|
type: 'root',
|
|
version: 1
|
|
}
|
|
};
|
|
|
|
const updatedLexical = _.cloneDeep(initialLexical);
|
|
updatedLexical.root.children.push({
|
|
children: [
|
|
{
|
|
detail: 0,
|
|
format: 0,
|
|
mode: 'normal',
|
|
style: '',
|
|
text: 'Testing',
|
|
type: 'text',
|
|
version: 1
|
|
}
|
|
],
|
|
direction: 'ltr',
|
|
format: '',
|
|
indent: 0,
|
|
type: 'paragraph',
|
|
version: 1
|
|
});
|
|
|
|
const page = {
|
|
title: 'Latest Collection Card Test',
|
|
status: 'draft',
|
|
lexical: JSON.stringify(initialLexical)
|
|
};
|
|
|
|
const {body: createBody} = await agent
|
|
.post('/pages/?formats=mobiledoc,lexical,html', {
|
|
headers: {
|
|
'content-type': 'application/json'
|
|
}
|
|
})
|
|
.body({pages: [page]})
|
|
.expectStatus(201);
|
|
|
|
const [createResponse] = createBody.pages;
|
|
|
|
// does not match body snapshot as we mostly only care about the request succeeding.
|
|
// matching body snapshots is tricky because collection cards have dynamic content,
|
|
// most notably the post dates which are always changing.
|
|
await agent
|
|
.put(`/pages/${createResponse.id}/?formats=mobiledoc,lexical,html`)
|
|
.body({
|
|
pages: [{
|
|
id: createResponse.id,
|
|
lexical: JSON.stringify(updatedLexical),
|
|
updated_at: createResponse.updated_at // satisfy collision detection
|
|
}]
|
|
})
|
|
.expectStatus(200);
|
|
});
|
|
|
|
it('Works with featured collection card', async function () {
|
|
const initialLexical = {
|
|
root: {
|
|
children: [
|
|
{
|
|
type: 'collection',
|
|
version: 1,
|
|
collection: 'featured',
|
|
postCount: 3,
|
|
layout: 'grid',
|
|
columns: 3,
|
|
header: 'Featured'
|
|
}
|
|
],
|
|
direction: null,
|
|
format: '',
|
|
indent: 0,
|
|
type: 'root',
|
|
version: 1
|
|
}
|
|
};
|
|
|
|
const updatedLexical = _.cloneDeep(initialLexical);
|
|
updatedLexical.root.children.push({
|
|
children: [
|
|
{
|
|
detail: 0,
|
|
format: 0,
|
|
mode: 'normal',
|
|
style: '',
|
|
text: 'Testing',
|
|
type: 'text',
|
|
version: 1
|
|
}
|
|
],
|
|
direction: 'ltr',
|
|
format: '',
|
|
indent: 0,
|
|
type: 'paragraph',
|
|
version: 1
|
|
});
|
|
|
|
const page = {
|
|
title: 'Latest Collection Card Test',
|
|
status: 'draft',
|
|
lexical: JSON.stringify(initialLexical)
|
|
};
|
|
|
|
const {body: createBody} = await agent
|
|
.post('/pages/?formats=mobiledoc,lexical,html', {
|
|
headers: {
|
|
'content-type': 'application/json'
|
|
}
|
|
})
|
|
.body({pages: [page]})
|
|
.expectStatus(201);
|
|
|
|
const [createResponse] = createBody.pages;
|
|
|
|
await agent
|
|
.put(`/pages/${createResponse.id}/?formats=mobiledoc,lexical,html`)
|
|
.body({
|
|
pages: [{
|
|
id: createResponse.id,
|
|
lexical: JSON.stringify(updatedLexical),
|
|
updated_at: createResponse.updated_at // satisfy collision detection
|
|
}]
|
|
})
|
|
.expectStatus(200);
|
|
});
|
|
});
|
|
|
|
describe('Copy', function () {
|
|
it('Can copy a page', async function () {
|
|
const page = {
|
|
title: 'Test Page',
|
|
status: 'published'
|
|
};
|
|
|
|
const {body: pageBody} = await agent
|
|
.post('/pages/?formats=mobiledoc,lexical,html', {
|
|
headers: {
|
|
'content-type': 'application/json'
|
|
}
|
|
})
|
|
.body({pages: [page]})
|
|
.expectStatus(201)
|
|
.matchBodySnapshot({
|
|
pages: [Object.assign({}, matchPageShallowIncludes)]
|
|
});
|
|
|
|
const [pageResponse] = pageBody.pages;
|
|
|
|
await agent
|
|
.post(`/pages/${pageResponse.id}/copy?formats=mobiledoc,lexical`)
|
|
.expectStatus(201)
|
|
.matchBodySnapshot({
|
|
pages: [Object.assign({}, matchPageShallowIncludes, {published_at: null})]
|
|
})
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag,
|
|
location: anyLocationFor('pages')
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Convert', function () {
|
|
it('can convert a mobiledoc page to lexical', async function () {
|
|
const mobiledoc = JSON.stringify({
|
|
version: '0.3.1',
|
|
ghostVersion: '4.0',
|
|
markups: [],
|
|
atoms: [],
|
|
cards: [],
|
|
sections: [
|
|
[1, 'p', [
|
|
[0, [], 0, 'This is some great content.']
|
|
]]
|
|
]
|
|
});
|
|
const expectedLexical = JSON.stringify({
|
|
root: {
|
|
children: [
|
|
{
|
|
children: [
|
|
{
|
|
detail: 0,
|
|
format: 0,
|
|
mode: 'normal',
|
|
style: '',
|
|
text: 'This is some great content.',
|
|
type: 'text',
|
|
version: 1
|
|
}
|
|
],
|
|
direction: 'ltr',
|
|
format: '',
|
|
indent: 0,
|
|
type: 'paragraph',
|
|
version: 1
|
|
}
|
|
],
|
|
direction: 'ltr',
|
|
format: '',
|
|
indent: 0,
|
|
type: 'root',
|
|
version: 1
|
|
}
|
|
});
|
|
const pageData = {
|
|
title: 'Test Post',
|
|
status: 'published',
|
|
mobiledoc: mobiledoc,
|
|
lexical: null
|
|
};
|
|
|
|
const {body: pageBody} = await agent
|
|
.post('/pages/?formats=mobiledoc,lexical,html', {
|
|
headers: {
|
|
'content-type': 'application/json'
|
|
}
|
|
})
|
|
.body({pages: [pageData]})
|
|
.expectStatus(201);
|
|
|
|
const [pageResponse] = pageBody.pages;
|
|
|
|
await agent
|
|
.put(`/pages/${pageResponse.id}/?formats=mobiledoc,lexical,html&convert_to_lexical=true`)
|
|
.body({pages: [Object.assign({}, pageResponse)]})
|
|
.expectStatus(200)
|
|
.matchBodySnapshot({
|
|
pages: [Object.assign({}, matchPageShallowIncludes, {lexical: expectedLexical, mobiledoc: null})]
|
|
})
|
|
.matchHeaderSnapshot({
|
|
'content-version': anyContentVersion,
|
|
etag: anyEtag
|
|
});
|
|
});
|
|
});
|
|
});
|