The tests work
This commit is contained in:
@@ -160,7 +160,7 @@ describe("invitation command - error cases", () => {
|
||||
const mockEngine = await createMockEngine(DEFAULT_SEED);
|
||||
engine = mockEngine.engine;
|
||||
await engine.importTemplate(p2pkhTemplate);
|
||||
app = await createMockAppService(engine);
|
||||
app = await createMockAppService(engine, mockEngine.state);
|
||||
tempDir = mkdtempSync(path.join(tmpdir(), "xo-cli-invitation-errors-"));
|
||||
paths = createMockPaths(tempDir);
|
||||
});
|
||||
@@ -201,7 +201,7 @@ describe("invitation command - receive flow", () => {
|
||||
const mockEngine = await createMockEngine(DEFAULT_SEED);
|
||||
engine = mockEngine.engine;
|
||||
await engine.importTemplate(p2pkhTemplate);
|
||||
app = await createMockAppService(engine);
|
||||
app = await createMockAppService(engine, mockEngine.state);
|
||||
tempDir = mkdtempSync(path.join(tmpdir(), "xo-cli-invitation-receive-"));
|
||||
paths = createMockPaths(tempDir);
|
||||
});
|
||||
@@ -276,7 +276,7 @@ describe("invitation command - receive flow", () => {
|
||||
await handleInvitationCommand(
|
||||
createCommandDeps(app, io, paths),
|
||||
["create", "Wallet (P2PKH)", "receive"],
|
||||
{},
|
||||
{ varTransferredSatoshis: "10000", role: "receiver" },
|
||||
);
|
||||
|
||||
expectLogs(spies, [{ out: "All requirements satisfied" }]);
|
||||
@@ -314,7 +314,7 @@ describe("invitation command - request satoshis flow", () => {
|
||||
const mockEngine = await createMockEngine(DEFAULT_SEED);
|
||||
engine = mockEngine.engine;
|
||||
await engine.importTemplate(p2pkhTemplate);
|
||||
app = await createMockAppService(engine);
|
||||
app = await createMockAppService(engine, mockEngine.state);
|
||||
tempDir = mkdtempSync(path.join(tmpdir(), "xo-cli-invitation-request-"));
|
||||
paths = createMockPaths(tempDir);
|
||||
});
|
||||
@@ -410,7 +410,7 @@ describe("invitation command - send flow with resources", () => {
|
||||
engine = mockEngine.engine;
|
||||
state = mockEngine.state;
|
||||
await engine.importTemplate(p2pkhTemplate);
|
||||
app = await createMockAppService(engine);
|
||||
app = await createMockAppService(engine, mockEngine.state);
|
||||
tempDir = mkdtempSync(path.join(tmpdir(), "xo-cli-invitation-send-"));
|
||||
paths = createMockPaths(tempDir);
|
||||
});
|
||||
@@ -489,7 +489,7 @@ describe("invitation command - send flow with resources", () => {
|
||||
varRecipientLockingscript:
|
||||
"76a91489abcdefabbaabbaabbaabbaabbaabbaabbaabba88ac",
|
||||
addInput:
|
||||
"0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"0000000000000000000000000000000000000000000000000000000000000001:0",
|
||||
role: "sender",
|
||||
},
|
||||
);
|
||||
@@ -536,7 +536,7 @@ describe("invitation command - multi-step append", () => {
|
||||
const mockEngine = await createMockEngine(DEFAULT_SEED);
|
||||
engine = mockEngine.engine;
|
||||
await engine.importTemplate(p2pkhTemplate);
|
||||
app = await createMockAppService(engine);
|
||||
app = await createMockAppService(engine, mockEngine.state);
|
||||
tempDir = mkdtempSync(path.join(tmpdir(), "xo-cli-invitation-append-"));
|
||||
paths = createMockPaths(tempDir);
|
||||
});
|
||||
@@ -684,7 +684,7 @@ describe("invitation command - list and inspect", () => {
|
||||
const mockEngine = await createMockEngine(DEFAULT_SEED);
|
||||
engine = mockEngine.engine;
|
||||
await engine.importTemplate(p2pkhTemplate);
|
||||
app = await createMockAppService(engine);
|
||||
app = await createMockAppService(engine, mockEngine.state);
|
||||
tempDir = mkdtempSync(path.join(tmpdir(), "xo-cli-invitation-list-"));
|
||||
paths = createMockPaths(tempDir);
|
||||
});
|
||||
@@ -853,7 +853,7 @@ describe("invitation command - sign flow", () => {
|
||||
const mockEngine = await createMockEngine(DEFAULT_SEED);
|
||||
engine = mockEngine.engine;
|
||||
await engine.importTemplate(p2pkhTemplate);
|
||||
app = await createMockAppService(engine);
|
||||
app = await createMockAppService(engine, mockEngine.state);
|
||||
tempDir = mkdtempSync(path.join(tmpdir(), "xo-cli-invitation-sign-"));
|
||||
paths = createMockPaths(tempDir);
|
||||
});
|
||||
@@ -930,7 +930,7 @@ describe("invitation command - sign flow", () => {
|
||||
const result = await handleInvitationCommand(
|
||||
createCommandDeps(app, io, paths),
|
||||
["create", "Wallet (P2PKH)", "receive"],
|
||||
{ sign: "true" },
|
||||
{ sign: "true", varTransferredSatoshis: "10000", role: "receiver" },
|
||||
);
|
||||
|
||||
expect(result.invitationIdentifier).toMatch(/^[a-f0-9]{32}$/);
|
||||
@@ -940,6 +940,24 @@ describe("invitation command - sign flow", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests the --sign flag on create will not auto-signs when requirements are not satisfied.
|
||||
*/
|
||||
test("--sign flag auto-signs on create", async () => {
|
||||
const { io, spies } = createMockIO();
|
||||
|
||||
const result = await handleInvitationCommand(
|
||||
createCommandDeps(app, io, paths),
|
||||
["create", "Wallet (P2PKH)", "receive"],
|
||||
{ sign: "true" },
|
||||
);
|
||||
|
||||
expect(result.invitationIdentifier).toMatch(/^[a-f0-9]{32}$/);
|
||||
expectLogs(spies, [
|
||||
{ out: "Remaining requirements" },
|
||||
]);
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that signing fails when invitation doesn't exist.
|
||||
*/
|
||||
@@ -969,12 +987,13 @@ describe("invitation command - import flow", () => {
|
||||
let app: AppService;
|
||||
let tempDir: string;
|
||||
let paths: CommandPaths;
|
||||
let mockEngine: any;
|
||||
|
||||
beforeEach(async () => {
|
||||
const mockEngine = await createMockEngine(DEFAULT_SEED);
|
||||
mockEngine = await createMockEngine(DEFAULT_SEED);
|
||||
engine = mockEngine.engine;
|
||||
await engine.importTemplate(p2pkhTemplate);
|
||||
app = await createMockAppService(engine);
|
||||
app = await createMockAppService(engine, mockEngine.state);
|
||||
tempDir = mkdtempSync(path.join(tmpdir(), "xo-cli-invitation-import-"));
|
||||
paths = createMockPaths(tempDir);
|
||||
});
|
||||
@@ -1001,7 +1020,7 @@ describe("invitation command - import flow", () => {
|
||||
`inv-${createResult.invitationIdentifier}.json`,
|
||||
);
|
||||
|
||||
const secondApp = await createMockAppService(engine);
|
||||
const secondApp = await createMockAppService(engine, mockEngine.state);
|
||||
const { io: importIO } = createMockIO();
|
||||
|
||||
const importResult = await handleInvitationCommand(
|
||||
@@ -1048,7 +1067,7 @@ describe("invitation command - import flow", () => {
|
||||
`inv-${createResult.invitationIdentifier}.json`,
|
||||
);
|
||||
|
||||
const secondApp = await createMockAppService(engine);
|
||||
const secondApp = await createMockAppService(engine, mockEngine.state);
|
||||
const { io: importIO } = createMockIO();
|
||||
|
||||
await handleInvitationCommand(
|
||||
@@ -1077,7 +1096,7 @@ describe("invitation command - import flow", () => {
|
||||
`inv-${createResult.invitationIdentifier}.json`,
|
||||
);
|
||||
|
||||
const secondApp = await createMockAppService(engine);
|
||||
const secondApp = await createMockAppService(engine, mockEngine.state);
|
||||
const { io: importIO } = createMockIO();
|
||||
|
||||
await handleInvitationCommand(
|
||||
@@ -1106,7 +1125,7 @@ describe("invitation command - auto-inputs flow", () => {
|
||||
const mockEngine = await createMockEngine(DEFAULT_SEED);
|
||||
engine = mockEngine.engine;
|
||||
await engine.importTemplate(p2pkhTemplate);
|
||||
app = await createMockAppService(engine);
|
||||
app = await createMockAppService(engine, mockEngine.state);
|
||||
tempDir = mkdtempSync(path.join(tmpdir(), "xo-cli-invitation-autoinputs-"));
|
||||
paths = createMockPaths(tempDir);
|
||||
});
|
||||
@@ -1182,7 +1201,7 @@ describe("invitation command - broadcast flow", () => {
|
||||
const mockEngine = await createMockEngine(DEFAULT_SEED);
|
||||
engine = mockEngine.engine;
|
||||
await engine.importTemplate(p2pkhTemplate);
|
||||
app = await createMockAppService(engine);
|
||||
app = await createMockAppService(engine, mockEngine.state);
|
||||
tempDir = mkdtempSync(path.join(tmpdir(), "xo-cli-invitation-broadcast-"));
|
||||
paths = createMockPaths(tempDir);
|
||||
});
|
||||
@@ -1247,7 +1266,7 @@ describe("invitation command - full lifecycle", () => {
|
||||
const mockEngine = await createMockEngine(DEFAULT_SEED);
|
||||
engine = mockEngine.engine;
|
||||
await engine.importTemplate(p2pkhTemplate);
|
||||
app = await createMockAppService(engine);
|
||||
app = await createMockAppService(engine, mockEngine.state);
|
||||
tempDir = mkdtempSync(path.join(tmpdir(), "xo-cli-invitation-lifecycle-"));
|
||||
paths = createMockPaths(tempDir);
|
||||
});
|
||||
@@ -1402,7 +1421,7 @@ describe("invitation command - full lifecycle", () => {
|
||||
const result = await handleInvitationCommand(
|
||||
createCommandDeps(app, io, paths),
|
||||
["create", "Wallet (P2PKH)", "receive"],
|
||||
{ sign: "true" },
|
||||
{ sign: "true", varTransferredSatoshis: "10000", role: "receiver" },
|
||||
);
|
||||
|
||||
expect(result.invitationIdentifier).toMatch(/^[a-f0-9]{32}$/);
|
||||
|
||||
@@ -85,7 +85,7 @@ describe("receive command", () => {
|
||||
engine = mockEngine.engine;
|
||||
await engine.importTemplate(p2pkhTemplate);
|
||||
|
||||
app = await createMockAppService(engine);
|
||||
app = await createMockAppService(engine, mockEngine.state);
|
||||
|
||||
tempDir = mkdtempSync(path.join(tmpdir(), "xo-cli-receive-tests-"));
|
||||
});
|
||||
@@ -139,4 +139,4 @@ describe("receive command", () => {
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
reserveResource,
|
||||
} from "../mocks/engine";
|
||||
import { type Engine } from "@xo-cash/engine";
|
||||
import { p2pkhTemplate } from "../mocks/template-p2pkh";
|
||||
import { p2pkhTemplate, p2pkhTemplateIdentifier } from "../mocks/template-p2pkh";
|
||||
import { AppService } from "../../../src/services/app";
|
||||
|
||||
import { handleResourceCommand } from "../../../src/cli/commands/resource";
|
||||
@@ -125,7 +125,7 @@ describe("resource command", () => {
|
||||
engine = mockEngine.engine;
|
||||
await engine.importTemplate(p2pkhTemplate);
|
||||
|
||||
app = await createMockAppService(engine);
|
||||
app = await createMockAppService(engine, mockEngine.state);
|
||||
|
||||
tempDir = mkdtempSync(path.join(tmpdir(), "xo-cli-resource-tests-"));
|
||||
});
|
||||
@@ -192,7 +192,7 @@ describe("resource command with populated data", () => {
|
||||
engine = mockEngine.engine;
|
||||
state = mockEngine.state;
|
||||
await engine.importTemplate(p2pkhTemplate);
|
||||
app = await createMockAppService(engine);
|
||||
app = await createMockAppService(engine, state);
|
||||
tempDir = mkdtempSync(path.join(tmpdir(), "xo-cli-resource-tests-"));
|
||||
});
|
||||
|
||||
@@ -283,9 +283,17 @@ describe("resource command with populated data", () => {
|
||||
});
|
||||
|
||||
test("unreserve releases a reserved UTXO", async () => {
|
||||
// Create an invitation
|
||||
const invitation = await engine.createInvitation({
|
||||
templateIdentifier: p2pkhTemplateIdentifier,
|
||||
actionIdentifier: "receive",
|
||||
variables: [],
|
||||
});
|
||||
const invitationInstance = await app.createInvitation(invitation);
|
||||
|
||||
const resource = await addFakeResource(state, {
|
||||
valueSatoshis: 25000,
|
||||
reservedBy: "inv-123",
|
||||
reservedBy: invitationInstance.data.invitationIdentifier,
|
||||
});
|
||||
|
||||
const { io, spies } = createMockIO();
|
||||
@@ -299,8 +307,8 @@ describe("resource command with populated data", () => {
|
||||
);
|
||||
|
||||
expectLogs(spies, [
|
||||
{ out: "Unreserved" },
|
||||
{ out: "was reserved for inv-123" },
|
||||
{ out: "Archived invitation" },
|
||||
{ out: invitationInstance.data.invitationIdentifier },
|
||||
]);
|
||||
|
||||
const resources = await engine.listUnspentOutputsData();
|
||||
@@ -327,15 +335,24 @@ describe("resource command with populated data", () => {
|
||||
});
|
||||
|
||||
test("unreserve-all releases all reserved UTXOs", async () => {
|
||||
// Create 2 fake invitations
|
||||
const invitation1 = await engine.createInvitation({
|
||||
templateIdentifier: p2pkhTemplateIdentifier,
|
||||
actionIdentifier: "receive",
|
||||
variables: [],
|
||||
});
|
||||
const invitation2 = await engine.createInvitation({
|
||||
templateIdentifier: p2pkhTemplateIdentifier,
|
||||
actionIdentifier: "receive",
|
||||
variables: [],
|
||||
});
|
||||
|
||||
const invitationInstance1 = await app.createInvitation(invitation1);
|
||||
const invitationInstance2 = await app.createInvitation(invitation2);
|
||||
|
||||
await addFakeResource(state, { valueSatoshis: 50000 });
|
||||
await addFakeResource(state, {
|
||||
valueSatoshis: 25000,
|
||||
reservedBy: "inv-123",
|
||||
});
|
||||
await addFakeResource(state, {
|
||||
valueSatoshis: 10000,
|
||||
reservedBy: "inv-456",
|
||||
});
|
||||
await addFakeResource(state, { valueSatoshis: 25000, reservedBy: invitationInstance1.data.invitationIdentifier });
|
||||
await addFakeResource(state, { valueSatoshis: 10000, reservedBy: invitationInstance2.data.invitationIdentifier });
|
||||
|
||||
const { io, spies } = createMockIO();
|
||||
const result = await handleResourceCommand(
|
||||
|
||||
@@ -204,9 +204,12 @@ describe("template command", () => {
|
||||
beforeEach(async () => {
|
||||
const mockEngine = await createMockEngine(DEFAULT_SEED);
|
||||
engine = mockEngine.engine;
|
||||
await engine.importTemplate(p2pkhTemplate);
|
||||
const { templateIdentifier } = await engine.importTemplate(p2pkhTemplate);
|
||||
if (templateIdentifier !== p2pkhTemplateIdentifier) {
|
||||
throw new Error("Template identifier mismatch");
|
||||
}
|
||||
|
||||
app = await createMockAppService(engine);
|
||||
app = await createMockAppService(engine, mockEngine.state);
|
||||
|
||||
tempDir = mkdtempSync(path.join(tmpdir(), "xo-cli-template-tests-"));
|
||||
});
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
UnspentOutputStatus,
|
||||
type UnspentOutputData,
|
||||
} from "@xo-cash/state";
|
||||
import { InMemoryBlockchainProvider } from "@xo-cash/engine";
|
||||
import { InMemoryBlockchainProvider } from "../../../src/utils/blockchain/in-memory-blockchain-provider.js";
|
||||
import { convertMnemonicToSeedBytes } from "@xo-cash/crypto";
|
||||
|
||||
import { binToHex, sha256 } from "@bitauth/libauth";
|
||||
@@ -20,6 +20,7 @@ import { MockElectrumService } from "./electrum-service";
|
||||
import { MockRatesService } from "./rates-service";
|
||||
import { RatesService } from "../../../src/services/rates";
|
||||
import { SettingsService } from "../../../src/services/settings";
|
||||
import { mkdirSync } from "node:fs";
|
||||
|
||||
export const DEFAULT_SEED =
|
||||
"oven crop same above under tower promote decrease vocal pretty require slow";
|
||||
@@ -68,6 +69,7 @@ export const addFakeResource = async (
|
||||
options: FakeResourceOptions = {},
|
||||
): Promise<UnspentOutputData> => {
|
||||
const resource: UnspentOutputData = {
|
||||
templateIdentifier: options.templateIdentifier ?? "test-template",
|
||||
status: UnspentOutputStatus.CONFIRMED,
|
||||
selectable: true,
|
||||
privacy: false,
|
||||
@@ -131,10 +133,16 @@ export const unreserveResource = async (
|
||||
* @returns A mock engine instance.
|
||||
*/
|
||||
export const createMockEngine = async (seed: string) => {
|
||||
const randomId = Math.random().toString(36).substring(2, 15);
|
||||
const stateDir = `${tmpdir()}/test-data-${randomId}`;
|
||||
mkdirSync(stateDir, { recursive: true });
|
||||
|
||||
// Create the in-memory storage adapter.
|
||||
const storage = await createStorageAdapter({
|
||||
storageType: "inmemory",
|
||||
storageType: StorageType.INDEXEDDB,
|
||||
accountHash: binToHex(sha256.hash(convertMnemonicToSeedBytes(seed))),
|
||||
databasePath: stateDir,
|
||||
databaseFilename: `xo-wallet-${randomId}.db`,
|
||||
});
|
||||
|
||||
// Initialize the storage adapter.
|
||||
@@ -152,13 +160,17 @@ export const createMockEngine = async (seed: string) => {
|
||||
await blockchainMonitor.initializeEventListeners();
|
||||
|
||||
// Create the engine instance.
|
||||
const engine = new Engine(seed, state, blockchainMonitor, blockchainProvider);
|
||||
const engine = new Engine(seed, state, blockchainProvider, blockchainMonitor);
|
||||
await engine.initializeStateSync();
|
||||
|
||||
return { engine, state, blockchainMonitor, blockchainProvider };
|
||||
};
|
||||
|
||||
export const createMockAppService = async (engine: Engine) => {
|
||||
export const createMockAppService = async (engine: Engine, state: State) => {
|
||||
if (!state) {
|
||||
throw new Error("State is required");
|
||||
}
|
||||
|
||||
const settings = new SettingsService(
|
||||
`${tmpdir()}/xo-cli-tests-settings.json`,
|
||||
);
|
||||
@@ -187,6 +199,7 @@ export const createMockAppService = async (engine: Engine) => {
|
||||
mockElectrum,
|
||||
rates,
|
||||
settings,
|
||||
state,
|
||||
new Uint8Array(32).fill(1),
|
||||
);
|
||||
};
|
||||
|
||||
+1395
-1444
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user