Skip to content

Commit 52b767d

Browse files
committedSep 26, 2019
initial commit
0 parents  commit 52b767d

11 files changed

+4160
-0
lines changed
 

‎.editorconfig

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# https://editorconfig.org
2+
3+
root = true
4+
5+
[*]
6+
charset = utf-8
7+
indent_style = space
8+
indent_size = 2
9+
end_of_line = lf
10+
insert_final_newline = true
11+
trim_trailing_whitespace = true
12+
13+
[*.md]
14+
insert_final_newline = false
15+
trim_trailing_whitespace = false

‎.eslintrc

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"parser": "@typescript-eslint/parser",
3+
"env": {
4+
"node": true
5+
},
6+
"extends": [
7+
"plugin:@typescript-eslint/recommended",
8+
"prettier/@typescript-eslint",
9+
"plugin:prettier/recommended"
10+
],
11+
"parserOptions": {
12+
"ecmaVersion": 2018,
13+
"sourceType": "module",
14+
"tsconfigRootDir": ".",
15+
"project": "./tsconfig.json"
16+
},
17+
"rules": {
18+
"@typescript-eslint/no-unused-vars": 2,
19+
"@typescript-eslint/explicit-function-return-type": 2,
20+
"@typescript-eslint/no-explicit-any": 1
21+
}
22+
}

‎.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lib/
2+
node_modules/

‎.prettierrc

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"trailingComma": "all",
3+
"semi": true,
4+
"singleQuote": true,
5+
"printWidth": 150,
6+
"tabWidth": 2
7+
}

‎LICENSE.md

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
## MIT License
2+
3+
Copyright (c) 2019-2020 Taktakpeops
4+
Permission is hereby granted, free of charge, to any person
5+
obtaining a copy of this software and associated documentation
6+
files (the "Software"), to deal in the Software without
7+
restriction, including without limitation the rights to use,
8+
copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the
10+
Software is furnished to do so, subject to the following
11+
conditions:
12+
13+
The above copyright notice and this permission notice shall be
14+
included in all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23+
OTHER DEALINGS IN THE SOFTWARE.

‎README.md

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# jest-environment-browserstack
2+
3+
Use Jest as test-runner for running your visual-tests and more using Browserstack.
4+
5+
The current implementation supports only the W3C way for capabilities. More info: https://www.browserstack.com/automate/selenium-4
6+
7+
# Usage
8+
9+
For using this environment, run first the following command in your terminal:
10+
11+
```
12+
npm install --save-dev jest-environment-browserstack
13+
```
14+
15+
Once it's done, configure your Jest config.
16+
17+
## Browserstack
18+
19+
Assuming your configuration is defined in your `package.json`, add the following lines to your `globals` definition:
20+
21+
```json
22+
{
23+
"jest": {
24+
"preset": "ts-jest",
25+
"testEnvironment": "jsdom",
26+
"globals": {
27+
"browserstack": {
28+
"capabilities": {
29+
"browserName": "chrome",
30+
"browserVersion": "76.0",
31+
"bstack:options": {
32+
"os": "Windows",
33+
"osVersion": "10",
34+
"userName": "myUsername",
35+
"accessKey": "myAccessKey",
36+
"buildName": "myBuild",
37+
"sessionName": "mySessionName"
38+
}
39+
}
40+
}
41+
}
42+
}
43+
}
44+
```
45+
46+
## Browserstack Local
47+
48+
Assuming here also your configuration is defined in your `package.json`, add the following lines to your `globals` definition:
49+
50+
```json
51+
{
52+
"jest": {
53+
"preset": "ts-jest",
54+
"testEnvironment": "jsdom",
55+
"globals": {
56+
"browserstack": {
57+
"capabilities": {
58+
"browserName": "chrome",
59+
"browserVersion": "76.0",
60+
"bstack:options": {
61+
"os": "Windows",
62+
"osVersion": "10",
63+
"userName": "myUsername",
64+
"accessKey": "myAccessKey",
65+
"buildName": "myBuild",
66+
"sessionName": "mySessionName"
67+
}
68+
},
69+
"localTesting": {
70+
"verbose": true
71+
}
72+
}
73+
}
74+
}
75+
}
76+
```
77+
78+
## Credentials
79+
80+
If you aren't willing to put your credentials in your `package.json` file, you can export in your environment `BROWSERSTACK_USER_NAME` and `BROWSERSTACK_ACCESS_KEY`. If you do so, `userName` and `accessKey` can be omitted.
81+
82+
# Known limitations
83+
84+
For now, only one browser can be defined.
85+
86+
# Bug and more
87+
88+
Feel free to open an issue on GitHub or to contribute by opening a pull-request.

‎package-lock.json

+3,810
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{
2+
"name": "jest-environment-browserstack",
3+
"version": "0.1.0",
4+
"description": "an environment for using Browserstack with Jest",
5+
"main": "lib/index.js",
6+
"types": "lib/index.d.ts",
7+
"scripts": {
8+
"build": "tsc",
9+
"lint": "eslint --ext .ts src/*",
10+
"lint:fix": "eslint --ext .ts src/* --fix",
11+
"prettier": "prettier --write \"**/*.{md,ts}\"",
12+
"test": "echo \"Error: no test specified\" && exit 1"
13+
},
14+
"keywords": [
15+
"jest",
16+
"browserstack",
17+
"e2e",
18+
"visual-testing",
19+
"test",
20+
"integration-test"
21+
],
22+
"author": "taktakpeops",
23+
"license": "MIT",
24+
"dependencies": {
25+
"@jest/types": "~24.9.0",
26+
"@types/selenium-webdriver": "~4.0.3",
27+
"browserstack-local": "~1.4.2",
28+
"jest-environment-node": "~24.9.0",
29+
"selenium-webdriver": "~4.0.0-alpha.5"
30+
},
31+
"devDependencies": {
32+
"@types/jest": "~24.0.18",
33+
"@types/node": "~12.7.7",
34+
"@typescript-eslint/eslint-plugin": "~2.3.1",
35+
"@typescript-eslint/parser": "~2.3.1",
36+
"eslint": "~6.4.0",
37+
"eslint-config-prettier": "~6.3.0",
38+
"eslint-plugin-prettier": "~3.1.1",
39+
"prettier": "~1.18.2",
40+
"typescript": "~3.6.3"
41+
}
42+
}

