173 lines
4.1 KiB
TypeScript
173 lines
4.1 KiB
TypeScript
import { test as base } from "@playwright/test";
|
|
import { spawn, spawnSync } from "child_process";
|
|
import { v4 as uuid } from "uuid";
|
|
import getPort from "get-port";
|
|
import * as path from "path";
|
|
import * as dgram from "dgram";
|
|
import * as http from "http";
|
|
import * as fs from "fs/promises";
|
|
import { MongoClient } from "mongodb";
|
|
import { MONGO_PORT, MONGO_HOST } from "../src/back/config.js";
|
|
|
|
type TestFixtures = {
|
|
backend: { url: string; env: Record<string, string> };
|
|
setMarkdownValue: (field_name: string, value: string) => Promise<void>;
|
|
};
|
|
|
|
const c8 = "./node_modules/c8/bin/c8.js";
|
|
const app_host = process.env.TESTS_RUN_IN_DOCKER
|
|
? "test" // the docker name
|
|
: "172.17.0.1"; // ip to access localhost from within docker (playwright always runs in docker)
|
|
|
|
export async function waitForHttpPort({
|
|
port,
|
|
host = app_host,
|
|
timeout = 5000 * 20,
|
|
interval = 200,
|
|
}: {
|
|
port: number;
|
|
host?: string;
|
|
timeout?: number;
|
|
interval?: number;
|
|
}): Promise<void> {
|
|
const start = Date.now();
|
|
|
|
return new Promise((resolve, reject) => {
|
|
const check = () => {
|
|
console.log("Making a request to", { host, port });
|
|
const req = http.get({ hostname: host, port, timeout: 1000 }, (res) => {
|
|
res.destroy();
|
|
resolve(); // Port is ready
|
|
});
|
|
|
|
req.on("error", () => {
|
|
if (Date.now() - start > timeout) {
|
|
reject(new Error(`Timeout waiting for HTTP port ${port}`));
|
|
} else {
|
|
setTimeout(check, interval);
|
|
}
|
|
});
|
|
};
|
|
|
|
check();
|
|
});
|
|
}
|
|
|
|
function triggerKillswitch(port: number) {
|
|
const client = dgram.createSocket("udp4");
|
|
|
|
const message = Buffer.from("Hello, UDP!");
|
|
const HOST = "127.0.0.1";
|
|
|
|
client.send(message, port, HOST, () => {
|
|
client.close();
|
|
});
|
|
}
|
|
|
|
async function dropMongoDB(mongo_db_name: string) {
|
|
const client = new MongoClient(`mongodb://${MONGO_HOST}:${MONGO_PORT}`);
|
|
|
|
try {
|
|
await client.connect();
|
|
const db = client.db(mongo_db_name);
|
|
|
|
const result = await db.dropDatabase();
|
|
console.log(`Database "${mongo_db_name}" dropped:`, result);
|
|
} catch (err) {
|
|
console.error("Error dropping database:", err);
|
|
} finally {
|
|
await client.close();
|
|
}
|
|
}
|
|
|
|
export const test = base.extend<TestFixtures>({
|
|
backend: async ({}, use, { file, titlePath }) => {
|
|
const port = await getPort();
|
|
const mongo_db_name = `test-app-${uuid()}`;
|
|
const killswitch_port = await getPort();
|
|
const coverage_temp_dir = path.join(
|
|
"coverage",
|
|
"tmp_split",
|
|
Date.now().toString()
|
|
);
|
|
await fs.mkdir(coverage_temp_dir, {
|
|
recursive: true,
|
|
});
|
|
const env = {
|
|
...process.env,
|
|
SEALIOUS_PORT: `${port}`,
|
|
SEALIOUS_MONGO_DB_NAME: mongo_db_name,
|
|
...(process.env.TESTS_RUN_IN_DOCKER
|
|
? { MEILISEARCH_HOST: `http://meilisearch:7700` }
|
|
: {}),
|
|
SEALIOUS_KILLSWITCH_PORT: `${killswitch_port}`,
|
|
};
|
|
|
|
const backendProcess = spawn(
|
|
c8,
|
|
[
|
|
"--src",
|
|
"src",
|
|
"--reporter",
|
|
"none",
|
|
"--temp-directory",
|
|
coverage_temp_dir,
|
|
"--all",
|
|
"node",
|
|
"dist/back/index.js",
|
|
],
|
|
{
|
|
env,
|
|
stdio: "inherit",
|
|
}
|
|
);
|
|
|
|
const onEndPromise = new Promise<void>((resolve) => {
|
|
backendProcess.on("exit", async () => {
|
|
await dropMongoDB(mongo_db_name);
|
|
spawnSync(
|
|
c8,
|
|
[
|
|
"report",
|
|
"--temp-directory",
|
|
coverage_temp_dir,
|
|
"--reporter",
|
|
"lcovonly",
|
|
"--report-dir",
|
|
path.join("coverage", Date.now().toString()),
|
|
],
|
|
{ stdio: "inherit" }
|
|
);
|
|
resolve();
|
|
});
|
|
});
|
|
|
|
await waitForHttpPort({ port, timeout: 20000 });
|
|
await use({ url: `http://${app_host}:${port}`, env });
|
|
triggerKillswitch(killswitch_port);
|
|
await onEndPromise;
|
|
},
|
|
|
|
setMarkdownValue: ({ page }, use) => {
|
|
use(async (field_name: string, value: string) => {
|
|
for (let i = 1; i <= 5; i++) {
|
|
try {
|
|
await page.getByRole("button", { name: "Preview" }).click();
|
|
await page
|
|
.locator(`textarea[name="${field_name}"] ~ .CodeMirror`)
|
|
.first()
|
|
.click({ timeout: 1000 });
|
|
await page.getByRole("textbox").press("ControlOrMeta+a");
|
|
await page.getByRole("textbox").first().type("Hamster, a dentist");
|
|
break;
|
|
} catch (e) {
|
|
console.error(e);
|
|
continue;
|
|
}
|
|
}
|
|
});
|
|
},
|
|
});
|
|
|
|
export { expect } from "@playwright/test";
|