Add test infrastructure with coverage and DB test skipping
- Create @reviq/test-helpers package with shared test utilities - Add describeE2E helper that auto-prefixes test names with [e2e] - Support SKIP_DB_TESTS=1 to skip database-dependent tests - Add unix socket support for TEST_DATABASE_URL - Add root commands: test:unit, test:all, test:cov, test:unit:cov - Configure bunfig.toml to exclude dist/ from coverage reports - Clean up tsconfig.json files to remove redundant settings Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,9 +9,7 @@
|
||||
"typecheck": "tsc --noEmit",
|
||||
"lint": "eslint . --cache",
|
||||
"clean": "rm -rf dist .eslintcache",
|
||||
"test:e2e": "bun test src/__tests__/e2e --no-parallel --coverage",
|
||||
"test:unit": "bun test src/__tests__/unit",
|
||||
"test": "bun test --coverage src/utils"
|
||||
"test": "bun test src/ --no-parallel"
|
||||
},
|
||||
"dependencies": {
|
||||
"@formatjs/intl-durationformat": "^0.9.2",
|
||||
@@ -34,12 +32,11 @@
|
||||
"devDependencies": {
|
||||
"@macalinao/eslint-config": "catalog:",
|
||||
"@macalinao/tsconfig": "catalog:",
|
||||
"@reviq/test-helpers": "workspace:*",
|
||||
"@reviq/virtual-authenticator": "workspace:*",
|
||||
"@types/bun": "catalog:",
|
||||
"@types/pg": "^8.16.0",
|
||||
"@types/zxcvbn": "^4.4.5",
|
||||
"eslint": "catalog:",
|
||||
"pg": "^8.16.3",
|
||||
"pino-pretty": "^13.1.3",
|
||||
"typescript": "catalog:"
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,7 @@
|
||||
"typecheck": "tsc --noEmit",
|
||||
"lint": "eslint . --cache",
|
||||
"clean": "rm -rf dist .eslintcache",
|
||||
"test": "bun test"
|
||||
"test": "bun test src/"
|
||||
},
|
||||
"dependencies": {
|
||||
"@noble/hashes": "^2.0.1",
|
||||
|
||||
25
bun.lock
25
bun.lock
@@ -35,12 +35,11 @@
|
||||
"devDependencies": {
|
||||
"@macalinao/eslint-config": "catalog:",
|
||||
"@macalinao/tsconfig": "catalog:",
|
||||
"@reviq/test-helpers": "workspace:*",
|
||||
"@reviq/virtual-authenticator": "workspace:*",
|
||||
"@types/bun": "catalog:",
|
||||
"@types/pg": "^8.16.0",
|
||||
"@types/zxcvbn": "^4.4.5",
|
||||
"eslint": "catalog:",
|
||||
"pg": "^8.16.3",
|
||||
"pino-pretty": "^13.1.3",
|
||||
"typescript": "catalog:",
|
||||
},
|
||||
@@ -180,6 +179,24 @@
|
||||
"typescript": "catalog:",
|
||||
},
|
||||
},
|
||||
"packages/testing/test-helpers": {
|
||||
"name": "@reviq/test-helpers",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"@reviq/db": "workspace:*",
|
||||
"@reviq/db-schema": "workspace:*",
|
||||
"kysely": "^0.28.2",
|
||||
"pg": "^8.16.3",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@macalinao/eslint-config": "catalog:",
|
||||
"@macalinao/tsconfig": "catalog:",
|
||||
"@types/bun": "catalog:",
|
||||
"@types/pg": "^8.16.0",
|
||||
"eslint": "catalog:",
|
||||
"typescript": "catalog:",
|
||||
},
|
||||
},
|
||||
"packages/testing/virtual-authenticator": {
|
||||
"name": "@reviq/virtual-authenticator",
|
||||
"version": "0.0.1",
|
||||
@@ -189,7 +206,7 @@
|
||||
"devDependencies": {
|
||||
"@macalinao/eslint-config": "catalog:",
|
||||
"@macalinao/tsconfig": "catalog:",
|
||||
"@types/bun": "latest",
|
||||
"@types/bun": "catalog:",
|
||||
"@types/node": "^25.0.3",
|
||||
"eslint": "catalog:",
|
||||
"typescript": "catalog:",
|
||||
@@ -425,6 +442,8 @@
|
||||
|
||||
"@reviq/db-schema": ["@reviq/db-schema@workspace:packages/db-schema"],
|
||||
|
||||
"@reviq/test-helpers": ["@reviq/test-helpers@workspace:packages/testing/test-helpers"],
|
||||
|
||||
"@reviq/utils": ["@reviq/utils@workspace:packages/utils"],
|
||||
|
||||
"@reviq/virtual-authenticator": ["@reviq/virtual-authenticator@workspace:packages/testing/virtual-authenticator"],
|
||||
|
||||
5
bunfig.toml
Normal file
5
bunfig.toml
Normal file
@@ -0,0 +1,5 @@
|
||||
[test]
|
||||
coveragePathIgnorePatterns = [
|
||||
"**/dist/**",
|
||||
"**/node_modules/**",
|
||||
]
|
||||
@@ -1,4 +1,4 @@
|
||||
\restrict F9AizESreuRieL4inRcHWWg3hyNET0FgnBDFBBBU3cZGPEpHjb591l8S2iglpap
|
||||
\restrict 7omiXDURqmmr2m2jWDDMoltRzeUAT80fRWiPifpD7IpQGCLgxQNBFsA5uBgakPg
|
||||
|
||||
-- Dumped from database version 17.7
|
||||
-- Dumped by pg_dump version 17.7
|
||||
@@ -1084,7 +1084,7 @@ ALTER TABLE ONLY public.user_devices
|
||||
-- PostgreSQL database dump complete
|
||||
--
|
||||
|
||||
\unrestrict F9AizESreuRieL4inRcHWWg3hyNET0FgnBDFBBBU3cZGPEpHjb591l8S2iglpap
|
||||
\unrestrict 7omiXDURqmmr2m2jWDDMoltRzeUAT80fRWiPifpD7IpQGCLgxQNBFsA5uBgakPg
|
||||
|
||||
|
||||
--
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
"typecheck": "turbo typecheck",
|
||||
"clean": "turbo clean",
|
||||
"test": "turbo test",
|
||||
"test:unit": "SKIP_DB_TESTS=1 turbo test",
|
||||
"test:all": "turbo test",
|
||||
"test:cov": "bun test --coverage",
|
||||
"test:unit:cov": "SKIP_DB_TESTS=1 bun test --coverage",
|
||||
"db:codegen": "bun run --cwd packages/db-schema generate"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "bun test",
|
||||
"test": "bun test src/",
|
||||
"clean": "tsc --build --clean && rm -rf dist/ node_modules/ .eslintcache",
|
||||
"lint": "eslint . --cache"
|
||||
},
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"build": "tsc",
|
||||
"clean": "tsc --build --clean && rm -rf dist/ node_modules/ .eslintcache",
|
||||
"lint": "eslint . --cache",
|
||||
"test": "bun test"
|
||||
"test": "bun test src/"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@macalinao/eslint-config": "catalog:",
|
||||
|
||||
@@ -1,15 +1,7 @@
|
||||
{
|
||||
"extends": "@macalinao/tsconfig/tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"composite": true,
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
{
|
||||
"extends": "@macalinao/tsconfig/tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"types": ["node", "bun"]
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
|
||||
12
packages/testing/test-helpers/eslint.config.js
Normal file
12
packages/testing/test-helpers/eslint.config.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import { configs } from "@macalinao/eslint-config";
|
||||
|
||||
export default [
|
||||
...configs.fast,
|
||||
{
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
33
packages/testing/test-helpers/package.json
Normal file
33
packages/testing/test-helpers/package.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "@reviq/test-helpers",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"clean": "tsc --build --clean && rm -rf dist/ node_modules/ .eslintcache",
|
||||
"lint": "eslint . --cache"
|
||||
},
|
||||
"dependencies": {
|
||||
"@reviq/db": "workspace:*",
|
||||
"@reviq/db-schema": "workspace:*",
|
||||
"kysely": "^0.28.2",
|
||||
"pg": "^8.16.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@macalinao/eslint-config": "catalog:",
|
||||
"@macalinao/tsconfig": "catalog:",
|
||||
"@types/bun": "catalog:",
|
||||
"@types/pg": "^8.16.0",
|
||||
"eslint": "catalog:",
|
||||
"typescript": "catalog:"
|
||||
}
|
||||
}
|
||||
18
packages/testing/test-helpers/src/index.ts
Normal file
18
packages/testing/test-helpers/src/index.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
export { describeE2E, SKIP_DB_TESTS } from "./skip-db-tests.js";
|
||||
export {
|
||||
DEFAULT_TEST_AAGUID,
|
||||
KNOWN_AAGUIDS,
|
||||
TEST_RP,
|
||||
} from "./test-constants.js";
|
||||
export {
|
||||
createTestDb,
|
||||
createTestUser,
|
||||
destroySharedDb,
|
||||
destroyTestDb,
|
||||
getSharedDb,
|
||||
getTestDatabaseUrl,
|
||||
initTestDb,
|
||||
runMigrations,
|
||||
truncateAllTables,
|
||||
} from "./test-db.js";
|
||||
export { withTestTransaction } from "./test-transaction.js";
|
||||
18
packages/testing/test-helpers/src/skip-db-tests.ts
Normal file
18
packages/testing/test-helpers/src/skip-db-tests.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { describe } from "bun:test";
|
||||
|
||||
/**
|
||||
* Skip flag for database-dependent tests.
|
||||
* Set SKIP_DB_TESTS=1 to skip e2e tests that require a database.
|
||||
*/
|
||||
export const SKIP_DB_TESTS: boolean = process.env.SKIP_DB_TESTS === "1";
|
||||
|
||||
const _describeSkipIf = describe.skipIf(SKIP_DB_TESTS);
|
||||
|
||||
/**
|
||||
* Use for describe blocks that require database access.
|
||||
* Automatically prefixes name with [e2e].
|
||||
* Skips tests when SKIP_DB_TESTS=1 is set.
|
||||
*/
|
||||
export function describeE2E(name: string, fn: () => void): void {
|
||||
_describeSkipIf(`[e2e] ${name}`, fn);
|
||||
}
|
||||
@@ -64,20 +64,31 @@ export function getTestDatabaseUrl(): string {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a postgres URL to extract components
|
||||
* Parses a postgres URL to extract components.
|
||||
* Supports both TCP and unix socket connections.
|
||||
*
|
||||
* Unix socket URL format: postgresql:///dbname?host=/var/run/postgresql
|
||||
*/
|
||||
function parsePostgresUrl(url: string): {
|
||||
host: string;
|
||||
port: number;
|
||||
port: number | undefined;
|
||||
user: string;
|
||||
password: string;
|
||||
database: string;
|
||||
} {
|
||||
const parsed = new URL(url);
|
||||
|
||||
// Unix socket: hostname is empty, socket path in `host` query param
|
||||
const isUnixSocket = !parsed.hostname;
|
||||
const socketPath = parsed.searchParams.get("host");
|
||||
|
||||
return {
|
||||
host: parsed.hostname,
|
||||
port: Number.parseInt(parsed.port || "5432", 10),
|
||||
user: parsed.username,
|
||||
host: isUnixSocket
|
||||
? (socketPath ?? "/var/run/postgresql")
|
||||
: parsed.hostname,
|
||||
port: isUnixSocket ? undefined : Number.parseInt(parsed.port || "5432", 10),
|
||||
// eslint-disable-next-line turbo/no-undeclared-env-vars, @typescript-eslint/prefer-nullish-coalescing -- USER is a system env var, and we want empty string to fall back
|
||||
user: parsed.username || process.env.USER || "postgres",
|
||||
password: parsed.password,
|
||||
database: parsed.pathname.slice(1), // Remove leading /
|
||||
};
|
||||
6
packages/testing/test-helpers/tsconfig.json
Normal file
6
packages/testing/test-helpers/tsconfig.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": "@macalinao/tsconfig/tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"types": ["bun"]
|
||||
}
|
||||
}
|
||||
@@ -3,14 +3,19 @@
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
".": "./src/index.ts"
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"clean": "tsc --build --clean && rm -rf dist/ node_modules/ .eslintcache",
|
||||
"lint": "eslint . --cache",
|
||||
"test": "bun test"
|
||||
"test": "bun test src/"
|
||||
},
|
||||
"dependencies": {
|
||||
"@simplewebauthn/types": "^12.0.0"
|
||||
@@ -18,7 +23,7 @@
|
||||
"devDependencies": {
|
||||
"@macalinao/eslint-config": "catalog:",
|
||||
"@macalinao/tsconfig": "catalog:",
|
||||
"@types/bun": "latest",
|
||||
"@types/bun": "catalog:",
|
||||
"@types/node": "^25.0.3",
|
||||
"eslint": "catalog:",
|
||||
"typescript": "catalog:"
|
||||
|
||||
@@ -1,15 +1,7 @@
|
||||
{
|
||||
"extends": "@macalinao/tsconfig/tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"composite": true,
|
||||
"types": ["node", "bun"]
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"build": "tsc",
|
||||
"clean": "tsc --build --clean && rm -rf dist/ node_modules/ .eslintcache",
|
||||
"lint": "eslint . --cache",
|
||||
"test": "bun test"
|
||||
"test": "bun test src/"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cloudflare/workers-types": "^4.20250529.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://turbo.build/schema.json",
|
||||
"globalEnv": ["DATABASE_URL", "PORT"],
|
||||
"globalEnv": ["DATABASE_URL", "PORT", "TEST_DATABASE_URL"],
|
||||
"tasks": {
|
||||
"build": {
|
||||
"dependsOn": ["^build"],
|
||||
@@ -33,6 +33,7 @@
|
||||
"test": {
|
||||
"dependsOn": ["^build"],
|
||||
"inputs": ["src/**/*.ts", "src/**/*.test.ts"],
|
||||
"env": ["SKIP_DB_TESTS", "TEST_DATABASE_URL"],
|
||||
"cache": false
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user