jasmine-browser-runner 2.0.0-beta.1 → 2.1.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 +80 -27
- package/index.js +5 -2
- package/lib/examples/default_esm_config.json +2 -0
- package/lib/server.js +11 -3
- package/lib/support/loaders.js +5 -2
- package/lib/types.js +43 -0
- package/lib/webdriver.js +39 -17
- package/package.json +4 -4
- package/run.html.ejs +2 -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
|
|
@@ -70,7 +57,9 @@ Its value can be `"firefox"`, `"headlessFirefox"`, `"safari"`,
|
|
|
70
57
|
If a source, spec, or helper file's name ends in `.mjs`, it will be loaded as
|
|
71
58
|
an ES module rather than a regular script. Note that ES modules can only be
|
|
72
59
|
loaded from other ES modules. So if your source files are ES modules, your
|
|
73
|
-
spec files need to be ES modules too.
|
|
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"`.
|
|
74
63
|
|
|
75
64
|
To allow spec files to import source files via relative paths, set the `specDir`
|
|
76
65
|
config field to something that's high enough up to include both spec and source
|
|
@@ -174,7 +163,71 @@ To run the specs:
|
|
|
174
163
|
2. Run `npx jasmine-browser-runner`.
|
|
175
164
|
3. Visit <http://localhost:8888>.
|
|
176
165
|
|
|
177
|
-
## Saucelabs
|
|
166
|
+
## Remote Grid support (Saucelabs, BrowserStack, etc.)
|
|
167
|
+
|
|
168
|
+
jasmine-browser-runner can run your Jasmine specs on a remote grid
|
|
169
|
+
provider like [Saucelabs](https://saucelabs.com/),
|
|
170
|
+
[BrowserStack](https://browserstack.com) or your own Selenium Grid.
|
|
171
|
+
To use a remote grid hub, set the `browser` object
|
|
172
|
+
in your config file as follows:
|
|
173
|
+
|
|
174
|
+
```json
|
|
175
|
+
// jasmine-browser.json
|
|
176
|
+
{
|
|
177
|
+
// ...
|
|
178
|
+
// BrowserStack
|
|
179
|
+
"browser": {
|
|
180
|
+
"name": "safari",
|
|
181
|
+
"useRemoteSeleniumGrid": true,
|
|
182
|
+
"remoteSeleniumGrid": {
|
|
183
|
+
"url": "https://hub-cloud.browserstack.com/wd/hub",
|
|
184
|
+
"bstack:options": {
|
|
185
|
+
"browserVersion": "16",
|
|
186
|
+
"os": "OS X",
|
|
187
|
+
"osVersion": "Monterey",
|
|
188
|
+
"local": "true",
|
|
189
|
+
"localIdentifier": "tunnel ID",
|
|
190
|
+
"debug": "true",
|
|
191
|
+
"userName": "your BrowserStack username",
|
|
192
|
+
"accessKey": "your BrowserStack access key"
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
```json
|
|
199
|
+
// jasmine-browser.json
|
|
200
|
+
{
|
|
201
|
+
// ...
|
|
202
|
+
// Saucelabs
|
|
203
|
+
"browser": {
|
|
204
|
+
"name": "safari",
|
|
205
|
+
"useRemoteSeleniumGrid": true,
|
|
206
|
+
"remoteSeleniumGrid": {
|
|
207
|
+
"url": "https://ondemand.saucelabs.com/wd/hub",
|
|
208
|
+
"platformName": "macOS 12",
|
|
209
|
+
"sauce:options": {
|
|
210
|
+
"tunnel-identifier": "tunnel ID",
|
|
211
|
+
"userName": "your Saucelabs username",
|
|
212
|
+
"accessKey": "your Saucelabs access key"
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
When using a remote grid provider, all properties of the `browser` object are
|
|
220
|
+
optional except for `name` which will be passed as the `browserName` capability,
|
|
221
|
+
and `useRemoteSeleniumGrid` which must be set to a value of `true`. if a
|
|
222
|
+
`remoteSeleniumGrid` object is included, any values it contains, with the
|
|
223
|
+
exception of the `url` will be used as `capabilties` sent to the grid hub url.
|
|
224
|
+
if no value is specified for the `url` then a default of
|
|
225
|
+
`http://localhost:4445/wd/hub` is used.
|
|
226
|
+
|
|
227
|
+
## Saucelabs support (legacy)
|
|
228
|
+
> NOTE: the below configuration format only supports using Saucelabs in the US. if connecting from the EU, please use the above specifying a `url` value specific to your region (e.g. `https://ondemand.eu-central-1.saucelabs.com:443/wd/hub`) to avoid a connection error of `WebDriverError: This user is unauthorized to the region. Please try another region, or contact customer support.`
|
|
229
|
+
|
|
230
|
+
> WARNING: the below configuration format may be removed in favour of using the above in the future so it is advised that you migrate to the above
|
|
178
231
|
|
|
179
232
|
jasmine-browser-runner can run your Jasmine specs on [Saucelabs](https://saucelabs.com/).
|
|
180
233
|
To use Saucelabs, set `browser.name`, `browser.useSauce`, and `browser.sauce`
|
|
@@ -223,7 +276,7 @@ Firefox, and Microsoft Edge) as well as Node.
|
|
|
223
276
|
|
|
224
277
|
| Environment | Supported versions |
|
|
225
278
|
|-------------------|------------------------|
|
|
226
|
-
| Node |
|
|
279
|
+
| Node | 18, 20 |
|
|
227
280
|
| Safari | 15-16 |
|
|
228
281
|
| Chrome | Evergreen |
|
|
229
282
|
| Firefox | Evergreen, 102 |
|
package/index.js
CHANGED
|
@@ -81,11 +81,14 @@ module.exports = {
|
|
|
81
81
|
|
|
82
82
|
const reporters = await createReporters(options, deps);
|
|
83
83
|
const useSauce = options.browser && options.browser.useSauce;
|
|
84
|
+
const useRemote = options.browser && options.browser.useRemoteSeleniumGrid;
|
|
84
85
|
let portRequest;
|
|
85
86
|
|
|
86
|
-
if (useSauce) {
|
|
87
|
+
if (useSauce || useRemote) {
|
|
87
88
|
if (options.port) {
|
|
88
|
-
throw new Error(
|
|
89
|
+
throw new Error(
|
|
90
|
+
"Can't specify a port when browser.useSauce or browser.useRemoteSeleniumGrid is true"
|
|
91
|
+
);
|
|
89
92
|
}
|
|
90
93
|
|
|
91
94
|
portRequest = 5555;
|
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() {
|
|
@@ -75,9 +82,9 @@ class Server {
|
|
|
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,
|
|
@@ -163,6 +170,7 @@ class Server {
|
|
|
163
170
|
cssFiles: self.allCss(),
|
|
164
171
|
jasmineJsFiles: self.jasmineJs(),
|
|
165
172
|
userJsFiles: self.userJs(),
|
|
173
|
+
esmFilenameExtension: self.options.esmFilenameExtension,
|
|
166
174
|
importMap: self.importMap(),
|
|
167
175
|
enableTopLevelAwait: self.options.enableTopLevelAwait || false,
|
|
168
176
|
})
|
package/lib/support/loaders.js
CHANGED
|
@@ -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
|
|
@@ -137,6 +143,12 @@
|
|
|
137
143
|
* @name BrowserInfo#useSauce
|
|
138
144
|
* @type boolean | undefined
|
|
139
145
|
*/
|
|
146
|
+
/**
|
|
147
|
+
* Whether to run the specs on a remote Selenium grid.
|
|
148
|
+
* Defaults to false.
|
|
149
|
+
* @name BrowserInfo#useRemoteSeleniumGrid
|
|
150
|
+
* @type boolean | undefined
|
|
151
|
+
*/
|
|
140
152
|
/**
|
|
141
153
|
* The browser name. Valid values include "firefox", "headlessFirefox",
|
|
142
154
|
* "safari", "MicrosoftEdge", "chrome", and "headlessChrome".
|
|
@@ -148,6 +160,11 @@
|
|
|
148
160
|
* @name BrowserInfo#sauce
|
|
149
161
|
* @type SauceConfig | undefined
|
|
150
162
|
*/
|
|
163
|
+
/**
|
|
164
|
+
* Configuration for running specs on a remote Selenium grid
|
|
165
|
+
* @name BrowserInfo#remoteSeleniumGrid
|
|
166
|
+
* @type RemoteSeleniumGridConfig | undefined
|
|
167
|
+
*/
|
|
151
168
|
|
|
152
169
|
/**
|
|
153
170
|
* Configuration for running specs on {@link https://saucelabs.com/|Saucelabs}
|
|
@@ -195,6 +212,32 @@
|
|
|
195
212
|
* @type Array.<string>
|
|
196
213
|
*/
|
|
197
214
|
|
|
215
|
+
/**
|
|
216
|
+
* Configuration for running specs on a remote Selenium grid
|
|
217
|
+
* Any additional properties, such as "sauce:options" or "bstack:options", will
|
|
218
|
+
* be included in the capabilities object passed through to Selenium Webdriver.
|
|
219
|
+
* @interface RemoteSeleniumGridConfig
|
|
220
|
+
* @example
|
|
221
|
+
* {
|
|
222
|
+
* "url": "https://hub-cloud.browserstack.com/wd/hub",
|
|
223
|
+
* "bstack:options": {
|
|
224
|
+
* "browserVersion": "16",
|
|
225
|
+
* "os": "OS X",
|
|
226
|
+
* "osVersion": "Monterey",
|
|
227
|
+
* "local": "true",
|
|
228
|
+
* "localIdentifier": "tunnel ID",
|
|
229
|
+
* "debug": "true",
|
|
230
|
+
* "userName": "your BrowserStack username",
|
|
231
|
+
* "accessKey": "your BrowserStack access key"
|
|
232
|
+
* }
|
|
233
|
+
* }
|
|
234
|
+
*/
|
|
235
|
+
/**
|
|
236
|
+
* URL of the remote Selenium grid
|
|
237
|
+
* @name RemoteSeleniumGridConfig#url
|
|
238
|
+
* @type string
|
|
239
|
+
*/
|
|
240
|
+
|
|
198
241
|
/**
|
|
199
242
|
* Options passed to {@link Server#start}
|
|
200
243
|
* @interface
|
package/lib/webdriver.js
CHANGED
|
@@ -4,6 +4,8 @@ function buildWebdriver(browserInfo, webdriverBuilder) {
|
|
|
4
4
|
|
|
5
5
|
webdriverBuilder = webdriverBuilder || new webdriver.Builder();
|
|
6
6
|
const useSauce = typeof browserInfo === 'object' && browserInfo.useSauce;
|
|
7
|
+
const useRemote =
|
|
8
|
+
typeof browserInfo === 'object' && browserInfo.useRemoteSeleniumGrid;
|
|
7
9
|
let browserName;
|
|
8
10
|
|
|
9
11
|
if (typeof browserInfo === 'string') {
|
|
@@ -14,7 +16,7 @@ function buildWebdriver(browserInfo, webdriverBuilder) {
|
|
|
14
16
|
|
|
15
17
|
browserName = browserName || 'firefox';
|
|
16
18
|
|
|
17
|
-
if (!useSauce) {
|
|
19
|
+
if (!(useRemote || useSauce)) {
|
|
18
20
|
if (browserName === 'headlessChrome') {
|
|
19
21
|
const caps = webdriver.Capabilities.chrome();
|
|
20
22
|
caps.set('goog:chromeOptions', {
|
|
@@ -44,26 +46,46 @@ function buildWebdriver(browserInfo, webdriverBuilder) {
|
|
|
44
46
|
}
|
|
45
47
|
}
|
|
46
48
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
let url;
|
|
50
|
+
let capabilities;
|
|
51
|
+
if (useRemote) {
|
|
52
|
+
const remote = browserInfo.remoteSeleniumGrid;
|
|
53
|
+
if (remote) {
|
|
54
|
+
url = remote.url;
|
|
55
|
+
capabilities = {
|
|
56
|
+
...remote,
|
|
57
|
+
[Capability.BROWSER_NAME]: browserName,
|
|
58
|
+
};
|
|
59
|
+
delete capabilities.url;
|
|
60
|
+
}
|
|
61
|
+
} else if (useSauce) {
|
|
62
|
+
// handle legacy `sauce` object
|
|
63
|
+
const sauce = browserInfo.sauce;
|
|
64
|
+
if (sauce) {
|
|
65
|
+
url = `http://${sauce.username}:${sauce.accessKey}@ondemand.saucelabs.com/wd/hub`;
|
|
66
|
+
capabilities = {
|
|
67
|
+
[Capability.BROWSER_NAME]: browserName,
|
|
68
|
+
build: sauce.build,
|
|
69
|
+
tags: sauce.tags,
|
|
70
|
+
};
|
|
53
71
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
72
|
+
capabilities[Capability.PLATFORM_NAME] = sauce.os;
|
|
73
|
+
capabilities[Capability.BROWSER_VERSION] = sauce.browserVersion;
|
|
74
|
+
capabilities['sauce:options'] = {
|
|
75
|
+
'tunnel-identifier': sauce.tunnelIdentifier,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (!capabilities) {
|
|
81
|
+
capabilities = {
|
|
82
|
+
[Capability.BROWSER_NAME]: browserName,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
59
85
|
|
|
60
86
|
return webdriverBuilder
|
|
61
87
|
.withCapabilities(capabilities)
|
|
62
|
-
.usingServer(
|
|
63
|
-
browserInfo.useSauce
|
|
64
|
-
? `http://${sauce.username}:${sauce.accessKey}@ondemand.saucelabs.com/wd/hub`
|
|
65
|
-
: 'http://@localhost:4445/wd/hub'
|
|
66
|
-
)
|
|
88
|
+
.usingServer(url || 'http://localhost:4445/wd/hub')
|
|
67
89
|
.build();
|
|
68
90
|
}
|
|
69
91
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jasmine-browser-runner",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.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"
|
package/run.html.ejs
CHANGED
|
@@ -24,11 +24,11 @@
|
|
|
24
24
|
<% userJsFiles.forEach(function(jsFile) { %>
|
|
25
25
|
'<%= jsFile %>',
|
|
26
26
|
<% }) %>
|
|
27
|
-
]);
|
|
27
|
+
], '<%=esmFilenameExtension%>');
|
|
28
28
|
</script>
|
|
29
29
|
<% } else { %>
|
|
30
30
|
<% userJsFiles.forEach(function(jsFile) { %>
|
|
31
|
-
<% if (jsFile.endsWith(
|
|
31
|
+
<% if (jsFile.endsWith(esmFilenameExtension)) { %>
|
|
32
32
|
<script type="module">_jasmine_loadEsModule('<%= jsFile %>')</script>
|
|
33
33
|
<% } else { %>
|
|
34
34
|
<script src="<%= jsFile %>" type="text/javascript"></script>
|