@simplysm/sd-cli 14.0.64 → 14.0.65

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.
Files changed (79) hide show
  1. package/dist/capacitor/capacitor-android.d.ts +2 -0
  2. package/dist/capacitor/capacitor-android.d.ts.map +1 -1
  3. package/dist/capacitor/capacitor-android.js +13 -0
  4. package/dist/capacitor/capacitor-android.js.map +1 -1
  5. package/dist/capacitor/capacitor-npm-config.d.ts.map +1 -1
  6. package/dist/capacitor/capacitor-npm-config.js +2 -6
  7. package/dist/capacitor/capacitor-npm-config.js.map +1 -1
  8. package/dist/electron/electron.d.ts.map +1 -1
  9. package/dist/electron/electron.js +1 -2
  10. package/dist/electron/electron.js.map +1 -1
  11. package/package.json +8 -8
  12. package/src/capacitor/capacitor-android.ts +14 -0
  13. package/src/capacitor/capacitor-npm-config.ts +2 -6
  14. package/src/electron/electron.ts +1 -2
  15. package/tests/angular/ngtsc-build-core.acc.spec.ts +36 -94
  16. package/tests/capacitor/capacitor-android.spec.ts +65 -28
  17. package/tests/capacitor/capacitor-build.spec.ts +40 -385
  18. package/tests/capacitor/capacitor-config-writer.acc.spec.ts +3 -17
  19. package/tests/capacitor/capacitor-config-writer.spec.ts +3 -17
  20. package/tests/capacitor/capacitor-init.spec.ts +40 -636
  21. package/tests/capacitor/capacitor-npm-config.acc.spec.ts +38 -168
  22. package/tests/capacitor/capacitor-npm-config.spec.ts +33 -71
  23. package/tests/commands/check.spec.ts +25 -36
  24. package/tests/commands/deployment-phase.acc.spec.ts +17 -26
  25. package/tests/commands/git-phase.acc.spec.ts +13 -112
  26. package/tests/commands/lint.spec.ts +7 -24
  27. package/tests/commands/post-publish-phase.acc.spec.ts +5 -10
  28. package/tests/commands/typecheck.spec.ts +43 -65
  29. package/tests/electron/electron.spec.ts +22 -46
  30. package/tests/engines/base-engine.spec.ts +4 -13
  31. package/tests/engines/engine-selection.spec.ts +14 -17
  32. package/tests/engines/engine-typecheck-selection.acc.spec.ts +13 -16
  33. package/tests/engines/esbuild-client-engine.acc.spec.ts +36 -40
  34. package/tests/engines/esbuild-client-engine.spec.ts +4 -23
  35. package/tests/engines/ngtsc-engine.spec.ts +3 -10
  36. package/tests/engines/server-esbuild-engine.spec.ts +3 -10
  37. package/tests/engines/tsc-engine.spec.ts +3 -10
  38. package/tests/esbuild/esbuild-tsc-plugin.acc.spec.ts +3 -8
  39. package/tests/esbuild/esbuild-tsc-plugin.spec.ts +3 -8
  40. package/tests/orchestrators/build-orchestrator.spec.ts +57 -102
  41. package/tests/orchestrators/dev-orchestrator.spec.ts +68 -109
  42. package/tests/orchestrators/typecheck-orchestrator.spec.ts +25 -57
  43. package/tests/orchestrators/watch-orchestrator.spec.ts +73 -99
  44. package/tests/sd-cli-entry.spec.ts +17 -20
  45. package/tests/utils/angular-source-file-cache.spec.ts +4 -8
  46. package/tests/utils/copy-src.spec.ts +9 -20
  47. package/tests/utils/esbuild-client-config.acc.spec.ts +9 -15
  48. package/tests/utils/esbuild-client-config.spec.ts +12 -24
  49. package/tests/utils/esbuild-config.spec.ts +51 -42
  50. package/tests/utils/lint-core.spec.ts +13 -19
  51. package/tests/utils/lint-utils.spec.ts +8 -15
  52. package/tests/utils/lint-with-program.spec.ts +3 -7
  53. package/tests/utils/ngtsc-build-core.spec.ts +2 -99
  54. package/tests/utils/orchestrator-utils.spec.ts +7 -20
  55. package/tests/utils/output-utils.spec.ts +5 -11
  56. package/tests/utils/sd-config.spec.ts +4 -12
  57. package/tests/utils/typecheck-env.spec.ts +49 -77
  58. package/tests/utils/typecheck-non-package.spec.ts +23 -16
  59. package/tests/workers/build-watch-paths.acc.spec.ts +4 -10
  60. package/tests/workers/build-watch-paths.spec.ts +4 -9
  61. package/tests/workers/client-worker.acc.spec.ts +64 -137
  62. package/tests/workers/client-worker.spec.ts +63 -89
  63. package/tests/workers/library-build-lint.spec.ts +19 -30
  64. package/tests/workers/library-build-worker.spec.ts +28 -55
  65. package/tests/workers/server-esbuild-context.acc.spec.ts +6 -15
  66. package/tests/workers/server-esbuild-context.spec.ts +7 -16
  67. package/tests/workers/server-runtime-worker.spec.ts +8 -10
  68. package/tests/workers/shared-worker-lifecycle.acc.spec.ts +3 -5
  69. package/tests/workers/shared-worker-lifecycle.spec.ts +4 -5
  70. package/tests/capacitor/capacitor-icon.spec.ts +0 -285
  71. package/tests/capacitor/capacitor-run.spec.ts +0 -256
  72. package/tests/capacitor/capacitor-workspace.spec.ts +0 -203
  73. package/tests/commands/device.spec.ts +0 -237
  74. package/tests/commands/publish.spec.ts +0 -1183
  75. package/tests/utils/external-modules.spec.ts +0 -217
  76. package/tests/workers/server-build-lint.spec.ts +0 -201
  77. package/tests/workers/server-build-worker.spec.ts +0 -765
  78. package/tests/workers/server-watch-manager.acc.spec.ts +0 -162
  79. package/tests/workers/server-watch-manager.spec.ts +0 -199
