jasmine-browser-runner 3.0.0-beta.1 → 3.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/MIT.LICENSE CHANGED
@@ -1,5 +1,5 @@
1
1
  Copyright (c) 2019 Pivotal Labs
2
- Copyright (c) 2020-2024 The Jasmine developers
2
+ Copyright (c) 2020-2025 The Jasmine developers
3
3
 
4
4
  Permission is hereby granted, free of charge, to any person obtaining
5
5
  a copy of this software and associated documentation files (the
package/README.md CHANGED
@@ -56,7 +56,7 @@ To use a browser other than Firefox, add a `browser` field to
56
56
  ```javascript
57
57
  export default {
58
58
  // ...
59
- "browser": "chrome"
59
+ browser: "chrome"
60
60
  }
61
61
  ```
62
62
 
@@ -71,8 +71,8 @@ in PEM format in `jasmine-browser.mjs`:
71
71
  ```javascript
72
72
  export default {
73
73
  // ...
74
- "tlsKey": "/path/to/tlsKey.pem",
75
- "tlsCert": "/path/to/tlsCert.pem",
74
+ tlsKey: "/path/to/tlsKey.pem",
75
+ tlsCert: "/path/to/tlsCert.pem",
76
76
  // ...
77
77
  }
78
78
  ```
@@ -85,38 +85,41 @@ or command line options may be necessary to use an invalid TLS certificate.
85
85
 
86
86
  ## Controlling which network interfaces are listened to
87
87
 
88
- By default, jasmine-browser-runner listens to all available network interfaces.
89
- You might need that if you're using a remote grid such as Saucelabs. If you
90
- don't need that, you can improve security by listening only to localhost.
88
+ **Note: This behavior differs between 2.x and 3.x. If you are using 2.x, please
89
+ consult the README for the version you're using.**
90
+
91
+ By default, jasmine-browser-runner listens to the network interface that
92
+ corresponds to localhost. To listen on a different interface, set `listenAddress`
93
+ to the corresponding hostname or IP address. To listen on all available network
94
+ interfaces, set `listenAddress` to `"*"`. You might need to do that if you're
95
+ using a remote grid such as Saucelabs.
91
96
 
92
97
  ```javascript
93
98
  export default {
94
99
  // ...
95
- "listenAddress": "localhost",
100
+ listenAddress: "*",
96
101
  // ...
97
102
  }
98
103
  ```
99
104
 
100
105
  ## Hostname support
101
106
 
107
+ **Note: This behavior differs between 2.x and 3.x. If you are using 2.x, please
108
+ consult the README for the version you're using.**
109
+
102
110
  If you need to access your tests via a specific hostname, you can do that by
103
111
  setting the `hostname` configuration property:
104
112
 
105
113
  ```javascript
106
114
  export default {
107
115
  // ...
108
- "hostname": "mymachine.mynetwork",
116
+ hostname: "mymachine.mynetwork",
109
117
  // ...
110
118
  }
111
119
  ```
112
120
 
113
121
  This can also be specified on the command line with `--hostname`.
114
122
 
115
- Setting `hostname` but not `listenAddress` has the same effect as setting
116
- `listenAddress` to the same value as `hostname`. If you need to set a hostname
117
- but retain the default behavior of listening to all network interfaces, you can
118
- do that by setting `listenAddress` to `"*"`.
119
-
120
123
  There are a few important caveats when doing this:
121
124
 
122
125
  1. This name must either be an IP or a name that can really be resolved on your
@@ -145,7 +148,7 @@ If a source, spec, or helper file's name ends in `.mjs`, it will be loaded as
145
148
  an ES module rather than a regular script. Note that ES modules can only be
146
149
  loaded from other ES modules. So if your source files are ES modules, your
147
150
  spec files need to be ES modules too. Want to use a different extension than
148
- `.esm`? Just set the `esmFilenameExtension` config property, e.g.
151
+ `.mjs`? Just set the `esmFilenameExtension` config property, e.g.
149
152
  `"esmFilenameExtension": ".js"`.
150
153
 
151
154
  To allow spec files to import source files via relative paths, set the `specDir`
@@ -153,8 +156,11 @@ config field to something that's high enough up to include both spec and source
153
156
  files, and set `srcFiles` to `[]`. You can autogenerate such a configuration by
154
157
  running `npx jasmine-browser-runner init --esm`.
155
158
 
159
+ If you want to load ES module source directly on load instead of loading it from
160
+ the corresponding spec, set the `modulesWithSideEffectsInSrcFiles` config property to `true`.
161
+
156
162
  If you have specs or helper files that use top-level await, set the
157
- `enableTopLevelAwait` config property is set to `true`.
163
+ `enableTopLevelAwait` config property to `true`.
158
164
 
159
165
  [Import maps](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap)
160
166
  are also supported:
@@ -326,7 +332,7 @@ import jasmineBrowser from 'jasmine-browser-runner';
326
332
  import config from './spec/support/jasmine-browser.mjs';
327
333
 
328
334
  config.projectBaseDir = path.resolve('some/path');
329
- jasmineBrowser.startServer(config, { port: 4321 });
335
+ jasmineBrowser.startServer(config);
330
336
 
331
337
 
332
338
  // CommonJS
@@ -336,7 +342,7 @@ const jasmineBrowser = require('jasmine-browser-runner');
336
342
  import('./spec/support/jasmine-browser.mjs')
337
343
  .then(function({default: config}) {
338
344
  config.projectBaseDir = path.resolve('some/path');
339
- jasmineBrowser.startServer(config, { port: 4321 });
345
+ jasmineBrowser.startServer(config);
340
346
  });
341
347
  ```
342
348
 
@@ -345,13 +351,13 @@ import('./spec/support/jasmine-browser.mjs')
345
351
  jasmine-browser-runner tests itself across popular browsers (Safari, Chrome,
346
352
  Firefox, and Microsoft Edge) as well as Node.
347
353
 
348
- | Environment | Supported versions |
349
- |-------------------|--------------------------|
350
- | Node | 18, 20, 22 |
351
- | Safari | 15-17 |
352
- | Chrome | Evergreen |
353
- | Firefox | Evergreen, 102, 115, 128 |
354
- | Edge | Evergreen |
354
+ | Environment | Supported versions |
355
+ |-------------------|----------------------------|
356
+ | Node | 18, 20, 22 |
357
+ | Safari | 15*, 16*, 17* |
358
+ | Chrome | Evergreen |
359
+ | Firefox | Evergreen, 102*, 115*, 128 |
360
+ | Edge | Evergreen |
355
361
 
356
362
  For evergreen browsers, each version of jasmine-browser-runner is tested against
357
363
  the version of the browser that is available to us at the time of release. Other
@@ -359,8 +365,13 @@ browsers, as well as older & newer versions of some supported browsers, are
359
365
  likely to work. However, jasmine-browser-runner isn't tested against them and
360
366
  they aren't actively supported.
361
367
 
368
+ \* Supported on a best-effort basis. Support for these versions may be dropped
369
+ if it becomes impractical, and bugs affecting only these versions may not be
370
+ treated as release blockers.
371
+
372
+
362
373
  To find out what environments work with a particular Jasmine release, see the [release notes](https://github.com/jasmine/jasmine/tree/main/release_notes).
363
374
 
364
375
  Copyright (c) 2019 Pivotal Labs<br>
365
- Copyright (c) 2020-2024 The Jasmine developers<br>
376
+ Copyright (c) 2020-2025 The Jasmine developers<br>
366
377
  This software is licensed under the MIT License.
package/lib/command.js CHANGED
@@ -80,12 +80,6 @@ const subCommands = [
80
80
  type: 'string',
81
81
  description: 'specify a seed for randomization',
82
82
  },
83
- {
84
- name: 'reporter',
85
- type: 'string',
86
- description:
87
- 'path to reporter to use instead of the default Jasmine reporter',
88
- },
89
83
  {
90
84
  name: 'browser',
91
85
  type: 'string',
@@ -13,7 +13,9 @@ export default {
13
13
  env: {
14
14
  stopSpecOnExpectationFailure: false,
15
15
  stopOnSpecFailure: false,
16
- random: true
16
+ random: true,
17
+ // Fail if a suite contains multiple suites or specs with the same name.
18
+ forbidDuplicateNames: true
17
19
  },
18
20
 
19
21
  // For security, listen only to localhost. You can also specify a different
@@ -11,13 +11,17 @@ export default {
11
11
  "spec/helpers/**/*.?(m)js"
12
12
  ],
13
13
  esmFilenameExtension: ".mjs",
14
+ // Set to true if you need to load module src files instead of loading via the spec files.
15
+ modulesWithSideEffectsInSrcFiles: false,
14
16
  // Allows the use of top-level await in src/spec/helper files. This is off by
15
17
  // default because it makes files load more slowly.
16
18
  enableTopLevelAwait: false,
17
19
  env: {
18
20
  stopSpecOnExpectationFailure: false,
19
21
  stopOnSpecFailure: false,
20
- random: true
22
+ random: true,
23
+ // Fail if a suite contains multiple suites or specs with the same name.
24
+ forbidDuplicateNames: true
21
25
  },
22
26
 
23
27
  // For security, listen only to localhost. You can also specify a different
package/lib/runner.js CHANGED
@@ -8,11 +8,6 @@ function getBatch(driver) {
8
8
  'if (results[i][1].passedExpectations) {\n' +
9
9
  'expectations = expectations.concat(results[i][1].passedExpectations);\n' +
10
10
  '}\n' +
11
- 'for (var j = 0; j < expectations.length; j++) {\n' +
12
- 'var expectation = expectations[j];\n' +
13
- "try { JSON.stringify(expectation.expected); } catch (e) { expectation.expected = '<circular expected>'; }\n" +
14
- "try { JSON.stringify(expectation.actual); } catch (e) { expectation.actual = '<circular actual>'; }\n" +
15
- '}\n' +
16
11
  '}\n' +
17
12
  'return results;'
18
13
  );
package/lib/server.js CHANGED
@@ -19,8 +19,6 @@ class Server {
19
19
  this.options = { ...options };
20
20
  this._deps = deps || { http, https };
21
21
  this.express = this.options.express || defaultExpress;
22
- this.useHtmlReporter =
23
- options.useHtmlReporter === undefined ? true : options.useHtmlReporter;
24
22
  this.projectBaseDir = options.projectBaseDir || path.resolve();
25
23
  this.jasmineCore = options.jasmineCore || require('./jasmineCore');
26
24
  this.jasmineCssFiles = this.jasmineCore.files.cssFiles.map(function(
@@ -70,10 +68,6 @@ class Server {
70
68
 
71
69
  getSupportFiles() {
72
70
  const result = ['/__support__/loaders.js'];
73
- if (!this.useHtmlReporter) {
74
- result.push('/__support__/clearReporters.js');
75
- }
76
-
77
71
  result.push('/__support__/batchReporter.js');
78
72
  return result;
79
73
  }
@@ -88,8 +82,11 @@ class Server {
88
82
  this.options.srcFiles,
89
83
  '/__src__'
90
84
  ).filter(url => {
91
- // Exclude ES modules. These will be loaded by other ES modules.
92
- return !url.endsWith(this.options.esmFilenameExtension);
85
+ // Exclude ES modules by default. These will be loaded by other ES modules.
86
+ return (
87
+ this.options.modulesWithSideEffectsInSrcFiles ||
88
+ !url.endsWith(this.options.esmFilenameExtension)
89
+ );
93
90
  });
94
91
  const helperUrls = this.getUrls(
95
92
  this.options.specDir,
@@ -117,14 +114,22 @@ class Server {
117
114
  const resultMap = {};
118
115
 
119
116
  if (importMap.imports) {
120
- resultMap.imports = reifyRawSpecifierMap(importMap.imports);
117
+ resultMap.imports = reifyRawSpecifierMap(
118
+ importMap.imports,
119
+ this.options,
120
+ this.projectBaseDir
121
+ );
121
122
  }
122
123
 
123
124
  if (importMap.scopes) {
124
125
  resultMap.scopes = {};
125
126
 
126
127
  for (const [scope, map] of Object.entries(importMap.scopes)) {
127
- resultMap.scopes[scope] = reifyRawSpecifierMap(map);
128
+ resultMap.scopes[scope] = reifyRawSpecifierMap(
129
+ map,
130
+ this.options,
131
+ this.projectBaseDir
132
+ );
128
133
  }
129
134
  }
130
135
 
@@ -197,6 +202,8 @@ class Server {
197
202
  esmFilenameExtension: self.options.esmFilenameExtension,
198
203
  importMap: self.importMap(),
199
204
  enableTopLevelAwait: self.options.enableTopLevelAwait || false,
205
+ modulesWithSideEffectsInSrcFiles:
206
+ self.options.modulesWithSideEffectsInSrcFiles || false,
200
207
  })
201
208
  );
202
209
  } catch (error) {
@@ -378,14 +385,32 @@ function unWindows(filePath) {
378
385
  // paths that the run.html.ejs file will contain. The `rawSpecifierMap` is not
379
386
  // the entire importMap. It is a key/value map that may be the "imports" value
380
387
  // or an individual map inside of "scopes"[someScope].
381
- function reifyRawSpecifierMap(rawSpecifierMap) {
388
+ function reifyRawSpecifierMap(rawSpecifierMap, options, projectBaseDir) {
382
389
  const concreteMap = {};
390
+ const absoluteModuleRootDir = options.importMap.moduleRootDir
391
+ ? path.resolve(projectBaseDir, options.importMap.moduleRootDir)
392
+ : projectBaseDir;
383
393
 
384
394
  for (const [key, value] of Object.entries(rawSpecifierMap)) {
385
395
  if (value.match(/^https?:\/\//)) {
386
396
  concreteMap[key] = value; // pass through unchanged
387
- } else {
397
+ continue;
398
+ }
399
+
400
+ const absolutePath = path.join(absoluteModuleRootDir, value);
401
+ const endsWithSeparator = value.endsWith('/') || value.endsWith('\\');
402
+
403
+ const resolvedSrcDir = path.join(absoluteModuleRootDir, options.srcDir);
404
+ const relativeFromSrcDir = path.relative(resolvedSrcDir, absolutePath);
405
+
406
+ if (relativeFromSrcDir.startsWith('..')) {
388
407
  concreteMap[key] = './' + unWindows(path.join('__moduleRoot__', value));
408
+ } else {
409
+ // We are under srcDir: Reuse existing __src__ path
410
+ concreteMap[key] =
411
+ './' +
412
+ unWindows(path.join('__src__', relativeFromSrcDir)) +
413
+ (endsWithSeparator ? '/' : '');
389
414
  }
390
415
  }
391
416
 
@@ -21,16 +21,31 @@ function BatchReporter() {
21
21
  };
22
22
 
23
23
  this.jasmineDone = function(info) {
24
+ deleteExpectedAndActual(info);
24
25
  events.push(['jasmineDone', info]);
25
26
  };
26
27
 
27
28
  this.suiteDone = function(info) {
29
+ deleteExpectedAndActual(info);
28
30
  events.push(['suiteDone', info]);
29
31
  };
30
32
 
31
33
  this.specDone = function(info) {
34
+ deleteExpectedAndActual(info);
32
35
  events.push(['specDone', info]);
33
36
  };
37
+
38
+ function deleteExpectedAndActual(info) {
39
+ for (const e of info.failedExpectations) {
40
+ // Delete expected and actual. Not all JS objects are serializable, we
41
+ // don't have a reliable way to determine what Selenium can and can't
42
+ // serialize, not everything that's serializable survives the process
43
+ // intact, and there are no known reporters that use the expected or
44
+ // actual properties of expectation results.
45
+ delete e.expected;
46
+ delete e.actual;
47
+ }
48
+ }
34
49
  }
35
50
 
36
51
  window.batchReporter = new BatchReporter();
@@ -1,24 +1,5 @@
1
1
  /* eslint-env browser, jasmine */
2
2
 
3
- window._jasmine_loadEsModule = function(src) {
4
- const script = document.createElement('script');
5
- script.type = 'module';
6
-
7
- // Safari reports syntax errors in ES modules as a script element error
8
- // event rather than a global error event. Rethrow so that Jasmine can
9
- // pick it up and fail the suite.
10
- script.addEventListener('error', function(event) {
11
- const msg =
12
- 'An error occurred while loading ' +
13
- src +
14
- '. Check the browser console for details.';
15
- throw new Error(msg);
16
- });
17
-
18
- script.src = src;
19
- document.head.appendChild(script);
20
- };
21
-
22
3
  window._jasmine_loadWithTopLevelAwaitSupport = async function(
23
4
  scriptUrls,
24
5
  esmFilenameExtension
package/lib/types.js CHANGED
@@ -8,12 +8,6 @@
8
8
  * certainly want to provide at least specFiles and srcFiles as well.
9
9
  * @see Server
10
10
  */
11
- /**
12
- * Whether to use Jasmine's default HTML reporter.
13
- * @name ServerCtorOptions#useHtmlReporter
14
- * @type boolean | undefined
15
- * @default true
16
- */
17
11
  /**
18
12
  * An array of CSS file paths or {@link https://github.com/isaacs/node-glob#glob-primer|globs}
19
13
  * that match CSS files. Each path or glob will be evaluated relative to
@@ -159,6 +153,16 @@
159
153
  * @type boolean | undefined
160
154
  * @default false
161
155
  */
156
+ /**
157
+ * If set to true jasmine loads also ES Modules which are included in SrcFiles.
158
+ * This option is off by default because in most scenarios it is better to load the
159
+ * module under test from the test itself.
160
+ * But if the module has wanted side effects (like for example polyfills) you can
161
+ * interleave ES module and classic scripts in your SrcFiles.
162
+ * @name Configuration#modulesWithSideEffectsInSrcFiles
163
+ * @type boolean | undefined
164
+ * @default false
165
+ */
162
166
  /**
163
167
  * <p>An optional map from paths to Express application middleware to mount on
164
168
  * those paths. This can be used to serve static files, proxy requests to
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jasmine-browser-runner",
3
- "version": "3.0.0-beta.1",
3
+ "version": "3.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,13 +43,13 @@
43
43
  "selenium-webdriver": "^4.12.0"
44
44
  },
45
45
  "peerDependencies": {
46
- "jasmine-core": "^5.0.0"
46
+ "jasmine-core": "^5.5.0"
47
47
  },
48
48
  "devDependencies": {
49
49
  "eslint": "^8.50.0",
50
50
  "eslint-plugin-jasmine": "^4.1.3",
51
51
  "jasmine": "^5.0.0",
52
- "jasmine-core": "^5.0.0",
52
+ "jasmine-core": "^5.5.0",
53
53
  "prettier": "^1.17.1",
54
54
  "shelljs": "^0.8.3",
55
55
  "temp": "^0.9.4"
package/run.html.ejs CHANGED
@@ -29,7 +29,9 @@
29
29
  <% } else { %>
30
30
  <% userJsFiles.forEach(function(jsFile) { %>
31
31
  <% if (jsFile.endsWith(esmFilenameExtension)) { %>
32
- <script type="module">_jasmine_loadEsModule('<%= jsFile %>')</script>
32
+ <script src="<%= jsFile %>" type="module"></script>
33
+ <% } else if (modulesWithSideEffectsInSrcFiles) { %>
34
+ <script src="<%= jsFile %>" type="text/javascript" defer></script>
33
35
  <% } else { %>
34
36
  <script src="<%= jsFile %>" type="text/javascript"></script>
35
37
  <% } %>
@@ -1,2 +0,0 @@
1
- /* eslint-env browser, jasmine */
2
- jasmine.getEnv().clearReporters();