@simplysm/sd-cli 14.0.18 → 14.0.21
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/dist/angular/vite-angular-plugin.d.ts +2 -0
- package/dist/angular/vite-angular-plugin.d.ts.map +1 -1
- package/dist/angular/vite-angular-plugin.js +57 -28
- package/dist/angular/vite-angular-plugin.js.map +1 -1
- package/dist/angular/vite-postcss-inline-plugin.d.ts.map +1 -1
- package/dist/angular/vite-postcss-inline-plugin.js +4 -1
- package/dist/angular/vite-postcss-inline-plugin.js.map +1 -1
- package/dist/capacitor/capacitor-android.d.ts +16 -0
- package/dist/capacitor/capacitor-android.d.ts.map +1 -0
- package/dist/capacitor/capacitor-android.js +289 -0
- package/dist/capacitor/capacitor-android.js.map +1 -0
- package/dist/capacitor/capacitor.d.ts +0 -50
- package/dist/capacitor/capacitor.d.ts.map +1 -1
- package/dist/capacitor/capacitor.js +16 -281
- package/dist/capacitor/capacitor.js.map +1 -1
- package/dist/commands/check.js +2 -2
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/device.d.ts.map +1 -1
- package/dist/commands/device.js +3 -2
- package/dist/commands/device.js.map +1 -1
- package/dist/commands/lint.d.ts +1 -42
- package/dist/commands/lint.d.ts.map +1 -1
- package/dist/commands/lint.js +1 -151
- package/dist/commands/lint.js.map +1 -1
- package/dist/commands/publish.d.ts.map +1 -1
- package/dist/commands/publish.js +2 -1
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/typecheck.d.ts +3 -40
- package/dist/commands/typecheck.d.ts.map +1 -1
- package/dist/commands/typecheck.js +3 -232
- package/dist/commands/typecheck.js.map +1 -1
- package/dist/electron/electron.d.ts.map +1 -1
- package/dist/electron/electron.js +20 -8
- package/dist/electron/electron.js.map +1 -1
- package/dist/orchestrators/DevWatchOrchestrator.d.ts +1 -0
- package/dist/orchestrators/DevWatchOrchestrator.d.ts.map +1 -1
- package/dist/orchestrators/DevWatchOrchestrator.js +16 -0
- package/dist/orchestrators/DevWatchOrchestrator.js.map +1 -1
- package/dist/orchestrators/TypecheckOrchestrator.d.ts +74 -0
- package/dist/orchestrators/TypecheckOrchestrator.d.ts.map +1 -0
- package/dist/orchestrators/TypecheckOrchestrator.js +285 -0
- package/dist/orchestrators/TypecheckOrchestrator.js.map +1 -0
- package/dist/sd-cli.js +6 -1
- package/dist/sd-cli.js.map +1 -1
- package/dist/utils/lint-core.d.ts +43 -0
- package/dist/utils/lint-core.d.ts.map +1 -0
- package/dist/utils/lint-core.js +154 -0
- package/dist/utils/lint-core.js.map +1 -0
- package/dist/utils/lint-utils.d.ts +1 -1
- package/dist/utils/lint-utils.d.ts.map +1 -1
- package/dist/utils/server-production-files.d.ts +22 -0
- package/dist/utils/server-production-files.d.ts.map +1 -0
- package/dist/utils/server-production-files.js +162 -0
- package/dist/utils/server-production-files.js.map +1 -0
- package/dist/utils/vite-config.d.ts +1 -1
- package/dist/utils/vite-config.d.ts.map +1 -1
- package/dist/utils/vite-config.js +76 -26
- package/dist/utils/vite-config.js.map +1 -1
- package/dist/utils/vite-scope-watch-plugin.d.ts.map +1 -1
- package/dist/utils/vite-scope-watch-plugin.js +7 -1
- package/dist/utils/vite-scope-watch-plugin.js.map +1 -1
- package/dist/workers/lint.worker.d.ts +1 -1
- package/dist/workers/lint.worker.d.ts.map +1 -1
- package/dist/workers/lint.worker.js +1 -1
- package/dist/workers/lint.worker.js.map +1 -1
- package/dist/workers/server-build.worker.d.ts.map +1 -1
- package/dist/workers/server-build.worker.js +11 -161
- package/dist/workers/server-build.worker.js.map +1 -1
- package/dist/workers/server-runtime.worker.d.ts.map +1 -1
- package/dist/workers/server-runtime.worker.js +15 -0
- package/dist/workers/server-runtime.worker.js.map +1 -1
- package/package.json +9 -7
- package/src/angular/vite-angular-plugin.ts +88 -34
- package/src/angular/vite-postcss-inline-plugin.ts +5 -1
- package/src/capacitor/capacitor-android.ts +368 -0
- package/src/capacitor/capacitor.ts +18 -363
- package/src/commands/check.ts +2 -2
- package/src/commands/device.ts +3 -2
- package/src/commands/lint.ts +1 -201
- package/src/commands/publish.ts +2 -1
- package/src/commands/typecheck.ts +7 -292
- package/src/electron/electron.ts +15 -8
- package/src/orchestrators/DevWatchOrchestrator.ts +18 -0
- package/src/orchestrators/TypecheckOrchestrator.ts +364 -0
- package/src/sd-cli.ts +6 -1
- package/src/utils/lint-core.ts +205 -0
- package/src/utils/lint-utils.ts +1 -1
- package/src/utils/server-production-files.ts +186 -0
- package/src/utils/vite-config.ts +83 -27
- package/src/utils/vite-scope-watch-plugin.ts +6 -1
- package/src/workers/lint.worker.ts +1 -1
- package/src/workers/server-build.worker.ts +10 -185
- package/src/workers/server-runtime.worker.ts +15 -0
- package/tests/angular/linker-disk-cache.spec.ts +31 -25
- package/tests/angular/vite-angular-plugin-hmr-fallback.spec.ts +15 -15
- package/tests/angular/vite-angular-plugin-hmr.spec.ts +9 -9
- package/tests/angular/vite-angular-plugin-legacy-watch.spec.ts +108 -0
- package/tests/angular/vite-angular-plugin-lint.spec.ts +4 -4
- package/tests/angular/vite-angular-plugin-scss-hmr.spec.ts +10 -15
- package/tests/angular/vite-angular-plugin.spec.ts +80 -15
- package/tests/angular/vite-postcss-inline-plugin.spec.ts +10 -0
- package/tests/capacitor/capacitor-android-exports.verify.md +11 -0
- package/tests/capacitor/capacitor-android.spec.ts +219 -0
- package/tests/capacitor/capacitor-build.spec.ts +17 -21
- package/tests/capacitor/capacitor-icon.spec.ts +17 -19
- package/tests/capacitor/capacitor-init.spec.ts +18 -14
- package/tests/capacitor/capacitor-run.spec.ts +10 -24
- package/tests/capacitor/capacitor-workspace.spec.ts +30 -25
- package/tests/commands/check.spec.ts +2 -2
- package/tests/commands/device.spec.ts +12 -7
- package/tests/commands/lint.spec.ts +33 -194
- package/tests/commands/publish-set.verify.md +7 -0
- package/tests/electron/electron-symlink-cleanup.verify.md +8 -0
- package/tests/electron/electron.spec.ts +27 -2
- package/tests/orchestrators/dist-delete-watcher.verify.md +10 -0
- package/tests/orchestrators/typecheck-orchestrator.spec.ts +180 -0
- package/tests/sd-cli-catch-all.verify.md +7 -0
- package/tests/utils/lint-core-import-paths.verify.md +10 -0
- package/tests/utils/lint-core.spec.ts +188 -0
- package/tests/utils/server-production-files-import-paths.verify.md +14 -0
- package/tests/utils/vite-config.spec.ts +255 -133
- package/tests/utils/vite-scope-watch-plugin.spec.ts +22 -0
- package/tests/workers/server-build-context-dispose.verify.md +8 -0
- package/tests/workers/server-runtime-worker.spec.ts +48 -4
|
@@ -2,6 +2,10 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
|
2
2
|
|
|
3
3
|
// --- Mock factories ---
|
|
4
4
|
|
|
5
|
+
vi.mock("vite-tsconfig-paths", () => ({
|
|
6
|
+
default: vi.fn(() => ({ name: "vite-tsconfig-paths" })),
|
|
7
|
+
}));
|
|
8
|
+
|
|
5
9
|
const mockSdAngularPlugin = vi.fn(() => ({ name: "sd-angular-plugin" }));
|
|
6
10
|
vi.mock("../../src/angular/vite-angular-plugin.js", () => ({
|
|
7
11
|
sdAngularPlugin: mockSdAngularPlugin,
|
|
@@ -31,9 +35,14 @@ vi.mock("browserslist-to-esbuild", () => ({
|
|
|
31
35
|
}),
|
|
32
36
|
}));
|
|
33
37
|
|
|
34
|
-
const
|
|
35
|
-
vi.mock("
|
|
36
|
-
|
|
38
|
+
const mockVitePWA = vi.fn(() => ({ name: "vite-plugin-pwa" }));
|
|
39
|
+
vi.mock("vite-plugin-pwa", () => ({
|
|
40
|
+
VitePWA: mockVitePWA,
|
|
41
|
+
}));
|
|
42
|
+
|
|
43
|
+
const mockGeneratePwaIcons = vi.fn().mockResolvedValue([]);
|
|
44
|
+
vi.mock("../../src/utils/generate-pwa-icons.js", () => ({
|
|
45
|
+
generatePwaIcons: mockGeneratePwaIcons,
|
|
37
46
|
}));
|
|
38
47
|
|
|
39
48
|
// --- Dynamic import ---
|
|
@@ -64,8 +73,8 @@ afterEach(() => {
|
|
|
64
73
|
|
|
65
74
|
describe("createClientViteConfig", () => {
|
|
66
75
|
// Acceptance: Scenario "define['process.env'] 제거"
|
|
67
|
-
it("does not include process.env in define, only import.meta.env keys", () => {
|
|
68
|
-
const config = createClientViteConfig({
|
|
76
|
+
it("does not include process.env in define, only import.meta.env keys", async () => {
|
|
77
|
+
const config = await createClientViteConfig({
|
|
69
78
|
...createDefaultOptions(),
|
|
70
79
|
env: { DEV: "true", VER: "1.0.0" },
|
|
71
80
|
});
|
|
@@ -76,64 +85,63 @@ describe("createClientViteConfig", () => {
|
|
|
76
85
|
expect(define["import.meta.env.VER"]).toBe('"1.0.0"');
|
|
77
86
|
});
|
|
78
87
|
|
|
79
|
-
// Acceptance: Scenario "
|
|
80
|
-
it("uses es2022
|
|
81
|
-
const config = createClientViteConfig(createDefaultOptions());
|
|
88
|
+
// Acceptance: Scenario "browserslist 미설정 시 최신 브라우저 유지"
|
|
89
|
+
it("uses es2022 esbuild target when no browserslist is provided", async () => {
|
|
90
|
+
const config = await createClientViteConfig(createDefaultOptions());
|
|
82
91
|
|
|
83
|
-
expect(config.
|
|
84
|
-
expect(config.esbuild).toBeUndefined();
|
|
92
|
+
expect(config.esbuild).toEqual({ target: "es2022" });
|
|
85
93
|
});
|
|
86
94
|
|
|
87
95
|
// Acceptance: Scenario "postCss 미설정 시 처리 없음"
|
|
88
|
-
it("does not set css.postcss when no postCssPlugins are provided", () => {
|
|
89
|
-
const config = createClientViteConfig(createDefaultOptions());
|
|
96
|
+
it("does not set css.postcss when no postCssPlugins are provided", async () => {
|
|
97
|
+
const config = await createClientViteConfig(createDefaultOptions());
|
|
90
98
|
|
|
91
99
|
expect(config.css).toBeUndefined();
|
|
92
100
|
});
|
|
93
101
|
|
|
94
102
|
// Acceptance: Scenario "polyfills.ts 파일 미존재 시 주입 없음"
|
|
95
|
-
it("does not add polyfills plugin when no polyfills are provided", () => {
|
|
96
|
-
const config = createClientViteConfig(createDefaultOptions());
|
|
103
|
+
it("does not add polyfills plugin when no polyfills are provided", async () => {
|
|
104
|
+
const config = await createClientViteConfig(createDefaultOptions());
|
|
97
105
|
|
|
98
106
|
const plugins = config.plugins as Array<{ name: string }>;
|
|
99
107
|
const polyfillPlugin = plugins.find((p) => p.name === "sd-polyfills");
|
|
100
108
|
expect(polyfillPlugin).toBeUndefined();
|
|
101
109
|
});
|
|
102
110
|
|
|
103
|
-
// Acceptance: Scenario "browserslist
|
|
104
|
-
it("converts browserslist string to
|
|
105
|
-
const config = createClientViteConfig({
|
|
111
|
+
// Acceptance: Scenario "browserslist 문자열 설정 시 해당 타겟으로 변환"
|
|
112
|
+
it("converts browserslist string to esbuild target", async () => {
|
|
113
|
+
const config = await createClientViteConfig({
|
|
106
114
|
...createDefaultOptions(),
|
|
107
115
|
browserslist: "last 2 Chrome versions",
|
|
108
116
|
});
|
|
109
117
|
|
|
110
|
-
expect(config.
|
|
118
|
+
expect((config.esbuild as { target: string | string[] }).target).toEqual(["chrome120", "chrome119"]);
|
|
111
119
|
});
|
|
112
120
|
|
|
113
121
|
// Acceptance: Scenario "browserslist 배열 설정"
|
|
114
|
-
it("converts browserslist array to
|
|
115
|
-
const config = createClientViteConfig({
|
|
122
|
+
it("converts browserslist array to esbuild target", async () => {
|
|
123
|
+
const config = await createClientViteConfig({
|
|
116
124
|
...createDefaultOptions(),
|
|
117
125
|
browserslist: ["ie 11", "last 2 versions"],
|
|
118
126
|
});
|
|
119
127
|
|
|
120
|
-
expect(config.
|
|
128
|
+
expect((config.esbuild as { target: string | string[] }).target).toEqual(["es2015"]);
|
|
121
129
|
});
|
|
122
130
|
|
|
123
|
-
// Acceptance: Scenario "dev
|
|
124
|
-
it("applies browserslist
|
|
125
|
-
const config = createClientViteConfig({
|
|
131
|
+
// Acceptance: Scenario "dev server에서도 browserslist 적용"
|
|
132
|
+
it("applies browserslist in dev mode too", async () => {
|
|
133
|
+
const config = await createClientViteConfig({
|
|
126
134
|
...createDefaultOptions(),
|
|
127
135
|
mode: "dev",
|
|
128
136
|
browserslist: "last 2 Chrome versions",
|
|
129
137
|
});
|
|
130
138
|
|
|
131
|
-
expect(config.
|
|
139
|
+
expect((config.esbuild as { target: string | string[] }).target).toEqual(["chrome120", "chrome119"]);
|
|
132
140
|
});
|
|
133
141
|
|
|
134
142
|
// Unit: browserslist is passed to sdAngularPlugin
|
|
135
|
-
it("passes browserslist to sdAngularPlugin as normalized array", () => {
|
|
136
|
-
createClientViteConfig({
|
|
143
|
+
it("passes browserslist to sdAngularPlugin as normalized array", async () => {
|
|
144
|
+
await createClientViteConfig({
|
|
137
145
|
...createDefaultOptions(),
|
|
138
146
|
browserslist: "last 2 Chrome versions",
|
|
139
147
|
});
|
|
@@ -146,9 +154,9 @@ describe("createClientViteConfig", () => {
|
|
|
146
154
|
});
|
|
147
155
|
|
|
148
156
|
// Acceptance: Scenario ".scss 파일에 PostCSS 적용"
|
|
149
|
-
it("sets css.postcss when postCssPlugins are provided", () => {
|
|
157
|
+
it("sets css.postcss when postCssPlugins are provided", async () => {
|
|
150
158
|
const fakePlugin = { postcssPlugin: "autoprefixer" };
|
|
151
|
-
const config = createClientViteConfig({
|
|
159
|
+
const config = await createClientViteConfig({
|
|
152
160
|
...createDefaultOptions(),
|
|
153
161
|
postCssPlugins: [fakePlugin],
|
|
154
162
|
});
|
|
@@ -157,9 +165,9 @@ describe("createClientViteConfig", () => {
|
|
|
157
165
|
});
|
|
158
166
|
|
|
159
167
|
// Unit: postCssPlugins is passed to sdAngularPlugin
|
|
160
|
-
it("passes postCssPlugins to sdAngularPlugin", () => {
|
|
168
|
+
it("passes postCssPlugins to sdAngularPlugin", async () => {
|
|
161
169
|
const fakePlugin = { postcssPlugin: "autoprefixer" };
|
|
162
|
-
createClientViteConfig({
|
|
170
|
+
await createClientViteConfig({
|
|
163
171
|
...createDefaultOptions(),
|
|
164
172
|
postCssPlugins: [fakePlugin],
|
|
165
173
|
});
|
|
@@ -172,9 +180,9 @@ describe("createClientViteConfig", () => {
|
|
|
172
180
|
});
|
|
173
181
|
|
|
174
182
|
// Acceptance: Scenario "Angular 라이브러리 번들 JS 내 인라인 CSS에 PostCSS 적용"
|
|
175
|
-
it("adds sdPostCssInlinePlugin when postCssPlugins are provided", () => {
|
|
183
|
+
it("adds sdPostCssInlinePlugin when postCssPlugins are provided", async () => {
|
|
176
184
|
const fakePlugin = { postcssPlugin: "autoprefixer" };
|
|
177
|
-
const config = createClientViteConfig({
|
|
185
|
+
const config = await createClientViteConfig({
|
|
178
186
|
...createDefaultOptions(),
|
|
179
187
|
postCssPlugins: [fakePlugin],
|
|
180
188
|
});
|
|
@@ -185,8 +193,8 @@ describe("createClientViteConfig", () => {
|
|
|
185
193
|
});
|
|
186
194
|
|
|
187
195
|
// Unit: no sdPostCssInlinePlugin when empty postCssPlugins
|
|
188
|
-
it("does not add sdPostCssInlinePlugin when postCssPlugins is empty", () => {
|
|
189
|
-
const config = createClientViteConfig({
|
|
196
|
+
it("does not add sdPostCssInlinePlugin when postCssPlugins is empty", async () => {
|
|
197
|
+
const config = await createClientViteConfig({
|
|
190
198
|
...createDefaultOptions(),
|
|
191
199
|
postCssPlugins: [],
|
|
192
200
|
});
|
|
@@ -197,8 +205,8 @@ describe("createClientViteConfig", () => {
|
|
|
197
205
|
});
|
|
198
206
|
|
|
199
207
|
// Acceptance: Scenario "polyfills.ts 파일 존재 시 자동 주입"
|
|
200
|
-
it("adds sd-polyfills plugin when polyfills are provided", () => {
|
|
201
|
-
const config = createClientViteConfig({
|
|
208
|
+
it("adds sd-polyfills plugin when polyfills are provided", async () => {
|
|
209
|
+
const config = await createClientViteConfig({
|
|
202
210
|
...createDefaultOptions(),
|
|
203
211
|
polyfills: ["./src/polyfills.ts"],
|
|
204
212
|
});
|
|
@@ -210,131 +218,245 @@ describe("createClientViteConfig", () => {
|
|
|
210
218
|
|
|
211
219
|
// --- legacyModule (Feature 1.1) ---
|
|
212
220
|
|
|
213
|
-
// Acceptance: Scenario "legacyModule
|
|
214
|
-
it("enables inlineDynamicImports
|
|
215
|
-
const config = createClientViteConfig({
|
|
221
|
+
// Acceptance: Scenario "legacyModule 활성화 시 inlineDynamicImports만 설정한다"
|
|
222
|
+
it("enables inlineDynamicImports without import.meta plugin when legacyModule is true", async () => {
|
|
223
|
+
const config = await createClientViteConfig({
|
|
216
224
|
...createDefaultOptions(),
|
|
217
225
|
legacyModule: true,
|
|
218
226
|
});
|
|
219
227
|
|
|
220
|
-
// inlineDynamicImports가 활성화된다
|
|
221
|
-
expect((config.build as any)?.
|
|
222
|
-
// import.meta 치환 플러그인이
|
|
228
|
+
// inlineDynamicImports가 활성화된다
|
|
229
|
+
expect((config.build as any)?.rollupOptions?.output?.inlineDynamicImports).toBe(true);
|
|
230
|
+
// import.meta 치환 플러그인이 없다 (esbuild target이 자동 치환)
|
|
223
231
|
const plugins = config.plugins as Array<{ name: string }>;
|
|
224
|
-
const legacyPlugin = plugins.find((p) => p.name === "sd-legacy-
|
|
225
|
-
expect(legacyPlugin).
|
|
232
|
+
const legacyPlugin = plugins.find((p) => p.name === "sd-legacy-import-meta");
|
|
233
|
+
expect(legacyPlugin).toBeUndefined();
|
|
226
234
|
});
|
|
227
235
|
|
|
228
|
-
// Acceptance: Scenario "legacyModule
|
|
229
|
-
it("does not set inlineDynamicImports when legacyModule is not set", () => {
|
|
230
|
-
const config = createClientViteConfig(createDefaultOptions());
|
|
236
|
+
// Acceptance: Scenario "legacyModule 미설정 시 코드 분할이 기본 동작한다"
|
|
237
|
+
it("does not set inlineDynamicImports when legacyModule is not set", async () => {
|
|
238
|
+
const config = await createClientViteConfig(createDefaultOptions());
|
|
231
239
|
|
|
232
240
|
// 코드 분할이 기본 동작한다
|
|
233
|
-
expect(config.build?.
|
|
241
|
+
expect(config.build?.rollupOptions).toBeUndefined();
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// Acceptance: Scenario "legacyModule: true는 inlineDynamicImports를 활성화한다"
|
|
245
|
+
it("legacyModule: true provides inlineDynamicImports (splitting replacement)", async () => {
|
|
246
|
+
const config = await createClientViteConfig({
|
|
247
|
+
...createDefaultOptions(),
|
|
248
|
+
legacyModule: true,
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
// 기존 splitting: false와 동일한 inlineDynamicImports 동작
|
|
252
|
+
expect((config.build as any)?.rollupOptions?.output?.inlineDynamicImports).toBe(true);
|
|
234
253
|
});
|
|
235
254
|
|
|
236
|
-
// --- legacyModule
|
|
255
|
+
// --- legacyModule esbuild.supported override (Feature 1.4) ---
|
|
237
256
|
|
|
238
|
-
// Acceptance: Scenario "legacyModule import
|
|
239
|
-
it("
|
|
240
|
-
const config = createClientViteConfig({
|
|
257
|
+
// Acceptance: Scenario "legacyModule: true일 때 esbuild.supported에 import-meta false 설정"
|
|
258
|
+
it("sets esbuild.supported to disable import-meta when legacyModule is true", async () => {
|
|
259
|
+
const config = await createClientViteConfig({
|
|
241
260
|
...createDefaultOptions(),
|
|
242
261
|
legacyModule: true,
|
|
243
262
|
});
|
|
244
263
|
|
|
245
|
-
const
|
|
246
|
-
expect(
|
|
264
|
+
const esbuildOpts = config.esbuild as Record<string, unknown> | undefined;
|
|
265
|
+
expect(esbuildOpts?.["supported"]).toEqual(
|
|
266
|
+
expect.objectContaining({
|
|
267
|
+
"import-meta": false,
|
|
268
|
+
}),
|
|
269
|
+
);
|
|
247
270
|
});
|
|
248
271
|
|
|
249
|
-
// Acceptance: Scenario "legacyModule
|
|
250
|
-
it("does not
|
|
251
|
-
const config = createClientViteConfig(createDefaultOptions());
|
|
272
|
+
// Acceptance: Scenario "legacyModule 미설정 시 esbuild.supported 변경 없음"
|
|
273
|
+
it("does not set esbuild.supported when legacyModule is not specified", async () => {
|
|
274
|
+
const config = await createClientViteConfig(createDefaultOptions());
|
|
252
275
|
|
|
253
|
-
const
|
|
254
|
-
expect(
|
|
276
|
+
const esbuildOpts = config.esbuild as Record<string, unknown> | undefined;
|
|
277
|
+
expect(esbuildOpts?.["supported"]).toBeUndefined();
|
|
255
278
|
});
|
|
256
279
|
|
|
257
280
|
// --- PWA (Feature 5.2) ---
|
|
258
281
|
|
|
259
|
-
// Acceptance: Scenario "
|
|
260
|
-
it("adds
|
|
261
|
-
const config = createClientViteConfig(createDefaultOptions());
|
|
282
|
+
// Acceptance: Scenario "기본 PWA 활성화"
|
|
283
|
+
it("adds VitePWA plugin in build mode when pwa is not specified (default enabled)", async () => {
|
|
284
|
+
const config = await createClientViteConfig(createDefaultOptions());
|
|
262
285
|
|
|
263
286
|
const plugins = config.plugins as Array<{ name: string }>;
|
|
264
|
-
const pwaPlugin = plugins.find((p) => p.name === "
|
|
287
|
+
const pwaPlugin = plugins.find((p) => p.name === "vite-plugin-pwa");
|
|
265
288
|
expect(pwaPlugin).toBeDefined();
|
|
266
289
|
});
|
|
267
290
|
|
|
268
|
-
// Acceptance: Scenario "
|
|
269
|
-
it("does not add
|
|
270
|
-
const config = createClientViteConfig({
|
|
291
|
+
// Acceptance: Scenario "PWA 명시적 비활성화"
|
|
292
|
+
it("does not add VitePWA plugin when pwa is false", async () => {
|
|
293
|
+
const config = await createClientViteConfig({
|
|
271
294
|
...createDefaultOptions(),
|
|
272
295
|
pwa: false,
|
|
273
296
|
});
|
|
274
297
|
|
|
275
298
|
const plugins = config.plugins as Array<{ name: string }>;
|
|
276
|
-
const pwaPlugin = plugins.find((p) => p.name === "
|
|
299
|
+
const pwaPlugin = plugins.find((p) => p.name === "vite-plugin-pwa");
|
|
277
300
|
expect(pwaPlugin).toBeUndefined();
|
|
278
301
|
});
|
|
279
302
|
|
|
280
|
-
// Acceptance: Scenario "dev 모드에서
|
|
281
|
-
it("does not add
|
|
282
|
-
const config = createClientViteConfig({
|
|
303
|
+
// Acceptance: Scenario "dev 모드에서 service worker 미등록"
|
|
304
|
+
it("does not add VitePWA plugin in dev mode", async () => {
|
|
305
|
+
const config = await createClientViteConfig({
|
|
283
306
|
...createDefaultOptions(),
|
|
284
307
|
mode: "dev",
|
|
285
308
|
});
|
|
286
309
|
|
|
287
310
|
const plugins = config.plugins as Array<{ name: string }>;
|
|
288
|
-
const pwaPlugin = plugins.find((p) => p.name === "
|
|
311
|
+
const pwaPlugin = plugins.find((p) => p.name === "vite-plugin-pwa");
|
|
289
312
|
expect(pwaPlugin).toBeUndefined();
|
|
290
313
|
});
|
|
291
314
|
|
|
292
|
-
// Acceptance: Scenario "
|
|
293
|
-
it("passes
|
|
294
|
-
createClientViteConfig({
|
|
315
|
+
// Acceptance: Scenario "manifest 필드 커스텀"
|
|
316
|
+
it("passes custom manifest fields to VitePWA plugin", async () => {
|
|
317
|
+
await createClientViteConfig({
|
|
295
318
|
...createDefaultOptions(),
|
|
296
319
|
pwa: {
|
|
297
320
|
manifest: { name: "My App", theme_color: "#000000" },
|
|
298
321
|
},
|
|
299
322
|
});
|
|
300
323
|
|
|
301
|
-
expect(
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
324
|
+
expect(mockVitePWA).toHaveBeenCalledWith(
|
|
325
|
+
expect.objectContaining({
|
|
326
|
+
manifest: expect.objectContaining({
|
|
327
|
+
name: "My App",
|
|
328
|
+
theme_color: "#000000",
|
|
329
|
+
short_name: "my-client",
|
|
330
|
+
display: "standalone",
|
|
331
|
+
background_color: "#ffffff",
|
|
332
|
+
}),
|
|
333
|
+
}),
|
|
334
|
+
);
|
|
306
335
|
});
|
|
307
336
|
|
|
308
|
-
//
|
|
309
|
-
it("
|
|
310
|
-
createClientViteConfig(createDefaultOptions());
|
|
337
|
+
// Acceptance: Scenario "기본 Workbox 캐싱"
|
|
338
|
+
it("uses default workbox globPatterns when pwa.workbox is not specified", async () => {
|
|
339
|
+
await createClientViteConfig(createDefaultOptions());
|
|
340
|
+
|
|
341
|
+
expect(mockVitePWA).toHaveBeenCalledWith(
|
|
342
|
+
expect.objectContaining({
|
|
343
|
+
workbox: {
|
|
344
|
+
globPatterns: ["**/*.{js,css,html,ico,png,svg,woff2}"],
|
|
345
|
+
},
|
|
346
|
+
}),
|
|
347
|
+
);
|
|
348
|
+
});
|
|
311
349
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
350
|
+
// Acceptance: Scenario "Workbox globPatterns 커스텀"
|
|
351
|
+
it("uses custom workbox globPatterns when specified", async () => {
|
|
352
|
+
await createClientViteConfig({
|
|
353
|
+
...createDefaultOptions(),
|
|
354
|
+
pwa: {
|
|
355
|
+
workbox: { globPatterns: ["**/*.{js,css,html,json}"] },
|
|
356
|
+
},
|
|
316
357
|
});
|
|
358
|
+
|
|
359
|
+
expect(mockVitePWA).toHaveBeenCalledWith(
|
|
360
|
+
expect.objectContaining({
|
|
361
|
+
workbox: {
|
|
362
|
+
globPatterns: ["**/*.{js,css,html,json}"],
|
|
363
|
+
},
|
|
364
|
+
}),
|
|
365
|
+
);
|
|
317
366
|
});
|
|
318
367
|
|
|
319
|
-
// Unit: pwa empty object
|
|
320
|
-
it("
|
|
321
|
-
createClientViteConfig({
|
|
368
|
+
// Unit: pwa empty object uses all defaults
|
|
369
|
+
it("uses all defaults when pwa is empty object", async () => {
|
|
370
|
+
await createClientViteConfig({
|
|
322
371
|
...createDefaultOptions(),
|
|
323
372
|
pwa: {},
|
|
324
373
|
});
|
|
325
374
|
|
|
326
|
-
expect(
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
375
|
+
expect(mockVitePWA).toHaveBeenCalledWith(
|
|
376
|
+
expect.objectContaining({
|
|
377
|
+
manifest: expect.objectContaining({
|
|
378
|
+
name: "my-client",
|
|
379
|
+
display: "standalone",
|
|
380
|
+
}),
|
|
381
|
+
}),
|
|
382
|
+
);
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
// Unit: pwa manifest custom icons overrides default
|
|
386
|
+
it("includes custom icons in manifest and skips auto-generation", async () => {
|
|
387
|
+
const icons = [{ src: "/icon-192.png", sizes: "192x192", type: "image/png" }];
|
|
388
|
+
await createClientViteConfig({
|
|
389
|
+
...createDefaultOptions(),
|
|
390
|
+
pwa: { manifest: { icons } },
|
|
330
391
|
});
|
|
392
|
+
|
|
393
|
+
expect(mockVitePWA).toHaveBeenCalledWith(
|
|
394
|
+
expect.objectContaining({
|
|
395
|
+
manifest: expect.objectContaining({ icons }),
|
|
396
|
+
}),
|
|
397
|
+
);
|
|
398
|
+
expect(mockGeneratePwaIcons).not.toHaveBeenCalled();
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
// Acceptance: Scenario "기본 아이콘 자동 생성"
|
|
402
|
+
it("calls generatePwaIcons and includes result in manifest", async () => {
|
|
403
|
+
mockGeneratePwaIcons.mockResolvedValue([
|
|
404
|
+
{ src: "icons/icon-192x192.png", sizes: "192x192", type: "image/png" },
|
|
405
|
+
{ src: "icons/icon-512x512.png", sizes: "512x512", type: "image/png" },
|
|
406
|
+
]);
|
|
407
|
+
|
|
408
|
+
await createClientViteConfig(createDefaultOptions());
|
|
409
|
+
|
|
410
|
+
expect(mockGeneratePwaIcons).toHaveBeenCalledWith("/packages/my-client");
|
|
411
|
+
expect(mockVitePWA).toHaveBeenCalledWith(
|
|
412
|
+
expect.objectContaining({
|
|
413
|
+
manifest: expect.objectContaining({
|
|
414
|
+
icons: [
|
|
415
|
+
{ src: "icons/icon-192x192.png", sizes: "192x192", type: "image/png" },
|
|
416
|
+
{ src: "icons/icon-512x512.png", sizes: "512x512", type: "image/png" },
|
|
417
|
+
],
|
|
418
|
+
}),
|
|
419
|
+
}),
|
|
420
|
+
);
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
// Acceptance: Scenario "원본 아이콘 파일이 없을 때"
|
|
424
|
+
it("does not include icons in manifest when no source icon exists", async () => {
|
|
425
|
+
mockGeneratePwaIcons.mockResolvedValue([]);
|
|
426
|
+
|
|
427
|
+
await createClientViteConfig(createDefaultOptions());
|
|
428
|
+
|
|
429
|
+
expect(mockVitePWA).toHaveBeenCalledWith(
|
|
430
|
+
expect.objectContaining({
|
|
431
|
+
manifest: expect.not.objectContaining({ icons: expect.anything() }),
|
|
432
|
+
}),
|
|
433
|
+
);
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
// Acceptance: Scenario "pwa 필드 미설정 시 기본값"
|
|
437
|
+
it("uses default manifest values from pkgName when pwa is undefined", async () => {
|
|
438
|
+
await createClientViteConfig(createDefaultOptions());
|
|
439
|
+
|
|
440
|
+
expect(mockVitePWA).toHaveBeenCalledWith(
|
|
441
|
+
expect.objectContaining({
|
|
442
|
+
registerType: "prompt",
|
|
443
|
+
injectRegister: "script",
|
|
444
|
+
manifest: expect.objectContaining({
|
|
445
|
+
name: "my-client",
|
|
446
|
+
short_name: "my-client",
|
|
447
|
+
display: "standalone",
|
|
448
|
+
theme_color: "#ffffff",
|
|
449
|
+
background_color: "#ffffff",
|
|
450
|
+
}),
|
|
451
|
+
}),
|
|
452
|
+
);
|
|
331
453
|
});
|
|
332
454
|
|
|
333
455
|
// --- watch option (Feature 1.2: legacy dev mode) ---
|
|
334
456
|
|
|
335
457
|
// Acceptance: Scenario "watch: true 시 build.watch 설정 및 emptyOutDir: false"
|
|
336
|
-
it("sets build.watch and emptyOutDir: false when watch is true in build mode", () => {
|
|
337
|
-
const config = createClientViteConfig({
|
|
458
|
+
it("sets build.watch and emptyOutDir: false when watch is true in build mode", async () => {
|
|
459
|
+
const config = await createClientViteConfig({
|
|
338
460
|
...createDefaultOptions(),
|
|
339
461
|
mode: "build",
|
|
340
462
|
watch: true,
|
|
@@ -349,7 +471,7 @@ describe("createClientViteConfig", () => {
|
|
|
349
471
|
it("includes sdScopeWatchPlugin when watch is true with replaceDeps in build mode", async () => {
|
|
350
472
|
const { sdScopeWatchPlugin } = await import("../../src/utils/vite-scope-watch-plugin");
|
|
351
473
|
|
|
352
|
-
const config = createClientViteConfig({
|
|
474
|
+
const config = await createClientViteConfig({
|
|
353
475
|
...createDefaultOptions(),
|
|
354
476
|
mode: "build",
|
|
355
477
|
watch: true,
|
|
@@ -363,8 +485,8 @@ describe("createClientViteConfig", () => {
|
|
|
363
485
|
});
|
|
364
486
|
|
|
365
487
|
// Acceptance: Scenario "watch 미설정 시 기존 build 동작 유지"
|
|
366
|
-
it("sets emptyOutDir: true and logLevel: silent when watch is not set in build mode", () => {
|
|
367
|
-
const config = createClientViteConfig(createDefaultOptions());
|
|
488
|
+
it("sets emptyOutDir: true and logLevel: silent when watch is not set in build mode", async () => {
|
|
489
|
+
const config = await createClientViteConfig(createDefaultOptions());
|
|
368
490
|
|
|
369
491
|
expect(config.build?.emptyOutDir).toBe(true);
|
|
370
492
|
expect(config.logLevel).toBe("silent");
|
|
@@ -372,8 +494,8 @@ describe("createClientViteConfig", () => {
|
|
|
372
494
|
});
|
|
373
495
|
|
|
374
496
|
// Unit: watch: true without replaceDeps does not add sdScopeWatchPlugin
|
|
375
|
-
it("does not add sdScopeWatchPlugin in watch mode without replaceDeps", () => {
|
|
376
|
-
const config = createClientViteConfig({
|
|
497
|
+
it("does not add sdScopeWatchPlugin in watch mode without replaceDeps", async () => {
|
|
498
|
+
const config = await createClientViteConfig({
|
|
377
499
|
...createDefaultOptions(),
|
|
378
500
|
mode: "build",
|
|
379
501
|
watch: true,
|
|
@@ -385,8 +507,8 @@ describe("createClientViteConfig", () => {
|
|
|
385
507
|
});
|
|
386
508
|
|
|
387
509
|
// Unit: watch: true still sets outDir
|
|
388
|
-
it("sets outDir in watch mode", () => {
|
|
389
|
-
const config = createClientViteConfig({
|
|
510
|
+
it("sets outDir in watch mode", async () => {
|
|
511
|
+
const config = await createClientViteConfig({
|
|
390
512
|
...createDefaultOptions(),
|
|
391
513
|
mode: "build",
|
|
392
514
|
watch: true,
|
|
@@ -399,8 +521,8 @@ describe("createClientViteConfig", () => {
|
|
|
399
521
|
// --- outDir override ---
|
|
400
522
|
|
|
401
523
|
// Acceptance: Scenario "outDir 설정 시 해당 경로로 빌드 출력"
|
|
402
|
-
it("uses custom outDir when provided", () => {
|
|
403
|
-
const config = createClientViteConfig({
|
|
524
|
+
it("uses custom outDir when provided", async () => {
|
|
525
|
+
const config = await createClientViteConfig({
|
|
404
526
|
...createDefaultOptions(),
|
|
405
527
|
outDir: "/packages/my-client/.capacitor/www",
|
|
406
528
|
});
|
|
@@ -409,8 +531,8 @@ describe("createClientViteConfig", () => {
|
|
|
409
531
|
});
|
|
410
532
|
|
|
411
533
|
// Acceptance: Scenario "outDir 미설정 시 pkgDir/dist 사용"
|
|
412
|
-
it("defaults outDir to pkgDir/dist when not provided", () => {
|
|
413
|
-
const config = createClientViteConfig(createDefaultOptions());
|
|
534
|
+
it("defaults outDir to pkgDir/dist when not provided", async () => {
|
|
535
|
+
const config = await createClientViteConfig(createDefaultOptions());
|
|
414
536
|
|
|
415
537
|
expect(config.build?.outDir).toMatch(/my-client[\\/]dist$/);
|
|
416
538
|
});
|
|
@@ -418,8 +540,8 @@ describe("createClientViteConfig", () => {
|
|
|
418
540
|
// --- exclude (Feature 1.1: vite-exclude-passthrough) ---
|
|
419
541
|
|
|
420
542
|
// Acceptance: Scenario "exclude에 패키지를 지정하면 pre-bundling에서 제외된다"
|
|
421
|
-
it("sets optimizeDeps.exclude when exclude is provided", () => {
|
|
422
|
-
const config = createClientViteConfig({
|
|
543
|
+
it("sets optimizeDeps.exclude when exclude is provided", async () => {
|
|
544
|
+
const config = await createClientViteConfig({
|
|
423
545
|
...createDefaultOptions(),
|
|
424
546
|
mode: "dev",
|
|
425
547
|
exclude: ["jeep-sqlite"],
|
|
@@ -429,8 +551,8 @@ describe("createClientViteConfig", () => {
|
|
|
429
551
|
});
|
|
430
552
|
|
|
431
553
|
// Acceptance: Scenario "exclude 미설정 시 기존 동작과 동일하다"
|
|
432
|
-
it("does not set optimizeDeps.exclude when exclude is not provided", () => {
|
|
433
|
-
const config = createClientViteConfig({
|
|
554
|
+
it("does not set optimizeDeps.exclude when exclude is not provided", async () => {
|
|
555
|
+
const config = await createClientViteConfig({
|
|
434
556
|
...createDefaultOptions(),
|
|
435
557
|
mode: "dev",
|
|
436
558
|
});
|
|
@@ -442,22 +564,22 @@ describe("createClientViteConfig", () => {
|
|
|
442
564
|
it("sets optimizeDeps.exclude from exclude while sdScopeWatchPlugin handles replaceDeps", async () => {
|
|
443
565
|
const { sdScopeWatchPlugin } = await import("../../src/utils/vite-scope-watch-plugin");
|
|
444
566
|
|
|
445
|
-
const config = createClientViteConfig({
|
|
567
|
+
const config = await createClientViteConfig({
|
|
446
568
|
...createDefaultOptions(),
|
|
447
569
|
mode: "dev",
|
|
448
570
|
exclude: ["jeep-sqlite"],
|
|
449
571
|
replaceDeps: [{ packageName: "@scope/core", sourcePath: "/packages/core" }],
|
|
450
572
|
});
|
|
451
573
|
|
|
452
|
-
// Base config에 exclude
|
|
453
|
-
expect(config.optimizeDeps?.exclude).toEqual(["jeep-sqlite"]);
|
|
454
|
-
// sdScopeWatchPlugin도 호출됨
|
|
574
|
+
// Base config에 사용자 exclude + replaceDeps 패키지 모두 포함
|
|
575
|
+
expect(config.optimizeDeps?.exclude).toEqual(["jeep-sqlite", "@scope/core"]);
|
|
576
|
+
// sdScopeWatchPlugin도 호출됨
|
|
455
577
|
expect(sdScopeWatchPlugin).toHaveBeenCalled();
|
|
456
578
|
});
|
|
457
579
|
|
|
458
580
|
// Acceptance: Scenario "exclude만 있고 replaceDeps가 없으면 exclude만 제외된다"
|
|
459
|
-
it("sets optimizeDeps.exclude from exclude when no replaceDeps", () => {
|
|
460
|
-
const config = createClientViteConfig({
|
|
581
|
+
it("sets optimizeDeps.exclude from exclude when no replaceDeps", async () => {
|
|
582
|
+
const config = await createClientViteConfig({
|
|
461
583
|
...createDefaultOptions(),
|
|
462
584
|
mode: "dev",
|
|
463
585
|
exclude: ["jeep-sqlite"],
|
|
@@ -473,8 +595,8 @@ describe("createClientViteConfig", () => {
|
|
|
473
595
|
// --- framework selection (Feature 1.1: client-framework-selection) ---
|
|
474
596
|
|
|
475
597
|
// Acceptance: Scenario "Solid 프레임워크 선택"
|
|
476
|
-
it("uses solidPlugin when framework is 'solid'", () => {
|
|
477
|
-
const config = createClientViteConfig({
|
|
598
|
+
it("uses solidPlugin when framework is 'solid'", async () => {
|
|
599
|
+
const config = await createClientViteConfig({
|
|
478
600
|
...createDefaultOptions(),
|
|
479
601
|
framework: "solid",
|
|
480
602
|
});
|
|
@@ -486,16 +608,16 @@ describe("createClientViteConfig", () => {
|
|
|
486
608
|
});
|
|
487
609
|
|
|
488
610
|
// Acceptance: Scenario "framework 미지정 시 기본값"
|
|
489
|
-
it("uses sdAngularPlugin when framework is not specified", () => {
|
|
490
|
-
createClientViteConfig(createDefaultOptions());
|
|
611
|
+
it("uses sdAngularPlugin when framework is not specified", async () => {
|
|
612
|
+
await createClientViteConfig(createDefaultOptions());
|
|
491
613
|
|
|
492
614
|
expect(mockSdAngularPlugin).toHaveBeenCalled();
|
|
493
615
|
expect(mockSolidPlugin).not.toHaveBeenCalled();
|
|
494
616
|
});
|
|
495
617
|
|
|
496
618
|
// Acceptance: Scenario "Angular 프레임워크 명시 선택"
|
|
497
|
-
it("uses sdAngularPlugin when framework is 'angular'", () => {
|
|
498
|
-
createClientViteConfig({
|
|
619
|
+
it("uses sdAngularPlugin when framework is 'angular'", async () => {
|
|
620
|
+
await createClientViteConfig({
|
|
499
621
|
...createDefaultOptions(),
|
|
500
622
|
framework: "angular",
|
|
501
623
|
});
|
|
@@ -505,9 +627,9 @@ describe("createClientViteConfig", () => {
|
|
|
505
627
|
});
|
|
506
628
|
|
|
507
629
|
// Acceptance: Scenario "Solid 빌드에서 PostCSS inline 플러그인 미적용"
|
|
508
|
-
it("does not add sdPostCssInlinePlugin when framework is 'solid' even with postCssPlugins", () => {
|
|
630
|
+
it("does not add sdPostCssInlinePlugin when framework is 'solid' even with postCssPlugins", async () => {
|
|
509
631
|
const fakePlugin = { postcssPlugin: "autoprefixer" };
|
|
510
|
-
const config = createClientViteConfig({
|
|
632
|
+
const config = await createClientViteConfig({
|
|
511
633
|
...createDefaultOptions(),
|
|
512
634
|
framework: "solid",
|
|
513
635
|
postCssPlugins: [fakePlugin],
|
|
@@ -522,8 +644,8 @@ describe("createClientViteConfig", () => {
|
|
|
522
644
|
// --- legacyModule dev mode (Feature: fix-legacy-ngdevmode) ---
|
|
523
645
|
|
|
524
646
|
// Acceptance: Scenario "legacyModule: true + dev 명령 실행 시 sdAngularPlugin에 dev: true 전달"
|
|
525
|
-
it("passes dev: true to sdAngularPlugin when mode is dev with legacyModule", () => {
|
|
526
|
-
createClientViteConfig({
|
|
647
|
+
it("passes dev: true to sdAngularPlugin when mode is dev with legacyModule", async () => {
|
|
648
|
+
await createClientViteConfig({
|
|
527
649
|
...createDefaultOptions(),
|
|
528
650
|
mode: "dev",
|
|
529
651
|
legacyModule: true,
|
|
@@ -536,8 +658,8 @@ describe("createClientViteConfig", () => {
|
|
|
536
658
|
});
|
|
537
659
|
|
|
538
660
|
// Acceptance: Scenario "legacyModule dev에서 build output 설정이 적용된다"
|
|
539
|
-
it("applies build output settings when mode is dev with legacyModule", () => {
|
|
540
|
-
const config = createClientViteConfig({
|
|
661
|
+
it("applies build output settings when mode is dev with legacyModule", async () => {
|
|
662
|
+
const config = await createClientViteConfig({
|
|
541
663
|
...createDefaultOptions(),
|
|
542
664
|
mode: "dev",
|
|
543
665
|
legacyModule: true,
|
|
@@ -550,9 +672,9 @@ describe("createClientViteConfig", () => {
|
|
|
550
672
|
expect(config.build?.minify).toBe(false);
|
|
551
673
|
});
|
|
552
674
|
|
|
553
|
-
//
|
|
554
|
-
it("does not add
|
|
555
|
-
const config = createClientViteConfig({
|
|
675
|
+
// Unit: legacyModule dev에서 PWA가 추가되지 않는다
|
|
676
|
+
it("does not add VitePWA plugin when mode is dev with legacyModule", async () => {
|
|
677
|
+
const config = await createClientViteConfig({
|
|
556
678
|
...createDefaultOptions(),
|
|
557
679
|
mode: "dev",
|
|
558
680
|
legacyModule: true,
|
|
@@ -560,7 +682,7 @@ describe("createClientViteConfig", () => {
|
|
|
560
682
|
});
|
|
561
683
|
|
|
562
684
|
const plugins = config.plugins as Array<{ name: string }>;
|
|
563
|
-
const pwaPlugin = plugins.find((p) => p.name === "
|
|
685
|
+
const pwaPlugin = plugins.find((p) => p.name === "vite-plugin-pwa");
|
|
564
686
|
expect(pwaPlugin).toBeUndefined();
|
|
565
687
|
});
|
|
566
688
|
});
|