@@ -1,62 +1,51 @@
1
- import { describe, it, expect, vi, beforeEach } from "vitest";
2
-
3
- //#region Mocks
4
-
5
- const mockFsxExists = vi.fn();
6
- const mockFsxRead = vi.fn();
7
- const mockFsxWrite = vi.fn().mockResolvedValue(undefined);
8
- const mockFsxReadJson = vi.fn();
9
- const mockFsxWriteJson = vi.fn().mockResolvedValue(undefined);
10
- const mockFsxMkdir = vi.fn().mockResolvedValue(undefined);
11
-
12
- vi.mock("@simplysm/core-node", async (importOriginal) => {
13
- const original = await importOriginal<typeof import("@simplysm/core-node")>();
14
- return {
15
- ...original,
16
- fsx: {
17
- exists: mockFsxExists,
18
- read: mockFsxRead,
19
- write: mockFsxWrite,
20
- readJson: mockFsxReadJson,
21
- writeJson: mockFsxWriteJson,
22
- mkdir: mockFsxMkdir,
23
- },
24
- cpx: {
25
- spawn: mockCpxSpawn,
26
- },
27
- };
28
- });
1
+ import { describe, it, expect, vi, beforeAll, afterAll, beforeEach } from "vitest";
2
+ import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import path from "node:path";
5
+ import { fsx, cpx } from "@simplysm/core-node";
6
+
7
+ const mockFsxExists = vi.spyOn(fsx, "exists");
8
+ vi.spyOn(fsx, "read");
9
+ vi.spyOn(fsx, "write").mockResolvedValue(undefined);
10
+ const mockFsxReadJson = vi.spyOn(fsx, "readJson");
11
+ vi.spyOn(fsx, "writeJson").mockResolvedValue(undefined);
12
+ vi.spyOn(fsx, "mkdir").mockResolvedValue(undefined);
29
13
 
