@sasjs/cli 6.3.0 → 6.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/build/commands/compile/internal/compileTestFile.d.ts +2 -0
- package/build/commands/compile/internal/compileTestFile.js +48 -60
- package/build/commands/compile/internal/spec/compileTestFile.spec.js +158 -0
- package/build/commands/help/help.js +1 -0
- package/build/types/index.d.ts +1 -1
- package/build/types/testing.d.ts +33 -0
- package/build/types/testing.js +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
- Scaffold a new SAS App in seconds (`sasjs create myApp -t jobs`)
|
|
18
18
|
- Compile / Build SAS Jobs, Services & Macros _locally_ and deploy / execute _remotely_, in isolation from other developers (`sasjs cbd`)
|
|
19
19
|
- Compile a single Job, Service or Test without touching the rest of the build (`sasjs compile identify --source sasjs/jobs/daily/load.sas`)
|
|
20
|
+
- Write the test coverage report to `sasjsbuild/coverage.json` on every compile, ready for a CI job to publish
|
|
20
21
|
- No dependency on the server filesystem
|
|
21
22
|
- Optionally synchronise a local folder onto the server filesystem using `sasjs fs`
|
|
22
23
|
- Trigger Viya Jobs & Flows (`sasjs job execute` / `sasjs flow execute`)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { CompileTree, Target } from '@sasjs/utils';
|
|
2
2
|
import { TestFlow } from '../../../types';
|
|
3
|
+
/** The coverage report `sasjs compile` writes to the build folder. */
|
|
4
|
+
export declare const coverageFileName = "coverage.json";
|
|
3
5
|
/**
|
|
4
6
|
* Resolves the relative destination fragment for a compiled test file inside
|
|
5
7
|
* `sasjsbuild/tests` - either just the file's basename (saveToRoot, used for
|
|
@@ -64,7 +64,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
64
64
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
65
65
|
};
|
|
66
66
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
67
|
-
exports.compileTestFlow = exports.getTestFileDestinationFragment = void 0;
|
|
67
|
+
exports.compileTestFlow = exports.getTestFileDestinationFragment = exports.coverageFileName = void 0;
|
|
68
68
|
exports.compileTestFile = compileTestFile;
|
|
69
69
|
exports.copyTestMacroFiles = copyTestMacroFiles;
|
|
70
70
|
var utils_1 = require("@sasjs/utils");
|
|
@@ -75,6 +75,8 @@ var config_1 = require("../../../utils/config");
|
|
|
75
75
|
var file_1 = require("../../../utils/file");
|
|
76
76
|
var _1 = require("./");
|
|
77
77
|
var getFileName = function (filePath) { return path_1.default.parse(filePath).base; };
|
|
78
|
+
/** The coverage report `sasjs compile` writes to the build folder. */
|
|
79
|
+
exports.coverageFileName = 'coverage.json';
|
|
78
80
|
/**
|
|
79
81
|
* Resolves the relative destination fragment for a compiled test file inside
|
|
80
82
|
* `sasjsbuild/tests` - either just the file's basename (saveToRoot, used for
|
|
@@ -232,7 +234,7 @@ var compileTestFlow = function (target) { return __awaiter(void 0, void 0, void
|
|
|
232
234
|
}); };
|
|
233
235
|
exports.compileTestFlow = compileTestFlow;
|
|
234
236
|
var printTestCoverage = function (testFlow, buildDestinationFolder, target) { return __awaiter(void 0, void 0, void 0, function () {
|
|
235
|
-
var toCover, covered, extraTests, serviceFolder, collectCoverage, jobFolder, macroFolders, filter,
|
|
237
|
+
var toCover, covered, extraTests, serviceFolder, collectCoverage, jobFolder, macroFolders, filter, coveredServices, servicesToCover, coveredJobs, jobsToCover, coveredMacros, macrosToCover, coverage, markCoverage, summarize, formatCoverage, summary, report;
|
|
236
238
|
var _a, _b, _c;
|
|
237
239
|
return __generator(this, function (_d) {
|
|
238
240
|
switch (_d.label) {
|
|
@@ -315,74 +317,52 @@ var printTestCoverage = function (testFlow, buildDestinationFolder, target) { re
|
|
|
315
317
|
filter = function (files, type) {
|
|
316
318
|
return files.filter(function (file) { return new RegExp("^".concat(type)).test(file); });
|
|
317
319
|
};
|
|
318
|
-
coverage = {};
|
|
319
|
-
notCovered = toCover.filter(function (tc) { return !covered.includes(tc); });
|
|
320
320
|
coveredServices = filter(covered, types_1.CoverageType.service);
|
|
321
321
|
servicesToCover = filter(toCover, types_1.CoverageType.service);
|
|
322
|
-
notCoveredServices = filter(notCovered, types_1.CoverageType.service);
|
|
323
|
-
notCoveredServices.forEach(function (file, i) {
|
|
324
|
-
coverage[file] = {
|
|
325
|
-
Type: types_1.CoverageType.service,
|
|
326
|
-
Coverage: types_1.CoverageState.notCovered
|
|
327
|
-
};
|
|
328
|
-
});
|
|
329
322
|
coveredJobs = filter(covered, types_1.CoverageType.job);
|
|
330
323
|
jobsToCover = filter(toCover, types_1.CoverageType.job);
|
|
331
|
-
notCoveredJobs = filter(notCovered, types_1.CoverageType.job);
|
|
332
|
-
notCoveredJobs.forEach(function (file, i) {
|
|
333
|
-
coverage[file] = {
|
|
334
|
-
Type: types_1.CoverageType.job,
|
|
335
|
-
Coverage: types_1.CoverageState.notCovered
|
|
336
|
-
};
|
|
337
|
-
});
|
|
338
324
|
coveredMacros = filter(covered, types_1.CoverageType.macro);
|
|
339
325
|
macrosToCover = filter(toCover, types_1.CoverageType.macro);
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
: macro;
|
|
355
|
-
});
|
|
356
|
-
return [2 /*return*/];
|
|
357
|
-
}
|
|
358
|
-
});
|
|
359
|
-
}); })];
|
|
360
|
-
case 5:
|
|
361
|
-
_d.sent();
|
|
362
|
-
_d.label = 6;
|
|
363
|
-
case 6:
|
|
364
|
-
notCoveredMacros.forEach(function (file, i) {
|
|
365
|
-
coverage[file] = {
|
|
366
|
-
Type: types_1.CoverageType.macro,
|
|
367
|
-
Coverage: types_1.CoverageState.notCovered
|
|
368
|
-
};
|
|
369
|
-
});
|
|
326
|
+
coverage = {};
|
|
327
|
+
markCoverage = function (type, filesToCover, coveredFiles) {
|
|
328
|
+
return filesToCover.forEach(function (file) {
|
|
329
|
+
coverage[file] = {
|
|
330
|
+
Type: type,
|
|
331
|
+
Coverage: coveredFiles.includes(file)
|
|
332
|
+
? types_1.CoverageState.covered
|
|
333
|
+
: types_1.CoverageState.notCovered
|
|
334
|
+
};
|
|
335
|
+
});
|
|
336
|
+
};
|
|
337
|
+
markCoverage(types_1.CoverageType.service, servicesToCover, coveredServices);
|
|
338
|
+
markCoverage(types_1.CoverageType.job, jobsToCover, coveredJobs);
|
|
339
|
+
markCoverage(types_1.CoverageType.macro, macrosToCover, coveredMacros);
|
|
370
340
|
extraTests.forEach(function (file) {
|
|
371
341
|
coverage[file] = {
|
|
372
342
|
Type: types_1.CoverageType.test,
|
|
373
343
|
Coverage: types_1.CoverageState.standalone
|
|
374
344
|
};
|
|
375
345
|
});
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
346
|
+
summarize = function (cov, toCov) { return ({
|
|
347
|
+
covered: cov.length,
|
|
348
|
+
total: toCov.length,
|
|
349
|
+
percentage: toCov.length ? Math.round((cov.length / toCov.length) * 100) : 0
|
|
350
|
+
}); };
|
|
351
|
+
formatCoverage = function (type, summary) {
|
|
380
352
|
var _a;
|
|
381
|
-
return
|
|
382
|
-
? (_a = process.logger) === null || _a === void 0 ? void 0 : _a.info("".concat(type, " coverage: ").concat(covered
|
|
353
|
+
return summary.total
|
|
354
|
+
? (_a = process.logger) === null || _a === void 0 ? void 0 : _a.info("".concat(type, " coverage: ").concat(summary.covered, "/").concat(summary.total, " (").concat(chalk_1.default.greenBright("".concat(summary.percentage, "%")), ")"))
|
|
383
355
|
: null;
|
|
384
356
|
};
|
|
357
|
+
summary = {
|
|
358
|
+
services: summarize(coveredServices, servicesToCover),
|
|
359
|
+
jobs: summarize(coveredJobs, jobsToCover),
|
|
360
|
+
macros: summarize(coveredMacros, macrosToCover),
|
|
361
|
+
overall: summarize(covered, toCover)
|
|
362
|
+
};
|
|
385
363
|
(_a = process.logger) === null || _a === void 0 ? void 0 : _a.info('Test coverage:');
|
|
364
|
+
// The table renders the same map coverage.json serialises, so a reader sees
|
|
365
|
+
// every file - covered rows included - under the key the report uses.
|
|
386
366
|
(_b = process.logger) === null || _b === void 0 ? void 0 : _b.table(Object.keys(coverage).map(function (key) { return [
|
|
387
367
|
key,
|
|
388
368
|
coverage[key].Type,
|
|
@@ -390,13 +370,21 @@ var printTestCoverage = function (testFlow, buildDestinationFolder, target) { re
|
|
|
390
370
|
]; }), {
|
|
391
371
|
head: ['File', 'Type', 'Coverage']
|
|
392
372
|
});
|
|
393
|
-
formatCoverage('Services',
|
|
394
|
-
formatCoverage('Jobs',
|
|
395
|
-
formatCoverage('Macros',
|
|
396
|
-
formatCoverage('Overall',
|
|
373
|
+
formatCoverage('Services', summary.services);
|
|
374
|
+
formatCoverage('Jobs', summary.jobs);
|
|
375
|
+
formatCoverage('Macros', summary.macros);
|
|
376
|
+
formatCoverage('Overall', summary.overall);
|
|
397
377
|
(_c = process.logger) === null || _c === void 0 ? void 0 : _c.log('');
|
|
398
|
-
return [4 /*yield*/, (0, utils_1.createFile)(path_1.default.join(buildDestinationFolder, 'testFlow.json'), JSON.stringify(testFlow, null, 2))
|
|
399
|
-
|
|
378
|
+
return [4 /*yield*/, (0, utils_1.createFile)(path_1.default.join(buildDestinationFolder, 'testFlow.json'), JSON.stringify(testFlow, null, 2))
|
|
379
|
+
// The numbers are already computed and rendered above, so the report costs
|
|
380
|
+
// one small file - which lets a CI job publish the figures instead of
|
|
381
|
+
// scraping the log.
|
|
382
|
+
];
|
|
383
|
+
case 5:
|
|
384
|
+
_d.sent();
|
|
385
|
+
report = { summary: summary, files: coverage };
|
|
386
|
+
return [4 /*yield*/, (0, utils_1.createFile)(path_1.default.join(buildDestinationFolder, exports.coverageFileName), JSON.stringify(report, null, 2))];
|
|
387
|
+
case 6:
|
|
400
388
|
_d.sent();
|
|
401
389
|
return [2 /*return*/];
|
|
402
390
|
}
|
|
@@ -51,6 +51,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
51
51
|
};
|
|
52
52
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
53
53
|
var __1 = require("../");
|
|
54
|
+
var compileTestFile_1 = require("../compileTestFile");
|
|
54
55
|
var utils_1 = require("@sasjs/utils");
|
|
55
56
|
var test_1 = require("../../../../utils/test");
|
|
56
57
|
var path_1 = __importDefault(require("path"));
|
|
@@ -391,6 +392,163 @@ describe('compileTestFile', function () {
|
|
|
391
392
|
}
|
|
392
393
|
});
|
|
393
394
|
}); });
|
|
395
|
+
it('should write the coverage report to the build folder', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
396
|
+
var report, _a, _b;
|
|
397
|
+
return __generator(this, function (_c) {
|
|
398
|
+
switch (_c.label) {
|
|
399
|
+
case 0: return [4 /*yield*/, (0, compile_1.compile)(target)];
|
|
400
|
+
case 1:
|
|
401
|
+
_c.sent();
|
|
402
|
+
_b = (_a = JSON).parse;
|
|
403
|
+
return [4 /*yield*/, (0, utils_1.readFile)(path_1.default.join(buildPath, compileTestFile_1.coverageFileName))];
|
|
404
|
+
case 2:
|
|
405
|
+
report = _b.apply(_a, [_c.sent()]);
|
|
406
|
+
expect(report.summary).toEqual({
|
|
407
|
+
services: { covered: 0, total: 4, percentage: 0 },
|
|
408
|
+
jobs: { covered: 0, total: 0, percentage: 0 },
|
|
409
|
+
macros: { covered: 0, total: 0, percentage: 0 },
|
|
410
|
+
overall: { covered: 0, total: 4, percentage: 0 }
|
|
411
|
+
});
|
|
412
|
+
// the same rows the console table lists, standalone tests included
|
|
413
|
+
expect(report.files[['services', 'common', 'appinit.sas'].join('/')]).toEqual({ Type: 'service', Coverage: 'not covered' });
|
|
414
|
+
expect(report.files[['tests', 'jobs', 'jobs', 'testJob.test.sas'].join('/')]).toEqual({ Type: 'test', Coverage: 'standalone' });
|
|
415
|
+
return [2 /*return*/];
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
}); });
|
|
419
|
+
it('should key the report by project-relative paths, never build machine paths', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
420
|
+
var macroPath, tableSpy, report, _a, _b, tableRows;
|
|
421
|
+
return __generator(this, function (_c) {
|
|
422
|
+
switch (_c.label) {
|
|
423
|
+
case 0:
|
|
424
|
+
macroPath = path_1.default.join(sasjsPath, 'macros', 'uncoveredmacro.sas');
|
|
425
|
+
tableSpy = jest
|
|
426
|
+
.spyOn(process.logger, 'table')
|
|
427
|
+
.mockImplementation(function () { return ''; });
|
|
428
|
+
return [4 /*yield*/, (0, utils_1.createFile)(macroPath, '%macro uncoveredmacro(); %mend uncoveredmacro;')];
|
|
429
|
+
case 1:
|
|
430
|
+
_c.sent();
|
|
431
|
+
_c.label = 2;
|
|
432
|
+
case 2:
|
|
433
|
+
_c.trys.push([2, , 5, 7]);
|
|
434
|
+
return [4 /*yield*/, (0, compile_1.compile)(target)];
|
|
435
|
+
case 3:
|
|
436
|
+
_c.sent();
|
|
437
|
+
_b = (_a = JSON).parse;
|
|
438
|
+
return [4 /*yield*/, (0, utils_1.readFile)(path_1.default.join(buildPath, compileTestFile_1.coverageFileName))];
|
|
439
|
+
case 4:
|
|
440
|
+
report = _b.apply(_a, [_c.sent()]);
|
|
441
|
+
// macros are keyed like services and jobs, in the report and in the
|
|
442
|
+
// console table alike - a build machine path in either would make the
|
|
443
|
+
// same project produce different output elsewhere.
|
|
444
|
+
expect(report.files['macros/uncoveredmacro.sas']).toEqual({
|
|
445
|
+
Type: 'macro',
|
|
446
|
+
Coverage: 'not covered'
|
|
447
|
+
});
|
|
448
|
+
expect(Object.keys(report.files).filter(function (key) { return path_1.default.isAbsolute(key); })).toEqual([]);
|
|
449
|
+
expect(report.summary.macros).toEqual({
|
|
450
|
+
covered: 0,
|
|
451
|
+
total: 1,
|
|
452
|
+
percentage: 0
|
|
453
|
+
});
|
|
454
|
+
tableRows = tableSpy.mock.calls[0][0];
|
|
455
|
+
expect(tableRows).toContainEqual([
|
|
456
|
+
'macros/uncoveredmacro.sas',
|
|
457
|
+
'macro',
|
|
458
|
+
'not covered'
|
|
459
|
+
]);
|
|
460
|
+
expect(tableRows.flat().filter(function (cell) { return path_1.default.isAbsolute(cell); })).toEqual([]);
|
|
461
|
+
return [3 /*break*/, 7];
|
|
462
|
+
case 5: return [4 /*yield*/, (0, utils_1.deleteFile)(macroPath)];
|
|
463
|
+
case 6:
|
|
464
|
+
_c.sent();
|
|
465
|
+
return [7 /*endfinally*/];
|
|
466
|
+
case 7: return [2 /*return*/];
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
}); });
|
|
470
|
+
it('should mark covered files in the report, not just the gaps', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
471
|
+
var macroPath, macroTestPath, tableSpy, report, _a, _b, tableRows;
|
|
472
|
+
return __generator(this, function (_c) {
|
|
473
|
+
switch (_c.label) {
|
|
474
|
+
case 0:
|
|
475
|
+
macroPath = path_1.default.join(sasjsPath, 'macros', 'coveredmacro.sas');
|
|
476
|
+
macroTestPath = path_1.default.join(sasjsPath, 'macros', 'coveredmacro.test.sas');
|
|
477
|
+
tableSpy = jest
|
|
478
|
+
.spyOn(process.logger, 'table')
|
|
479
|
+
.mockImplementation(function () { return ''; });
|
|
480
|
+
return [4 /*yield*/, (0, utils_1.createFile)(macroPath, '%macro coveredmacro(); %mend coveredmacro;')];
|
|
481
|
+
case 1:
|
|
482
|
+
_c.sent();
|
|
483
|
+
return [4 /*yield*/, (0, utils_1.createFile)(macroTestPath, '%put testing coveredmacro;')];
|
|
484
|
+
case 2:
|
|
485
|
+
_c.sent();
|
|
486
|
+
_c.label = 3;
|
|
487
|
+
case 3:
|
|
488
|
+
_c.trys.push([3, , 6, 9]);
|
|
489
|
+
return [4 /*yield*/, (0, compile_1.compile)(target)];
|
|
490
|
+
case 4:
|
|
491
|
+
_c.sent();
|
|
492
|
+
_b = (_a = JSON).parse;
|
|
493
|
+
return [4 /*yield*/, (0, utils_1.readFile)(path_1.default.join(buildPath, compileTestFile_1.coverageFileName))];
|
|
494
|
+
case 5:
|
|
495
|
+
report = _b.apply(_a, [_c.sent()]);
|
|
496
|
+
expect(report.files['macros/coveredmacro.sas']).toEqual({
|
|
497
|
+
Type: 'macro',
|
|
498
|
+
Coverage: 'covered'
|
|
499
|
+
});
|
|
500
|
+
expect(report.summary.macros).toEqual({
|
|
501
|
+
covered: 1,
|
|
502
|
+
total: 1,
|
|
503
|
+
percentage: 100
|
|
504
|
+
});
|
|
505
|
+
tableRows = tableSpy.mock.calls[0][0];
|
|
506
|
+
expect(tableRows).toContainEqual([
|
|
507
|
+
'macros/coveredmacro.sas',
|
|
508
|
+
'macro',
|
|
509
|
+
'covered'
|
|
510
|
+
]);
|
|
511
|
+
return [3 /*break*/, 9];
|
|
512
|
+
case 6: return [4 /*yield*/, (0, utils_1.deleteFile)(macroPath)];
|
|
513
|
+
case 7:
|
|
514
|
+
_c.sent();
|
|
515
|
+
return [4 /*yield*/, (0, utils_1.deleteFile)(macroTestPath)];
|
|
516
|
+
case 8:
|
|
517
|
+
_c.sent();
|
|
518
|
+
return [7 /*endfinally*/];
|
|
519
|
+
case 9: return [2 /*return*/];
|
|
520
|
+
}
|
|
521
|
+
});
|
|
522
|
+
}); });
|
|
523
|
+
it('should not write a coverage report when no tests were compiled', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
524
|
+
var coveragePath, testFlow;
|
|
525
|
+
return __generator(this, function (_a) {
|
|
526
|
+
switch (_a.label) {
|
|
527
|
+
case 0: return [4 /*yield*/, (0, compile_1.compile)(target)];
|
|
528
|
+
case 1:
|
|
529
|
+
_a.sent();
|
|
530
|
+
coveragePath = path_1.default.join(buildPath, compileTestFile_1.coverageFileName);
|
|
531
|
+
// remove the report the compile wrote, so the assertion below is about
|
|
532
|
+
// the no-tests path and not about a file left over from it
|
|
533
|
+
return [4 /*yield*/, (0, utils_1.deleteFile)(coveragePath)];
|
|
534
|
+
case 2:
|
|
535
|
+
// remove the report the compile wrote, so the assertion below is about
|
|
536
|
+
// the no-tests path and not about a file left over from it
|
|
537
|
+
_a.sent();
|
|
538
|
+
return [4 /*yield*/, (0, utils_1.deleteFolder)(path_1.default.join(buildPath, 'tests'))];
|
|
539
|
+
case 3:
|
|
540
|
+
_a.sent();
|
|
541
|
+
return [4 /*yield*/, (0, __1.compileTestFlow)(target)];
|
|
542
|
+
case 4:
|
|
543
|
+
testFlow = _a.sent();
|
|
544
|
+
expect(testFlow).toBeUndefined();
|
|
545
|
+
return [4 /*yield*/, expect((0, utils_1.fileExists)(coveragePath)).resolves.toEqual(false)];
|
|
546
|
+
case 5:
|
|
547
|
+
_a.sent();
|
|
548
|
+
return [2 /*return*/];
|
|
549
|
+
}
|
|
550
|
+
});
|
|
551
|
+
}); });
|
|
394
552
|
it('should log a warning is testFolders was used in root or target configuration', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
395
553
|
var testTarget, testConfig, expectedWarn;
|
|
396
554
|
return __generator(this, function (_a) {
|
|
@@ -97,6 +97,7 @@ function printHelpText() {
|
|
|
97
97
|
"compiles the services specified in the ".concat(chalk_1.default.cyanBright('serviceFolders'), " property of the 'serviceConfig' in your target and common configuration."),
|
|
98
98
|
"A single file is compiled by naming its type as a sub command - ".concat(chalk_1.default.cyanBright('job'), ", ").concat(chalk_1.default.cyanBright('service'), ", ").concat(chalk_1.default.cyanBright('test'), " or ").concat(chalk_1.default.cyanBright('identify'), ", which works the type out from the file itself - together with ").concat(chalk_1.default.cyanBright('--source'), " (or ").concat(chalk_1.default.cyanBright('-s'), ")."),
|
|
99
99
|
"The compiled file is written to the ".concat(chalk_1.default.cyanBright('jobs'), " or ").concat(chalk_1.default.cyanBright('services'), " folder of sasjsbuild for its type, or below ").concat(chalk_1.default.cyanBright('--output'), " (or ").concat(chalk_1.default.cyanBright('-o'), ") when given."),
|
|
100
|
+
"The test coverage report is written to ".concat(chalk_1.default.cyanBright('coverage.json'), " in the build folder alongside ").concat(chalk_1.default.cyanBright('testFlow.json'), "."),
|
|
100
101
|
"command example: sasjs compile identify --source sasjs/jobs/daily/load.sas --target myTarget"
|
|
101
102
|
]
|
|
102
103
|
},
|
package/build/types/index.d.ts
CHANGED
|
@@ -2,6 +2,6 @@ export { CommandBase } from './command/commandBase';
|
|
|
2
2
|
export { File, FilePath } from './file';
|
|
3
3
|
export { Folder } from './folder';
|
|
4
4
|
export { TargetScope } from './targetScope';
|
|
5
|
-
export { TestFlow, Coverage, CoverageType, CoverageState, TestResults, TestResultStatus, TestDescription, TestResult, TestResultDescription, TestResultCsv } from './testing';
|
|
5
|
+
export { TestFlow, Coverage, CoverageReport, CoverageSummary, CoverageType, CoverageState, TestResults, TestResultStatus, TestDescription, TestResult, TestResultDescription, TestResultCsv } from './testing';
|
|
6
6
|
export { Flow, FlowWave, FlowWaveJob } from './flow';
|
|
7
7
|
export * from './log';
|
package/build/types/testing.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export declare enum CoverageType {
|
|
|
12
12
|
}
|
|
13
13
|
export declare enum CoverageState {
|
|
14
14
|
notCovered = "not covered",
|
|
15
|
+
covered = "covered",
|
|
15
16
|
standalone = "standalone"
|
|
16
17
|
}
|
|
17
18
|
export interface Coverage {
|
|
@@ -20,6 +21,38 @@ export interface Coverage {
|
|
|
20
21
|
Coverage: CoverageState;
|
|
21
22
|
};
|
|
22
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Totals for one group of files (services, jobs, macros or all of them).
|
|
26
|
+
* `percentage` is rounded to a whole number, matching the figure printed in
|
|
27
|
+
* the console summary.
|
|
28
|
+
*/
|
|
29
|
+
export interface CoverageSummary {
|
|
30
|
+
covered: number;
|
|
31
|
+
total: number;
|
|
32
|
+
percentage: number;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The content of the coverage report `sasjs compile` writes to
|
|
36
|
+
* `coverage.json` in the build folder.
|
|
37
|
+
*
|
|
38
|
+
* `summary` carries the same totals as the console output. `files` is a
|
|
39
|
+
* complete per-file map - every service, job and macro the compile found,
|
|
40
|
+
* each marked `covered` or `not covered`, plus standalone tests - keyed by
|
|
41
|
+
* project-relative path (`services/common/appinit.sas`,
|
|
42
|
+
* `macros/mymacro.sas`), never by a path from the machine that compiled it.
|
|
43
|
+
*
|
|
44
|
+
* The console table renders this same map, so the rows a reader sees and the
|
|
45
|
+
* keys a consumer reads are the same, covered rows included.
|
|
46
|
+
*/
|
|
47
|
+
export interface CoverageReport {
|
|
48
|
+
summary: {
|
|
49
|
+
services: CoverageSummary;
|
|
50
|
+
jobs: CoverageSummary;
|
|
51
|
+
macros: CoverageSummary;
|
|
52
|
+
overall: CoverageSummary;
|
|
53
|
+
};
|
|
54
|
+
files: Coverage;
|
|
55
|
+
}
|
|
23
56
|
export interface TestResultDescription {
|
|
24
57
|
TEST_DESCRIPTION: string;
|
|
25
58
|
TEST_RESULT: TestResultStatus.pass | TestResultStatus.fail;
|
package/build/types/testing.js
CHANGED
|
@@ -11,6 +11,7 @@ var CoverageType;
|
|
|
11
11
|
var CoverageState;
|
|
12
12
|
(function (CoverageState) {
|
|
13
13
|
CoverageState["notCovered"] = "not covered";
|
|
14
|
+
CoverageState["covered"] = "covered";
|
|
14
15
|
CoverageState["standalone"] = "standalone";
|
|
15
16
|
})(CoverageState || (exports.CoverageState = CoverageState = {}));
|
|
16
17
|
var TestResultStatus;
|
package/package.json
CHANGED