95 lines
4.4 KiB
TypeScript
95 lines
4.4 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
import { fileURLToPath } from "node:url";
|
|
import { serializeOnboardingState } from "../src/services/onboarding-serialization.js";
|
|
|
|
type StoredFixture = { onboarding: Record<string, unknown> };
|
|
const fixturePath = fileURLToPath(new URL("./fixtures/onboarding-rev10.json", import.meta.url));
|
|
const fixture = JSON.parse(readFileSync(fixturePath, "utf8")) as StoredFixture;
|
|
const response = serializeOnboardingState("user_3EX1LG3gBk3KY6kfD9PiTkWubs4", fixture.onboarding);
|
|
|
|
assert.equal(response.id, "user_3EX1LG3gBk3KY6kfD9PiTkWubs4");
|
|
assert.equal(response.revision, 10);
|
|
assert.equal(response.data.revision, 10);
|
|
assert.equal(response.data.status, "completed");
|
|
assert.equal(response.data.profile.icp, "experienced");
|
|
assert.equal(response.data.access_choice, "trial");
|
|
assert.equal(response.data.completed_at, "2026-07-12T21:31:42.957Z");
|
|
assert.equal(response.updatedAt, "2026-07-12T21:33:01.914Z");
|
|
assert.deepEqual(response.payload, {
|
|
schema_version: 1,
|
|
source_revision: 10,
|
|
primary_intent: "grow",
|
|
mode: "individual",
|
|
question_branch: "professional",
|
|
onboarding_icp: "experienced",
|
|
curator_registry_icp: null,
|
|
target_role: "Senior Software Engineer",
|
|
target_field: "technical",
|
|
experience_context: "5+ · clients",
|
|
goals: ["role"],
|
|
barriers: ["offers"],
|
|
priority: "role",
|
|
weekly_time_commitment: "steady",
|
|
});
|
|
|
|
const serialized = JSON.parse(JSON.stringify(response));
|
|
assert.deepEqual(serialized, response, "GET response must be JSON serializable without losing rev10 state");
|
|
|
|
const compose = readFileSync(fileURLToPath(new URL("../docker-compose.override.yml", import.meta.url)), "utf8");
|
|
assert.match(
|
|
compose,
|
|
/user-service-staging:\s+external:\s+true\s+name:\s+user-service-staging_default/s,
|
|
"backend must join the canonical user-service staging network",
|
|
);
|
|
assert.doesNotMatch(compose, /name:\s+growqr-app_growqr-net/, "obsolete substitute user network must not be configured");
|
|
assert.match(compose, /RESUME_SERVICE_URL:\s+http:\/\/growqr_resume_api:8000/, "backend must route Resume through canonical Docker DNS");
|
|
for (const modelKey of ["LLM_MODEL", "GROW_AGENT_MODEL", "CONVERSATION_ACTOR_MODEL"]) {
|
|
assert.match(compose, new RegExp(`${modelKey}:\\s+kimi-k2\\.6`), `${modelKey} must stay on the verified staging model`);
|
|
}
|
|
assert.doesNotMatch(compose, /minimax-m3/, "staging compose must not restore the broken MiniMax model pin");
|
|
|
|
const canonicalServiceNetworks = [
|
|
["interview-service", "interview-service_default"],
|
|
["roleplay-service", "roleplay-service_default"],
|
|
["resume-builder-staging", "resume-builder-staging_default"],
|
|
["course-service", "course-service_default"],
|
|
["qscore-service-staging", "qscore-service-staging_default"],
|
|
["matchmaking-v2-staging", "matchmaking-v2_default"],
|
|
["user-service-staging", "user-service-staging_default"],
|
|
] as const;
|
|
|
|
for (const [key, name] of canonicalServiceNetworks) {
|
|
assert.match(
|
|
compose,
|
|
new RegExp(`${key}:\\s+external:\\s+true\\s+name:\\s+${name.replace(/[.*+?^${}()|[\\]\\]/g, "\\$&")}`, "s"),
|
|
`backend must join canonical network ${name}`,
|
|
);
|
|
}
|
|
|
|
for (const obsoleteName of [
|
|
"resume-builder_default",
|
|
"courses_service_default",
|
|
"qscore-service_default",
|
|
"matchmaking-service_default",
|
|
"growqr-app_growqr-net",
|
|
]) {
|
|
assert.doesNotMatch(compose, new RegExp(`name:\\s+${obsoleteName}`), `obsolete substitute network ${obsoleteName} must not be configured`);
|
|
}
|
|
|
|
|
|
const stagingCompose = readFileSync(fileURLToPath(new URL("./staging-compose.sh", import.meta.url)), "utf8");
|
|
assert.match(stagingCompose, /PROJECT=growqr-backend-staging/, "staging wrapper must pin the compose project name");
|
|
for (const [, name] of canonicalServiceNetworks) {
|
|
assert.match(stagingCompose, new RegExp(name.replace(/[.*+?^${}()|[\\]\\]/g, "\\$&")), `staging wrapper must verify ${name}`);
|
|
}
|
|
|
|
const packageJson = JSON.parse(readFileSync(fileURLToPath(new URL("../package.json", import.meta.url)), "utf8")) as {
|
|
scripts?: Record<string, string>;
|
|
};
|
|
assert.equal(packageJson.scripts?.["compose:up"], "scripts/staging-compose.sh up");
|
|
assert.equal(packageJson.scripts?.["compose:down"], "scripts/staging-compose.sh down");
|
|
assert.equal(packageJson.scripts?.["staging:preflight"], "scripts/staging-compose.sh preflight");
|
|
assert.equal(packageJson.scripts?.["staging:verify"], "scripts/staging-compose.sh verify");
|
|
console.log("onboarding-rev10-read: fixture serialization and staging network assertions passed");
|