@simplysm/sd-cli 14.0.64 → 14.0.66

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 +13 -13
  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,28 +1,6 @@
1
1
  import { describe, it, expect, vi, beforeEach } from "vitest";
2
2
 
3
- // --- Mock factories (vi.mock is hoisted) ---
4
-
5
- vi.mock("../../src/utils/sd-config", () => ({
6
- loadSdConfig: vi.fn(),
7
- }));
8
-
9
- vi.mock("../../src/utils/build-env", () => ({
10
- getVersion: vi.fn(),
11
- }));
12
-
13
- vi.mock("../../src/deps/replace-deps/replace-deps", () => ({
14
- watchReplaceDeps: vi.fn(),
15
- }));
16
-
17
- vi.mock("../../src/utils/output-utils", async (importOriginal) => {
18
- const actual = await importOriginal<typeof import("../../src/utils/output-utils")>();
19
- return {
20
- ...actual,
21
- printDiagnostics: vi.fn(),
22
- printServers: vi.fn(),
23
- };
24
- });
25
-
3
+ // SignalHandler는 OS signal 등록 부작용이 있어 mock 유지
26
4
  vi.mock("../../src/runtime/SignalHandler", () => ({
27
5
  SignalHandler: vi.fn().mockImplementation(function (this: any) {
28
6
  this.waitForTermination = vi.fn().mockResolvedValue(undefined);
@@ -31,7 +9,28 @@ vi.mock("../../src/runtime/SignalHandler", () => ({
31
9
  }),
32
10
  }));
33
11
 
34
- // Engine mock
12
+ import * as sdConfigMod from "../../src/utils/sd-config";
13
+ import * as buildEnvMod from "../../src/utils/build-env";
14
+ import * as replaceDepsMod from "../../src/deps/replace-deps/replace-deps";
15
+ import * as outputUtilsMod from "../../src/utils/output-utils";
16
+ import * as engineFactoryMod from "../../src/engines/engine-factory";
17
+ import * as coreNode from "@simplysm/core-node";
18
+ import * as capacitorMod from "../../src/capacitor/capacitor";
19
+ import * as electronMod from "../../src/electron/electron";
20
+
21
+ import { loadSdConfig } from "../../src/utils/sd-config";
22
+ import { getVersion } from "../../src/utils/build-env";
23
+ import { watchReplaceDeps } from "../../src/deps/replace-deps/replace-deps";
24
+ import { printDiagnostics, printServers as _printServers } from "../../src/utils/output-utils";
25
+ import { createBuildEngine } from "../../src/engines/engine-factory";
26
+ import { Worker } from "@simplysm/core-node";
27
+ import { Capacitor } from "../../src/capacitor/capacitor";
28
+ import { Electron } from "../../src/electron/electron";
29
+
30
+ import { SignalHandler } from "../../src/runtime/SignalHandler";
31
+ import { DevOrchestrator } from "../../src/orchestrators/DevOrchestrator";
32
+ import type { SdConfig } from "../../src/sd-config.types";
33
+
35
34
  const mockBuildEngines: Array<{
36
35
  run: ReturnType<typeof vi.fn>;
37
36
  startWatch: ReturnType<typeof vi.fn>;
@@ -40,92 +39,18 @@ const mockBuildEngines: Array<{
40
39
  port?: number;
41
40
  }> = [];
42
41
 
43
- vi.mock("../../src/engines/engine-factory", () => ({
44
- createBuildEngine: vi.fn((pkg: any, options: any) => {
45
- const engine = {
46
- run: vi.fn().mockResolvedValue({
47
- success: true,
48
- build: { success: true, errors: [], warnings: [], diagnostics: [] },
49
- }),
50
- startWatch: vi.fn().mockImplementation(() => {
51
- const resolve = options.rebuildManager.registerBuild(
52
- `${pkg.name}:build`,
53
- `${pkg.name} (${pkg.config.target})`,
54
- );
55
- options.resultCollector.add({
56
- name: pkg.name,
57
- target: pkg.config.target,
58
- type: "build",
59
- status: "success",
60
- });
61
- resolve();
62
- }),
63
- stop: vi.fn().mockResolvedValue(undefined),
64
- _pkgName: pkg.name,
65
- };
66
- mockBuildEngines.push(engine);
67
- return engine;
68
- }),
69
- }));
70
-
71
- vi.mock("@simplysm/core-node", () => ({
72
- FsWatcher: {
73
- watch: vi.fn().mockResolvedValue({
74
- onChange: vi.fn(),
75
- close: vi.fn().mockResolvedValue(undefined),
76
- }),
77
- },
78
- Worker: {
79
- create: vi.fn(),
80
- },
81
- pathx: {
82
- posix: vi.fn((p: string) => p.replace(/\\/g, "/")),
83
- posixResolve: vi.fn((...args: string[]) => args.join("/").replace(/\\/g, "/")),
84
- isChildPath: vi.fn((child: string, parent: string) => child.startsWith(parent + "/")),
85
- filterByTargets: vi.fn((files: string[], targets: string[]) => targets.length === 0 ? files : files),
86
- },
87
- }));
88
-
89
- // Capacitor mock
90
42
  const mockCapacitorInstance = {
91
43
  initialize: vi.fn().mockResolvedValue(undefined),
92
44
  build: vi.fn().mockResolvedValue(undefined),
93
45
  run: vi.fn().mockResolvedValue(undefined),
94
46
  };
95
47
 
96
- vi.mock("../../src/capacitor/capacitor", () => ({
97
- Capacitor: {
98
- create: vi.fn().mockResolvedValue(mockCapacitorInstance),
99
- },
100
- }));
101
-
102
- // Electron mock
103
48
  const mockElectronInstance = {
104
49
  initialize: vi.fn().mockResolvedValue(undefined),
105
50
  build: vi.fn().mockResolvedValue(undefined),
106
51
  run: vi.fn().mockResolvedValue(undefined),
107
52
  };
108
53
 
109
- vi.mock("../../src/electron/electron", () => ({
110
- Electron: {
111
- create: vi.fn().mockResolvedValue(mockElectronInstance),
112
- },
113
- }));
114
-
115
- // --- Dynamic imports after mocking ---
116
-
117
- const { DevOrchestrator } = await import("../../src/orchestrators/DevOrchestrator");
118
- const { loadSdConfig } = await import("../../src/utils/sd-config");
119
- const { watchReplaceDeps } = await import("../../src/deps/replace-deps/replace-deps");
120
- const { printDiagnostics, printServers: _printServers } = await import("../../src/utils/output-utils");
121
- const { createBuildEngine } = await import("../../src/engines/engine-factory");
122
- const { Worker } = await import("@simplysm/core-node");
123
- const { getVersion } = await import("../../src/utils/build-env");
124
- const { Capacitor } = await import("../../src/capacitor/capacitor");
125
- const { Electron } = await import("../../src/electron/electron");
126
-
127
- import type { SdConfig } from "../../src/sd-config.types";
128
-
129
54
  // --- Runtime worker mock helper ---
130
55
 
131
56
  interface MockRuntimeProxy {
@@ -230,27 +155,61 @@ function setupEngineWithClientPort(
230
155
 
231
156
  describe("DevOrchestrator", () => {
232
157
  beforeEach(() => {
233
- vi.clearAllMocks();
158
+ vi.restoreAllMocks();
159
+ vi.mocked(SignalHandler).mockReset();
160
+ vi.mocked(SignalHandler).mockImplementation(function (this: any) {
161
+ this.waitForTermination = vi.fn().mockResolvedValue(undefined);
162
+ this.isTerminated = vi.fn().mockReturnValue(false);
163
+ this.requestTermination = vi.fn();
164
+ });
165
+
234
166
  mockBuildEngines.length = 0;
235
167
  mockRuntimeProxies = [];
236
168
  capturedRebuildManager = undefined;
237
169
  capturedResultCollector = undefined;
170
+
238
171
  vi.spyOn(process, "cwd").mockReturnValue("/test-root");
239
172
  vi.spyOn(process.stdout, "write").mockImplementation(() => true);
240
- vi.mocked(Worker.create).mockImplementation(() => {
173
+
174
+ vi.spyOn(sdConfigMod, "loadSdConfig").mockResolvedValue({ packages: {} });
175
+ vi.spyOn(buildEnvMod, "getVersion").mockResolvedValue("1.0.0");
176
+ vi.spyOn(replaceDepsMod, "watchReplaceDeps").mockResolvedValue({
177
+ entries: [], dispose: vi.fn(),
178
+ });
179
+ vi.spyOn(outputUtilsMod, "printDiagnostics").mockImplementation(() => {});
180
+ vi.spyOn(outputUtilsMod, "printServers").mockImplementation(() => {});
181
+
182
+ vi.spyOn(coreNode.FsWatcher, "watch").mockResolvedValue({
183
+ onChange: vi.fn(),
184
+ close: vi.fn().mockResolvedValue(undefined),
185
+ } as any);
186
+ vi.spyOn(coreNode.Worker, "create").mockImplementation(() => {
241
187
  const proxy = createMockRuntimeProxy();
242
188
  mockRuntimeProxies.push(proxy);
243
189
  return proxy as any;
244
190
  });
245
- mockCapacitorInstance.initialize.mockResolvedValue(undefined);
246
- mockCapacitorInstance.build.mockResolvedValue(undefined);
247
- mockCapacitorInstance.run.mockResolvedValue(undefined);
248
- mockElectronInstance.initialize.mockResolvedValue(undefined);
249
- mockElectronInstance.build.mockResolvedValue(undefined);
250
- mockElectronInstance.run.mockResolvedValue(undefined);
251
- vi.mocked(Capacitor.create).mockResolvedValue(mockCapacitorInstance as any);
252
- vi.mocked(Electron.create).mockResolvedValue(mockElectronInstance as any);
253
- vi.mocked(createBuildEngine).mockImplementation((pkg: any, options: any) => {
191
+ vi.spyOn(coreNode.pathx, "posix").mockImplementation((p: string) => p.replace(/\\/g, "/") as coreNode.pathx.PosixPath);
192
+ vi.spyOn(coreNode.pathx, "posixResolve").mockImplementation(
193
+ (...args: string[]) => args.join("/").replace(/\\/g, "/") as coreNode.pathx.PosixPath,
194
+ );
195
+ vi.spyOn(coreNode.pathx, "isChildPath").mockImplementation(
196
+ (child: string, parent: string) => child.startsWith(parent + "/"),
197
+ );
198
+ vi.spyOn(coreNode.pathx, "filterByTargets").mockImplementation(
199
+ (files: string[], targets: string[]) => targets.length === 0 ? files : files,
200
+ );
201
+
202
+ mockCapacitorInstance.initialize.mockReset().mockResolvedValue(undefined);
203
+ mockCapacitorInstance.build.mockReset().mockResolvedValue(undefined);
204
+ mockCapacitorInstance.run.mockReset().mockResolvedValue(undefined);
205
+ mockElectronInstance.initialize.mockReset().mockResolvedValue(undefined);
206
+ mockElectronInstance.build.mockReset().mockResolvedValue(undefined);
207
+ mockElectronInstance.run.mockReset().mockResolvedValue(undefined);
208
+
209
+ vi.spyOn(capacitorMod.Capacitor, "create").mockResolvedValue(mockCapacitorInstance as any);
210
+ vi.spyOn(electronMod.Electron, "create").mockResolvedValue(mockElectronInstance as any);
211
+
212
+ vi.spyOn(engineFactoryMod, "createBuildEngine").mockImplementation((pkg: any, options: any) => {
254
213
  capturedRebuildManager = options.rebuildManager;
255
214
  capturedResultCollector = options.resultCollector;
256
215
  const engine = {
@@ -1,67 +1,27 @@
1
1
  import { describe, it, expect, vi, beforeEach } from "vitest";
2
2
 
3
- //#region Mocks
4
-
5
- const mocks = vi.hoisted(() => ({
6
- loadAndValidateConfig: vi.fn(),
7
- deserializeDiagnostic: vi.fn((d: any) => d),
8
- typecheckNonPackageFiles: vi.fn(),
9
- createTypecheckEngine: vi.fn(),
10
- discoverWorkspacePackages: vi.fn(),
11
- mergeTestsPackagesIntoConfig: vi.fn(),
12
- }));
3
+ import * as orchestratorUtils from "../../src/utils/orchestrator-utils";
4
+ import * as typecheckSerialization from "../../src/typecheck/typecheck-serialization";
5
+ import * as typecheckNonPackage from "../../src/typecheck/typecheck-non-package";
6
+ import * as engineFactory from "../../src/engines/engine-factory";
7
+ import * as packageUtils from "../../src/utils/package-utils";
8
+
9
+ import { TypecheckOrchestrator } from "../../src/orchestrators/TypecheckOrchestrator";
10
+
11
+ const mocks = {
12
+ loadAndValidateConfig: undefined as unknown as ReturnType<typeof vi.spyOn>,
13
+ deserializeDiagnostic: undefined as unknown as ReturnType<typeof vi.spyOn>,
14
+ typecheckNonPackageFiles: undefined as unknown as ReturnType<typeof vi.spyOn>,
15
+ createTypecheckEngine: undefined as unknown as ReturnType<typeof vi.spyOn>,
16
+ discoverWorkspacePackages: undefined as unknown as ReturnType<typeof vi.spyOn>,
17
+ mergeTestsPackagesIntoConfig: undefined as unknown as ReturnType<typeof vi.spyOn>,
18
+ };
13
19
 
14
20
  const mockEngines: Array<{
15
21
  run: ReturnType<typeof vi.fn>;
16
22
  stop: ReturnType<typeof vi.fn>;
17
23
  }> = [];
18
24
 
19
- vi.mock("../../src/utils/orchestrator-utils", () => ({
20
- loadAndValidateConfig: mocks.loadAndValidateConfig,
21
- }));
22
-
23
- vi.mock("../../src/typecheck/typecheck-serialization", () => ({
24
- deserializeDiagnostic: mocks.deserializeDiagnostic,
25
- }));
26
-
27
- vi.mock("../../src/typecheck/typecheck-non-package", () => ({
28
- typecheckNonPackageFiles: mocks.typecheckNonPackageFiles,
29
- }));
30
-
31
- vi.mock("../../src/engines/engine-factory", () => ({
32
- createTypecheckEngine: mocks.createTypecheckEngine,
33
- }));
34
-
35
- vi.mock("../../src/utils/package-utils", async (importOriginal) => {
36
- const actual = await importOriginal<typeof import("../../src/utils/package-utils")>();
37
- return {
38
- ...actual,
39
- discoverWorkspacePackages: mocks.discoverWorkspacePackages,
40
- mergeTestsPackagesIntoConfig: mocks.mergeTestsPackagesIntoConfig,
41
- };
42
- });
43
-
44
- vi.mock("typescript", async (importOriginal) => {
45
- const orig = await importOriginal<Record<string, unknown>>();
46
- const origDefault = (orig["default"] ?? orig) as Record<string, unknown>;
47
- return {
48
- ...orig,
49
- default: {
50
- ...origDefault,
51
- sortAndDeduplicateDiagnostics: vi.fn((d: unknown[]) => d),
52
- formatDiagnosticsWithColorAndContext: vi.fn((diags: Array<{ messageText: string }>) =>
53
- diags.map((d) => `formatted: ${d.messageText}`).join("\n"),
54
- ),
55
- },
56
- };
57
- });
58
-
59
- const { TypecheckOrchestrator } = await import(
60
- "../../src/orchestrators/TypecheckOrchestrator"
61
- );
62
-
63
- //#endregion
64
-
65
25
  //#region Helpers
66
26
 
67
27
  function createMockEngine() {
@@ -99,8 +59,16 @@ function setupDefaults(packages: Record<string, any> = {}) {
99
59
  //#region Tests
100
60
 
101
61
  beforeEach(() => {
102
- vi.clearAllMocks();
62
+ vi.restoreAllMocks();
103
63
  mockEngines.length = 0;
64
+
65
+ mocks.loadAndValidateConfig = vi.spyOn(orchestratorUtils, "loadAndValidateConfig");
66
+ mocks.deserializeDiagnostic = vi.spyOn(typecheckSerialization, "deserializeDiagnostic")
67
+ .mockImplementation((d: any) => d);
68
+ mocks.typecheckNonPackageFiles = vi.spyOn(typecheckNonPackage, "typecheckNonPackageFiles");
69
+ mocks.createTypecheckEngine = vi.spyOn(engineFactory, "createTypecheckEngine");
70
+ mocks.discoverWorkspacePackages = vi.spyOn(packageUtils, "discoverWorkspacePackages");
71
+ mocks.mergeTestsPackagesIntoConfig = vi.spyOn(packageUtils, "mergeTestsPackagesIntoConfig");
104
72
  });
105
73
 
106
74
  describe("TypecheckOrchestrator", () => {
@@ -1,28 +1,6 @@
1
1
  import { describe, it, expect, vi, beforeEach } from "vitest";
2
2
 
3
- // --- Mock factories (vi.mock is hoisted) ---
4
-
5
- vi.mock("../../src/utils/sd-config", () => ({
6
- loadSdConfig: vi.fn(),
7
- }));
8
-
9
- vi.mock("../../src/utils/build-env", () => ({
10
- getVersion: vi.fn(),
11
- }));
12
-
13
- vi.mock("../../src/deps/replace-deps/replace-deps", () => ({
14
- watchReplaceDeps: vi.fn(),
15
- }));
16
-
17
- vi.mock("../../src/utils/output-utils", async (importOriginal) => {
18
- const actual = await importOriginal<typeof import("../../src/utils/output-utils")>();
19
- return {
20
- ...actual,
21
- printDiagnostics: vi.fn(),
22
- printServers: vi.fn(),
23
- };
24
- });
25
-
3
+ // SignalHandler는 OS signal(SIGINT/SIGTERM) 등록 부작용이 있어 mock 유지
26
4
  vi.mock("../../src/runtime/SignalHandler", () => ({
27
5
  SignalHandler: vi.fn().mockImplementation(function (this: any) {
28
6
  this.waitForTermination = vi.fn().mockResolvedValue(undefined);
@@ -31,66 +9,7 @@ vi.mock("../../src/runtime/SignalHandler", () => ({
31
9
  }),
32
10
  }));
33
11
 
34
- vi.mock("../../src/utils/copy-src", () => ({
35
- watchCopySrcFiles: vi.fn().mockResolvedValue({
36
- close: vi.fn().mockResolvedValue(undefined),
37
- }),
38
- }));
39
-
40
- // Engine mock — tracks created engines and the package they were created for
41
- const mockBuildEngines: Array<{
42
- run: ReturnType<typeof vi.fn>;
43
- startWatch: ReturnType<typeof vi.fn>;
44
- stop: ReturnType<typeof vi.fn>;
45
- _pkgName: string;
46
- }> = [];
47
-
48
- vi.mock("../../src/engines/engine-factory", () => ({
49
- createBuildEngine: vi.fn((pkg: any, options: any) => {
50
- const engine = {
51
- run: vi.fn().mockResolvedValue({
52
- success: true,
53
- build: { success: true, errors: [], warnings: [], diagnostics: [] },
54
- }),
55
- startWatch: vi.fn().mockImplementation(() => {
56
- const resolve = options.rebuildManager.registerBuild(
57
- `${pkg.name}:build`,
58
- `${pkg.name} (${pkg.config.target})`,
59
- );
60
- options.resultCollector.add({
61
- name: pkg.name,
62
- target: pkg.config.target,
63
- type: "build",
64
- status: "success",
65
- });
66
- resolve();
67
- }),
68
- stop: vi.fn().mockResolvedValue(undefined),
69
- _pkgName: pkg.name,
70
- };
71
- mockBuildEngines.push(engine);
72
- return engine;
73
- }),
74
- }));
75
-
76
- vi.mock("@simplysm/core-node", () => ({
77
- FsWatcher: {
78
- watch: vi.fn().mockResolvedValue({
79
- onChange: vi.fn(),
80
- close: vi.fn().mockResolvedValue(undefined),
81
- }),
82
- },
83
- Worker: {
84
- create: vi.fn(),
85
- },
86
- pathx: {
87
- posix: vi.fn((p: string) => p.replace(/\\/g, "/")),
88
- posixResolve: vi.fn((...args: string[]) => args.join("/").replace(/\\/g, "/")),
89
- isChildPath: vi.fn((child: string, parent: string) => child.startsWith(parent + "/")),
90
- filterByTargets: vi.fn((files: string[], targets: string[]) => targets.length === 0 ? files : files),
91
- },
92
- }));
93
-
12
+ // child_process는 ESM namespace immutable이라 spyOn 불가 — vi.mock 유지
94
13
  vi.mock("child_process", () => ({
95
14
  spawn: vi.fn(() => ({
96
15
  on: vi.fn(),
@@ -99,20 +18,33 @@ vi.mock("child_process", () => ({
99
18
  })),
100
19
  }));
101
20
 
102
- // --- Dynamic imports after mocking ---
103
-
104
- const { WatchOrchestrator } = await import("../../src/orchestrators/WatchOrchestrator");
105
- const { loadSdConfig } = await import("../../src/utils/sd-config");
106
- const { watchReplaceDeps } = await import("../../src/deps/replace-deps/replace-deps");
107
- const { printDiagnostics } = await import("../../src/utils/output-utils");
108
- const { createBuildEngine } = await import("../../src/engines/engine-factory");
109
- const { watchCopySrcFiles } = await import("../../src/utils/copy-src");
110
- const { FsWatcher } = await import("@simplysm/core-node");
111
- const { spawn } = await import("child_process");
112
- const { getVersion } = await import("../../src/utils/build-env");
113
-
21
+ import * as sdConfigMod from "../../src/utils/sd-config";
22
+ import * as buildEnvMod from "../../src/utils/build-env";
23
+ import * as replaceDepsMod from "../../src/deps/replace-deps/replace-deps";
24
+ import * as outputUtilsMod from "../../src/utils/output-utils";
25
+ import * as copySrcMod from "../../src/utils/copy-src";
26
+ import * as engineFactoryMod from "../../src/engines/engine-factory";
27
+ import * as coreNode from "@simplysm/core-node";
28
+
29
+ import { loadSdConfig } from "../../src/utils/sd-config";
30
+ import { getVersion } from "../../src/utils/build-env";
31
+ import { watchReplaceDeps } from "../../src/deps/replace-deps/replace-deps";
32
+ import { printDiagnostics } from "../../src/utils/output-utils";
33
+ import { watchCopySrcFiles } from "../../src/utils/copy-src";
34
+ import { FsWatcher } from "@simplysm/core-node";
35
+ import { spawn } from "child_process";
36
+
37
+ import { SignalHandler } from "../../src/runtime/SignalHandler";
38
+ import { WatchOrchestrator } from "../../src/orchestrators/WatchOrchestrator";
114
39
  import type { SdConfig } from "../../src/sd-config.types";
115
40
 
41
+ const mockBuildEngines: Array<{
42
+ run: ReturnType<typeof vi.fn>;
43
+ startWatch: ReturnType<typeof vi.fn>;
44
+ stop: ReturnType<typeof vi.fn>;
45
+ _pkgName: string;
46
+ }> = [];
47
+
116
48
  // --- Helpers ---
117
49
 
118
50
  function createConfig(overrides: Partial<SdConfig> = {}): SdConfig {
@@ -129,11 +61,55 @@ function setupDefaults(config: SdConfig): void {
129
61
 
130
62
  describe("WatchOrchestrator", () => {
131
63
  beforeEach(() => {
132
- vi.clearAllMocks();
64
+ vi.restoreAllMocks();
65
+ vi.mocked(spawn).mockClear();
66
+ vi.mocked(SignalHandler).mockReset();
67
+ vi.mocked(SignalHandler).mockImplementation(function (this: any) {
68
+ this.waitForTermination = vi.fn().mockResolvedValue(undefined);
69
+ this.isTerminated = vi.fn().mockReturnValue(false);
70
+ this.requestTermination = vi.fn();
71
+ });
133
72
  mockBuildEngines.length = 0;
134
73
  vi.spyOn(process, "cwd").mockReturnValue("/test-root");
135
74
  vi.spyOn(process.stdout, "write").mockImplementation(() => true);
136
- vi.mocked(createBuildEngine).mockImplementation((pkg: any, options: any) => {
75
+
76
+ vi.spyOn(sdConfigMod, "loadSdConfig").mockResolvedValue({ packages: {} });
77
+ vi.spyOn(buildEnvMod, "getVersion").mockResolvedValue("1.0.0");
78
+ vi.spyOn(replaceDepsMod, "watchReplaceDeps").mockResolvedValue({
79
+ entries: [],
80
+ dispose: vi.fn(),
81
+ });
82
+ vi.spyOn(outputUtilsMod, "printDiagnostics").mockImplementation(() => {});
83
+ vi.spyOn(outputUtilsMod, "printServers").mockImplementation(() => {});
84
+ vi.spyOn(copySrcMod, "watchCopySrcFiles").mockResolvedValue({
85
+ close: vi.fn().mockResolvedValue(undefined),
86
+ } as any);
87
+
88
+ vi.spyOn(coreNode.FsWatcher, "watch").mockResolvedValue({
89
+ onChange: vi.fn(),
90
+ close: vi.fn().mockResolvedValue(undefined),
91
+ } as any);
92
+ vi.spyOn(coreNode.Worker, "create").mockReturnValue(undefined as any);
93
+ vi.spyOn(coreNode.pathx, "posix").mockImplementation((p: string) => p.replace(/\\/g, "/") as coreNode.pathx.PosixPath);
94
+ vi.spyOn(coreNode.pathx, "posixResolve").mockImplementation(
95
+ (...args: string[]) => args.join("/").replace(/\\/g, "/") as coreNode.pathx.PosixPath,
96
+ );
97
+ vi.spyOn(coreNode.pathx, "isChildPath").mockImplementation(
98
+ (child: string, parent: string) => child.startsWith(parent + "/"),
99
+ );
100
+ vi.spyOn(coreNode.pathx, "filterByTargets").mockImplementation(
101
+ (files: string[], targets: string[]) => targets.length === 0 ? files : files,
102
+ );
103
+
104
+ vi.mocked(spawn).mockImplementation(
105
+ (() => ({
106
+ on: vi.fn(),
107
+ kill: vi.fn(),
108
+ exitCode: 0,
109
+ })) as any,
110
+ );
111
+
112
+ vi.spyOn(engineFactoryMod, "createBuildEngine").mockImplementation((pkg: any, options: any) => {
137
113
  const engine = {
138
114
  run: vi.fn().mockResolvedValue({
139
115
  success: true,
@@ -334,8 +310,6 @@ describe("WatchOrchestrator", () => {
334
310
  packages: { "core-common": { target: "node" } },
335
311
  }));
336
312
 
337
- const { SignalHandler } = await import("../../src/runtime/SignalHandler");
338
-
339
313
  const orchestrator = new WatchOrchestrator({ targets: [], options: [] });
340
314
  await orchestrator.initialize();
341
315
  await orchestrator.awaitTermination();
@@ -1,24 +1,21 @@
1
- import { describe, it, expect, vi } from "vitest";
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
2
 
3
- // Mock all command modules to prevent side effects during parsing
4
- vi.mock("../src/commands/check", () => ({
5
- runCheck: vi.fn().mockResolvedValue(undefined),
6
- }));
7
- vi.mock("../src/commands/watch", () => ({
8
- runWatch: vi.fn().mockResolvedValue(undefined),
9
- }));
10
- vi.mock("../src/commands/dev", () => ({
11
- runDev: vi.fn().mockResolvedValue(undefined),
12
- }));
13
- vi.mock("../src/commands/build", () => ({
14
- runBuild: vi.fn().mockResolvedValue(undefined),
15
- }));
16
- vi.mock("../src/commands/publish", () => ({
17
- runPublish: vi.fn().mockResolvedValue(undefined),
18
- }));
19
- vi.mock("../src/commands/replace-deps", () => ({
20
- runReplaceDeps: vi.fn().mockResolvedValue(undefined),
21
- }));
3
+ import * as checkCmd from "../src/commands/check";
4
+ import * as watchCmd from "../src/commands/watch";
5
+ import * as devCmd from "../src/commands/dev";
6
+ import * as buildCmd from "../src/commands/build";
7
+ import * as publishCmd from "../src/commands/publish/publish-command";
8
+ import * as replaceDepsCmd from "../src/commands/replace-deps";
9
+
10
+ beforeEach(() => {
11
+ vi.restoreAllMocks();
12
+ vi.spyOn(checkCmd, "runCheck").mockResolvedValue(undefined);
13
+ vi.spyOn(watchCmd, "runWatch").mockResolvedValue(undefined);
14
+ vi.spyOn(devCmd, "runDev").mockResolvedValue(undefined);
15
+ vi.spyOn(buildCmd, "runBuild").mockResolvedValue(undefined);
16
+ vi.spyOn(publishCmd, "runPublish").mockResolvedValue(undefined);
17
+ vi.spyOn(replaceDepsCmd, "runReplaceDeps").mockResolvedValue(undefined);
18
+ });
22
19
 
23
20
  describe("sd-cli-entry COMMAND_NAMES", () => {
24
21
  it("includes expected commands", async () => {
@@ -1,15 +1,11 @@
1
1
  import { describe, it, expect, vi } from "vitest";
2
2
  import ts from "typescript";
3
+ import * as angularBuild from "../../src/angular/angular-build";
3
4
 
4
- // Minimal mock to allow angular-compiler import (it depends on angular-build)
5
- vi.mock("../../src/angular/angular-build", () => ({
6
- NgtscProgram: vi.fn(),
7
- OptimizeFor: { WholeProgram: 0, SingleFile: 1 },
8
- }));
5
+ // angular-build의 NgtscProgram 클래스 인스턴스화는 실제 Angular 컴파일러 필요 spy로 차단
6
+ vi.spyOn(angularBuild, "NgtscProgram" as any).mockImplementation((() => ({})) as any);
9
7
 
10
- const { AngularSourceFileCache, augmentHostWithCaching } = await import(
11
- "../../src/angular/angular-compiler"
12
- );
8
+ import { AngularSourceFileCache, augmentHostWithCaching } from "../../src/angular/angular-compiler";
13
9
 
14
10
  // =============================================================================
15
11
  // AngularSourceFileCache — Unit Tests
@@ -1,32 +1,21 @@
1
1
  import { describe, it, expect, vi, beforeEach } from "vitest";
2
2
  import path from "path";
3
+ import { fsx, FsWatcher } from "@simplysm/core-node";
3
4
 
4
5
  const mockOnChange = vi.fn();
5
6
  const mockWatcherClose = vi.fn();
6
7
 
7
8
  const toPosix = (p: string) => p.replace(/\\/g, "/");
8
9
 
9
- vi.mock("@simplysm/core-node", async (importOriginal) => {
10
- const actual = await importOriginal<typeof import("@simplysm/core-node")>();
11
- return {
12
- ...actual,
13
- fsx: {
14
- glob: vi.fn(),
15
- mkdir: vi.fn(),
16
- copy: vi.fn(),
17
- rm: vi.fn(),
18
- },
19
- FsWatcher: {
20
- watch: vi.fn(() => Promise.resolve({
21
- onChange: mockOnChange,
22
- close: mockWatcherClose,
23
- })),
24
- },
25
- };
26
- });
10
+ vi.spyOn(fsx, "glob");
11
+ vi.spyOn(fsx, "mkdir");
12
+ vi.spyOn(fsx, "copy");
13
+ vi.spyOn(fsx, "rm");
14
+ vi.spyOn(FsWatcher, "watch").mockImplementation(() =>
15
+ Promise.resolve({ onChange: mockOnChange, close: mockWatcherClose } as any),
16
+ );
27
17
 
28
- const { fsx, FsWatcher } = await import("@simplysm/core-node");
29
- const { copySrcFiles, watchCopySrcFiles } = await import("../../src/utils/copy-src");
18
+ import { copySrcFiles, watchCopySrcFiles } from "../../src/utils/copy-src";
30
19
 
31
20
  const pkgDir = toPosix(path.resolve("/workspace/packages/my-pkg"));
32
21
  const srcDir = toPosix(path.join(pkgDir, "src"));