fix(tests): use global hookTimeout for integration test beforeAll hooks (#125)
* fix(tests): remove explicit beforeAll timeouts that override global hookTimeout Integration tests passed 60s timeouts to beforeAll, overriding the 120s hookTimeout in vitest.smoke.config.ts. On CI the dev server startup can consume the full 60s, leaving no time for setup + seeding. Also bumps createTestServer's default waitForServer timeout from 60s to 90s, leaving 30s margin within the 120s hook budget. * fix(tests): don't remove shared node_modules symlink during cleanup Multiple integration test suites run concurrently and share the fixture/node_modules symlink. When the suite that created it finishes first, its cleanup deletes the symlink, causing other suites to fail with MODULE_NOT_FOUND when their server process tries to resolve astro. The symlink is gitignored so it's safe to leave in place.
This commit is contained in:
@@ -19,7 +19,6 @@ import { assertNodeVersion, createTestServer } from "../server.js";
|
|||||||
const exec = promisify(execFile);
|
const exec = promisify(execFile);
|
||||||
|
|
||||||
const PORT = 4398; // Different port from client integration tests
|
const PORT = 4398; // Different port from client integration tests
|
||||||
const TIMEOUT = 60_000;
|
|
||||||
|
|
||||||
// Path to the built CLI binary
|
// Path to the built CLI binary
|
||||||
const CLI_BIN = resolve(import.meta.dirname, "../../../dist/cli/index.mjs");
|
const CLI_BIN = resolve(import.meta.dirname, "../../../dist/cli/index.mjs");
|
||||||
@@ -30,7 +29,7 @@ describe("CLI Integration", () => {
|
|||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
assertNodeVersion();
|
assertNodeVersion();
|
||||||
ctx = await createTestServer({ port: PORT });
|
ctx = await createTestServer({ port: PORT });
|
||||||
}, TIMEOUT);
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await ctx?.cleanup();
|
await ctx?.cleanup();
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import type { TestServerContext } from "../server.js";
|
|||||||
import { assertNodeVersion, createTestServer } from "../server.js";
|
import { assertNodeVersion, createTestServer } from "../server.js";
|
||||||
|
|
||||||
const PORT = 4399;
|
const PORT = 4399;
|
||||||
const TIMEOUT = 60_000;
|
|
||||||
|
|
||||||
describe("EmDashClient Integration", () => {
|
describe("EmDashClient Integration", () => {
|
||||||
let ctx: TestServerContext;
|
let ctx: TestServerContext;
|
||||||
@@ -23,7 +22,7 @@ describe("EmDashClient Integration", () => {
|
|||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
assertNodeVersion();
|
assertNodeVersion();
|
||||||
ctx = await createTestServer({ port: PORT });
|
ctx = await createTestServer({ port: PORT });
|
||||||
}, TIMEOUT);
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await ctx?.cleanup();
|
await ctx?.cleanup();
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import type { TestServerContext } from "../server.js";
|
|||||||
import { assertNodeVersion, createTestServer } from "../server.js";
|
import { assertNodeVersion, createTestServer } from "../server.js";
|
||||||
|
|
||||||
const PORT = 4396;
|
const PORT = 4396;
|
||||||
const TIMEOUT = 60_000;
|
|
||||||
|
|
||||||
/** Helper: raw fetch with auth headers */
|
/** Helper: raw fetch with auth headers */
|
||||||
async function adminFetch(
|
async function adminFetch(
|
||||||
@@ -88,7 +87,7 @@ describe("Comments Integration", () => {
|
|||||||
const body = await res.text().catch(() => "");
|
const body = await res.text().catch(() => "");
|
||||||
throw new Error(`Failed to enable comments on posts (${res.status}): ${body}`);
|
throw new Error(`Failed to enable comments on posts (${res.status}): ${body}`);
|
||||||
}
|
}
|
||||||
}, TIMEOUT);
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await ctx?.cleanup();
|
await ctx?.cleanup();
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import type { TestServerContext } from "../server.js";
|
|||||||
import { assertNodeVersion, createTestServer } from "../server.js";
|
import { assertNodeVersion, createTestServer } from "../server.js";
|
||||||
|
|
||||||
const PORT = 4397;
|
const PORT = 4397;
|
||||||
const TIMEOUT = 90_000;
|
|
||||||
|
|
||||||
describe("Field Widgets Integration", () => {
|
describe("Field Widgets Integration", () => {
|
||||||
let ctx: TestServerContext;
|
let ctx: TestServerContext;
|
||||||
@@ -25,7 +24,7 @@ describe("Field Widgets Integration", () => {
|
|||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
assertNodeVersion();
|
assertNodeVersion();
|
||||||
ctx = await createTestServer({ port: PORT });
|
ctx = await createTestServer({ port: PORT });
|
||||||
}, TIMEOUT);
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await ctx?.cleanup();
|
await ctx?.cleanup();
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { execFile, spawn } from "node:child_process";
|
import { execFile, spawn } from "node:child_process";
|
||||||
import { existsSync, mkdtempSync, rmSync, symlinkSync, unlinkSync } from "node:fs";
|
import { existsSync, mkdtempSync, rmSync, symlinkSync } from "node:fs";
|
||||||
import { tmpdir } from "node:os";
|
import { tmpdir } from "node:os";
|
||||||
import { join, resolve } from "node:path";
|
import { join, resolve } from "node:path";
|
||||||
import { promisify } from "node:util";
|
import { promisify } from "node:util";
|
||||||
@@ -43,7 +43,7 @@ const DONOR_NODE_MODULES = resolve(import.meta.dirname, "../../../../demos/simpl
|
|||||||
|
|
||||||
export interface TestServerOptions {
|
export interface TestServerOptions {
|
||||||
port: number;
|
port: number;
|
||||||
/** Server startup timeout in ms (default: 30_000) */
|
/** Server startup timeout in ms (default: 90_000) */
|
||||||
timeout?: number;
|
timeout?: number;
|
||||||
/** Seed test data after setup (default: true) */
|
/** Seed test data after setup (default: true) */
|
||||||
seed?: boolean;
|
seed?: boolean;
|
||||||
@@ -148,7 +148,7 @@ async function waitForServer(url: string, timeoutMs: number): Promise<void> {
|
|||||||
* database file — source files stay at their real paths.
|
* database file — source files stay at their real paths.
|
||||||
*/
|
*/
|
||||||
export async function createTestServer(options: TestServerOptions): Promise<TestServerContext> {
|
export async function createTestServer(options: TestServerOptions): Promise<TestServerContext> {
|
||||||
const { port, timeout = 60_000, seed = true } = options;
|
const { port, timeout = 90_000, seed = true } = options;
|
||||||
const baseUrl = `http://localhost:${port}`;
|
const baseUrl = `http://localhost:${port}`;
|
||||||
|
|
||||||
// --- 0. Ensure workspace is built ---
|
// --- 0. Ensure workspace is built ---
|
||||||
@@ -161,12 +161,12 @@ export async function createTestServer(options: TestServerOptions): Promise<Test
|
|||||||
|
|
||||||
// Ensure node_modules symlink exists in the fixture dir.
|
// Ensure node_modules symlink exists in the fixture dir.
|
||||||
// Multiple test suites may race to create this — handle EEXIST gracefully.
|
// Multiple test suites may race to create this — handle EEXIST gracefully.
|
||||||
|
// The symlink is intentionally never removed: it's shared across concurrent
|
||||||
|
// test suites and gitignored, so cleanup of one suite must not break others.
|
||||||
const fixtureNodeModules = join(FIXTURE_DIR, "node_modules");
|
const fixtureNodeModules = join(FIXTURE_DIR, "node_modules");
|
||||||
let createdSymlink = false;
|
|
||||||
if (!existsSync(fixtureNodeModules)) {
|
if (!existsSync(fixtureNodeModules)) {
|
||||||
try {
|
try {
|
||||||
symlinkSync(DONOR_NODE_MODULES, fixtureNodeModules);
|
symlinkSync(DONOR_NODE_MODULES, fixtureNodeModules);
|
||||||
createdSymlink = true;
|
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
if ((err as NodeJS.ErrnoException).code !== "EEXIST") throw err;
|
if ((err as NodeJS.ErrnoException).code !== "EEXIST") throw err;
|
||||||
}
|
}
|
||||||
@@ -215,13 +215,6 @@ export async function createTestServer(options: TestServerOptions): Promise<Test
|
|||||||
|
|
||||||
// Remove temp data directory
|
// Remove temp data directory
|
||||||
rmSync(tempDataDir, { recursive: true, force: true });
|
rmSync(tempDataDir, { recursive: true, force: true });
|
||||||
|
|
||||||
// Remove symlink if we created it
|
|
||||||
if (createdSymlink && existsSync(fixtureNodeModules)) {
|
|
||||||
try {
|
|
||||||
unlinkSync(fixtureNodeModules);
|
|
||||||
} catch {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user