Fixed configUtils and adapter cache issues in E2E tests (#16167)

no issue

There are a couple of issues with resetting the Ghost instance between
E2E test files:

These issues came to the surface because of new tests written in
https://github.com/TryGhost/Ghost/pull/16117

**1. configUtils.restore does not work correctly**
`config.reset()` is a callback based method. On top of that, it doesn't
really work reliably (https://github.com/indexzero/nconf/issues/93)

What kinda happens, is that you first call `config.reset` but
immediately after you correcty reset the config using the `config.set`
calls afterwards. But since `config.reset` is async, that reset will
happen after all those sets, and the end result is that it isn't reset
correctly.

This mainly caused issues in the new updated images tests, which were
updating the config `imageOptimization.contentImageSizes`, which is a
deeply nested config value. Maybe some references to objects are reused
in nconf that cause this issue?

Wrapping `config.reset()` in a promise does fix the issue.

**2. Adapters cache not reset between tests**
At the start of each test, we set `paths:contentPath` to a nice new
temporary directory. But if a previous test already requests a
localStorage adapter, that adapter would have been created and in the
constructor `paths:contentPath` would have been passed. That same
instance will be reused in the next test run. So it won't read the new
config again. To fix this, we need to reset the adapter instances
between E2E tests.

How was this visible? Test uploads were stored in the actual git
repository, and not in a temporary directory. When writing the new image
upload tests, this also resulted in unreliable test runs because some
image names were already taken (from previous test runs).

**3. Old 2E2 test Ghost server not stopped**
Sometimes we still need access to the frontend test server using
`getAgentsWithFrontend`. But that does start a new Ghost server which is
actually listening for HTTP traffic. This could result in a fatal error
in tests because the port is already in use. The issue is that old E2E
tests also start a HTTP server, but they don't stop the server. When you
used the old `startGhost` util, it would check if a server was already
running and stop it first. The new `getAgentsWithFrontend` now also has
the same functionality to fix that issue.
This commit is contained in:
Simon Backx 2023-01-30 14:06:20 +01:00 committed by GitHub
parent b8fe582378
commit 8f8ca481a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
74 changed files with 245 additions and 211 deletions

View File

@ -53,6 +53,15 @@ module.exports = class AdapterManager {
this.baseClasses[type] = BaseClass;
}
/**
* Force recreation of all instances instead of reusing cached instances. Use when editing config file during tests.
*/
clearInstanceCache() {
for (const key of Object.keys(this.instanceCache)) {
this.instanceCache[key] = {};
}
}
/**
* getAdapter
*
@ -75,7 +84,7 @@ module.exports = class AdapterManager {
} else {
adapterType = adapterName;
}
const adapterCache = this.instanceCache[adapterType];
if (!adapterCache) {

View File

@ -29,5 +29,12 @@ module.exports = {
const {adapterClassName, adapterConfig} = resolveAdapterOptions(name, adapterServiceConfig);
return adapterManager.getAdapter(name, adapterClassName, adapterConfig);
},
/**
* Force recreation of all instances instead of reusing cached instances. Use when editing config file during tests.
*/
clearCache() {
adapterManager.clearInstanceCache();
}
};

View File

@ -791,7 +791,7 @@ describe('Members API', function () {
await agent.delete(`/members/${memberPassVerification.id}`);
await agent.delete(`/members/${memberFailVerification.id}`);
configUtils.restore();
await configUtils.restore();
});
it('Can add and send a signup confirmation email', async function () {

View File

@ -17,8 +17,8 @@ describe('Authors Content API', function () {
await testUtils.initFixtures('owner:post', 'users', 'user:inactive', 'posts', 'api_keys');
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
});
const validKey = localUtils.getValidKey();

View File

@ -18,8 +18,8 @@ describe('Tags Content API', function () {
await testUtils.initFixtures('users', 'user:inactive', 'posts', 'tags:extra', 'api_keys');
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
});
const validKey = localUtils.getValidKey();

View File

@ -191,8 +191,8 @@ describe('Comments API', function () {
mockManager.mockMail();
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
mockManager.restore();
});

View File

@ -20,10 +20,10 @@ describe('Members Feedback', function () {
mockManager.mockMail();
});
afterEach(function () {
afterEach(async function () {
clock?.restore();
clock = undefined;
configUtils.restore();
await configUtils.restore();
mockManager.restore();
});
@ -273,7 +273,7 @@ describe('Members Feedback', function () {
}
]
});
const model3 = await models.MemberFeedback.findOne({id: feedbackId}, {require: true});
assert.equal(body3.feedback[0].id, feedbackId);
assert.equal(body3.feedback[0].score, 1);

View File

@ -28,8 +28,8 @@ describe('Advanced URL Configurations', function () {
request = supertest.agent(configUtils.config.get('server:host') + ':' + configUtils.config.get('server:port'));
});
after(function () {
configUtils.restore();
after(async function () {
await configUtils.restore();
urlUtils.restore();
});

View File

@ -170,7 +170,7 @@ describe('Default Frontend routing', function () {
});
after(async function () {
configUtils.restore();
await configUtils.restore();
await testUtils.startGhost({forceStart: true});
request = supertest.agent(configUtils.config.get('url'));

View File

@ -63,9 +63,9 @@ describe('Admin Routing', function () {
request = supertest.agent(config.get('server:host') + ':' + config.get('server:port'));
});
after(function () {
after(async function () {
urlUtils.restore();
configUtils.restore();
await configUtils.restore();
});
it('should redirect admin access over non-HTTPS', async function () {
@ -90,8 +90,8 @@ describe('Admin Routing', function () {
configUtils.set('paths', configPaths);
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
});
it('serves assets in production', async function () {

View File

@ -191,8 +191,8 @@ describe('Member Attribution Service', function () {
configUtils.set('url', 'https://siteurl.com/subdirectory/');
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
});
it('resolves urls', async function () {

View File

@ -184,7 +184,7 @@ describe('Batch sending tests', function () {
});
afterEach(async function () {
configUtils.restore();
await configUtils.restore();
await models.Settings.edit([{
key: 'email_verification_required',
value: false
@ -653,7 +653,7 @@ describe('Batch sending tests', function () {
sinon.assert.calledOnce(getSignupEvents);
assert.equal(settingsCache.get('email_verification_required'), true);
configUtils.restore();
await configUtils.restore();
});
describe('Analytics', function () {

View File

@ -240,9 +240,9 @@ describe('Integration: services/url/UrlService', function () {
})();
});
afterEach(function () {
afterEach(async function () {
urlService.resetGenerators();
configUtils.restore();
await configUtils.restore();
});
it('getUrl', function () {

View File

@ -15,8 +15,8 @@ describe('Authors Content API', function () {
await testUtils.initFixtures('owner:post', 'users', 'user:inactive', 'posts', 'api_keys');
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
});
it('can read authors with fields', function () {

View File

@ -16,8 +16,8 @@ describe('api/endpoints/content/pages', function () {
await testUtils.initFixtures('users', 'user:inactive', 'posts', 'tags:extra', 'api_keys');
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
});
it('Returns a validation error when unsupported "page" filter is used', function () {

View File

@ -16,8 +16,8 @@ describe('api/endpoints/content/posts', function () {
await testUtils.initFixtures('users', 'user:inactive', 'posts', 'tags:extra', 'api_keys');
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
urlUtils.restore();
});

View File

@ -17,8 +17,8 @@ describe('api/endpoints/content/tags', function () {
await testUtils.initFixtures('users', 'user:inactive', 'posts', 'tags:extra', 'api_keys');
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
});
it('Can read tags with fields', function () {

View File

@ -43,8 +43,8 @@ describe('Frontend behavior tests', function () {
sinon.restore();
});
after(function () {
configUtils.restore();
after(async function () {
await configUtils.restore();
urlUtils.restore();
sinon.restore();
});
@ -292,9 +292,9 @@ describe('Frontend behavior tests', function () {
urlUtils.stubUrlUtilsFromConfig();
});
after(function () {
after(async function () {
urlUtils.restore();
configUtils.restore();
await configUtils.restore();
});
describe('protocol', function () {
@ -398,8 +398,8 @@ describe('Frontend behavior tests', function () {
localUtils.overrideGhostConfig(configUtils);
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
urlUtils.restore();
});
@ -505,8 +505,8 @@ describe('Frontend behavior tests', function () {
localUtils.overrideGhostConfig(configUtils);
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
urlUtils.restore();
});
@ -558,8 +558,8 @@ describe('Frontend behavior tests', function () {
localUtils.overrideGhostConfig(configUtils);
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
urlUtils.restore();
});
@ -650,8 +650,8 @@ describe('Frontend behavior tests', function () {
localUtils.overrideGhostConfig(configUtils);
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
urlUtils.restore();
});
@ -726,8 +726,8 @@ describe('Frontend behavior tests', function () {
localUtils.overrideGhostConfig(configUtils);
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
urlUtils.restore();
});
@ -873,8 +873,8 @@ describe('Frontend behavior tests', function () {
localUtils.overrideGhostConfig(configUtils);
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
urlUtils.restore();
});
@ -978,8 +978,8 @@ describe('Frontend behavior tests', function () {
localUtils.overrideGhostConfig(configUtils);
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
urlUtils.restore();
sinon.restore();
});
@ -1036,8 +1036,8 @@ describe('Frontend behavior tests', function () {
localUtils.overrideGhostConfig(configUtils);
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
urlUtils.restore();
});
@ -1087,8 +1087,8 @@ describe('Frontend behavior tests', function () {
localUtils.overrideGhostConfig(configUtils);
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
urlUtils.restore();
sinon.restore();
});
@ -1262,8 +1262,8 @@ describe('Frontend behavior tests', function () {
localUtils.overrideGhostConfig(configUtils);
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
urlUtils.restore();
});
@ -1495,8 +1495,8 @@ describe('Frontend behavior tests', function () {
localUtils.overrideGhostConfig(configUtils);
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
urlUtils.restore();
});

View File

@ -13,8 +13,8 @@ describe('Integration - Web - vhosts', function () {
before(testUtils.teardownDb);
after(function () {
configUtils.restore();
after(async function () {
await configUtils.restore();
urlUtils.restore();
sinon.restore();
});
@ -36,8 +36,8 @@ describe('Integration - Web - vhosts', function () {
urlUtils.stubUrlUtilsFromConfig();
});
after(function () {
configUtils.restore();
after(async function () {
await configUtils.restore();
urlUtils.restore();
sinon.restore();
});
@ -144,8 +144,8 @@ describe('Integration - Web - vhosts', function () {
urlUtils.stubUrlUtilsFromConfig();
});
after(function () {
configUtils.restore();
after(async function () {
await configUtils.restore();
urlUtils.restore();
sinon.restore();
});
@ -297,8 +297,8 @@ describe('Integration - Web - vhosts', function () {
urlUtils.stubUrlUtilsFromConfig();
});
after(function () {
configUtils.restore();
after(async function () {
await configUtils.restore();
urlUtils.restore();
sinon.restore();
});

View File

@ -41,8 +41,8 @@ describe('Post Model', function () {
});
describe('Single author posts', function () {
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
});
describe('fetchOne/fetchAll/fetchPage', function () {

View File

@ -229,14 +229,12 @@ describe('Dynamic Routing', function () {
});
});
after(function () {
configUtils.restore();
after(async function () {
await configUtils.restore();
return testUtils.startGhost({forceStart: true})
.then(function () {
sinon.stub(themeEngine.getActive(), 'config').withArgs('posts_per_page').returns(5);
request = supertest.agent(config.get('url'));
});
await testUtils.startGhost({forceStart: true});
sinon.stub(themeEngine.getActive(), 'config').withArgs('posts_per_page').returns(5);
request = supertest.agent(config.get('url'));
});
it('should redirect without slash', function (done) {
@ -431,14 +429,12 @@ describe('Dynamic Routing', function () {
});
});
after(function () {
configUtils.restore();
after(async function () {
await configUtils.restore();
return testUtils.startGhost({forceStart: true})
.then(function () {
sinon.stub(themeEngine.getActive(), 'config').withArgs('posts_per_page').returns(5);
request = supertest.agent(config.get('url'));
});
await testUtils.startGhost({forceStart: true});
sinon.stub(themeEngine.getActive(), 'config').withArgs('posts_per_page').returns(5);
request = supertest.agent(config.get('url'));
});
it('should redirect without slash', function (done) {

View File

@ -211,13 +211,12 @@ describe('Frontend Routing', function () {
});
after(function (done) {
configUtils.restore();
testUtils.startGhost({forceStart: true})
.then(function () {
request = supertest.agent(config.get('url'));
addPosts(done);
});
configUtils.restore().then(() => {
return testUtils.startGhost({forceStart: true});
}).then(function () {
request = supertest.agent(config.get('url'));
addPosts(done);
});
});
it('should redirect without slash', function (done) {

View File

@ -48,9 +48,9 @@ describe('Private Controller', function () {
});
});
afterEach(function () {
afterEach(async function () {
sinon.restore();
configUtils.restore();
await configUtils.restore();
});
it('Should render default password page when theme has no password template', function (done) {

View File

@ -21,8 +21,8 @@ describe('{{asset}} helper', function () {
});
});
after(function () {
configUtils.restore();
after(async function () {
await configUtils.restore();
sinon.restore();
});
@ -92,8 +92,8 @@ describe('{{asset}} helper', function () {
configUtils.set({'admin:url': 'http://localhost'});
});
after(function () {
configUtils.restore();
after(async function () {
await configUtils.restore();
});
it('handles favicon correctly', function () {

View File

@ -27,10 +27,10 @@ describe('{{comment_count}} helper', function () {
sinon.stub(settingsCache, 'get');
});
afterEach(function () {
afterEach(async function () {
mockManager.restore();
sinon.restore();
configUtils.restore();
await configUtils.restore();
});
it('returns a script with the post id when autowrap is disabled', async function () {

View File

@ -24,10 +24,10 @@ describe('{{comments}} helper', function () {
configUtils.set('comments:version', 'test.version');
});
afterEach(function () {
afterEach(async function () {
mockManager.restore();
sinon.restore();
configUtils.restore();
await configUtils.restore();
});
it('returns undefined if not used withing post context', function (done) {

View File

@ -338,8 +338,8 @@ describe('{{#get}} helper', function () {
};
});
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
});
it('should log a warning if it hits the notify threshold', async function () {

View File

@ -362,9 +362,9 @@ describe('{{ghost_head}} helper', function () {
makeFixtures();
});
afterEach(function () {
afterEach(async function () {
sinon.restore();
configUtils.restore();
await configUtils.restore();
});
describe('without Code Injection', function () {

View File

@ -23,8 +23,8 @@ describe('{{img_url}} helper', function () {
configUtils.set({url: 'http://localhost:65535/'});
});
after(function () {
configUtils.restore();
after(async function () {
await configUtils.restore();
});
it('should output relative url of image', function () {
@ -85,8 +85,8 @@ describe('{{img_url}} helper', function () {
configUtils.set({url: 'http://localhost:65535/blog'});
});
after(function () {
configUtils.restore();
after(async function () {
await configUtils.restore();
});
it('should output relative url of image', function () {
@ -113,8 +113,8 @@ describe('{{img_url}} helper', function () {
configUtils.set({url: 'http://localhost:65535/'});
});
after(function () {
configUtils.restore();
after(async function () {
await configUtils.restore();
});
it('should output correct url for absolute paths which are internal', function () {
@ -204,7 +204,7 @@ describe('{{img_url}} helper', function () {
const rendered = img_url('/content/images/author-image-relative-url.png', {
hash: {
size: 'medium'
},
},
data: {
config: {
image_sizes: {
@ -222,7 +222,7 @@ describe('{{img_url}} helper', function () {
const rendered = img_url('/content/images/author-image-relative-url.png', {
hash: {
format: 'webp'
},
},
data: {
config: {
image_sizes: {
@ -241,7 +241,7 @@ describe('{{img_url}} helper', function () {
hash: {
size: 'w600',
format: 'webp'
},
},
data: {
config: {
image_sizes: {
@ -260,7 +260,7 @@ describe('{{img_url}} helper', function () {
hash: {
size: 'w600',
format: 'invalid'
},
},
data: {
config: {
image_sizes: {
@ -280,8 +280,8 @@ describe('{{img_url}} helper', function () {
configUtils.set({url: 'http://localhost:65535/'});
});
after(function () {
configUtils.restore();
after(async function () {
await configUtils.restore();
});
it('works without size option', function () {

View File

@ -34,8 +34,8 @@ describe('{{link}} helper', function () {
};
});
after(function () {
configUtils.restore();
after(async function () {
await configUtils.restore();
});
describe('basic behavior: simple links without context', function () {

View File

@ -32,8 +32,8 @@ describe('{{link_class}} helper', function () {
};
});
after(function () {
configUtils.restore();
after(async function () {
await configUtils.restore();
});
it('throws an error for missing for=""', function () {

View File

@ -14,8 +14,8 @@ describe('{{meta_title}} helper', function () {
});
});
after(function () {
configUtils.restore();
after(async function () {
await configUtils.restore();
sinon.restore();
});

View File

@ -30,8 +30,8 @@ describe('{{url}} helper', function () {
configUtils.set({url: 'http://localhost:65535/'});
});
after(function () {
configUtils.restore();
after(async function () {
await configUtils.restore();
});
it('should return the slug with a prefix slash if the context is a post', function () {
@ -239,8 +239,8 @@ describe('{{url}} helper', function () {
configUtils.set({url: 'http://localhost:65535/blog'});
});
after(function () {
configUtils.restore();
after(async function () {
await configUtils.restore();
});
it('external urls should be retained in a nav context with subdir', function () {

View File

@ -8,8 +8,8 @@ const config = configUtils.config;
const getAssetUrl = require('../../../../core/frontend/meta/asset-url');
describe('getAssetUrl', function () {
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
sinon.restore();
});
@ -93,8 +93,8 @@ describe('getAssetUrl', function () {
configUtils.set({url: 'http://localhost:65535/blog'});
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
});
it('should return asset url with just context', function () {

View File

@ -128,8 +128,8 @@ describe('getPaginatedUrl', function () {
configUtils.set({url: 'http://localhost:65535/blog'});
});
after(function () {
configUtils.restore();
after(async function () {
await configUtils.restore();
});
it('should calculate correct urls for index', function () {

View File

@ -25,9 +25,9 @@ describe('UNIT - services/routing/ParentRouter', function () {
res.locals = {};
});
afterEach(function () {
afterEach(async function () {
sinon.restore();
configUtils.restore();
await configUtils.restore();
});
describe('fn: _getSiteRouter', function () {

View File

@ -14,9 +14,9 @@ describe('UNIT - services/routing/RSSRouter', function () {
sinon.stub(urlUtils, 'urlJoin');
});
afterEach(function () {
afterEach(async function () {
sinon.restore();
configUtils.restore();
await configUtils.restore();
});
it('default', function () {

View File

@ -10,8 +10,8 @@ describe('UNIT - services/routing/StaticRoutesRouter', function () {
let next;
let routerCreatedSpy;
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
});
beforeEach(function () {

View File

@ -139,13 +139,13 @@ describe('Unit - services/routing/controllers/entry', function () {
entry: post
});
urlUtils.redirectToAdmin.callsFake(function (statusCode, _res, editorUrl) {
configUtils.restore();
urlUtils.redirectToAdmin.callsFake(async function (statusCode, _res, editorUrl) {
await configUtils.restore();
done(new Error('redirectToAdmin was called'));
});
controllers.entry(req, res, (err) => {
configUtils.restore();
controllers.entry(req, res, async (err) => {
await configUtils.restore();
urlUtils.redirectToAdmin.called.should.eql(false);
should.not.exist(err);
done(err);

View File

@ -22,9 +22,9 @@ describe('Unit - services/routing/controllers/previews', function () {
};
}
afterEach(function () {
afterEach(async function () {
sinon.restore();
configUtils.restore();
await configUtils.restore();
});
let previewStub;

View File

@ -8,8 +8,8 @@ describe('RSS: Cache', function () {
let generateSpy;
let generateFeedReset;
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
sinon.restore();
generateFeedReset();
});

View File

@ -37,9 +37,9 @@ describe('RSS: Generate Feed', function () {
});
});
afterEach(function () {
afterEach(async function () {
sinon.restore();
configUtils.restore();
await configUtils.restore();
});
beforeEach(function () {

View File

@ -10,8 +10,8 @@ describe('Frontend apps:', function () {
configUtils.set({'portal:styles': 'https://cdn.example.com/~{version}/main.css'});
});
after(function () {
configUtils.restore();
after(async function () {
await configUtils.restore();
});
it('should return app urls and version from config', async function () {

View File

@ -29,9 +29,9 @@ describe('Serve Favicon', function () {
originalStoragePath = storage.getStorage().storagePath;
});
afterEach(function () {
afterEach(async function () {
sinon.restore();
configUtils.restore();
await configUtils.restore();
localSettingsCache = {};
storage.getStorage().storagePath = originalStoragePath;
});

View File

@ -14,13 +14,13 @@ describe('Scheduling: utils', function () {
}
});
afterEach(function () {
afterEach(async function () {
if (scope.adapter) {
fs.unlinkSync(scope.adapter);
scope.adapter = null;
}
configUtils.restore();
await configUtils.restore();
});
describe('success', function () {

View File

@ -25,9 +25,9 @@ describe('Local Images Storage', function () {
momentStub = sinon.stub(moment.fn, 'format');
});
afterEach(function () {
afterEach(async function () {
sinon.restore();
configUtils.restore();
await configUtils.restore();
});
beforeEach(function () {

View File

@ -15,13 +15,13 @@ describe('storage: index_spec', function () {
}
});
afterEach(function () {
afterEach(async function () {
if (scope.adapter) {
fs.unlinkSync(scope.adapter);
scope.adapter = null;
}
configUtils.restore();
await configUtils.restore();
});
it('default image storage is local file storage', function () {

View File

@ -22,10 +22,10 @@ const storage = require('../../../../../core/server/adapters/storage');
const configUtils = require('../../../../utils/configUtils');
describe('Importer', function () {
afterEach(function () {
afterEach(async function () {
sinon.restore();
ImageHandler = rewire('../../../../../core/server/data/importer/handlers/image');
configUtils.restore();
await configUtils.restore();
});
describe('ImportManager', function () {

View File

@ -9,10 +9,10 @@ const urlUtils = require('../../../../core/shared/url-utils');
const mockUtils = require('../../../utils/mocks');
describe('lib/mobiledoc', function () {
afterEach(function () {
afterEach(async function () {
sinon.restore();
nock.cleanAll();
configUtils.restore();
await configUtils.restore();
// ensure config changes are reset and picked up by next test
mobiledocLib.reload();
mockUtils.modules.unmockNonExistentModule(/sharp/);

View File

@ -15,8 +15,8 @@ describe('External Request', function () {
});
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
sinon.restore();
nock.cleanAll();
});
@ -179,8 +179,8 @@ describe('External Request', function () {
});
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
sinon.restore();
nock.cleanAll();
});

View File

@ -15,8 +15,8 @@ describe('Unit: models/member', function () {
config.set('assetHash', '1');
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
sinon.restore();
});

View File

@ -9,9 +9,9 @@ describe('Unit: models/permission', function () {
models.init();
});
after(function () {
after(async function () {
sinon.restore();
configUtils.restore();
await configUtils.restore();
});
describe('add', function () {

View File

@ -27,9 +27,9 @@ describe('Notify', function () {
eventSpy = sinon.spy(events, 'emit');
});
afterEach(function () {
afterEach(async function () {
process.send = undefined;
configUtils.restore();
await configUtils.restore();
socketStub.restore();
eventSpy.restore();
});

View File

@ -16,9 +16,9 @@ function expectedLabsObject(obj) {
}
describe('Labs Service', function () {
afterEach(function () {
afterEach(async function () {
sinon.restore();
configUtils.restore();
await configUtils.restore();
});
it('can getAll, even if empty with enabled members', function () {

View File

@ -23,8 +23,8 @@ describe('Limit Service Init', function () {
});
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
sinon.restore();
});

View File

@ -39,9 +39,9 @@ const mailDataIncomplete = {
const sandbox = sinon.createSandbox();
describe('Mail: Ghostmailer', function () {
afterEach(function () {
afterEach(async function () {
mailer = null;
configUtils.restore();
await configUtils.restore();
sandbox.restore();
});

View File

@ -59,8 +59,8 @@ describe('Members - config', function () {
});
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
urlUtils.restore();
sinon.restore();
});

View File

@ -40,8 +40,8 @@ describe('Settings Helpers - getActiveStripeKeys', function () {
});
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
});
it('Uses direct keys when stripeDirect is true, regardles of which keys exist', function () {

View File

@ -23,9 +23,9 @@ describe('Slack', function () {
eventStub = sinon.stub(events, 'on');
});
afterEach(function () {
afterEach(async function () {
sinon.restore();
configUtils.restore();
await configUtils.restore();
});
it('listen() should initialise event correctly', function () {

View File

@ -34,8 +34,8 @@ describe('Stripe - config', function () {
});
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
});
it('Returns null if Stripe not connected', function () {

View File

@ -16,9 +16,9 @@ describe('XMLRPC', function () {
configUtils.set('privacy:useRpcPing', true);
});
afterEach(function () {
afterEach(async function () {
sinon.restore();
configUtils.restore();
await configUtils.restore();
nock.cleanAll();
});

View File

@ -9,12 +9,12 @@ describe('Admin App', function () {
const req = {};
let res;
beforeEach(function () {
beforeEach(async function () {
res = {
sendFile: sinon.spy()
};
configUtils.restore();
await configUtils.restore();
configUtils.set('paths:adminAssets', path.resolve('test/utils/fixtures/admin-build'));
});

View File

@ -34,9 +34,9 @@ describe('cors', function () {
next = sinon.spy();
});
afterEach(function () {
afterEach(async function () {
sinon.restore();
configUtils.restore();
await configUtils.restore();
cors = rewire('../../../../../../core/server/web/api/middleware/cors')[1];
});

View File

@ -22,9 +22,9 @@ describe('normalize', function () {
sinon.stub(logging, 'error');
});
afterEach(function () {
afterEach(async function () {
sinon.restore();
configUtils.restore();
await configUtils.restore();
});
it('should do manipulation by default', function (done) {

View File

@ -29,9 +29,9 @@ describe('UNIT: url redirects', function () {
next = sinon.spy();
});
afterEach(function () {
afterEach(async function () {
sinon.restore();
configUtils.restore();
await configUtils.restore();
host = null;
});

View File

@ -8,12 +8,12 @@ const configUtils = require('../../../utils/configUtils');
*/
describe('Adapter Config', function () {
before(function () {
configUtils.restore();
before(async function () {
await configUtils.restore();
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
});
describe('Storage', function () {

View File

@ -6,8 +6,8 @@ describe('vhost utils', function () {
configUtils.set('url', 'http://ghost.blog');
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
});
// url = 'https://ghost.blog'

View File

@ -5,12 +5,12 @@ const _ = require('lodash');
const configUtils = require('../../../utils/configUtils');
describe('Config Loader', function () {
before(function () {
configUtils.restore();
before(async function () {
await configUtils.restore();
});
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
});
describe('hierarchy of config channels', function () {

View File

@ -9,8 +9,8 @@ const fakeDSN = 'https://aaabbbccc000111222333444555667@sentry.io/1234567';
let sentry;
describe('UNIT: sentry', function () {
afterEach(function () {
configUtils.restore();
afterEach(async function () {
await configUtils.restore();
sinon.restore();
});

View File

@ -26,12 +26,16 @@ configUtils.set = function () {
* important: do not delete cloneDeep for value
* nconf keeps this as a reference and then it can happen that the defaultConfig get's overridden by new values
*/
configUtils.restore = function () {
configUtils.restore = async function () {
/**
* we have to reset the whole config object
* config keys, which get set via a test and do not exist in the config files, won't get reseted
*/
config.reset();
await new Promise((resolve) => {
config.reset(() => {
resolve();
});
});
_.each(configUtils.defaultConfig, function (value, key) {
config.set(key, _.cloneDeep(value));

View File

@ -185,7 +185,8 @@ const mockLabsDisabled = (flag, alpha = true) => {
};
const restore = () => {
configUtils.restore();
// eslint-disable-next-line no-console
configUtils.restore().catch(console.error);
sinon.restore();
mocks = {};
fakedLabsFlags = {};

View File

@ -34,6 +34,8 @@ const db = require('./db-utils');
// Services that need resetting
const settingsService = require('../../core/server/services/settings/settings-service');
const supertest = require('supertest');
const {stopGhost} = require('./e2e-utils');
const adapterManager = require('../../core/server/services/adapter-manager');
/**
* @param {Object} [options={}]
@ -53,6 +55,9 @@ const startGhost = async (options = {}) => {
// NOTE: need to pass this config to the server instance
configUtils.set('paths:contentPath', contentFolder);
// Adapter cache has to be cleared to avoid reusing cached adapter instances between restarts
adapterManager.clearCache();
const defaults = {
backend: true,
frontend: false,
@ -335,6 +340,11 @@ const getAgentsWithFrontend = async () => {
server: true
};
try {
// Possible that we still have a running Ghost server from a previous old E2E test
// Those tests never stopped the server in the tests manually
await stopGhost();
// Start a new Ghost server with real HTTP listener
ghostServer = await startGhost(bootOptions);
const app = ghostServer.rootApp;

View File

@ -20,6 +20,7 @@ const routeSettingsService = require('../../core/server/services/route-settings'
const themeService = require('../../core/server/services/themes');
const limits = require('../../core/server/services/limits');
const customRedirectsService = require('../../core/server/services/custom-redirects');
const adapterManager = require('../../core/server/services/adapter-manager');
// Other Test Utilities
const configUtils = require('./configUtils');
@ -112,6 +113,9 @@ const restartModeGhostStart = async ({frontend, copyThemes, copySettings}) => {
debug('init done');
// Adapter cache has to be cleared to avoid reusing cached adapter instances between restarts
adapterManager.clearCache();
// Reset the settings cache
await settingsService.init();
debug('settings done');
@ -160,6 +164,9 @@ const freshModeGhostStart = async (options) => {
// Stop the server (forceStart Mode)
await stopGhost();
// Adapter cache has to be cleared to avoid reusing cached adapter instances between restarts
adapterManager.clearCache();
// Reset the settings cache and disable listeners so they don't get triggered further
settingsService.reset();

View File

@ -53,7 +53,8 @@ const stubUrlUtilsFromConfig = () => {
const restore = () => {
defaultSandbox.restore();
configUtils.restore();
// eslint-disable-next-line no-console
configUtils.restore().catch(console.error);
};
module.exports.stubUrlUtilsFromConfig = stubUrlUtilsFromConfig;