@syngrisi/wdio-sdk 2.1.32-alpha.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/.eslintrc.cjs +45 -0
- package/LICENSE.md +9 -0
- package/README.md +118 -0
- package/README.md.bak +109 -0
- package/dist/WDIODriver.js +241 -0
- package/dist/lib/api.js +142 -0
- package/dist/lib/getDomDump.js +79 -0
- package/dist/lib/paramsGuard.js +18 -0
- package/dist/lib/utils.js +29 -0
- package/dist/lib/wdioHelpers.js +119 -0
- package/dist/schemas/Baseline.schema.js +22 -0
- package/dist/schemas/BaselineParams.schema.js +19 -0
- package/dist/schemas/Check.schema.js +43 -0
- package/dist/schemas/SessionParams.schema.js +18 -0
- package/dist/schemas/WDIODriver.js +36 -0
- package/dist/schemas/paramGuard.js +15 -0
- package/dist/schemas/paramsGuard.js +18 -0
- package/dist/types.js +2 -0
- package/package.json +60 -0
- package/tsconfig.json +82 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/typedoc.config.cjs +6 -0
package/.eslintrc.cjs
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
root: true,
|
|
3
|
+
parser: '@typescript-eslint/parser',
|
|
4
|
+
plugins: ['@typescript-eslint', 'unicorn'],
|
|
5
|
+
extends: [
|
|
6
|
+
'eslint:recommended',
|
|
7
|
+
'plugin:import/errors',
|
|
8
|
+
'plugin:import/warnings'
|
|
9
|
+
],
|
|
10
|
+
env: {
|
|
11
|
+
node: true,
|
|
12
|
+
es6: true,
|
|
13
|
+
jest: true
|
|
14
|
+
},
|
|
15
|
+
parserOptions: {
|
|
16
|
+
ecmaVersion: 2019,
|
|
17
|
+
sourceType: 'module'
|
|
18
|
+
},
|
|
19
|
+
rules: {
|
|
20
|
+
semi: ['error', 'never'],
|
|
21
|
+
quotes: ['error', 'single'],
|
|
22
|
+
indent: [2, 4],
|
|
23
|
+
|
|
24
|
+
'no-constant-condition': 0,
|
|
25
|
+
// see https://stackoverflow.com/questions/55280555/typescript-eslint-eslint-plugin-error-route-is-defined-but-never-used-no-un
|
|
26
|
+
'no-unused-vars': 'off',
|
|
27
|
+
'@typescript-eslint/no-unused-vars': 'error',
|
|
28
|
+
|
|
29
|
+
'import/no-unresolved': 0,
|
|
30
|
+
'import/named': 2,
|
|
31
|
+
'import/namespace': 2,
|
|
32
|
+
'import/default': 2,
|
|
33
|
+
'import/export': 2,
|
|
34
|
+
|
|
35
|
+
'unicorn/prefer-node-protocol': ['error']
|
|
36
|
+
},
|
|
37
|
+
overrides: [
|
|
38
|
+
{
|
|
39
|
+
files: ['*.ts'],
|
|
40
|
+
rules: {
|
|
41
|
+
'no-undef': 'off'
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|
package/LICENSE.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Viktar Silakou
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Syngrisi WebdriverIO SDK
|
|
2
|
+
|
|
3
|
+
The Syngrisi SDK for WebdriverIO, `@syngrisi/wdio-sdk` provides a simple and powerful way to integrate visual regression
|
|
4
|
+
testing into your WebdriverIO tests. By using this SDK, you can send snapshots from your browser tests to the Syngrisi
|
|
5
|
+
server for comparison against baseline images, and easily manage visual testing sessions.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- Start and stop test sessions seamlessly within your test flows.
|
|
10
|
+
- Perform visual checks with automatic baseline comparison.
|
|
11
|
+
- Fetch baseline and snapshot data programmatically.
|
|
12
|
+
- Easily extendable to fit any WebdriverIO-based testing framework.
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
To install the Syngrisi WebdriverIO SDK, run:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @syngrisi/wdio-sdk
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Base Workflow Overview
|
|
23
|
+
|
|
24
|
+
There is 3 basic step for particular test:
|
|
25
|
+
|
|
26
|
+
<p align="center">
|
|
27
|
+
<img src="./docs/flow.png" alt="workflow" width="40%">
|
|
28
|
+
</p>
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
|
|
32
|
+
The following is a standard workflow to use the SDK in your tests:
|
|
33
|
+
|
|
34
|
+
### 1. Initialize the Driver
|
|
35
|
+
|
|
36
|
+
Before starting your test session, initialize the driver with the necessary configuration.
|
|
37
|
+
|
|
38
|
+
```js
|
|
39
|
+
const { SyngrisiDriver } = require('@syngrisi/wdio-sdk');
|
|
40
|
+
|
|
41
|
+
const config = {
|
|
42
|
+
apiKey: 'your-api-key',
|
|
43
|
+
serverUrl: 'your-singrisi-url'
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const driver = new SyngrisiDriver(config);
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 2. Start a Test Session
|
|
50
|
+
|
|
51
|
+
Start a test session with the desired parameters.
|
|
52
|
+
|
|
53
|
+
```js
|
|
54
|
+
const sessionParams = {
|
|
55
|
+
os: 'Windows',
|
|
56
|
+
viewport: '1920x1080',
|
|
57
|
+
browserName: 'chrome',
|
|
58
|
+
browserVersion: '89.0',
|
|
59
|
+
test: 'Homepage Test',
|
|
60
|
+
app: 'Your App',
|
|
61
|
+
run: 'Run 1',
|
|
62
|
+
branch: 'main',
|
|
63
|
+
runident: 'unique-run-identifier',
|
|
64
|
+
suite: 'My Test Suite',
|
|
65
|
+
tags: ['tag1', 'tag2']
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
await driver.startTestSession({ params: sessionParams });
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 3. Perform a visual Check
|
|
72
|
+
|
|
73
|
+
Perform a visual check by providing the check name, image buffer, and any additional parameters.
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
driver.check({
|
|
77
|
+
checkName: 'Header',
|
|
78
|
+
imageBuffer: await $('#header').saveScreenshot(),
|
|
79
|
+
params: {
|
|
80
|
+
viewport: '1200x800',
|
|
81
|
+
browserName: 'chrome',
|
|
82
|
+
os: 'Windows',
|
|
83
|
+
app: 'MyProject',
|
|
84
|
+
branch: 'develop'
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
await driver.check({ 'About Page', await $('#header').saveScreenshot(), params: {/* other parameters */ } });
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### 4. Stop the Test Session
|
|
91
|
+
|
|
92
|
+
Once all checks are completed, stop the test session.
|
|
93
|
+
|
|
94
|
+
```js
|
|
95
|
+
await driver.stopTestSession();
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Environment variables
|
|
99
|
+
Environment variables are used to modify the behavior of the Syngrisi WebdriverIO SDK without code changes.
|
|
100
|
+
|
|
101
|
+
Example: To set the log level to debug, use the following command:
|
|
102
|
+
|
|
103
|
+
Windows: `set SYNGRISI_LOG_LEVEL=debug`
|
|
104
|
+
macOS/Linux: `export SYNGRISI_LOG_LEVEL=debug`
|
|
105
|
+
|
|
106
|
+
`ENV_POSTFIX` - will add to platform property, you can use this to set some unique platform name for particular
|
|
107
|
+
environment
|
|
108
|
+
`SYNGRISI_LOG_LEVEL` - logging level (`"trace" | "debug" | "info" | "warn" | "error"`)
|
|
109
|
+
|
|
110
|
+
## Documentation
|
|
111
|
+
|
|
112
|
+
For detailed information about all available methods, parameters, and configurations, please refer to
|
|
113
|
+
the [Syngrisi packages documentation](TODO ADD LINK TO ROOT docs folder published on github.io).
|
|
114
|
+
|
|
115
|
+
## License
|
|
116
|
+
|
|
117
|
+
This project is licensed under the [MIT License](LICENSE.md).
|
|
118
|
+
|
package/README.md.bak
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
## SDK for Syngrisi tool
|
|
2
|
+
|
|
3
|
+
### Base Flow Overview
|
|
4
|
+
|
|
5
|
+
There is 3 basic step for particular test:
|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
### Installation
|
|
9
|
+
|
|
10
|
+
```shell script
|
|
11
|
+
npm i @syngrisi/syngrisi-wdio-sdk --save-dev
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
### Usage Example
|
|
15
|
+
|
|
16
|
+
```javascript
|
|
17
|
+
const syngrisi = require('@syngrisi/syngrisi-wdio-sdk');
|
|
18
|
+
const vrsHost = 'localhost';
|
|
19
|
+
const vrsPort = 3000;
|
|
20
|
+
const VRSConfig = { url: `http://${vrsHost}:${vrsPort}/` };
|
|
21
|
+
const { remote } = require('webdriverio');
|
|
22
|
+
|
|
23
|
+
;(async () => {
|
|
24
|
+
global.browser = await remote({
|
|
25
|
+
capabilities: { browserName: 'chrome' }
|
|
26
|
+
})
|
|
27
|
+
// 0. Add Syngrisi driver to browser object
|
|
28
|
+
browser.vDriver = new syngrisi.vDriver(VRSConfig);
|
|
29
|
+
|
|
30
|
+
// 1. Start Syngrisi test session
|
|
31
|
+
await browser.vDriver.startTestSession({
|
|
32
|
+
app: 'Test Application',
|
|
33
|
+
test: 'My first Syngrisi test',
|
|
34
|
+
suite: 'My first Syngrisi suite'
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
await browser.navigateTo('https://www.google.com/ncr')
|
|
38
|
+
|
|
39
|
+
// 2.1. perform visual check
|
|
40
|
+
const screenshot = new Buffer(await browser.takeScreenshot(), 'base64');
|
|
41
|
+
|
|
42
|
+
await browser.vDriver.checkSnapshot(
|
|
43
|
+
'My Check',
|
|
44
|
+
screenshot
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const searchInput = await browser.$('[name=q]');
|
|
48
|
+
await searchInput.setValue('Σύγκριση');
|
|
49
|
+
|
|
50
|
+
const searchBtn = await browser.$('input[value="Google Search"]');
|
|
51
|
+
await (searchBtn.waitForClickable())
|
|
52
|
+
await searchBtn.click();
|
|
53
|
+
|
|
54
|
+
// 2.2 perform another visual check
|
|
55
|
+
const screenshot2 = new Buffer(await browser.takeScreenshot(), 'base64');
|
|
56
|
+
|
|
57
|
+
await browser.vDriver.checkSnapshot(
|
|
58
|
+
'My another Check',
|
|
59
|
+
screenshot2
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
// 2.3 stop test Session
|
|
63
|
+
await browser.vDriver.stopTestSession();
|
|
64
|
+
|
|
65
|
+
})().catch((err) => {
|
|
66
|
+
log.error(err)
|
|
67
|
+
throw err
|
|
68
|
+
}).finally(() => browser.deleteSession());
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Environment variables
|
|
72
|
+
|
|
73
|
+
`RUN_NAME` - use such variable to set up specific run name, by default it will generate automatically
|
|
74
|
+
`ENV_POSTFIX` - will add to platform property, you can use this to set some unique platform name for particular
|
|
75
|
+
environment
|
|
76
|
+
`SYNGRISI_LOG_LEVEL` - logging level (`"trace" | "debug" | "info" | "warn" | "error"`)
|
|
77
|
+
|
|
78
|
+
### SDK API
|
|
79
|
+
|
|
80
|
+
#### vDriver class
|
|
81
|
+
|
|
82
|
+
- `vDriver(cfg)` (constructor) - initialize vDriver instance
|
|
83
|
+
|
|
84
|
+
##### Parameters
|
|
85
|
+
|
|
86
|
+
| Name | Type | Details |
|
|
87
|
+
|-------|----------|----------------------------------------|
|
|
88
|
+
| `cfg` | `object` | e.g.: `{url: 'http://localhost:3000'}` |
|
|
89
|
+
|
|
90
|
+
- `startTestSession(params)` - starts of the test session
|
|
91
|
+
|
|
92
|
+
##### Parameters
|
|
93
|
+
|
|
94
|
+
| Name | Type | Details |
|
|
95
|
+
|----------|----------|-----------------------------------------------------------------------|
|
|
96
|
+
| `params` | `object` | e.g: {app: 'App Name', <br>test: 'Test Name',<br>suite: 'Suite Name'} |
|
|
97
|
+
|
|
98
|
+
- `checkSnapshot(checkName, imageBuffer, domDump)` - create snapshot and send to Syngrisi API
|
|
99
|
+
|
|
100
|
+
##### Parameters
|
|
101
|
+
|
|
102
|
+
| Name | Type | Details |
|
|
103
|
+
|---------------|----------|-------------------------------------------------------------------------------|
|
|
104
|
+
| `checkName` | `String` | eg.: 'Check Name' |
|
|
105
|
+
| `imageBuffer` | `Buffer` | File buffer |
|
|
106
|
+
| `domDump` | `String` | Web Page DOM Dump JSON string, to get properly dump use `getDomDump()` method |
|
|
107
|
+
|
|
108
|
+
- `stopTestSession()` - stop of the test session
|
|
109
|
+
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.WDIODriver = exports.getDomDump = void 0;
|
|
7
|
+
const hasha_1 = __importDefault(require("hasha"));
|
|
8
|
+
const logger_1 = __importDefault(require("@wdio/logger"));
|
|
9
|
+
const getDomDump_1 = require("./lib/getDomDump");
|
|
10
|
+
Object.defineProperty(exports, "getDomDump", { enumerable: true, get: function () { return getDomDump_1.getDomDump; } });
|
|
11
|
+
const core_api_1 = require("@syngrisi/core-api");
|
|
12
|
+
const WDIODriver_1 = require("./schemas/WDIODriver");
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
14
|
+
const wdioHelpers_1 = require("./lib/wdioHelpers");
|
|
15
|
+
const paramsGuard_1 = require("./lib/paramsGuard");
|
|
16
|
+
const log = (0, logger_1.default)('syngrisi-wdio-sdk');
|
|
17
|
+
// 0 | 4 | 2 | 1 | 3 | 5 | "trace" | "debug" | "info" | "warn" | "error" |
|
|
18
|
+
if (process.env.SYNGRISI_LOG_LEVEL) {
|
|
19
|
+
log.setLevel(process.env.SYNGRISI_LOG_LEVEL);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The `WDIODriver` class is responsible for managing the interaction between WebdriverIO and the Syngrisi server.
|
|
23
|
+
* It provides methods to start and stop test sessions, retrieve baselines and snapshots, and perform visual checks.
|
|
24
|
+
*/
|
|
25
|
+
class WDIODriver {
|
|
26
|
+
/**
|
|
27
|
+
* Creates an instance of the WDIODriver.
|
|
28
|
+
* @param {Config} cfg - Configuration object for the Syngrisi API.
|
|
29
|
+
* @example
|
|
30
|
+
* const driver = new WDIODriver({
|
|
31
|
+
* host: '<your-syngrisi-url>',
|
|
32
|
+
* apiKey: 'your-api-key'
|
|
33
|
+
* });
|
|
34
|
+
*/
|
|
35
|
+
constructor(cfg) {
|
|
36
|
+
this.api = new core_api_1.SyngrisiApi(cfg);
|
|
37
|
+
this.params = {
|
|
38
|
+
// @ts-ignore
|
|
39
|
+
test: {}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Starts a new test session with the provided parameters.
|
|
44
|
+
* @param {SessionParams} params - Parameters for the test session.
|
|
45
|
+
* @param {boolean} [suppressErrors=false] - Flag to suppress thrown errors.
|
|
46
|
+
* @returns {Promise<SessionResponse | ErrorObject>} The session response or an error object.
|
|
47
|
+
* @example
|
|
48
|
+
* driver.startTestSession({
|
|
49
|
+
* params: {
|
|
50
|
+
* os: 'Windows',
|
|
51
|
+
* browserName: 'chrome',
|
|
52
|
+
* test: 'Main Page Test',
|
|
53
|
+
* app: 'MyProject',
|
|
54
|
+
* run: 'run-123',
|
|
55
|
+
* branch: 'master',
|
|
56
|
+
* runident: 'run-identification-string',
|
|
57
|
+
* tags: ['tag1', 'tag2']
|
|
58
|
+
* },
|
|
59
|
+
* suppressErrors: true
|
|
60
|
+
* });
|
|
61
|
+
*/
|
|
62
|
+
async startTestSession({ params, suppressErrors = false }) {
|
|
63
|
+
try {
|
|
64
|
+
(0, paramsGuard_1.paramsGuard)(params, 'startTestSession, params', WDIODriver_1.SessionParamsSchema);
|
|
65
|
+
this.params.test = {
|
|
66
|
+
os: params.os || await (0, wdioHelpers_1.getOS)(),
|
|
67
|
+
viewport: params.viewport || await (0, wdioHelpers_1.getViewport)(),
|
|
68
|
+
browser: params.browserName || await (0, wdioHelpers_1.getBrowserName)(),
|
|
69
|
+
browserVersion: params.browserVersion || await (0, wdioHelpers_1.getBrowserVersion)(),
|
|
70
|
+
name: params.test,
|
|
71
|
+
app: params.app,
|
|
72
|
+
run: params.run,
|
|
73
|
+
branch: params.branch,
|
|
74
|
+
runident: params.runident,
|
|
75
|
+
suite: params.suite || 'Unknown',
|
|
76
|
+
tags: params.tags,
|
|
77
|
+
browserFullVersion: params.browserFullVersion || await (0, wdioHelpers_1.getBrowserFullVersion)()
|
|
78
|
+
};
|
|
79
|
+
// noinspection DuplicatedCode
|
|
80
|
+
const result = await this.api.startSession(this.params.test);
|
|
81
|
+
if (result.error && !suppressErrors) {
|
|
82
|
+
throw `❌ Start Test Session Error: ${JSON.stringify(result, null, ' ')}`;
|
|
83
|
+
}
|
|
84
|
+
if (!result) {
|
|
85
|
+
throw new Error(`response is empty, params: ${JSON.stringify(params, null, '\t')}`);
|
|
86
|
+
}
|
|
87
|
+
this.params.test.testId = result._id;
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
catch (e) {
|
|
91
|
+
const eMsg = `Cannot start session, error: '${e}' \n '${e.stack}'`;
|
|
92
|
+
log.error(eMsg);
|
|
93
|
+
throw new Error(eMsg);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Stops the currently running test session.
|
|
98
|
+
* @param {boolean} [suppressErrors=false] - Flag to suppress thrown errors.
|
|
99
|
+
* @returns {Promise<SessionResponse | ErrorObject>} The stop session response or an error object.
|
|
100
|
+
* @example
|
|
101
|
+
* driver.stopTestSession();
|
|
102
|
+
*/
|
|
103
|
+
async stopTestSession({ suppressErrors = false } = {}) {
|
|
104
|
+
try {
|
|
105
|
+
const testId = this.params.test.testId;
|
|
106
|
+
if (!testId) {
|
|
107
|
+
throw `❌ Stop Test Session Error: testId id empty, driver params: '${JSON.stringify(this.params)}'`;
|
|
108
|
+
}
|
|
109
|
+
this.params.test.testId = undefined;
|
|
110
|
+
const result = await this.api.stopSession(testId);
|
|
111
|
+
if (result.error && !suppressErrors) {
|
|
112
|
+
throw `❌ Stop Test Session Error: ${JSON.stringify(result, null, ' ')}`;
|
|
113
|
+
}
|
|
114
|
+
log.debug(`Session with testId: '${result._id}' was stopped`);
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
117
|
+
catch (e) {
|
|
118
|
+
const eMsg = `Cannot stop session, error: '${e}' \n '${e.stack}'`;
|
|
119
|
+
log.error(eMsg);
|
|
120
|
+
throw e;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Fetches baselines matching the provided criteria.
|
|
125
|
+
* @param {BaselineParams} params - Baseline search parameters.
|
|
126
|
+
* @returns {Promise<BaselineResponse | ErrorObject>} The baseline response or an error object.
|
|
127
|
+
* @example
|
|
128
|
+
* driver.getBaselines({
|
|
129
|
+
* params: {
|
|
130
|
+
* name: 'Main Page',
|
|
131
|
+
* viewport: '1200x800',
|
|
132
|
+
* browserName: 'chrome',
|
|
133
|
+
* os: 'Windows',
|
|
134
|
+
* app: 'MyProject',
|
|
135
|
+
* branch: 'master'
|
|
136
|
+
* }
|
|
137
|
+
* });
|
|
138
|
+
*/
|
|
139
|
+
async getBaselines({ params }) {
|
|
140
|
+
// ident: ['name', 'viewport', 'browserName', 'os', 'app', 'branch'];
|
|
141
|
+
let opts = {
|
|
142
|
+
name: params.name,
|
|
143
|
+
viewport: params.viewport || await (0, wdioHelpers_1.getViewport)(),
|
|
144
|
+
browserName: params.browserName || this.params.test.browser || await (0, wdioHelpers_1.getBrowserVersion)(),
|
|
145
|
+
os: params.os || this.params.test.os || await (0, wdioHelpers_1.getOS)(),
|
|
146
|
+
app: params.app || this.params.test.app,
|
|
147
|
+
branch: params.branch || this.params.test.branch,
|
|
148
|
+
};
|
|
149
|
+
(0, paramsGuard_1.paramsGuard)(opts, 'getBaseline, opts', WDIODriver_1.BaselineParamsSchema);
|
|
150
|
+
const result = await this.api.getBaselines(opts);
|
|
151
|
+
if (result.error) {
|
|
152
|
+
throw `❌ Get baselines error: ${JSON.stringify(result, null, ' ')}`;
|
|
153
|
+
}
|
|
154
|
+
return result;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Retrieves snapshots based on the given search criteria.
|
|
158
|
+
* @param {Snapshot} params - Snapshot search parameters.
|
|
159
|
+
* @returns {Promise<SnapshotResponse | ErrorObject>} The snapshot response or an error object.
|
|
160
|
+
* @example
|
|
161
|
+
* driver.getSnapshots({
|
|
162
|
+
* params: {
|
|
163
|
+
* name: 'Checkout Page',
|
|
164
|
+
* viewport: '1200x800',
|
|
165
|
+
* browserName: 'firefox',
|
|
166
|
+
* os: 'macOS',
|
|
167
|
+
* app: 'E-commerce Platform',
|
|
168
|
+
* branch: 'feature-xyz'
|
|
169
|
+
* }
|
|
170
|
+
* });
|
|
171
|
+
*/
|
|
172
|
+
async getSnapshots({ params }) {
|
|
173
|
+
const result = await this.api.getSnapshots(params);
|
|
174
|
+
if (result.error) {
|
|
175
|
+
throw `❌ Get snapshots error: ${JSON.stringify(result, null, ' ')}`;
|
|
176
|
+
}
|
|
177
|
+
return result;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Submits a check to Syngrisi with the provided image and associated test details.
|
|
181
|
+
* @param {string} checkName - Name of the check.
|
|
182
|
+
* @param {Buffer} imageBuffer - Buffer containing image data for the check.
|
|
183
|
+
* @param {CheckParams} params - Additional check parameters.
|
|
184
|
+
* @param {any} domDump - Serialized DOM dump associated with the image check.
|
|
185
|
+
* @param {boolean} [suppressErrors=false] - Flag to suppress thrown errors.
|
|
186
|
+
* @returns {Promise<CheckResponse | ErrorObject>} The check response or an error object.
|
|
187
|
+
* @example
|
|
188
|
+
* driver.check({
|
|
189
|
+
* checkName: 'Main Navigation Bar',
|
|
190
|
+
* imageBuffer: fs.readFileSync('navbar.png'),
|
|
191
|
+
* params: {
|
|
192
|
+
* viewport: '1200x800',
|
|
193
|
+
* browserName: 'chrome',
|
|
194
|
+
* os: 'Windows',
|
|
195
|
+
* app: 'MyApp',
|
|
196
|
+
* branch: 'develop'
|
|
197
|
+
* },
|
|
198
|
+
* suppressErrors: false
|
|
199
|
+
* });
|
|
200
|
+
*/
|
|
201
|
+
async check({ checkName, imageBuffer, params, domDump, suppressErrors = false }) {
|
|
202
|
+
if (this.params.test.testId === undefined) {
|
|
203
|
+
throw new Error('The test id is empty, the session may not have started yet:'
|
|
204
|
+
+ `check name: '${checkName}', driver: '${JSON.stringify(this, null, '\t')}'`);
|
|
205
|
+
}
|
|
206
|
+
if (!Buffer.isBuffer(imageBuffer))
|
|
207
|
+
throw new Error('check - wrong imageBuffer');
|
|
208
|
+
let opts = null;
|
|
209
|
+
try {
|
|
210
|
+
opts = {
|
|
211
|
+
// ident: ['name', 'viewport', 'browserName', 'os', 'app', 'branch'];
|
|
212
|
+
name: checkName,
|
|
213
|
+
viewport: params?.viewport || await (0, wdioHelpers_1.getViewport)(),
|
|
214
|
+
browserName: this.params.test.browser,
|
|
215
|
+
os: this.params.test.os,
|
|
216
|
+
app: this.params.test.app,
|
|
217
|
+
branch: this.params.test.branch,
|
|
218
|
+
// ['name', 'viewport', 'browserName', 'os', 'app', 'branch', 'testId', 'suite', 'browserVersion', 'browserFullVersion' ];
|
|
219
|
+
testId: this.params.test.testId,
|
|
220
|
+
suite: this.params.test.suite,
|
|
221
|
+
browserVersion: this.params.test.browserVersion,
|
|
222
|
+
browserFullVersion: this.params.test.browserFullVersion,
|
|
223
|
+
hashCode: (0, hasha_1.default)(imageBuffer),
|
|
224
|
+
domDump: domDump,
|
|
225
|
+
};
|
|
226
|
+
(0, paramsGuard_1.paramsGuard)(opts, 'check, opts', core_api_1.CheckParamsSchema);
|
|
227
|
+
Object.assign(opts, params);
|
|
228
|
+
const result = await this.api.coreCheck(imageBuffer, opts);
|
|
229
|
+
if (result.error && !suppressErrors) {
|
|
230
|
+
throw `❌ Create Check error: ${JSON.stringify(result, null, ' ')}`;
|
|
231
|
+
}
|
|
232
|
+
return result;
|
|
233
|
+
}
|
|
234
|
+
catch (e) {
|
|
235
|
+
log.error(`cannot create check, params: '${JSON.stringify(params)}' opts: '${JSON.stringify(opts)}, error: '${e.stack || e.toString()}'`);
|
|
236
|
+
throw e;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
exports.WDIODriver = WDIODriver;
|
|
241
|
+
exports.SyngrisiDriver = WDIODriver;
|
package/dist/lib/api.js
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SyngrisiApi = void 0;
|
|
7
|
+
const form_data_1 = __importDefault(require("form-data"));
|
|
8
|
+
const got_cjs_1 = __importDefault(require("got-cjs"));
|
|
9
|
+
const hasha_1 = __importDefault(require("hasha"));
|
|
10
|
+
const logger_1 = __importDefault(require("@wdio/logger"));
|
|
11
|
+
const utils_1 = require("./utils");
|
|
12
|
+
const log = (0, logger_1.default)('syngrisi-wdio-sdk');
|
|
13
|
+
class SyngrisiApi {
|
|
14
|
+
constructor(cfg) {
|
|
15
|
+
this.config = cfg;
|
|
16
|
+
}
|
|
17
|
+
objectToSearch(obj) {
|
|
18
|
+
const str = [];
|
|
19
|
+
for (const p in obj) {
|
|
20
|
+
if (Object.prototype.hasOwnProperty.call(obj, p)) {
|
|
21
|
+
str.push(`${encodeURIComponent(p)}=${encodeURIComponent(obj[p])}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return str.join('&');
|
|
25
|
+
}
|
|
26
|
+
async startSession(params) {
|
|
27
|
+
const apiHash = (0, hasha_1.default)(this.config.apiKey);
|
|
28
|
+
const form = new form_data_1.default();
|
|
29
|
+
const required = ['run', 'suite', 'runident', 'name', 'viewport', 'browser', 'browserVersion', 'os', 'app'];
|
|
30
|
+
required.forEach(param => form.append(param, params[param]));
|
|
31
|
+
// optional
|
|
32
|
+
if (params.tags)
|
|
33
|
+
form.append('tags', JSON.stringify(params.tags));
|
|
34
|
+
if (params.branch)
|
|
35
|
+
form.append('branch', params.branch);
|
|
36
|
+
const response = await got_cjs_1.default.post(`${this.config.url}v1/client/startSession`, {
|
|
37
|
+
body: form,
|
|
38
|
+
headers: { apikey: apiHash },
|
|
39
|
+
}).json();
|
|
40
|
+
return response;
|
|
41
|
+
}
|
|
42
|
+
async stopSession(testId) {
|
|
43
|
+
try {
|
|
44
|
+
const apiHash = (0, hasha_1.default)(this.config.apiKey);
|
|
45
|
+
const form = new form_data_1.default();
|
|
46
|
+
const response = await got_cjs_1.default.post(`${this.config.url}v1/client/stopSession/${testId}`, {
|
|
47
|
+
body: form,
|
|
48
|
+
headers: { apikey: apiHash },
|
|
49
|
+
}).json();
|
|
50
|
+
return response;
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
throw new Error(`Cannot stop the test session with id: '${testId}', error: '${e}'`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
addMessageIfCheckFailed(result) {
|
|
57
|
+
const patchedResult = result;
|
|
58
|
+
if (patchedResult.status.includes('failed')) {
|
|
59
|
+
const checkView = `'${this.config.url}?checkId=${patchedResult._id}&modalIsOpen=true'`;
|
|
60
|
+
patchedResult.message = `To evaluate the results of the check, follow the link: '${checkView}'`;
|
|
61
|
+
// basically the links is useless - backward compatibility
|
|
62
|
+
patchedResult.vrsGroupLink = checkView;
|
|
63
|
+
patchedResult.vrsDiffLink = checkView;
|
|
64
|
+
}
|
|
65
|
+
return patchedResult;
|
|
66
|
+
}
|
|
67
|
+
async coreCheck(imageBuffer, params) {
|
|
68
|
+
let resultWithHash = await this.createCheck(params, null, params.hashCode);
|
|
69
|
+
resultWithHash = this.addMessageIfCheckFailed(resultWithHash);
|
|
70
|
+
log.info(`Check result Phase #1: ${(0, utils_1.prettyCheckResult)(resultWithHash)}`);
|
|
71
|
+
if (resultWithHash.status === 'requiredFileData') {
|
|
72
|
+
let resultWithFile = await this.createCheck(params, imageBuffer, params.hashCode);
|
|
73
|
+
log.info(`Check result Phase #2: ${(0, utils_1.prettyCheckResult)(resultWithFile)}`);
|
|
74
|
+
resultWithFile = this.addMessageIfCheckFailed(resultWithFile);
|
|
75
|
+
return resultWithFile;
|
|
76
|
+
}
|
|
77
|
+
return resultWithHash;
|
|
78
|
+
}
|
|
79
|
+
async createCheck(params, imageBuffer, hashCode) {
|
|
80
|
+
const apiHash = (0, hasha_1.default)(this.config.apiKey);
|
|
81
|
+
const url = `${this.config.url}v1/client/createCheck`;
|
|
82
|
+
const form = new form_data_1.default();
|
|
83
|
+
const fieldsMapping = {
|
|
84
|
+
branch: 'branch',
|
|
85
|
+
app: 'appName',
|
|
86
|
+
suite: 'suitename',
|
|
87
|
+
domDump: 'domdump',
|
|
88
|
+
vShifting: 'vShifting',
|
|
89
|
+
testId: 'testid',
|
|
90
|
+
name: 'name',
|
|
91
|
+
viewport: 'viewport',
|
|
92
|
+
browserName: 'browserName',
|
|
93
|
+
browserVersion: 'browserVersion',
|
|
94
|
+
browserFullVersion: 'browserFullVersion',
|
|
95
|
+
os: 'os'
|
|
96
|
+
};
|
|
97
|
+
try {
|
|
98
|
+
Object.keys(fieldsMapping).forEach(key => {
|
|
99
|
+
if (params[key]) { // @ts-ignore
|
|
100
|
+
form.append(fieldsMapping[key], params[key]);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
if (hashCode)
|
|
104
|
+
form.append('hashcode', hashCode);
|
|
105
|
+
if (imageBuffer)
|
|
106
|
+
form.append('file', imageBuffer, 'file');
|
|
107
|
+
const result = await got_cjs_1.default.post(url, {
|
|
108
|
+
body: form,
|
|
109
|
+
headers: { apikey: apiHash },
|
|
110
|
+
}).json();
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
catch (e) {
|
|
114
|
+
log.error('❌ createCheck error create check vi API' + e.stack || e.toString());
|
|
115
|
+
log.error('👉 Params:', params);
|
|
116
|
+
if (e.response)
|
|
117
|
+
(0, utils_1.printErrorResponseBody)(e);
|
|
118
|
+
throw e;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
async getIdent(apiKey) {
|
|
122
|
+
const url = `${this.config.url}v1/client/getIdent?apikey=${(0, hasha_1.default)(apiKey)}`;
|
|
123
|
+
const result = await got_cjs_1.default.get(url).json();
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
async checkIfBaselineExist(params) {
|
|
127
|
+
try {
|
|
128
|
+
const searchString = this.objectToSearch({
|
|
129
|
+
...params, ...{ apikey: (0, hasha_1.default)(this.config.apiKey) },
|
|
130
|
+
});
|
|
131
|
+
const url = `${this.config.url}v1/client/checkIfScreenshotHasBaselines?${searchString}`;
|
|
132
|
+
// console.log({ url });
|
|
133
|
+
const result = got_cjs_1.default.get(url, { throwHttpErrors: false })
|
|
134
|
+
.json();
|
|
135
|
+
return result;
|
|
136
|
+
}
|
|
137
|
+
catch (e) {
|
|
138
|
+
throw new Error(e.toString() + e.stack);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
exports.SyngrisiApi = SyngrisiApi;
|