UNPKG

@clickup/ent-framework

Version:

A PostgreSQL graph-database-alike library with microsharding and row-level security

112 lines (103 loc) 3.15 kB
import { inspect } from "util"; import type { InsertInput, Row, Table, UpdateInput } from "../../types"; import { EntValidationError } from "../errors/EntValidationError"; import type { Validation } from "../Validation"; import { VC } from "../VC"; import { VCWithQueryCache } from "../VCFlavor"; const vcTestGuest = VC.createGuestPleaseDoNotUseCreationPointsMustBeLimited().withTransitiveMasterFreshness(); /** * Creates a test VC. */ export function createVC(): VC { const vc = vcTestGuest .withFlavor(new VCWithQueryCache({ maxQueries: 1000 })) .withDefaultFreshness(); return vc; } /** * Normalizes the text before matching the snapshot. */ export function expectToMatchSnapshot( str: string, snapshotName?: string, ): void { const exp = expect( str.replace(/\b(vc:\w+)\(\d+\)/g, "$1").replace(/\d{10,}/g, "<id>"), ); snapshotName ? exp.toMatchSnapshot(snapshotName) : exp.toMatchSnapshot(); } /** * A helper class to log some predicate response (plus the row argument) and * return it, see how it's used in the code. * * - Q: "If we have a class which validates a validation, who'd be validating * the function which validates the validation?" * - A: "TS & Jest" */ export class ValidationTester { private log: string[] = []; respond<TRes>( predName: string, response: TRes, row?: unknown, ): TRes extends Error ? boolean : TRes { predName += row ? " " + inspect(row) : ""; if (response instanceof Error) { this.log.push(`[${predName} threw] ${response}`); throw response; } else { this.log.push( `[${predName} returned] ` + (typeof response === "object" ? inspect( response instanceof Promise ? response.constructor.name // hide e.g. Datadog guts : { ...response }, { compact: true, depth: 10, breakLength: 10000 }, ) : response), ); return response as TRes extends Error ? boolean : TRes; } } async matchSnapshot<TTable extends Table>({ validation, row, method, updateInput, vc = vcTestGuest, }: { validation: Validation<TTable>; row: Row<TTable>; vc?: VC; } & ( | { method: "validateLoad" | "validateInsert" | "validateDelete"; updateInput?: never; } | { method: "validateUpdate"; updateInput: UpdateInput<TTable>; } )): Promise<boolean> { let res = ""; let allow = false; try { if (method === "validateUpdate") { await validation.validateUpdate(vc, row, updateInput); } else { await validation[method](vc, row as InsertInput<TTable> & Row<TTable>); } res = "OK"; allow = true; } catch (e: unknown) { const severity = e instanceof EntValidationError ? "Failure" : "Error Thrown Through"; res = `${severity}\n--- (error returned to client) ---\n${e}`; } res += "\n--- (what actually happened) ---\n" + this.log.join("\n"); expect(res.replace(/\b(vc:\w+)\(\d+\)/g, "$1")).toMatchSnapshot(); return allow; } }