@elastic/synthetics 1.0.0-beta.22 → 1.0.0-beta.25
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/CHANGELOG.md +23 -0
- package/NOTICE.txt +0 -29
- package/dist/cli.js +55 -184
- package/dist/cli.js.map +1 -1
- package/dist/common_types.d.ts +43 -36
- package/dist/common_types.d.ts.map +1 -1
- package/dist/core/gatherer.d.ts +2 -3
- package/dist/core/gatherer.d.ts.map +1 -1
- package/dist/core/gatherer.js +17 -9
- package/dist/core/gatherer.js.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +7 -9
- package/dist/core/index.js.map +1 -1
- package/dist/core/runner.d.ts +1 -8
- package/dist/core/runner.d.ts.map +1 -1
- package/dist/core/runner.js +2 -3
- package/dist/core/runner.js.map +1 -1
- package/dist/dsl/journey.d.ts +4 -3
- package/dist/dsl/journey.d.ts.map +1 -1
- package/dist/dsl/journey.js +4 -3
- package/dist/dsl/journey.js.map +1 -1
- package/dist/dsl/step.d.ts +3 -2
- package/dist/dsl/step.d.ts.map +1 -1
- package/dist/dsl/step.js +2 -1
- package/dist/dsl/step.js.map +1 -1
- package/dist/formatter/javascript.d.ts +31 -6
- package/dist/formatter/javascript.d.ts.map +1 -1
- package/dist/formatter/javascript.js +45 -24
- package/dist/formatter/javascript.js.map +1 -1
- package/dist/helpers.d.ts +2 -1
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +30 -1
- package/dist/helpers.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -17
- package/dist/index.js.map +1 -1
- package/dist/{parse_args.d.ts → loader.d.ts} +2 -5
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +144 -0
- package/dist/loader.js.map +1 -0
- package/dist/options.d.ts +27 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +108 -0
- package/dist/options.js.map +1 -0
- package/dist/plugins/network.d.ts +17 -33
- package/dist/plugins/network.d.ts.map +1 -1
- package/dist/plugins/network.js +179 -245
- package/dist/plugins/network.js.map +1 -1
- package/dist/plugins/plugin-manager.d.ts +1 -1
- package/dist/plugins/plugin-manager.d.ts.map +1 -1
- package/dist/plugins/plugin-manager.js +2 -2
- package/dist/plugins/plugin-manager.js.map +1 -1
- package/dist/reporters/json.d.ts +0 -1
- package/dist/reporters/json.d.ts.map +1 -1
- package/dist/reporters/json.js +5 -24
- package/dist/reporters/json.js.map +1 -1
- package/dist/sdk/trace-metrics.js +3 -4
- package/dist/sdk/trace-metrics.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -4
- package/src/cli.ts +114 -188
- package/src/common_types.ts +47 -36
- package/src/core/gatherer.ts +17 -10
- package/src/core/index.ts +22 -16
- package/src/core/runner.ts +3 -23
- package/src/dsl/journey.ts +10 -4
- package/src/dsl/step.ts +9 -2
- package/src/formatter/javascript.ts +59 -22
- package/src/helpers.ts +40 -1
- package/src/index.ts +10 -16
- package/src/loader.ts +162 -0
- package/src/options.ts +116 -0
- package/src/plugins/network.ts +218 -293
- package/src/plugins/plugin-manager.ts +2 -2
- package/src/reporters/json.ts +1 -17
- package/dist/parse_args.d.ts.map +0 -1
- package/dist/parse_args.js +0 -103
- package/dist/parse_args.js.map +0 -1
- package/src/parse_args.ts +0 -158
package/src/cli.ts
CHANGED
|
@@ -25,200 +25,126 @@
|
|
|
25
25
|
*
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
33
|
-
import
|
|
34
|
-
import { expect } from './core/expect';
|
|
35
|
-
import {
|
|
36
|
-
findPkgJsonByTraversing,
|
|
37
|
-
isDepInstalled,
|
|
38
|
-
isDirectory,
|
|
39
|
-
totalist,
|
|
40
|
-
parseNetworkConditions,
|
|
41
|
-
} from './helpers';
|
|
28
|
+
import { program, Option } from 'commander';
|
|
29
|
+
import { CliArgs } from './common_types';
|
|
30
|
+
import { reporters } from './reporters';
|
|
31
|
+
import { DEFAULT_NETWORK_CONDITIONS_ARG } from './helpers';
|
|
32
|
+
import { normalizeOptions } from './options';
|
|
33
|
+
import { loadTestFiles } from './loader';
|
|
42
34
|
import { run } from './';
|
|
43
|
-
import { readConfig } from './config';
|
|
44
35
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
* Set debug based on DEBUG ENV and -d flags
|
|
48
|
-
* namespace - synthetics
|
|
49
|
-
*/
|
|
50
|
-
const namespace = 'synthetics';
|
|
51
|
-
if (process.env.DEBUG === namespace || Boolean(options.debug)) {
|
|
52
|
-
process.env.DEBUG = '1';
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const loadInlineScript = source => {
|
|
56
|
-
const scriptFn = new Function(
|
|
57
|
-
'step',
|
|
58
|
-
'page',
|
|
59
|
-
'context',
|
|
60
|
-
'browser',
|
|
61
|
-
'params',
|
|
62
|
-
'expect',
|
|
63
|
-
source
|
|
64
|
-
);
|
|
65
|
-
journey('inline', ({ page, context, browser, params }) => {
|
|
66
|
-
scriptFn.apply(null, [step, page, context, browser, params, expect]);
|
|
67
|
-
});
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
async function readStdin() {
|
|
71
|
-
const chunks = [];
|
|
72
|
-
stdin.resume();
|
|
73
|
-
stdin.setEncoding('utf-8');
|
|
74
|
-
for await (const chunk of stdin) {
|
|
75
|
-
chunks.push(chunk);
|
|
76
|
-
}
|
|
77
|
-
return chunks.join();
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function requireSuites(suites: Iterable<string>) {
|
|
81
|
-
for (const suite of suites) {
|
|
82
|
-
require(suite);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Handle both directory and files that are passed through TTY
|
|
88
|
-
* and add them to suites
|
|
89
|
-
*/
|
|
90
|
-
async function prepareSuites(inputs: string[]) {
|
|
91
|
-
const suites = new Set<string>();
|
|
92
|
-
const addSuite = absPath => {
|
|
93
|
-
log(`Processing file: ${absPath}`);
|
|
94
|
-
suites.add(require.resolve(absPath));
|
|
95
|
-
};
|
|
96
|
-
/**
|
|
97
|
-
* Match all files inside the directory with the
|
|
98
|
-
* .journey.{mjs|cjs|js|ts) extensions
|
|
99
|
-
*/
|
|
100
|
-
const pattern = options.pattern
|
|
101
|
-
? new RegExp(options.pattern, 'i')
|
|
102
|
-
: /.+\.journey\.([mc]js|[jt]s?)$/;
|
|
103
|
-
/**
|
|
104
|
-
* Ignore node_modules by default when running suites
|
|
105
|
-
*/
|
|
106
|
-
const ignored = /node_modules/i;
|
|
36
|
+
/* eslint-disable-next-line @typescript-eslint/no-var-requires */
|
|
37
|
+
const { name, version } = require('../package.json');
|
|
107
38
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
39
|
+
program
|
|
40
|
+
.name(`npx ${name}`)
|
|
41
|
+
.usage('[options] [dir] [files] file')
|
|
42
|
+
.option(
|
|
43
|
+
'-c, --config <path>',
|
|
44
|
+
'configuration path (default: synthetics.config.js)'
|
|
45
|
+
)
|
|
46
|
+
.option(
|
|
47
|
+
'-p, --params <jsonstring>',
|
|
48
|
+
'JSON object that gets injected to all journeys',
|
|
49
|
+
JSON.parse
|
|
50
|
+
)
|
|
51
|
+
.addOption(
|
|
52
|
+
new Option('--reporter <value>', `output repoter format`).choices(
|
|
53
|
+
Object.keys(reporters)
|
|
54
|
+
)
|
|
55
|
+
)
|
|
56
|
+
.option(
|
|
57
|
+
'--pattern <pattern>',
|
|
58
|
+
'RegExp file patterns to search inside directory'
|
|
59
|
+
)
|
|
60
|
+
.option('--inline', 'Run inline journeys from heartbeat')
|
|
61
|
+
.option('-r, --require <modules...>', 'module(s) to preload')
|
|
62
|
+
.option('--no-headless', 'run browser in headful mode')
|
|
63
|
+
.option('--sandbox', 'enable chromium sandboxing', false)
|
|
64
|
+
.option('--rich-events', 'Mimics a heartbeat run')
|
|
65
|
+
.option(
|
|
66
|
+
'--capability <features...>',
|
|
67
|
+
'Enable capabilities through feature flags'
|
|
68
|
+
)
|
|
69
|
+
.addOption(
|
|
70
|
+
new Option('--screenshots [flag]', 'take screenshots at end of each step')
|
|
71
|
+
.choices(['on', 'off', 'only-on-failure'])
|
|
72
|
+
.default('on')
|
|
73
|
+
)
|
|
74
|
+
.option(
|
|
75
|
+
'--dry-run',
|
|
76
|
+
"don't actually execute anything, report only registered journeys"
|
|
77
|
+
)
|
|
78
|
+
.option(
|
|
79
|
+
'--match <name>',
|
|
80
|
+
'run only journeys with a name or tags that matches the glob'
|
|
81
|
+
)
|
|
82
|
+
.option(
|
|
83
|
+
'--tags <name...>',
|
|
84
|
+
'run only journeys with the given tag(s), or globs'
|
|
85
|
+
)
|
|
86
|
+
.option(
|
|
87
|
+
'--outfd <fd>',
|
|
88
|
+
'specify a file descriptor for logs. Default is stdout',
|
|
89
|
+
parseInt
|
|
90
|
+
)
|
|
91
|
+
.option(
|
|
92
|
+
'--ws-endpoint <endpoint>',
|
|
93
|
+
'Browser WebSocket endpoint to connect to'
|
|
94
|
+
)
|
|
95
|
+
.option(
|
|
96
|
+
'--pause-on-error',
|
|
97
|
+
'pause on error until a keypress is made in the console. Useful during development'
|
|
98
|
+
)
|
|
99
|
+
.option(
|
|
100
|
+
'--ignore-https-errors',
|
|
101
|
+
'ignores any HTTPS errors in sites being tested, including ones related to unrecognized certs or signatures. This can be insecure!'
|
|
102
|
+
)
|
|
103
|
+
.option(
|
|
104
|
+
'--quiet-exit-code',
|
|
105
|
+
'always return 0 as an exit code status, regardless of test pass / fail. Only return > 0 exit codes on internal errors where the suite could not be run'
|
|
106
|
+
)
|
|
107
|
+
.option(
|
|
108
|
+
'--throttling <d/u/l>',
|
|
109
|
+
'List of options to throttle network conditions for download throughput (d) in megabits/second, upload throughput (u) in megabits/second and latency (l) in milliseconds.',
|
|
110
|
+
DEFAULT_NETWORK_CONDITIONS_ARG
|
|
111
|
+
)
|
|
112
|
+
.option('--no-throttling', 'Turns off default network throttling.')
|
|
113
|
+
.option(
|
|
114
|
+
'--playwright-options <jsonstring>',
|
|
115
|
+
'JSON object to pass in custom Playwright options for the agent. Options passed will be merged with Playwright options defined in your synthetics.config.js file. Options defined via --playwright-options take precedence.',
|
|
116
|
+
JSON.parse
|
|
117
|
+
)
|
|
118
|
+
.version(version)
|
|
119
|
+
.description('Run synthetic tests')
|
|
120
|
+
.action(async (cliArgs: CliArgs) => {
|
|
121
|
+
try {
|
|
122
|
+
await loadTestFiles(cliArgs, program.args);
|
|
123
|
+
const options = normalizeOptions(cliArgs);
|
|
124
|
+
const results = await run(options);
|
|
125
|
+
/**
|
|
126
|
+
* Exit with error status if any journey fails
|
|
127
|
+
*/
|
|
128
|
+
if (!options.quietExitCode) {
|
|
129
|
+
for (const result of Object.values(results)) {
|
|
130
|
+
if (result.status === 'failed') {
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
119
133
|
}
|
|
120
|
-
});
|
|
121
|
-
} else {
|
|
122
|
-
addSuite(absPath);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
return suites.values();
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
(async () => {
|
|
129
|
-
/**
|
|
130
|
-
* Transform `.ts` files out of the box by invoking
|
|
131
|
-
* the `ts-node` via `transpile-only` mode that compiles
|
|
132
|
-
* TS files without doing any extensive type checks.
|
|
133
|
-
*
|
|
134
|
-
* We must register `ts-node` _before_ loading inline
|
|
135
|
-
* scripts too because otherwise we will not be able to
|
|
136
|
-
* require `.ts` configuration files.
|
|
137
|
-
*/
|
|
138
|
-
/* eslint-disable-next-line @typescript-eslint/no-var-requires */
|
|
139
|
-
require('ts-node').register({
|
|
140
|
-
transpileOnly: true,
|
|
141
|
-
compilerOptions: {
|
|
142
|
-
esModuleInterop: true,
|
|
143
|
-
allowJs: true,
|
|
144
|
-
target: 'es2018',
|
|
145
|
-
},
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
if (options.inline) {
|
|
149
|
-
const source = await readStdin();
|
|
150
|
-
loadInlineScript(source);
|
|
151
|
-
} else {
|
|
152
|
-
/**
|
|
153
|
-
* Preload modules before running the suites
|
|
154
|
-
*/
|
|
155
|
-
const modules = [].concat(options.require || []).filter(Boolean);
|
|
156
|
-
for (const name of modules) {
|
|
157
|
-
if (isDepInstalled(name)) {
|
|
158
|
-
require(name);
|
|
159
|
-
} else {
|
|
160
|
-
throw new Error(`cannot find module '${name}'`);
|
|
161
134
|
}
|
|
135
|
+
} catch (e) {
|
|
136
|
+
console.error(e);
|
|
137
|
+
process.exit(1);
|
|
162
138
|
}
|
|
163
|
-
|
|
164
|
-
* Handle piped files by reading the STDIN
|
|
165
|
-
* ex: ls example/suites/*.js | npx @elastic/synthetics
|
|
166
|
-
*/
|
|
167
|
-
const files =
|
|
168
|
-
program.args.length > 0
|
|
169
|
-
? program.args
|
|
170
|
-
: (await readStdin()).split('\n').filter(Boolean);
|
|
171
|
-
const suites = await prepareSuites(files);
|
|
172
|
-
requireSuites(suites);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Use the NODE_ENV variable to control the environment
|
|
177
|
-
*/
|
|
178
|
-
const environment = process.env['NODE_ENV'] || 'development';
|
|
179
|
-
/**
|
|
180
|
-
* Validate and handle configs
|
|
181
|
-
*/
|
|
182
|
-
const config =
|
|
183
|
-
options.config || !options.inline
|
|
184
|
-
? readConfig(environment, options.config)
|
|
185
|
-
: {};
|
|
186
|
-
const params = merge(config.params, options.params || {});
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Favor playwright options passed via cli to inline playwright options
|
|
190
|
-
*/
|
|
191
|
-
const playwrightOptions = merge.all([
|
|
192
|
-
config.playwrightOptions || {},
|
|
193
|
-
options.playwrightOptions || {},
|
|
194
|
-
{
|
|
195
|
-
headless: options.headless,
|
|
196
|
-
chromiumSandbox: options.sandbox,
|
|
197
|
-
ignoreHTTPSErrors: options.ignoreHttpsErrors,
|
|
198
|
-
},
|
|
199
|
-
]);
|
|
139
|
+
});
|
|
200
140
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
...options,
|
|
141
|
+
program
|
|
142
|
+
.command('push')
|
|
143
|
+
.description(
|
|
144
|
+
'Push monitors to create new montors with Kibana monitor management UI'
|
|
145
|
+
)
|
|
146
|
+
.action(() => {
|
|
147
|
+
throw new Error('TODO: Implement me');
|
|
209
148
|
});
|
|
210
149
|
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Exit with error status if any journey fails
|
|
214
|
-
*/
|
|
215
|
-
for (const result of Object.values(results)) {
|
|
216
|
-
if (result.status === 'failed') {
|
|
217
|
-
process.exit(1);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
})().catch(e => {
|
|
222
|
-
console.error(e);
|
|
223
|
-
process.exit(1);
|
|
224
|
-
});
|
|
150
|
+
program.parse(process.argv);
|
package/src/common_types.ts
CHANGED
|
@@ -31,18 +31,17 @@ import {
|
|
|
31
31
|
ChromiumBrowserContext,
|
|
32
32
|
Page,
|
|
33
33
|
} from 'playwright-chromium';
|
|
34
|
-
import { Protocol } from 'playwright-chromium/types/protocol';
|
|
35
34
|
import { Step } from './dsl';
|
|
36
|
-
import { reporters } from './reporters';
|
|
35
|
+
import { Reporter, reporters } from './reporters';
|
|
37
36
|
|
|
38
37
|
export type VoidCallback = () => void;
|
|
39
|
-
export type
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
uploadThroughput: number;
|
|
44
|
-
latency: number;
|
|
38
|
+
export type Location = {
|
|
39
|
+
file: string;
|
|
40
|
+
line: number;
|
|
41
|
+
column: number;
|
|
45
42
|
};
|
|
43
|
+
|
|
44
|
+
export type Params = Record<string, any>;
|
|
46
45
|
export type HooksArgs = {
|
|
47
46
|
env: string;
|
|
48
47
|
params: Params;
|
|
@@ -51,6 +50,13 @@ export type HooksCallback = (args: HooksArgs) => void;
|
|
|
51
50
|
export type StatusValue = 'succeeded' | 'failed' | 'skipped';
|
|
52
51
|
export type Reporters = keyof typeof reporters;
|
|
53
52
|
|
|
53
|
+
export type NetworkConditions = {
|
|
54
|
+
offline: boolean;
|
|
55
|
+
downloadThroughput: number;
|
|
56
|
+
uploadThroughput: number;
|
|
57
|
+
latency: number;
|
|
58
|
+
};
|
|
59
|
+
|
|
54
60
|
export type Driver = {
|
|
55
61
|
browser: ChromiumBrowser;
|
|
56
62
|
context: ChromiumBrowserContext;
|
|
@@ -123,11 +129,9 @@ export type Request = {
|
|
|
123
129
|
|
|
124
130
|
export type Response = {
|
|
125
131
|
url?: string;
|
|
126
|
-
protocol?: string;
|
|
127
132
|
status: number;
|
|
128
133
|
statusText?: string;
|
|
129
|
-
mimeType
|
|
130
|
-
httpVersion?: string;
|
|
134
|
+
mimeType?: string;
|
|
131
135
|
headers: Record<string, string>;
|
|
132
136
|
// Total size in bytes of the response (body and headers)
|
|
133
137
|
bytes?: number;
|
|
@@ -141,7 +145,6 @@ export type Response = {
|
|
|
141
145
|
remoteIPAddress?: string;
|
|
142
146
|
remotePort?: number;
|
|
143
147
|
fromServiceWorker?: boolean;
|
|
144
|
-
timing?: Protocol.Network.ResourceTiming;
|
|
145
148
|
};
|
|
146
149
|
|
|
147
150
|
export type NetworkInfo = {
|
|
@@ -149,19 +152,17 @@ export type NetworkInfo = {
|
|
|
149
152
|
browser: BrowserInfo;
|
|
150
153
|
type: string;
|
|
151
154
|
request: Request;
|
|
152
|
-
response
|
|
155
|
+
response: Response;
|
|
153
156
|
isNavigationRequest: boolean;
|
|
154
157
|
requestSentTime: number;
|
|
155
158
|
loadEndTime: number;
|
|
156
159
|
responseReceivedTime: number;
|
|
157
160
|
resourceSize: number;
|
|
158
161
|
transferSize: number;
|
|
159
|
-
timings
|
|
162
|
+
timings: {
|
|
160
163
|
blocked: number;
|
|
161
|
-
queueing: number;
|
|
162
164
|
dns: number;
|
|
163
165
|
ssl: number;
|
|
164
|
-
proxy: number;
|
|
165
166
|
connect: number;
|
|
166
167
|
send: number;
|
|
167
168
|
wait: number;
|
|
@@ -186,34 +187,44 @@ export type PluginOutput = {
|
|
|
186
187
|
|
|
187
188
|
export type ScreenshotOptions = 'on' | 'off' | 'only-on-failure';
|
|
188
189
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
config?: string;
|
|
192
|
-
outfd?: number;
|
|
193
|
-
headless?: boolean;
|
|
190
|
+
type BaseArgs = {
|
|
191
|
+
params?: Params;
|
|
194
192
|
screenshots?: ScreenshotOptions;
|
|
195
|
-
ssblocks?: boolean;
|
|
196
|
-
metrics?: boolean;
|
|
197
|
-
filmstrips?: boolean;
|
|
198
|
-
trace?: boolean;
|
|
199
193
|
dryRun?: boolean;
|
|
200
|
-
|
|
194
|
+
match?: string;
|
|
195
|
+
tags?: Array<string>;
|
|
196
|
+
outfd?: number;
|
|
197
|
+
wsEndpoint?: string;
|
|
201
198
|
pauseOnError?: boolean;
|
|
199
|
+
ignoreHttpsErrors?: boolean;
|
|
200
|
+
playwrightOptions?: PlaywrightOptions;
|
|
202
201
|
quietExitCode?: boolean;
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
export type CliArgs = BaseArgs & {
|
|
205
|
+
config?: string;
|
|
203
206
|
reporter?: Reporters;
|
|
204
|
-
wsEndpoint?: string;
|
|
205
|
-
sandbox?: boolean;
|
|
206
207
|
pattern?: string;
|
|
207
|
-
inline
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
208
|
+
inline?: boolean;
|
|
209
|
+
require?: Array<string>;
|
|
210
|
+
headless?: boolean;
|
|
211
|
+
sandbox?: boolean;
|
|
212
|
+
richEvents?: boolean;
|
|
213
|
+
capability?: Array<string>;
|
|
212
214
|
ignoreHttpsErrors?: boolean;
|
|
213
|
-
params?: Params;
|
|
214
215
|
throttling?: boolean | string;
|
|
215
|
-
|
|
216
|
-
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
export type RunOptions = BaseArgs & {
|
|
219
|
+
metrics?: boolean;
|
|
220
|
+
ssblocks?: boolean;
|
|
221
|
+
network?: boolean;
|
|
222
|
+
trace?: boolean;
|
|
223
|
+
filmstrips?: boolean;
|
|
224
|
+
environment?: string;
|
|
225
|
+
playwrightOptions?: PlaywrightOptions;
|
|
226
|
+
networkConditions?: NetworkConditions;
|
|
227
|
+
reporter?: CliArgs['reporter'] | Reporter;
|
|
217
228
|
};
|
|
218
229
|
|
|
219
230
|
export type PlaywrightOptions = LaunchOptions & BrowserContextOptions;
|
package/src/core/gatherer.ts
CHANGED
|
@@ -25,9 +25,8 @@
|
|
|
25
25
|
|
|
26
26
|
import { chromium, ChromiumBrowser, BrowserContext } from 'playwright-chromium';
|
|
27
27
|
import { PluginManager } from '../plugins';
|
|
28
|
-
import { RunOptions } from './runner';
|
|
29
28
|
import { log } from './logger';
|
|
30
|
-
import { Driver } from '../common_types';
|
|
29
|
+
import { Driver, RunOptions } from '../common_types';
|
|
31
30
|
|
|
32
31
|
/**
|
|
33
32
|
* Purpose of the Gatherer is to set up the necessary browser driver
|
|
@@ -58,7 +57,7 @@ export class Gatherer {
|
|
|
58
57
|
...playwrightOptions,
|
|
59
58
|
userAgent: await Gatherer.getUserAgent(playwrightOptions?.userAgent),
|
|
60
59
|
});
|
|
61
|
-
|
|
60
|
+
Gatherer.setNetworkConditions(context, networkConditions);
|
|
62
61
|
|
|
63
62
|
const page = await context.newPage();
|
|
64
63
|
const client = await context.newCDPSession(page);
|
|
@@ -74,18 +73,26 @@ export class Gatherer {
|
|
|
74
73
|
return userAgent + syntheticsIdentifier;
|
|
75
74
|
}
|
|
76
75
|
|
|
77
|
-
static
|
|
76
|
+
static setNetworkConditions(
|
|
78
77
|
context: BrowserContext,
|
|
79
78
|
networkConditions: RunOptions['networkConditions']
|
|
80
79
|
) {
|
|
81
80
|
if (networkConditions) {
|
|
82
|
-
context.on('page',
|
|
81
|
+
context.on('page', page => {
|
|
83
82
|
const context = page.context();
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
83
|
+
const emulatePromise = context
|
|
84
|
+
.newCDPSession(page)
|
|
85
|
+
.then(client =>
|
|
86
|
+
client.send('Network.emulateNetworkConditions', networkConditions)
|
|
87
|
+
);
|
|
88
|
+
/**
|
|
89
|
+
* Guard against pages that gets closed before the emulation kicks to capture
|
|
90
|
+
* unhandled rejections from accessing the CDP session of closed page
|
|
91
|
+
*/
|
|
92
|
+
Promise.race([
|
|
93
|
+
new Promise<void>(resolve => page.on('close', () => resolve())),
|
|
94
|
+
emulatePromise,
|
|
95
|
+
]);
|
|
89
96
|
});
|
|
90
97
|
}
|
|
91
98
|
}
|
package/src/core/index.ts
CHANGED
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
|
|
26
26
|
import { Journey, JourneyCallback, JourneyOptions } from '../dsl';
|
|
27
27
|
import Runner from './runner';
|
|
28
|
-
import { VoidCallback, HooksCallback } from '../common_types';
|
|
28
|
+
import { VoidCallback, HooksCallback, Location } from '../common_types';
|
|
29
|
+
import { wrapFnWithLocation } from '../helpers';
|
|
29
30
|
import { log } from './logger';
|
|
30
31
|
|
|
31
32
|
/**
|
|
@@ -39,23 +40,28 @@ if (!global[SYNTHETICS_RUNNER]) {
|
|
|
39
40
|
|
|
40
41
|
export const runner: Runner = global[SYNTHETICS_RUNNER];
|
|
41
42
|
|
|
42
|
-
export const journey = (
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
export const journey = wrapFnWithLocation(
|
|
44
|
+
(
|
|
45
|
+
location: Location,
|
|
46
|
+
options: JourneyOptions | string,
|
|
47
|
+
callback: JourneyCallback
|
|
48
|
+
) => {
|
|
49
|
+
log(`register journey: ${JSON.stringify(options)}`);
|
|
50
|
+
if (typeof options === 'string') {
|
|
51
|
+
options = { name: options, id: options };
|
|
52
|
+
}
|
|
53
|
+
const j = new Journey(options, callback, location);
|
|
54
|
+
runner.addJourney(j);
|
|
55
|
+
return j;
|
|
49
56
|
}
|
|
50
|
-
|
|
51
|
-
runner.addJourney(j);
|
|
52
|
-
return j;
|
|
53
|
-
};
|
|
57
|
+
);
|
|
54
58
|
|
|
55
|
-
export const step = (
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
+
export const step = wrapFnWithLocation(
|
|
60
|
+
(location: Location, name: string, callback: VoidCallback) => {
|
|
61
|
+
log(`register step: ${name}`);
|
|
62
|
+
return runner.currentJourney?.addStep(name, callback, location);
|
|
63
|
+
}
|
|
64
|
+
);
|
|
59
65
|
|
|
60
66
|
export const beforeAll = (callback: HooksCallback) => {
|
|
61
67
|
runner.addHook('beforeAll', callback);
|
package/src/core/runner.ts
CHANGED
|
@@ -28,7 +28,7 @@ import { join } from 'path';
|
|
|
28
28
|
import { rm } from 'fs/promises';
|
|
29
29
|
import { Journey } from '../dsl/journey';
|
|
30
30
|
import { Step } from '../dsl/step';
|
|
31
|
-
import { reporters
|
|
31
|
+
import { reporters } from '../reporters';
|
|
32
32
|
import {
|
|
33
33
|
CACHE_PATH,
|
|
34
34
|
monotonicTimeInSeconds,
|
|
@@ -44,36 +44,16 @@ import {
|
|
|
44
44
|
Params,
|
|
45
45
|
NetworkConditions,
|
|
46
46
|
PluginOutput,
|
|
47
|
-
CliArgs,
|
|
48
47
|
HooksArgs,
|
|
49
|
-
PlaywrightOptions,
|
|
50
48
|
Driver,
|
|
51
49
|
Screenshot,
|
|
50
|
+
RunOptions,
|
|
52
51
|
} from '../common_types';
|
|
53
52
|
import { PageMetrics, PluginManager } from '../plugins';
|
|
54
53
|
import { PerformanceManager } from '../plugins';
|
|
55
54
|
import { Gatherer } from './gatherer';
|
|
56
55
|
import { log } from './logger';
|
|
57
56
|
|
|
58
|
-
export type RunOptions = Omit<
|
|
59
|
-
CliArgs,
|
|
60
|
-
| 'debug'
|
|
61
|
-
| 'pattern'
|
|
62
|
-
| 'inline'
|
|
63
|
-
| 'require'
|
|
64
|
-
| 'reporter'
|
|
65
|
-
| 'richEvents'
|
|
66
|
-
| 'capability'
|
|
67
|
-
| 'sandbox'
|
|
68
|
-
| 'headless'
|
|
69
|
-
| 'throttling'
|
|
70
|
-
> & {
|
|
71
|
-
environment?: string;
|
|
72
|
-
playwrightOptions?: PlaywrightOptions;
|
|
73
|
-
networkConditions?: NetworkConditions;
|
|
74
|
-
reporter?: CliArgs['reporter'] | Reporter;
|
|
75
|
-
};
|
|
76
|
-
|
|
77
57
|
type HookType = 'beforeAll' | 'afterAll';
|
|
78
58
|
export type SuiteHooks = Record<HookType, Array<HooksCallback>>;
|
|
79
59
|
|
|
@@ -352,7 +332,7 @@ export default class Runner extends EventEmitter {
|
|
|
352
332
|
) {
|
|
353
333
|
const end = monotonicTimeInSeconds();
|
|
354
334
|
const { pluginManager, start, status, error } = result;
|
|
355
|
-
const pluginOutput = pluginManager.output();
|
|
335
|
+
const pluginOutput = await pluginManager.output();
|
|
356
336
|
this.emit('journey:end', {
|
|
357
337
|
journey,
|
|
358
338
|
status,
|
package/src/dsl/journey.ts
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
import { Browser, Page, BrowserContext, CDPSession } from 'playwright-chromium';
|
|
27
27
|
import micromatch, { isMatch } from 'micromatch';
|
|
28
28
|
import { Step } from './step';
|
|
29
|
-
import { VoidCallback, HooksCallback, Params } from '../common_types';
|
|
29
|
+
import { VoidCallback, HooksCallback, Params, Location } from '../common_types';
|
|
30
30
|
|
|
31
31
|
export type JourneyOptions = {
|
|
32
32
|
name: string;
|
|
@@ -49,18 +49,24 @@ export class Journey {
|
|
|
49
49
|
id?: string;
|
|
50
50
|
tags?: string[];
|
|
51
51
|
callback: JourneyCallback;
|
|
52
|
+
location?: Location;
|
|
52
53
|
steps: Step[] = [];
|
|
53
54
|
hooks: Hooks = { before: [], after: [] };
|
|
54
55
|
|
|
55
|
-
constructor(
|
|
56
|
+
constructor(
|
|
57
|
+
options: JourneyOptions,
|
|
58
|
+
callback: JourneyCallback,
|
|
59
|
+
location?: Location
|
|
60
|
+
) {
|
|
56
61
|
this.name = options.name;
|
|
57
62
|
this.id = options.id || options.name;
|
|
58
63
|
this.tags = options.tags;
|
|
59
64
|
this.callback = callback;
|
|
65
|
+
this.location = location;
|
|
60
66
|
}
|
|
61
67
|
|
|
62
|
-
addStep(name: string, callback: VoidCallback) {
|
|
63
|
-
const step = new Step(name, this.steps.length + 1, callback);
|
|
68
|
+
addStep(name: string, callback: VoidCallback, location?: Location) {
|
|
69
|
+
const step = new Step(name, this.steps.length + 1, callback, location);
|
|
64
70
|
this.steps.push(step);
|
|
65
71
|
return step;
|
|
66
72
|
}
|
package/src/dsl/step.ts
CHANGED
|
@@ -23,16 +23,23 @@
|
|
|
23
23
|
*
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
import { VoidCallback } from '../common_types';
|
|
26
|
+
import { Location, VoidCallback } from '../common_types';
|
|
27
27
|
|
|
28
28
|
export class Step {
|
|
29
29
|
name: string;
|
|
30
30
|
index: number;
|
|
31
31
|
callback: VoidCallback;
|
|
32
|
+
location?: Location;
|
|
32
33
|
|
|
33
|
-
constructor(
|
|
34
|
+
constructor(
|
|
35
|
+
name: string,
|
|
36
|
+
index: number,
|
|
37
|
+
callback: VoidCallback,
|
|
38
|
+
location: Location
|
|
39
|
+
) {
|
|
34
40
|
this.name = name;
|
|
35
41
|
this.index = index;
|
|
36
42
|
this.callback = callback;
|
|
43
|
+
this.location = location;
|
|
37
44
|
}
|
|
38
45
|
}
|