2021-02-04 19:15:23 +01:00
|
|
|
const { promises: fs } = require('fs');
|
|
|
|
const path = require('path');
|
|
|
|
const Koa = require('koa');
|
2019-12-11 18:26:20 +01:00
|
|
|
|
2021-02-04 19:15:23 +01:00
|
|
|
const CURRENT_STATE_KEY = '__CURRENT__';
|
|
|
|
const DEFAULT_STATE_KEY = '__DEFAULT__';
|
2019-12-11 18:26:20 +01:00
|
|
|
|
2021-02-04 19:15:23 +01:00
|
|
|
const FIXTURE_SERVER_HOST = 'localhost';
|
|
|
|
const FIXTURE_SERVER_PORT = 12345;
|
2019-12-11 18:26:20 +01:00
|
|
|
|
|
|
|
class FixtureServer {
|
2020-11-03 00:41:28 +01:00
|
|
|
constructor() {
|
2021-02-04 19:15:23 +01:00
|
|
|
this._app = new Koa();
|
|
|
|
this._stateMap = new Map([[DEFAULT_STATE_KEY, Object.create(null)]]);
|
|
|
|
this._initialStateCache = new Map();
|
2019-12-11 18:26:20 +01:00
|
|
|
|
|
|
|
this._app.use(async (ctx) => {
|
|
|
|
// Firefox is _super_ strict about needing CORS headers
|
2021-02-04 19:15:23 +01:00
|
|
|
ctx.set('Access-Control-Allow-Origin', '*');
|
2019-12-11 18:26:20 +01:00
|
|
|
if (this._isStateRequest(ctx)) {
|
2021-02-04 19:15:23 +01:00
|
|
|
ctx.body = this._stateMap.get(CURRENT_STATE_KEY);
|
2019-12-11 18:26:20 +01:00
|
|
|
}
|
2021-02-04 19:15:23 +01:00
|
|
|
});
|
2019-12-11 18:26:20 +01:00
|
|
|
}
|
|
|
|
|
2020-11-03 00:41:28 +01:00
|
|
|
async start() {
|
2019-12-11 18:26:20 +01:00
|
|
|
const options = {
|
|
|
|
host: FIXTURE_SERVER_HOST,
|
|
|
|
port: FIXTURE_SERVER_PORT,
|
|
|
|
exclusive: true,
|
2021-02-04 19:15:23 +01:00
|
|
|
};
|
2019-12-11 18:26:20 +01:00
|
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
2021-02-04 19:15:23 +01:00
|
|
|
this._server = this._app.listen(options);
|
|
|
|
this._server.once('error', reject);
|
|
|
|
this._server.once('listening', resolve);
|
|
|
|
});
|
2019-12-11 18:26:20 +01:00
|
|
|
}
|
|
|
|
|
2020-11-03 00:41:28 +01:00
|
|
|
async stop() {
|
2019-12-11 18:26:20 +01:00
|
|
|
if (!this._server) {
|
2021-02-04 19:15:23 +01:00
|
|
|
return;
|
2019-12-11 18:26:20 +01:00
|
|
|
}
|
|
|
|
|
2020-08-12 21:06:57 +02:00
|
|
|
await new Promise((resolve, reject) => {
|
2021-02-04 19:15:23 +01:00
|
|
|
this._server.close();
|
|
|
|
this._server.once('error', reject);
|
|
|
|
this._server.once('close', resolve);
|
|
|
|
});
|
2019-12-11 18:26:20 +01:00
|
|
|
}
|
|
|
|
|
2020-11-03 00:41:28 +01:00
|
|
|
async loadState(directory) {
|
2021-02-04 19:15:23 +01:00
|
|
|
const statePath = path.resolve(__dirname, directory, 'state.json');
|
2019-12-11 18:26:20 +01:00
|
|
|
|
2021-02-04 19:15:23 +01:00
|
|
|
let state;
|
2019-12-11 18:26:20 +01:00
|
|
|
if (this._initialStateCache.has(statePath)) {
|
2021-02-04 19:15:23 +01:00
|
|
|
state = this._initialStateCache.get(statePath);
|
2019-12-11 18:26:20 +01:00
|
|
|
} else {
|
2021-02-04 19:15:23 +01:00
|
|
|
const data = await fs.readFile(statePath);
|
|
|
|
state = JSON.parse(data.toString('utf-8'));
|
|
|
|
this._initialStateCache.set(statePath, state);
|
2019-12-11 18:26:20 +01:00
|
|
|
}
|
|
|
|
|
2021-02-04 19:15:23 +01:00
|
|
|
this._stateMap.set(CURRENT_STATE_KEY, state);
|
2019-12-11 18:26:20 +01:00
|
|
|
}
|
|
|
|
|
2020-11-03 00:41:28 +01:00
|
|
|
_isStateRequest(ctx) {
|
2021-02-04 19:15:23 +01:00
|
|
|
return ctx.method === 'GET' && ctx.path === '/state.json';
|
2019-12-11 18:26:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-04 19:15:23 +01:00
|
|
|
module.exports = FixtureServer;
|