@sasjs/cli 6.14.0 → 6.15.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/sw.js +509 -174
- package/build/commands/build/internal/mockSite/mockSite.js +32 -8
- package/build/commands/build/internal/mockSite/spec/mockSite.spec.js +78 -5
- package/build/commands/build/internal/mockSite/spec/sw.spec.js +532 -56
- package/package.json +1 -1
|
@@ -391,6 +391,37 @@ var EXECUTABLE_TYPES = [
|
|
|
391
391
|
'text/javascript',
|
|
392
392
|
'application/javascript'
|
|
393
393
|
];
|
|
394
|
+
/**
|
|
395
|
+
* Tells the interface that this page is answered by the browser host.
|
|
396
|
+
*
|
|
397
|
+
* A mock site is the server's own interface running against a service worker,
|
|
398
|
+
* and nothing in the document said so: the API answers the same routes, the same
|
|
399
|
+
* mode and the same run times a desktop server does, so an interface could not
|
|
400
|
+
* tell a visitor what they were looking at. sasjs/server reads the tag and, where
|
|
401
|
+
* it is absent, knows the server answered the page.
|
|
402
|
+
*
|
|
403
|
+
* The insertion is reported when the page has no `<head>`, the way the other two
|
|
404
|
+
* rewrites report markup they could not find - silently leaving the tag off a
|
|
405
|
+
* page the browser host cannot mark is what the reader of the absence rule would
|
|
406
|
+
* misread as "a server answered this". The check for an existing tag is scoped
|
|
407
|
+
* to the head, because a page may mention the tag in a script or a template
|
|
408
|
+
* without carrying it, and a document-wide test would then insert nothing.
|
|
409
|
+
*/
|
|
410
|
+
var HOST_TAG = '<meta name="sasjs-host" content="browser" />';
|
|
411
|
+
var HOST_TAG_PATTERN = /<meta\s+name=["']sasjs-host["']/i;
|
|
412
|
+
var markBrowserHost = function (html, warnings) {
|
|
413
|
+
var head = /<head(\s[^>]*)?>/i.exec(html);
|
|
414
|
+
if (!head) {
|
|
415
|
+
warnings.push('no <head> element found - the sasjs-host tag was not added, so the page will read as server-answered');
|
|
416
|
+
return html;
|
|
417
|
+
}
|
|
418
|
+
var start = head.index + head[0].length;
|
|
419
|
+
var close = html.toLowerCase().indexOf('</head>', start);
|
|
420
|
+
var inHead = close < 0 ? html.slice(start) : html.slice(start, close);
|
|
421
|
+
if (HOST_TAG_PATTERN.test(inHead))
|
|
422
|
+
return html;
|
|
423
|
+
return html.slice(0, start) + HOST_TAG + html.slice(start);
|
|
424
|
+
};
|
|
394
425
|
/**
|
|
395
426
|
* Points the app at its own origin and replaces its script tags with the boot
|
|
396
427
|
* loader. Both changes are reported when the expected markup is absent, rather
|
|
@@ -399,14 +430,7 @@ var EXECUTABLE_TYPES = [
|
|
|
399
430
|
var patchIndexHtml = function (html, version) {
|
|
400
431
|
var warnings = [];
|
|
401
432
|
var patched = html;
|
|
402
|
-
|
|
403
|
-
// wants to say so: the server's own interface reads it to describe the host
|
|
404
|
-
// it is running on, and a browser host is a different thing to explain than a
|
|
405
|
-
// server process. Absence means the server answered the page.
|
|
406
|
-
if (!/<meta\s+name=["']sasjs-host["']/i.test(patched))
|
|
407
|
-
patched = patched.replace(/<head(\s[^>]*)?>/i, function (head) {
|
|
408
|
-
return "".concat(head, "\n <meta name=\"sasjs-host\" content=\"browser\" />");
|
|
409
|
-
});
|
|
433
|
+
patched = markBrowserHost(patched, warnings);
|
|
410
434
|
if (/<sasjs[^>]*>/i.test(patched)) {
|
|
411
435
|
patched = patched.replace(/(<sasjs[^>]*?)\sserverurl="[^"]*"/i, '$1 serverurl=""');
|
|
412
436
|
patched = patched.replace(/(<sasjs[^>]*?)\sloginmechanism="[^"]*"/i, '$1 loginmechanism="Default"');
|
|
@@ -368,18 +368,91 @@ describe('browser-hosted build', function () {
|
|
|
368
368
|
});
|
|
369
369
|
}); });
|
|
370
370
|
it('states in the page that the API is answered here', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
371
|
-
var html;
|
|
371
|
+
var html, tag;
|
|
372
372
|
return __generator(this, function (_a) {
|
|
373
373
|
switch (_a.label) {
|
|
374
374
|
case 0: return [4 /*yield*/, (0, mockSite_1.buildMockSite)(target())];
|
|
375
375
|
case 1:
|
|
376
376
|
_a.sent();
|
|
377
377
|
html = fs_1.default.readFileSync(path_1.default.join(out(), 'index.html'), 'utf8');
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
378
|
+
tag = '<meta name="sasjs-host" content="browser" />';
|
|
379
|
+
expect(html).toContain(tag);
|
|
380
|
+
expect(html.indexOf(tag)).toBeLessThan(html.indexOf('</head>'));
|
|
381
|
+
// once: the tag it inserts is the one the guard then finds
|
|
382
|
+
expect(html.split('sasjs-host').length - 1).toBe(1);
|
|
383
|
+
return [2 /*return*/];
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
}); });
|
|
387
|
+
it('leaves a page that already carries the host tag alone', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
388
|
+
var html;
|
|
389
|
+
return __generator(this, function (_a) {
|
|
390
|
+
switch (_a.label) {
|
|
391
|
+
case 0:
|
|
392
|
+
write(path_1.default.join(root, 'client', 'dist', 'index.html'), [
|
|
393
|
+
'<!doctype html><html><head>',
|
|
394
|
+
'<meta name="sasjs-host" content="browser">',
|
|
395
|
+
'</head><body><script src="main.abc123.js"></script></body></html>'
|
|
396
|
+
].join('\n'));
|
|
397
|
+
return [4 /*yield*/, (0, mockSite_1.buildMockSite)(target())];
|
|
398
|
+
case 1:
|
|
399
|
+
_a.sent();
|
|
400
|
+
html = fs_1.default.readFileSync(path_1.default.join(out(), 'index.html'), 'utf8');
|
|
401
|
+
expect(html.split('sasjs-host').length - 1).toBe(1);
|
|
402
|
+
return [2 /*return*/];
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
}); });
|
|
406
|
+
it('inserts the tag when the page only mentions it outside the head', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
407
|
+
var html;
|
|
408
|
+
return __generator(this, function (_a) {
|
|
409
|
+
switch (_a.label) {
|
|
410
|
+
case 0:
|
|
411
|
+
write(path_1.default.join(root, 'client', 'dist', 'index.html'), [
|
|
412
|
+
'<!doctype html><html><head><title>App</title></head><body>',
|
|
413
|
+
'<script src="main.abc123.js"></script>',
|
|
414
|
+
'<template><meta name="sasjs-host" content="browser"></template>',
|
|
415
|
+
'</body></html>'
|
|
416
|
+
].join('\n'));
|
|
417
|
+
return [4 /*yield*/, (0, mockSite_1.buildMockSite)(target())];
|
|
418
|
+
case 1:
|
|
419
|
+
_a.sent();
|
|
420
|
+
html = fs_1.default.readFileSync(path_1.default.join(out(), 'index.html'), 'utf8');
|
|
421
|
+
// the template's copy is not the page's tag: the head gets its own
|
|
422
|
+
expect(html.split('sasjs-host').length - 1).toBe(2);
|
|
423
|
+
expect(html.indexOf('content="browser" />')).toBeLessThan(html.indexOf('</head>'));
|
|
424
|
+
return [2 /*return*/];
|
|
425
|
+
}
|
|
426
|
+
});
|
|
427
|
+
}); });
|
|
428
|
+
it('marks a page whose head is never closed', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
429
|
+
var html;
|
|
430
|
+
return __generator(this, function (_a) {
|
|
431
|
+
switch (_a.label) {
|
|
432
|
+
case 0:
|
|
433
|
+
write(path_1.default.join(root, 'client', 'dist', 'index.html'), '<!doctype html><html><head><title>App</title><body><script src="main.abc123.js"></script></body></html>');
|
|
434
|
+
return [4 /*yield*/, (0, mockSite_1.buildMockSite)(target())];
|
|
435
|
+
case 1:
|
|
436
|
+
_a.sent();
|
|
437
|
+
html = fs_1.default.readFileSync(path_1.default.join(out(), 'index.html'), 'utf8');
|
|
381
438
|
expect(html).toContain('<meta name="sasjs-host" content="browser" />');
|
|
382
|
-
|
|
439
|
+
return [2 /*return*/];
|
|
440
|
+
}
|
|
441
|
+
});
|
|
442
|
+
}); });
|
|
443
|
+
it('warns when a page has no head to mark', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
444
|
+
var html;
|
|
445
|
+
var _a;
|
|
446
|
+
return __generator(this, function (_b) {
|
|
447
|
+
switch (_b.label) {
|
|
448
|
+
case 0:
|
|
449
|
+
write(path_1.default.join(root, 'client', 'dist', 'index.html'), '<!doctype html><html><body><script src="main.abc123.js"></script></body></html>');
|
|
450
|
+
return [4 /*yield*/, (0, mockSite_1.buildMockSite)(target())];
|
|
451
|
+
case 1:
|
|
452
|
+
_b.sent();
|
|
453
|
+
expect((_a = process.logger) === null || _a === void 0 ? void 0 : _a.warn).toHaveBeenCalledWith(expect.stringContaining('no <head> element found'));
|
|
454
|
+
html = fs_1.default.readFileSync(path_1.default.join(out(), 'index.html'), 'utf8');
|
|
455
|
+
expect(html).not.toContain('sasjs-host');
|
|
383
456
|
return [2 /*return*/];
|
|
384
457
|
}
|
|
385
458
|
});
|