@adobe/ccweb-add-on-scaffolder 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/.c8rc.json +7 -0
  2. package/.mocharc.json +5 -0
  3. package/CODE_OF_CONDUCT.md +79 -0
  4. package/CONTRIBUTING.md +47 -0
  5. package/LICENSE +21 -0
  6. package/README.md +11 -0
  7. package/dist/app/AddOnBuilder.d.ts +72 -0
  8. package/dist/app/AddOnBuilder.d.ts.map +1 -0
  9. package/dist/app/AddOnBuilder.js +25 -0
  10. package/dist/app/AddOnScaffolder.d.ts +36 -0
  11. package/dist/app/AddOnScaffolder.d.ts.map +1 -0
  12. package/dist/app/AddOnScaffolder.js +25 -0
  13. package/dist/app/PackageBuilder.d.ts +38 -0
  14. package/dist/app/PackageBuilder.d.ts.map +1 -0
  15. package/dist/app/PackageBuilder.js +25 -0
  16. package/dist/app/TemplateAddOnBuilder.d.ts +90 -0
  17. package/dist/app/TemplateAddOnBuilder.d.ts.map +1 -0
  18. package/dist/app/TemplateAddOnBuilder.js +273 -0
  19. package/dist/app/TemplateAddOnScaffolder.d.ts +63 -0
  20. package/dist/app/TemplateAddOnScaffolder.d.ts.map +1 -0
  21. package/dist/app/TemplateAddOnScaffolder.js +130 -0
  22. package/dist/app/TemplatePackageBuilder.d.ts +49 -0
  23. package/dist/app/TemplatePackageBuilder.d.ts.map +1 -0
  24. package/dist/app/TemplatePackageBuilder.js +92 -0
  25. package/dist/app/index.d.ts +30 -0
  26. package/dist/app/index.d.ts.map +1 -0
  27. package/dist/app/index.js +30 -0
  28. package/dist/config/index.d.ts +26 -0
  29. package/dist/config/index.d.ts.map +1 -0
  30. package/dist/config/index.js +26 -0
  31. package/dist/config/inversify.config.d.ts +27 -0
  32. package/dist/config/inversify.config.d.ts.map +1 -0
  33. package/dist/config/inversify.config.js +47 -0
  34. package/dist/config/inversify.types.d.ts +31 -0
  35. package/dist/config/inversify.types.d.ts.map +1 -0
  36. package/dist/config/inversify.types.js +31 -0
  37. package/dist/constants.d.ts +33 -0
  38. package/dist/constants.d.ts.map +1 -0
  39. package/dist/constants.js +34 -0
  40. package/dist/index.d.ts +28 -0
  41. package/dist/index.d.ts.map +1 -0
  42. package/dist/index.js +28 -0
  43. package/dist/models/ScaffolderOptions.d.ts +65 -0
  44. package/dist/models/ScaffolderOptions.d.ts.map +1 -0
  45. package/dist/models/ScaffolderOptions.js +71 -0
  46. package/dist/models/index.d.ts +25 -0
  47. package/dist/models/index.d.ts.map +1 -0
  48. package/dist/models/index.js +25 -0
  49. package/dist/tsconfig.tsbuildinfo +1 -0
  50. package/dist/validators/AddOnTemplateValidator.d.ts +46 -0
  51. package/dist/validators/AddOnTemplateValidator.d.ts.map +1 -0
  52. package/dist/validators/AddOnTemplateValidator.js +78 -0
  53. package/dist/validators/TemplateValidator.d.ts +35 -0
  54. package/dist/validators/TemplateValidator.d.ts.map +1 -0
  55. package/dist/validators/TemplateValidator.js +25 -0
  56. package/dist/validators/index.d.ts +26 -0
  57. package/dist/validators/index.d.ts.map +1 -0
  58. package/dist/validators/index.js +26 -0
  59. package/package.json +57 -0
  60. package/src/app/AddOnBuilder.ts +79 -0
  61. package/src/app/AddOnScaffolder.ts +37 -0
  62. package/src/app/PackageBuilder.ts +40 -0
  63. package/src/app/TemplateAddOnBuilder.ts +319 -0
  64. package/src/app/TemplateAddOnScaffolder.ts +153 -0
  65. package/src/app/TemplatePackageBuilder.ts +102 -0
  66. package/src/app/index.ts +30 -0
  67. package/src/config/index.ts +26 -0
  68. package/src/config/inversify.config.ts +58 -0
  69. package/src/config/inversify.types.ts +31 -0
  70. package/src/constants.ts +36 -0
  71. package/src/index.ts +28 -0
  72. package/src/models/ScaffolderOptions.ts +86 -0
  73. package/src/models/index.ts +25 -0
  74. package/src/test/app/TemplateAddOnBuilder.spec.ts +1391 -0
  75. package/src/test/app/TemplateAddOnScaffolder.spec.ts +272 -0
  76. package/src/test/app/TemplatePackageBuilder.spec.ts +332 -0
  77. package/src/test/app/data/first-test-app/.template/template.json +10 -0
  78. package/src/test/app/data/first-test-app/package.json +19 -0
  79. package/src/test/app/data/first-test-app/src/manifest.json +21 -0
  80. package/src/test/app/data/first_test_app/.template/template.json +10 -0
  81. package/src/test/app/data/first_test_app/package.json +19 -0
  82. package/src/test/app/data/first_test_app/src/manifest.json +21 -0
  83. package/src/test/app/data/second-test-app/package.json +19 -0
  84. package/src/test/app/data/second-test-app/src/manifest.json +33 -0
  85. package/src/test/app/data/third-test-app/.template/template.json +10 -0
  86. package/src/test/app/data/third-test-app/package.json +19 -0
  87. package/src/test/app/data/third-test-app/src/manifest.json +23 -0
  88. package/src/test/models/ScaffolderOptions.spec.ts +61 -0
  89. package/src/test/validators/AppTemplateValidator.spec.ts +98 -0
  90. package/src/validators/AddOnTemplateValidator.ts +79 -0
  91. package/src/validators/TemplateValidator.ts +35 -0
  92. package/src/validators/index.ts +26 -0
  93. package/tsconfig.json +28 -0