‎src/config.ts

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
export interface BrowserstackW3COptions {
2+
userName: string;
3+
accessKey: string;
4+
os?: string;
5+
osVersion?: string;
6+
local?: boolean;
7+
debug?: boolean;
8+
buildName?: string;
9+
sessionName?: string;
10+
localIdentifier?: string;
11+
networkLogs?: boolean;
12+
}
13+
14+
export interface BrowserstackCapabilities {
15+
browserName: string;
16+
'bstack:options': BrowserstackW3COptions;
17+
browserVersion?: string;
18+
}

‎src/index.ts

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import NodeEnvironment from 'jest-environment-node';
2+
import { Config } from '@jest/types';
3+
import { Options, Local } from 'browserstack-local';
4+
import { Builder, WebDriver } from 'selenium-webdriver';
5+
import { randomBytes } from 'crypto';
6+
import { Script } from 'vm';
7+
8+
import { BrowserstackCapabilities } from './config';
9+
10+
export default class BrowserstackEnvironment extends NodeEnvironment {
11+
private readonly localIdentifier: string;
12+
13+
private readonly key: string;
14+
15+
private readonly selHubUrl: string;
16+
17+
private readonly btCapabilities: BrowserstackCapabilities;
18+
19+
private btTunnelOpts: Options;
20+
21+
constructor(config: Config.ProjectConfig) {
22+
super(config);
23+
24+
const {
25+
browserstack: { capabilities, seleniumHubUrl = 'https://hub-cloud.browserstack.com/wd/hub', localTesting = null },
26+
} = config.globals;
27+
28+
this.btCapabilities = capabilities;
29+
30+
const opts = this.btCapabilities['bstack:options'];
31+
32+
if (!opts.accessKey || !opts.userName) {
33+
const { BROWSERSTACK_USER_NAME: userName = '', BROWSERSTACK_ACCESS_KEY: accessKey = '' } = process.env;
34+
35+
if (!userName || !accessKey) {
36+
throw new Error('valid credentials for Browserstack are requierd');
37+
}
38+
39+
this.btCapabilities['bstack:options'].accessKey = accessKey;
40+
this.btCapabilities['bstack:options'].userName = userName;
41+
}
42+
43+
this.key = opts.accessKey;
44+
45+
if (opts.local) {
46+
if (!opts.localIdentifier) {
47+
this.localIdentifier = Buffer.from(randomBytes(28)).toString('hex');
48+
opts.localIdentifier = this.localIdentifier;
49+
} else {
50+
this.localIdentifier = opts.localIdentifier;
51+
}
52+
53+
this.btTunnelOpts = localTesting;
54+
}
55+
56+
this.selHubUrl = seleniumHubUrl;
57+
}
58+
59+
async setup(): Promise<void> {
60+
await super.setup();
61+
62+
if (this.btTunnelOpts) {
63+
await this.createBTTunnel();
64+
}
65+
66+
this.global.__driver__ = await this.createWDDriver();
67+
}
68+
69+
async teardown(): Promise<void> {
70+
await super.teardown();
71+
72+
await this.global.__driver__.quit();
73+
await this.closeBTTunnel();
74+
}
75+
76+
runScript(script: Script): any {
77+
return super.runScript(script);
78+
}
79+
80+
private async createWDDriver(): Promise<WebDriver> {
81+
const driverFactory = new Builder().usingServer(this.selHubUrl).withCapabilities(this.btCapabilities);
82+
83+
return await driverFactory.build();
84+
}
85+
86+
private createBTTunnel(): Promise<void | Error> {
87+
if (this.localIdentifier) {
88+
this.btTunnelOpts.localIdentifier = this.localIdentifier;
89+
}
90+
91+
this.btTunnelOpts.key = this.key;
92+
93+
this.global.__local__ = new Local();
94+
95+
return new Promise((resolve, reject): void => {
96+
this.global.__local__.start(this.btTunnelOpts, (err?: Error) => {
97+
if (err) {
98+
return reject(err);
99+
}
100+
101+
return resolve();
102+
});
103+
});
104+
}
105+
106+
private closeBTTunnel(): Promise<void | Error> {
107+
return new Promise((resolve, reject): void => {
108+
this.global.__local__.stop((err?: Error) => {
109+
if (err) {
110+
return reject(err);
111+
}
112+
resolve();
113+
});
114+
});
115+
}
116+
}

‎tsconfig.json

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"compilerOptions": {
3+
"module": "commonjs",
4+
"esModuleInterop": true,
5+
"target": "es6",
6+
"allowJs": false,
7+
"declaration": true,
8+
"noImplicitAny": true,
9+
"outDir": "./lib"
10+
},
11+
"include": [
12+
"src/*.ts"
13+
],
14+
"exclude": [
15+
"node_modules/"
16+
]
17+
}

0 commit comments

Comments
 (0)
Please sign in to comment.