Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion tests/hash-backend-integration/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"fix:eslint": "eslint --fix .",
"lint:eslint": "eslint --report-unused-disable-directives .",
"lint:tsc": "tsc --noEmit",
"test:integration": "vitest --run"
"test:integration": "vitest --run && vitest --run --config vitest.snapshot.config.ts"
},
"dependencies": {
"@apps/hash-api": "workspace:*",
Expand Down
29 changes: 29 additions & 0 deletions tests/hash-backend-integration/src/tests/admin-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,25 @@ import { StatusCode } from "@local/status";

import type { GraphStatus } from "@rust/hash-graph-type-defs/typescript/status";

/**
* Throw unless running in the snapshot group of the backend integration
* tests.
*
* Destructive graph operations wipe the shared system graph that the seeded
* group (`vitest.config.ts`) seeds once per run via `globalSetup`, so they
* may only run in the snapshot group (`vitest.snapshot.config.ts`), which
* runs as a separate vitest invocation after the seeded group and owns the
* wipe. The snapshot group's config sets the `HASH_TEST_GROUP` marker checked
* here.
*/
const assertRunningInSnapshotGroup = (operation: string) => {
if (process.env.HASH_TEST_GROUP !== "snapshot") {
throw new Error(
`\`${operation}\` wipes the graph and may only run in the snapshot group of the backend integration tests, which runs as a separate vitest invocation after the seeded group so it cannot destroy the system graph seeded by \`globalSetup\`. To make a test file destructive, place it under \`src/tests/subgraph/\` so that \`vitest.snapshot.config.ts\` picks it up.`,
);
}
};

// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
const port = process.env.HASH_GRAPH_ADMIN_PORT || "4001";

Expand Down Expand Up @@ -96,8 +115,13 @@ export const deleteEntities = async () => {

/**
* Restore a snapshot from a file.
*
* May only be called from the snapshot group of the backend integration
* tests (`vitest.snapshot.config.ts`).
*/
export const restoreSnapshot = async (snapshotPath: string) => {
assertRunningInSnapshotGroup("restoreSnapshot");

await fetch(`http://127.0.0.1:${port}/snapshot`, {
method: "POST",
body: createReadStream(snapshotPath),
Expand Down Expand Up @@ -137,8 +161,13 @@ export const deleteUser = async (
* Reset the Graph.
*
* This is a convenience function for deleting all entities, entity types, property types, data types, and accounts.
*
* May only be called from the snapshot group of the backend integration
* tests (`vitest.snapshot.config.ts`).
*/
export const resetGraph = async () => {
assertRunningInSnapshotGroup("resetGraph");

await deleteEntities();
await deleteEntityTypes();
await deletePropertyTypes();
Expand Down
7 changes: 6 additions & 1 deletion tests/hash-backend-integration/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
{
"extends": "@local/tsconfig/legacy-base-tsconfig-to-refactor.json",
"include": ["./src/", "codegen.config.ts", "vitest.config.ts"]
"include": [
"./src/",
"codegen.config.ts",
"vitest.config.ts",
"vitest.snapshot.config.ts"
]
}
90 changes: 41 additions & 49 deletions tests/hash-backend-integration/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -1,65 +1,57 @@
/// <reference types="vitest" />
import { defineConfig } from "vitest/config";
import { BaseSequencer } from "vitest/node";

import type { TestSpecification } from "vitest/node";
import type { TestUserConfig } from "vitest/config";

/**
* The subgraph tests reset the graph and restore standalone snapshots,
* destroying the shared system graph seeded once per run by `globalSetup`.
* Sort them after all other test files so that they cannot break tests which
* rely on the shared seed – the next run's `globalSetup` re-seeds the graph
* from scratch.
* The backend integration tests are split into two groups which run as
* separate, sequential vitest invocations (see the `test:integration` script
* in `package.json`):
*
* - the seeded group (this config, `src/tests/graph/`): runs against the
* shared system graph seeded once per run by `globalSetup` and must never
* wipe it, and
* - the snapshot group (`vitest.snapshot.config.ts`, `src/tests/subgraph/`):
* wipes the graph and restores standalone snapshots, so it runs after the
* seeded group.
*
* These test options are shared between the two configs.
*/
class DestructiveTestsLastSequencer extends BaseSequencer {
override async sort(files: TestSpecification[]) {
const isDestructive = (file: TestSpecification) =>
file.moduleId.includes("/src/tests/subgraph/");

const sorted = await super.sort(files);

return [
...sorted.filter((file) => !isDestructive(file)),
...sorted.filter(isDestructive),
];
}
}
export const sharedTestConfig = {
coverage: {
enabled: process.env.TEST_COVERAGE === "true",
provider: "istanbul",
reporter: ["lcov", "text"],
include: ["**/*.{c,m,}{j,t}s{x,}"],
exclude: ["**/node_modules/**", "**/dist/**"],
},
setupFiles: [
"@local/hash-backend-utils/environment",
"./src/tests/setup-opentelemetry.ts",
],
environment: "node",
testTimeout: 60_000,
hookTimeout: 120_000,
sequence: {
hooks: "list",
},
/**
* These integration tests share a single graph instance, so running files
* in parallel causes graph state races.
*/
fileParallelism: false,
maxWorkers: 1,
maxConcurrency: 1,
} satisfies TestUserConfig;

export default defineConfig({
plugins: [],
build: {
target: "esnext",
},
test: {
coverage: {
enabled: process.env.TEST_COVERAGE === "true",
provider: "istanbul",
reporter: ["lcov", "text"],
include: ["**/*.{c,m,}{j,t}s{x,}"],
exclude: ["**/node_modules/**", "**/dist/**"],
},
...sharedTestConfig,
globalSetup: ["./src/tests/global-setup.ts"],
setupFiles: [
"@local/hash-backend-utils/environment",
"./src/tests/setup-opentelemetry.ts",
],
include: [
"src/tests/graph/**/*.test.ts",
"src/tests/subgraph/**/*.test.ts",
],
environment: "node",
testTimeout: 60_000,
hookTimeout: 120_000,
sequence: {
hooks: "list",
sequencer: DestructiveTestsLastSequencer,
},
/**
* These integration tests share a single graph instance, so running files
* in parallel causes graph state races.
*/
fileParallelism: false,
maxWorkers: 1,
maxConcurrency: 1,
include: ["src/tests/graph/**/*.test.ts"],
},
});
44 changes: 44 additions & 0 deletions tests/hash-backend-integration/vitest.snapshot.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/// <reference types="vitest" />
import { defineConfig } from "vitest/config";

import { sharedTestConfig } from "./vitest.config";

/**
* Config for the snapshot group of the backend integration tests: the test
* files under `src/tests/subgraph/` wipe the graph via `resetGraph` and
* restore standalone snapshots via `restoreSnapshot`, so they cannot share
* the system graph seeded by the seeded group's `globalSetup`.
*
* The `test:integration` script in `package.json` runs this config as a
* separate vitest invocation after the seeded group (`vitest.config.ts`), so
* the seeded group structurally cannot lose its seed to these tests. There is
* deliberately no `globalSetup` here – each test file restores the snapshot
* it needs, and the next seeded run re-seeds the graph from scratch.
*
* To make a test file destructive, place it under `src/tests/subgraph/` so
* this config picks it up. Destructive graph operations refuse to run outside
* this group: `resetGraph`/`restoreSnapshot` in `src/tests/admin-server.ts`
* throw unless the `HASH_TEST_GROUP` marker below is set.
*/
export default defineConfig({
plugins: [],
build: {
target: "esnext",
},
test: {
...sharedTestConfig,
coverage: {
...sharedTestConfig.coverage,
/**
* Written next to the seeded group's `./coverage` – vitest cleans its
* reports directory at the start of a run, so sharing one directory
* would discard the seeded group's report.
*/
reportsDirectory: "./coverage-snapshot",
},
include: ["src/tests/subgraph/**/*.test.ts"],
env: {
HASH_TEST_GROUP: "snapshot",
},
},
});
Loading