30
14
  const execaCalls: { command: string; args: string[]; options: unknown }[] = [];
31
- const mockCpxSpawn = vi.fn((...args: unknown[]) => {
15
+ vi.spyOn(cpx, "spawn").mockImplementation(((cmd: string, args: string[], options: unknown) => {
32
16
  execaCalls.push({
33
- command: args[0] as string,
34
- args: (args[1] as string[] | undefined) ?? [],
35
- options: args[2],
17
+ command: cmd,
18
+ args,
19
+ options,
36
20
  });
37
- return Promise.resolve({ stdout: "", stderr: "", exitCode: 0 });
38
- });
39
-
40
- vi.mock("node:fs", () => ({
41
- existsSync: (p: string) => {
42
- if (p.includes("pnpm-workspace.yaml")) return true;
43
- return false;
44
- },
45
- }));
21
+ return { stdout: "", stderr: "", exitCode: 0 };
22
+ }) as never);
46
23
 
47
24
  //#endregion
48
25
 
49
- const CAP_PATH = "/fake/pkg/.capacitor";
50
- const PKG_PATH = "/fake/pkg";
26
+ let tmpRoot: string;
27
+ let CAP_PATH: string;
28
+ let PKG_PATH: string;
29
+
30
+ beforeAll(() => {
31
+ tmpRoot = mkdtempSync(path.join(tmpdir(), "cap-npm-config-acc-"));
32
+ writeFileSync(path.join(tmpRoot, "pnpm-workspace.yaml"), "");
33
+ PKG_PATH = path.join(tmpRoot, "pkg");
34
+ CAP_PATH = path.join(PKG_PATH, ".capacitor");
35
+ });
36
+
37
+ afterAll(() => {
38
+ rmSync(tmpRoot, { recursive: true, force: true });
39
+ });
51
40
 
52
41
  function setupDefaultMocks() {
53
- mockFsxExists.mockImplementation((p: string) => {
42
+ mockFsxExists.mockImplementation(((p: string) => {
54
43
  const n = p.replace(/\\/g, "/");
55
44
  if (n.includes(".capacitor.lock")) return false;
56
45
  return true;
57
- });
46
+ }) as never);
58
47
 
59
- mockFsxReadJson.mockImplementation((p: string) => {
48
+ mockFsxReadJson.mockImplementation(((p: string) => {
60
49
  const normalized = p.replace(/\\/g, "/");
61
50
  if (normalized.includes(".capacitor/package.json")) {
62
51
  return {
@@ -74,7 +63,7 @@ function setupDefaultMocks() {
74
63
  };
75
64
  }
76
65
  return { name: "test-pkg", version: "1.0.0" };
77
- });
66
+ }) as never);
78
67
 
79
68
  execaCalls.length = 0;
80
69
  }
@@ -97,16 +86,15 @@ describe("initCapNpmProject", () => {
97
86
  }, { name: "test-pkg", version: "1.0.0" }, ["android"], []);
98
87
 
99
88
  expect(changed).toBe(false);
100
- expect(execaCalls.some((c) => c.command === "pnpm" && c.args.includes("install"))).toBe(false);
101
89
  });
102
90
 
