-
Notifications
You must be signed in to change notification settings - Fork 3.1k
/
test-helper-iframe.js
103 lines (100 loc) · 4.03 KB
/
test-helper-iframe.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// Handle errors around fetching, parsing and registering import maps.
const onScriptError = event => {
window.registrationResult = {type: 'FetchError', error: event.error};
return false;
};
window.windowErrorHandler = event => {
window.registrationResult = {type: 'ParseError', error: event.error};
return false;
};
window.addEventListener('error', window.windowErrorHandler);
// Handle specifier resolution requests from the parent frame.
// For failures, we post error names and messages instead of error
// objects themselves and re-create error objects later, to avoid
// issues around serializing error objects which is a quite new feature.
window.addEventListener('message', event => {
if (event.data.action === 'prepareResolve') {
// To get the result of #resolve-a-module-specifier given a script
// (with base URL = |baseURL|) and |specifier|, the service worker
// first serves an importer script with response URL = |baseURL|:
// window.importHelper = (specifier) => import(specifier);
// This is to use |baseURL| as the referringScript's base URL.
// Step 1. Signal the service worker to serve
// the importer script for the next fetch request.
parent.worker.postMessage('serveImporterScript');
} else if (event.data.action === 'resolve') {
if (event.data.expectedURL === null ||
new URL(event.data.expectedURL).protocol === 'https:') {
// Testing without internal methods:
// If the resolution is expected to fail (null case here),
// we can test the failure just by catching the exception.
// If the expected URL is HTTPS, we can test the result by
// intercepting requests by service workers.
// Step 3. Evaluate the importer script as a classic script,
// in order to prevent |baseURL| from being mapped by import maps.
const script = document.createElement('script');
script.onload = () => {
// Step 4. Trigger dynamic import from |baseURL|.
importHelper(event.data.specifier)
.then(module => {
// Step 5. Service worker responds with a JSON containing
// the request URL for the dynamic import
// (= the result of #resolve-a-module-specifier).
parent.postMessage({type: 'ResolutionSuccess',
result: module.response.url},
'*');
})
.catch(e => {
parent.postMessage(
{type: 'Failure', result: e.name, message: e.message},
'*');
});
};
script.src = event.data.baseURL;
document.body.appendChild(script);
} else {
// Testing with internal methods.
// For example, the resolution results are data: URLs.
if (!event.data.useInternalMethods) {
parent.postMessage(
{type: 'Failure',
result: 'Error',
message: 'internals.resolveModuleSpecifier is not available'},
'*');
return;
}
try {
const result = internals.resolveModuleSpecifier(
event.data.specifier,
event.data.baseURL,
document);
parent.postMessage(
{type: 'ResolutionSuccess', result: result}, '*');
} catch (e) {
parent.postMessage(
{type: 'Failure', result: e.name, message: e.message}, '*');
}
}
} else if (event.data.action === 'getParsedImportMap') {
if (!event.data.useInternalMethods) {
parent.postMessage(
{type: 'Failure',
result: 'Error',
message: 'internals.getParsedImportMap is not available'},
'*');
}
try {
parent.postMessage({
type: 'GetParsedImportMapSuccess',
result: internals.getParsedImportMap(document)}, '*');
} catch (e) {
parent.postMessage(
{type: 'Failure', result: e.name, message: e.message}, '*');
}
} else {
parent.postMessage({
type: 'Failure',
result: 'Error',
message: 'Invalid Action: ' + event.data.action}, '*');
}
});