@@ -0,0 +1,1391 @@
1
+ /********************************************************************************
2
+ * MIT License
3
+
4
+ * © Copyright 2023 Adobe. All rights reserved.
5
+
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ ********************************************************************************/
24
+
25
+ import type { Logger } from "@adobe/ccweb-add-on-core";
26
+ import { PackageJson, TemplateJson, getJSONString } from "@adobe/ccweb-add-on-core";
27
+ import { AddOnManifest, EntrypointType } from "@adobe/ccweb-add-on-manifest";
28
+ import chai, { assert } from "chai";
29
+ import chaiAsPromised from "chai-as-promised";
30
+ import fs from "fs-extra";
31
+ import "mocha";
32
+ import { createRequire } from "module";
33
+ import os from "os";
34
+ import path from "path";
35
+ import type { SinonSandbox } from "sinon";
36
+ import sinon from "sinon";
37
+ import type { StubbedInstance } from "ts-sinon";
38
+ import { stubInterface } from "ts-sinon";
39
+ import { fileURLToPath } from "url";
40
+ import type { AddOnBuilder } from "../../app/index.js";
41
+ import { TemplateAddOnBuilder } from "../../app/index.js";
42
+ import { MANIFEST_JSON, PACKAGE_JSON } from "../../constants.js";
43
+ import { ScaffolderOptions } from "../../models/ScaffolderOptions.js";
44
+
45
+ chai.use(chaiAsPromised);
46
+
47
+ describe("TemplateAddOnBuilder", () => {
48
+ const __filename = fileURLToPath(import.meta.url);
49
+ const __dirname = path.dirname(__filename);
50
+ const __require = createRequire(import.meta.url);
51
+
52
+ const testAppPackageJson = __require("./data/first-test-app/package.json");
53
+
54
+ let logger: StubbedInstance<Logger>;
55
+
56
+ beforeEach(() => {
57
+ logger = stubInterface<Logger>();
58
+ });
59
+
60
+ describe("getPackageJson", () => {
61
+ it("should return PackageJson from package.json in Add-on directory.", () => {
62
+ const options = new ScaffolderOptions(
63
+ `${__dirname}/data/first-test-app`,
64
+ "first-test-app",
65
+ EntrypointType.PANEL,
66
+ `${__dirname}/data`,
67
+ "react-javascript",
68
+ false
69
+ );
70
+
71
+ const expectedPacakgeJson = new PackageJson(testAppPackageJson);
72
+
73
+ const addOnBuilder: AddOnBuilder = new TemplateAddOnBuilder(options, logger);
74
+ const packageJson = addOnBuilder.getPackageJson();
75
+
76
+ assert.deepEqual(packageJson, expectedPacakgeJson);
77
+ });
78
+ });
79
+
80
+ describe("getTemplateJson", () => {
81
+ let sandbox: SinonSandbox;
82
+ beforeEach(() => {
83
+ sandbox = sinon.createSandbox();
84
+ });
85
+
86
+ afterEach(() => {
87
+ sandbox.restore();
88
+ });
89
+
90
+ it("should return empty TemplateJson when template.json does not exist.", () => {
91
+ const options = new ScaffolderOptions(
92
+ `${__dirname}/data/first-test-app`,
93
+ "first-test-app",
94
+ EntrypointType.PANEL,
95
+ `${__dirname}/data`,
96
+ `${__dirname}/data/first-test-app`,
97
+ false
98
+ );
99
+
100
+ const expectedTemplateJson = new TemplateJson({});
101
+
102
+ const addOnBuilder: AddOnBuilder = new TemplateAddOnBuilder(options, logger);
103
+ const templateJson = addOnBuilder.getTemplateJson();
104
+
105
+ assert.deepEqual(templateJson, expectedTemplateJson);
106
+ });
107
+
108
+ it("should return TemplateJson when template.json exists.", () => {
109
+ const options = new ScaffolderOptions(
110
+ `${__dirname}/data/first-test-app`,
111
+ "first-test-app",
112
+ EntrypointType.PANEL,
113
+ `${__dirname}/data`,
114
+ "shared-storage-javascript",
115
+ false
116
+ );
117
+
118
+ sandbox.stub(process, "cwd").returns(options.addOnDirectory);
119
+
120
+ const expectedTemplateJson = new TemplateJson({
121
+ scripts: {
122
+ clean: "ccweb-add-on-scripts clean",
123
+ build: "ccweb-add-on-scripts build",
124
+ start: "ccweb-add-on-scripts start"
125
+ },
126
+ devDependencies: {
127
+ prettier: "2.6.0"
128
+ }
129
+ });
130
+
131
+ const addOnBuilder: AddOnBuilder = new TemplateAddOnBuilder(options, logger);
132
+ const templateJson = addOnBuilder.getTemplateJson();
133
+
134
+ assert.deepEqual(templateJson, expectedTemplateJson);
135
+ });
136
+ });
137
+
138
+ describe("getDevDependenciesToInstall", () => {
139
+ it("should return empty set when TemplateJson does not contain devDependencies.", () => {
140
+ const options = new ScaffolderOptions(
141
+ `${__dirname}/data/first-test-app`,
142
+ "first-test-app",
143
+ EntrypointType.PANEL,
144
+ `${__dirname}/data`,
145
+ `${__dirname}/data/first-test-app`,
146
+ false
147
+ );
148
+
149
+ const addOnBuilder: AddOnBuilder = new TemplateAddOnBuilder(options, logger);
150
+ const devDependencies = addOnBuilder.getDevDependenciesToInstall(new TemplateJson({}));
151
+
152
+ assert.equal(devDependencies.size, 0);
153
+ });
154
+
155
+ it("should return a set of installable devDependencies from TemplateJson.", () => {
156
+ const options = new ScaffolderOptions(
157
+ `${__dirname}/data/first-test-app`,
158
+ "first-test-app",
159
+ EntrypointType.PANEL,
160
+ `${__dirname}/data`,
161
+ "react-javascript",
162
+ false
163
+ );
164
+
165
+ const templateJson = new TemplateJson({
166
+ devDependencies: {
167
+ a: "1.0.0",
168
+ b: "2.0.0",
169
+ c: "3.0.0"
170
+ }
171
+ });
172
+
173
+ const expectedDevDependencies = new Set(["a@1.0.0", "b@2.0.0", "c@3.0.0"]);
174
+
175
+ const addOnBuilder: AddOnBuilder = new TemplateAddOnBuilder(options, logger);
176
+ const devDependencies = addOnBuilder.getDevDependenciesToInstall(templateJson);
177
+
178
+ assert.deepEqual(devDependencies, expectedDevDependencies);
179
+ });
180
+ });
181
+
182
+ describe("getDependenciesToInstall", () => {
183
+ it("should return empty set when TemplateJson does not contain dependencies.", () => {
184
+ const options = new ScaffolderOptions(
185
+ `${__dirname}/data/first-test-app`,
186
+ "first-test-app",
187
+ EntrypointType.PANEL,
188
+ `${__dirname}/data`,
189
+ `${__dirname}/data/first-test-app`,
190
+ false
191
+ );
192
+
193
+ const addOnBuilder: AddOnBuilder = new TemplateAddOnBuilder(options, logger);
194
+ const dependencies = addOnBuilder.getDependenciesToInstall(new TemplateJson({}));
195
+
196
+ assert.equal(dependencies.size, 0);
197
+ });
198
+
199
+ it("should return a set of installable dependencies from TemplateJson.", () => {
200
+ const options = new ScaffolderOptions(
201
+ `${__dirname}/data/first-test-app`,
202
+ "first-test-app",
203
+ EntrypointType.PANEL,
204
+ `${__dirname}/data`,
205
+ "react-javascript",
206
+ false
207
+ );
208
+
209
+ const templateJson = new TemplateJson({
210
+ dependencies: {
211
+ a: "1.0.0",
212
+ b: "2.0.0",
213
+ c: "3.0.0"
214
+ }
215
+ });
216
+
217
+ const expectedDependencies = new Set(["a@1.0.0", "b@2.0.0", "c@3.0.0"]);
218
+
219
+ const addOnBuilder: AddOnBuilder = new TemplateAddOnBuilder(options, logger);
220
+ const dependencies = addOnBuilder.getDependenciesToInstall(templateJson);
221
+
222
+ assert.deepEqual(dependencies, expectedDependencies);
223
+ });
224
+ });
225
+
226
+ describe("build()", () => {
227
+ const additionalInfo = {
228
+ sourceId: "fakeAddOnSource",
229
+ privileged: true,
230
+ isDeveloperAddOn: false
231
+ };
232
+ describe("_updateReadMe", () => {
233
+ let sandbox: SinonSandbox;
234
+ beforeEach(() => {
235
+ sandbox = sinon.createSandbox();
236
+ });
237
+
238
+ afterEach(() => {
239
+ sandbox.restore();
240
+ });
241
+
242
+ const packageJson = new PackageJson({ testAppPackageJson }).toJSON();
243
+
244
+ it("should return if README.md does not exist.", () => {
245
+ const options = new ScaffolderOptions(
246
+ `${__dirname}/data/first-test-app`,
247
+ "first-test-app",
248
+ EntrypointType.PANEL,
249
+ `${__dirname}/data`,
250
+ "javascript",
251
+ false
252
+ );
253
+
254
+ sandbox.stub(process, "cwd").returns(options.addOnDirectory);
255
+
256
+ // write package.json stub.
257
+ const writeFileStub = sandbox.stub(fs, "writeFileSync");
258
+ writeFileStub.withArgs(path.join(options.addOnDirectory, PACKAGE_JSON), packageJson + os.EOL).returns();
259
+
260
+ // _updateReadMe() stub.
261
+ const existsStub = sandbox.stub(fs, "existsSync");
262
+ existsStub.withArgs(path.join(options.addOnDirectory, "README.md")).returns(false);
263
+ const renameSpy = sandbox.spy(fs, "renameSync");
264
+
265
+ // _copyTemplateFiles() stubs.
266
+ const templateRootDirectory = path.join(__dirname, "data", "first-test-app", ".template");
267
+ const templateContentDirectory = path.join(templateRootDirectory, "template");
268
+ existsStub.withArgs(templateContentDirectory).returns(true);
269
+
270
+ const copyStub = sandbox.stub(fs, "copySync");
271
+ copyStub.withArgs(templateContentDirectory, options.addOnDirectory).returns();
272
+
273
+ // _updateGitIgnore() stubs.
274
+ existsStub.withArgs(path.join(options.addOnDirectory, ".gitignore")).returns(false);
275
+
276
+ const moveStub = sandbox.stub(fs, "moveSync");
277
+ moveStub
278
+ .withArgs(
279
+ path.join(options.addOnDirectory, "gitignore"),
280
+ path.join(options.addOnDirectory, ".gitignore")
281
+ )
282
+ .returns();
283
+
284
+ // _updateManifest() stubs.
285
+ const manifestJsonPath = path.join(options.addOnDirectory, "src", MANIFEST_JSON);
286
+ existsStub.withArgs(manifestJsonPath).returns(false);
287
+
288
+ // _removeTemplateTempFiles() stubs.
289
+ sandbox.stub(fs, "removeSync").returns();
290
+ const { manifest } = AddOnManifest.createManifest({
291
+ manifest: {
292
+ testId: "first-test-app",
293
+ name: "first test app",
294
+ version: "1.0.1",
295
+ manifestVersion: 2,
296
+ requirements: {
297
+ apps: [
298
+ {
299
+ name: "Express",
300
+ apiVersion: 1
301
+ }
302
+ ]
303
+ },
304
+ entryPoints: [
305
+ {
306
+ type: EntrypointType.PANEL,
307
+ id: "first-test-app",
308
+ main: "index.html"
309
+ }
310
+ ]
311
+ },
312
+ additionalInfo
313
+ });
314
+ writeFileStub
315
+ .withArgs(manifestJsonPath, getJSONString(manifest!.manifestProperties) + os.EOL)
316
+ .returns();
317
+
318
+ const addOnBuilder: AddOnBuilder = new TemplateAddOnBuilder(options, logger);
319
+ addOnBuilder.build(packageJson);
320
+
321
+ assert.equal(renameSpy.callCount, 0);
322
+ });
323
+
324
+ it("should rename existing README.md to README.OLD.md if the former exists.", () => {
325
+ const options = new ScaffolderOptions(
326
+ `${__dirname}/data/first-test-app`,
327
+ "first-test-app",
328
+ EntrypointType.PANEL,
329
+ `${__dirname}/data`,
330
+ "react-javascript",
331
+ false
332
+ );
333
+
334
+ sandbox.stub(process, "cwd").returns(options.addOnDirectory);
335
+
336
+ // write package.json stub.
337
+ const writeFileStub = sandbox.stub(fs, "writeFileSync");
338
+ writeFileStub.withArgs(path.join(options.addOnDirectory, PACKAGE_JSON), packageJson + os.EOL).returns();
339
+
340
+ // _updateReadMe() stub.
341
+ const existsStub = sandbox.stub(fs, "existsSync");
342
+ existsStub.withArgs(path.join(options.addOnDirectory, "README.md")).returns(true);
343
+
344
+ const renameStub = sandbox.stub(fs, "renameSync");
345
+ renameStub.returns();
346
+
347
+ // _copyTemplateFiles() stubs.
348
+ const templateRootDirectory = path.join(__dirname, "data", "first-test-app", ".template");
349
+ const templateContentDirectory = path.join(templateRootDirectory, "template");
350
+ existsStub.withArgs(templateContentDirectory).returns(true);
351
+
352
+ const copyStub = sandbox.stub(fs, "copySync");
353
+ copyStub.withArgs(templateContentDirectory, options.addOnDirectory).returns();
354
+
355
+ // _updateGitIgnore() stubs.
356
+ existsStub.withArgs(path.join(options.addOnDirectory, ".gitignore")).returns(false);
357
+
358
+ const moveStub = sandbox.stub(fs, "moveSync");
359
+ moveStub
360
+ .withArgs(
361
+ path.join(options.addOnDirectory, "gitignore"),
362
+ path.join(options.addOnDirectory, ".gitignore")
363
+ )
364
+ .returns();
365
+
366
+ // _updateManifest() stubs.
367
+ const manifestJsonPath = path.join(options.addOnDirectory, "src", MANIFEST_JSON);
368
+ existsStub.withArgs(manifestJsonPath).returns(false);
369
+
370
+ // _removeTemplateTempFiles() stubs.
371
+ sandbox.stub(fs, "removeSync").returns();
372
+
373
+ const { manifest } = AddOnManifest.createManifest({
374
+ manifest: {
375
+ testId: "first-test-app",
376
+ name: "first test app",
377
+ version: "1.0.1",
378
+ manifestVersion: 2,
379
+ requirements: {
380
+ apps: [
381
+ {
382
+ name: "Express",
383
+ apiVersion: 1
384
+ }
385
+ ]
386
+ },
387
+ entryPoints: [
388
+ {
389
+ type: EntrypointType.PANEL,
390
+ id: "first-test-app",
391
+ main: "index.html"
392
+ }
393
+ ]
394
+ },
395
+ additionalInfo
396
+ });
397
+
398
+ writeFileStub
399
+ .withArgs(manifestJsonPath, getJSONString(manifest!.manifestProperties) + os.EOL)
400
+ .returns();
401
+
402
+ const addOnBuilder: AddOnBuilder = new TemplateAddOnBuilder(options, logger);
403
+ addOnBuilder.build(packageJson);
404
+
405
+ assert.equal(renameStub.callCount, 1);
406
+ assert.equal(
407
+ renameStub.calledWith(
408
+ path.join(options.addOnDirectory, "README.md"),
409
+ path.join(options.addOnDirectory, "README.OLD.md")
410
+ ),
411
+ true
412
+ );
413
+ });
414
+ });
415
+
416
+ describe("_copyTemplateFiles", () => {
417
+ let sandbox: SinonSandbox;
418
+ beforeEach(() => {
419
+ sandbox = sinon.createSandbox();
420
+ });
421
+
422
+ afterEach(() => {
423
+ sandbox.restore();
424
+ });
425
+
426
+ const packageJson = new PackageJson({ testAppPackageJson }).toJSON();
427
+
428
+ it("should exit if template content directory does not exist.", () => {
429
+ const options = new ScaffolderOptions(
430
+ `${__dirname}/data/first-test-app`,
431
+ "first-test-app",
432
+ EntrypointType.PANEL,
433
+ `${__dirname}/data`,
434
+ "react-javascript",
435
+ false
436
+ );
437
+
438
+ sandbox.stub(process, "cwd").returns(options.addOnDirectory);
439
+
440
+ // write package.json stub.
441
+ const writeFileStub = sandbox.stub(fs, "writeFileSync");
442
+ writeFileStub.withArgs(path.join(options.addOnDirectory, PACKAGE_JSON), packageJson + os.EOL).returns();
443
+
444
+ // _updateReadMe() stub.
445
+ const existsStub = sandbox.stub(fs, "existsSync");
446
+ existsStub.withArgs(path.join(options.addOnDirectory, "README.md")).returns(false);
447
+
448
+ // _copyTemplateFiles() stubs.
449
+ const templateRootDirectory = path.join(__dirname, "data", "first-test-app", ".template");
450
+ const templateContentDirectory = path.join(templateRootDirectory, "template");
451
+ existsStub.withArgs(templateContentDirectory).returns(false);
452
+
453
+ const processExitStub = sandbox.stub(process, "exit");
454
+
455
+ // _updateGitIgnore() stubs.
456
+ existsStub.withArgs(path.join(options.addOnDirectory, ".gitignore")).returns(false);
457
+
458
+ const moveStub = sandbox.stub(fs, "moveSync");
459
+ moveStub
460
+ .withArgs(
461
+ path.join(options.addOnDirectory, "gitignore"),
462
+ path.join(options.addOnDirectory, ".gitignore")
463
+ )
464
+ .returns();
465
+
466
+ // _updateManifest() stubs.
467
+ const manifestJsonPath = path.join(options.addOnDirectory, "src", MANIFEST_JSON);
468
+ existsStub.withArgs(manifestJsonPath).returns(false);
469
+
470
+ // _removeTemplateTempFiles() stubs.
471
+ sandbox.stub(fs, "removeSync").returns();
472
+
473
+ const { manifest } = AddOnManifest.createManifest({
474
+ manifest: {
475
+ testId: "first-test-app",
476
+ name: "first test app",
477
+ version: "1.0.1",
478
+ manifestVersion: 2,
479
+ requirements: {
480
+ apps: [
481
+ {
482
+ name: "Express",
483
+ apiVersion: 1
484
+ }
485
+ ]
486
+ },
487
+ entryPoints: [
488
+ {
489
+ type: EntrypointType.PANEL,
490
+ id: "first-test-app",
491
+ main: "index.html"
492
+ }
493
+ ]
494
+ },
495
+ additionalInfo
496
+ });
497
+
498
+ writeFileStub
499
+ .withArgs(manifestJsonPath, getJSONString(manifest!.manifestProperties) + os.EOL)
500
+ .returns();
501
+
502
+ const addOnBuilder: AddOnBuilder = new TemplateAddOnBuilder(options, logger);
503
+ addOnBuilder.build(packageJson);
504
+
505
+ assert.equal(logger.warning.callCount, 1);
506
+ assert.equal(logger.warning.calledWith(`Could not locate template: ${templateContentDirectory}`), true);
507
+
508
+ assert.equal(processExitStub.callCount, 1);
509
+ assert.equal(processExitStub.calledWith(1), true);
510
+ });
511
+
512
+ it("should copy template directory contents.", () => {
513
+ const options = new ScaffolderOptions(
514
+ `${__dirname}/data/first-test-app`,
515
+ "first-test-app",
516
+ EntrypointType.PANEL,
517
+ `${__dirname}/data`,
518
+ "react-javascript",
519
+ false
520
+ );
521
+
522
+ sandbox.stub(process, "cwd").returns(options.addOnDirectory);
523
+
524
+ // write package.json stub.
525
+ const writeFileStub = sandbox.stub(fs, "writeFileSync");
526
+ writeFileStub.withArgs(path.join(options.addOnDirectory, PACKAGE_JSON), packageJson + os.EOL).returns();
527
+
528
+ // _updateReadMe() stub.
529
+ const existsStub = sandbox.stub(fs, "existsSync");
530
+ existsStub.withArgs(path.join(options.addOnDirectory, "README.md")).returns(false);
531
+
532
+ // _copyTemplateFiles() stubs.
533
+ const templateRootDirectory = path.join(__dirname, "data", "first-test-app", ".template");
534
+ const templateContentDirectory = path.join(templateRootDirectory, "template");
535
+ existsStub.withArgs(templateContentDirectory).returns(true);
536
+
537
+ const copyStub = sandbox.stub(fs, "copySync");
538
+ copyStub.withArgs(templateContentDirectory, options.addOnDirectory).returns();
539
+
540
+ // _updateGitIgnore() stubs.
541
+ existsStub.withArgs(path.join(options.addOnDirectory, ".gitignore")).returns(false);
542
+
543
+ const moveStub = sandbox.stub(fs, "moveSync");
544
+ moveStub
545
+ .withArgs(
546
+ path.join(options.addOnDirectory, "gitignore"),
547
+ path.join(options.addOnDirectory, ".gitignore")
548
+ )
549
+ .returns();
550
+
551
+ // _updateManifest() stubs.
552
+ const manifestJsonPath = path.join(options.addOnDirectory, "src", MANIFEST_JSON);
553
+ existsStub.withArgs(manifestJsonPath).returns(false);
554
+
555
+ // _removeTemplateTempFiles() stubs.
556
+ sandbox.stub(fs, "removeSync").returns();
557
+
558
+ const { manifest } = AddOnManifest.createManifest({
559
+ manifest: {
560
+ testId: "first-test-app",
561
+ name: "first test app",
562
+ version: "1.0.1",
563
+ manifestVersion: 2,
564
+ requirements: {
565
+ apps: [
566
+ {
567
+ name: "Express",
568
+ apiVersion: 1
569
+ }
570
+ ]
571
+ },
572
+ entryPoints: [
573
+ {
574
+ type: EntrypointType.PANEL,
575
+ id: "first-test-app",
576
+ main: "index.html"
577
+ }
578
+ ]
579
+ },
580
+ additionalInfo
581
+ });
582
+
583
+ writeFileStub
584
+ .withArgs(manifestJsonPath, getJSONString(manifest!.manifestProperties) + os.EOL)
585
+ .returns();
586
+
587
+ const addOnBuilder: AddOnBuilder = new TemplateAddOnBuilder(options, logger);
588
+ addOnBuilder.build(packageJson);
589
+
590
+ assert.equal(copyStub.callCount, 1);
591
+ assert.equal(copyStub.calledWith(templateContentDirectory, options.addOnDirectory), true);
592
+ });
593
+ });
594
+
595
+ describe("_updateGitIgnore", () => {
596
+ let sandbox: SinonSandbox;
597
+ beforeEach(() => {
598
+ sandbox = sinon.createSandbox();
599
+ });
600
+
601
+ afterEach(() => {
602
+ sandbox.restore();
603
+ });
604
+
605
+ const packageJson = new PackageJson({ testAppPackageJson }).toJSON();
606
+
607
+ it("should move gitignore to .gitignore if .gitignore does not exist in Add-on diectory.", () => {
608
+ const options = new ScaffolderOptions(
609
+ `${__dirname}/data/second-test-app`,
610
+ "second-test-app",
611
+ EntrypointType.PANEL,
612
+ `${__dirname}/data`,
613
+ "javascript",
614
+ false
615
+ );
616
+
617
+ sandbox.stub(process, "cwd").returns(options.addOnDirectory);
618
+
619
+ // write package.json stub.
620
+ const writeFileStub = sandbox.stub(fs, "writeFileSync");
621
+ writeFileStub.withArgs(path.join(options.addOnDirectory, PACKAGE_JSON), packageJson + os.EOL).returns();
622
+
623
+ // _updateReadMe() stub.
624
+ const existsStub = sandbox.stub(fs, "existsSync");
625
+ existsStub.withArgs(path.join(options.addOnDirectory, "README.md")).returns(false);
626
+
627
+ // _copyTemplateFiles() stubs.
628
+ const templateRootDirectory = path.join(__dirname, "data", options.addOnName, ".template");
629
+ const templateContentDirectory = path.join(templateRootDirectory, "template");
630
+ existsStub.withArgs(templateContentDirectory).returns(true);
631
+
632
+ const copyStub = sandbox.stub(fs, "copySync");
633
+ copyStub.withArgs(templateContentDirectory, options.addOnDirectory).returns();
634
+
635
+ // _updateGitIgnore() stubs.
636
+ existsStub.withArgs(path.join(options.addOnDirectory, ".gitignore")).returns(false);
637
+ const moveStub = sandbox.stub(fs, "moveSync");
638
+ moveStub
639
+ .withArgs(
640
+ path.join(options.addOnDirectory, "gitignore"),
641
+ path.join(options.addOnDirectory, ".gitignore")
642
+ )
643
+ .returns();
644
+
645
+ // _updateManifest() stubs.
646
+ const manifestJsonPath = path.join(options.addOnDirectory, "src", MANIFEST_JSON);
647
+ existsStub.withArgs(manifestJsonPath).returns(false);
648
+
649
+ // _removeTemplateTempFiles() stubs.
650
+ sandbox.stub(fs, "removeSync").returns();
651
+
652
+ const { manifest } = AddOnManifest.createManifest({
653
+ manifest: {
654
+ testId: options.addOnName,
655
+ name: "Second Test App",
656
+ version: "1.0.1",
657
+ manifestVersion: 2,
658
+ requirements: {
659
+ apps: [
660
+ {
661
+ name: "Express",
662
+ apiVersion: 1
663
+ }
664
+ ]
665
+ },
666
+ entryPoints: [
667
+ {
668
+ type: EntrypointType.PANEL,
669
+ id: "first-test-app",
670
+ main: "index.html"
671
+ }
672
+ ]
673
+ },
674
+ additionalInfo
675
+ });
676
+
677
+ writeFileStub
678
+ .withArgs(manifestJsonPath, getJSONString(manifest!.manifestProperties) + os.EOL)
679
+ .returns();
680
+
681
+ const addOnBuilder: AddOnBuilder = new TemplateAddOnBuilder(options, logger);
682
+ addOnBuilder.build(packageJson);
683
+
684
+ assert.equal(moveStub.callCount, 1);
685
+ assert.equal(
686
+ moveStub.calledWith(
687
+ path.join(options.addOnDirectory, "gitignore"),
688
+ path.join(options.addOnDirectory, ".gitignore")
689
+ ),
690
+ true
691
+ );
692
+ });
693
+
694
+ it("should merge .gitignore files if .gitignore exists in ap directory.", () => {
695
+ const options = new ScaffolderOptions(
696
+ `${__dirname}/data/first-test-app`,
697
+ "first-test-app",
698
+ EntrypointType.PANEL,
699
+ `${__dirname}/data`,
700
+ "react-javascript",
701
+ false
702
+ );
703
+
704
+ sandbox.stub(process, "cwd").returns(options.addOnDirectory);
705
+
706
+ // write package.json stub.
707
+ const writeFileStub = sandbox.stub(fs, "writeFileSync");
708
+ writeFileStub.withArgs(path.join(options.addOnDirectory, PACKAGE_JSON), packageJson + os.EOL).returns();
709
+
710
+ // _updateReadMe() stub.
711
+ const existsStub = sandbox.stub(fs, "existsSync");
712
+ existsStub.withArgs(path.join(options.addOnDirectory, "README.md")).returns(false);
713
+
714
+ // _copyTemplateFiles() stubs.
715
+ const templateRootDirectory = path.join(__dirname, "data", options.addOnName, ".template");
716
+ const templateContentDirectory = path.join(templateRootDirectory, "template");
717
+ existsStub.withArgs(templateContentDirectory).returns(true);
718
+
719
+ const copyStub = sandbox.stub(fs, "copySync");
720
+ copyStub.withArgs(templateContentDirectory, options.addOnDirectory).returns();
721
+
722
+ // _updateGitIgnore() stubs.
723
+ existsStub.withArgs(path.join(options.addOnDirectory, ".gitignore")).returns(true);
724
+
725
+ const readFileStub = sandbox.stub(fs, "readFileSync");
726
+ const appendFileStub = sandbox.stub(fs, "appendFileSync");
727
+ const unlinkStub = sandbox.stub(fs, "unlinkSync");
728
+
729
+ const data = stubInterface<Buffer>();
730
+ readFileStub.withArgs(path.join(options.addOnDirectory, "gitignore")).returns(data);
731
+ appendFileStub.withArgs(path.join(options.addOnDirectory, ".gitignore"), data).returns();
732
+ unlinkStub.withArgs(path.join(options.addOnDirectory, "gitignore")).returns();
733
+
734
+ // _updateManifest() stubs.
735
+ const manifestJsonPath = path.join(options.addOnDirectory, "src", MANIFEST_JSON);
736
+ existsStub.withArgs(manifestJsonPath).returns(false);
737
+
738
+ // _removeTemplateTempFiles() stubs.
739
+ sandbox.stub(fs, "removeSync").returns();
740
+
741
+ const { manifest } = AddOnManifest.createManifest({
742
+ manifest: {
743
+ testId: "first-test-app",
744
+ name: "first test app",
745
+ version: "1.0.1",
746
+ manifestVersion: 2,
747
+ requirements: {
748
+ apps: [
749
+ {
750
+ name: "Express",
751
+ apiVersion: 1
752
+ }
753
+ ]
754
+ },
755
+ entryPoints: [
756
+ {
757
+ type: EntrypointType.PANEL,
758
+ id: "first-test-app",
759
+ main: "index.html"
760
+ }
761
+ ]
762
+ },
763
+ additionalInfo
764
+ });
765
+
766
+ writeFileStub
767
+ .withArgs(manifestJsonPath, getJSONString(manifest!.manifestProperties) + os.EOL)
768
+ .returns();
769
+
770
+ const addOnBuilder: AddOnBuilder = new TemplateAddOnBuilder(options, logger);
771
+ addOnBuilder.build(packageJson);
772
+
773
+ assert.equal(readFileStub.callCount, 1);
774
+ assert.equal(readFileStub.calledWith(path.join(options.addOnDirectory, "gitignore")), true);
775
+
776
+ assert.equal(appendFileStub.callCount, 1);
777
+ assert.equal(appendFileStub.calledWith(path.join(options.addOnDirectory, ".gitignore"), data), true);
778
+
779
+ assert.equal(unlinkStub.callCount, 1);
780
+ assert.equal(unlinkStub.calledWith(path.join(options.addOnDirectory, "gitignore")), true);
781
+ });
782
+ });
783
+
784
+ describe("_updateManifest", () => {
785
+ let sandbox: SinonSandbox;
786
+ beforeEach(() => {
787
+ sandbox = sinon.createSandbox();
788
+ });
789
+
790
+ afterEach(() => {
791
+ sandbox.restore();
792
+ });
793
+
794
+ const packageJson = new PackageJson({ testAppPackageJson }).toJSON();
795
+
796
+ it("should create new manifest.json if it does not exist in Add-on diectory.", () => {
797
+ const options = new ScaffolderOptions(
798
+ `${__dirname}/data/first-test-app`,
799
+ "first-test-app",
800
+ EntrypointType.PANEL,
801
+ `${__dirname}/data`,
802
+ "react-javascript",
803
+ false
804
+ );
805
+
806
+ sandbox.stub(process, "cwd").returns(options.addOnDirectory);
807
+
808
+ // write package.json stub.
809
+ const writeFileStub = sandbox.stub(fs, "writeFileSync");
810
+ writeFileStub.withArgs(path.join(options.addOnDirectory, PACKAGE_JSON), packageJson + os.EOL).returns();
811
+
812
+ // _updateReadMe() stub.
813
+ const existsStub = sandbox.stub(fs, "existsSync");
814
+ existsStub.withArgs(path.join(options.addOnDirectory, "README.md")).returns(false);
815
+
816
+ // _copyTemplateFiles() stubs.
817
+ const templateRootDirectory = path.join(__dirname, "data", "first-test-app", ".template");
818
+ const templateContentDirectory = path.join(templateRootDirectory, "template");
819
+ existsStub.withArgs(templateContentDirectory).returns(true);
820
+
821
+ const copyStub = sandbox.stub(fs, "copySync");
822
+ copyStub.withArgs(templateContentDirectory, options.addOnDirectory).returns();
823
+
824
+ // _updateGitIgnore() stubs.
825
+ existsStub.withArgs(path.join(options.addOnDirectory, ".gitignore")).returns(false);
826
+
827
+ const moveStub = sandbox.stub(fs, "moveSync");
828
+ moveStub
829
+ .withArgs(
830
+ path.join(options.addOnDirectory, "gitignore"),
831
+ path.join(options.addOnDirectory, ".gitignore")
832
+ )
833
+ .returns();
834
+
835
+ // _updateManifest() stubs.
836
+ const manifestJsonPath = path.join(options.addOnDirectory, "src", MANIFEST_JSON);
837
+ existsStub.withArgs(manifestJsonPath).returns(false);
838
+
839
+ // _removeTemplateTempFiles() stubs.
840
+ sandbox.stub(fs, "removeSync").returns();
841
+
842
+ const { manifest } = AddOnManifest.createManifest({
843
+ manifest: {
844
+ testId: "first-test-app",
845
+ name: "first test app",
846
+ version: "1.0.1",
847
+ manifestVersion: 2,
848
+ requirements: {
849
+ apps: [
850
+ {
851
+ name: "Express",
852
+ apiVersion: 1
853
+ }
854
+ ]
855
+ },
856
+ entryPoints: [
857
+ {
858
+ type: EntrypointType.PANEL,
859
+ id: "first-test-app",
860
+ main: "index.html"
861
+ }
862
+ ]
863
+ },
864
+ additionalInfo
865
+ });
866
+
867
+ writeFileStub
868
+ .withArgs(manifestJsonPath, getJSONString(manifest!.manifestProperties) + os.EOL)
869
+ .returns();
870
+
871
+ const addOnBuilder: AddOnBuilder = new TemplateAddOnBuilder(options, logger);
872
+ addOnBuilder.build(packageJson);
873
+
874
+ assert.equal(writeFileStub.callCount, 2);
875
+ });
876
+
877
+ it("should update manifest.json after it has been copied to the app diectory.", () => {
878
+ const options = new ScaffolderOptions(
879
+ `${__dirname}/data/first_test_app`,
880
+ "first_test_app",
881
+ EntrypointType.PANEL,
882
+ `${__dirname}/data`,
883
+ "javascript",
884
+ false
885
+ );
886
+
887
+ sandbox.stub(process, "cwd").returns(options.addOnDirectory);
888
+
889
+ // write package.json stub.
890
+ const writeFileStub = sandbox.stub(fs, "writeFileSync");
891
+ writeFileStub.withArgs(path.join(options.addOnDirectory, PACKAGE_JSON), packageJson + os.EOL).returns();
892
+
893
+ // _updateReadMe() stub.
894
+ const existsStub = sandbox.stub(fs, "existsSync");
895
+ existsStub.withArgs(path.join(options.addOnDirectory, "README.md")).returns(false);
896
+
897
+ // _copyTemplateFiles() stubs.
898
+ const templateRootDirectory = path.join(__dirname, "data", "first_test_app", ".template");
899
+ const templateContentDirectory = path.join(templateRootDirectory, "template");
900
+ existsStub.withArgs(templateContentDirectory).returns(true);
901
+
902
+ const copyStub = sandbox.stub(fs, "copySync");
903
+ copyStub.withArgs(templateContentDirectory, options.addOnDirectory).returns();
904
+
905
+ // _updateGitIgnore() stubs.
906
+ existsStub.withArgs(path.join(options.addOnDirectory, ".gitignore")).returns(false);
907
+
908
+ const moveStub = sandbox.stub(fs, "moveSync");
909
+ moveStub
910
+ .withArgs(
911
+ path.join(options.addOnDirectory, "gitignore"),
912
+ path.join(options.addOnDirectory, ".gitignore")
913
+ )
914
+ .returns();
915
+
916
+ // _updateManifest() stubs.
917
+ const manifestJsonPath = path.join(options.addOnDirectory, "src", MANIFEST_JSON);
918
+ existsStub.withArgs(manifestJsonPath).returns(true);
919
+
920
+ const unlinkStub = sandbox.stub(fs, "unlinkSync");
921
+ unlinkStub.withArgs(manifestJsonPath).returns();
922
+
923
+ // _removeTemplateTempFiles() stubs.
924
+ sandbox.stub(fs, "removeSync").returns();
925
+
926
+ const { manifest } = AddOnManifest.createManifest({
927
+ manifest: {
928
+ testId: "first_test_app",
929
+ name: "First Test App",
930
+ version: "1.0.0",
931
+ manifestVersion: 2,
932
+ requirements: {
933
+ apps: [
934
+ {
935
+ name: "Express",
936
+ apiVersion: 1
937
+ }
938
+ ]
939
+ },
940
+ entryPoints: [
941
+ {
942
+ type: EntrypointType.PANEL,
943
+ id: "panel1",
944
+ main: "index.html"
945
+ }
946
+ ]
947
+ },
948
+ additionalInfo
949
+ });
950
+
951
+ writeFileStub
952
+ .withArgs(manifestJsonPath, getJSONString(manifest!.manifestProperties) + os.EOL)
953
+ .returns();
954
+
955
+ const addOnBuilder: AddOnBuilder = new TemplateAddOnBuilder(options, logger);
956
+ addOnBuilder.build(packageJson);
957
+
958
+ assert.equal(unlinkStub.callCount, 1);
959
+ assert.equal(unlinkStub.calledWith(manifestJsonPath), true);
960
+
961
+ assert.equal(writeFileStub.callCount, 2);
962
+ assert.equal(writeFileStub.getCall(1).calledWith(manifestJsonPath), true);
963
+ });
964
+
965
+ it("should not update manifest when it is invalid.", () => {
966
+ const options = new ScaffolderOptions(
967
+ `${__dirname}/data/third-test-app`,
968
+ "third-test-app",
969
+ EntrypointType.PANEL,
970
+ `${__dirname}/data`,
971
+ "javascript",
972
+ false
973
+ );
974
+
975
+ const thirdAppPackageJson = __require("./data/third-test-app/package.json");
976
+ const thirdPackageJson = new PackageJson({ thirdAppPackageJson }).toJSON();
977
+ sandbox.stub(process, "cwd").returns(options.addOnDirectory);
978
+
979
+ // write package.json stub.
980
+ const writeFileStub = sandbox.stub(fs, "writeFileSync");
981
+ writeFileStub
982
+ .withArgs(path.join(options.addOnDirectory, PACKAGE_JSON), thirdPackageJson + os.EOL)
983
+ .returns();
984
+
985
+ // _updateReadMe() stub.
986
+ const existsStub = sandbox.stub(fs, "existsSync");
987
+ existsStub.withArgs(path.join(options.addOnDirectory, "README.md")).returns(false);
988
+
989
+ // _copyTemplateFiles() stubs.
990
+ const templateRootDirectory = path.join(__dirname, "data", "third-test-app", ".template");
991
+ const templateContentDirectory = path.join(templateRootDirectory, "template");
992
+ existsStub.withArgs(templateContentDirectory).returns(true);
993
+
994
+ const copyStub = sandbox.stub(fs, "copySync");
995
+ copyStub.withArgs(templateContentDirectory, options.addOnDirectory).returns();
996
+
997
+ // _updateGitIgnore() stubs.
998
+ existsStub.withArgs(path.join(options.addOnDirectory, ".gitignore")).returns(false);
999
+
1000
+ const moveStub = sandbox.stub(fs, "moveSync");
1001
+ moveStub
1002
+ .withArgs(
1003
+ path.join(options.addOnDirectory, "gitignore"),
1004
+ path.join(options.addOnDirectory, ".gitignore")
1005
+ )
1006
+ .returns();
1007
+
1008
+ // _updateManifest() stubs.
1009
+ const manifestJsonPath = path.join(options.addOnDirectory, "src", MANIFEST_JSON);
1010
+ existsStub.withArgs(manifestJsonPath).returns(true);
1011
+
1012
+ const unlinkStub = sandbox.stub(fs, "unlinkSync");
1013
+ unlinkStub.withArgs(manifestJsonPath).returns();
1014
+
1015
+ // _removeTemplateTempFiles() stubs.
1016
+ sandbox.stub(fs, "removeSync").returns();
1017
+
1018
+ const addOnBuilder: AddOnBuilder = new TemplateAddOnBuilder(options, logger);
1019
+ addOnBuilder.build(thirdPackageJson);
1020
+
1021
+ assert.equal(writeFileStub.callCount, 1);
1022
+ assert.equal(logger.warning.calledOnce, true);
1023
+ });
1024
+ });
1025
+ });
1026
+
1027
+ describe("displaySuccess", () => {
1028
+ let sandbox: SinonSandbox;
1029
+
1030
+ const additionalInfo = {
1031
+ sourceId: "fakeAddOnSource",
1032
+ privileged: true,
1033
+ isDeveloperAddOn: false
1034
+ };
1035
+
1036
+ beforeEach(() => {
1037
+ sandbox = sinon.createSandbox();
1038
+ });
1039
+
1040
+ afterEach(() => {
1041
+ sandbox.restore();
1042
+ });
1043
+
1044
+ const packageJson = new PackageJson({ testAppPackageJson }).toJSON();
1045
+
1046
+ it("should display success with next steps for the correct root directory and addOndirectory.", () => {
1047
+ const options = new ScaffolderOptions(
1048
+ `${__dirname}/data/first-test-app`,
1049
+ "first-test-app",
1050
+ EntrypointType.PANEL,
1051
+ `${__dirname}/data`,
1052
+ "react-javascript",
1053
+ false
1054
+ );
1055
+
1056
+ sandbox.stub(process, "cwd").returns(options.addOnDirectory);
1057
+
1058
+ // write package.json stub.
1059
+ const writeFileStub = sandbox.stub(fs, "writeFileSync");
1060
+ writeFileStub.withArgs(path.join(options.addOnDirectory, PACKAGE_JSON), packageJson + os.EOL).returns();
1061
+
1062
+ // _updateReadMe() stub.
1063
+ const existsStub = sandbox.stub(fs, "existsSync");
1064
+ existsStub.withArgs(path.join(options.addOnDirectory, "README.md")).returns(true);
1065
+
1066
+ const renameStub = sandbox.stub(fs, "renameSync");
1067
+ renameStub.returns();
1068
+
1069
+ // _copyTemplateFiles() stubs.
1070
+ const templateRootDirectory = path.join(__dirname, "data", options.addOnName, ".template");
1071
+ const templateContentDirectory = path.join(templateRootDirectory, "template");
1072
+ existsStub.withArgs(templateContentDirectory).returns(true);
1073
+
1074
+ const copyStub = sandbox.stub(fs, "copySync");
1075
+ copyStub.withArgs(templateContentDirectory, options.addOnDirectory).returns();
1076
+
1077
+ // _updateGitIgnore() stubs.
1078
+ existsStub.withArgs(path.join(options.addOnDirectory, ".gitignore")).returns(true);
1079
+
1080
+ const readFileStub = sandbox.stub(fs, "readFileSync");
1081
+ const appendFileStub = sandbox.stub(fs, "appendFileSync");
1082
+ const unlinkStub = sandbox.stub(fs, "unlinkSync");
1083
+
1084
+ const data = stubInterface<Buffer>();
1085
+ readFileStub.withArgs(path.join(options.addOnDirectory, "gitignore")).returns(data);
1086
+ appendFileStub.withArgs(path.join(options.addOnDirectory, ".gitignore"), data).returns();
1087
+ unlinkStub.withArgs(path.join(options.addOnDirectory, "gitignore")).returns();
1088
+
1089
+ // _updateManifest() stubs.
1090
+ const manifestJsonPath = path.join(options.addOnDirectory, "src", MANIFEST_JSON);
1091
+ existsStub.withArgs(manifestJsonPath).returns(false);
1092
+
1093
+ // _removeTemplateTempFiles() stubs.
1094
+ sandbox.stub(fs, "removeSync").returns();
1095
+
1096
+ const { manifest } = AddOnManifest.createManifest({
1097
+ manifest: {
1098
+ testId: "first-test-app",
1099
+ name: "first test app",
1100
+ version: "1.0.1",
1101
+ manifestVersion: 2,
1102
+ requirements: {
1103
+ apps: [
1104
+ {
1105
+ name: "Express",
1106
+ apiVersion: 1
1107
+ }
1108
+ ]
1109
+ },
1110
+ entryPoints: [
1111
+ {
1112
+ type: EntrypointType.PANEL,
1113
+ id: "first-test-app",
1114
+ main: "index.html"
1115
+ }
1116
+ ]
1117
+ },
1118
+ additionalInfo
1119
+ });
1120
+
1121
+ writeFileStub.withArgs(manifestJsonPath, getJSONString(manifest!.manifestProperties) + os.EOL).returns();
1122
+
1123
+ const addOnBuilder: AddOnBuilder = new TemplateAddOnBuilder(options, logger);
1124
+ addOnBuilder.build(packageJson);
1125
+ addOnBuilder.displaySuccess();
1126
+ assert.equal(logger.message.callCount, 3);
1127
+
1128
+ assert.equal(
1129
+ logger.message.getCall(0).calledWith("Builds the Add-on.", {
1130
+ prefix: " "
1131
+ }),
1132
+ true
1133
+ );
1134
+ assert.equal(
1135
+ logger.message.getCall(1).calledWith("Starts the development server and hosts the Add-on.", {
1136
+ prefix: " "
1137
+ }),
1138
+ true
1139
+ );
1140
+ assert.equal(
1141
+ logger.message.getCall(2).calledWith("We suggest that you begin by typing:", {
1142
+ prefix: "\n",
1143
+ postfix: "\n"
1144
+ }),
1145
+ true
1146
+ );
1147
+
1148
+ assert.equal(logger.information.callCount, 4);
1149
+ assert.equal(
1150
+ logger.information.getCall(0).calledWith("npm run build", {
1151
+ prefix: " "
1152
+ }),
1153
+ true
1154
+ );
1155
+ assert.equal(
1156
+ logger.information.getCall(1).calledWith("npm run start", {
1157
+ prefix: " "
1158
+ }),
1159
+ true
1160
+ );
1161
+ assert.equal(
1162
+ logger.information.getCall(2).calledWith("npm run build", {
1163
+ prefix: " "
1164
+ }),
1165
+ true
1166
+ );
1167
+ assert.equal(
1168
+ logger.information.getCall(3).calledWith("npm run start", {
1169
+ prefix: " ",
1170
+ postfix: "\n"
1171
+ }),
1172
+ true
1173
+ );
1174
+
1175
+ assert.equal(logger.success.callCount, 2);
1176
+ assert.equal(
1177
+ logger.success
1178
+ .getCall(0)
1179
+ .calledWith(`Success! Created ${options.addOnName} at ${options.addOnDirectory}.`),
1180
+ true
1181
+ );
1182
+ assert.equal(
1183
+ logger.success.getCall(1).calledWith(`Inside this directory, you can run the following commands:`, {
1184
+ postfix: "\n"
1185
+ }),
1186
+ true
1187
+ );
1188
+
1189
+ assert.equal(logger.warning.callCount, 4);
1190
+ assert.equal(
1191
+ logger.warning.getCall(0).calledWith(`cd ${options.addOnName}`, {
1192
+ prefix: " "
1193
+ }),
1194
+ true
1195
+ );
1196
+ assert.equal(
1197
+ logger.warning.getCall(1).calledWith("You had a 'README.md' file, we renamed it to 'README.OLD.md'", {
1198
+ postfix: "\n"
1199
+ }),
1200
+ true
1201
+ );
1202
+ assert.equal(
1203
+ logger.warning
1204
+ .getCall(2)
1205
+ .calledWith("You had a '.gitignore' file, we merged it with the template '.gitignore'", {
1206
+ postfix: "\n"
1207
+ }),
1208
+ true
1209
+ );
1210
+ assert.equal(
1211
+ logger.warning.getCall(3).calledWith("So what will you create today?", {
1212
+ postfix: "\n"
1213
+ }),
1214
+ true
1215
+ );
1216
+ });
1217
+
1218
+ it("should display success with next steps for the incorrect root directory and addOndirectory.", () => {
1219
+ const options = new ScaffolderOptions(
1220
+ `${__dirname}/data/first-test-app`,
1221
+ "first-test-app",
1222
+ EntrypointType.PANEL,
1223
+ `data`,
1224
+ "react-javascript",
1225
+ false
1226
+ );
1227
+
1228
+ sandbox.stub(process, "cwd").returns(options.addOnDirectory);
1229
+
1230
+ // write package.json stub.
1231
+ const writeFileStub = sandbox.stub(fs, "writeFileSync");
1232
+ writeFileStub.withArgs(path.join(options.addOnDirectory, PACKAGE_JSON), packageJson + os.EOL).returns();
1233
+
1234
+ // _updateReadMe() stub.
1235
+ const existsStub = sandbox.stub(fs, "existsSync");
1236
+ existsStub.withArgs(path.join(options.addOnDirectory, "README.md")).returns(true);
1237
+
1238
+ const renameStub = sandbox.stub(fs, "renameSync");
1239
+ renameStub.returns();
1240
+
1241
+ // _copyTemplateFiles() stubs.
1242
+ const templateRootDirectory = path.join(__dirname, "data", options.addOnName, ".template");
1243
+ const templateContentDirectory = path.join(templateRootDirectory, "template");
1244
+ existsStub.withArgs(templateContentDirectory).returns(true);
1245
+
1246
+ const copyStub = sandbox.stub(fs, "copySync");
1247
+ copyStub.withArgs(templateContentDirectory, options.addOnDirectory).returns();
1248
+
1249
+ // _updateGitIgnore() stubs.
1250
+ existsStub.withArgs(path.join(options.addOnDirectory, ".gitignore")).returns(true);
1251
+
1252
+ const readFileStub = sandbox.stub(fs, "readFileSync");
1253
+ const appendFileStub = sandbox.stub(fs, "appendFileSync");
1254
+ const unlinkStub = sandbox.stub(fs, "unlinkSync");
1255
+
1256
+ const data = stubInterface<Buffer>();
1257
+ readFileStub.withArgs(path.join(options.addOnDirectory, "gitignore")).returns(data);
1258
+ appendFileStub.withArgs(path.join(options.addOnDirectory, ".gitignore"), data).returns();
1259
+ unlinkStub.withArgs(path.join(options.addOnDirectory, "gitignore")).returns();
1260
+
1261
+ // _updateManifest() stubs.
1262
+ const manifestJsonPath = path.join(options.addOnDirectory, "src", MANIFEST_JSON);
1263
+ existsStub.withArgs(manifestJsonPath).returns(false);
1264
+
1265
+ // _removeTemplateTempFiles() stubs.
1266
+ sandbox.stub(fs, "removeSync").returns();
1267
+
1268
+ const { manifest } = AddOnManifest.createManifest({
1269
+ manifest: {
1270
+ testId: "first-test-app",
1271
+ name: "first test app",
1272
+ version: "1.0.1",
1273
+ manifestVersion: 2,
1274
+ requirements: {
1275
+ apps: [
1276
+ {
1277
+ name: "Express",
1278
+ apiVersion: 1
1279
+ }
1280
+ ]
1281
+ },
1282
+ entryPoints: [
1283
+ {
1284
+ type: EntrypointType.PANEL,
1285
+ id: "first-test-app",
1286
+ main: "index.html"
1287
+ }
1288
+ ]
1289
+ },
1290
+ additionalInfo
1291
+ });
1292
+
1293
+ writeFileStub.withArgs(manifestJsonPath, getJSONString(manifest!.manifestProperties) + os.EOL).returns();
1294
+
1295
+ const addOnBuilder: AddOnBuilder = new TemplateAddOnBuilder(options, logger);
1296
+ addOnBuilder.build(packageJson);
1297
+ addOnBuilder.displaySuccess();
1298
+
1299
+ assert.equal(logger.message.callCount, 3);
1300
+
1301
+ assert.equal(
1302
+ logger.message.getCall(0).calledWith("Builds the Add-on.", {
1303
+ prefix: " "
1304
+ }),
1305
+ true
1306
+ );
1307
+ assert.equal(
1308
+ logger.message.getCall(1).calledWith("Starts the development server and hosts the Add-on.", {
1309
+ prefix: " "
1310
+ }),
1311
+ true
1312
+ );
1313
+ assert.equal(
1314
+ logger.message.getCall(2).calledWith("We suggest that you begin by typing:", {
1315
+ prefix: "\n",
1316
+ postfix: "\n"
1317
+ }),
1318
+ true
1319
+ );
1320
+
1321
+ assert.equal(logger.information.callCount, 4);
1322
+ assert.equal(
1323
+ logger.information.getCall(0).calledWith("npm run build", {
1324
+ prefix: " "
1325
+ }),
1326
+ true
1327
+ );
1328
+ assert.equal(
1329
+ logger.information.getCall(1).calledWith("npm run start", {
1330
+ prefix: " "
1331
+ }),
1332
+ true
1333
+ );
1334
+ assert.equal(
1335
+ logger.information.getCall(2).calledWith("npm run build", {
1336
+ prefix: " "
1337
+ }),
1338
+ true
1339
+ );
1340
+ assert.equal(
1341
+ logger.information.getCall(3).calledWith("npm run start", {
1342
+ prefix: " ",
1343
+ postfix: "\n"
1344
+ }),
1345
+ true
1346
+ );
1347
+
1348
+ assert.equal(logger.success.callCount, 2);
1349
+ assert.equal(
1350
+ logger.success
1351
+ .getCall(0)
1352
+ .calledWith(`Success! Created ${options.addOnName} at ${options.addOnDirectory}.`),
1353
+ true
1354
+ );
1355
+ assert.equal(
1356
+ logger.success.getCall(1).calledWith(`Inside this directory, you can run the following commands:`, {
1357
+ postfix: "\n"
1358
+ }),
1359
+ true
1360
+ );
1361
+
1362
+ assert.equal(logger.warning.callCount, 4);
1363
+ assert.equal(
1364
+ logger.warning.getCall(0).calledWith(`cd ${options.addOnDirectory}`, {
1365
+ prefix: " "
1366
+ }),
1367
+ true
1368
+ );
1369
+ assert.equal(
1370
+ logger.warning.getCall(1).calledWith("You had a 'README.md' file, we renamed it to 'README.OLD.md'", {
1371
+ postfix: "\n"
1372
+ }),
1373
+ true
1374
+ );
1375
+ assert.equal(
1376
+ logger.warning
1377
+ .getCall(2)
1378
+ .calledWith("You had a '.gitignore' file, we merged it with the template '.gitignore'", {
1379
+ postfix: "\n"
1380
+ }),
1381
+ true
1382
+ );
1383
+ assert.equal(
1384
+ logger.warning.getCall(3).calledWith("So what will you create today?", {
1385
+ postfix: "\n"
1386
+ }),
1387
+ true
1388
+ );
1389
+ });
1390
+ });
1391
+ });