codeceptjs 3.7.6-beta.2 → 3.7.6-beta.4
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/lib/event.js +10 -1
- package/lib/helper/Appium.js +145 -25
- package/lib/helper/JSONResponse.js +4 -4
- package/lib/helper/Playwright.js +2 -3
- package/lib/helper/Puppeteer.js +6 -6
- package/lib/helper/WebDriver.js +3 -3
- package/lib/listener/steps.js +2 -2
- package/lib/output.js +51 -5
- package/lib/plugin/htmlReporter.js +147 -79
- package/lib/result.js +100 -23
- package/package.json +5 -2
- package/typings/promiseBasedTypes.d.ts +37 -25
- package/typings/types.d.ts +127 -30
package/lib/result.js
CHANGED
|
@@ -3,22 +3,21 @@ const path = require('path')
|
|
|
3
3
|
const { serializeTest } = require('./mocha/test')
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* @
|
|
9
|
-
* @property {number}
|
|
10
|
-
* @property {number}
|
|
11
|
-
* @property {number}
|
|
12
|
-
* @property {
|
|
13
|
-
* @property {
|
|
14
|
-
* @property {
|
|
15
|
-
|
|
16
|
-
|
|
6
|
+
* @typedef {Object} Stats Statistics for a test result.
|
|
7
|
+
* @property {number} passes Number of passed tests.
|
|
8
|
+
* @property {number} failures Number of failed tests.
|
|
9
|
+
* @property {number} tests Total number of tests.
|
|
10
|
+
* @property {number} pending Number of pending tests.
|
|
11
|
+
* @property {number} failedHooks Number of failed hooks.
|
|
12
|
+
* @property {Date} start Start time of the test run.
|
|
13
|
+
* @property {Date} end End time of the test run.
|
|
14
|
+
* @property {number} duration Duration of the test run, in milliseconds.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Result of a test run. Will be emitted for example in "event.all.result" events.
|
|
17
19
|
*/
|
|
18
20
|
class Result {
|
|
19
|
-
/**
|
|
20
|
-
* Create Result of the test run
|
|
21
|
-
*/
|
|
22
21
|
constructor() {
|
|
23
22
|
this._startTime = new Date()
|
|
24
23
|
this._endTime = null
|
|
@@ -27,6 +26,9 @@ class Result {
|
|
|
27
26
|
this.start()
|
|
28
27
|
}
|
|
29
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Resets all collected stats, tests, and failure reports.
|
|
31
|
+
*/
|
|
30
32
|
reset() {
|
|
31
33
|
this._stats = {
|
|
32
34
|
passes: 0,
|
|
@@ -39,43 +41,85 @@ class Result {
|
|
|
39
41
|
duration: 0,
|
|
40
42
|
}
|
|
41
43
|
|
|
42
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* @type {CodeceptJS.Test[]}
|
|
46
|
+
* @private
|
|
47
|
+
*/
|
|
43
48
|
this._tests = []
|
|
44
49
|
|
|
45
|
-
/**
|
|
50
|
+
/**
|
|
51
|
+
* @type {string[][]}
|
|
52
|
+
* @private
|
|
53
|
+
*/
|
|
46
54
|
this._failures = []
|
|
47
55
|
}
|
|
48
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Sets the start time to the current time.
|
|
59
|
+
*/
|
|
49
60
|
start() {
|
|
50
61
|
this._startTime = new Date()
|
|
51
62
|
}
|
|
52
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Sets the end time to the current time.
|
|
66
|
+
*/
|
|
53
67
|
finish() {
|
|
54
68
|
this._endTime = new Date()
|
|
55
69
|
}
|
|
56
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Whether this result contains any failed tests.
|
|
73
|
+
*
|
|
74
|
+
* @type {boolean}
|
|
75
|
+
* @readonly
|
|
76
|
+
*/
|
|
57
77
|
get hasFailed() {
|
|
58
78
|
return this._stats.failures > 0
|
|
59
79
|
}
|
|
60
80
|
|
|
81
|
+
/**
|
|
82
|
+
* All collected tests.
|
|
83
|
+
*
|
|
84
|
+
* @type {CodeceptJS.Test[]}
|
|
85
|
+
* @readonly
|
|
86
|
+
*/
|
|
61
87
|
get tests() {
|
|
62
88
|
return this._tests
|
|
63
89
|
}
|
|
64
90
|
|
|
91
|
+
/**
|
|
92
|
+
* The failure reports (array of strings per failed test).
|
|
93
|
+
*
|
|
94
|
+
* @type {string[][]}
|
|
95
|
+
* @readonly
|
|
96
|
+
*/
|
|
65
97
|
get failures() {
|
|
66
98
|
return this._failures.filter(f => f && (!Array.isArray(f) || f.length > 0))
|
|
67
99
|
}
|
|
68
100
|
|
|
101
|
+
/**
|
|
102
|
+
* The test statistics.
|
|
103
|
+
*
|
|
104
|
+
* @type {Stats}
|
|
105
|
+
* @readonly
|
|
106
|
+
*/
|
|
69
107
|
get stats() {
|
|
70
108
|
return this._stats
|
|
71
109
|
}
|
|
72
110
|
|
|
111
|
+
/**
|
|
112
|
+
* The start time of the test run.
|
|
113
|
+
*
|
|
114
|
+
* @type {Date}
|
|
115
|
+
* @readonly
|
|
116
|
+
*/
|
|
73
117
|
get startTime() {
|
|
74
118
|
return this._startTime
|
|
75
119
|
}
|
|
76
120
|
|
|
77
121
|
/**
|
|
78
|
-
*
|
|
122
|
+
* Adds a test to this result.
|
|
79
123
|
*
|
|
80
124
|
* @param {CodeceptJS.Test} test
|
|
81
125
|
*/
|
|
@@ -90,34 +134,67 @@ class Result {
|
|
|
90
134
|
}
|
|
91
135
|
|
|
92
136
|
/**
|
|
93
|
-
*
|
|
137
|
+
* Adds failure reports to this result.
|
|
94
138
|
*
|
|
95
|
-
* @param {
|
|
139
|
+
* @param {string[][]} newFailures
|
|
96
140
|
*/
|
|
97
141
|
addFailures(newFailures) {
|
|
98
142
|
this._failures.push(...newFailures)
|
|
99
143
|
}
|
|
100
144
|
|
|
145
|
+
/**
|
|
146
|
+
* Whether this result contains any failed tests.
|
|
147
|
+
*
|
|
148
|
+
* @type {boolean}
|
|
149
|
+
* @readonly
|
|
150
|
+
*/
|
|
101
151
|
get hasFailures() {
|
|
102
152
|
return this.stats.failures > 0
|
|
103
153
|
}
|
|
104
154
|
|
|
155
|
+
/**
|
|
156
|
+
* The duration of the test run, in milliseconds.
|
|
157
|
+
*
|
|
158
|
+
* @type {number}
|
|
159
|
+
* @readonly
|
|
160
|
+
*/
|
|
105
161
|
get duration() {
|
|
106
162
|
return this._endTime ? +this._endTime - +this._startTime : 0
|
|
107
163
|
}
|
|
108
164
|
|
|
165
|
+
/**
|
|
166
|
+
* All failed tests.
|
|
167
|
+
*
|
|
168
|
+
* @type {CodeceptJS.Test[]}
|
|
169
|
+
* readonly
|
|
170
|
+
*/
|
|
109
171
|
get failedTests() {
|
|
110
172
|
return this._tests.filter(test => test.state === 'failed')
|
|
111
173
|
}
|
|
112
174
|
|
|
175
|
+
/**
|
|
176
|
+
* All passed tests.
|
|
177
|
+
*
|
|
178
|
+
* @type {CodeceptJS.Test[]}
|
|
179
|
+
* @readonly
|
|
180
|
+
*/
|
|
113
181
|
get passedTests() {
|
|
114
182
|
return this._tests.filter(test => test.state === 'passed')
|
|
115
183
|
}
|
|
116
184
|
|
|
185
|
+
/**
|
|
186
|
+
* All skipped tests.
|
|
187
|
+
*
|
|
188
|
+
* @type {CodeceptJS.Test[]}
|
|
189
|
+
* @readonly
|
|
190
|
+
*/
|
|
117
191
|
get skippedTests() {
|
|
118
192
|
return this._tests.filter(test => test.state === 'skipped' || test.state === 'pending')
|
|
119
193
|
}
|
|
120
194
|
|
|
195
|
+
/**
|
|
196
|
+
* @returns {object} The JSON representation of this result.
|
|
197
|
+
*/
|
|
121
198
|
simplify() {
|
|
122
199
|
return {
|
|
123
200
|
hasFailed: this.hasFailed,
|
|
@@ -129,9 +206,9 @@ class Result {
|
|
|
129
206
|
}
|
|
130
207
|
|
|
131
208
|
/**
|
|
132
|
-
*
|
|
209
|
+
* Saves this result to a JSON file.
|
|
133
210
|
*
|
|
134
|
-
* @param {string} fileName
|
|
211
|
+
* @param {string} [fileName] Path to the JSON file, relative to `output_dir`. Defaults to "result.json".
|
|
135
212
|
*/
|
|
136
213
|
save(fileName) {
|
|
137
214
|
if (!fileName) fileName = 'result.json'
|
|
@@ -139,9 +216,9 @@ class Result {
|
|
|
139
216
|
}
|
|
140
217
|
|
|
141
218
|
/**
|
|
142
|
-
*
|
|
219
|
+
* Adds stats to this result.
|
|
143
220
|
*
|
|
144
|
-
* @param {
|
|
221
|
+
* @param {Partial<Stats>} [newStats]
|
|
145
222
|
*/
|
|
146
223
|
addStats(newStats = {}) {
|
|
147
224
|
this._stats.passes += newStats.passes || 0
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeceptjs",
|
|
3
|
-
"version": "3.7.6-beta.
|
|
3
|
+
"version": "3.7.6-beta.4",
|
|
4
4
|
"description": "Supercharged End 2 End Testing Framework for NodeJS",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"acceptance",
|
|
@@ -48,6 +48,9 @@
|
|
|
48
48
|
"repository": "Codeception/codeceptjs",
|
|
49
49
|
"scripts": {
|
|
50
50
|
"test-server": "node bin/test-server.js test/data/rest/db.json --host 0.0.0.0 -p 8010",
|
|
51
|
+
"mock-server:start": "node test/mock-server/start-mock-server.js",
|
|
52
|
+
"mock-server:stop": "kill -9 $(lsof -t -i:3001)",
|
|
53
|
+
"test:with-mock-server": "npm run mock-server:start && npm test",
|
|
51
54
|
"json-server:graphql": "node test/data/graphql/index.js",
|
|
52
55
|
"lint": "eslint bin/ examples/ lib/ test/ translations/ runok.js",
|
|
53
56
|
"lint-fix": "eslint bin/ examples/ lib/ test/ translations/ runok.js --fix",
|
|
@@ -138,7 +141,7 @@
|
|
|
138
141
|
"@pollyjs/core": "6.0.6",
|
|
139
142
|
"@types/chai": "5.2.2",
|
|
140
143
|
"@types/inquirer": "9.0.9",
|
|
141
|
-
"@types/node": "24.6.
|
|
144
|
+
"@types/node": "^24.6.2",
|
|
142
145
|
"@wdio/sauce-service": "9.12.5",
|
|
143
146
|
"@wdio/selenium-standalone-service": "8.15.0",
|
|
144
147
|
"@wdio/utils": "9.19.2",
|
|
@@ -2733,12 +2733,14 @@ declare namespace CodeceptJS {
|
|
|
2733
2733
|
* @property [highlightElement] - highlight the interacting elements. Default: false. Note: only activate under verbose mode (--verbose).
|
|
2734
2734
|
* @property [recordHar] - record HAR and will be saved to `output/har`. See more of [HAR options](https://playwright.dev/docs/api/class-browser#browser-new-context-option-record-har).
|
|
2735
2735
|
* @property [testIdAttribute = data-testid] - locate elements based on the testIdAttribute. See more of [locate by test id](https://playwright.dev/docs/locators#locate-by-test-id).
|
|
2736
|
-
* @property [customLocatorStrategies] - custom locator strategies. An object with keys as strategy names and values as JavaScript functions. Example: `{ byRole: (selector, root) => { return root.querySelector(
|
|
2736
|
+
* @property [customLocatorStrategies] - custom locator strategies. An object with keys as strategy names and values as JavaScript functions. Example: `{ byRole: (selector, root) => { return root.querySelector(`[role="${selector}"]`) } }`
|
|
2737
|
+
* @property [storageState] - Playwright storage state (path to JSON file or object)
|
|
2738
|
+
* passed directly to `browser.newContext`.
|
|
2739
|
+
* If a Scenario is declared with a `cookies` option (e.g. `Scenario('name', { cookies: [...] }, fn)`),
|
|
2740
|
+
* those cookies are used instead and the configured `storageState` is ignored (no merge).
|
|
2741
|
+
* May include session cookies, auth tokens, localStorage and (if captured with
|
|
2742
|
+
* `grabStorageState({ indexedDB: true })`) IndexedDB data; treat as sensitive and do not commit.
|
|
2737
2743
|
*/
|
|
2738
|
-
// @ts-ignore
|
|
2739
|
-
// @ts-ignore
|
|
2740
|
-
// @ts-ignore
|
|
2741
|
-
// @ts-ignore
|
|
2742
2744
|
type PlaywrightConfig = {
|
|
2743
2745
|
url?: string;
|
|
2744
2746
|
browser?: 'chromium' | 'firefox' | 'webkit' | 'electron';
|
|
@@ -2777,6 +2779,7 @@ declare namespace CodeceptJS {
|
|
|
2777
2779
|
recordHar?: any;
|
|
2778
2780
|
testIdAttribute?: string;
|
|
2779
2781
|
customLocatorStrategies?: any;
|
|
2782
|
+
storageState?: string | any;
|
|
2780
2783
|
};
|
|
2781
2784
|
/**
|
|
2782
2785
|
* Uses [Playwright](https://github.com/microsoft/playwright) library to run tests inside:
|
|
@@ -3688,7 +3691,7 @@ declare namespace CodeceptJS {
|
|
|
3688
3691
|
*/
|
|
3689
3692
|
pressKeyUp(key: string): Promise<any>;
|
|
3690
3693
|
/**
|
|
3691
|
-
* _Note:_ Shortcuts like `'Meta'` + `'A'` do not work on macOS ([
|
|
3694
|
+
* _Note:_ Shortcuts like `'Meta'` + `'A'` do not work on macOS ([puppeteer/puppeteer#1313](https://github.com/puppeteer/puppeteer/issues/1313)).
|
|
3692
3695
|
*
|
|
3693
3696
|
* Presses a key in the browser (on a focused element).
|
|
3694
3697
|
*
|
|
@@ -4087,6 +4090,27 @@ declare namespace CodeceptJS {
|
|
|
4087
4090
|
* @param [name = null] - cookie name.
|
|
4088
4091
|
*/
|
|
4089
4092
|
grabCookie(name?: string): Promise<any>;
|
|
4093
|
+
/**
|
|
4094
|
+
* Grab the current storage state (cookies, localStorage, etc.) via Playwright's `browserContext.storageState()`.
|
|
4095
|
+
* Returns the raw object that Playwright provides.
|
|
4096
|
+
*
|
|
4097
|
+
* Security: The returned object can contain authentication tokens, session cookies
|
|
4098
|
+
* and (when `indexedDB: true` is used) data that may include user PII. Treat it as a secret.
|
|
4099
|
+
* Avoid committing it to source control and prefer storing it in a protected secrets store / CI artifact vault.
|
|
4100
|
+
* @param [options.indexedDB] - set to true to include IndexedDB in snapshot (Playwright >=1.51)
|
|
4101
|
+
*
|
|
4102
|
+
* ```js
|
|
4103
|
+
* // basic usage
|
|
4104
|
+
* const state = await I.grabStorageState();
|
|
4105
|
+
* require('fs').writeFileSync('authState.json', JSON.stringify(state));
|
|
4106
|
+
*
|
|
4107
|
+
* // include IndexedDB when using Firebase Auth, etc.
|
|
4108
|
+
* const stateWithIDB = await I.grabStorageState({ indexedDB: true });
|
|
4109
|
+
* ```
|
|
4110
|
+
*/
|
|
4111
|
+
grabStorageState(options?: {
|
|
4112
|
+
indexedDB?: boolean;
|
|
4113
|
+
}): Promise<any>;
|
|
4090
4114
|
/**
|
|
4091
4115
|
* Clears a cookie by name,
|
|
4092
4116
|
* if none provided clears all cookies.
|
|
@@ -4517,7 +4541,7 @@ declare namespace CodeceptJS {
|
|
|
4517
4541
|
/**
|
|
4518
4542
|
* Waits for navigation to finish. By default, it takes configured `waitForNavigation` option.
|
|
4519
4543
|
*
|
|
4520
|
-
* See [Playwright's reference](https://playwright.dev/docs/api/class-page
|
|
4544
|
+
* See [Playwright's reference](https://playwright.dev/docs/api/class-page#page-wait-for-navigation)
|
|
4521
4545
|
*/
|
|
4522
4546
|
waitForNavigation(options: any): Promise<any>;
|
|
4523
4547
|
/**
|
|
@@ -6105,7 +6129,7 @@ declare namespace CodeceptJS {
|
|
|
6105
6129
|
* @property [keepBrowserState = false] - keep browser state between tests when `restart` is set to false.
|
|
6106
6130
|
* @property [keepCookies = false] - keep cookies between tests when `restart` is set to false.
|
|
6107
6131
|
* @property [waitForAction = 100] - how long to wait after click, doubleClick or PressKey actions in ms. Default: 100.
|
|
6108
|
-
* @property [waitForNavigation = load] - when to consider navigation succeeded. Possible options: `load`, `domcontentloaded`, `networkidle0`, `networkidle2`. See [Puppeteer API](https://github.com/
|
|
6132
|
+
* @property [waitForNavigation = load] - when to consider navigation succeeded. Possible options: `load`, `domcontentloaded`, `networkidle0`, `networkidle2`. See [Puppeteer API](https://github.com/puppeteer/puppeteer/blob/main/docs/api/puppeteer.waitforoptions.md). Array values are accepted as well.
|
|
6109
6133
|
* @property [pressKeyDelay = 10] - delay between key presses in ms. Used when calling Puppeteers page.type(...) in fillField/appendField
|
|
6110
6134
|
* @property [getPageTimeout = 30000] - config option to set maximum navigation time in milliseconds. If the timeout is set to 0, then timeout will be disabled.
|
|
6111
6135
|
* @property [waitForTimeout = 1000] - default wait* timeout in ms.
|
|
@@ -6113,13 +6137,9 @@ declare namespace CodeceptJS {
|
|
|
6113
6137
|
* @property [userAgent] - user-agent string.
|
|
6114
6138
|
* @property [manualStart = false] - do not start browser before a test, start it manually inside a helper with `this.helpers["Puppeteer"]._startBrowser()`.
|
|
6115
6139
|
* @property [browser = chrome] - can be changed to `firefox` when using [puppeteer-firefox](https://codecept.io/helpers/Puppeteer-firefox).
|
|
6116
|
-
* @property [chrome] - pass additional [Puppeteer run options](https://github.com/
|
|
6140
|
+
* @property [chrome] - pass additional [Puppeteer run options](https://github.com/puppeteer/puppeteer/blob/main/docs/api/puppeteer.launchoptions.md).
|
|
6117
6141
|
* @property [highlightElement] - highlight the interacting elements. Default: false. Note: only activate under verbose mode (--verbose).
|
|
6118
6142
|
*/
|
|
6119
|
-
// @ts-ignore
|
|
6120
|
-
// @ts-ignore
|
|
6121
|
-
// @ts-ignore
|
|
6122
|
-
// @ts-ignore
|
|
6123
6143
|
type PuppeteerConfig = {
|
|
6124
6144
|
url: string;
|
|
6125
6145
|
basicAuth?: any;
|
|
@@ -6133,7 +6153,7 @@ declare namespace CodeceptJS {
|
|
|
6133
6153
|
keepBrowserState?: boolean;
|
|
6134
6154
|
keepCookies?: boolean;
|
|
6135
6155
|
waitForAction?: number;
|
|
6136
|
-
waitForNavigation?: string;
|
|
6156
|
+
waitForNavigation?: string | string[];
|
|
6137
6157
|
pressKeyDelay?: number;
|
|
6138
6158
|
getPageTimeout?: number;
|
|
6139
6159
|
waitForTimeout?: number;
|
|
@@ -6145,7 +6165,7 @@ declare namespace CodeceptJS {
|
|
|
6145
6165
|
highlightElement?: boolean;
|
|
6146
6166
|
};
|
|
6147
6167
|
/**
|
|
6148
|
-
* Uses [Google Chrome's Puppeteer](https://github.com/
|
|
6168
|
+
* Uses [Google Chrome's Puppeteer](https://github.com/puppeteer/puppeteer) library to run tests inside headless Chrome.
|
|
6149
6169
|
* Browser control is executed via DevTools Protocol (instead of Selenium).
|
|
6150
6170
|
* This helper works with a browser out of the box with no additional tools required to install.
|
|
6151
6171
|
*
|
|
@@ -6887,7 +6907,7 @@ declare namespace CodeceptJS {
|
|
|
6887
6907
|
*/
|
|
6888
6908
|
pressKeyUp(key: string): Promise<any>;
|
|
6889
6909
|
/**
|
|
6890
|
-
* _Note:_ Shortcuts like `'Meta'` + `'A'` do not work on macOS ([
|
|
6910
|
+
* _Note:_ Shortcuts like `'Meta'` + `'A'` do not work on macOS ([puppeteer/puppeteer#1313](https://github.com/puppeteer/puppeteer/issues/1313)).
|
|
6891
6911
|
*
|
|
6892
6912
|
* Presses a key in the browser (on a focused element).
|
|
6893
6913
|
*
|
|
@@ -7735,7 +7755,7 @@ declare namespace CodeceptJS {
|
|
|
7735
7755
|
/**
|
|
7736
7756
|
* Waits for navigation to finish. By default, takes configured `waitForNavigation` option.
|
|
7737
7757
|
*
|
|
7738
|
-
* See [Puppeteer's reference](https://github.com/
|
|
7758
|
+
* See [Puppeteer's reference](https://github.com/puppeteer/puppeteer/blob/main/docs/api/puppeteer.page.waitfornavigation.md)
|
|
7739
7759
|
*/
|
|
7740
7760
|
waitForNavigation(opts: any): Promise<any>;
|
|
7741
7761
|
/**
|
|
@@ -7964,10 +7984,6 @@ declare namespace CodeceptJS {
|
|
|
7964
7984
|
* @property [onResponse] - an async function which can update response object.
|
|
7965
7985
|
* @property [maxUploadFileSize] - set the max content file size in MB when performing api calls.
|
|
7966
7986
|
*/
|
|
7967
|
-
// @ts-ignore
|
|
7968
|
-
// @ts-ignore
|
|
7969
|
-
// @ts-ignore
|
|
7970
|
-
// @ts-ignore
|
|
7971
7987
|
type RESTConfig = {
|
|
7972
7988
|
endpoint?: string;
|
|
7973
7989
|
prettyPrintJson?: boolean;
|
|
@@ -9123,10 +9139,6 @@ declare namespace CodeceptJS {
|
|
|
9123
9139
|
* @property [highlightElement] - highlight the interacting elements. Default: false. Note: only activate under verbose mode (--verbose).
|
|
9124
9140
|
* @property [logLevel = silent] - level of logging verbosity. Default: silent. Options: trace | debug | info | warn | error | silent. More info: https://webdriver.io/docs/configuration/#loglevel
|
|
9125
9141
|
*/
|
|
9126
|
-
// @ts-ignore
|
|
9127
|
-
// @ts-ignore
|
|
9128
|
-
// @ts-ignore
|
|
9129
|
-
// @ts-ignore
|
|
9130
9142
|
type WebDriverConfig = {
|
|
9131
9143
|
url: string;
|
|
9132
9144
|
browser: string;
|