@sasjs/cli 6.30.0 → 6.31.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/build/commands/build/internal/mockSite/assets/api-console.css +365 -0
- package/build/commands/build/internal/mockSite/assets/api-console.js +762 -0
- package/build/commands/build/internal/mockSite/assets/api-index.html +83 -0
- package/build/commands/build/internal/mockSite/assets/boot.js +23 -1
- package/build/commands/build/internal/mockSite/assets/persist.js +76 -5
- package/build/commands/build/internal/mockSite/assets/runtime-core.js +413 -50
- package/build/commands/build/internal/mockSite/assets/sw.js +156 -15
- package/build/commands/build/internal/mockSite/mockSite.d.ts +25 -0
- package/build/commands/build/internal/mockSite/mockSite.js +311 -24
- package/build/commands/build/internal/mockSite/spec/apiConsole.spec.d.ts +1 -0
- package/build/commands/build/internal/mockSite/spec/apiConsole.spec.js +1371 -0
- package/build/commands/build/internal/mockSite/spec/apiConsoleBasePath.spec.d.ts +1 -0
- package/build/commands/build/internal/mockSite/spec/apiConsoleBasePath.spec.js +303 -0
- package/build/commands/build/internal/mockSite/spec/boot.spec.js +50 -3
- package/build/commands/build/internal/mockSite/spec/mockSite.spec.js +217 -3
- package/build/commands/build/internal/mockSite/spec/persist.spec.js +179 -1
- package/build/commands/build/internal/mockSite/spec/runtime-core.spec.js +546 -0
- package/build/commands/build/internal/mockSite/spec/sw.spec.js +407 -53
- package/build/commands/version/spec/version.spec.js +11 -1
- package/build/commands/version/version.d.ts +5 -3
- package/build/commands/version/version.js +17 -7
- package/build/types/mockWebBasePath.d.ts +9 -0
- package/package.json +13 -32
|
@@ -213,6 +213,10 @@ var loadPersist = function (options) {
|
|
|
213
213
|
// the identity row lives beside the drive, under its own key
|
|
214
214
|
if (options.seededIdentity)
|
|
215
215
|
fake.rows.set('current', options.seededIdentity);
|
|
216
|
+
// and the paths a visitor deleted, which a sharded site's index would
|
|
217
|
+
// otherwise restore
|
|
218
|
+
if (options.seededDeleted)
|
|
219
|
+
fake.rows.set('deleted', options.seededDeleted);
|
|
216
220
|
return fake;
|
|
217
221
|
})();
|
|
218
222
|
global.indexedDB = idb;
|
|
@@ -228,6 +232,40 @@ var loadPersist = function (options) {
|
|
|
228
232
|
stored: local
|
|
229
233
|
};
|
|
230
234
|
};
|
|
235
|
+
/**
|
|
236
|
+
* Waits for the store's own handshake to land.
|
|
237
|
+
*
|
|
238
|
+
* A persist message is answered by a chain of transactions - write the files,
|
|
239
|
+
* read the tombstone list, write it back - and the page does not expose the
|
|
240
|
+
* promise. A fixed sleep is a race on a slow runner (Windows was the one that
|
|
241
|
+
* failed), so the assertions poll for the change they expect instead.
|
|
242
|
+
*/
|
|
243
|
+
var settleUntil = function (check_1) {
|
|
244
|
+
var args_1 = [];
|
|
245
|
+
for (var _i = 1; _i < arguments.length; _i++) {
|
|
246
|
+
args_1[_i - 1] = arguments[_i];
|
|
247
|
+
}
|
|
248
|
+
return __awaiter(void 0, __spreadArray([check_1], __read(args_1), false), void 0, function (check, timeout) {
|
|
249
|
+
var started;
|
|
250
|
+
if (timeout === void 0) { timeout = 4000; }
|
|
251
|
+
return __generator(this, function (_a) {
|
|
252
|
+
switch (_a.label) {
|
|
253
|
+
case 0:
|
|
254
|
+
started = Date.now();
|
|
255
|
+
_a.label = 1;
|
|
256
|
+
case 1:
|
|
257
|
+
if (!(Date.now() - started < timeout)) return [3 /*break*/, 3];
|
|
258
|
+
if (check())
|
|
259
|
+
return [2 /*return*/];
|
|
260
|
+
return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, 10); })];
|
|
261
|
+
case 2:
|
|
262
|
+
_a.sent();
|
|
263
|
+
return [3 /*break*/, 1];
|
|
264
|
+
case 3: return [2 /*return*/];
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
};
|
|
231
269
|
describe('page-side store', function () {
|
|
232
270
|
afterEach(function () {
|
|
233
271
|
jest.useRealTimers();
|
|
@@ -440,7 +478,7 @@ describe('page-side store', function () {
|
|
|
440
478
|
case 0:
|
|
441
479
|
_a = loadPersist(), window = _a.window, reply = _a.reply, rows = _a.rows;
|
|
442
480
|
reply({ type: 'sasjs-persist', files: { '/sasjs/drive/c.txt': 'ccc' } });
|
|
443
|
-
return [4 /*yield*/,
|
|
481
|
+
return [4 /*yield*/, settleUntil(function () { return rows.get('/sasjs/drive/c.txt') === 'ccc'; })];
|
|
444
482
|
case 1:
|
|
445
483
|
_b.sent();
|
|
446
484
|
expect(rows.get('/sasjs/drive/c.txt')).toBe('ccc');
|
|
@@ -448,6 +486,146 @@ describe('page-side store', function () {
|
|
|
448
486
|
}
|
|
449
487
|
});
|
|
450
488
|
}); });
|
|
489
|
+
/**
|
|
490
|
+
* A deletion has to outlive the worker, and the page is the only store that can
|
|
491
|
+
* keep it.
|
|
492
|
+
*
|
|
493
|
+
* The drive in a sharded build is not all in the page either: the index lists
|
|
494
|
+
* every file the build ships, so a file the visitor deleted comes back on the
|
|
495
|
+
* next load unless the path is remembered here and handed to the worker at
|
|
496
|
+
* boot.
|
|
497
|
+
*/
|
|
498
|
+
it('remembers a deleted path, and forgets it when the path is written again', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
499
|
+
var _a, window, reply, rows;
|
|
500
|
+
return __generator(this, function (_b) {
|
|
501
|
+
switch (_b.label) {
|
|
502
|
+
case 0:
|
|
503
|
+
_a = loadPersist({
|
|
504
|
+
seeded: { '/sasjs/drive/a.txt': 'a', '/sasjs/drive/b.txt': 'b' }
|
|
505
|
+
}), window = _a.window, reply = _a.reply, rows = _a.rows;
|
|
506
|
+
reply({ type: 'sasjs-persist', files: { '/sasjs/drive/a.txt': null } });
|
|
507
|
+
return [4 /*yield*/, settleUntil(function () { return rows.has('deleted'); })];
|
|
508
|
+
case 1:
|
|
509
|
+
_b.sent();
|
|
510
|
+
expect(rows.get('deleted')).toEqual(['/sasjs/drive/a.txt']);
|
|
511
|
+
// the row itself is gone, and the tombstone is what stops the index bringing
|
|
512
|
+
// it back
|
|
513
|
+
expect(rows.has('/sasjs/drive/a.txt')).toBe(false);
|
|
514
|
+
reply({ type: 'sasjs-persist', files: { '/sasjs/drive/a.txt': 'again' } });
|
|
515
|
+
// the tombstone is written back after the file, so poll for it rather than
|
|
516
|
+
// for the write that precedes it
|
|
517
|
+
return [4 /*yield*/, settleUntil(function () { return !rows.has('deleted'); })];
|
|
518
|
+
case 2:
|
|
519
|
+
// the tombstone is written back after the file, so poll for it rather than
|
|
520
|
+
// for the write that precedes it
|
|
521
|
+
_b.sent();
|
|
522
|
+
expect(rows.has('deleted')).toBe(false);
|
|
523
|
+
expect(rows.get('/sasjs/drive/a.txt')).toBe('again');
|
|
524
|
+
return [2 /*return*/];
|
|
525
|
+
}
|
|
526
|
+
});
|
|
527
|
+
}); });
|
|
528
|
+
it('writes no file when the worker could not read the drive whole', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
529
|
+
var controller, _a, page, listeners, reply, answering, pending;
|
|
530
|
+
return __generator(this, function (_b) {
|
|
531
|
+
switch (_b.label) {
|
|
532
|
+
case 0:
|
|
533
|
+
controller = { postMessage: jest.fn() };
|
|
534
|
+
_a = loadPersist({
|
|
535
|
+
controller: controller,
|
|
536
|
+
ready: Promise.resolve({})
|
|
537
|
+
}), page = _a.window, listeners = _a.listeners, reply = _a.reply;
|
|
538
|
+
answering = setInterval(function () {
|
|
539
|
+
var asked = controller.postMessage.mock.calls;
|
|
540
|
+
if (!asked.length)
|
|
541
|
+
return;
|
|
542
|
+
__spreadArray([], __read(listeners), false).forEach(function (fn) {
|
|
543
|
+
return fn({ data: { type: asked[0][0].type + '-ack', booted: true } });
|
|
544
|
+
});
|
|
545
|
+
}, 5);
|
|
546
|
+
return [4 /*yield*/, page.__sasjsMockReady];
|
|
547
|
+
case 1:
|
|
548
|
+
_b.sent();
|
|
549
|
+
clearInterval(answering);
|
|
550
|
+
pending = page.SASjsMock.download();
|
|
551
|
+
return [4 /*yield*/, Promise.resolve()
|
|
552
|
+
// the worker answers with what it has and says why it could not finish, and a
|
|
553
|
+
// file built from that would be a capture with every app bundle missing
|
|
554
|
+
];
|
|
555
|
+
case 2:
|
|
556
|
+
_b.sent();
|
|
557
|
+
// the worker answers with what it has and says why it could not finish, and a
|
|
558
|
+
// file built from that would be a capture with every app bundle missing
|
|
559
|
+
reply({
|
|
560
|
+
type: 'sasjs-snapshot',
|
|
561
|
+
files: { '/sasjs/drive/a.txt': 'a' },
|
|
562
|
+
error: 'ensureAll rejected: ENOENT'
|
|
563
|
+
});
|
|
564
|
+
return [4 /*yield*/, expect(pending).rejects.toThrow(/could not be read whole/)];
|
|
565
|
+
case 3:
|
|
566
|
+
_b.sent();
|
|
567
|
+
return [2 /*return*/];
|
|
568
|
+
}
|
|
569
|
+
});
|
|
570
|
+
}); });
|
|
571
|
+
it('drops the recorded deletions with the rest of the drive', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
572
|
+
var _a, window, listeners, rows, pending;
|
|
573
|
+
return __generator(this, function (_b) {
|
|
574
|
+
switch (_b.label) {
|
|
575
|
+
case 0:
|
|
576
|
+
_a = loadPersist({
|
|
577
|
+
seeded: { '/sasjs/drive/a.txt': 'a' },
|
|
578
|
+
seededDeleted: ['/sasjs/drive/a.txt']
|
|
579
|
+
}), window = _a.window, listeners = _a.listeners, rows = _a.rows;
|
|
580
|
+
pending = window.SASjsMock.reset();
|
|
581
|
+
return [4 /*yield*/, Promise.resolve()];
|
|
582
|
+
case 1:
|
|
583
|
+
_b.sent();
|
|
584
|
+
__spreadArray([], __read(listeners), false).forEach(function (fn) { return fn({ data: { type: 'sasjs-reset-ack' } }); });
|
|
585
|
+
return [4 /*yield*/, pending];
|
|
586
|
+
case 2:
|
|
587
|
+
_b.sent();
|
|
588
|
+
return [4 /*yield*/, settleUntil(function () { return !rows.has('deleted'); })];
|
|
589
|
+
case 3:
|
|
590
|
+
_b.sent();
|
|
591
|
+
expect(rows.has('deleted')).toBe(false);
|
|
592
|
+
return [2 /*return*/];
|
|
593
|
+
}
|
|
594
|
+
});
|
|
595
|
+
}); });
|
|
596
|
+
it('tells the worker which paths were deleted, so its index cannot restore them', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
597
|
+
var controller, _a, window, listeners, answering;
|
|
598
|
+
return __generator(this, function (_b) {
|
|
599
|
+
switch (_b.label) {
|
|
600
|
+
case 0:
|
|
601
|
+
controller = { postMessage: jest.fn() };
|
|
602
|
+
_a = loadPersist({
|
|
603
|
+
controller: controller,
|
|
604
|
+
ready: Promise.resolve({}),
|
|
605
|
+
seeded: { '/sasjs/drive/b.txt': 'b' },
|
|
606
|
+
seededDeleted: ['/sasjs/drive/a.txt']
|
|
607
|
+
}), window = _a.window, listeners = _a.listeners;
|
|
608
|
+
answering = setInterval(function () {
|
|
609
|
+
var asked = controller.postMessage.mock.calls;
|
|
610
|
+
if (!asked.length)
|
|
611
|
+
return;
|
|
612
|
+
var type = asked[0][0].type;
|
|
613
|
+
__spreadArray([], __read(listeners), false).forEach(function (fn) {
|
|
614
|
+
return fn({ data: { type: type + '-ack', booted: true } });
|
|
615
|
+
});
|
|
616
|
+
}, 5);
|
|
617
|
+
return [4 /*yield*/, window.__sasjsMockReady];
|
|
618
|
+
case 1:
|
|
619
|
+
_b.sent();
|
|
620
|
+
clearInterval(answering);
|
|
621
|
+
expect(controller.postMessage.mock.calls[0][0]).toEqual(expect.objectContaining({
|
|
622
|
+
type: 'sasjs-load',
|
|
623
|
+
deleted: ['/sasjs/drive/a.txt']
|
|
624
|
+
}));
|
|
625
|
+
return [2 /*return*/];
|
|
626
|
+
}
|
|
627
|
+
});
|
|
628
|
+
}); });
|
|
451
629
|
it('resets the worker and the stored drive together', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
452
630
|
var _a, window, posted, reply, rows, pending;
|
|
453
631
|
return __generator(this, function (_b) {
|