jasmine-browser-runner 2.3.0 → 2.5.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 +2 -1
- package/README.md +128 -54
- package/bin/jasmine-browser-runner +5 -5
- package/index.js +15 -17
- package/lib/command.js +17 -1
- package/lib/config.js +10 -11
- package/lib/console_reporter.js +4 -4
- package/lib/examples/default_config.mjs +30 -0
- package/lib/examples/default_esm_config.mjs +34 -0
- package/lib/runner.js +29 -3
- package/lib/server.js +92 -19
- package/lib/types.js +51 -0
- package/lib/webdriver.js +6 -0
- package/package.json +7 -6
- package/lib/examples/default_config.json +0 -21
- package/lib/examples/default_esm_config.json +0 -21
package/MIT.LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
jasmine-browser-runner runs your Jasmine specs in a browser. It's suitable for
|
|
2
2
|
interactive use with normal browsers as well as running specs in CI builds
|
|
3
|
-
using either headless
|
|
3
|
+
using either headless browsers or with a remote Selenuium grid provider
|
|
4
|
+
such as Saucelabs.
|
|
4
5
|
|
|
5
6
|
# Getting started
|
|
6
7
|
|
|
@@ -19,12 +20,22 @@ npx jasmine-browser-runner init
|
|
|
19
20
|
If you intend to use ES modules, add `--esm` to the `jasmine-browser-runner init`
|
|
20
21
|
command.
|
|
21
22
|
|
|
22
|
-
Then, customize `spec/support/jasmine-browser.
|
|
23
|
+
Then, customize `spec/support/jasmine-browser.mjs` to suit your needs. You can
|
|
23
24
|
change the spec files, helpers, and source files that are loaded, specify the
|
|
24
25
|
[Jasmine env's configuration](https://jasmine.github.io/api/edge/Configuration.html),
|
|
25
26
|
and more.
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
In addition to `spec/support/jasmine-browser.mjs`, jasmine-browser-runner also
|
|
29
|
+
supports other config file paths:
|
|
30
|
+
|
|
31
|
+
* `spec/support/jasmine-browser.js`
|
|
32
|
+
* `spec/support/jasmine-browser.json` (generated by previous versions of the
|
|
33
|
+
`init` subcommand)
|
|
34
|
+
* Any other JavaScript or JSON file, if you use the `--config` option. This
|
|
35
|
+
file can be a JSON file or a javascript file whose default export is a config
|
|
36
|
+
object.
|
|
37
|
+
|
|
38
|
+
More information about the configuration can be found at the runner [documentation website](https://jasmine.github.io/api/browser-runner/edge/Configuration.html).
|
|
28
39
|
|
|
29
40
|
To start the server so that you can run the specs interactively (particularly
|
|
30
41
|
useful for debugging):
|
|
@@ -40,10 +51,10 @@ npx jasmine-browser-runner runSpecs
|
|
|
40
51
|
```
|
|
41
52
|
|
|
42
53
|
To use a browser other than Firefox, add a `browser` field to
|
|
43
|
-
`jasmine-browser.
|
|
54
|
+
`jasmine-browser.mjs`:
|
|
44
55
|
|
|
45
56
|
```javascript
|
|
46
|
-
{
|
|
57
|
+
export default {
|
|
47
58
|
// ...
|
|
48
59
|
"browser": "chrome"
|
|
49
60
|
}
|
|
@@ -52,6 +63,82 @@ To use a browser other than Firefox, add a `browser` field to
|
|
|
52
63
|
Its value can be `"firefox"`, `"headlessFirefox"`, `"safari"`,
|
|
53
64
|
`"MicrosoftEdge"`, `"chrome"`, or `"headlessChrome"`.
|
|
54
65
|
|
|
66
|
+
## TLS support
|
|
67
|
+
|
|
68
|
+
To serve tests over HTTPS instead of HTTP, supply a path to a TLS cert and key
|
|
69
|
+
in PEM format in `jasmine-browser.mjs`:
|
|
70
|
+
|
|
71
|
+
```javascript
|
|
72
|
+
export default {
|
|
73
|
+
// ...
|
|
74
|
+
"tlsKey": "/path/to/tlsKey.pem",
|
|
75
|
+
"tlsCert": "/path/to/tlsCert.pem",
|
|
76
|
+
// ...
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
These can also be specified on the command line with `--tlsKey` and `--tlsCert`.
|
|
81
|
+
|
|
82
|
+
Note that if you are using a self-signed or otherwise invalid certificate, the
|
|
83
|
+
browser will not allow the connection by default. Additional browser configs
|
|
84
|
+
or command line options may be necessary to use an invalid TLS certificate.
|
|
85
|
+
|
|
86
|
+
## Controlling which network interfaces are listened to
|
|
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.
|
|
91
|
+
|
|
92
|
+
```javascript
|
|
93
|
+
export default {
|
|
94
|
+
// ...
|
|
95
|
+
"listenAddress": "localhost",
|
|
96
|
+
// ...
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Hostname support
|
|
101
|
+
|
|
102
|
+
If you need to access your tests via a specific hostname, you can do that by
|
|
103
|
+
setting the `hostname` configuration property:
|
|
104
|
+
|
|
105
|
+
```javascript
|
|
106
|
+
export default {
|
|
107
|
+
// ...
|
|
108
|
+
"hostname": "mymachine.mynetwork",
|
|
109
|
+
// ...
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
This can also be specified on the command line with `--hostname`.
|
|
114
|
+
|
|
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
|
+
There are a few important caveats when doing this:
|
|
121
|
+
|
|
122
|
+
1. This name must either be an IP or a name that can really be resolved on your
|
|
123
|
+
system. Otherwise, you will get `ENOTFOUND` errors.
|
|
124
|
+
2. This name must correspond to an IP assigned to one of the network interfaces
|
|
125
|
+
on your system. Otherwise, you will get `EADDRNOTAVAIL` errors.
|
|
126
|
+
3. If this name matches the [HSTS preload list](https://hstspreload.org/),
|
|
127
|
+
browsers will force the connection to HTTPS. If you are not using TLS, you
|
|
128
|
+
will get an error that says `The browser tried to speak HTTPS to an HTTP
|
|
129
|
+
server. Misconfiguration is likely.` You may be surprised by the names on
|
|
130
|
+
that preload list, which include such favorite local network hostnames as:
|
|
131
|
+
- dev
|
|
132
|
+
- foo
|
|
133
|
+
- app
|
|
134
|
+
- nexus
|
|
135
|
+
- windows
|
|
136
|
+
- office
|
|
137
|
+
- dad
|
|
138
|
+
You can see a full list in [Chromium source](https://raw.githubusercontent.com/chromium/chromium/main/net/http/transport_security_state_static.json)
|
|
139
|
+
or query your hostname at the [HSTS preload site](https://hstspreload.org/).
|
|
140
|
+
|
|
141
|
+
|
|
55
142
|
## ES module support
|
|
56
143
|
|
|
57
144
|
If a source, spec, or helper file's name ends in `.mjs`, it will be loaded as
|
|
@@ -73,7 +160,7 @@ If you have specs or helper files that use top-level await, set the
|
|
|
73
160
|
are also supported:
|
|
74
161
|
|
|
75
162
|
```javascript
|
|
76
|
-
{
|
|
163
|
+
export default {
|
|
77
164
|
// ...
|
|
78
165
|
"importMap": {
|
|
79
166
|
"moduleRootDir": "node_modules",
|
|
@@ -93,11 +180,11 @@ whether you use the Asset Pipeline or Webpacker.
|
|
|
93
180
|
|
|
94
181
|
### Webpacker
|
|
95
182
|
|
|
96
|
-
1. Run `yarn add --dev jasmine-browser-runner`.
|
|
183
|
+
1. Run `yarn add --dev jasmine-browser-runner jasmine-core`.
|
|
97
184
|
2. Run `npx jasmine-browser-runner init`.
|
|
98
|
-
3. Edit `spec/support/jasmine-browser.
|
|
185
|
+
3. Edit `spec/support/jasmine-browser.mjs` as follows:
|
|
99
186
|
```
|
|
100
|
-
{
|
|
187
|
+
export default {
|
|
101
188
|
"srcDir": ".",
|
|
102
189
|
"srcFiles": [],
|
|
103
190
|
"specDir": "public/packs/js",
|
|
@@ -137,9 +224,9 @@ To run the specs:
|
|
|
137
224
|
the Rails application.
|
|
138
225
|
2. Run `yarn add --dev jasmine-browser-runner`.
|
|
139
226
|
3. Run `npx jasmine-browser-runner init`.
|
|
140
|
-
5. Edit `spec/support/jasmine-browser.
|
|
227
|
+
5. Edit `spec/support/jasmine-browser.mjs` as follows:
|
|
141
228
|
```
|
|
142
|
-
{
|
|
229
|
+
export default {
|
|
143
230
|
"srcDir": "public/assets",
|
|
144
231
|
"srcFiles": [
|
|
145
232
|
"application-*.js"
|
|
@@ -171,9 +258,9 @@ provider like [Saucelabs](https://saucelabs.com/),
|
|
|
171
258
|
To use a remote grid hub, set the `browser` object
|
|
172
259
|
in your config file as follows:
|
|
173
260
|
|
|
174
|
-
```
|
|
175
|
-
// jasmine-browser.
|
|
176
|
-
{
|
|
261
|
+
```javascript
|
|
262
|
+
// jasmine-browser.mjs
|
|
263
|
+
export default {
|
|
177
264
|
// ...
|
|
178
265
|
// BrowserStack
|
|
179
266
|
"browser": {
|
|
@@ -195,9 +282,9 @@ in your config file as follows:
|
|
|
195
282
|
}
|
|
196
283
|
}
|
|
197
284
|
```
|
|
198
|
-
```
|
|
199
|
-
// jasmine-browser.
|
|
200
|
-
{
|
|
285
|
+
```javascript
|
|
286
|
+
// jasmine-browser.mjs
|
|
287
|
+
export default {
|
|
201
288
|
// ...
|
|
202
289
|
// Saucelabs
|
|
203
290
|
"browser": {
|
|
@@ -224,49 +311,33 @@ exception of the `url` will be used as `capabilties` sent to the grid hub url.
|
|
|
224
311
|
if no value is specified for the `url` then a default of
|
|
225
312
|
`http://localhost:4445/wd/hub` is used.
|
|
226
313
|
|
|
227
|
-
|
|
228
|
-
|
|
314
|
+
It's common for remote grids to support only a limited set of ports. Check your
|
|
315
|
+
remote grid's documentation to make sure that the port you're using is
|
|
316
|
+
supported. When using a remote grid, `jasmine-browser-runner` will run on port
|
|
317
|
+
5555 unless you use the `--port` command line option or specify a port in the
|
|
318
|
+
second parameter to`startServer`.
|
|
229
319
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
jasmine-browser-runner can run your Jasmine specs on [Saucelabs](https://saucelabs.com/).
|
|
233
|
-
To use Saucelabs, set `browser.name`, `browser.useSauce`, and `browser.sauce`
|
|
234
|
-
in your config file as follows:
|
|
320
|
+
## Want more control?
|
|
235
321
|
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
"useSauce": true,
|
|
242
|
-
"sauce": {
|
|
243
|
-
"browserVersion": "13",
|
|
244
|
-
"os": "OS X 10.15",
|
|
245
|
-
"tags": ["your tag", "your other tag"],
|
|
246
|
-
"tunnelIdentifier": "tunnel ID",
|
|
247
|
-
"username": "your Saucelabs username",
|
|
248
|
-
"accessKey": "your Saucelabs access key"
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
```
|
|
322
|
+
```javascript
|
|
323
|
+
// ESM
|
|
324
|
+
import path from 'path';
|
|
325
|
+
import jasmineBrowser from 'jasmine-browser-runner';
|
|
326
|
+
import config from './spec/support/jasmine-browser.mjs';
|
|
253
327
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
specific operating system. Setting `browser.sauce.tunnelIdentifier` is strongly
|
|
257
|
-
recommended unless you're sure that your account will never have more than one
|
|
258
|
-
active tunnel.
|
|
328
|
+
config.projectBaseDir = path.resolve('some/path');
|
|
329
|
+
jasmineBrowser.startServer(config, { port: 4321 });
|
|
259
330
|
|
|
260
|
-
## Want more control?
|
|
261
331
|
|
|
262
|
-
|
|
332
|
+
// CommonJS
|
|
263
333
|
const path = require('path');
|
|
264
334
|
const jasmineBrowser = require('jasmine-browser-runner');
|
|
265
335
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
jasmineBrowser.startServer(config, { port: 4321 });
|
|
336
|
+
import('./spec/support/jasmine-browser.mjs')
|
|
337
|
+
.then(function({default: config}) {
|
|
338
|
+
config.projectBaseDir = path.resolve('some/path');
|
|
339
|
+
jasmineBrowser.startServer(config, { port: 4321 });
|
|
340
|
+
});
|
|
270
341
|
```
|
|
271
342
|
|
|
272
343
|
## Supported environments
|
|
@@ -277,9 +348,9 @@ Firefox, and Microsoft Edge) as well as Node.
|
|
|
277
348
|
| Environment | Supported versions |
|
|
278
349
|
|-------------------|------------------------|
|
|
279
350
|
| Node | 18, 20 |
|
|
280
|
-
| Safari | 15-
|
|
351
|
+
| Safari | 15-17 |
|
|
281
352
|
| Chrome | Evergreen |
|
|
282
|
-
| Firefox | Evergreen, 102
|
|
353
|
+
| Firefox | Evergreen, 102, 115 |
|
|
283
354
|
| Edge | Evergreen |
|
|
284
355
|
|
|
285
356
|
For evergreen browsers, each version of jasmine-browser-runner is tested against
|
|
@@ -290,3 +361,6 @@ they aren't actively supported.
|
|
|
290
361
|
|
|
291
362
|
To find out what environments work with a particular Jasmine release, see the [release notes](https://github.com/jasmine/jasmine/tree/main/release_notes).
|
|
292
363
|
|
|
364
|
+
Copyright (c) 2019 Pivotal Labs<br>
|
|
365
|
+
Copyright (c) 2020-2024 The Jasmine developers<br>
|
|
366
|
+
This software is licensed under the MIT License.
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const jasmineCore = require('../lib/jasmineCore');
|
|
5
|
+
const Command = require('../lib/command');
|
|
6
|
+
const 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/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const ConsoleReporter = require('./lib/console_reporter')
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
const ConsoleReporter = require('./lib/console_reporter');
|
|
2
|
+
const webdriverModule = require('./lib/webdriver');
|
|
3
|
+
const Server = require('./lib/server');
|
|
4
|
+
const Runner = require('./lib/runner');
|
|
5
|
+
const ModuleLoader = require('./lib/moduleLoader');
|
|
6
6
|
|
|
7
7
|
async function createReporters(options, deps) {
|
|
8
8
|
const result = [];
|
|
@@ -80,20 +80,18 @@ module.exports = {
|
|
|
80
80
|
const server = new ServerClass(options);
|
|
81
81
|
|
|
82
82
|
const reporters = await createReporters(options, deps);
|
|
83
|
-
const
|
|
83
|
+
const useLegacySauce = options.browser && options.browser.useSauce;
|
|
84
84
|
const useRemote = options.browser && options.browser.useRemoteSeleniumGrid;
|
|
85
|
+
const useSauceCompletionReporting =
|
|
86
|
+
useLegacySauce ||
|
|
87
|
+
(useRemote &&
|
|
88
|
+
options.browser.remoteSeleniumGrid?.url?.includes('saucelabs.com'));
|
|
85
89
|
let portRequest;
|
|
86
90
|
|
|
87
|
-
if (
|
|
88
|
-
if (options.port) {
|
|
89
|
-
throw new Error(
|
|
90
|
-
"Can't specify a port when browser.useSauce or browser.useRemoteSeleniumGrid is true"
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
portRequest = 5555;
|
|
95
|
-
} else if (options.port) {
|
|
91
|
+
if (options.port) {
|
|
96
92
|
portRequest = options.port;
|
|
93
|
+
} else if (useLegacySauce || useRemote) {
|
|
94
|
+
portRequest = 5555;
|
|
97
95
|
} else {
|
|
98
96
|
portRequest = 0;
|
|
99
97
|
}
|
|
@@ -104,7 +102,7 @@ module.exports = {
|
|
|
104
102
|
const webdriver = buildWebdriver(options.browser);
|
|
105
103
|
|
|
106
104
|
try {
|
|
107
|
-
const host =
|
|
105
|
+
const host = `${server.scheme()}://${server.hostname()}:${server.port()}`;
|
|
108
106
|
const runner = new RunnerClass({ webdriver, reporters, host });
|
|
109
107
|
|
|
110
108
|
console.log('Running tests in the browser...');
|
|
@@ -128,7 +126,7 @@ module.exports = {
|
|
|
128
126
|
|
|
129
127
|
return details;
|
|
130
128
|
} finally {
|
|
131
|
-
if (
|
|
129
|
+
if (useSauceCompletionReporting) {
|
|
132
130
|
await webdriver.executeScript(
|
|
133
131
|
`sauce:job-result=${process.exitCode === 0}`
|
|
134
132
|
);
|
package/lib/command.js
CHANGED
|
@@ -11,6 +11,17 @@ const UsageError = require('./usage_error');
|
|
|
11
11
|
const commonOptions = [
|
|
12
12
|
{ name: 'config', type: 'string', description: 'path to the config file' },
|
|
13
13
|
{ name: 'port', type: 'number', description: 'port to run the server on' },
|
|
14
|
+
{
|
|
15
|
+
name: 'tlsCert',
|
|
16
|
+
type: 'string',
|
|
17
|
+
description: 'Path to TLS cert file for https',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: 'tlsKey',
|
|
21
|
+
type: 'string',
|
|
22
|
+
description: 'Path to TLS key file for https',
|
|
23
|
+
},
|
|
24
|
+
{ name: 'hostname', type: 'string', description: 'hostname to listen on' },
|
|
14
25
|
];
|
|
15
26
|
|
|
16
27
|
const subCommands = [
|
|
@@ -80,6 +91,11 @@ const subCommands = [
|
|
|
80
91
|
type: 'string',
|
|
81
92
|
description: 'which local browser to launch',
|
|
82
93
|
},
|
|
94
|
+
{
|
|
95
|
+
name: 'hideDisabled',
|
|
96
|
+
type: 'bool',
|
|
97
|
+
description: 'hide disabled tests',
|
|
98
|
+
},
|
|
83
99
|
]),
|
|
84
100
|
},
|
|
85
101
|
];
|
|
@@ -149,7 +165,7 @@ class Command {
|
|
|
149
165
|
}
|
|
150
166
|
|
|
151
167
|
init(options) {
|
|
152
|
-
const dest = 'spec/support/jasmine-browser.
|
|
168
|
+
const dest = 'spec/support/jasmine-browser.mjs';
|
|
153
169
|
|
|
154
170
|
if (fs.existsSync(dest)) {
|
|
155
171
|
this._logger.log(`${dest} already exists.`);
|
package/lib/config.js
CHANGED
|
@@ -20,10 +20,12 @@ async function loadConfig(baseDir, cliOptions) {
|
|
|
20
20
|
|
|
21
21
|
const candidates = (specifiedConfigFile
|
|
22
22
|
? [specifiedConfigFile]
|
|
23
|
-
: [
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
: [
|
|
24
|
+
'spec/support/jasmine-browser.mjs',
|
|
25
|
+
'spec/support/jasmine-browser.js',
|
|
26
|
+
'spec/support/jasmine-browser.json',
|
|
27
|
+
]
|
|
28
|
+
).map(name => path.resolve(baseDir, name));
|
|
27
29
|
|
|
28
30
|
const fullPath = candidates.find(p => fs.existsSync(p));
|
|
29
31
|
|
|
@@ -57,18 +59,15 @@ function validateConfig(config) {
|
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
function defaultConfig() {
|
|
60
|
-
return fs.readFileSync(require.resolve('./examples/default_config.
|
|
62
|
+
return fs.readFileSync(require.resolve('./examples/default_config.mjs'), {
|
|
61
63
|
encoding: 'utf8',
|
|
62
64
|
});
|
|
63
65
|
}
|
|
64
66
|
|
|
65
67
|
function defaultEsmConfig() {
|
|
66
|
-
return fs.readFileSync(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
encoding: 'utf8',
|
|
70
|
-
}
|
|
71
|
-
);
|
|
68
|
+
return fs.readFileSync(require.resolve('./examples/default_esm_config.mjs'), {
|
|
69
|
+
encoding: 'utf8',
|
|
70
|
+
});
|
|
72
71
|
}
|
|
73
72
|
|
|
74
73
|
function validateImportMap(importMap) {
|
package/lib/console_reporter.js
CHANGED
|
@@ -171,20 +171,20 @@ function ConsoleReporter() {
|
|
|
171
171
|
this.specDone = function(result) {
|
|
172
172
|
specCount++;
|
|
173
173
|
|
|
174
|
-
if (result.status
|
|
174
|
+
if (result.status === 'pending') {
|
|
175
175
|
pendingSpecs.push(result);
|
|
176
176
|
executableSpecCount++;
|
|
177
177
|
print(colored('yellow', '*'));
|
|
178
178
|
return;
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
-
if (result.status
|
|
181
|
+
if (result.status === 'passed') {
|
|
182
182
|
executableSpecCount++;
|
|
183
183
|
print(colored('green', '.'));
|
|
184
184
|
return;
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
-
if (result.status
|
|
187
|
+
if (result.status === 'failed') {
|
|
188
188
|
failureCount++;
|
|
189
189
|
failedSpecs.push(result);
|
|
190
190
|
executableSpecCount++;
|
|
@@ -210,7 +210,7 @@ function ConsoleReporter() {
|
|
|
210
210
|
}
|
|
211
211
|
|
|
212
212
|
function plural(str, count) {
|
|
213
|
-
return count
|
|
213
|
+
return count === 1 ? str : str + 's';
|
|
214
214
|
}
|
|
215
215
|
|
|
216
216
|
function repeat(thing, times) {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
srcDir: "src",
|
|
3
|
+
srcFiles: [
|
|
4
|
+
"**/*.js"
|
|
5
|
+
],
|
|
6
|
+
specDir: "spec",
|
|
7
|
+
specFiles: [
|
|
8
|
+
"**/*[sS]pec.js"
|
|
9
|
+
],
|
|
10
|
+
helpers: [
|
|
11
|
+
"helpers/**/*.js"
|
|
12
|
+
],
|
|
13
|
+
env: {
|
|
14
|
+
stopSpecOnExpectationFailure: false,
|
|
15
|
+
stopOnSpecFailure: false,
|
|
16
|
+
random: true
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
// For security, listen only to localhost. You can also specify a different
|
|
20
|
+
// hostname or IP address, or remove the property or set it to "*" to listen
|
|
21
|
+
// to all network interfaces.
|
|
22
|
+
listenAddress: "localhost",
|
|
23
|
+
|
|
24
|
+
// The hostname that the browser will use to connect to the server.
|
|
25
|
+
hostname: "localhost",
|
|
26
|
+
|
|
27
|
+
browser: {
|
|
28
|
+
name: "firefox"
|
|
29
|
+
}
|
|
30
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
srcDir: "src",
|
|
3
|
+
// srcFiles should usually be left empty when using ES modules, because you'll
|
|
4
|
+
// explicitly import sources from your specs.
|
|
5
|
+
srcFiles: [],
|
|
6
|
+
specDir: ".",
|
|
7
|
+
specFiles: [
|
|
8
|
+
"spec/**/*[sS]pec.?(m)js"
|
|
9
|
+
],
|
|
10
|
+
helpers: [
|
|
11
|
+
"spec/helpers/**/*.?(m)js"
|
|
12
|
+
],
|
|
13
|
+
esmFilenameExtension: ".mjs",
|
|
14
|
+
// Allows the use of top-level await in src/spec/helper files. This is off by
|
|
15
|
+
// default because it makes files load more slowly.
|
|
16
|
+
enableTopLevelAwait: false,
|
|
17
|
+
env: {
|
|
18
|
+
stopSpecOnExpectationFailure: false,
|
|
19
|
+
stopOnSpecFailure: false,
|
|
20
|
+
random: true
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
// For security, listen only to localhost. You can also specify a different
|
|
24
|
+
// hostname or IP address, or remove the property or set it to "*" to listen
|
|
25
|
+
// to all network interfaces.
|
|
26
|
+
listenAddress: "localhost",
|
|
27
|
+
|
|
28
|
+
// The hostname that the browser will use to connect to the server.
|
|
29
|
+
hostname: "localhost",
|
|
30
|
+
|
|
31
|
+
browser: {
|
|
32
|
+
name: "firefox"
|
|
33
|
+
}
|
|
34
|
+
};
|
package/lib/runner.js
CHANGED
|
@@ -76,6 +76,7 @@ function urlParams(runOptions) {
|
|
|
76
76
|
random: runOptions.random,
|
|
77
77
|
seed: runOptions.seed,
|
|
78
78
|
spec: runOptions.filter,
|
|
79
|
+
hideDisabled: runOptions.hideDisabled,
|
|
79
80
|
})
|
|
80
81
|
)
|
|
81
82
|
);
|
|
@@ -100,9 +101,34 @@ class Runner {
|
|
|
100
101
|
|
|
101
102
|
async run(runOptions) {
|
|
102
103
|
runOptions = runOptions || {};
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
await this._options.webdriver.get(
|
|
107
|
+
this._options.host + urlParams(runOptions)
|
|
108
|
+
);
|
|
109
|
+
} catch (error) {
|
|
110
|
+
// Looking for Chrome's "WebDriverError: ... net::ERR_SSL_PROTOCOL_ERROR"
|
|
111
|
+
// or Firefox's "WebDriverError: ... about:neterror?e=nssFailure2"
|
|
112
|
+
if (error.name === 'WebDriverError') {
|
|
113
|
+
if (
|
|
114
|
+
error.message.includes('ERR_SSL_PROTOCOL_ERROR') ||
|
|
115
|
+
error.message.includes('about:neterror?e=nssFailure2')
|
|
116
|
+
) {
|
|
117
|
+
// Show a friendlier error.
|
|
118
|
+
throw new Error(
|
|
119
|
+
'The browser tried to speak HTTPS to an HTTP server. This ' +
|
|
120
|
+
"probably means that the configured hostname is on the browser's " +
|
|
121
|
+
'HSTS preload list. Try a different hostname or configure a TLS ' +
|
|
122
|
+
'certificate. See ' +
|
|
123
|
+
'<https://github.com/jasmine/jasmine-browser-runner?tab=readme-ov-file#hostname-support> ' +
|
|
124
|
+
'for more information.'
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Rethrow the original error.
|
|
130
|
+
throw error;
|
|
131
|
+
}
|
|
106
132
|
|
|
107
133
|
return await runTillEnd(this._options.webdriver, this._options.reporters);
|
|
108
134
|
}
|
package/lib/server.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
const defaultExpress = require('express')
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
const defaultExpress = require('express');
|
|
2
|
+
const ejs = require('ejs');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const glob = require('glob');
|
|
5
|
+
const http = require('http');
|
|
6
|
+
const https = require('https');
|
|
7
|
+
const path = require('path');
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* @class Server
|
|
@@ -13,8 +15,9 @@ class Server {
|
|
|
13
15
|
* @constructor
|
|
14
16
|
* @param {ServerCtorOptions} options
|
|
15
17
|
*/
|
|
16
|
-
constructor(options) {
|
|
18
|
+
constructor(options, deps) {
|
|
17
19
|
this.options = { ...options };
|
|
20
|
+
this._deps = deps || { http, https };
|
|
18
21
|
this.express = this.options.express || defaultExpress;
|
|
19
22
|
this.useHtmlReporter =
|
|
20
23
|
options.useHtmlReporter === undefined ? true : options.useHtmlReporter;
|
|
@@ -57,11 +60,12 @@ class Server {
|
|
|
57
60
|
}
|
|
58
61
|
|
|
59
62
|
getUrls(baseDir, globs, urlRoot) {
|
|
60
|
-
return findFiles(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
return findFiles(
|
|
64
|
+
path.resolve(this.projectBaseDir, baseDir),
|
|
65
|
+
globs || []
|
|
66
|
+
).map(function(p) {
|
|
67
|
+
return isUrl(p) ? p : unWindows(path.join(urlRoot, p));
|
|
68
|
+
});
|
|
65
69
|
}
|
|
66
70
|
|
|
67
71
|
getSupportFiles() {
|
|
@@ -148,11 +152,15 @@ class Server {
|
|
|
148
152
|
);
|
|
149
153
|
app.use(
|
|
150
154
|
'/__spec__',
|
|
151
|
-
this.express.static(
|
|
155
|
+
this.express.static(
|
|
156
|
+
path.resolve(this.projectBaseDir, this.options.specDir)
|
|
157
|
+
)
|
|
152
158
|
);
|
|
153
159
|
app.use(
|
|
154
160
|
'/__src__',
|
|
155
|
-
this.express.static(
|
|
161
|
+
this.express.static(
|
|
162
|
+
path.resolve(this.projectBaseDir, this.options.srcDir)
|
|
163
|
+
)
|
|
156
164
|
);
|
|
157
165
|
|
|
158
166
|
if (this.options.middleware) {
|
|
@@ -165,7 +173,10 @@ class Server {
|
|
|
165
173
|
|
|
166
174
|
if (this.options.importMap) {
|
|
167
175
|
const dir = this.options.importMap.moduleRootDir
|
|
168
|
-
? path.
|
|
176
|
+
? path.resolve(
|
|
177
|
+
this.projectBaseDir,
|
|
178
|
+
this.options.importMap.moduleRootDir
|
|
179
|
+
)
|
|
169
180
|
: this.projectBaseDir;
|
|
170
181
|
app.use('/__moduleRoot__', this.express.static(dir));
|
|
171
182
|
}
|
|
@@ -210,12 +221,36 @@ class Server {
|
|
|
210
221
|
});
|
|
211
222
|
|
|
212
223
|
const port = findPort(serverOptions.port, this.options.port);
|
|
224
|
+
const tlsCert = serverOptions.tlsCert || this.options.tlsCert;
|
|
225
|
+
const tlsKey = serverOptions.tlsKey || this.options.tlsKey;
|
|
226
|
+
const hostname = serverOptions.hostname || this.options.hostname;
|
|
227
|
+
// The last two fallbacks here are necessary for backwards compatibility.
|
|
228
|
+
let listenAddress =
|
|
229
|
+
serverOptions.listenAddress ||
|
|
230
|
+
this.options.listenAddress ||
|
|
231
|
+
hostname ||
|
|
232
|
+
'';
|
|
233
|
+
|
|
234
|
+
if (listenAddress === '*') {
|
|
235
|
+
listenAddress = '';
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const listenOptions = {
|
|
239
|
+
port,
|
|
240
|
+
host: listenAddress,
|
|
241
|
+
};
|
|
242
|
+
this._httpHostname = hostname || 'localhost';
|
|
243
|
+
|
|
213
244
|
return new Promise(resolve => {
|
|
214
|
-
|
|
245
|
+
const callback = () => {
|
|
215
246
|
const runningPort = this._httpServer.address().port;
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
247
|
+
const url =
|
|
248
|
+
this._httpServerScheme +
|
|
249
|
+
'://' +
|
|
250
|
+
this._httpHostname +
|
|
251
|
+
':' +
|
|
252
|
+
runningPort;
|
|
253
|
+
console.log(`Jasmine server is running here: ${url}`);
|
|
219
254
|
console.log(
|
|
220
255
|
`Jasmine tests are here: ${path.resolve(
|
|
221
256
|
self.options.specDir
|
|
@@ -225,7 +260,23 @@ class Server {
|
|
|
225
260
|
`Source files are here: ${path.resolve(self.options.srcDir)}`
|
|
226
261
|
);
|
|
227
262
|
resolve();
|
|
228
|
-
}
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
if (tlsKey && tlsCert) {
|
|
266
|
+
const httpsOptions = {
|
|
267
|
+
key: fs.readFileSync(tlsKey),
|
|
268
|
+
cert: fs.readFileSync(tlsCert),
|
|
269
|
+
};
|
|
270
|
+
this._httpServer = this._deps.https
|
|
271
|
+
.createServer(httpsOptions, app)
|
|
272
|
+
.listen(listenOptions, callback);
|
|
273
|
+
this._httpServerScheme = 'https';
|
|
274
|
+
} else {
|
|
275
|
+
this._httpServer = this._deps.http
|
|
276
|
+
.createServer(app)
|
|
277
|
+
.listen(listenOptions, callback);
|
|
278
|
+
this._httpServerScheme = 'http';
|
|
279
|
+
}
|
|
229
280
|
});
|
|
230
281
|
}
|
|
231
282
|
|
|
@@ -257,6 +308,28 @@ class Server {
|
|
|
257
308
|
|
|
258
309
|
return this._httpServer.address().port;
|
|
259
310
|
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Gets the URL scheme that the server is listening on. The server must be
|
|
314
|
+
* started before this method is called.
|
|
315
|
+
* @function
|
|
316
|
+
* @name Server#scheme
|
|
317
|
+
* @return {string} The URL scheme ('http' or 'https')
|
|
318
|
+
*/
|
|
319
|
+
scheme() {
|
|
320
|
+
return this._httpServerScheme;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Gets the hostname that the server is listening on. The server must be
|
|
325
|
+
* started before this method is called.
|
|
326
|
+
* @function
|
|
327
|
+
* @name Server#hostname
|
|
328
|
+
* @return {string} The hostname (localhost if not specified)
|
|
329
|
+
*/
|
|
330
|
+
hostname() {
|
|
331
|
+
return this._httpHostname;
|
|
332
|
+
}
|
|
260
333
|
}
|
|
261
334
|
|
|
262
335
|
function findPort(serverPort, optionsPort) {
|
package/lib/types.js
CHANGED
|
@@ -39,6 +39,37 @@
|
|
|
39
39
|
* @name ServerCtorOptions#port
|
|
40
40
|
* @type number | undefined
|
|
41
41
|
*/
|
|
42
|
+
/**
|
|
43
|
+
* The path to a TLS key. Activates HTTPS mode. If specified, tlsCert must also
|
|
44
|
+
* be specified.
|
|
45
|
+
* @name ServerCtorOptions#tlsKey
|
|
46
|
+
* @type string
|
|
47
|
+
*/
|
|
48
|
+
/**
|
|
49
|
+
* The path to a TLS cert. Activates HTTPS mode. If specified, tlsKey must also
|
|
50
|
+
* be specified.
|
|
51
|
+
* @name ServerCtorOptions#tlsCert
|
|
52
|
+
* @type string
|
|
53
|
+
*/
|
|
54
|
+
/**
|
|
55
|
+
* The hostname or IP address of the network interface to listen on. For
|
|
56
|
+
* security, this should be set to localhost or an equivalent unless you need
|
|
57
|
+
* the server to be accessible over other network interfaces. Set to "*" to
|
|
58
|
+
* listen on all interfaces, which may be required by some remote Selenium
|
|
59
|
+
* grids.
|
|
60
|
+
* @name ServerCtorOptions#listenAddress
|
|
61
|
+
* @default The value of {@link ServerCtorOptions#hostname} or {@link ServerStartOptions#hostname} if configured, otherwise "*"
|
|
62
|
+
* @type string | undefined
|
|
63
|
+
*/
|
|
64
|
+
/**
|
|
65
|
+
* The hostname to use in the URL given to browsers. For backward compatibility,
|
|
66
|
+
* setting this property without also setting {@link ServerCtorOptions#listenAddress}
|
|
67
|
+
* or {@link ServerStartOptions#listenAddress} has the same effect as setting
|
|
68
|
+
* the listen address to the hostname.
|
|
69
|
+
* @name ServerCtorOptions#hostname
|
|
70
|
+
* @default "localhost"
|
|
71
|
+
* @type string | undefined
|
|
72
|
+
*/
|
|
42
73
|
/**
|
|
43
74
|
* The root directory of the project.
|
|
44
75
|
* @name ServerCtorOptions#projectBaseDir
|
|
@@ -271,6 +302,26 @@
|
|
|
271
302
|
* @name ServerStartOptions#port
|
|
272
303
|
* @type number | undefined
|
|
273
304
|
*/
|
|
305
|
+
/**
|
|
306
|
+
* The path to a TLS key. Activates HTTPS mode. If specified, tlsCert must also
|
|
307
|
+
* be specified.
|
|
308
|
+
* @name ServerStartOptions#tlsKey
|
|
309
|
+
* @type string
|
|
310
|
+
*/
|
|
311
|
+
/**
|
|
312
|
+
* The path to a TLS cert. Activates HTTPS mode. If specified, tlsKey must also
|
|
313
|
+
* be specified.
|
|
314
|
+
* @name ServerStartOptions#tlsCert
|
|
315
|
+
* @type string
|
|
316
|
+
*/
|
|
317
|
+
/**
|
|
318
|
+
* @see ServerCtorOptions#hostname
|
|
319
|
+
* @name ServerStartOptions#hostname
|
|
320
|
+
*/
|
|
321
|
+
/**
|
|
322
|
+
* @see ServerCtorOptions#listenAddress
|
|
323
|
+
* @name ServerStartOptions#listenAddress
|
|
324
|
+
*/
|
|
274
325
|
|
|
275
326
|
/**
|
|
276
327
|
* Describes an import map.
|
package/lib/webdriver.js
CHANGED
|
@@ -60,6 +60,12 @@ function buildWebdriver(browserInfo, webdriverBuilder) {
|
|
|
60
60
|
}
|
|
61
61
|
} else if (useSauce) {
|
|
62
62
|
// handle legacy `sauce` object
|
|
63
|
+
console.warn(
|
|
64
|
+
'Deprecation warning: Direct support for Saucelabs is deprecated and ' +
|
|
65
|
+
'will be removed in a future release. Please use Saucelabs via the ' +
|
|
66
|
+
'remote Selenium grid feature. See the jasmine-browser-runner README ' +
|
|
67
|
+
'for details.'
|
|
68
|
+
);
|
|
63
69
|
const sauce = browserInfo.sauce;
|
|
64
70
|
if (sauce) {
|
|
65
71
|
url = `http://${sauce.username}:${sauce.accessKey}@ondemand.saucelabs.com/wd/hub`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jasmine-browser-runner",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.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",
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
"run.html.ejs",
|
|
14
14
|
"bin/*.js",
|
|
15
15
|
"lib/**/*.js",
|
|
16
|
-
"lib/examples/default_config.
|
|
17
|
-
"lib/examples/default_esm_config.
|
|
16
|
+
"lib/examples/default_config.mjs",
|
|
17
|
+
"lib/examples/default_esm_config.mjs"
|
|
18
18
|
],
|
|
19
19
|
"scripts": {
|
|
20
20
|
"posttest": "eslint bin/* lib spec index.js --ignore-path=.styleIgnore && prettier --check --ignore-path=.styleIgnore \"lib/**/*.js\" \"spec/**/*.js\" index.js",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"homepage": "https://github.com/jasmine/jasmine-browser-runner#readme",
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"ejs": "^3.1.6",
|
|
41
|
-
"express": "^4.
|
|
41
|
+
"express": "^4.19.2",
|
|
42
42
|
"glob": "^10.0.0",
|
|
43
43
|
"selenium-webdriver": "^4.12.0"
|
|
44
44
|
},
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"ejs-lint": "^2.0.0",
|
|
50
|
-
"eslint": "^8.
|
|
50
|
+
"eslint": "^8.50.0",
|
|
51
51
|
"eslint-plugin-jasmine": "^4.1.3",
|
|
52
52
|
"jasmine": "^5.0.0",
|
|
53
53
|
"jasmine-core": "^5.0.0",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"expectAsync": "readonly"
|
|
73
73
|
},
|
|
74
74
|
"parserOptions": {
|
|
75
|
-
"ecmaVersion":
|
|
75
|
+
"ecmaVersion": 2022
|
|
76
76
|
},
|
|
77
77
|
"plugins": [
|
|
78
78
|
"jasmine"
|
|
@@ -102,6 +102,7 @@
|
|
|
102
102
|
"functions": "never"
|
|
103
103
|
}
|
|
104
104
|
],
|
|
105
|
+
"eqeqeq": "error",
|
|
105
106
|
"func-call-spacing": [
|
|
106
107
|
"error",
|
|
107
108
|
"never"
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"srcDir": "src",
|
|
3
|
-
"srcFiles": [
|
|
4
|
-
"**/*.js"
|
|
5
|
-
],
|
|
6
|
-
"specDir": "spec",
|
|
7
|
-
"specFiles": [
|
|
8
|
-
"**/*[sS]pec.js"
|
|
9
|
-
],
|
|
10
|
-
"helpers": [
|
|
11
|
-
"helpers/**/*.js"
|
|
12
|
-
],
|
|
13
|
-
"env": {
|
|
14
|
-
"stopSpecOnExpectationFailure": false,
|
|
15
|
-
"stopOnSpecFailure": false,
|
|
16
|
-
"random": true
|
|
17
|
-
},
|
|
18
|
-
"browser": {
|
|
19
|
-
"name": "firefox"
|
|
20
|
-
}
|
|
21
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"srcDir": "src",
|
|
3
|
-
"srcFiles": [],
|
|
4
|
-
"specDir": ".",
|
|
5
|
-
"specFiles": [
|
|
6
|
-
"spec/**/*[sS]pec.?(m)js"
|
|
7
|
-
],
|
|
8
|
-
"helpers": [
|
|
9
|
-
"spec/helpers/**/*.?(m)js"
|
|
10
|
-
],
|
|
11
|
-
"esmFilenameExtension": ".mjs",
|
|
12
|
-
"enableTopLevelAwait": false,
|
|
13
|
-
"env": {
|
|
14
|
-
"stopSpecOnExpectationFailure": false,
|
|
15
|
-
"stopOnSpecFailure": false,
|
|
16
|
-
"random": true
|
|
17
|
-
},
|
|
18
|
-
"browser": {
|
|
19
|
-
"name": "firefox"
|
|
20
|
-
}
|
|
21
|
-
}
|