Skip to content
Merged
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
43 changes: 31 additions & 12 deletions apps/cli/src/legacy/commands/config/diff/diff.live.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { type ConfigChangeClass, projectConfigMappingRows } from "@supabase/config/internal";
import { expect } from "vitest";

import { requireLiveSuccess, test } from "../../../../../tests/helpers/live.ts";
Expand All @@ -8,18 +9,36 @@ import { requireLiveSuccess, test } from "../../../../../tests/helpers/live.ts";
// in diff.integration.test.ts. The `workspace` fixture behind `cli` is a
// fresh `supabase init` project directory.
test("diffs a freshly-initialized config against the project", async ({ cli, project }) => {
const result = await cli(["config", "diff", "--project-ref", project.ref]);
expect(`${result.stdout}${result.stderr}`).not.toContain("Unauthorized");
expect(result.stderr).toContain(`Comparing against project ${project.ref} using base config`);
expect(result.stderr).toContain("Comparison scope:");
// The GoTrue-keyed auth record — the one surface mocks cannot prove — must
// classify CLEANLY against a fresh config: the platform's reports of
// unconfigured state (session zeros canonicalized to "0s" via
// unconfiguredValue, platform-rendered mailer subjects via platformRendered,
// disabled notification toggles) are suppressed by the registry's declared
// baselines, not flagged as drift. Asserting only exit 0 here would let that noise through silently.
const authChangeLines = result.stdout.split("\n").filter((line) => line.startsWith("auth."));
expect(authChangeLines, result.stdout).toEqual([]);
const result = await cli([
"config",
"diff",
"--project-ref",
project.ref,
"--output-format",
"json",
]);
// Read-only success regardless of drift (no --exit-code passed).
requireLiveSuccess(result, "config diff");
expect(result.stderr).toContain(`Comparing against project ${project.ref} using base config`);
const payload = JSON.parse(result.stdout) as {
scope: { present: string[] };
changes: Array<{ path: string[]; class: ConfigChangeClass }>;
};
expect(payload.scope.present).toContain("auth");
const changes = payload.changes.map(({ path, class: kind }) => ({ path: path.join("."), kind }));
const classified = changes.map((change) => `${change.path} [${change.kind}]`).join("\n");
// A fresh project legitimately drifts from the init template (confirmations,
// TOTP, site URL), so remote auth values must reach classification, while
// the registry's declared baselines suppress the platform's own defaults.
expect(
changes.some((change) => change.path.startsWith("auth.") && change.kind !== "local_only"),
classified,
).toBe(true);
const baselines = projectConfigMappingRows
.filter((row) => row.unconfiguredValue !== undefined || row.platformRendered === true)
.map((row) => row.configPath.join("."));
expect(
changes.filter((change) => baselines.includes(change.path)),
classified,
).toEqual([]);
});
Loading