mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-03-11 02:12:21 -05:00
Added API tests for custom theme settings (#13519)
refs https://github.com/TryGhost/Team/issues/1104 - bumped `@tryghost/custom-theme-settings-service` so it throws a more appropriate `ValidationError` when setting keys don't exist or a select value is not known - changed the custom theme settings service to have a `.init()` method which creates an instance of the service under `.api` so that we're able to create the instance at a particular point in the boot process when we know the models have been initialised - there were problems in tests because the service was being initialised through the require chain before models were initialised through the boot process - fixed incorrect `camelCase` of resource name in API responses
This commit is contained in:
parent
7ad6dec0e0
commit
c33b596e9c
10 changed files with 269 additions and 17 deletions
|
@ -119,6 +119,8 @@ async function initServicesForFrontend() {
|
||||||
debug('Begin: Themes');
|
debug('Begin: Themes');
|
||||||
const themeService = require('./server/services/themes');
|
const themeService = require('./server/services/themes');
|
||||||
await themeService.init();
|
await themeService.init();
|
||||||
|
const customThemeSettingsService = require('./server/services/custom-theme-settings');
|
||||||
|
customThemeSettingsService.init();
|
||||||
debug('End: Themes');
|
debug('End: Themes');
|
||||||
|
|
||||||
debug('End: initServicesForFrontend');
|
debug('End: initServicesForFrontend');
|
||||||
|
|
|
@ -6,7 +6,7 @@ module.exports = {
|
||||||
browse: {
|
browse: {
|
||||||
permissions: true,
|
permissions: true,
|
||||||
query() {
|
query() {
|
||||||
return customThemeSettingsService.listSettings();
|
return customThemeSettingsService.api.listSettings();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ module.exports = {
|
||||||
},
|
},
|
||||||
permissions: true,
|
permissions: true,
|
||||||
query(frame) {
|
query(frame) {
|
||||||
return customThemeSettingsService.updateSettings(frame.data.custom_theme_settings);
|
return customThemeSettingsService.api.updateSettings(frame.data.custom_theme_settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
browse(models, apiConfig, frame) {
|
browse(models, apiConfig, frame) {
|
||||||
frame.response = {
|
frame.response = {
|
||||||
customThemeSettings: models
|
custom_theme_settings: models
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
edit(models, apiConfig, frame) {
|
edit(models, apiConfig, frame) {
|
||||||
frame.response = {
|
frame.response = {
|
||||||
customThemeSettings: models
|
custom_theme_settings: models
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,7 +2,13 @@ const {Service: CustomThemeSettingsService} = require('@tryghost/custom-theme-se
|
||||||
const customThemeSettingsCache = require('../../shared/custom-theme-settings-cache');
|
const customThemeSettingsCache = require('../../shared/custom-theme-settings-cache');
|
||||||
const models = require('../models');
|
const models = require('../models');
|
||||||
|
|
||||||
module.exports = new CustomThemeSettingsService({
|
class CustomThemeSettingsServiceWrapper {
|
||||||
model: models.CustomThemeSetting,
|
init() {
|
||||||
cache: customThemeSettingsCache
|
this.api = new CustomThemeSettingsService({
|
||||||
});
|
model: models.CustomThemeSetting,
|
||||||
|
cache: customThemeSettingsCache
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new CustomThemeSettingsServiceWrapper();
|
||||||
|
|
|
@ -12,7 +12,7 @@ module.exports = {
|
||||||
debug('Activating theme (method A on boot)', themeName);
|
debug('Activating theme (method A on boot)', themeName);
|
||||||
// TODO: probably a better place for this to happen - after successful activation / when reloading site?
|
// TODO: probably a better place for this to happen - after successful activation / when reloading site?
|
||||||
if (labs.isSet('customThemeSettings')) {
|
if (labs.isSet('customThemeSettings')) {
|
||||||
customThemeSettings.activateTheme(checkedTheme);
|
customThemeSettings.api.activateTheme(checkedTheme);
|
||||||
}
|
}
|
||||||
bridge.activateTheme(theme, checkedTheme);
|
bridge.activateTheme(theme, checkedTheme);
|
||||||
},
|
},
|
||||||
|
@ -20,7 +20,7 @@ module.exports = {
|
||||||
debug('Activating theme (method B on API "activate")', themeName);
|
debug('Activating theme (method B on API "activate")', themeName);
|
||||||
// TODO: probably a better place for this to happen - after successful activation / when reloading site?
|
// TODO: probably a better place for this to happen - after successful activation / when reloading site?
|
||||||
if (labs.isSet('customThemeSettings')) {
|
if (labs.isSet('customThemeSettings')) {
|
||||||
customThemeSettings.activateTheme(checkedTheme);
|
customThemeSettings.api.activateTheme(checkedTheme);
|
||||||
}
|
}
|
||||||
bridge.activateTheme(theme, checkedTheme);
|
bridge.activateTheme(theme, checkedTheme);
|
||||||
},
|
},
|
||||||
|
@ -28,7 +28,7 @@ module.exports = {
|
||||||
debug('Activating theme (method C on API "override")', themeName);
|
debug('Activating theme (method C on API "override")', themeName);
|
||||||
// TODO: probably a better place for this to happen - after successful activation / when reloading site?
|
// TODO: probably a better place for this to happen - after successful activation / when reloading site?
|
||||||
if (labs.isSet('customThemeSettings')) {
|
if (labs.isSet('customThemeSettings')) {
|
||||||
customThemeSettings.activateTheme(checkedTheme);
|
customThemeSettings.api.activateTheme(checkedTheme);
|
||||||
}
|
}
|
||||||
bridge.activateTheme(theme, checkedTheme);
|
bridge.activateTheme(theme, checkedTheme);
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@
|
||||||
"@tryghost/color-utils": "0.1.2",
|
"@tryghost/color-utils": "0.1.2",
|
||||||
"@tryghost/config-url-helpers": "0.1.2",
|
"@tryghost/config-url-helpers": "0.1.2",
|
||||||
"@tryghost/constants": "0.1.11",
|
"@tryghost/constants": "0.1.11",
|
||||||
"@tryghost/custom-theme-settings-service": "0.1.0",
|
"@tryghost/custom-theme-settings-service": "0.1.1",
|
||||||
"@tryghost/debug": "0.1.5",
|
"@tryghost/debug": "0.1.5",
|
||||||
"@tryghost/email-analytics-provider-mailgun": "1.0.2",
|
"@tryghost/email-analytics-provider-mailgun": "1.0.2",
|
||||||
"@tryghost/email-analytics-service": "1.0.2",
|
"@tryghost/email-analytics-service": "1.0.2",
|
||||||
|
|
211
test/e2e-api/admin/custom_theme_settings.test.js
Normal file
211
test/e2e-api/admin/custom_theme_settings.test.js
Normal file
|
@ -0,0 +1,211 @@
|
||||||
|
const should = require('should');
|
||||||
|
const supertest = require('supertest');
|
||||||
|
const testUtils = require('../../utils');
|
||||||
|
const localUtils = require('./utils');
|
||||||
|
|
||||||
|
const config = require('../../../core/shared/config');
|
||||||
|
|
||||||
|
describe('Custom Theme Settings API', function () {
|
||||||
|
let request;
|
||||||
|
|
||||||
|
before(async function () {
|
||||||
|
await testUtils.startGhost();
|
||||||
|
request = supertest.agent(config.get('url'));
|
||||||
|
await localUtils.doAuth(request, 'users:extra', 'custom_theme_settings');
|
||||||
|
|
||||||
|
// require here so we know it's already been set up with models
|
||||||
|
const customThemeSettingsService = require('../../../core/server/services/custom-theme-settings');
|
||||||
|
// fake a theme activation with custom settings - settings match fixtures
|
||||||
|
await customThemeSettingsService.api.activateTheme({
|
||||||
|
name: 'casper',
|
||||||
|
customSettings: {
|
||||||
|
header_typography: {
|
||||||
|
type: 'select',
|
||||||
|
options: ['Serif', 'Sans-serif'],
|
||||||
|
default: 'Sans-serif'
|
||||||
|
},
|
||||||
|
footer_type: {
|
||||||
|
type: 'select',
|
||||||
|
options: ['Full', 'Minimal', 'CTA'],
|
||||||
|
default: 'Full',
|
||||||
|
group: 'homepage'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Browse', function () {
|
||||||
|
it('can fetch settings for current theme', async function () {
|
||||||
|
const res = await request
|
||||||
|
.get(localUtils.API.getApiQuery(`custom_theme_settings/`))
|
||||||
|
.set('Origin', config.get('url'))
|
||||||
|
.set('Accept', 'application/json')
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
should.not.exist(res.headers['x-cache-invalidate']);
|
||||||
|
const jsonResponse = res.body;
|
||||||
|
should.exist(jsonResponse);
|
||||||
|
should.exist(jsonResponse.custom_theme_settings);
|
||||||
|
|
||||||
|
jsonResponse.custom_theme_settings.length.should.equal(2);
|
||||||
|
|
||||||
|
jsonResponse.custom_theme_settings[0].should.match({
|
||||||
|
id: /.+/,
|
||||||
|
key: 'header_typography',
|
||||||
|
type: 'select',
|
||||||
|
options: ['Serif', 'Sans-serif'],
|
||||||
|
default: 'Sans-serif',
|
||||||
|
value: 'Serif'
|
||||||
|
});
|
||||||
|
|
||||||
|
jsonResponse.custom_theme_settings[1].should.match({
|
||||||
|
id: /.+/,
|
||||||
|
key: 'footer_type',
|
||||||
|
type: 'select',
|
||||||
|
options: ['Full', 'Minimal', 'CTA'],
|
||||||
|
default: 'Full',
|
||||||
|
value: 'Full',
|
||||||
|
group: 'homepage'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Edit', function () {
|
||||||
|
it('can update all settings for current theme', async function () {
|
||||||
|
// `.updateSettings()` only cares about `key` and `value`, everything else is set by the theme
|
||||||
|
const custom_theme_settings = [{
|
||||||
|
id: 'id',
|
||||||
|
type: 'type',
|
||||||
|
options: ['option'],
|
||||||
|
default: 'default',
|
||||||
|
key: 'header_typography',
|
||||||
|
value: 'Sans-serif'
|
||||||
|
}, {
|
||||||
|
key: 'footer_type',
|
||||||
|
value: 'Minimal'
|
||||||
|
}];
|
||||||
|
|
||||||
|
const res = await request
|
||||||
|
.put(localUtils.API.getApiQuery(`custom_theme_settings/`))
|
||||||
|
.set('Origin', config.get('url'))
|
||||||
|
.send({custom_theme_settings})
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
should.exist(res.headers['x-cache-invalidate']);
|
||||||
|
|
||||||
|
const jsonResponse = res.body;
|
||||||
|
should.exist(jsonResponse);
|
||||||
|
should.exist(jsonResponse.custom_theme_settings);
|
||||||
|
|
||||||
|
jsonResponse.custom_theme_settings.length.should.equal(2);
|
||||||
|
|
||||||
|
jsonResponse.custom_theme_settings[0].should.match({
|
||||||
|
id: /.+/,
|
||||||
|
key: 'header_typography',
|
||||||
|
type: 'select',
|
||||||
|
options: ['Serif', 'Sans-serif'],
|
||||||
|
default: 'Sans-serif',
|
||||||
|
value: 'Sans-serif'
|
||||||
|
});
|
||||||
|
|
||||||
|
jsonResponse.custom_theme_settings[1].should.match({
|
||||||
|
id: /.+/,
|
||||||
|
key: 'footer_type',
|
||||||
|
type: 'select',
|
||||||
|
options: ['Full', 'Minimal', 'CTA'],
|
||||||
|
default: 'Full',
|
||||||
|
value: 'Minimal',
|
||||||
|
group: 'homepage'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can update some settings', async function () {
|
||||||
|
// `.updateSettings()` only cares about `key` and `value`, everything else is set by the theme
|
||||||
|
const custom_theme_settings = [{
|
||||||
|
key: 'footer_type',
|
||||||
|
value: 'Minimal'
|
||||||
|
}];
|
||||||
|
|
||||||
|
const res = await request
|
||||||
|
.put(localUtils.API.getApiQuery(`custom_theme_settings/`))
|
||||||
|
.set('Origin', config.get('url'))
|
||||||
|
.send({custom_theme_settings})
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
should.exist(res.headers['x-cache-invalidate']);
|
||||||
|
|
||||||
|
const jsonResponse = res.body;
|
||||||
|
should.exist(jsonResponse);
|
||||||
|
should.exist(jsonResponse.custom_theme_settings);
|
||||||
|
|
||||||
|
jsonResponse.custom_theme_settings.length.should.equal(2);
|
||||||
|
|
||||||
|
jsonResponse.custom_theme_settings[0].should.match({
|
||||||
|
id: /.+/,
|
||||||
|
key: 'header_typography',
|
||||||
|
type: 'select',
|
||||||
|
options: ['Serif', 'Sans-serif'],
|
||||||
|
default: 'Sans-serif',
|
||||||
|
value: 'Sans-serif' // set in previous test
|
||||||
|
});
|
||||||
|
|
||||||
|
jsonResponse.custom_theme_settings[1].should.match({
|
||||||
|
id: /.+/,
|
||||||
|
key: 'footer_type',
|
||||||
|
type: 'select',
|
||||||
|
options: ['Full', 'Minimal', 'CTA'],
|
||||||
|
default: 'Full',
|
||||||
|
value: 'Minimal',
|
||||||
|
group: 'homepage'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('errors for unknown key', async function () {
|
||||||
|
const custom_theme_settings = [{
|
||||||
|
key: 'unknown',
|
||||||
|
value: 'Not gonna work'
|
||||||
|
}];
|
||||||
|
|
||||||
|
const res = await request
|
||||||
|
.put(localUtils.API.getApiQuery(`custom_theme_settings/`))
|
||||||
|
.set('Origin', config.get('url'))
|
||||||
|
.send({custom_theme_settings})
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||||
|
.expect(422);
|
||||||
|
|
||||||
|
should.not.exist(res.headers['x-cache-invalidate']);
|
||||||
|
|
||||||
|
const jsonResponse = res.body;
|
||||||
|
should.exist(jsonResponse);
|
||||||
|
should.exist(jsonResponse.errors);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('errors for invalid select value', async function () {
|
||||||
|
const custom_theme_settings = [{
|
||||||
|
key: 'header_typography',
|
||||||
|
value: 'Not gonna work'
|
||||||
|
}];
|
||||||
|
|
||||||
|
const res = await request
|
||||||
|
.put(localUtils.API.getApiQuery(`custom_theme_settings/`))
|
||||||
|
.set('Origin', config.get('url'))
|
||||||
|
.send({custom_theme_settings})
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||||
|
.expect(422);
|
||||||
|
|
||||||
|
should.not.exist(res.headers['x-cache-invalidate']);
|
||||||
|
|
||||||
|
const jsonResponse = res.body;
|
||||||
|
should.exist(jsonResponse);
|
||||||
|
should.exist(jsonResponse.errors);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -543,6 +543,12 @@ const fixtures = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
insertCustomThemeSettings: function insertCustomThemeSettings() {
|
||||||
|
return Promise.map(DataGenerator.forKnex.custom_theme_settings, function (setting) {
|
||||||
|
return models.CustomThemeSetting.add(setting, context.internal);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
async enableAllLabsFeatures() {
|
async enableAllLabsFeatures() {
|
||||||
const labsValue = Object.fromEntries(labsService.WRITABLE_KEYS_ALLOWLIST.map(key => [key, true]));
|
const labsValue = Object.fromEntries(labsService.WRITABLE_KEYS_ALLOWLIST.map(key => [key, true]));
|
||||||
const labsSetting = DataGenerator.forKnex.createSetting({
|
const labsSetting = DataGenerator.forKnex.createSetting({
|
||||||
|
@ -652,6 +658,9 @@ const toDoList = {
|
||||||
},
|
},
|
||||||
'labs:enabled': function enableAllLabsFeatures() {
|
'labs:enabled': function enableAllLabsFeatures() {
|
||||||
return fixtures.enableAllLabsFeatures();
|
return fixtures.enableAllLabsFeatures();
|
||||||
|
},
|
||||||
|
custom_theme_settings: function insertCustomThemeSettings() {
|
||||||
|
return fixtures.insertCustomThemeSettings();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -668,6 +668,23 @@ DataGenerator.Content = {
|
||||||
name: 'Test snippet 1',
|
name: 'Test snippet 1',
|
||||||
mobiledoc: '{}'
|
mobiledoc: '{}'
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
custom_theme_settings: [
|
||||||
|
{
|
||||||
|
id: ObjectId().toHexString(),
|
||||||
|
theme: 'casper',
|
||||||
|
key: 'header_typography',
|
||||||
|
type: 'select',
|
||||||
|
value: 'Serif'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: ObjectId().toHexString(),
|
||||||
|
theme: 'casper',
|
||||||
|
key: 'footer_type',
|
||||||
|
type: 'select',
|
||||||
|
value: 'Full'
|
||||||
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1282,6 +1299,11 @@ DataGenerator.forKnex = (function () {
|
||||||
createBasic(DataGenerator.Content.snippets[0])
|
createBasic(DataGenerator.Content.snippets[0])
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const custom_theme_settings = [
|
||||||
|
createBasic(DataGenerator.Content.custom_theme_settings[0]),
|
||||||
|
createBasic(DataGenerator.Content.custom_theme_settings[1])
|
||||||
|
];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
createPost,
|
createPost,
|
||||||
createGenericPost,
|
createGenericPost,
|
||||||
|
@ -1306,6 +1328,7 @@ DataGenerator.forKnex = (function () {
|
||||||
createWebhook,
|
createWebhook,
|
||||||
createIntegration,
|
createIntegration,
|
||||||
createEmail,
|
createEmail,
|
||||||
|
createCustomThemeSetting: createBasic,
|
||||||
|
|
||||||
invites,
|
invites,
|
||||||
posts,
|
posts,
|
||||||
|
@ -1330,7 +1353,8 @@ DataGenerator.forKnex = (function () {
|
||||||
stripe_customer_subscriptions,
|
stripe_customer_subscriptions,
|
||||||
stripe_prices,
|
stripe_prices,
|
||||||
stripe_products,
|
stripe_products,
|
||||||
snippets
|
snippets,
|
||||||
|
custom_theme_settings
|
||||||
};
|
};
|
||||||
}());
|
}());
|
||||||
|
|
||||||
|
|
|
@ -1333,10 +1333,10 @@
|
||||||
resolved "https://registry.yarnpkg.com/@tryghost/constants/-/constants-0.1.11.tgz#ffcc6ccb10a768aaa9276c3a22b2dea9f560e247"
|
resolved "https://registry.yarnpkg.com/@tryghost/constants/-/constants-0.1.11.tgz#ffcc6ccb10a768aaa9276c3a22b2dea9f560e247"
|
||||||
integrity sha512-ml1aJ4nJmfA8MRAJ3l9+iTdccGDQiUN1En8XwYwypfrKlECR8Mw/kKRPnqHge598+ED6J1+at5gArSq6bLKbug==
|
integrity sha512-ml1aJ4nJmfA8MRAJ3l9+iTdccGDQiUN1En8XwYwypfrKlECR8Mw/kKRPnqHge598+ED6J1+at5gArSq6bLKbug==
|
||||||
|
|
||||||
"@tryghost/custom-theme-settings-service@0.1.0":
|
"@tryghost/custom-theme-settings-service@0.1.1":
|
||||||
version "0.1.0"
|
version "0.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/@tryghost/custom-theme-settings-service/-/custom-theme-settings-service-0.1.0.tgz#ebb23289b7c092e3125db12e0fa8be74d2054db5"
|
resolved "https://registry.yarnpkg.com/@tryghost/custom-theme-settings-service/-/custom-theme-settings-service-0.1.1.tgz#f7403f7b9ad11a1ef0a0211ac28011210df31f36"
|
||||||
integrity sha512-n4nCEZOZLheSHWMykpMjYHuOc0AUn+XJRW9WAEgD7g9kXuArwvsa42uWVZ12VqyQ5JSz3W5rVYXNLlZX+M3k4w==
|
integrity sha512-Mo0w+UMYbhsgHm47x2fGek7j2Qo3RhZaALCRvdaBrHjaXihaSAXTy6T+5dKY4eQeiZ4rZ+5QVza7bQ93ttcxbg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@tryghost/debug" "^0.1.5"
|
"@tryghost/debug" "^0.1.5"
|
||||||
"@tryghost/errors" "^0.2.14"
|
"@tryghost/errors" "^0.2.14"
|
||||||
|
|
Loading…
Add table
Reference in a new issue