Ghost/ghost/core/test/utils/index.js
Chris Raible c0471f0c28
🐛 Fixed frontend routing prioritizing collections over built in routes (#20765)
ref
https://linear.app/tryghost/issue/ONC-242/frontend-routing-prioritizes-collections-over-taxonomies

- Under a fairly specific edge case with a collection route that conflicts with a default, built-in route ("taxonomy" — like tags, authors, etc), the frontend routing would prioritize the collection over the taxonomy.

- For example, with the following in a custom `routes.yaml`:
```
collections:
  /:
    permalink: /{primary_tag}/{slug}/
    template: index
```

If a post exists with the same slug as its primary tag's slug, the frontend routing would redirect the `/tag/{slug}/` route to the post in the collection, rather than serving the tag itself.

- This commit changes that, so if a collection's route conflicts with e.g. a `/tag/{slug}/` default route, Ghost will still return the built in route, rather than the collection.
2024-08-21 13:45:59 -07:00

174 lines
5.0 KiB
JavaScript

require('../../core/server/overrides');
// Utility Packages
const {sequence} = require('@tryghost/promise');
const debug = require('@tryghost/debug')('test:utils');
const _ = require('lodash');
// Ghost Internals
const models = require('../../core/server/models');
// Other Test Utilities
const e2eUtils = require('./e2e-utils');
const APIUtils = require('./api');
const dbUtils = require('./db-utils');
const fixtureUtils = require('./fixture-utils');
const redirects = require('./redirects');
const cacheRules = require('./fixtures/cache-rules');
const context = require('./fixtures/context');
const DataGenerator = require('./fixtures/data-generator');
const filterData = require('./fixtures/filter-param');
// Require additional assertions which help us keep our tests small and clear
require('./assertions');
// ## Test Setup and Teardown
const initFixtures = function initFixtures() {
const options = _.merge({init: true}, _.transform(arguments, function (result, val) {
result[val] = true;
}));
const fixtureOps = fixtureUtils.getFixtureOps(options);
return sequence(fixtureOps);
};
/**
* ## Setup Integration Tests
* Setup takes a list of arguments like: 'default', 'tag', 'perms:tag', 'perms:init'
* Setup does 'init' (DB) by default
*/
const setup = function setup() {
/*eslint no-invalid-this: "off"*/
const self = this;
const args = arguments;
return function innerSetup() {
debug('Setup start');
models.init();
return initFixtures
.apply(self, args)
.finally(() => {
debug('Setup end');
});
};
};
const createUser = function createUser(options) {
const user = options.user;
const role = options.role;
return models.Role.fetchAll(context.internal)
.then(function (roles) {
roles = roles.toJSON();
user.roles = [_.find(roles, {name: role})];
return models.User.add(user, context.internal)
.then(function () {
return user;
});
});
};
const createPost = function createPost(options) {
const post = DataGenerator.forKnex.createPost(options.post);
return models.Post.add(post, context.internal);
};
const createTag = function createTag(options) {
const tag = DataGenerator.forKnex.createTag(options.tag);
return models.Tag.add(tag, context.internal);
};
const createEmail = function createEmail(options) {
const email = DataGenerator.forKnex.createEmail(options.email);
return models.Email.add(email, context.internal);
};
const createEmailedPost = async function createEmailedPost({postOptions, emailOptions}) {
const post = await createPost(postOptions);
emailOptions.email.post_id = post.id;
const email = await createEmail(emailOptions);
return {post, email};
};
module.exports = {
startGhost: e2eUtils.startGhost,
stopGhost: e2eUtils.stopGhost,
getExistingData: e2eUtils.getExistingData,
teardownDb: dbUtils.teardown,
truncate: dbUtils.truncate,
knex: dbUtils.knex,
setup: setup,
createUser: createUser,
createPost: createPost,
createTag: createTag,
createEmailedPost,
/**
* renderObject: res.render(view, dbResponse)
* templateOptions: hbs.updateTemplateOptions(...)
*/
createHbsResponse: function createHbsResponse(options) {
const renderObject = options.renderObject || {};
const templateOptions = options.templateOptions;
const locals = options.locals || {};
const hbsStructure = {
data: {
site: {},
config: {},
labs: {},
root: {
_locals: {}
}
}
};
_.merge(hbsStructure.data, templateOptions);
_.merge(hbsStructure.data.root, renderObject);
_.merge(hbsStructure.data.root, locals);
hbsStructure.data.root._locals = locals;
return hbsStructure;
},
initFixtures: initFixtures,
initData: dbUtils.initData,
clearData: dbUtils.clearData,
setupRedirectsFile: redirects.setupFile,
fixtures: fixtureUtils.fixtures,
DataGenerator: DataGenerator,
filterData: filterData,
API: APIUtils({getFixtureOps: fixtureUtils.getFixtureOps}),
// Helpers to make it easier to write tests which are easy to read
context: context,
permissions: {
owner: {user: {roles: [DataGenerator.Content.roles[3]]}},
admin: {user: {roles: [DataGenerator.Content.roles[0]]}},
editor: {user: {roles: [DataGenerator.Content.roles[1]]}},
author: {user: {roles: [DataGenerator.Content.roles[2]]}},
contributor: {user: {roles: [DataGenerator.Content.roles[4]]}}
},
roles: {
ids: {
owner: DataGenerator.Content.roles[3].id,
admin: DataGenerator.Content.roles[0].id,
editor: DataGenerator.Content.roles[1].id,
author: DataGenerator.Content.roles[2].id,
contributor: DataGenerator.Content.roles[4].id
}
},
cacheRules: cacheRules
};