55144d0e4a
Adds Store.listMeta() and Store.listSchemas() to expose meta-schema discovery, backed by an in-memory metaSet (memory store) and a persistent _index/_meta file (FS store). Surfaces both via new json-cas list-meta and list-schema CLI commands wrapped in @output/list-meta and @output/list-schema envelope schemas. The FS store migrates from existing nodes when _meta is absent (scanning self-referencing nodes) and preserves _meta on subsequent opens. delete() removes affected hashes from the meta index and persists the change. Closes #90 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
660 lines
20 KiB
TypeScript
660 lines
20 KiB
TypeScript
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join, resolve } from "node:path";
|
|
import { envValue, putSchemaFile, runCli } from "./helpers";
|
|
|
|
// ---- Issue #50: Schema Validation in put Command ----
|
|
|
|
describe("Issue #50: Schema Validation in put", () => {
|
|
describe("Test Group 1: Valid Data (Regression Tests)", () => {
|
|
test("T1.1: Valid data matching schema should be accepted", async () => {
|
|
const tmpStore = mkdtempSync(join(tmpdir(), "json-cas-test-"));
|
|
try {
|
|
await runCli(["init"], tmpStore);
|
|
|
|
// Create schema with required name property
|
|
const schemaFile = join(tmpStore, "schema.json");
|
|
writeFileSync(
|
|
schemaFile,
|
|
JSON.stringify({
|
|
type: "object",
|
|
properties: { name: { type: "string" } },
|
|
required: ["name"],
|
|
additionalProperties: false,
|
|
}),
|
|
);
|
|
const schemaHash = await putSchemaFile(tmpStore, schemaFile);
|
|
|
|
// Create valid payload
|
|
const payloadFile = join(tmpStore, "payload.json");
|
|
writeFileSync(payloadFile, JSON.stringify({ name: "test" }));
|
|
|
|
const { stdout, stderr, exitCode } = await runCli(
|
|
["put", schemaHash.trim(), payloadFile],
|
|
tmpStore,
|
|
);
|
|
|
|
expect(exitCode).toBe(0);
|
|
expect(stderr).toBe("");
|
|
expect(envValue(stdout)).toMatch(/^[0-9A-HJKMNP-TV-Z]{13}$/);
|
|
|
|
// Verify node was stored
|
|
const hash = envValue(stdout) as string;
|
|
const { exitCode: hasExitCode } = await runCli(["has", hash], tmpStore);
|
|
expect(hasExitCode).toBe(0);
|
|
} finally {
|
|
rmSync(tmpStore, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("T1.2: Valid data with optional properties should be accepted", async () => {
|
|
const tmpStore = mkdtempSync(join(tmpdir(), "json-cas-test-"));
|
|
try {
|
|
await runCli(["init"], tmpStore);
|
|
|
|
// Schema with optional property
|
|
const schemaFile = join(tmpStore, "schema.json");
|
|
writeFileSync(
|
|
schemaFile,
|
|
JSON.stringify({
|
|
type: "object",
|
|
properties: {
|
|
name: { type: "string" },
|
|
age: { type: "number" },
|
|
},
|
|
required: ["name"],
|
|
additionalProperties: false,
|
|
}),
|
|
);
|
|
const schemaHash = await putSchemaFile(tmpStore, schemaFile);
|
|
|
|
// Payload with only required properties
|
|
const payloadFile = join(tmpStore, "payload.json");
|
|
writeFileSync(payloadFile, JSON.stringify({ name: "test" }));
|
|
|
|
const { exitCode, stdout } = await runCli(
|
|
["put", schemaHash.trim(), payloadFile],
|
|
tmpStore,
|
|
);
|
|
|
|
expect(exitCode).toBe(0);
|
|
expect(envValue(stdout)).toMatch(/^[0-9A-HJKMNP-TV-Z]{13}$/);
|
|
} finally {
|
|
rmSync(tmpStore, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("T1.3: Valid data with nested objects should be accepted", async () => {
|
|
const tmpStore = mkdtempSync(join(tmpdir(), "json-cas-test-"));
|
|
try {
|
|
await runCli(["init"], tmpStore);
|
|
|
|
// Schema with nested structure
|
|
const schemaFile = join(tmpStore, "schema.json");
|
|
writeFileSync(
|
|
schemaFile,
|
|
JSON.stringify({
|
|
type: "object",
|
|
properties: {
|
|
name: { type: "string" },
|
|
address: {
|
|
type: "object",
|
|
properties: {
|
|
street: { type: "string" },
|
|
city: { type: "string" },
|
|
},
|
|
},
|
|
},
|
|
additionalProperties: false,
|
|
}),
|
|
);
|
|
const schemaHash = await putSchemaFile(tmpStore, schemaFile);
|
|
|
|
// Payload with nested structure
|
|
const payloadFile = join(tmpStore, "payload.json");
|
|
writeFileSync(
|
|
payloadFile,
|
|
JSON.stringify({
|
|
name: "test",
|
|
address: { street: "123 Main", city: "NYC" },
|
|
}),
|
|
);
|
|
|
|
const { exitCode, stdout } = await runCli(
|
|
["put", schemaHash.trim(), payloadFile],
|
|
tmpStore,
|
|
);
|
|
|
|
expect(exitCode).toBe(0);
|
|
expect(envValue(stdout)).toMatch(/^[0-9A-HJKMNP-TV-Z]{13}$/);
|
|
} finally {
|
|
rmSync(tmpStore, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("T1.4: Valid data using @ alias for type-hash should be accepted", async () => {
|
|
const tmpStore = mkdtempSync(join(tmpdir(), "json-cas-test-"));
|
|
try {
|
|
await runCli(["init"], tmpStore);
|
|
|
|
const payloadFile = join(tmpStore, "payload.json");
|
|
writeFileSync(payloadFile, JSON.stringify("hello world"));
|
|
|
|
const { exitCode, stdout } = await runCli(
|
|
["put", "@string", payloadFile],
|
|
tmpStore,
|
|
);
|
|
|
|
expect(exitCode).toBe(0);
|
|
expect(envValue(stdout)).toMatch(/^[0-9A-HJKMNP-TV-Z]{13}$/);
|
|
} finally {
|
|
rmSync(tmpStore, { recursive: true, force: true });
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("Test Group 2: Type Mismatches (New Validation)", () => {
|
|
test("T2.1: Wrong property type should be rejected", async () => {
|
|
const tmpStore = mkdtempSync(join(tmpdir(), "json-cas-test-"));
|
|
try {
|
|
await runCli(["init"], tmpStore);
|
|
|
|
// Schema with name as string
|
|
const schemaFile = join(tmpStore, "schema.json");
|
|
writeFileSync(
|
|
schemaFile,
|
|
JSON.stringify({
|
|
type: "object",
|
|
properties: { name: { type: "string" } },
|
|
required: ["name"],
|
|
additionalProperties: false,
|
|
}),
|
|
);
|
|
const schemaHash = await putSchemaFile(tmpStore, schemaFile);
|
|
|
|
// Payload with name as number
|
|
const payloadFile = join(tmpStore, "payload.json");
|
|
writeFileSync(payloadFile, JSON.stringify({ name: 123 }));
|
|
|
|
const { exitCode, stdout, stderr } = await runCli(
|
|
["put", schemaHash.trim(), payloadFile],
|
|
tmpStore,
|
|
);
|
|
|
|
expect(exitCode).toBe(1);
|
|
expect(stdout).toBe("");
|
|
expect(stderr).toContain("Validation failed");
|
|
expect(stderr).toContain(schemaHash.trim());
|
|
expect(stderr).toContain(payloadFile);
|
|
|
|
// Verify no node was stored
|
|
const { stdout: hasOutput } = await runCli(
|
|
["has", "0000000000000"],
|
|
tmpStore,
|
|
);
|
|
expect(envValue(hasOutput)).toBe(false);
|
|
} finally {
|
|
rmSync(tmpStore, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("T2.2: Missing required property should be rejected", async () => {
|
|
const tmpStore = mkdtempSync(join(tmpdir(), "json-cas-test-"));
|
|
try {
|
|
await runCli(["init"], tmpStore);
|
|
|
|
// Schema with required name
|
|
const schemaFile = join(tmpStore, "schema.json");
|
|
writeFileSync(
|
|
schemaFile,
|
|
JSON.stringify({
|
|
type: "object",
|
|
properties: { name: { type: "string" } },
|
|
required: ["name"],
|
|
additionalProperties: false,
|
|
}),
|
|
);
|
|
const schemaHash = await putSchemaFile(tmpStore, schemaFile);
|
|
|
|
// Empty payload
|
|
const payloadFile = join(tmpStore, "payload.json");
|
|
writeFileSync(payloadFile, JSON.stringify({}));
|
|
|
|
const { exitCode, stderr } = await runCli(
|
|
["put", schemaHash.trim(), payloadFile],
|
|
tmpStore,
|
|
);
|
|
|
|
expect(exitCode).not.toBe(0);
|
|
expect(stderr).toContain("Validation failed");
|
|
} finally {
|
|
rmSync(tmpStore, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("T2.3: Additional properties when disallowed should be rejected", async () => {
|
|
const tmpStore = mkdtempSync(join(tmpdir(), "json-cas-test-"));
|
|
try {
|
|
await runCli(["init"], tmpStore);
|
|
|
|
// Schema with additionalProperties: false
|
|
const schemaFile = join(tmpStore, "schema.json");
|
|
writeFileSync(
|
|
schemaFile,
|
|
JSON.stringify({
|
|
type: "object",
|
|
properties: { name: { type: "string" } },
|
|
additionalProperties: false,
|
|
}),
|
|
);
|
|
const schemaHash = await putSchemaFile(tmpStore, schemaFile);
|
|
|
|
// Payload with extra property
|
|
const payloadFile = join(tmpStore, "payload.json");
|
|
writeFileSync(
|
|
payloadFile,
|
|
JSON.stringify({ name: "test", extra: "not allowed" }),
|
|
);
|
|
|
|
const { exitCode, stderr } = await runCli(
|
|
["put", schemaHash.trim(), payloadFile],
|
|
tmpStore,
|
|
);
|
|
|
|
expect(exitCode).not.toBe(0);
|
|
expect(stderr).toContain("Validation failed");
|
|
} finally {
|
|
rmSync(tmpStore, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("T2.4: Wrong root type should be rejected", async () => {
|
|
const tmpStore = mkdtempSync(join(tmpdir(), "json-cas-test-"));
|
|
try {
|
|
await runCli(["init"], tmpStore);
|
|
|
|
// Schema expecting array
|
|
const schemaFile = join(tmpStore, "schema.json");
|
|
writeFileSync(
|
|
schemaFile,
|
|
JSON.stringify({
|
|
type: "array",
|
|
items: { type: "string" },
|
|
}),
|
|
);
|
|
const schemaHash = await putSchemaFile(tmpStore, schemaFile);
|
|
|
|
// Payload is an object
|
|
const payloadFile = join(tmpStore, "payload.json");
|
|
writeFileSync(payloadFile, JSON.stringify({}));
|
|
|
|
const { exitCode, stderr } = await runCli(
|
|
["put", schemaHash.trim(), payloadFile],
|
|
tmpStore,
|
|
);
|
|
|
|
expect(exitCode).not.toBe(0);
|
|
expect(stderr).toContain("Validation failed");
|
|
} finally {
|
|
rmSync(tmpStore, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("T2.5: Nested type mismatch should be rejected", async () => {
|
|
const tmpStore = mkdtempSync(join(tmpdir(), "json-cas-test-"));
|
|
try {
|
|
await runCli(["init"], tmpStore);
|
|
|
|
// Schema with nested object
|
|
const schemaFile = join(tmpStore, "schema.json");
|
|
writeFileSync(
|
|
schemaFile,
|
|
JSON.stringify({
|
|
type: "object",
|
|
properties: {
|
|
user: {
|
|
type: "object",
|
|
properties: {
|
|
age: { type: "number" },
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
);
|
|
const schemaHash = await putSchemaFile(tmpStore, schemaFile);
|
|
|
|
// Payload with wrong nested type
|
|
const payloadFile = join(tmpStore, "payload.json");
|
|
writeFileSync(
|
|
payloadFile,
|
|
JSON.stringify({ user: { age: "not a number" } }),
|
|
);
|
|
|
|
const { exitCode, stderr } = await runCli(
|
|
["put", schemaHash.trim(), payloadFile],
|
|
tmpStore,
|
|
);
|
|
|
|
expect(exitCode).not.toBe(0);
|
|
expect(stderr).toContain("Validation failed");
|
|
} finally {
|
|
rmSync(tmpStore, { recursive: true, force: true });
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("Test Group 3: Schema Errors (Edge Cases)", () => {
|
|
test("T3.1: Non-existent type-hash should fail gracefully", async () => {
|
|
const tmpStore = mkdtempSync(join(tmpdir(), "json-cas-test-"));
|
|
try {
|
|
await runCli(["init"], tmpStore);
|
|
|
|
const payloadFile = join(tmpStore, "payload.json");
|
|
writeFileSync(payloadFile, JSON.stringify({ name: "test" }));
|
|
|
|
const { exitCode, stderr } = await runCli(
|
|
["put", "ZZZZZZZZZZZZZ", payloadFile],
|
|
tmpStore,
|
|
);
|
|
|
|
expect(exitCode).not.toBe(0);
|
|
expect(stderr).toContain("Schema not found");
|
|
} finally {
|
|
rmSync(tmpStore, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("T3.3: Invalid @ alias should fail before validation", async () => {
|
|
const tmpStore = mkdtempSync(join(tmpdir(), "json-cas-test-"));
|
|
try {
|
|
await runCli(["init"], tmpStore);
|
|
|
|
const payloadFile = join(tmpStore, "payload.json");
|
|
writeFileSync(payloadFile, JSON.stringify({}));
|
|
|
|
const { exitCode, stderr } = await runCli(
|
|
["put", "@nonexistent", payloadFile],
|
|
tmpStore,
|
|
);
|
|
|
|
expect(exitCode).not.toBe(0);
|
|
expect(stderr).toContain("Schema not found");
|
|
} finally {
|
|
rmSync(tmpStore, { recursive: true, force: true });
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("Test Group 4: Integration with Existing Features", () => {
|
|
test("T4.1: Hash command should not validate (dry-run consistency)", async () => {
|
|
const tmpStore = mkdtempSync(join(tmpdir(), "json-cas-test-"));
|
|
try {
|
|
await runCli(["init"], tmpStore);
|
|
|
|
// Create schema
|
|
const schemaFile = join(tmpStore, "schema.json");
|
|
writeFileSync(
|
|
schemaFile,
|
|
JSON.stringify({
|
|
type: "object",
|
|
properties: { name: { type: "string" } },
|
|
required: ["name"],
|
|
additionalProperties: false,
|
|
}),
|
|
);
|
|
const schemaHash = await putSchemaFile(tmpStore, schemaFile);
|
|
|
|
// Invalid payload
|
|
const payloadFile = join(tmpStore, "payload.json");
|
|
writeFileSync(payloadFile, JSON.stringify({ name: 123 }));
|
|
|
|
// Hash command should succeed even with invalid data
|
|
const { exitCode, stdout } = await runCli(
|
|
["hash", schemaHash.trim(), payloadFile],
|
|
tmpStore,
|
|
);
|
|
|
|
expect(exitCode).toBe(0);
|
|
expect(envValue(stdout)).toMatch(/^[0-9A-HJKMNP-TV-Z]{13}$/);
|
|
} finally {
|
|
rmSync(tmpStore, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("T4.2: Validation respects cas_ref format in schemas", async () => {
|
|
const tmpStore = mkdtempSync(join(tmpdir(), "json-cas-test-"));
|
|
try {
|
|
await runCli(["init"], tmpStore);
|
|
|
|
// Schema with cas_ref format
|
|
const schemaFile = join(tmpStore, "schema.json");
|
|
writeFileSync(
|
|
schemaFile,
|
|
JSON.stringify({
|
|
type: "object",
|
|
properties: {
|
|
ref: { type: "string", format: "cas_ref" },
|
|
},
|
|
}),
|
|
);
|
|
const schemaHash = await putSchemaFile(tmpStore, schemaFile);
|
|
|
|
// Valid cas_ref
|
|
const validFile = join(tmpStore, "valid.json");
|
|
writeFileSync(validFile, JSON.stringify({ ref: "0000000000000" }));
|
|
|
|
const { exitCode: validExitCode } = await runCli(
|
|
["put", schemaHash.trim(), validFile],
|
|
tmpStore,
|
|
);
|
|
expect(validExitCode).toBe(0);
|
|
|
|
// Invalid cas_ref (wrong length)
|
|
const invalidFile = join(tmpStore, "invalid.json");
|
|
writeFileSync(invalidFile, JSON.stringify({ ref: "short" }));
|
|
|
|
const { exitCode: invalidExitCode, stderr } = await runCli(
|
|
["put", schemaHash.trim(), invalidFile],
|
|
tmpStore,
|
|
);
|
|
expect(invalidExitCode).not.toBe(0);
|
|
expect(stderr).toContain("Validation failed");
|
|
} finally {
|
|
rmSync(tmpStore, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("T4.3: Schema self-validation still works", async () => {
|
|
const tmpStore = mkdtempSync(join(tmpdir(), "json-cas-test-"));
|
|
try {
|
|
await runCli(["init"], tmpStore);
|
|
|
|
// Valid schema
|
|
const schemaFile = join(tmpStore, "schema.json");
|
|
writeFileSync(
|
|
schemaFile,
|
|
JSON.stringify({
|
|
type: "object",
|
|
properties: { name: { type: "string" } },
|
|
}),
|
|
);
|
|
|
|
const hash = await putSchemaFile(tmpStore, schemaFile);
|
|
expect(hash).toMatch(/^[0-9A-HJKMNP-TV-Z]{13}$/);
|
|
} finally {
|
|
rmSync(tmpStore, { recursive: true, force: true });
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("Test Group 5: Error Message Quality", () => {
|
|
test("T5.1: Error message should be helpful", async () => {
|
|
const tmpStore = mkdtempSync(join(tmpdir(), "json-cas-test-"));
|
|
try {
|
|
await runCli(["init"], tmpStore);
|
|
|
|
const schemaFile = join(tmpStore, "schema.json");
|
|
writeFileSync(
|
|
schemaFile,
|
|
JSON.stringify({
|
|
type: "object",
|
|
properties: { name: { type: "string" } },
|
|
required: ["name"],
|
|
}),
|
|
);
|
|
const schemaHash = await putSchemaFile(tmpStore, schemaFile);
|
|
|
|
const payloadFile = join(tmpStore, "payload.json");
|
|
writeFileSync(payloadFile, JSON.stringify({ name: 123 }));
|
|
|
|
const { stderr } = await runCli(
|
|
["put", schemaHash.trim(), payloadFile],
|
|
tmpStore,
|
|
);
|
|
|
|
expect(stderr).toContain("Validation failed");
|
|
expect(stderr).toContain(schemaHash.trim());
|
|
expect(stderr).toContain(payloadFile);
|
|
} finally {
|
|
rmSync(tmpStore, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("T5.2: Error should go to stderr, not stdout", async () => {
|
|
const tmpStore = mkdtempSync(join(tmpdir(), "json-cas-test-"));
|
|
try {
|
|
await runCli(["init"], tmpStore);
|
|
|
|
const schemaFile = join(tmpStore, "schema.json");
|
|
writeFileSync(
|
|
schemaFile,
|
|
JSON.stringify({
|
|
type: "object",
|
|
properties: { name: { type: "string" } },
|
|
}),
|
|
);
|
|
const schemaHash = await putSchemaFile(tmpStore, schemaFile);
|
|
|
|
const payloadFile = join(tmpStore, "payload.json");
|
|
writeFileSync(payloadFile, JSON.stringify({ name: 123 }));
|
|
|
|
const { stdout, stderr } = await runCli(
|
|
["put", schemaHash.trim(), payloadFile],
|
|
tmpStore,
|
|
);
|
|
|
|
expect(stdout).toBe("");
|
|
expect(stderr.length).toBeGreaterThan(0);
|
|
} finally {
|
|
rmSync(tmpStore, { recursive: true, force: true });
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
// e2e Phase 2 tests
|
|
describe("Phase 2: Schema Validation", () => {
|
|
let tmpStore: string;
|
|
let varDbPath: string;
|
|
let typeHash: string;
|
|
let nodeHash: string;
|
|
|
|
const entrypoint = resolve(import.meta.dir, "../src/index.ts");
|
|
|
|
beforeAll(async () => {
|
|
tmpStore = mkdtempSync(join(tmpdir(), "json-cas-e2e-"));
|
|
varDbPath = join(tmpStore, "variables.db");
|
|
|
|
const schemaFile = join(tmpStore, "test-schema.json");
|
|
writeFileSync(
|
|
schemaFile,
|
|
JSON.stringify({
|
|
type: "object",
|
|
properties: { name: { type: "string" }, age: { type: "number" } },
|
|
required: ["name"],
|
|
additionalProperties: false,
|
|
}),
|
|
);
|
|
const { openStore: openFsStore } = await import("@uncaged/json-cas-fs");
|
|
const { putSchema } = await import("@uncaged/json-cas");
|
|
const store = await openFsStore(tmpStore);
|
|
typeHash = await putSchema(
|
|
store,
|
|
JSON.parse(readFileSync(schemaFile, "utf-8")),
|
|
);
|
|
|
|
const nodeFile = join(tmpStore, "test-node.json");
|
|
writeFileSync(nodeFile, JSON.stringify({ name: "Alice", age: 30 }));
|
|
const proc = Bun.spawn(
|
|
[
|
|
"bun",
|
|
entrypoint,
|
|
"--store",
|
|
tmpStore,
|
|
"--var-db",
|
|
varDbPath,
|
|
"put",
|
|
typeHash,
|
|
nodeFile,
|
|
],
|
|
{ stdout: "pipe", stderr: "pipe" },
|
|
);
|
|
await proc.exited;
|
|
const stdout = (await new Response(proc.stdout).text()).trim();
|
|
nodeHash = envValue(stdout) as string;
|
|
});
|
|
|
|
afterAll(() => {
|
|
rmSync(tmpStore, { recursive: true, force: true });
|
|
});
|
|
|
|
test("2.1 put {name:123} against string-schema fails with non-zero exit", async () => {
|
|
const badFile = join(tmpStore, "bad-node.json");
|
|
writeFileSync(badFile, JSON.stringify({ name: 123 }));
|
|
const proc = Bun.spawn(
|
|
[
|
|
"bun",
|
|
entrypoint,
|
|
"--store",
|
|
tmpStore,
|
|
"--var-db",
|
|
varDbPath,
|
|
"put",
|
|
typeHash,
|
|
badFile,
|
|
],
|
|
{ stdout: "pipe", stderr: "pipe" },
|
|
);
|
|
const exitCode = await proc.exited;
|
|
const stdout = (await new Response(proc.stdout).text()).trim();
|
|
const stderr = (await new Response(proc.stderr).text()).trim();
|
|
expect(exitCode).not.toBe(0);
|
|
expect(stdout).toBe("");
|
|
expect(stderr).toContain("Validation failed");
|
|
expect(stderr).toContain(typeHash);
|
|
});
|
|
|
|
test("2.3 put against non-existent schema hash fails", async () => {
|
|
const nodeFile = join(tmpStore, "test-node.json");
|
|
const proc = Bun.spawn(
|
|
[
|
|
"bun",
|
|
entrypoint,
|
|
"--store",
|
|
tmpStore,
|
|
"--var-db",
|
|
varDbPath,
|
|
"put",
|
|
"AAAAAAAAAAAAA",
|
|
nodeFile,
|
|
],
|
|
{ stdout: "pipe", stderr: "pipe" },
|
|
);
|
|
const exitCode = await proc.exited;
|
|
const stderr = (await new Response(proc.stderr).text()).trim();
|
|
expect(exitCode).not.toBe(0);
|
|
expect(stderr).toMatchSnapshot();
|
|
});
|
|
});
|