jasmine-browser-runner 2.0.0-beta.0 → 2.0.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 +34 -26
- package/bin/jasmine-browser-runner +2 -2
- package/lib/command.js +1 -1
- package/lib/config.js +81 -0
- package/lib/examples/default_esm_config.json +2 -0
- package/lib/server.js +73 -12
- package/lib/support/batchReporter.js +2 -2
- package/lib/support/loaders.js +7 -4
- package/lib/types.js +48 -0
- package/package.json +6 -5
- package/run.html.ejs +7 -2
package/README.md
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
[](https://circleci.com/gh/jasmine/jasmine-browser)
|
|
2
|
-
|
|
3
|
-
|
|
4
1
|
jasmine-browser-runner runs your Jasmine specs in a browser. It's suitable for
|
|
5
2
|
interactive use with normal browsers as well as running specs in CI builds
|
|
6
3
|
using either headless Chrome or Saucelabs.
|
|
@@ -9,44 +6,34 @@ using either headless Chrome or Saucelabs.
|
|
|
9
6
|
|
|
10
7
|
```bash
|
|
11
8
|
npm install --save-dev jasmine-browser-runner jasmine-core
|
|
9
|
+
npx jasmine-browser-runner init
|
|
12
10
|
```
|
|
13
11
|
|
|
14
12
|
or
|
|
15
13
|
|
|
16
14
|
```bash
|
|
17
15
|
yarn add -D jasmine-browser-runner jasmine-core
|
|
16
|
+
npx jasmine-browser-runner init
|
|
18
17
|
```
|
|
19
18
|
|
|
20
|
-
|
|
19
|
+
If you intend to use ES modules, add `--esm` to the `jasmine-browser-runner init`
|
|
20
|
+
command.
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
"**/*.?(m)js"
|
|
27
|
-
],
|
|
28
|
-
"specDir": "spec",
|
|
29
|
-
"specFiles": [
|
|
30
|
-
"**/*[Ss]pec.?(m)js"
|
|
31
|
-
],
|
|
32
|
-
"helpers": [
|
|
33
|
-
"helpers/asyncAwait.js"
|
|
34
|
-
],
|
|
35
|
-
"env": {
|
|
36
|
-
"random": true
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
```
|
|
22
|
+
Then, customize `spec/support/jasmine-browser.json` to suit your needs. You can
|
|
23
|
+
change the spec files, helpers, and source files that are loaded, specify the
|
|
24
|
+
[Jasmine env's configuration](https://jasmine.github.io/api/edge/Configuration.html),
|
|
25
|
+
and more.
|
|
40
26
|
|
|
41
27
|
You can also use the `--config` option to specify a different file. This file can be a JSON file or a javascript file that exports a object that looks like the JSON above.
|
|
42
28
|
|
|
43
|
-
|
|
29
|
+
To start the server so that you can run the specs interactively (particularly
|
|
30
|
+
useful for debugging):
|
|
44
31
|
|
|
45
32
|
```
|
|
46
33
|
npx jasmine-browser-runner serve
|
|
47
34
|
```
|
|
48
35
|
|
|
49
|
-
|
|
36
|
+
To run the specs in a browser (defaults to Firefox):
|
|
50
37
|
|
|
51
38
|
```
|
|
52
39
|
npx jasmine-browser-runner runSpecs
|
|
@@ -68,7 +55,11 @@ Its value can be `"firefox"`, `"headlessFirefox"`, `"safari"`,
|
|
|
68
55
|
## ES module support
|
|
69
56
|
|
|
70
57
|
If a source, spec, or helper file's name ends in `.mjs`, it will be loaded as
|
|
71
|
-
an ES module rather than a regular script.
|
|
58
|
+
an ES module rather than a regular script. Note that ES modules can only be
|
|
59
|
+
loaded from other ES modules. So if your source files are ES modules, your
|
|
60
|
+
spec files need to be ES modules too. Want to use a different extension than
|
|
61
|
+
`.esm`? Just set the `esmFilenameExtension` config property, e.g.
|
|
62
|
+
`"esmFilenameExtension": ".js"`.
|
|
72
63
|
|
|
73
64
|
To allow spec files to import source files via relative paths, set the `specDir`
|
|
74
65
|
config field to something that's high enough up to include both spec and source
|
|
@@ -78,6 +69,23 @@ running `npx jasmine-browser-runner init --esm`.
|
|
|
78
69
|
If you have specs or helper files that use top-level await, set the
|
|
79
70
|
`enableTopLevelAwait` config property is set to `true`.
|
|
80
71
|
|
|
72
|
+
[Import maps](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap)
|
|
73
|
+
are also supported:
|
|
74
|
+
|
|
75
|
+
```javascript
|
|
76
|
+
{
|
|
77
|
+
// ...
|
|
78
|
+
"importMap": {
|
|
79
|
+
"moduleRootDir": "node_modules",
|
|
80
|
+
"imports": {
|
|
81
|
+
"some-lib":"some-lib/dist/index.mjs",
|
|
82
|
+
"some-lib/": "some-lib/dist/",
|
|
83
|
+
"some-cdn-lib": "https://example.com/some-cdn-lib"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
81
89
|
## Use with Rails
|
|
82
90
|
|
|
83
91
|
You can use jasmine-browser-runner to test your Rails application's JavaScript,
|
|
@@ -204,7 +212,7 @@ Firefox, and Microsoft Edge) as well as Node.
|
|
|
204
212
|
|
|
205
213
|
| Environment | Supported versions |
|
|
206
214
|
|-------------------|------------------------|
|
|
207
|
-
| Node |
|
|
215
|
+
| Node | 18, 20 |
|
|
208
216
|
| Safari | 15-16 |
|
|
209
217
|
| Chrome | Evergreen |
|
|
210
218
|
| Firefox | Evergreen, 102 |
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
const path = require('path'),
|
|
4
4
|
jasmineCore = require('../lib/jasmineCore'),
|
|
5
5
|
Command = require('../lib/command'),
|
|
6
6
|
jasmineBrowser = require('../index.js');
|
|
7
7
|
const UsageError = require('../lib/usage_error');
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
const command = new Command({
|
|
10
10
|
baseDir: path.resolve(),
|
|
11
11
|
jasmineCore,
|
|
12
12
|
jasmineBrowser,
|
package/lib/command.js
CHANGED
|
@@ -250,7 +250,7 @@ function wrapDescription(indentLevel, prefixWidth, maxWidth, text) {
|
|
|
250
250
|
return text;
|
|
251
251
|
}
|
|
252
252
|
|
|
253
|
-
|
|
253
|
+
const chunks = [];
|
|
254
254
|
while (text.length > columnWidth) {
|
|
255
255
|
const wrapChar = text.lastIndexOf(' ', columnWidth);
|
|
256
256
|
chunks.push(text.substring(0, wrapChar));
|
package/lib/config.js
CHANGED
|
@@ -50,6 +50,10 @@ function validateConfig(config) {
|
|
|
50
50
|
throw new Error(`Configuration's ${k} property is not an array`);
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
|
+
|
|
54
|
+
if (config.importMap) {
|
|
55
|
+
validateImportMap(config.importMap);
|
|
56
|
+
}
|
|
53
57
|
}
|
|
54
58
|
|
|
55
59
|
function defaultConfig() {
|
|
@@ -67,6 +71,83 @@ function defaultEsmConfig() {
|
|
|
67
71
|
);
|
|
68
72
|
}
|
|
69
73
|
|
|
74
|
+
function validateImportMap(importMap) {
|
|
75
|
+
// basic validation, but not the entire spec.
|
|
76
|
+
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap
|
|
77
|
+
|
|
78
|
+
if (typeof importMap !== 'object') {
|
|
79
|
+
throw new Error("Configuration's importMap property is not an object");
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (!importMap.imports && !importMap.scopes) {
|
|
83
|
+
throw new Error("Configuration's importMap contains no imports or scopes");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (importMap.imports) {
|
|
87
|
+
validateImports('importMap.imports', importMap.imports);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (importMap.scopes) {
|
|
91
|
+
for (const [kScope, vScope] of Object.entries(importMap.scopes)) {
|
|
92
|
+
if (kScope === '') {
|
|
93
|
+
throw new Error(
|
|
94
|
+
"Configuration's importMap.scopes cannot contain empty keys"
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
if (typeof vScope !== 'object') {
|
|
98
|
+
throw new Error(
|
|
99
|
+
"Configuration's importMap.scopes property is not an object"
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
validateImports('importMap.scopes', vScope);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const moduleRootDir = importMap.moduleRootDir;
|
|
107
|
+
|
|
108
|
+
if (moduleRootDir === '') {
|
|
109
|
+
throw new Error(
|
|
110
|
+
'Configuration.importMap.moduleRootDir cannot be an empty string'
|
|
111
|
+
);
|
|
112
|
+
} else if (moduleRootDir && moduleRootDir.startsWith('../')) {
|
|
113
|
+
throw new Error(
|
|
114
|
+
'Configuration.importMap.moduleRootDir cannot start with ../'
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Both importMap.imports and importMap.scopes[k].value should be an object with
|
|
120
|
+
// module specifiers, hence this helper function for DRY.
|
|
121
|
+
// @param context `importMap.imports` | `importMap.scopes`
|
|
122
|
+
// @param module specifier map of string -> string
|
|
123
|
+
function validateImports(context, imports) {
|
|
124
|
+
if (typeof imports !== 'object') {
|
|
125
|
+
throw new Error(`Configuration's ${context} property is not an object`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (Object.keys(imports).length === 0) {
|
|
129
|
+
throw new Error(`Configuration's ${context} map cannot be empty`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
for (const [kImport, vImport] of Object.entries(imports)) {
|
|
133
|
+
if (kImport === '') {
|
|
134
|
+
throw new Error(
|
|
135
|
+
`Configuration's ${context} map cannot contain empty string keys`
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (vImport === '') {
|
|
140
|
+
throw new Error(
|
|
141
|
+
`Configuration's ${context} map cannot contain empty string values`
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (typeof vImport !== 'string') {
|
|
146
|
+
throw new Error(`Configuration's ${context} map value is not a string`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
70
151
|
module.exports = {
|
|
71
152
|
loadConfig,
|
|
72
153
|
validateConfig,
|
package/lib/server.js
CHANGED
|
@@ -14,7 +14,7 @@ class Server {
|
|
|
14
14
|
* @param {ServerCtorOptions} options
|
|
15
15
|
*/
|
|
16
16
|
constructor(options) {
|
|
17
|
-
this.options = options;
|
|
17
|
+
this.options = { ...options };
|
|
18
18
|
this.useHtmlReporter =
|
|
19
19
|
options.useHtmlReporter === undefined ? true : options.useHtmlReporter;
|
|
20
20
|
this.projectBaseDir = options.projectBaseDir || path.resolve();
|
|
@@ -29,6 +29,13 @@ class Server {
|
|
|
29
29
|
return unWindows(path.join('/__jasmine__', fileName));
|
|
30
30
|
})
|
|
31
31
|
.concat(this.bootFiles());
|
|
32
|
+
|
|
33
|
+
if (!this.options.esmFilenameExtension) {
|
|
34
|
+
this.options.esmFilenameExtension = '.mjs';
|
|
35
|
+
} else if (this.options.esmFilenameExtension[0] !== '.') {
|
|
36
|
+
this.options.esmFilenameExtension =
|
|
37
|
+
'.' + this.options.esmFilenameExtension;
|
|
38
|
+
}
|
|
32
39
|
}
|
|
33
40
|
|
|
34
41
|
bootFiles() {
|
|
@@ -40,7 +47,7 @@ class Server {
|
|
|
40
47
|
}
|
|
41
48
|
|
|
42
49
|
allCss() {
|
|
43
|
-
|
|
50
|
+
const urls = this.getUrls(
|
|
44
51
|
this.options.srcDir,
|
|
45
52
|
this.options.cssFiles,
|
|
46
53
|
'/__src__'
|
|
@@ -71,20 +78,20 @@ class Server {
|
|
|
71
78
|
}
|
|
72
79
|
|
|
73
80
|
userJs() {
|
|
74
|
-
|
|
81
|
+
const srcUrls = this.getUrls(
|
|
75
82
|
this.options.srcDir,
|
|
76
83
|
this.options.srcFiles,
|
|
77
84
|
'/__src__'
|
|
78
|
-
).filter(
|
|
85
|
+
).filter(url => {
|
|
79
86
|
// Exclude ES modules. These will be loaded by other ES modules.
|
|
80
|
-
return !url.endsWith(
|
|
87
|
+
return !url.endsWith(this.options.esmFilenameExtension);
|
|
81
88
|
});
|
|
82
|
-
|
|
89
|
+
const helperUrls = this.getUrls(
|
|
83
90
|
this.options.specDir,
|
|
84
91
|
this.options.helpers,
|
|
85
92
|
'/__spec__'
|
|
86
93
|
);
|
|
87
|
-
|
|
94
|
+
const specUrls = this.getUrls(
|
|
88
95
|
this.options.specDir,
|
|
89
96
|
this.options.specFiles,
|
|
90
97
|
'/__spec__'
|
|
@@ -92,6 +99,33 @@ class Server {
|
|
|
92
99
|
return [].concat(srcUrls, helperUrls, specUrls);
|
|
93
100
|
}
|
|
94
101
|
|
|
102
|
+
// Bound property for ejs template, used to inject a `<script
|
|
103
|
+
// type="importmap">` tag. This changes specifier target values for any
|
|
104
|
+
// relative module paths according to `this.options.importMap.moduleRootDir`.
|
|
105
|
+
// @returns ImportMap | undefined
|
|
106
|
+
importMap() {
|
|
107
|
+
const { importMap } = this.options;
|
|
108
|
+
if (!importMap) {
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const resultMap = {};
|
|
113
|
+
|
|
114
|
+
if (importMap.imports) {
|
|
115
|
+
resultMap.imports = reifyRawSpecifierMap(importMap.imports);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (importMap.scopes) {
|
|
119
|
+
resultMap.scopes = {};
|
|
120
|
+
|
|
121
|
+
for (const [scope, map] of Object.entries(importMap.scopes)) {
|
|
122
|
+
resultMap.scopes[scope] = reifyRawSpecifierMap(map);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return resultMap;
|
|
127
|
+
}
|
|
128
|
+
|
|
95
129
|
/**
|
|
96
130
|
* Starts the server.
|
|
97
131
|
* @param {ServerStartOptions} options
|
|
@@ -99,7 +133,7 @@ class Server {
|
|
|
99
133
|
*/
|
|
100
134
|
start(serverOptions) {
|
|
101
135
|
serverOptions = serverOptions || {};
|
|
102
|
-
|
|
136
|
+
const app = express();
|
|
103
137
|
|
|
104
138
|
app.use('/__jasmine__', express.static(this.jasmineCore.files.path));
|
|
105
139
|
app.use('/__boot__', express.static(this.jasmineCore.files.bootDir));
|
|
@@ -114,14 +148,21 @@ class Server {
|
|
|
114
148
|
express.static(path.join(this.projectBaseDir, this.options.srcDir))
|
|
115
149
|
);
|
|
116
150
|
|
|
117
|
-
|
|
151
|
+
if (this.options.importMap) {
|
|
152
|
+
const dir = this.options.importMap.moduleRootDir
|
|
153
|
+
? path.join(this.projectBaseDir, this.options.importMap.moduleRootDir)
|
|
154
|
+
: this.projectBaseDir;
|
|
155
|
+
app.use('/__moduleRoot__', express.static(dir));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const indexTemplate = ejs.compile(
|
|
118
159
|
fs.readFileSync(path.resolve(__dirname, '../run.html.ejs')).toString()
|
|
119
160
|
);
|
|
120
|
-
|
|
161
|
+
const configTemplate = ejs.compile(
|
|
121
162
|
fs.readFileSync(path.resolve(__dirname, '../config.js.ejs')).toString()
|
|
122
163
|
);
|
|
123
164
|
|
|
124
|
-
|
|
165
|
+
const self = this;
|
|
125
166
|
app.get('/', function(req, res) {
|
|
126
167
|
try {
|
|
127
168
|
res.send(
|
|
@@ -129,6 +170,8 @@ class Server {
|
|
|
129
170
|
cssFiles: self.allCss(),
|
|
130
171
|
jasmineJsFiles: self.jasmineJs(),
|
|
131
172
|
userJsFiles: self.userJs(),
|
|
173
|
+
esmFilenameExtension: self.options.esmFilenameExtension,
|
|
174
|
+
importMap: self.importMap(),
|
|
132
175
|
enableTopLevelAwait: self.options.enableTopLevelAwait || false,
|
|
133
176
|
})
|
|
134
177
|
);
|
|
@@ -151,7 +194,7 @@ class Server {
|
|
|
151
194
|
}
|
|
152
195
|
});
|
|
153
196
|
|
|
154
|
-
|
|
197
|
+
const port = findPort(serverOptions.port, this.options.port);
|
|
155
198
|
return new Promise(resolve => {
|
|
156
199
|
this._httpServer = app.listen(port, () => {
|
|
157
200
|
const runningPort = this._httpServer.address().port;
|
|
@@ -258,4 +301,22 @@ function unWindows(filePath) {
|
|
|
258
301
|
return filePath.replace(/\\/g, '/');
|
|
259
302
|
}
|
|
260
303
|
|
|
304
|
+
// Processes the incoming `rawSpecifierMap`, converting targets to use actual
|
|
305
|
+
// paths that the run.html.ejs file will contain. The `rawSpecifierMap` is not
|
|
306
|
+
// the entire importMap. It is a key/value map that may be the "imports" value
|
|
307
|
+
// or an individual map inside of "scopes"[someScope].
|
|
308
|
+
function reifyRawSpecifierMap(rawSpecifierMap) {
|
|
309
|
+
const concreteMap = {};
|
|
310
|
+
|
|
311
|
+
for (const [key, value] of Object.entries(rawSpecifierMap)) {
|
|
312
|
+
if (value.match(/^https?:\/\//)) {
|
|
313
|
+
concreteMap[key] = value; // pass through unchanged
|
|
314
|
+
} else {
|
|
315
|
+
concreteMap[key] = './' + unWindows(path.join('__moduleRoot__', value));
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return concreteMap;
|
|
320
|
+
}
|
|
321
|
+
|
|
261
322
|
module.exports = Server;
|
package/lib/support/loaders.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/* eslint-env browser, jasmine */
|
|
2
2
|
|
|
3
3
|
window._jasmine_loadEsModule = function(src) {
|
|
4
|
-
|
|
4
|
+
const script = document.createElement('script');
|
|
5
5
|
script.type = 'module';
|
|
6
6
|
|
|
7
7
|
// Safari reports syntax errors in ES modules as a script element error
|
|
8
8
|
// event rather than a global error event. Rethrow so that Jasmine can
|
|
9
9
|
// pick it up and fail the suite.
|
|
10
10
|
script.addEventListener('error', function(event) {
|
|
11
|
-
|
|
11
|
+
const msg =
|
|
12
12
|
'An error occurred while loading ' +
|
|
13
13
|
src +
|
|
14
14
|
'. Check the browser console for details.';
|
|
@@ -19,7 +19,10 @@ window._jasmine_loadEsModule = function(src) {
|
|
|
19
19
|
document.head.appendChild(script);
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
-
window._jasmine_loadWithTopLevelAwaitSupport = async function(
|
|
22
|
+
window._jasmine_loadWithTopLevelAwaitSupport = async function(
|
|
23
|
+
scriptUrls,
|
|
24
|
+
esmFilenameExtension
|
|
25
|
+
) {
|
|
23
26
|
const scriptsLoaded = (async function() {
|
|
24
27
|
// Load scripts sequentially to ensure that users can get a stable order
|
|
25
28
|
// by disabling randomization or setting a seed. This can be considerably
|
|
@@ -28,7 +31,7 @@ window._jasmine_loadWithTopLevelAwaitSupport = async function(scriptUrls) {
|
|
|
28
31
|
// describes will execute in a consistent order in the presence of top-level
|
|
29
32
|
// await.
|
|
30
33
|
for (const url of scriptUrls) {
|
|
31
|
-
const isEsm = url.endsWith(
|
|
34
|
+
const isEsm = url.endsWith(esmFilenameExtension);
|
|
32
35
|
|
|
33
36
|
if (isEsm) {
|
|
34
37
|
try {
|
package/lib/types.js
CHANGED
|
@@ -70,6 +70,12 @@
|
|
|
70
70
|
* @name ServerCtorOptions#srcFiles
|
|
71
71
|
* @type string[] | undefined
|
|
72
72
|
*/
|
|
73
|
+
/**
|
|
74
|
+
* The file extension used by ES modules
|
|
75
|
+
* @name ServerCtorOptions#esmFilenameExtension
|
|
76
|
+
* @type string | undefined
|
|
77
|
+
* @default ".mjs"
|
|
78
|
+
*/
|
|
73
79
|
|
|
74
80
|
/**
|
|
75
81
|
* Specifies the properties of the configuration file, as well as
|
|
@@ -111,6 +117,14 @@
|
|
|
111
117
|
* @type boolean | undefined
|
|
112
118
|
* @default true
|
|
113
119
|
*/
|
|
120
|
+
/**
|
|
121
|
+
* Import maps entry to generate the `<script type="importmap">` section in the
|
|
122
|
+
* `<head>`, to enable ES Module testing in the browser.
|
|
123
|
+
*
|
|
124
|
+
* @name Configuration#importMap
|
|
125
|
+
* @type ImportMap | undefined
|
|
126
|
+
* @default undefined
|
|
127
|
+
*/
|
|
114
128
|
/**
|
|
115
129
|
* Whether to enable support for top-level await. This option is off by default
|
|
116
130
|
* because it comes with a performance penalty.
|
|
@@ -197,3 +211,37 @@
|
|
|
197
211
|
* @name ServerStartOptions#port
|
|
198
212
|
* @type number | undefined
|
|
199
213
|
*/
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Describes an import map.
|
|
217
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap}
|
|
218
|
+
* @see {@link https://github.com/WICG/import-maps}
|
|
219
|
+
* @interface ImportMap
|
|
220
|
+
*/
|
|
221
|
+
/**
|
|
222
|
+
* A single, unscoped module specifier map.
|
|
223
|
+
* @name ImportMap#imports
|
|
224
|
+
* @type {Object.<string, string>}
|
|
225
|
+
*/
|
|
226
|
+
/**
|
|
227
|
+
* Map of one or more scoped module specifier maps.
|
|
228
|
+
* @name ImportMap#scopes
|
|
229
|
+
* @type {Object.<string, Object.<string, string>>}
|
|
230
|
+
*/
|
|
231
|
+
/**
|
|
232
|
+
* Optional directory that specifies the root for relative paths in import map
|
|
233
|
+
* (if required).
|
|
234
|
+
*
|
|
235
|
+
* For example, if you only use import paths that resolve to absolute targets,
|
|
236
|
+
* e.g. 'my-pkg': 'https://mycdn.url/my-pkg', then you do not need this dir
|
|
237
|
+
* option. But if you need to reference a folder, e.g. `node_modules`, then this
|
|
238
|
+
* is required.
|
|
239
|
+
*
|
|
240
|
+
* moduleRootDir is evaluated relative to the project base directory, which is
|
|
241
|
+
* typically the current working directory from which jasmine-browser-runner is
|
|
242
|
+
* run.
|
|
243
|
+
*
|
|
244
|
+
* @name ImportMap#moduleRootDir
|
|
245
|
+
* @type string
|
|
246
|
+
* @example 'node_modules'
|
|
247
|
+
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jasmine-browser-runner",
|
|
3
|
-
"version": "2.0.0
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Serve and run your Jasmine specs in a browser",
|
|
5
5
|
"bin": "bin/jasmine-browser-runner",
|
|
6
6
|
"exports": "./index.js",
|
|
@@ -43,14 +43,14 @@
|
|
|
43
43
|
"selenium-webdriver": "^4.8.2"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
|
-
"jasmine-core": "^5.0.0
|
|
46
|
+
"jasmine-core": "^5.0.0"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"ejs-lint": "^2.0.0",
|
|
50
50
|
"eslint": "^8.38.0",
|
|
51
51
|
"eslint-plugin-jasmine": "^4.1.3",
|
|
52
|
-
"jasmine": "^5.0.0
|
|
53
|
-
"jasmine-core": "^5.0.0
|
|
52
|
+
"jasmine": "^5.0.0",
|
|
53
|
+
"jasmine-core": "^5.0.0",
|
|
54
54
|
"prettier": "^1.17.1",
|
|
55
55
|
"shelljs": "^0.8.3",
|
|
56
56
|
"temp": "^0.9.4"
|
|
@@ -115,7 +115,8 @@
|
|
|
115
115
|
"always"
|
|
116
116
|
],
|
|
117
117
|
"space-before-blocks": "error",
|
|
118
|
-
"no-console": "off"
|
|
118
|
+
"no-console": "off",
|
|
119
|
+
"no-var": "error"
|
|
119
120
|
},
|
|
120
121
|
"overrides": [
|
|
121
122
|
{
|
package/run.html.ejs
CHANGED
|
@@ -8,6 +8,11 @@
|
|
|
8
8
|
<% cssFiles.forEach(function(cssFile) { %>
|
|
9
9
|
<link rel="stylesheet" href="<%= cssFile %>" type="text/css" media="screen"/>
|
|
10
10
|
<% }) %>
|
|
11
|
+
<% if (importMap) { %>
|
|
12
|
+
<script type="importmap">
|
|
13
|
+
<%- JSON.stringify(importMap, null, 2) %>
|
|
14
|
+
</script>
|
|
15
|
+
<% } %>
|
|
11
16
|
</head>
|
|
12
17
|
<body>
|
|
13
18
|
<% jasmineJsFiles.forEach(function(jsFile) { %>
|
|
@@ -19,11 +24,11 @@
|
|
|
19
24
|
<% userJsFiles.forEach(function(jsFile) { %>
|
|
20
25
|
'<%= jsFile %>',
|
|
21
26
|
<% }) %>
|
|
22
|
-
]);
|
|
27
|
+
], '<%=esmFilenameExtension%>');
|
|
23
28
|
</script>
|
|
24
29
|
<% } else { %>
|
|
25
30
|
<% userJsFiles.forEach(function(jsFile) { %>
|
|
26
|
-
<% if (jsFile.endsWith(
|
|
31
|
+
<% if (jsFile.endsWith(esmFilenameExtension)) { %>
|
|
27
32
|
<script type="module">_jasmine_loadEsModule('<%= jsFile %>')</script>
|
|
28
33
|
<% } else { %>
|
|
29
34
|
<script src="<%= jsFile %>" type="text/javascript"></script>
|