@lhremote/cli 0.0.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +58 -2
- package/dist/cli.js +4 -2
- package/dist/cli.js.map +1 -1
- package/dist/handlers/campaign-add-action.d.ts +14 -0
- package/dist/handlers/campaign-add-action.d.ts.map +1 -0
- package/dist/handlers/campaign-add-action.js +51 -0
- package/dist/handlers/campaign-add-action.js.map +1 -0
- package/dist/handlers/campaign-add-action.test.d.ts +2 -0
- package/dist/handlers/campaign-add-action.test.d.ts.map +1 -0
- package/dist/handlers/campaign-add-action.test.js +121 -0
- package/dist/handlers/campaign-add-action.test.js.map +1 -0
- package/dist/handlers/campaign-create.d.ts +11 -0
- package/dist/handlers/campaign-create.d.ts.map +1 -0
- package/dist/handlers/campaign-create.js +79 -0
- package/dist/handlers/campaign-create.js.map +1 -0
- package/dist/handlers/campaign-create.test.d.ts +2 -0
- package/dist/handlers/campaign-create.test.d.ts.map +1 -0
- package/dist/handlers/campaign-create.test.js +139 -0
- package/dist/handlers/campaign-create.test.js.map +1 -0
- package/dist/handlers/campaign-delete.d.ts +8 -0
- package/dist/handlers/campaign-delete.d.ts.map +1 -0
- package/dist/handlers/campaign-delete.js +39 -0
- package/dist/handlers/campaign-delete.js.map +1 -0
- package/dist/handlers/campaign-delete.test.d.ts +2 -0
- package/dist/handlers/campaign-delete.test.d.ts.map +1 -0
- package/dist/handlers/campaign-delete.test.js +73 -0
- package/dist/handlers/campaign-delete.test.js.map +1 -0
- package/dist/handlers/campaign-exclude-add.d.ts +11 -0
- package/dist/handlers/campaign-exclude-add.d.ts.map +1 -0
- package/dist/handlers/campaign-exclude-add.js +58 -0
- package/dist/handlers/campaign-exclude-add.js.map +1 -0
- package/dist/handlers/campaign-exclude-add.test.d.ts +2 -0
- package/dist/handlers/campaign-exclude-add.test.d.ts.map +1 -0
- package/dist/handlers/campaign-exclude-add.test.js +144 -0
- package/dist/handlers/campaign-exclude-add.test.js.map +1 -0
- package/dist/handlers/campaign-exclude-list.d.ts +9 -0
- package/dist/handlers/campaign-exclude-list.d.ts.map +1 -0
- package/dist/handlers/campaign-exclude-list.js +46 -0
- package/dist/handlers/campaign-exclude-list.js.map +1 -0
- package/dist/handlers/campaign-exclude-list.test.d.ts +2 -0
- package/dist/handlers/campaign-exclude-list.test.d.ts.map +1 -0
- package/dist/handlers/campaign-exclude-list.test.js +109 -0
- package/dist/handlers/campaign-exclude-list.test.js.map +1 -0
- package/dist/handlers/campaign-exclude-remove.d.ts +11 -0
- package/dist/handlers/campaign-exclude-remove.d.ts.map +1 -0
- package/dist/handlers/campaign-exclude-remove.js +58 -0
- package/dist/handlers/campaign-exclude-remove.js.map +1 -0
- package/dist/handlers/campaign-exclude-remove.test.d.ts +2 -0
- package/dist/handlers/campaign-exclude-remove.test.d.ts.map +1 -0
- package/dist/handlers/campaign-exclude-remove.test.js +147 -0
- package/dist/handlers/campaign-exclude-remove.test.js.map +1 -0
- package/dist/handlers/campaign-export.d.ts +9 -0
- package/dist/handlers/campaign-export.d.ts.map +1 -0
- package/dist/handlers/campaign-export.js +42 -0
- package/dist/handlers/campaign-export.js.map +1 -0
- package/dist/handlers/campaign-export.test.d.ts +2 -0
- package/dist/handlers/campaign-export.test.d.ts.map +1 -0
- package/dist/handlers/campaign-export.test.js +84 -0
- package/dist/handlers/campaign-export.test.js.map +1 -0
- package/dist/handlers/campaign-get.d.ts +8 -0
- package/dist/handlers/campaign-get.d.ts.map +1 -0
- package/dist/handlers/campaign-get.js +46 -0
- package/dist/handlers/campaign-get.js.map +1 -0
- package/dist/handlers/campaign-get.test.d.ts +2 -0
- package/dist/handlers/campaign-get.test.d.ts.map +1 -0
- package/dist/handlers/campaign-get.test.js +131 -0
- package/dist/handlers/campaign-get.test.js.map +1 -0
- package/dist/handlers/campaign-list.d.ts +6 -0
- package/dist/handlers/campaign-list.d.ts.map +1 -0
- package/dist/handlers/campaign-list.js +55 -0
- package/dist/handlers/campaign-list.js.map +1 -0
- package/dist/handlers/campaign-list.test.d.ts +2 -0
- package/dist/handlers/campaign-list.test.d.ts.map +1 -0
- package/dist/handlers/campaign-list.test.js +129 -0
- package/dist/handlers/campaign-list.test.js.map +1 -0
- package/dist/handlers/campaign-move-next.d.ts +10 -0
- package/dist/handlers/campaign-move-next.d.ts.map +1 -0
- package/dist/handlers/campaign-move-next.js +52 -0
- package/dist/handlers/campaign-move-next.js.map +1 -0
- package/dist/handlers/campaign-move-next.test.d.ts +2 -0
- package/dist/handlers/campaign-move-next.test.d.ts.map +1 -0
- package/dist/handlers/campaign-move-next.test.js +127 -0
- package/dist/handlers/campaign-move-next.test.js.map +1 -0
- package/dist/handlers/campaign-remove-action.d.ts +8 -0
- package/dist/handlers/campaign-remove-action.d.ts.map +1 -0
- package/dist/handlers/campaign-remove-action.js +43 -0
- package/dist/handlers/campaign-remove-action.js.map +1 -0
- package/dist/handlers/campaign-remove-action.test.d.ts +2 -0
- package/dist/handlers/campaign-remove-action.test.d.ts.map +1 -0
- package/dist/handlers/campaign-remove-action.test.js +79 -0
- package/dist/handlers/campaign-remove-action.test.js.map +1 -0
- package/dist/handlers/campaign-reorder-actions.d.ts +9 -0
- package/dist/handlers/campaign-reorder-actions.d.ts.map +1 -0
- package/dist/handlers/campaign-reorder-actions.js +66 -0
- package/dist/handlers/campaign-reorder-actions.js.map +1 -0
- package/dist/handlers/campaign-reorder-actions.test.d.ts +2 -0
- package/dist/handlers/campaign-reorder-actions.test.d.ts.map +1 -0
- package/dist/handlers/campaign-reorder-actions.test.js +118 -0
- package/dist/handlers/campaign-reorder-actions.test.js.map +1 -0
- package/dist/handlers/campaign-retry.d.ts +10 -0
- package/dist/handlers/campaign-retry.d.ts.map +1 -0
- package/dist/handlers/campaign-retry.js +45 -0
- package/dist/handlers/campaign-retry.js.map +1 -0
- package/dist/handlers/campaign-retry.test.d.ts +2 -0
- package/dist/handlers/campaign-retry.test.d.ts.map +1 -0
- package/dist/handlers/campaign-retry.test.js +111 -0
- package/dist/handlers/campaign-retry.test.js.map +1 -0
- package/dist/handlers/campaign-start.d.ts +10 -0
- package/dist/handlers/campaign-start.d.ts.map +1 -0
- package/dist/handlers/campaign-start.js +54 -0
- package/dist/handlers/campaign-start.js.map +1 -0
- package/dist/handlers/campaign-start.test.d.ts +2 -0
- package/dist/handlers/campaign-start.test.d.ts.map +1 -0
- package/dist/handlers/campaign-start.test.js +119 -0
- package/dist/handlers/campaign-start.test.js.map +1 -0
- package/dist/handlers/campaign-statistics.d.ts +10 -0
- package/dist/handlers/campaign-statistics.d.ts.map +1 -0
- package/dist/handlers/campaign-statistics.js +63 -0
- package/dist/handlers/campaign-statistics.js.map +1 -0
- package/dist/handlers/campaign-statistics.test.d.ts +2 -0
- package/dist/handlers/campaign-statistics.test.d.ts.map +1 -0
- package/dist/handlers/campaign-statistics.test.js +141 -0
- package/dist/handlers/campaign-statistics.test.js.map +1 -0
- package/dist/handlers/campaign-status.d.ts +10 -0
- package/dist/handlers/campaign-status.d.ts.map +1 -0
- package/dist/handlers/campaign-status.js +62 -0
- package/dist/handlers/campaign-status.js.map +1 -0
- package/dist/handlers/campaign-status.test.d.ts +2 -0
- package/dist/handlers/campaign-status.test.d.ts.map +1 -0
- package/dist/handlers/campaign-status.test.js +123 -0
- package/dist/handlers/campaign-status.test.js.map +1 -0
- package/dist/handlers/campaign-stop.d.ts +8 -0
- package/dist/handlers/campaign-stop.d.ts.map +1 -0
- package/dist/handlers/campaign-stop.js +39 -0
- package/dist/handlers/campaign-stop.js.map +1 -0
- package/dist/handlers/campaign-stop.test.d.ts +2 -0
- package/dist/handlers/campaign-stop.test.d.ts.map +1 -0
- package/dist/handlers/campaign-stop.test.js +73 -0
- package/dist/handlers/campaign-stop.test.js.map +1 -0
- package/dist/handlers/campaign-update.d.ts +11 -0
- package/dist/handlers/campaign-update.d.ts.map +1 -0
- package/dist/handlers/campaign-update.js +51 -0
- package/dist/handlers/campaign-update.js.map +1 -0
- package/dist/handlers/campaign-update.test.d.ts +2 -0
- package/dist/handlers/campaign-update.test.d.ts.map +1 -0
- package/dist/handlers/campaign-update.test.js +95 -0
- package/dist/handlers/campaign-update.test.js.map +1 -0
- package/dist/handlers/check-replies.d.ts +9 -0
- package/dist/handlers/check-replies.d.ts.map +1 -0
- package/dist/handlers/check-replies.js +49 -0
- package/dist/handlers/check-replies.js.map +1 -0
- package/dist/handlers/check-replies.test.d.ts +2 -0
- package/dist/handlers/check-replies.test.d.ts.map +1 -0
- package/dist/handlers/check-replies.test.js +138 -0
- package/dist/handlers/check-replies.test.js.map +1 -0
- package/dist/handlers/check-status.d.ts +8 -0
- package/dist/handlers/check-status.d.ts.map +1 -0
- package/dist/handlers/check-status.js +50 -0
- package/dist/handlers/check-status.js.map +1 -0
- package/dist/handlers/check-status.test.d.ts +2 -0
- package/dist/handlers/check-status.test.d.ts.map +1 -0
- package/dist/handlers/check-status.test.js +112 -0
- package/dist/handlers/check-status.test.js.map +1 -0
- package/dist/handlers/describe-actions.d.ts +7 -0
- package/dist/handlers/describe-actions.d.ts.map +1 -0
- package/dist/handlers/describe-actions.js +74 -0
- package/dist/handlers/describe-actions.js.map +1 -0
- package/dist/handlers/describe-actions.test.d.ts +2 -0
- package/dist/handlers/describe-actions.test.d.ts.map +1 -0
- package/dist/handlers/describe-actions.test.js +95 -0
- package/dist/handlers/describe-actions.test.js.map +1 -0
- package/dist/handlers/find-app.d.ts +5 -0
- package/dist/handlers/find-app.d.ts.map +1 -0
- package/dist/handlers/find-app.js +28 -0
- package/dist/handlers/find-app.js.map +1 -0
- package/dist/handlers/find-app.test.d.ts +2 -0
- package/dist/handlers/find-app.test.d.ts.map +1 -0
- package/dist/handlers/find-app.test.js +75 -0
- package/dist/handlers/find-app.test.js.map +1 -0
- package/dist/handlers/import-people-from-urls.d.ts +10 -0
- package/dist/handlers/import-people-from-urls.d.ts.map +1 -0
- package/dist/handlers/import-people-from-urls.js +96 -0
- package/dist/handlers/import-people-from-urls.js.map +1 -0
- package/dist/handlers/import-people-from-urls.test.d.ts +2 -0
- package/dist/handlers/import-people-from-urls.test.d.ts.map +1 -0
- package/dist/handlers/import-people-from-urls.test.js +166 -0
- package/dist/handlers/import-people-from-urls.test.js.map +1 -0
- package/dist/handlers/index.d.ts +33 -0
- package/dist/handlers/index.d.ts.map +1 -0
- package/dist/handlers/index.js +35 -0
- package/dist/handlers/index.js.map +1 -0
- package/dist/handlers/launch-app.d.ts +3 -0
- package/dist/handlers/launch-app.d.ts.map +1 -0
- package/dist/handlers/launch-app.js +18 -0
- package/dist/handlers/launch-app.js.map +1 -0
- package/dist/handlers/launch-app.test.d.ts +2 -0
- package/dist/handlers/launch-app.test.d.ts.map +1 -0
- package/dist/handlers/launch-app.test.js +64 -0
- package/dist/handlers/launch-app.test.js.map +1 -0
- package/dist/handlers/list-accounts.d.ts +8 -0
- package/dist/handlers/list-accounts.d.ts.map +1 -0
- package/dist/handlers/list-accounts.js +43 -0
- package/dist/handlers/list-accounts.js.map +1 -0
- package/dist/handlers/list-accounts.test.d.ts +2 -0
- package/dist/handlers/list-accounts.test.d.ts.map +1 -0
- package/dist/handlers/list-accounts.test.js +87 -0
- package/dist/handlers/list-accounts.test.js.map +1 -0
- package/dist/handlers/person-ids.d.ts +7 -0
- package/dist/handlers/person-ids.d.ts.map +1 -0
- package/dist/handlers/person-ids.js +50 -0
- package/dist/handlers/person-ids.js.map +1 -0
- package/dist/handlers/query-messages.d.ts +10 -0
- package/dist/handlers/query-messages.d.ts.map +1 -0
- package/dist/handlers/query-messages.integration.test.d.ts +2 -0
- package/dist/handlers/query-messages.integration.test.d.ts.map +1 -0
- package/dist/handlers/query-messages.integration.test.js +106 -0
- package/dist/handlers/query-messages.integration.test.js.map +1 -0
- package/dist/handlers/query-messages.js +113 -0
- package/dist/handlers/query-messages.js.map +1 -0
- package/dist/handlers/query-messages.test.d.ts +2 -0
- package/dist/handlers/query-messages.test.d.ts.map +1 -0
- package/dist/handlers/query-messages.test.js +231 -0
- package/dist/handlers/query-messages.test.js.map +1 -0
- package/dist/handlers/query-profile.d.ts +7 -0
- package/dist/handlers/query-profile.d.ts.map +1 -0
- package/dist/handlers/query-profile.js +79 -0
- package/dist/handlers/query-profile.js.map +1 -0
- package/dist/handlers/query-profile.test.d.ts +2 -0
- package/dist/handlers/query-profile.test.d.ts.map +1 -0
- package/dist/handlers/query-profile.test.js +221 -0
- package/dist/handlers/query-profile.test.js.map +1 -0
- package/dist/handlers/query-profiles.d.ts +9 -0
- package/dist/handlers/query-profiles.d.ts.map +1 -0
- package/dist/handlers/query-profiles.js +83 -0
- package/dist/handlers/query-profiles.js.map +1 -0
- package/dist/handlers/query-profiles.test.d.ts +2 -0
- package/dist/handlers/query-profiles.test.d.ts.map +1 -0
- package/dist/handlers/query-profiles.test.js +286 -0
- package/dist/handlers/query-profiles.test.js.map +1 -0
- package/dist/handlers/quit-app.d.ts +3 -0
- package/dist/handlers/quit-app.d.ts.map +1 -0
- package/dist/handlers/quit-app.js +18 -0
- package/dist/handlers/quit-app.js.map +1 -0
- package/dist/handlers/quit-app.test.d.ts +2 -0
- package/dist/handlers/quit-app.test.d.ts.map +1 -0
- package/dist/handlers/quit-app.test.js +60 -0
- package/dist/handlers/quit-app.test.js.map +1 -0
- package/dist/handlers/scrape-messaging-history.d.ts +8 -0
- package/dist/handlers/scrape-messaging-history.d.ts.map +1 -0
- package/dist/handlers/scrape-messaging-history.js +45 -0
- package/dist/handlers/scrape-messaging-history.js.map +1 -0
- package/dist/handlers/scrape-messaging-history.test.d.ts +2 -0
- package/dist/handlers/scrape-messaging-history.test.d.ts.map +1 -0
- package/dist/handlers/scrape-messaging-history.test.js +101 -0
- package/dist/handlers/scrape-messaging-history.test.js.map +1 -0
- package/dist/handlers/start-instance.d.ts +7 -0
- package/dist/handlers/start-instance.d.ts.map +1 -0
- package/dist/handlers/start-instance.js +42 -0
- package/dist/handlers/start-instance.js.map +1 -0
- package/dist/handlers/start-instance.test.d.ts +2 -0
- package/dist/handlers/start-instance.test.d.ts.map +1 -0
- package/dist/handlers/start-instance.test.js +97 -0
- package/dist/handlers/start-instance.test.js.map +1 -0
- package/dist/handlers/stop-instance.d.ts +7 -0
- package/dist/handlers/stop-instance.d.ts.map +1 -0
- package/dist/handlers/stop-instance.js +34 -0
- package/dist/handlers/stop-instance.js.map +1 -0
- package/dist/handlers/stop-instance.test.d.ts +2 -0
- package/dist/handlers/stop-instance.test.d.ts.map +1 -0
- package/dist/handlers/stop-instance.test.js +66 -0
- package/dist/handlers/stop-instance.test.js.map +1 -0
- package/dist/handlers/testing/mock-helpers.d.ts +56 -0
- package/dist/handlers/testing/mock-helpers.d.ts.map +1 -0
- package/dist/handlers/testing/mock-helpers.js +95 -0
- package/dist/handlers/testing/mock-helpers.js.map +1 -0
- package/dist/program.d.ts +6 -0
- package/dist/program.d.ts.map +1 -0
- package/dist/program.js +341 -0
- package/dist/program.js.map +1 -0
- package/dist/program.test.d.ts +2 -0
- package/dist/program.test.d.ts.map +1 -0
- package/dist/program.test.js +154 -0
- package/dist/program.test.js.map +1 -0
- package/package.json +27 -13
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
4
|
+
vi.mock("@lhremote/core", async (importOriginal) => {
|
|
5
|
+
const actual = await importOriginal();
|
|
6
|
+
return {
|
|
7
|
+
...actual,
|
|
8
|
+
scrapeMessagingHistory: vi.fn(),
|
|
9
|
+
};
|
|
10
|
+
});
|
|
11
|
+
import { InstanceNotRunningError, scrapeMessagingHistory, } from "@lhremote/core";
|
|
12
|
+
import { handleScrapeMessagingHistory } from "./scrape-messaging-history.js";
|
|
13
|
+
import { getStderr, getStdout } from "./testing/mock-helpers.js";
|
|
14
|
+
const MOCK_STATS = {
|
|
15
|
+
totalChats: 42,
|
|
16
|
+
totalMessages: 256,
|
|
17
|
+
earliestMessage: "2024-06-01T10:00:00Z",
|
|
18
|
+
latestMessage: "2025-01-15T14:00:00Z",
|
|
19
|
+
};
|
|
20
|
+
const MOCK_RESULT = {
|
|
21
|
+
success: true,
|
|
22
|
+
actionType: "ScrapeMessagingHistory",
|
|
23
|
+
stats: MOCK_STATS,
|
|
24
|
+
};
|
|
25
|
+
describe("handleScrapeMessagingHistory", () => {
|
|
26
|
+
const originalExitCode = process.exitCode;
|
|
27
|
+
let stdoutSpy;
|
|
28
|
+
let stderrSpy;
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
process.exitCode = undefined;
|
|
31
|
+
vi.clearAllMocks();
|
|
32
|
+
stdoutSpy = vi.spyOn(process.stdout, "write").mockReturnValue(true);
|
|
33
|
+
stderrSpy = vi.spyOn(process.stderr, "write").mockReturnValue(true);
|
|
34
|
+
});
|
|
35
|
+
afterEach(() => {
|
|
36
|
+
process.exitCode = originalExitCode;
|
|
37
|
+
vi.restoreAllMocks();
|
|
38
|
+
});
|
|
39
|
+
it("prints JSON with --json", async () => {
|
|
40
|
+
vi.mocked(scrapeMessagingHistory).mockResolvedValue(MOCK_RESULT);
|
|
41
|
+
await handleScrapeMessagingHistory({ json: true });
|
|
42
|
+
expect(process.exitCode).toBeUndefined();
|
|
43
|
+
const output = JSON.parse(getStdout(stdoutSpy));
|
|
44
|
+
expect(output.success).toBe(true);
|
|
45
|
+
expect(output.actionType).toBe("ScrapeMessagingHistory");
|
|
46
|
+
expect(output.stats).toEqual(MOCK_STATS);
|
|
47
|
+
});
|
|
48
|
+
it("prints human-readable output by default", async () => {
|
|
49
|
+
vi.mocked(scrapeMessagingHistory).mockResolvedValue(MOCK_RESULT);
|
|
50
|
+
await handleScrapeMessagingHistory({});
|
|
51
|
+
expect(process.exitCode).toBeUndefined();
|
|
52
|
+
const output = getStdout(stdoutSpy);
|
|
53
|
+
expect(output).toContain("42 conversations");
|
|
54
|
+
expect(output).toContain("256 messages");
|
|
55
|
+
expect(output).toContain("2024-06-01");
|
|
56
|
+
expect(output).toContain("2025-01-15");
|
|
57
|
+
});
|
|
58
|
+
it("prints progress to stderr", async () => {
|
|
59
|
+
vi.mocked(scrapeMessagingHistory).mockResolvedValue(MOCK_RESULT);
|
|
60
|
+
await handleScrapeMessagingHistory({});
|
|
61
|
+
const stderr = getStderr(stderrSpy);
|
|
62
|
+
expect(stderr).toContain("Scraping messaging history");
|
|
63
|
+
expect(stderr).toContain("Done.");
|
|
64
|
+
});
|
|
65
|
+
it("omits date range when no messages", async () => {
|
|
66
|
+
vi.mocked(scrapeMessagingHistory).mockResolvedValue({
|
|
67
|
+
success: true,
|
|
68
|
+
actionType: "ScrapeMessagingHistory",
|
|
69
|
+
stats: {
|
|
70
|
+
totalChats: 0,
|
|
71
|
+
totalMessages: 0,
|
|
72
|
+
earliestMessage: null,
|
|
73
|
+
latestMessage: null,
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
await handleScrapeMessagingHistory({});
|
|
77
|
+
expect(process.exitCode).toBeUndefined();
|
|
78
|
+
const output = getStdout(stdoutSpy);
|
|
79
|
+
expect(output).toContain("0 conversations");
|
|
80
|
+
expect(output).not.toContain("Date range");
|
|
81
|
+
});
|
|
82
|
+
it("sets exitCode 1 when resolveAccount fails", async () => {
|
|
83
|
+
vi.mocked(scrapeMessagingHistory).mockRejectedValue(new Error("No accounts found."));
|
|
84
|
+
await handleScrapeMessagingHistory({});
|
|
85
|
+
expect(process.exitCode).toBe(1);
|
|
86
|
+
expect(getStderr(stderrSpy)).toContain("No accounts found.");
|
|
87
|
+
});
|
|
88
|
+
it("sets exitCode 1 when instance not running", async () => {
|
|
89
|
+
vi.mocked(scrapeMessagingHistory).mockRejectedValue(new InstanceNotRunningError("No LinkedHelper instance is running. Use start-instance first."));
|
|
90
|
+
await handleScrapeMessagingHistory({});
|
|
91
|
+
expect(process.exitCode).toBe(1);
|
|
92
|
+
expect(getStderr(stderrSpy)).toContain("No LinkedHelper instance is running.");
|
|
93
|
+
});
|
|
94
|
+
it("sets exitCode 1 on unexpected error", async () => {
|
|
95
|
+
vi.mocked(scrapeMessagingHistory).mockRejectedValue(new Error("connection reset"));
|
|
96
|
+
await handleScrapeMessagingHistory({});
|
|
97
|
+
expect(process.exitCode).toBe(1);
|
|
98
|
+
expect(getStderr(stderrSpy)).toContain("connection reset");
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
//# sourceMappingURL=scrape-messaging-history.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scrape-messaging-history.test.js","sourceRoot":"","sources":["../../src/handlers/scrape-messaging-history.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Handle the {@link https://github.com/alexey-pelykh/lhremote#account--instance | start-instance} CLI command. */
|
|
2
|
+
export declare function handleStartInstance(accountIdArg: string, options: {
|
|
3
|
+
cdpPort?: number;
|
|
4
|
+
cdpHost?: string;
|
|
5
|
+
allowRemote?: boolean;
|
|
6
|
+
}): Promise<void>;
|
|
7
|
+
//# sourceMappingURL=start-instance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start-instance.d.ts","sourceRoot":"","sources":["../../src/handlers/start-instance.ts"],"names":[],"mappings":"AAUA,mHAAmH;AACnH,wBAAsB,mBAAmB,CACvC,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,GACrE,OAAO,CAAC,IAAI,CAAC,CA+Cf"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
import { DEFAULT_CDP_PORT, errorMessage, LauncherService, startInstanceWithRecovery, } from "@lhremote/core";
|
|
4
|
+
/** Handle the {@link https://github.com/alexey-pelykh/lhremote#account--instance | start-instance} CLI command. */
|
|
5
|
+
export async function handleStartInstance(accountIdArg, options) {
|
|
6
|
+
const accountId = Number(accountIdArg);
|
|
7
|
+
const cdpPort = options.cdpPort ?? DEFAULT_CDP_PORT;
|
|
8
|
+
const launcher = new LauncherService(cdpPort, {
|
|
9
|
+
...(options.cdpHost !== undefined && { host: options.cdpHost }),
|
|
10
|
+
...(options.allowRemote !== undefined && { allowRemote: options.allowRemote }),
|
|
11
|
+
});
|
|
12
|
+
try {
|
|
13
|
+
await launcher.connect();
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
const message = errorMessage(error);
|
|
17
|
+
process.stderr.write(`${message}\n`);
|
|
18
|
+
process.exitCode = 1;
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
const outcome = await startInstanceWithRecovery(launcher, accountId, cdpPort);
|
|
23
|
+
if (outcome.status === "timeout") {
|
|
24
|
+
process.stderr.write("Instance started but failed to initialize within timeout.\n");
|
|
25
|
+
process.exitCode = 1;
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const verb = outcome.status === "already_running"
|
|
29
|
+
? "already running"
|
|
30
|
+
: "started";
|
|
31
|
+
process.stdout.write(`Instance ${verb} for account ${String(accountId)} on CDP port ${String(outcome.port)}\n`);
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
const message = errorMessage(error);
|
|
35
|
+
process.stderr.write(`${message}\n`);
|
|
36
|
+
process.exitCode = 1;
|
|
37
|
+
}
|
|
38
|
+
finally {
|
|
39
|
+
launcher.disconnect();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=start-instance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start-instance.js","sourceRoot":"","sources":["../../src/handlers/start-instance.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,eAAe,EACf,yBAAyB,GAC1B,MAAM,gBAAgB,CAAC;AAExB,mHAAmH;AACnH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,YAAoB,EACpB,OAAsE;IAEtE,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,gBAAgB,CAAC;IACpD,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,OAAO,EAAE;QAC5C,GAAG,CAAC,OAAO,CAAC,OAAO,KAAK,SAAS,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;QAC/D,GAAG,CAAC,OAAO,CAAC,WAAW,KAAK,SAAS,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC;KAC/E,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,MAAM,QAAQ,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;QACpC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC;QACrC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,yBAAyB,CAC7C,QAAQ,EACR,SAAS,EACT,OAAO,CACR,CAAC;QAEF,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YACjC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,6DAA6D,CAC9D,CAAC;YACF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QAED,MAAM,IAAI,GACR,OAAO,CAAC,MAAM,KAAK,iBAAiB;YAClC,CAAC,CAAC,iBAAiB;YACnB,CAAC,CAAC,SAAS,CAAC;QAEhB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,YAAY,IAAI,gBAAgB,MAAM,CAAC,SAAS,CAAC,gBAAgB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAC1F,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;QACpC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC;QACrC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvB,CAAC;YAAS,CAAC;QACT,QAAQ,CAAC,UAAU,EAAE,CAAC;IACxB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start-instance.test.d.ts","sourceRoot":"","sources":["../../src/handlers/start-instance.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
4
|
+
vi.mock("@lhremote/core", async (importOriginal) => {
|
|
5
|
+
const actual = await importOriginal();
|
|
6
|
+
return {
|
|
7
|
+
...actual,
|
|
8
|
+
LauncherService: vi.fn(),
|
|
9
|
+
startInstanceWithRecovery: vi.fn(),
|
|
10
|
+
};
|
|
11
|
+
});
|
|
12
|
+
import { LauncherService, LinkedHelperNotRunningError, startInstanceWithRecovery, } from "@lhremote/core";
|
|
13
|
+
import { handleStartInstance } from "./start-instance.js";
|
|
14
|
+
import { mockLauncher } from "./testing/mock-helpers.js";
|
|
15
|
+
describe("handleStartInstance", () => {
|
|
16
|
+
const originalExitCode = process.exitCode;
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
process.exitCode = undefined;
|
|
19
|
+
vi.clearAllMocks();
|
|
20
|
+
});
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
process.exitCode = originalExitCode;
|
|
23
|
+
vi.restoreAllMocks();
|
|
24
|
+
});
|
|
25
|
+
it("prints success with port on successful start", async () => {
|
|
26
|
+
const stdoutSpy = vi
|
|
27
|
+
.spyOn(process.stdout, "write")
|
|
28
|
+
.mockReturnValue(true);
|
|
29
|
+
mockLauncher();
|
|
30
|
+
vi.mocked(startInstanceWithRecovery).mockResolvedValue({
|
|
31
|
+
status: "started",
|
|
32
|
+
port: 55123,
|
|
33
|
+
});
|
|
34
|
+
await handleStartInstance("42", {});
|
|
35
|
+
expect(stdoutSpy).toHaveBeenCalledWith("Instance started for account 42 on CDP port 55123\n");
|
|
36
|
+
expect(process.exitCode).toBeUndefined();
|
|
37
|
+
});
|
|
38
|
+
it("sets exitCode 1 on connection error", async () => {
|
|
39
|
+
const stderrSpy = vi
|
|
40
|
+
.spyOn(process.stderr, "write")
|
|
41
|
+
.mockReturnValue(true);
|
|
42
|
+
mockLauncher({
|
|
43
|
+
connect: vi
|
|
44
|
+
.fn()
|
|
45
|
+
.mockRejectedValue(new LinkedHelperNotRunningError(9222)),
|
|
46
|
+
});
|
|
47
|
+
await handleStartInstance("42", {});
|
|
48
|
+
expect(process.exitCode).toBe(1);
|
|
49
|
+
expect(stderrSpy).toHaveBeenCalledWith(expect.stringContaining("not running"));
|
|
50
|
+
});
|
|
51
|
+
it("handles idempotent 'already running' when port available", async () => {
|
|
52
|
+
const stdoutSpy = vi
|
|
53
|
+
.spyOn(process.stdout, "write")
|
|
54
|
+
.mockReturnValue(true);
|
|
55
|
+
mockLauncher();
|
|
56
|
+
vi.mocked(startInstanceWithRecovery).mockResolvedValue({
|
|
57
|
+
status: "already_running",
|
|
58
|
+
port: 55123,
|
|
59
|
+
});
|
|
60
|
+
await handleStartInstance("42", {});
|
|
61
|
+
expect(stdoutSpy).toHaveBeenCalledWith("Instance already running for account 42 on CDP port 55123\n");
|
|
62
|
+
expect(process.exitCode).toBeUndefined();
|
|
63
|
+
});
|
|
64
|
+
it("sets exitCode 1 on unexpected error", async () => {
|
|
65
|
+
const stderrSpy = vi
|
|
66
|
+
.spyOn(process.stderr, "write")
|
|
67
|
+
.mockReturnValue(true);
|
|
68
|
+
mockLauncher();
|
|
69
|
+
vi.mocked(startInstanceWithRecovery).mockRejectedValue(new Error("unexpected failure"));
|
|
70
|
+
await handleStartInstance("42", {});
|
|
71
|
+
expect(process.exitCode).toBe(1);
|
|
72
|
+
expect(stderrSpy).toHaveBeenCalledWith(expect.stringContaining("unexpected failure"));
|
|
73
|
+
});
|
|
74
|
+
it("passes cdpPort option to LauncherService", async () => {
|
|
75
|
+
vi.spyOn(process.stdout, "write").mockReturnValue(true);
|
|
76
|
+
mockLauncher();
|
|
77
|
+
vi.mocked(startInstanceWithRecovery).mockResolvedValue({
|
|
78
|
+
status: "started",
|
|
79
|
+
port: 55123,
|
|
80
|
+
});
|
|
81
|
+
await handleStartInstance("42", { cdpPort: 4567 });
|
|
82
|
+
expect(LauncherService).toHaveBeenCalledWith(4567, {});
|
|
83
|
+
});
|
|
84
|
+
it("sets exitCode 1 when instance fails to initialize within timeout", async () => {
|
|
85
|
+
const stderrSpy = vi
|
|
86
|
+
.spyOn(process.stderr, "write")
|
|
87
|
+
.mockReturnValue(true);
|
|
88
|
+
mockLauncher();
|
|
89
|
+
vi.mocked(startInstanceWithRecovery).mockResolvedValue({
|
|
90
|
+
status: "timeout",
|
|
91
|
+
});
|
|
92
|
+
await handleStartInstance("42", {});
|
|
93
|
+
expect(process.exitCode).toBe(1);
|
|
94
|
+
expect(stderrSpy).toHaveBeenCalledWith("Instance started but failed to initialize within timeout.\n");
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
//# sourceMappingURL=start-instance.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start-instance.test.js","sourceRoot":"","sources":["../../src/handlers/start-instance.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Handle the {@link https://github.com/alexey-pelykh/lhremote#account--instance | stop-instance} CLI command. */
|
|
2
|
+
export declare function handleStopInstance(accountIdArg: string, options: {
|
|
3
|
+
cdpPort?: number;
|
|
4
|
+
cdpHost?: string;
|
|
5
|
+
allowRemote?: boolean;
|
|
6
|
+
}): Promise<void>;
|
|
7
|
+
//# sourceMappingURL=stop-instance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stop-instance.d.ts","sourceRoot":"","sources":["../../src/handlers/stop-instance.ts"],"names":[],"mappings":"AAKA,kHAAkH;AAClH,wBAAsB,kBAAkB,CACtC,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,GACrE,OAAO,CAAC,IAAI,CAAC,CA6Bf"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
import { DEFAULT_CDP_PORT, errorMessage, LauncherService } from "@lhremote/core";
|
|
4
|
+
/** Handle the {@link https://github.com/alexey-pelykh/lhremote#account--instance | stop-instance} CLI command. */
|
|
5
|
+
export async function handleStopInstance(accountIdArg, options) {
|
|
6
|
+
const accountId = Number(accountIdArg);
|
|
7
|
+
const cdpPort = options.cdpPort ?? DEFAULT_CDP_PORT;
|
|
8
|
+
const launcher = new LauncherService(cdpPort, {
|
|
9
|
+
...(options.cdpHost !== undefined && { host: options.cdpHost }),
|
|
10
|
+
...(options.allowRemote !== undefined && { allowRemote: options.allowRemote }),
|
|
11
|
+
});
|
|
12
|
+
try {
|
|
13
|
+
await launcher.connect();
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
const message = errorMessage(error);
|
|
17
|
+
process.stderr.write(`${message}\n`);
|
|
18
|
+
process.exitCode = 1;
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
await launcher.stopInstance(accountId);
|
|
23
|
+
process.stdout.write(`Instance stopped for account ${String(accountId)}\n`);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
const message = errorMessage(error);
|
|
27
|
+
process.stderr.write(`${message}\n`);
|
|
28
|
+
process.exitCode = 1;
|
|
29
|
+
}
|
|
30
|
+
finally {
|
|
31
|
+
launcher.disconnect();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=stop-instance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stop-instance.js","sourceRoot":"","sources":["../../src/handlers/stop-instance.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjF,kHAAkH;AAClH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,YAAoB,EACpB,OAAsE;IAEtE,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,gBAAgB,CAAC;IACpD,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,OAAO,EAAE;QAC5C,GAAG,CAAC,OAAO,CAAC,OAAO,KAAK,SAAS,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;QAC/D,GAAG,CAAC,OAAO,CAAC,WAAW,KAAK,SAAS,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC;KAC/E,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,MAAM,QAAQ,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;QACpC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC;QACrC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,IAAI,CAAC;QACH,MAAM,QAAQ,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;QACvC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,gCAAgC,MAAM,CAAC,SAAS,CAAC,IAAI,CACtD,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;QACpC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC;QACrC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvB,CAAC;YAAS,CAAC;QACT,QAAQ,CAAC,UAAU,EAAE,CAAC;IACxB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stop-instance.test.d.ts","sourceRoot":"","sources":["../../src/handlers/stop-instance.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
4
|
+
vi.mock("@lhremote/core", async (importOriginal) => {
|
|
5
|
+
const actual = await importOriginal();
|
|
6
|
+
return {
|
|
7
|
+
...actual,
|
|
8
|
+
LauncherService: vi.fn(),
|
|
9
|
+
};
|
|
10
|
+
});
|
|
11
|
+
import { LauncherService, LinkedHelperNotRunningError, } from "@lhremote/core";
|
|
12
|
+
import { handleStopInstance } from "./stop-instance.js";
|
|
13
|
+
import { mockLauncher } from "./testing/mock-helpers.js";
|
|
14
|
+
describe("handleStopInstance", () => {
|
|
15
|
+
const originalExitCode = process.exitCode;
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
process.exitCode = undefined;
|
|
18
|
+
vi.clearAllMocks();
|
|
19
|
+
});
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
process.exitCode = originalExitCode;
|
|
22
|
+
vi.restoreAllMocks();
|
|
23
|
+
});
|
|
24
|
+
it("prints success on successful stop", async () => {
|
|
25
|
+
const stdoutSpy = vi
|
|
26
|
+
.spyOn(process.stdout, "write")
|
|
27
|
+
.mockReturnValue(true);
|
|
28
|
+
mockLauncher({ stopInstance: vi.fn().mockResolvedValue(undefined) });
|
|
29
|
+
await handleStopInstance("42", {});
|
|
30
|
+
expect(stdoutSpy).toHaveBeenCalledWith("Instance stopped for account 42\n");
|
|
31
|
+
expect(process.exitCode).toBeUndefined();
|
|
32
|
+
});
|
|
33
|
+
it("sets exitCode 1 on connection error", async () => {
|
|
34
|
+
const stderrSpy = vi
|
|
35
|
+
.spyOn(process.stderr, "write")
|
|
36
|
+
.mockReturnValue(true);
|
|
37
|
+
mockLauncher({
|
|
38
|
+
connect: vi
|
|
39
|
+
.fn()
|
|
40
|
+
.mockRejectedValue(new LinkedHelperNotRunningError(9222)),
|
|
41
|
+
});
|
|
42
|
+
await handleStopInstance("42", {});
|
|
43
|
+
expect(process.exitCode).toBe(1);
|
|
44
|
+
expect(stderrSpy).toHaveBeenCalledWith(expect.stringContaining("not running"));
|
|
45
|
+
});
|
|
46
|
+
it("sets exitCode 1 on unexpected error", async () => {
|
|
47
|
+
const stderrSpy = vi
|
|
48
|
+
.spyOn(process.stderr, "write")
|
|
49
|
+
.mockReturnValue(true);
|
|
50
|
+
mockLauncher({
|
|
51
|
+
stopInstance: vi
|
|
52
|
+
.fn()
|
|
53
|
+
.mockRejectedValue(new Error("unexpected failure")),
|
|
54
|
+
});
|
|
55
|
+
await handleStopInstance("42", {});
|
|
56
|
+
expect(process.exitCode).toBe(1);
|
|
57
|
+
expect(stderrSpy).toHaveBeenCalledWith("unexpected failure\n");
|
|
58
|
+
});
|
|
59
|
+
it("passes cdpPort option to LauncherService", async () => {
|
|
60
|
+
vi.spyOn(process.stdout, "write").mockReturnValue(true);
|
|
61
|
+
mockLauncher({ stopInstance: vi.fn().mockResolvedValue(undefined) });
|
|
62
|
+
await handleStopInstance("42", { cdpPort: 4567 });
|
|
63
|
+
expect(LauncherService).toHaveBeenCalledWith(4567, {});
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
//# sourceMappingURL=stop-instance.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stop-instance.test.js","sourceRoot":"","sources":["../../src/handlers/stop-instance.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Mock } from "vitest";
|
|
2
|
+
import { vi } from "vitest";
|
|
3
|
+
import type { LauncherService } from "@lhremote/core";
|
|
4
|
+
/**
|
|
5
|
+
* Collect all captured stdout output from a `process.stdout.write` spy.
|
|
6
|
+
*/
|
|
7
|
+
export declare function getStdout(spy: Mock): string;
|
|
8
|
+
/**
|
|
9
|
+
* Collect all captured stderr output from a `process.stderr.write` spy.
|
|
10
|
+
*/
|
|
11
|
+
export declare function getStderr(spy: Mock): string;
|
|
12
|
+
/**
|
|
13
|
+
* Mock {@link LauncherService} with optional method overrides.
|
|
14
|
+
*
|
|
15
|
+
* Returns the `disconnect` spy so callers can assert cleanup.
|
|
16
|
+
*/
|
|
17
|
+
export declare function mockLauncher(overrides?: Partial<LauncherService>): {
|
|
18
|
+
disconnect: ReturnType<typeof vi.fn>;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Mock {@link DatabaseClient} with a no-op `close` and empty `db`.
|
|
22
|
+
*
|
|
23
|
+
* Returns the `close` spy so callers can assert cleanup.
|
|
24
|
+
*/
|
|
25
|
+
export declare function mockDb(): {
|
|
26
|
+
close: ReturnType<typeof vi.fn>;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Mock {@link discoverAllDatabases} to return the given map.
|
|
30
|
+
*
|
|
31
|
+
* Defaults to a single account at id 1.
|
|
32
|
+
*/
|
|
33
|
+
export declare function mockDiscovery(databases?: Map<number, string>): void;
|
|
34
|
+
/**
|
|
35
|
+
* Mock {@link resolveAccount} to return the given account id.
|
|
36
|
+
*/
|
|
37
|
+
export declare function mockResolveAccount(accountId?: number): void;
|
|
38
|
+
/**
|
|
39
|
+
* Mock {@link withInstanceDatabase} so the callback receives a
|
|
40
|
+
* synthetic {@link InstanceDatabaseContext}.
|
|
41
|
+
*
|
|
42
|
+
* Returns the `executeAction` spy from the mock instance.
|
|
43
|
+
*/
|
|
44
|
+
export declare function mockWithInstanceDatabase(): {
|
|
45
|
+
executeAction: ReturnType<typeof vi.fn>;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Mock {@link withDatabase} so the callback receives a
|
|
49
|
+
* synthetic {@link DatabaseContext}.
|
|
50
|
+
*
|
|
51
|
+
* Returns a mock `db` object for further stubbing.
|
|
52
|
+
*/
|
|
53
|
+
export declare function mockWithDatabase(): {
|
|
54
|
+
db: Record<string, unknown>;
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=mock-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-helpers.d.ts","sourceRoot":"","sources":["../../../src/handlers/testing/mock-helpers.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE5B,OAAO,KAAK,EAIV,eAAe,EAChB,MAAM,gBAAgB,CAAC;AAUxB;;GAEG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,IAAI,GAAG,MAAM,CAE3C;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,IAAI,GAAG,MAAM,CAE3C;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,SAAS,GAAE,OAAO,CAAC,eAAe,CAAM,GACvC;IAAE,UAAU,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAA;CAAE,CAW1C;AAED;;;;GAIG;AACH,wBAAgB,MAAM,IAAI;IAAE,KAAK,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAA;CAAE,CAM5D;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,SAAS,GAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAiC,GAC7D,IAAI,CAEN;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,SAAI,GAAG,IAAI,CAEtD;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,IAAI;IAC1C,aAAa,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;CACzC,CAcA;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,IAAI;IAAE,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAWlE"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
import { vi } from "vitest";
|
|
4
|
+
import { DatabaseClient as DatabaseClientCtor, LauncherService as LauncherServiceCtor, discoverAllDatabases, resolveAccount, withDatabase, withInstanceDatabase, } from "@lhremote/core";
|
|
5
|
+
/**
|
|
6
|
+
* Collect all captured stdout output from a `process.stdout.write` spy.
|
|
7
|
+
*/
|
|
8
|
+
export function getStdout(spy) {
|
|
9
|
+
return spy.mock.calls.map((call) => String(call[0])).join("");
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Collect all captured stderr output from a `process.stderr.write` spy.
|
|
13
|
+
*/
|
|
14
|
+
export function getStderr(spy) {
|
|
15
|
+
return spy.mock.calls.map((call) => String(call[0])).join("");
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Mock {@link LauncherService} with optional method overrides.
|
|
19
|
+
*
|
|
20
|
+
* Returns the `disconnect` spy so callers can assert cleanup.
|
|
21
|
+
*/
|
|
22
|
+
export function mockLauncher(overrides = {}) {
|
|
23
|
+
const disconnect = vi.fn();
|
|
24
|
+
vi.mocked(LauncherServiceCtor).mockImplementation(function () {
|
|
25
|
+
return {
|
|
26
|
+
connect: vi.fn().mockResolvedValue(undefined),
|
|
27
|
+
disconnect,
|
|
28
|
+
listAccounts: vi.fn().mockResolvedValue([]),
|
|
29
|
+
...overrides,
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
return { disconnect };
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Mock {@link DatabaseClient} with a no-op `close` and empty `db`.
|
|
36
|
+
*
|
|
37
|
+
* Returns the `close` spy so callers can assert cleanup.
|
|
38
|
+
*/
|
|
39
|
+
export function mockDb() {
|
|
40
|
+
const close = vi.fn();
|
|
41
|
+
vi.mocked(DatabaseClientCtor).mockImplementation(function () {
|
|
42
|
+
return { close, db: {} };
|
|
43
|
+
});
|
|
44
|
+
return { close };
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Mock {@link discoverAllDatabases} to return the given map.
|
|
48
|
+
*
|
|
49
|
+
* Defaults to a single account at id 1.
|
|
50
|
+
*/
|
|
51
|
+
export function mockDiscovery(databases = new Map([[1, "/path/to/db"]])) {
|
|
52
|
+
vi.mocked(discoverAllDatabases).mockReturnValue(databases);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Mock {@link resolveAccount} to return the given account id.
|
|
56
|
+
*/
|
|
57
|
+
export function mockResolveAccount(accountId = 1) {
|
|
58
|
+
vi.mocked(resolveAccount).mockResolvedValue(accountId);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Mock {@link withInstanceDatabase} so the callback receives a
|
|
62
|
+
* synthetic {@link InstanceDatabaseContext}.
|
|
63
|
+
*
|
|
64
|
+
* Returns the `executeAction` spy from the mock instance.
|
|
65
|
+
*/
|
|
66
|
+
export function mockWithInstanceDatabase() {
|
|
67
|
+
const executeAction = vi.fn().mockResolvedValue(undefined);
|
|
68
|
+
vi.mocked(withInstanceDatabase).mockImplementation(async (_cdpPort, _accountId, callback) => {
|
|
69
|
+
const mockInstance = { executeAction };
|
|
70
|
+
const mockDbObj = {};
|
|
71
|
+
return callback({
|
|
72
|
+
accountId: _accountId,
|
|
73
|
+
instance: mockInstance,
|
|
74
|
+
db: mockDbObj,
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
return { executeAction };
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Mock {@link withDatabase} so the callback receives a
|
|
81
|
+
* synthetic {@link DatabaseContext}.
|
|
82
|
+
*
|
|
83
|
+
* Returns a mock `db` object for further stubbing.
|
|
84
|
+
*/
|
|
85
|
+
export function mockWithDatabase() {
|
|
86
|
+
const db = {};
|
|
87
|
+
vi.mocked(withDatabase).mockImplementation(async (_accountId, callback) => {
|
|
88
|
+
return callback({
|
|
89
|
+
accountId: _accountId,
|
|
90
|
+
db,
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
return { db };
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=mock-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-helpers.js","sourceRoot":"","sources":["../../../src/handlers/testing/mock-helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,OAAO,EAAgC,MAAM,WAAW,CAAC;AAuElE;;GAEG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAgXvC"}
|