Files
xo-cli/tests/cli/commands/mnemonic.test.ts

146 lines
4.1 KiB
TypeScript

import { expect, test, describe, beforeEach, afterEach } from "vitest";
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import path from "node:path";
import { DEFAULT_SEED } from "../mocks/engine";
import { handleMnemonicCommand } from "../../../src/cli/commands/mnemonic";
import { CommandError } from "../../../src/cli/commands/types";
import { createMockIO, createMockPaths, expectLogs, type LogExpectation } from "../mocks/command";
import { BCHMnemonicURL } from "../../../src/utils/bch-mnemonic-url";
type TestCase = {
inputs: string[];
options?: Record<string, string>;
shouldThrow: boolean;
expectedEvent?: string;
expectedData?: Record<string, unknown>;
logs?: LogExpectation[];
};
const testCases: TestCase[] = [
// Successful creation of a mnemonic file
{
inputs: ["create"],
shouldThrow: false,
expectedData: {
savedAs: expect.stringMatching(/^mnemonic-\w+$/),
},
logs: [{ out: "Mnemonic file created" }],
},
// Successfully creating a mnemonic file with a custom filename
{
inputs: ["create"],
options: { output: "custom-filename" },
shouldThrow: false,
expectedData: {
savedAs: "custom-filename",
},
logs: [{ out: "custom-filename" }],
},
// Successfully listing mnemonic files
{
inputs: ["list"],
shouldThrow: false,
expectedData: {
count: expect.toSatisfy((count: number) => count >= 1),
},
logs: [{ out: "mnemonic-test" }],
},
// Successfully exposing a mnemonic file
{
inputs: ["expose", "mnemonic-test"],
shouldThrow: false,
expectedData: {
mnemonic: DEFAULT_SEED,
},
logs: [{ out: DEFAULT_SEED }],
},
// Successfully importing a mnemonic file
{
inputs: ["import", ...DEFAULT_SEED.split(" ")],
shouldThrow: false,
expectedData: {
savedAs: expect.stringMatching(/^mnemonic-\w+$/),
},
logs: [{ out: "Mnemonic file created" }],
},
// Failure to import a mnemonic file due to missing arguments
{
inputs: ["import"],
shouldThrow: true,
expectedEvent: "mnemonic.import.seed_missing",
},
// Failure to expose a mnemonic file due to missing arguments
{
inputs: ["expose"],
shouldThrow: true,
expectedEvent: "mnemonic.expose.file_missing",
},
// Failure to expose a mnemonic file due to unknown mnemonic file
{
inputs: ["expose", "unknown-mnemonic-file"],
shouldThrow: true,
expectedEvent: "mnemonic.expose.file_not_found",
},
// Missing sub-command
{
inputs: [],
shouldThrow: true,
expectedEvent: "mnemonic.subcommand.missing",
},
// Unknown sub-command
{
inputs: ["unknown"],
shouldThrow: true,
expectedEvent: "mnemonic.subcommand.unknown",
},
];
describe("mnemonic commands", () => {
let tempDir: string;
beforeEach(async () => {
tempDir = mkdtempSync(path.join(tmpdir(), "xo-cli-mnemonic-tests-"));
// Write a single test mnemonic file to the temp directory
writeFileSync(
path.join(tempDir, "mnemonic-test"),
BCHMnemonicURL.fromSeed(DEFAULT_SEED).toURL(),
"utf8",
);
});
afterEach(async () => {
rmSync(tempDir, { recursive: true, force: true });
});
test.each(testCases)("mnemonic command: $inputs", async ({ inputs, options, shouldThrow, expectedEvent, expectedData, logs }) => {
const { io, spies } = createMockIO();
const paths = createMockPaths(tempDir);
if (shouldThrow) {
try {
await handleMnemonicCommand({ io, paths }, inputs, options ?? {});
expect.fail("Expected command to throw");
} catch (error) {
if (expectedEvent) {
expect(error).toBeInstanceOf(CommandError);
expect((error as CommandError).event).toBe(expectedEvent);
}
}
} else {
const result = await handleMnemonicCommand({ io, paths }, inputs, options ?? {});
if (expectedData) {
Object.entries(expectedData).forEach(([key, value]) => {
expect(result[key as keyof typeof result]).toEqual(value);
});
}
}
if (logs) {
expectLogs(spies, logs);
}
});
});