@sasjs/cli 6.31.0 → 6.32.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.js +42 -7
- package/build/commands/build/internal/mockSite/assets/api-index.html +1 -1
- package/build/commands/build/internal/mockSite/assets/sw.js +5 -28
- package/build/commands/build/internal/mockSite/mockSite.d.ts +1 -1
- package/build/commands/build/internal/mockSite/mockSite.js +14 -9
- package/build/commands/build/internal/mockSite/spec/apiConsole.spec.js +74 -8
- package/build/commands/build/internal/mockSite/spec/apiConsoleBasePath.spec.js +121 -9
- package/build/commands/build/internal/mockSite/spec/mockSite.spec.js +9 -11
- package/build/commands/build/internal/mockSite/spec/sw.spec.js +63 -85
- package/build/types/mockWebBasePath.d.ts +1 -1
- package/package.json +1 -1
|
@@ -23,13 +23,34 @@
|
|
|
23
23
|
'use strict'
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
* The site's root
|
|
27
|
-
*
|
|
26
|
+
* The site's root.
|
|
27
|
+
*
|
|
28
|
+
* Taken from the worker that controls this page, `<base>/sw.js`: that is the
|
|
29
|
+
* one statement of the base the page carries, and it holds wherever the console
|
|
30
|
+
* sits - a copy under `<base>/tools/api-console/` still calls the site's own
|
|
31
|
+
* API rather than a folder that happens to be two levels up. Only a worker
|
|
32
|
+
* whose root covers this page counts, since a page can be controlled by another
|
|
33
|
+
* site's worker, and one registered below the page names a folder inside it. A
|
|
34
|
+
* page with no such worker falls back to its own URL, one level below the root.
|
|
28
35
|
*/
|
|
29
36
|
const base = (function () {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
37
|
+
// this page's own folder, however it was typed: with the page, with the
|
|
38
|
+
// file, or without the trailing slash
|
|
39
|
+
let dir = location.pathname
|
|
40
|
+
if (/\/index\.html?$/.test(dir)) dir = dir.replace(/index\.html?$/, '')
|
|
41
|
+
if (!dir.endsWith('/')) dir += '/'
|
|
42
|
+
const parent = dir.replace(/[^/]+\/$/, '')
|
|
43
|
+
|
|
44
|
+
const script =
|
|
45
|
+
navigator.serviceWorker && navigator.serviceWorker.controller
|
|
46
|
+
? navigator.serviceWorker.controller.scriptURL
|
|
47
|
+
: ''
|
|
48
|
+
if (script) {
|
|
49
|
+
const swPath = new URL(script).pathname
|
|
50
|
+
const root = /\/sw\.js$/.test(swPath) ? swPath.replace(/sw\.js$/, '') : ''
|
|
51
|
+
if (root && parent.startsWith(root)) return root
|
|
52
|
+
}
|
|
53
|
+
return parent || '/'
|
|
33
54
|
})()
|
|
34
55
|
|
|
35
56
|
const apiUrl = (path) => base + String(path).replace(/^\/+/, '')
|
|
@@ -76,7 +97,7 @@
|
|
|
76
97
|
* Starts the demo backend for this page.
|
|
77
98
|
*
|
|
78
99
|
* The application's boot loader registers the worker; a visitor who lands on
|
|
79
|
-
* `/api/` first has no loader, and every request would reach the static host
|
|
100
|
+
* `/api-console/` first has no loader, and every request would reach the static host
|
|
80
101
|
* and 404. So: register it beside the site, wait for it to control this page,
|
|
81
102
|
* then load `host/persist.js`, which is what hands the worker the drive this
|
|
82
103
|
* browser already has and keeps whatever this page changes.
|
|
@@ -692,6 +713,14 @@
|
|
|
692
713
|
)
|
|
693
714
|
})
|
|
694
715
|
|
|
716
|
+
/** Where a reset returns to: this page, without the flag but with the route. */
|
|
717
|
+
const resetTarget = () => {
|
|
718
|
+
const query = new URLSearchParams(location.search)
|
|
719
|
+
query.delete('reset')
|
|
720
|
+
const rest = query.toString()
|
|
721
|
+
return location.pathname + (rest ? '?' + rest : '')
|
|
722
|
+
}
|
|
723
|
+
|
|
695
724
|
/**
|
|
696
725
|
* `?reset=1` starts the demo again from the state the build ships.
|
|
697
726
|
*
|
|
@@ -719,7 +748,9 @@
|
|
|
719
748
|
'The demo could not be reset: ' + ((e && e.message) || e)
|
|
720
749
|
return true
|
|
721
750
|
}
|
|
722
|
-
|
|
751
|
+
// back to this page, with the flag gone: the console's folder is the page's
|
|
752
|
+
// own, so a build that moves the folder cannot strand the redirect
|
|
753
|
+
location.replace(resetTarget())
|
|
723
754
|
return true
|
|
724
755
|
}
|
|
725
756
|
|
|
@@ -755,6 +786,10 @@
|
|
|
755
786
|
if (chosen) select(chosen)
|
|
756
787
|
}
|
|
757
788
|
|
|
789
|
+
// the redirect itself cannot be observed in a page that does not navigate; the
|
|
790
|
+
// choice of target can, and it is what a folder move would break
|
|
791
|
+
window.SASjsApiConsole = { resetTarget }
|
|
792
|
+
|
|
758
793
|
start().catch((e) => {
|
|
759
794
|
const list = el('routes')
|
|
760
795
|
if (list) list.textContent = 'The console could not start: ' + e.message
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
The API console for a browser-hosted build.
|
|
10
10
|
|
|
11
11
|
Static, and deliberately so: no bundler, no framework, no network of its
|
|
12
|
-
own beyond the API it is documenting. It is served from <base>/api/ and
|
|
12
|
+
own beyond the API it is documenting. It is served from <base>/api-console/ and
|
|
13
13
|
every request it makes is the same request an application makes, so the
|
|
14
14
|
service worker answers it and the answer is the mock's real answer.
|
|
15
15
|
|
|
@@ -1732,22 +1732,6 @@ const handle = async (request, url) => {
|
|
|
1732
1732
|
return response
|
|
1733
1733
|
}
|
|
1734
1734
|
|
|
1735
|
-
// The console's own files under `/api/`, replaced at build time from the list the
|
|
1736
|
-
// builder writes the folder from, so the two cannot drift apart.
|
|
1737
|
-
const API_CONSOLE_FILES = [
|
|
1738
|
-
'index.html',
|
|
1739
|
-
'console.js',
|
|
1740
|
-
'console.css',
|
|
1741
|
-
'operations.json'
|
|
1742
|
-
]
|
|
1743
|
-
|
|
1744
|
-
const CONSOLE_FILE = new RegExp(
|
|
1745
|
-
'^/api/(' +
|
|
1746
|
-
API_CONSOLE_FILES.map((name) => name.replace(/\./g, '\\.')).join('|') +
|
|
1747
|
-
')$',
|
|
1748
|
-
'i'
|
|
1749
|
-
)
|
|
1750
|
-
|
|
1751
1735
|
self.addEventListener('fetch', (event) => {
|
|
1752
1736
|
const url = new URL(event.request.url)
|
|
1753
1737
|
if (url.origin !== self.location.origin) return
|
|
@@ -1780,20 +1764,13 @@ self.addEventListener('fetch', (event) => {
|
|
|
1780
1764
|
// listing is the server's web route, and an interface that lists apps asks for
|
|
1781
1765
|
// it on every visit.
|
|
1782
1766
|
//
|
|
1783
|
-
// `/api` and `/api/` on their own are the
|
|
1784
|
-
//
|
|
1785
|
-
//
|
|
1786
|
-
// spelling, which routeRequest
|
|
1767
|
+
// `/api` and `/api/` on their own are left to the static host: a site's own
|
|
1768
|
+
// application can answer that route (this framework's server interface does),
|
|
1769
|
+
// and the worker has no business putting an API answer in front of it. Every
|
|
1770
|
+
// other `/api/...` is an API call on the short spelling, which routeRequest
|
|
1771
|
+
// canonicalises to `/SASjsApi`.
|
|
1787
1772
|
if (/^\/api\/?$/i.test(path)) return
|
|
1788
1773
|
|
|
1789
|
-
// And the console's own files, which live under that prefix: a path naming one
|
|
1790
|
-
// of them is the page's, not an API call, so the static host answers it. Named
|
|
1791
|
-
// one by one on purpose - an extension test would also pass through
|
|
1792
|
-
// `/api/admin/logs/foo.log`, which is a real call on the short spelling. The
|
|
1793
|
-
// list is replaced at build time with the one the builder writes the folder
|
|
1794
|
-
// from, so a file added there cannot arrive here as an API path.
|
|
1795
|
-
if (CONSOLE_FILE.test(path)) return
|
|
1796
|
-
|
|
1797
1774
|
if (!/^\/(SASjsApi|SASLogon|AppStream|api|app)(\/|$)/i.test(path)) return
|
|
1798
1775
|
event.respondWith(handle(event.request, url))
|
|
1799
1776
|
})
|
|
@@ -14,7 +14,7 @@ export interface MockSiteResult {
|
|
|
14
14
|
* large folder or file. Zero when the site ships no snapshot.
|
|
15
15
|
*/
|
|
16
16
|
snapshotShards: number;
|
|
17
|
-
/** True when the site carries the API console at <base>/api/. */
|
|
17
|
+
/** True when the site carries the API console at <base>/api-console/. */
|
|
18
18
|
apiConsole: boolean;
|
|
19
19
|
/** True when a recorded SAS session was shipped, for .sas runs to answer. */
|
|
20
20
|
sasTranscript: boolean;
|
|
@@ -1008,7 +1008,15 @@ var patchIndexHtml = function (html, version, basePath, outputFolder) {
|
|
|
1008
1008
|
}
|
|
1009
1009
|
return { patched: patched, warnings: warnings };
|
|
1010
1010
|
};
|
|
1011
|
-
/**
|
|
1011
|
+
/**
|
|
1012
|
+
* The folder the console lives in, under the site root.
|
|
1013
|
+
*
|
|
1014
|
+
* Not `api`: an application can answer `/api` itself - this framework's own server
|
|
1015
|
+
* interface does - and a page there would collide with its route, so a site
|
|
1016
|
+
* refresh on that screen would land on the console instead of the application.
|
|
1017
|
+
*/
|
|
1018
|
+
var API_CONSOLE_DIR = 'api-console';
|
|
1019
|
+
/** The files the console consists of, under `<output>/api-console`. */
|
|
1012
1020
|
var API_CONSOLE_FILES = [
|
|
1013
1021
|
'index.html',
|
|
1014
1022
|
'console.js',
|
|
@@ -1016,7 +1024,7 @@ var API_CONSOLE_FILES = [
|
|
|
1016
1024
|
'operations.json'
|
|
1017
1025
|
];
|
|
1018
1026
|
/**
|
|
1019
|
-
* The API console: a page at `<base>/api/` that lists every operation the API
|
|
1027
|
+
* The API console: a page at `<base>/api-console/` that lists every operation the API
|
|
1020
1028
|
* document declares and sends them against this host.
|
|
1021
1029
|
*
|
|
1022
1030
|
* The route table is the same one the worker answers from (`ROUTES` from
|
|
@@ -1028,8 +1036,8 @@ var API_CONSOLE_FILES = [
|
|
|
1028
1036
|
* a visit costs the demo nothing until someone types the URL.
|
|
1029
1037
|
*/
|
|
1030
1038
|
var writeApiConsole = function (outputFolder, version) {
|
|
1031
|
-
var folder = path_1.default.join(outputFolder,
|
|
1032
|
-
// `<base>/api/` is this build's, not the project's: a site that ships its own
|
|
1039
|
+
var folder = path_1.default.join(outputFolder, API_CONSOLE_DIR);
|
|
1040
|
+
// `<base>/api-console/` is this build's, not the project's: a site that ships its own
|
|
1033
1041
|
// files there would have them replaced without a word, so it keeps them and
|
|
1034
1042
|
// the console is left out
|
|
1035
1043
|
var taken = API_CONSOLE_FILES.filter(function (file) {
|
|
@@ -1040,7 +1048,7 @@ var writeApiConsole = function (outputFolder, version) {
|
|
|
1040
1048
|
written: false,
|
|
1041
1049
|
operations: 0,
|
|
1042
1050
|
warning: "The site already carries ".concat(taken
|
|
1043
|
-
.map(function (file) { return '
|
|
1051
|
+
.map(function (file) { return API_CONSOLE_DIR + '/' + file; })
|
|
1044
1052
|
.join(', '), ", so the API console was not written. ") +
|
|
1045
1053
|
'Move those files, or set streamConfig.mockApi to false to silence this.'
|
|
1046
1054
|
};
|
|
@@ -1260,10 +1268,7 @@ function buildMockSite(target) {
|
|
|
1260
1268
|
.readFileSync(swPath, 'utf8')
|
|
1261
1269
|
.replace("importScripts('host/runtime-core.js')", "importScripts('host/runtime-core.js?v=".concat(hostVersion, "')"))
|
|
1262
1270
|
.replace("importScripts('host/api-browser.js')", "importScripts('host/api-browser.js?v=".concat(hostVersion, "')"))
|
|
1263
|
-
.replace("importScripts('host/lint-browser.js')", "importScripts('host/lint-browser.js?v=".concat(hostVersion, "')"))
|
|
1264
|
-
// the console's file list, from the one place that writes the folder: a
|
|
1265
|
-
// second copy here would let a new file be served as an API path
|
|
1266
|
-
.replace(/const API_CONSOLE_FILES = \[[^\]]*\]/, "const API_CONSOLE_FILES = ".concat(JSON.stringify(API_CONSOLE_FILES))));
|
|
1271
|
+
.replace("importScripts('host/lint-browser.js')", "importScripts('host/lint-browser.js?v=".concat(hostVersion, "')")));
|
|
1267
1272
|
snapshotSource = path_1.default.join(buildFolder, 'mock-snapshot.json');
|
|
1268
1273
|
hasSnapshot = fs_1.default.existsSync(snapshotSource);
|
|
1269
1274
|
snapshotShards = 0;
|
|
@@ -675,7 +675,7 @@ describe('the API console', function () {
|
|
|
675
675
|
case 0:
|
|
676
676
|
jest.resetModules();
|
|
677
677
|
document.body.innerHTML = bodyOf(page());
|
|
678
|
-
history.replaceState({}, '', '/api/?route=' + encodeURIComponent('GET /SASjsApi/user'));
|
|
678
|
+
history.replaceState({}, '', '/api-console/?route=' + encodeURIComponent('GET /SASjsApi/user'));
|
|
679
679
|
global.fetch = jest.fn(function (url) { return __awaiter(void 0, void 0, void 0, function () {
|
|
680
680
|
return __generator(this, function (_a) {
|
|
681
681
|
return [2 /*return*/, String(url).includes('operations.json')
|
|
@@ -699,7 +699,7 @@ describe('the API console', function () {
|
|
|
699
699
|
return [3 /*break*/, 1];
|
|
700
700
|
case 4:
|
|
701
701
|
expect(document.getElementById('title').textContent).toBe('GET /SASjsApi/user');
|
|
702
|
-
history.replaceState({}, '', '/api/');
|
|
702
|
+
history.replaceState({}, '', '/api-console/');
|
|
703
703
|
return [2 /*return*/];
|
|
704
704
|
}
|
|
705
705
|
});
|
|
@@ -1093,7 +1093,7 @@ describe('the API console', function () {
|
|
|
1093
1093
|
// jsdom does not navigate, and the redirect is the last thing the page does:
|
|
1094
1094
|
// what matters here is that the drive was reset before it
|
|
1095
1095
|
return [4 /*yield*/, loadConsole(function () {
|
|
1096
|
-
history.replaceState({}, '', '/api/?reset=1');
|
|
1096
|
+
history.replaceState({}, '', '/api-console/?reset=1');
|
|
1097
1097
|
window.SASjsMock = { reset: reset };
|
|
1098
1098
|
})];
|
|
1099
1099
|
case 1:
|
|
@@ -1105,7 +1105,7 @@ describe('the API console', function () {
|
|
|
1105
1105
|
_a.sent();
|
|
1106
1106
|
expect(reset).toHaveBeenCalled();
|
|
1107
1107
|
expect(sessionStorage.length).toBe(0);
|
|
1108
|
-
history.replaceState({}, '', '/api/');
|
|
1108
|
+
history.replaceState({}, '', '/api-console/');
|
|
1109
1109
|
return [2 /*return*/];
|
|
1110
1110
|
}
|
|
1111
1111
|
});
|
|
@@ -1125,7 +1125,7 @@ describe('the API console', function () {
|
|
|
1125
1125
|
return [4 /*yield*/, loadConsole(function () {
|
|
1126
1126
|
// no host bridge on this page at all
|
|
1127
1127
|
delete window.SASjsMock;
|
|
1128
|
-
history.replaceState({}, '', '/api/?reset=1');
|
|
1128
|
+
history.replaceState({}, '', '/api-console/?reset=1');
|
|
1129
1129
|
})];
|
|
1130
1130
|
case 1:
|
|
1131
1131
|
_a.sent();
|
|
@@ -1136,7 +1136,7 @@ describe('the API console', function () {
|
|
|
1136
1136
|
_a.sent();
|
|
1137
1137
|
expect(global.indexedDB.deleteDatabase).toHaveBeenCalledWith('sasjs-mock-host');
|
|
1138
1138
|
expect(document.getElementById('routes').textContent).toContain('still holds the drive');
|
|
1139
|
-
history.replaceState({}, '', '/api/');
|
|
1139
|
+
history.replaceState({}, '', '/api-console/');
|
|
1140
1140
|
delete global.indexedDB;
|
|
1141
1141
|
return [2 /*return*/];
|
|
1142
1142
|
}
|
|
@@ -1152,7 +1152,7 @@ describe('the API console', function () {
|
|
|
1152
1152
|
}); }); });
|
|
1153
1153
|
sessionStorage.setItem('mock-console-token', 'kept');
|
|
1154
1154
|
return [4 /*yield*/, loadConsole(function () {
|
|
1155
|
-
history.replaceState({}, '', '/api/?reset=0');
|
|
1155
|
+
history.replaceState({}, '', '/api-console/?reset=0');
|
|
1156
1156
|
window.SASjsMock = { reset: reset };
|
|
1157
1157
|
})];
|
|
1158
1158
|
case 1:
|
|
@@ -1162,7 +1162,7 @@ describe('the API console', function () {
|
|
|
1162
1162
|
_a.sent();
|
|
1163
1163
|
expect(reset).not.toHaveBeenCalled();
|
|
1164
1164
|
expect(sessionStorage.getItem('mock-console-token')).toBe('kept');
|
|
1165
|
-
history.replaceState({}, '', '/api/');
|
|
1165
|
+
history.replaceState({}, '', '/api-console/');
|
|
1166
1166
|
return [2 /*return*/];
|
|
1167
1167
|
}
|
|
1168
1168
|
});
|
|
@@ -1331,6 +1331,72 @@ describe('the API console', function () {
|
|
|
1331
1331
|
}
|
|
1332
1332
|
});
|
|
1333
1333
|
}); });
|
|
1334
|
+
it('says so, rather than reloading again, when the worker never claims the page', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
1335
|
+
var error, host, i;
|
|
1336
|
+
return __generator(this, function (_a) {
|
|
1337
|
+
switch (_a.label) {
|
|
1338
|
+
case 0:
|
|
1339
|
+
error = jest.spyOn(console, 'error').mockImplementation(function () { });
|
|
1340
|
+
host = withServiceWorker();
|
|
1341
|
+
sessionStorage.setItem('mock-console-reloaded', '1');
|
|
1342
|
+
return [4 /*yield*/, loadConsole()];
|
|
1343
|
+
case 1:
|
|
1344
|
+
_a.sent();
|
|
1345
|
+
i = 0;
|
|
1346
|
+
_a.label = 2;
|
|
1347
|
+
case 2:
|
|
1348
|
+
if (!(i < 200)) return [3 /*break*/, 5];
|
|
1349
|
+
if (error.mock.calls.some(function (call) { return /take control/.test(String(call[0])); }))
|
|
1350
|
+
return [3 /*break*/, 5];
|
|
1351
|
+
return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, 25); })];
|
|
1352
|
+
case 3:
|
|
1353
|
+
_a.sent();
|
|
1354
|
+
_a.label = 4;
|
|
1355
|
+
case 4:
|
|
1356
|
+
i++;
|
|
1357
|
+
return [3 /*break*/, 2];
|
|
1358
|
+
case 5:
|
|
1359
|
+
expect(error.mock.calls.some(function (call) { return /take control/.test(String(call[0])); })).toBe(true);
|
|
1360
|
+
expect(host.sw.register).toHaveBeenCalled();
|
|
1361
|
+
error.mockRestore();
|
|
1362
|
+
return [2 /*return*/];
|
|
1363
|
+
}
|
|
1364
|
+
});
|
|
1365
|
+
}); });
|
|
1366
|
+
it('returns to its own page after a reset, wherever that page is', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
1367
|
+
var deleted, page;
|
|
1368
|
+
return __generator(this, function (_a) {
|
|
1369
|
+
switch (_a.label) {
|
|
1370
|
+
case 0:
|
|
1371
|
+
deleted = [];
|
|
1372
|
+
global.indexedDB = {
|
|
1373
|
+
deleteDatabase: function (name) {
|
|
1374
|
+
deleted.push(name);
|
|
1375
|
+
var request = {};
|
|
1376
|
+
setTimeout(function () { return request.onsuccess && request.onsuccess(); }, 5);
|
|
1377
|
+
return request;
|
|
1378
|
+
}
|
|
1379
|
+
};
|
|
1380
|
+
return [4 /*yield*/, loadConsole(function () {
|
|
1381
|
+
delete window.SASjsMock;
|
|
1382
|
+
history.replaceState({}, '', '/demo/api-console/?reset=1&route=GET%20%2FSASjsApi%2Fuser');
|
|
1383
|
+
})];
|
|
1384
|
+
case 1:
|
|
1385
|
+
_a.sent();
|
|
1386
|
+
return [4 /*yield*/, settle(function () { return deleted.length > 0; })];
|
|
1387
|
+
case 2:
|
|
1388
|
+
_a.sent();
|
|
1389
|
+
page = window.SASjsApiConsole;
|
|
1390
|
+
expect(page).toBeDefined();
|
|
1391
|
+
// the folder is the page's, the flag goes, and the route the visitor was on
|
|
1392
|
+
// stays: a reset should not cost them the deep link
|
|
1393
|
+
expect(page.resetTarget()).toBe('/demo/api-console/?route=GET+%2FSASjsApi%2Fuser');
|
|
1394
|
+
delete global.indexedDB;
|
|
1395
|
+
history.replaceState({}, '', '/api-console/');
|
|
1396
|
+
return [2 /*return*/];
|
|
1397
|
+
}
|
|
1398
|
+
});
|
|
1399
|
+
}); });
|
|
1334
1400
|
it('drops the token when the visitor goes back to the demo administrator', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
1335
1401
|
var calls, back;
|
|
1336
1402
|
return __generator(this, function (_a) {
|
|
@@ -66,7 +66,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
66
66
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
67
67
|
/**
|
|
68
68
|
* @jest-environment jsdom
|
|
69
|
-
* @jest-environment-options {"url": "http://localhost/demo/api/"}
|
|
69
|
+
* @jest-environment-options {"url": "http://localhost/demo/api-console/"}
|
|
70
70
|
*/
|
|
71
71
|
var fs_1 = __importDefault(require("fs"));
|
|
72
72
|
var path_1 = __importDefault(require("path"));
|
|
@@ -74,11 +74,10 @@ var path_1 = __importDefault(require("path"));
|
|
|
74
74
|
* The console under a base path.
|
|
75
75
|
*
|
|
76
76
|
* `mockWebBasePath` is a supported option (a site published at `/demo`), and the
|
|
77
|
-
* console
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
* still renders, and every call goes to a path the host does not answer.
|
|
77
|
+
* console works out its root from the worker it registered - `<base>/sw.js` - with
|
|
78
|
+
* its own URL as the fallback. This file runs the page at `/demo/api-console/`,
|
|
79
|
+
* where a wrong derivation is silent: the page still renders, and every call goes
|
|
80
|
+
* to a path the host does not answer.
|
|
82
81
|
*/
|
|
83
82
|
var assets = path_1.default.join(__dirname, '..', 'assets');
|
|
84
83
|
var page = function () { return fs_1.default.readFileSync(path_1.default.join(assets, 'api-index.html'), 'utf8'); };
|
|
@@ -136,6 +135,119 @@ describe('the API console under a base path', function () {
|
|
|
136
135
|
afterEach(function () {
|
|
137
136
|
delete navigator.serviceWorker;
|
|
138
137
|
});
|
|
138
|
+
it('takes the root from the worker that covers it, not from its own folder', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
139
|
+
var realCreate, sw, asked;
|
|
140
|
+
return __generator(this, function (_a) {
|
|
141
|
+
switch (_a.label) {
|
|
142
|
+
case 0:
|
|
143
|
+
// the shapes where the two disagree are the only ones that prove the worker
|
|
144
|
+
// is read at all: the site's worker at `/demo/sw.js` controlling a console
|
|
145
|
+
// two folders down still names `/demo/`, which the folder alone cannot
|
|
146
|
+
document.body.innerHTML = bodyOf(page());
|
|
147
|
+
document.head.innerHTML =
|
|
148
|
+
'<meta name="sasjs-mock-version" content="3.0.0" />';
|
|
149
|
+
global.fetch = jest.fn(function (url) { return __awaiter(void 0, void 0, void 0, function () {
|
|
150
|
+
return __generator(this, function (_a) {
|
|
151
|
+
return [2 /*return*/, String(url).includes('operations.json')
|
|
152
|
+
? jsonResponse(operations)
|
|
153
|
+
: jsonResponse({ format: 1, users: [] })];
|
|
154
|
+
});
|
|
155
|
+
}); });
|
|
156
|
+
realCreate = document.createElement.bind(document);
|
|
157
|
+
jest.spyOn(document, 'createElement').mockImplementation(function (tag) {
|
|
158
|
+
var node = realCreate(tag);
|
|
159
|
+
if (String(tag).toLowerCase() === 'script')
|
|
160
|
+
setTimeout(function () { return node.dispatchEvent(new Event('load')); }, 0);
|
|
161
|
+
return node;
|
|
162
|
+
});
|
|
163
|
+
sw = {
|
|
164
|
+
controller: { scriptURL: 'http://localhost/demo/sw.js' },
|
|
165
|
+
register: jest.fn(function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
166
|
+
return [2 /*return*/, ({})];
|
|
167
|
+
}); }); }),
|
|
168
|
+
addEventListener: jest.fn()
|
|
169
|
+
};
|
|
170
|
+
Object.defineProperty(navigator, 'serviceWorker', {
|
|
171
|
+
value: sw,
|
|
172
|
+
configurable: true
|
|
173
|
+
});
|
|
174
|
+
history.replaceState({}, '', '/demo/tools/api-console/');
|
|
175
|
+
jest.resetModules();
|
|
176
|
+
require('../assets/api-console.js');
|
|
177
|
+
return [4 /*yield*/, settle(function () {
|
|
178
|
+
return global.fetch.mock.calls.some(function (call) {
|
|
179
|
+
return String(call[0]).includes('identity.json');
|
|
180
|
+
});
|
|
181
|
+
})];
|
|
182
|
+
case 1:
|
|
183
|
+
_a.sent();
|
|
184
|
+
asked = global.fetch.mock.calls.map(function (call) {
|
|
185
|
+
return String(call[0]);
|
|
186
|
+
});
|
|
187
|
+
// the site's root, not the folder two levels up from the page
|
|
188
|
+
expect(asked).toContain('/demo/host/identity.json');
|
|
189
|
+
expect(asked.some(function (url) { return url.startsWith('/demo/tools/'); })).toBe(false);
|
|
190
|
+
history.replaceState({}, '', '/demo/tools/api-console/');
|
|
191
|
+
return [2 /*return*/];
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
}); });
|
|
195
|
+
it('ignores a worker that belongs to another site', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
196
|
+
var realCreate, sw, asked;
|
|
197
|
+
return __generator(this, function (_a) {
|
|
198
|
+
switch (_a.label) {
|
|
199
|
+
case 0:
|
|
200
|
+
// a page can be controlled by some other site's worker; its `sw.js` names a
|
|
201
|
+
// root that has nothing to do with this console, so the page's own folder has
|
|
202
|
+
// to win
|
|
203
|
+
document.body.innerHTML = bodyOf(page());
|
|
204
|
+
document.head.innerHTML =
|
|
205
|
+
'<meta name="sasjs-mock-version" content="3.0.0" />';
|
|
206
|
+
global.fetch = jest.fn(function (url) { return __awaiter(void 0, void 0, void 0, function () {
|
|
207
|
+
return __generator(this, function (_a) {
|
|
208
|
+
return [2 /*return*/, String(url).includes('operations.json')
|
|
209
|
+
? jsonResponse(operations)
|
|
210
|
+
: jsonResponse({ format: 1, users: [] })];
|
|
211
|
+
});
|
|
212
|
+
}); });
|
|
213
|
+
realCreate = document.createElement.bind(document);
|
|
214
|
+
jest.spyOn(document, 'createElement').mockImplementation(function (tag) {
|
|
215
|
+
var node = realCreate(tag);
|
|
216
|
+
if (String(tag).toLowerCase() === 'script')
|
|
217
|
+
setTimeout(function () { return node.dispatchEvent(new Event('load')); }, 0);
|
|
218
|
+
return node;
|
|
219
|
+
});
|
|
220
|
+
sw = {
|
|
221
|
+
controller: { scriptURL: 'http://localhost/other/sw.js' },
|
|
222
|
+
register: jest.fn(function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
223
|
+
return [2 /*return*/, ({})];
|
|
224
|
+
}); }); }),
|
|
225
|
+
addEventListener: jest.fn()
|
|
226
|
+
};
|
|
227
|
+
Object.defineProperty(navigator, 'serviceWorker', {
|
|
228
|
+
value: sw,
|
|
229
|
+
configurable: true
|
|
230
|
+
});
|
|
231
|
+
history.replaceState({}, '', '/demo/api-console/');
|
|
232
|
+
jest.resetModules();
|
|
233
|
+
require('../assets/api-console.js');
|
|
234
|
+
return [4 /*yield*/, settle(function () {
|
|
235
|
+
return global.fetch.mock.calls.some(function (call) {
|
|
236
|
+
return String(call[0]).includes('identity.json');
|
|
237
|
+
});
|
|
238
|
+
})];
|
|
239
|
+
case 1:
|
|
240
|
+
_a.sent();
|
|
241
|
+
asked = global.fetch.mock.calls.map(function (call) {
|
|
242
|
+
return String(call[0]);
|
|
243
|
+
});
|
|
244
|
+
expect(asked).toContain('/demo/host/identity.json');
|
|
245
|
+
expect(asked.some(function (url) { return url.startsWith('/other/'); })).toBe(false);
|
|
246
|
+
history.replaceState({}, '', '/demo/api-console/');
|
|
247
|
+
return [2 /*return*/];
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
}); });
|
|
139
251
|
it('finds the folder from a URL without its trailing slash', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
140
252
|
var realCreate, sw, asked;
|
|
141
253
|
return __generator(this, function (_a) {
|
|
@@ -143,8 +255,8 @@ describe('the API console under a base path', function () {
|
|
|
143
255
|
case 0:
|
|
144
256
|
// `/demo/api` is the shape a person types, and the page used to read that as
|
|
145
257
|
// the origin root: every call went to /SASjsApi/... and the worker to /sw.js
|
|
146
|
-
history.replaceState({}, '', '/demo/api');
|
|
147
|
-
expect(location.pathname).toBe('/demo/api');
|
|
258
|
+
history.replaceState({}, '', '/demo/api-console');
|
|
259
|
+
expect(location.pathname).toBe('/demo/api-console');
|
|
148
260
|
document.body.innerHTML = bodyOf(page());
|
|
149
261
|
document.head.innerHTML =
|
|
150
262
|
'<meta name="sasjs-mock-version" content="2.0.0" />';
|
|
@@ -187,7 +299,7 @@ describe('the API console under a base path', function () {
|
|
|
187
299
|
return String(call[0]);
|
|
188
300
|
});
|
|
189
301
|
expect(asked).toContain('/demo/host/identity.json');
|
|
190
|
-
history.replaceState({}, '', '/demo/api/');
|
|
302
|
+
history.replaceState({}, '', '/demo/api-console/');
|
|
191
303
|
return [2 /*return*/];
|
|
192
304
|
}
|
|
193
305
|
});
|
|
@@ -1051,14 +1051,14 @@ describe('browser-hosted build', function () {
|
|
|
1051
1051
|
* the host drift.
|
|
1052
1052
|
*/
|
|
1053
1053
|
it('ships an API console built from the route table', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
1054
|
-
var result, folder, shipped, sw,
|
|
1054
|
+
var result, folder, shipped, sw, operations, createUser, html, version, appHtml, loader;
|
|
1055
1055
|
return __generator(this, function (_a) {
|
|
1056
1056
|
switch (_a.label) {
|
|
1057
1057
|
case 0: return [4 /*yield*/, (0, mockSite_1.buildMockSite)(target())];
|
|
1058
1058
|
case 1:
|
|
1059
1059
|
result = _a.sent();
|
|
1060
1060
|
expect(result.apiConsole).toBe(true);
|
|
1061
|
-
folder = path_1.default.join(out(), 'api');
|
|
1061
|
+
folder = path_1.default.join(out(), 'api-console');
|
|
1062
1062
|
shipped = fs_1.default.readdirSync(folder).sort();
|
|
1063
1063
|
// every file the folder holds, and the worker's passthrough list is that same
|
|
1064
1064
|
// list: a second copy in sw.js would let a new file be answered as an API path
|
|
@@ -1069,9 +1069,7 @@ describe('browser-hosted build', function () {
|
|
|
1069
1069
|
'operations.json'
|
|
1070
1070
|
]);
|
|
1071
1071
|
sw = fs_1.default.readFileSync(path_1.default.join(out(), 'sw.js'), 'utf8');
|
|
1072
|
-
|
|
1073
|
-
expect(listed).not.toBeNull();
|
|
1074
|
-
expect(JSON.parse(listed[1]).sort()).toEqual(shipped);
|
|
1072
|
+
expect(sw).not.toContain('API_CONSOLE_FILES');
|
|
1075
1073
|
operations = JSON.parse(fs_1.default.readFileSync(path_1.default.join(folder, 'operations.json'), 'utf8'));
|
|
1076
1074
|
expect(operations.length).toBeGreaterThan(20);
|
|
1077
1075
|
createUser = operations.find(function (operation) { return operation.id === 'POST /SASjsApi/user'; });
|
|
@@ -1091,12 +1089,12 @@ describe('browser-hosted build', function () {
|
|
|
1091
1089
|
}
|
|
1092
1090
|
});
|
|
1093
1091
|
}); });
|
|
1094
|
-
it('leaves the console out when the site ships its own
|
|
1092
|
+
it('leaves the console out when the site ships its own console folder, and says so', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
1095
1093
|
var own, result;
|
|
1096
1094
|
return __generator(this, function (_a) {
|
|
1097
1095
|
switch (_a.label) {
|
|
1098
1096
|
case 0:
|
|
1099
|
-
own = path_1.default.join(root, 'client', 'dist', 'api');
|
|
1097
|
+
own = path_1.default.join(root, 'client', 'dist', 'api-console');
|
|
1100
1098
|
fs_1.default.mkdirSync(own, { recursive: true });
|
|
1101
1099
|
fs_1.default.writeFileSync(path_1.default.join(own, 'index.html'), '<p>ours</p>');
|
|
1102
1100
|
return [4 /*yield*/, (0, mockSite_1.buildMockSite)(target())
|
|
@@ -1108,9 +1106,9 @@ describe('browser-hosted build', function () {
|
|
|
1108
1106
|
// the project's file is not replaced, and the loss is reported rather than
|
|
1109
1107
|
// silent: the build has no way to know which of the two the site wants
|
|
1110
1108
|
expect(result.apiConsole).toBe(false);
|
|
1111
|
-
expect(fs_1.default.readFileSync(path_1.default.join(out(), 'api', 'index.html'), 'utf8')).toBe('<p>ours</p>');
|
|
1112
|
-
expect(fs_1.default.existsSync(path_1.default.join(out(), 'api', 'console.js'))).toBe(false);
|
|
1113
|
-
expect(process.logger.warn).toHaveBeenCalledWith(expect.stringContaining('api/index.html'));
|
|
1109
|
+
expect(fs_1.default.readFileSync(path_1.default.join(out(), 'api-console', 'index.html'), 'utf8')).toBe('<p>ours</p>');
|
|
1110
|
+
expect(fs_1.default.existsSync(path_1.default.join(out(), 'api-console', 'console.js'))).toBe(false);
|
|
1111
|
+
expect(process.logger.warn).toHaveBeenCalledWith(expect.stringContaining('api-console/index.html'));
|
|
1114
1112
|
return [2 /*return*/];
|
|
1115
1113
|
}
|
|
1116
1114
|
});
|
|
@@ -1123,7 +1121,7 @@ describe('browser-hosted build', function () {
|
|
|
1123
1121
|
case 1:
|
|
1124
1122
|
result = _a.sent();
|
|
1125
1123
|
expect(result.apiConsole).toBe(false);
|
|
1126
|
-
expect(fs_1.default.existsSync(path_1.default.join(out(), 'api'))).toBe(false);
|
|
1124
|
+
expect(fs_1.default.existsSync(path_1.default.join(out(), 'api-console'))).toBe(false);
|
|
1127
1125
|
return [2 /*return*/];
|
|
1128
1126
|
}
|
|
1129
1127
|
});
|
|
@@ -86,7 +86,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
86
86
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
87
87
|
};
|
|
88
88
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
89
|
-
var fs_1 = __importDefault(require("fs"));
|
|
90
89
|
var path_1 = __importDefault(require("path"));
|
|
91
90
|
var api_1 = require("@sasjs/api");
|
|
92
91
|
var os_1 = __importDefault(require("os"));
|
|
@@ -2566,46 +2565,25 @@ describe('service worker host', function () {
|
|
|
2566
2565
|
* The console's own files are the page, not an API call.
|
|
2567
2566
|
*
|
|
2568
2567
|
* `/api/...` is the API's short spelling, so the worker answers it - except for
|
|
2569
|
-
*
|
|
2570
|
-
* that wrong answers the page's own script with an API 404, and the console
|
|
2571
|
-
* renders nothing.
|
|
2568
|
+
* `/api` itself, which a site's own application may answer.
|
|
2572
2569
|
*/
|
|
2573
|
-
it('leaves
|
|
2574
|
-
var worker,
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
switch (_b.label) {
|
|
2570
|
+
it('leaves /api to the site, and answers the short spelling below it', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2571
|
+
var worker, response;
|
|
2572
|
+
return __generator(this, function (_a) {
|
|
2573
|
+
switch (_a.label) {
|
|
2578
2574
|
case 0:
|
|
2579
2575
|
worker = seeded();
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
expect(
|
|
2583
|
-
files = listed[1]
|
|
2584
|
-
.split(',')
|
|
2585
|
-
.map(function (entry) { return entry.trim().replace(/^'|'$/g, ''); })
|
|
2586
|
-
.filter(Boolean);
|
|
2587
|
-
expect(files.length).toBeGreaterThan(3);
|
|
2576
|
+
// a site's own application can answer /api (the server interface does), so the
|
|
2577
|
+
// worker hands it on; `/api/<something>` is an API call on the short spelling
|
|
2578
|
+
expect(worker.dispatch('/api')).toBeUndefined();
|
|
2588
2579
|
expect(worker.dispatch('/api/')).toBeUndefined();
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
}
|
|
2594
|
-
}
|
|
2595
|
-
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
2596
|
-
finally {
|
|
2597
|
-
try {
|
|
2598
|
-
if (files_1_1 && !files_1_1.done && (_a = files_1.return)) _a.call(files_1);
|
|
2599
|
-
}
|
|
2600
|
-
finally { if (e_2) throw e_2.error; }
|
|
2601
|
-
}
|
|
2602
|
-
return [4 /*yield*/, worker.dispatch('/api/admin/logs/missing.log')];
|
|
2603
|
-
case 1:
|
|
2604
|
-
log = _b.sent();
|
|
2605
|
-
expect(log.status).not.toBeUndefined();
|
|
2580
|
+
// the console has a folder of its own, which is not an API prefix: the static
|
|
2581
|
+
// host serves it and the worker never sees it
|
|
2582
|
+
expect(worker.dispatch('/api-console/console.js')).toBeUndefined();
|
|
2583
|
+
expect(worker.dispatch('/api-console/operations.json')).toBeUndefined();
|
|
2606
2584
|
return [4 /*yield*/, worker.dispatch('/api/user')];
|
|
2607
|
-
case
|
|
2608
|
-
response =
|
|
2585
|
+
case 1:
|
|
2586
|
+
response = _a.sent();
|
|
2609
2587
|
expect(response.status).toBe(200);
|
|
2610
2588
|
return [2 /*return*/];
|
|
2611
2589
|
}
|
|
@@ -2630,8 +2608,8 @@ describe('service worker host', function () {
|
|
|
2630
2608
|
});
|
|
2631
2609
|
}); });
|
|
2632
2610
|
it('publishes, lists, serves and removes an app through the package surface', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
2633
|
-
var dispatch, _a, _b, path_2, listing, _c,
|
|
2634
|
-
var
|
|
2611
|
+
var dispatch, _a, _b, path_2, listing, _c, e_2_1, _d, _e, path_3, landing, e_3_1, root, archive, form, published, app, _f, _g, path_4, listing, _h, e_4_1, _j, _k, path_5, page, _l, e_5_1, folder, _m, refused, missing, removed, _o, after, _p, gone;
|
|
2612
|
+
var e_2, _q, e_3, _r, e_4, _s, e_5, _t;
|
|
2635
2613
|
return __generator(this, function (_u) {
|
|
2636
2614
|
switch (_u.label) {
|
|
2637
2615
|
case 0:
|
|
@@ -2658,14 +2636,14 @@ describe('service worker host', function () {
|
|
|
2658
2636
|
return [3 /*break*/, 2];
|
|
2659
2637
|
case 6: return [3 /*break*/, 9];
|
|
2660
2638
|
case 7:
|
|
2661
|
-
|
|
2662
|
-
|
|
2639
|
+
e_2_1 = _u.sent();
|
|
2640
|
+
e_2 = { error: e_2_1 };
|
|
2663
2641
|
return [3 /*break*/, 9];
|
|
2664
2642
|
case 8:
|
|
2665
2643
|
try {
|
|
2666
2644
|
if (_b && !_b.done && (_q = _a.return)) _q.call(_a);
|
|
2667
2645
|
}
|
|
2668
|
-
finally { if (
|
|
2646
|
+
finally { if (e_2) throw e_2.error; }
|
|
2669
2647
|
return [7 /*endfinally*/];
|
|
2670
2648
|
case 9:
|
|
2671
2649
|
_u.trys.push([9, 14, 15, 16]);
|
|
@@ -2685,14 +2663,14 @@ describe('service worker host', function () {
|
|
|
2685
2663
|
return [3 /*break*/, 10];
|
|
2686
2664
|
case 13: return [3 /*break*/, 16];
|
|
2687
2665
|
case 14:
|
|
2688
|
-
|
|
2689
|
-
|
|
2666
|
+
e_3_1 = _u.sent();
|
|
2667
|
+
e_3 = { error: e_3_1 };
|
|
2690
2668
|
return [3 /*break*/, 16];
|
|
2691
2669
|
case 15:
|
|
2692
2670
|
try {
|
|
2693
2671
|
if (_e && !_e.done && (_r = _d.return)) _r.call(_d);
|
|
2694
2672
|
}
|
|
2695
|
-
finally { if (
|
|
2673
|
+
finally { if (e_3) throw e_3.error; }
|
|
2696
2674
|
return [7 /*endfinally*/];
|
|
2697
2675
|
case 16: return [4 /*yield*/, dispatch('/AppStream')];
|
|
2698
2676
|
case 17:
|
|
@@ -2745,14 +2723,14 @@ describe('service worker host', function () {
|
|
|
2745
2723
|
return [3 /*break*/, 22];
|
|
2746
2724
|
case 26: return [3 /*break*/, 29];
|
|
2747
2725
|
case 27:
|
|
2748
|
-
|
|
2749
|
-
|
|
2726
|
+
e_4_1 = _u.sent();
|
|
2727
|
+
e_4 = { error: e_4_1 };
|
|
2750
2728
|
return [3 /*break*/, 29];
|
|
2751
2729
|
case 28:
|
|
2752
2730
|
try {
|
|
2753
2731
|
if (_g && !_g.done && (_s = _f.return)) _s.call(_f);
|
|
2754
2732
|
}
|
|
2755
|
-
finally { if (
|
|
2733
|
+
finally { if (e_4) throw e_4.error; }
|
|
2756
2734
|
return [7 /*endfinally*/];
|
|
2757
2735
|
case 29:
|
|
2758
2736
|
_u.trys.push([29, 35, 36, 37]);
|
|
@@ -2779,14 +2757,14 @@ describe('service worker host', function () {
|
|
|
2779
2757
|
return [3 /*break*/, 30];
|
|
2780
2758
|
case 34: return [3 /*break*/, 37];
|
|
2781
2759
|
case 35:
|
|
2782
|
-
|
|
2783
|
-
|
|
2760
|
+
e_5_1 = _u.sent();
|
|
2761
|
+
e_5 = { error: e_5_1 };
|
|
2784
2762
|
return [3 /*break*/, 37];
|
|
2785
2763
|
case 36:
|
|
2786
2764
|
try {
|
|
2787
2765
|
if (_k && !_k.done && (_t = _j.return)) _t.call(_j);
|
|
2788
2766
|
}
|
|
2789
|
-
finally { if (
|
|
2767
|
+
finally { if (e_5) throw e_5.error; }
|
|
2790
2768
|
return [7 /*endfinally*/];
|
|
2791
2769
|
case 37: return [4 /*yield*/, dispatch("/app/".concat(app.id))];
|
|
2792
2770
|
case 38:
|
|
@@ -3735,7 +3713,7 @@ describe('service worker host', function () {
|
|
|
3735
3713
|
}); });
|
|
3736
3714
|
});
|
|
3737
3715
|
describe('conformance corpus', function () {
|
|
3738
|
-
var
|
|
3716
|
+
var e_6, _a, e_7, _b;
|
|
3739
3717
|
/**
|
|
3740
3718
|
* The corpus is what "the same API" means: the cases @sasjs/api runs against
|
|
3741
3719
|
* its own services, and against a live sasjs/server, run here against this
|
|
@@ -3744,7 +3722,7 @@ describe('service worker host', function () {
|
|
|
3744
3722
|
* used to have - and it is a test rather than a review.
|
|
3745
3723
|
*/
|
|
3746
3724
|
var httpFor = function (testCase) {
|
|
3747
|
-
var
|
|
3725
|
+
var e_8, _a;
|
|
3748
3726
|
var _b;
|
|
3749
3727
|
var _c = __read(testCase.route.split(' '), 2), method = _c[0], routePath = _c[1];
|
|
3750
3728
|
var query = new URLSearchParams();
|
|
@@ -3755,12 +3733,12 @@ describe('service worker host', function () {
|
|
|
3755
3733
|
query.set(key, String(value));
|
|
3756
3734
|
}
|
|
3757
3735
|
}
|
|
3758
|
-
catch (
|
|
3736
|
+
catch (e_8_1) { e_8 = { error: e_8_1 }; }
|
|
3759
3737
|
finally {
|
|
3760
3738
|
try {
|
|
3761
3739
|
if (_e && !_e.done && (_a = _d.return)) _a.call(_d);
|
|
3762
3740
|
}
|
|
3763
|
-
finally { if (
|
|
3741
|
+
finally { if (e_8) throw e_8.error; }
|
|
3764
3742
|
}
|
|
3765
3743
|
var suffix = query.toString() ? "?".concat(query) : '';
|
|
3766
3744
|
var init = { method: method };
|
|
@@ -3791,8 +3769,8 @@ describe('service worker host', function () {
|
|
|
3791
3769
|
* does.
|
|
3792
3770
|
*/
|
|
3793
3771
|
var seedDrive = function (runtime, testCase) { return __awaiter(void 0, void 0, void 0, function () {
|
|
3794
|
-
var text, _a, _b, _c, file, contents, _d, _e, _f, file, contents,
|
|
3795
|
-
var
|
|
3772
|
+
var text, _a, _b, _c, file, contents, _d, _e, _f, file, contents, e_9_1;
|
|
3773
|
+
var e_10, _g, e_9, _h;
|
|
3796
3774
|
return __generator(this, function (_j) {
|
|
3797
3775
|
switch (_j.label) {
|
|
3798
3776
|
case 0:
|
|
@@ -3804,12 +3782,12 @@ describe('service worker host', function () {
|
|
|
3804
3782
|
text["/sasjs/drive/files".concat(file)] = contents;
|
|
3805
3783
|
}
|
|
3806
3784
|
}
|
|
3807
|
-
catch (
|
|
3785
|
+
catch (e_10_1) { e_10 = { error: e_10_1 }; }
|
|
3808
3786
|
finally {
|
|
3809
3787
|
try {
|
|
3810
3788
|
if (_b && !_b.done && (_g = _a.return)) _g.call(_a);
|
|
3811
3789
|
}
|
|
3812
|
-
finally { if (
|
|
3790
|
+
finally { if (e_10) throw e_10.error; }
|
|
3813
3791
|
}
|
|
3814
3792
|
return [4 /*yield*/, runtime.load(text)];
|
|
3815
3793
|
case 1:
|
|
@@ -3832,14 +3810,14 @@ describe('service worker host', function () {
|
|
|
3832
3810
|
return [3 /*break*/, 3];
|
|
3833
3811
|
case 6: return [3 /*break*/, 9];
|
|
3834
3812
|
case 7:
|
|
3835
|
-
|
|
3836
|
-
|
|
3813
|
+
e_9_1 = _j.sent();
|
|
3814
|
+
e_9 = { error: e_9_1 };
|
|
3837
3815
|
return [3 /*break*/, 9];
|
|
3838
3816
|
case 8:
|
|
3839
3817
|
try {
|
|
3840
3818
|
if (_e && !_e.done && (_h = _d.return)) _h.call(_d);
|
|
3841
3819
|
}
|
|
3842
|
-
finally { if (
|
|
3820
|
+
finally { if (e_9) throw e_9.error; }
|
|
3843
3821
|
return [7 /*endfinally*/];
|
|
3844
3822
|
case 9: return [2 /*return*/];
|
|
3845
3823
|
}
|
|
@@ -3950,12 +3928,12 @@ describe('service worker host', function () {
|
|
|
3950
3928
|
_loop_1(testCase);
|
|
3951
3929
|
}
|
|
3952
3930
|
}
|
|
3953
|
-
catch (
|
|
3931
|
+
catch (e_6_1) { e_6 = { error: e_6_1 }; }
|
|
3954
3932
|
finally {
|
|
3955
3933
|
try {
|
|
3956
3934
|
if (DRIVE_CORPUS_1_1 && !DRIVE_CORPUS_1_1.done && (_a = DRIVE_CORPUS_1.return)) _a.call(DRIVE_CORPUS_1);
|
|
3957
3935
|
}
|
|
3958
|
-
finally { if (
|
|
3936
|
+
finally { if (e_6) throw e_6.error; }
|
|
3959
3937
|
}
|
|
3960
3938
|
/** The app a removal case names, as the corpus states it. */
|
|
3961
3939
|
var CORPUS_APP = {
|
|
@@ -4024,7 +4002,7 @@ describe('service worker host', function () {
|
|
|
4024
4002
|
return __generator(this, function (_a) {
|
|
4025
4003
|
files = {};
|
|
4026
4004
|
walk = function (members, prefix) {
|
|
4027
|
-
var
|
|
4005
|
+
var e_11, _a;
|
|
4028
4006
|
var _b;
|
|
4029
4007
|
try {
|
|
4030
4008
|
for (var _c = __values(members || []), _d = _c.next(); !_d.done; _d = _c.next()) {
|
|
@@ -4039,12 +4017,12 @@ describe('service worker host', function () {
|
|
|
4039
4017
|
: String((_b = member.code) !== null && _b !== void 0 ? _b : '');
|
|
4040
4018
|
}
|
|
4041
4019
|
}
|
|
4042
|
-
catch (
|
|
4020
|
+
catch (e_11_1) { e_11 = { error: e_11_1 }; }
|
|
4043
4021
|
finally {
|
|
4044
4022
|
try {
|
|
4045
4023
|
if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
|
|
4046
4024
|
}
|
|
4047
|
-
finally { if (
|
|
4025
|
+
finally { if (e_11) throw e_11.error; }
|
|
4048
4026
|
}
|
|
4049
4027
|
};
|
|
4050
4028
|
walk(tree === null || tree === void 0 ? void 0 : tree.members, '');
|
|
@@ -4061,7 +4039,7 @@ describe('service worker host', function () {
|
|
|
4061
4039
|
*/
|
|
4062
4040
|
var deployRequest = function (testCase) { return __awaiter(void 0, void 0, void 0, function () {
|
|
4063
4041
|
var _a, requestPath, init, body, archive, form, _b, _c, _d, field, value;
|
|
4064
|
-
var
|
|
4042
|
+
var e_12, _e;
|
|
4065
4043
|
return __generator(this, function (_f) {
|
|
4066
4044
|
switch (_f.label) {
|
|
4067
4045
|
case 0:
|
|
@@ -4080,12 +4058,12 @@ describe('service worker host', function () {
|
|
|
4080
4058
|
form.set(field, String(value));
|
|
4081
4059
|
}
|
|
4082
4060
|
}
|
|
4083
|
-
catch (
|
|
4061
|
+
catch (e_12_1) { e_12 = { error: e_12_1 }; }
|
|
4084
4062
|
finally {
|
|
4085
4063
|
try {
|
|
4086
4064
|
if (_c && !_c.done && (_e = _b.return)) _e.call(_b);
|
|
4087
4065
|
}
|
|
4088
|
-
finally { if (
|
|
4066
|
+
finally { if (e_12) throw e_12.error; }
|
|
4089
4067
|
}
|
|
4090
4068
|
form.set('file', new Blob([new Uint8Array(archive)]), 'deploy.zip');
|
|
4091
4069
|
return [2 /*return*/, { requestPath: requestPath, init: { method: 'POST', body: form } }];
|
|
@@ -4094,8 +4072,8 @@ describe('service worker host', function () {
|
|
|
4094
4072
|
}); };
|
|
4095
4073
|
var _loop_2 = function (testCase) {
|
|
4096
4074
|
it(testCase.id, function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
4097
|
-
var worker, _a, requestPath, init, response, listing, ids, _b, _c, path_6, file,
|
|
4098
|
-
var
|
|
4075
|
+
var worker, _a, requestPath, init, response, listing, ids, _b, _c, path_6, file, e_13_1, _d, _e, path_7, file, e_14_1;
|
|
4076
|
+
var e_13, _f, e_14, _g;
|
|
4099
4077
|
var _h, _j, _k;
|
|
4100
4078
|
return __generator(this, function (_l) {
|
|
4101
4079
|
switch (_l.label) {
|
|
@@ -4147,14 +4125,14 @@ describe('service worker host', function () {
|
|
|
4147
4125
|
return [3 /*break*/, 9];
|
|
4148
4126
|
case 12: return [3 /*break*/, 15];
|
|
4149
4127
|
case 13:
|
|
4150
|
-
|
|
4151
|
-
|
|
4128
|
+
e_13_1 = _l.sent();
|
|
4129
|
+
e_13 = { error: e_13_1 };
|
|
4152
4130
|
return [3 /*break*/, 15];
|
|
4153
4131
|
case 14:
|
|
4154
4132
|
try {
|
|
4155
4133
|
if (_c && !_c.done && (_f = _b.return)) _f.call(_b);
|
|
4156
4134
|
}
|
|
4157
|
-
finally { if (
|
|
4135
|
+
finally { if (e_13) throw e_13.error; }
|
|
4158
4136
|
return [7 /*endfinally*/];
|
|
4159
4137
|
case 15:
|
|
4160
4138
|
_l.trys.push([15, 20, 21, 22]);
|
|
@@ -4173,14 +4151,14 @@ describe('service worker host', function () {
|
|
|
4173
4151
|
return [3 /*break*/, 16];
|
|
4174
4152
|
case 19: return [3 /*break*/, 22];
|
|
4175
4153
|
case 20:
|
|
4176
|
-
|
|
4177
|
-
|
|
4154
|
+
e_14_1 = _l.sent();
|
|
4155
|
+
e_14 = { error: e_14_1 };
|
|
4178
4156
|
return [3 /*break*/, 22];
|
|
4179
4157
|
case 21:
|
|
4180
4158
|
try {
|
|
4181
4159
|
if (_e && !_e.done && (_g = _d.return)) _g.call(_d);
|
|
4182
4160
|
}
|
|
4183
|
-
finally { if (
|
|
4161
|
+
finally { if (e_14) throw e_14.error; }
|
|
4184
4162
|
return [7 /*endfinally*/];
|
|
4185
4163
|
case 22: return [2 /*return*/];
|
|
4186
4164
|
}
|
|
@@ -4213,12 +4191,12 @@ describe('service worker host', function () {
|
|
|
4213
4191
|
_loop_2(testCase);
|
|
4214
4192
|
}
|
|
4215
4193
|
}
|
|
4216
|
-
catch (
|
|
4194
|
+
catch (e_7_1) { e_7 = { error: e_7_1 }; }
|
|
4217
4195
|
finally {
|
|
4218
4196
|
try {
|
|
4219
4197
|
if (_d && !_d.done && (_b = _c.return)) _b.call(_c);
|
|
4220
4198
|
}
|
|
4221
|
-
finally { if (
|
|
4199
|
+
finally { if (e_7) throw e_7.error; }
|
|
4222
4200
|
}
|
|
4223
4201
|
});
|
|
4224
4202
|
/**
|
|
@@ -4230,7 +4208,7 @@ describe('service worker host', function () {
|
|
|
4230
4208
|
* are the package's.
|
|
4231
4209
|
*/
|
|
4232
4210
|
describe('identity and record conformance', function () {
|
|
4233
|
-
var
|
|
4211
|
+
var e_15, _a;
|
|
4234
4212
|
/**
|
|
4235
4213
|
* Boots the worker from a fixture, the way the page does: the case's own
|
|
4236
4214
|
* identity, and `subject: null` for no implicit caller, so a case that
|
|
@@ -4263,7 +4241,7 @@ describe('service worker host', function () {
|
|
|
4263
4241
|
};
|
|
4264
4242
|
/** The request a case describes, as HTTP: path parameters filled, token sent. */
|
|
4265
4243
|
var httpForCase = function (testCase) {
|
|
4266
|
-
var
|
|
4244
|
+
var e_16, _a;
|
|
4267
4245
|
var _b = __read(testCase.route.split(' '), 2), method = _b[0], routePath = _b[1];
|
|
4268
4246
|
var filled = routePath.replace(/\{(\w+)\}/g, function (_match, name) {
|
|
4269
4247
|
return encodeURIComponent(String((testCase.request.params || {})[name]));
|
|
@@ -4276,12 +4254,12 @@ describe('service worker host', function () {
|
|
|
4276
4254
|
query.set(key, String(value));
|
|
4277
4255
|
}
|
|
4278
4256
|
}
|
|
4279
|
-
catch (
|
|
4257
|
+
catch (e_16_1) { e_16 = { error: e_16_1 }; }
|
|
4280
4258
|
finally {
|
|
4281
4259
|
try {
|
|
4282
4260
|
if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
|
|
4283
4261
|
}
|
|
4284
|
-
finally { if (
|
|
4262
|
+
finally { if (e_16) throw e_16.error; }
|
|
4285
4263
|
}
|
|
4286
4264
|
var suffix = query.toString() ? "?".concat(query) : '';
|
|
4287
4265
|
var headers = {};
|
|
@@ -4403,12 +4381,12 @@ describe('service worker host', function () {
|
|
|
4403
4381
|
_loop_3(testCase);
|
|
4404
4382
|
}
|
|
4405
4383
|
}
|
|
4406
|
-
catch (
|
|
4384
|
+
catch (e_15_1) { e_15 = { error: e_15_1 }; }
|
|
4407
4385
|
finally {
|
|
4408
4386
|
try {
|
|
4409
4387
|
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
4410
4388
|
}
|
|
4411
|
-
finally { if (
|
|
4389
|
+
finally { if (e_15) throw e_15.error; }
|
|
4412
4390
|
}
|
|
4413
4391
|
it('answers as the fixture administrator when no subject was chosen', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
4414
4392
|
var worker, response, rules;
|
|
@@ -21,7 +21,7 @@ declare module '@sasjs/utils/types/config' {
|
|
|
21
21
|
*/
|
|
22
22
|
mockWebBasePath?: string;
|
|
23
23
|
/**
|
|
24
|
-
* Whether the mock site carries the API console at `<base>/api/`.
|
|
24
|
+
* Whether the mock site carries the API console at `<base>/api-console/`.
|
|
25
25
|
*
|
|
26
26
|
* On unless it is set to false: the console is how a demonstration site lets
|
|
27
27
|
* a visitor try the API it is a mock of, and a page nothing links to costs
|