mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 15:18:11 +00:00
60 lines
2.2 KiB
TypeScript
60 lines
2.2 KiB
TypeScript
import { createRequire } from "node:module";
|
|
import * as path from "node:path";
|
|
|
|
/**
|
|
* `pg` is not a dependency of this directory and pnpm's strict layout means a
|
|
* bare `import "pg"` does not resolve here. Borrow it from the app that already
|
|
* owns a Postgres client rather than adding a duplicate declaration of the same
|
|
* driver to the workspace root.
|
|
*/
|
|
const requireFrom = createRequire(
|
|
path.join(__dirname, "..", "..", "apps", "edr-hr-api", "package.json"),
|
|
);
|
|
const { Client } = requireFrom("pg") as typeof import("pg");
|
|
|
|
/**
|
|
* Direct database reads for assertions.
|
|
*
|
|
* The suite's doctrine (docs/hr-finance-ui-e2e-matrix.md) is that every scenario
|
|
* checks the DOM, the network response AND the database row, and fails if the
|
|
* three disagree. A UI that renders the right number from a stale cache, or an
|
|
* API that answers 200 without writing, both pass a DOM-only test.
|
|
*
|
|
* READ-ONLY by intent. Fixtures are created through the product's own endpoints
|
|
* or the seed scripts, never here — a test that sets up state with raw SQL stops
|
|
* proving the code path that normally creates it.
|
|
*/
|
|
const config = {
|
|
host: process.env.DB_HOST ?? "localhost",
|
|
port: Number(process.env.DB_PORT ?? 5432),
|
|
user: process.env.DB_USER ?? "postgres",
|
|
password: process.env.DB_PASSWORD,
|
|
database: process.env.DB_NAME ?? "smart_office_e2e",
|
|
};
|
|
|
|
export async function query<T = Record<string, unknown>>(
|
|
sql: string,
|
|
params: unknown[] = [],
|
|
): Promise<T[]> {
|
|
if (config.database === "smart_office_prod") {
|
|
// The suite must never read prod as if it were the fixture database: an
|
|
// assertion that passes there is meaningless and the mistake is silent.
|
|
throw new Error("Refusing to run e2e assertions against smart_office_prod");
|
|
}
|
|
const client = new Client(config);
|
|
await client.connect();
|
|
try {
|
|
const { rows } = await client.query(sql, params);
|
|
return rows as T[];
|
|
} finally {
|
|
await client.end();
|
|
}
|
|
}
|
|
|
|
/** Convenience for the common "one row, one column" assertion. */
|
|
export async function scalar<T = string>(sql: string, params: unknown[] = []): Promise<T | null> {
|
|
const rows = await query<Record<string, T>>(sql, params);
|
|
if (!rows.length) return null;
|
|
return Object.values(rows[0])[0] ?? null;
|
|
}
|