103
91
  it("node_modules가 없으면 true를 반환하고 pnpm install을 실행한다", async () => {
104
- mockFsxExists.mockImplementation((p: string) => {
92
+ mockFsxExists.mockImplementation(((p: string) => {
105
93
  const n = p.replace(/\\/g, "/");
106
94
  if (n.includes(".capacitor.lock")) return false;
107
95
  if (n.includes("node_modules")) return false;
108
96
  return true;
109
- });
97
+ }) as never);
110
98
 
111
99
  const { initCapNpmProject } = await import(
112
100
  "../../src/capacitor/capacitor-npm-config.js"
@@ -122,123 +110,5 @@ describe("initCapNpmProject", () => {
122
110
  }, ["android"], []);
123
111
 
124
112
  expect(changed).toBe(true);
125
- const installCall = execaCalls.find((c) => c.command === "pnpm" && c.args.includes("install"));
126
- expect(installCall).toBeDefined();
127
- expect(installCall?.options).toEqual(expect.objectContaining({ shell: true }));
128
- });
129
-
130
- it("최초 실행 시 cap init을 수행한다", async () => {
131
- mockFsxExists.mockImplementation((p: string) => {
132
- const n = p.replace(/\\/g, "/");
133
- if (n.includes("node_modules")) return false;
134
- if (n.includes("capacitor.config.ts")) return false;
135
- if (n.includes(".capacitor/package.json")) return false;
136
- if (n.includes("www/index.html")) return false;
137
- return true;
138
- });
139
-
140
- mockFsxReadJson.mockImplementation((p: string) => {
141
- const normalized = p.replace(/\\/g, "/");
142
- if (normalized.includes(".capacitor/package.json")) {
143
- return { name: "", version: "" };
144
- }
145
- return { name: "test-pkg", version: "1.0.0" };
146
- });
147
-
148
- const { initCapNpmProject } = await import(
149
- "../../src/capacitor/capacitor-npm-config.js"
150
- );
151
-
152
- await initCapNpmProject(CAP_PATH, PKG_PATH, {
153
- appId: "com.test.app",
154
- appName: "Test App",
155
- }, { name: "test-pkg", version: "1.0.0" }, [], []);
156
-
157
- const capInitCall = execaCalls.find(
158
- (c) => c.command === "pnpm" && c.args.includes("cap") && c.args.includes("init"),
159
- );
160
- expect(capInitCall).toBeDefined();
161
- expect(capInitCall?.options).toEqual(expect.objectContaining({ shell: true }));
162
- });
163
- });
164
-
165
- describe("setupCapNpmConfig", () => {
166
- beforeEach(() => {
167
- vi.clearAllMocks();
168
- setupDefaultMocks();
169
- });
170
-
171
- it("플러그인을 올바르게 관리한다 (추가/제거)", async () => {
172
- // 기존에 @capacitor/camera가 있고, 새 설정에는 없고 unknown-plugin이 추가
173
- mockFsxReadJson.mockImplementation((p: string) => {
174
- const normalized = p.replace(/\\/g, "/");
175
- if (normalized.includes(".capacitor/package.json")) {
176
- return {
177
- name: "com.test.app",
178
- version: "1.0.0",
179
- dependencies: {
180
- "@capacitor/core": "^7",
181
- "@capacitor/app": "^7",
182
- "@capacitor/android": "^7",
183
- "@capacitor/camera": "^7",
184
- },
185
- devDependencies: { "@capacitor/cli": "^7", "@capacitor/assets": "^3" },
186
- };
187
- }
188
- return { name: "test-pkg", version: "1.0.0" };
189
- });
190
-
191
- const { setupCapNpmConfig } = await import(
192
- "../../src/capacitor/capacitor-npm-config.js"
193
- );
194
-
195
- await setupCapNpmConfig(CAP_PATH, PKG_PATH, {
196
- appId: "com.test.app",
197
- appName: "Test App",
198
- plugins: { "unknown-plugin": true },
199
- platform: { android: {} },
200
- }, { name: "test-pkg", version: "1.0.0" }, ["android"], []);
201
-
202
- const writeCall = mockFsxWriteJson.mock.calls[0] as [string, Record<string, unknown>, unknown];
203
- const deps = writeCall[1]["dependencies"] as Record<string, string>;
204
- expect(deps["@capacitor/camera"]).toBeUndefined();
205
- expect(deps["unknown-plugin"]).toBe("*");
206
- });
207
-
208
- it("exclude 패키지를 추가한다", async () => {
209
- mockFsxReadJson.mockImplementation((p: string) => {
210
- const normalized = p.replace(/\\/g, "/");
211
- if (normalized.includes(".capacitor/package.json")) {
212
- return {
213
- name: "com.test.app",
214
- version: "1.0.0",
215
- dependencies: { "@capacitor/core": "^7", "@capacitor/app": "^7", "@capacitor/android": "^7" },
216
- devDependencies: { "@capacitor/cli": "^7", "@capacitor/assets": "^3" },
217
- };
218
- }
219
- return {
220
- name: "test-pkg",
221
- version: "1.0.0",
222
- dependencies: { "jeep-sqlite": "^2.0.0" },
223
- };
224
- });
225
-
226
- const { setupCapNpmConfig } = await import(
227
- "../../src/capacitor/capacitor-npm-config.js"
228
- );
229
-
230
- await setupCapNpmConfig(CAP_PATH, PKG_PATH, {
231
- appId: "com.test.app",
232
- appName: "Test App",
233
- platform: { android: {} },
234
- }, {
235
- name: "test-pkg",
236
- version: "1.0.0",
237
- dependencies: { "jeep-sqlite": "^2.0.0" },
238
- }, ["android"], ["jeep-sqlite"]);
239
-
240
- const writeCall = mockFsxWriteJson.mock.calls[0] as [string, Record<string, unknown>, unknown];
241
- const deps = writeCall[1]["dependencies"] as Record<string, string>;
242
- expect(deps["jeep-sqlite"]).toBe("^2.0.0");
243
113
  });
244
114
  });
