gristlabs_grist-core/test/server/customUtil.ts

95 lines
2.6 KiB
TypeScript
Raw Permalink Normal View History

import {getAppRoot} from 'app/server/lib/places';
import {fromCallback, listenPromise} from 'app/server/lib/serverUtils';
import express from 'express';
import * as http from 'http';
import {AddressInfo, Socket} from 'net';
import * as path from 'path';
import {fixturesRoot} from 'test/server/testUtils';
export interface Serving {
url: string;
shutdown: () => Promise<void>;
}
// Adds static files from a directory.
// By default exposes /fixture/sites
export function addStatic(app: express.Express, rootDir?: string) {
// mix in a copy of the plugin api
app.use(/^\/(grist-plugin-api.js)$/, (req, res) =>
res.sendFile(req.params[0], {root:
path.resolve(getAppRoot(), "static")}));
app.use(express.static(rootDir || path.resolve(fixturesRoot, "sites"), {
setHeaders: (res: express.Response) => {
res.set("Access-Control-Allow-Origin", "*");
}
}));
}
// Serve from a directory.
export async function serveStatic(rootDir: string): Promise<Serving> {
return serveSomething(app => addStatic(app, rootDir));
}
// Serve a string of html.
export async function serveSinglePage(html: string): Promise<Serving> {
return serveSomething(app => {
app.get('', (req, res) => res.send(html));
});
}
export function serveCustomViews(): Promise<Serving> {
return serveStatic(path.resolve(fixturesRoot, "sites"));
}
export async function serveSomething(setup: (app: express.Express) => void, port= 0): Promise<Serving> {
const app = express();
const server = http.createServer(app);
await listenPromise(server.listen(port));
const connections = new Set<Socket>();
server.on('connection', (conn) => {
connections.add(conn);
conn.on('close', () => connections.delete(conn));
});
async function shutdown() {
for (const conn of connections) { conn.destroy(); }
await fromCallback(cb => server.close(cb));
}
port = (server.address() as AddressInfo).port;
app.set('port', port);
setup(app);
const url = `http://localhost:${port}`;
return {url, shutdown};
}
/**
* Creates a promise like object that can be resolved from outside.
*/
export class Defer {
private _resolve!: () => void;
private _reject!: (err: any) => void;
private _promise: Promise<void>;
constructor() {
this._promise = new Promise<void>((resolve, reject) => {
this._resolve = resolve;
this._reject = reject;
});
}
public get then() {
return this._promise.then.bind(this._promise);
}
public resolve() {
this._resolve();
}
public reject(err: any) {
this._reject(err);
}
}