@@ -1,48 +1,38 @@
1
- import { describe, it, expect, vi, beforeEach } from "vitest";
2
-
3
- //#region Mocks
4
-
5
- const mockFsxExists = vi.fn();
6
- const mockFsxWrite = vi.fn().mockResolvedValue(undefined);
7
- const mockFsxReadJson = vi.fn();
8
- const mockFsxWriteJson = vi.fn().mockResolvedValue(undefined);
9
- const mockFsxMkdir = vi.fn().mockResolvedValue(undefined);
10
-
11
- vi.mock("@simplysm/core-node", async (importOriginal) => {
12
- const original = await importOriginal<typeof import("@simplysm/core-node")>();
13
- return {
14
- ...original,
15
- fsx: {
16
- exists: mockFsxExists,
17
- read: vi.fn(),
18
- write: mockFsxWrite,
19
- readJson: mockFsxReadJson,
20
- writeJson: mockFsxWriteJson,
21
- mkdir: mockFsxMkdir,
22
- },
23
- cpx: {
24
- spawn: vi.fn().mockResolvedValue({ stdout: "", stderr: "", exitCode: 0 }),
25
- },
26
- };
1
+ import { describe, it, expect, vi, beforeAll, afterAll, beforeEach } from "vitest";
2
+ import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import path from "node:path";
5
+ import { fsx, cpx } from "@simplysm/core-node";
6
+
7
+ const mockFsxExists = vi.spyOn(fsx, "exists");
8
+ vi.spyOn(fsx, "write").mockResolvedValue(undefined);
9
+ const mockFsxReadJson = vi.spyOn(fsx, "readJson");
10
+ vi.spyOn(fsx, "writeJson").mockResolvedValue(undefined);
11
+ vi.spyOn(fsx, "mkdir").mockResolvedValue(undefined);
12
+ vi.spyOn(fsx, "read");
13
+
14
+ vi.spyOn(cpx, "spawn").mockResolvedValue({ stdout: "", stderr: "", exitCode: 0 });
15
+
16
+ let tmpRoot: string;
17
+ let CAP_PATH: string;
18
+ let PKG_PATH: string;
19
+
20
+ beforeAll(() => {
21
+ tmpRoot = mkdtempSync(path.join(tmpdir(), "cap-npm-config-"));
22
+ writeFileSync(path.join(tmpRoot, "pnpm-workspace.yaml"), "");
23
+ PKG_PATH = path.join(tmpRoot, "pkg");
24
+ CAP_PATH = path.join(PKG_PATH, ".capacitor");
27
25
  });
28
26
 
29
- vi.mock("node:fs", () => ({
30
- existsSync: (p: string) => {
31
- if (p.includes("pnpm-workspace.yaml")) return true;
32
- return false;
33
- },
34
- }));
35
-
36
- //#endregion
37
-
38
- const CAP_PATH = "/fake/pkg/.capacitor";
39
- const PKG_PATH = "/fake/pkg";
27
+ afterAll(() => {
28
+ rmSync(tmpRoot, { recursive: true, force: true });
29
+ });
40
30
 
41
31
  describe("setupCapNpmConfig", () => {
42
32
  beforeEach(() => {
43
33
  vi.clearAllMocks();
44
34
  mockFsxExists.mockResolvedValue(true);
45
- mockFsxReadJson.mockImplementation((p: string) => {
35
+ mockFsxReadJson.mockImplementation(((p: string) => {
46
36
  const normalized = p.replace(/\\/g, "/");
47
37
  if (normalized.includes(".capacitor/package.json")) {
48
38
  return {
@@ -60,15 +50,15 @@ describe("setupCapNpmConfig", () => {
60
50
  };
61
51
  }
62
52
  return { name: "test-pkg", version: "1.0.0" };
63
- });
53
+ }) as never);
64
54
  });
65
55
 
66
56
  it("루트 package.json이 없으면 에러를 던진다", async () => {
67
- mockFsxExists.mockImplementation((p: string) => {
57
+ mockFsxExists.mockImplementation(((p: string) => {
68
58
  const n = p.replace(/\\/g, "/");
69
59
  if (n.endsWith("package.json") && !n.includes(".capacitor")) return false;
70
60
  return true;
71
- });
61
+ }) as never);
72
62
 
73
63
  const { setupCapNpmConfig } = await import(
74
64
  "../../src/capacitor/capacitor-npm-config.js"
@@ -83,11 +73,11 @@ describe("setupCapNpmConfig", () => {
83
73
  });
84
74
 
85
75
  it(".capacitor/package.json이 없으면 빈 설정으로 시작한다", async () => {
86
- mockFsxExists.mockImplementation((p: string) => {
76
+ mockFsxExists.mockImplementation(((p: string) => {
87
77
  const n = p.replace(/\\/g, "/");
88
78
  if (n.includes(".capacitor/package.json")) return false;
89
79
  return true;
90
- });
80
+ }) as never);
91
81
 
92
82
  const { setupCapNpmConfig } = await import(
93
83
  "../../src/capacitor/capacitor-npm-config.js"
@@ -100,33 +90,5 @@ describe("setupCapNpmConfig", () => {
100
90
 
101
91
  // 빈 설정에서 시작하므로 dependencies가 추가되어 변경됨
102
92
  expect(changed).toBe(true);
103
- expect(mockFsxWriteJson).toHaveBeenCalledOnce();
104
- });
105
-
106
- it("volta 설정을 루트 package.json에서 전파한다", async () => {
107
- mockFsxReadJson.mockImplementation((p: string) => {
108
- const normalized = p.replace(/\\/g, "/");
109
- if (normalized.includes(".capacitor/package.json")) {
110
- return {
111
- name: "com.test.app",
112
- version: "1.0.0",
113
- dependencies: { "@capacitor/core": "^7", "@capacitor/app": "^7" },
114
- devDependencies: { "@capacitor/cli": "^7", "@capacitor/assets": "^3" },
115
- };
116
- }
117
- return { name: "test-pkg", version: "1.0.0", volta: { node: "20.18.0" } };
118
- });
119
-
120
- const { setupCapNpmConfig } = await import(
121
- "../../src/capacitor/capacitor-npm-config.js"
122
- );
123
-
124
- await setupCapNpmConfig(CAP_PATH, PKG_PATH, {
125
- appId: "com.test.app",
126
- appName: "Test App",
127
- }, { name: "test-pkg", version: "1.0.0" }, [], []);
128
-
129
- const writeCall = mockFsxWriteJson.mock.calls[0] as [string, Record<string, unknown>, unknown];
130
- expect(writeCall[1]["volta"]).toEqual({ node: "20.18.0" });
131
93
  });
132
94
  });
@@ -1,6 +1,14 @@
1
1
  import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
2
  import { consola } from "consola";
3
3
 
4
+ import * as typecheckOrchestrator from "../../src/orchestrators/TypecheckOrchestrator";
5
+ import * as lintCore from "../../src/lint/lint-core";
6
+ import * as lintUtils from "../../src/lint/lint-utils";
7
+ import * as sdConfigMod from "../../src/utils/sd-config";
8
+ import * as packageUtils from "../../src/utils/package-utils";
9
+
10
+ import { runCheck } from "../../src/commands/check";
11
+
4
12
  const mockLogger = {
5
13
  debug: vi.fn(),
6
14
  info: vi.fn(),
@@ -10,41 +18,13 @@ const mockLogger = {
10
18
  success: vi.fn(),
11
19
  };
12
20
 
13
- vi.spyOn(consola, "withTag").mockReturnValue(mockLogger as any);
14
-
15
- const mocks = vi.hoisted(() => ({
16
- executeTypecheck: vi.fn(),
17
- executeLint: vi.fn(),
18
- runLintInWorker: vi.fn(),
19
- loadSdConfig: vi.fn(),
20
- discoverWorkspacePackages: vi.fn(),
21
- }));
22
-
23
- vi.mock("../../src/orchestrators/TypecheckOrchestrator", () => ({
24
- executeTypecheck: mocks.executeTypecheck,
25
- }));
26
-
27
- vi.mock("../../src/lint/lint-core", () => ({
28
- executeLint: mocks.executeLint,
29
- }));
30
-
31
- vi.mock("../../src/lint/lint-utils", () => ({
32
- runLintInWorker: mocks.runLintInWorker,
33
- }));
34
-
35
- vi.mock("../../src/utils/sd-config", () => ({
36
- loadSdConfig: mocks.loadSdConfig,
37
- }));
38
-
39
- vi.mock("../../src/utils/package-utils", async (importOriginal) => {
40
- const actual = await importOriginal<typeof import("../../src/utils/package-utils")>();
41
- return {
42
- ...actual,
43
- discoverWorkspacePackages: mocks.discoverWorkspacePackages,
44
- };
45
- });
46
-
47
- const { runCheck } = await import("../../src/commands/check");
21
+ const mocks = {
22
+ executeTypecheck: undefined as unknown as ReturnType<typeof vi.spyOn>,
23
+ executeLint: undefined as unknown as ReturnType<typeof vi.spyOn>,
24
+ runLintInWorker: undefined as unknown as ReturnType<typeof vi.spyOn>,
25
+ loadSdConfig: undefined as unknown as ReturnType<typeof vi.spyOn>,
26
+ discoverWorkspacePackages: undefined as unknown as ReturnType<typeof vi.spyOn>,
27
+ };
48
28
 
49
29
  /**
50
30
  * Collects all calls to the given mock function's first argument into an array,
@@ -58,10 +38,19 @@ describe("runCheck", () => {
58
38
  let savedExitCode: typeof process.exitCode;
59
39
 
60
40
  beforeEach(() => {
61
- vi.clearAllMocks();
41
+ vi.restoreAllMocks();
62
42
  savedExitCode = process.exitCode;
63
43
  process.exitCode = undefined;
64
44
 
45
+ vi.spyOn(consola, "withTag").mockReturnValue(mockLogger as any);
46
+ Object.values(mockLogger).forEach((m) => m.mockReset());
47
+
48
+ mocks.executeTypecheck = vi.spyOn(typecheckOrchestrator, "executeTypecheck");
49
+ mocks.executeLint = vi.spyOn(lintCore, "executeLint");
50
+ mocks.runLintInWorker = vi.spyOn(lintUtils, "runLintInWorker");
51
+ mocks.loadSdConfig = vi.spyOn(sdConfigMod, "loadSdConfig");
52
+ mocks.discoverWorkspacePackages = vi.spyOn(packageUtils, "discoverWorkspacePackages");
53
+
65
54
  // Default: workspace packages
66
55
  mocks.discoverWorkspacePackages.mockReturnValue(
67
56
  new Map([
@@ -1,27 +1,18 @@
1
1
  import { describe, it, expect, vi, beforeEach } from "vitest";
2
2
  import path from "path";
3
+ import { cpx, fsx } from "@simplysm/core-node";
4
+ import { StorageFactory } from "@simplysm/storage";
3
5
 
4
- const mocks = vi.hoisted(() => ({
5
- execa: vi.fn(),
6
+ const mocks = {
7
+ execa: vi.spyOn(cpx, "spawn"),
6
8
  fsx: {
7
- readJson: vi.fn(),
8
- copy: vi.fn(),
9
+ readJson: vi.spyOn(fsx, "readJson"),
10
+ copy: vi.spyOn(fsx, "copy"),
9
11
  },
10
- storageConnect: vi.fn(),
11
- }));
12
+ storageConnect: vi.spyOn(StorageFactory, "connect"),
13
+ };
12
14
 
13
- vi.mock("@simplysm/core-node", () => ({
14
- cpx: {
15
- spawn: mocks.execa,
16
- },
17
- fsx: mocks.fsx,
18
- }));
19
-
20
- vi.mock("@simplysm/storage", () => ({
21
- StorageFactory: { connect: mocks.storageConnect },
22
- }));
23
-
24
- const { runDeployment } = await import("../../src/commands/publish/deployment-phase");
15
+ import { runDeployment } from "../../src/commands/publish/deployment-phase";
25
16
 
26
17
  const CWD = process.cwd();
27
18
 
@@ -49,17 +40,17 @@ describe("runDeployment", () => {
49
40
  it("deploys packages in dependency level order", async () => {
50
41
  const publishOrder: string[] = [];
51
42
  mocks.execa.mockImplementation(
52
- (_cmd: string, _args?: string[], opts?: { cwd?: string }) => {
43
+ ((_cmd: string, _args?: string[], opts?: { cwd?: string }) => {
53
44
  publishOrder.push(path.basename(opts?.cwd ?? ""));
54
45
  return { stdout: "", stderr: "", exitCode: 0 };
55
- },
46
+ }) as never,
56
47
  );
57
- mocks.fsx.readJson.mockImplementation((p: string) => {
48
+ mocks.fsx.readJson.mockImplementation(((p: string) => {
58
49
  if (p.includes("pkg-b")) {
59
50
  return { name: "@simplysm/pkg-b", version: "14.0.1", dependencies: { "@simplysm/pkg-a": "~14.0.0" } };
60
51
  }
61
52
  return { name: "@simplysm/pkg-a", version: "14.0.1", dependencies: {} };
62
- });
53
+ }) as never);
63
54
 
64
55
  const logger = createLogger();
65
56
  await runDeployment(
@@ -104,19 +95,19 @@ describe("runDeployment", () => {
104
95
  });
105
96
 
106
97
  it("reports partially deployed packages on failure", async () => {
107
- mocks.fsx.readJson.mockImplementation((p: string) => {
98
+ mocks.fsx.readJson.mockImplementation(((p: string) => {
108
99
  const name = path.basename(path.dirname(p));
109
100
  return { name: `@simplysm/${name}`, version: "14.0.1", dependencies: {} };
110
- });
101
+ }) as never);
111
102
 
112
103
  // pkg-a succeeds, pkg-b fails
113
104
  mocks.execa.mockImplementation(
114
- (_cmd: string, _args?: string[], opts?: { cwd?: string }) => {
105
+ ((_cmd: string, _args?: string[], opts?: { cwd?: string }) => {
115
106
  if (opts?.cwd?.includes("pkg-b")) {
116
107
  throw new Error("publish failed");
117
108
  }
118
109
  return { stdout: "", stderr: "", exitCode: 0 };
119
- },
110
+ }) as never,
120
111
  );
121
112
 
122
113
  const logger = createLogger();