@elastic/synthetics 1.0.0-beta.8 → 1.0.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 +5 -4
- package/dist/cli.js +139 -165
- package/dist/cli.js.map +1 -1
- package/dist/common_types.d.ts +158 -34
- package/dist/common_types.d.ts.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +7 -6
- package/dist/config.js.map +1 -1
- package/dist/core/browser-service.d.ts +1 -1
- package/dist/core/browser-service.d.ts.map +1 -1
- package/dist/core/browser-service.js +7 -6
- package/dist/core/browser-service.js.map +1 -1
- package/dist/core/expect.d.ts +25 -25
- package/dist/core/expect.d.ts.map +1 -1
- package/dist/core/expect.js.map +1 -1
- package/dist/core/gatherer.d.ts +5 -8
- package/dist/core/gatherer.d.ts.map +1 -1
- package/dist/core/gatherer.js +75 -17
- package/dist/core/gatherer.js.map +1 -1
- package/dist/core/index.d.ts +5 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +23 -11
- package/dist/core/index.js.map +1 -1
- package/dist/core/logger.d.ts +0 -1
- package/dist/core/logger.d.ts.map +1 -1
- package/dist/core/logger.js +10 -17
- package/dist/core/logger.js.map +1 -1
- package/dist/core/runner.d.ts +12 -63
- package/dist/core/runner.d.ts.map +1 -1
- package/dist/core/runner.js +159 -92
- package/dist/core/runner.js.map +1 -1
- package/dist/core/transform.d.ts +37 -0
- package/dist/core/transform.d.ts.map +1 -0
- package/dist/core/transform.js +148 -0
- package/dist/core/transform.js.map +1 -0
- package/dist/dsl/index.js +5 -1
- package/dist/dsl/index.js.map +1 -1
- package/dist/dsl/journey.d.ts +9 -7
- package/dist/dsl/journey.d.ts.map +1 -1
- package/dist/dsl/journey.js +32 -39
- package/dist/dsl/journey.js.map +1 -1
- package/dist/dsl/monitor.d.ts +93 -0
- package/dist/dsl/monitor.d.ts.map +1 -0
- package/dist/dsl/monitor.js +110 -0
- package/dist/dsl/monitor.js.map +1 -0
- package/dist/dsl/step.d.ts +3 -2
- package/dist/dsl/step.d.ts.map +1 -1
- package/dist/dsl/step.js +6 -1
- package/dist/dsl/step.js.map +1 -1
- package/dist/formatter/javascript.d.ts +115 -0
- package/dist/formatter/javascript.d.ts.map +1 -0
- package/dist/formatter/javascript.js +331 -0
- package/dist/formatter/javascript.js.map +1 -0
- package/dist/generator/index.d.ts +24 -0
- package/dist/generator/index.d.ts.map +1 -0
- package/dist/generator/index.js +241 -0
- package/dist/generator/index.js.map +1 -0
- package/dist/{reporters/reporter.js → generator/utils.d.ts} +5 -3
- package/dist/generator/utils.d.ts.map +1 -0
- package/dist/generator/utils.js +84 -0
- package/dist/generator/utils.js.map +1 -0
- package/dist/helpers.d.ts +36 -9
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +170 -24
- package/dist/helpers.js.map +1 -1
- package/dist/index.d.ts +5 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -26
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +34 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +153 -0
- package/dist/loader.js.map +1 -0
- package/dist/locations/index.d.ts +45 -0
- package/dist/locations/index.d.ts.map +1 -0
- package/dist/locations/index.js +83 -0
- package/dist/locations/index.js.map +1 -0
- package/dist/{reporters/reporter.d.ts → locations/public-locations.d.ts} +12 -8
- package/dist/locations/public-locations.d.ts.map +1 -0
- package/dist/locations/public-locations.js +41 -0
- package/dist/locations/public-locations.js.map +1 -0
- package/dist/options.d.ts +42 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +146 -0
- package/dist/options.js.map +1 -0
- package/dist/plugins/browser-console.d.ts +5 -4
- package/dist/plugins/browser-console.d.ts.map +1 -1
- package/dist/plugins/browser-console.js +47 -24
- package/dist/plugins/browser-console.js.map +1 -1
- package/dist/plugins/index.js +5 -1
- package/dist/plugins/index.js.map +1 -1
- package/dist/plugins/network.d.ts +24 -31
- package/dist/plugins/network.d.ts.map +1 -1
- package/dist/plugins/network.js +226 -229
- package/dist/plugins/network.js.map +1 -1
- package/dist/plugins/performance.d.ts +4 -19
- package/dist/plugins/performance.d.ts.map +1 -1
- package/dist/plugins/performance.js +6 -5
- package/dist/plugins/performance.js.map +1 -1
- package/dist/plugins/plugin-manager.d.ts +9 -5
- package/dist/plugins/plugin-manager.d.ts.map +1 -1
- package/dist/plugins/plugin-manager.js +46 -30
- package/dist/plugins/plugin-manager.js.map +1 -1
- package/dist/plugins/tracing.d.ts +6 -6
- package/dist/plugins/tracing.d.ts.map +1 -1
- package/dist/plugins/tracing.js +13 -7
- package/dist/plugins/tracing.js.map +1 -1
- package/dist/push/bundler.d.ts +35 -0
- package/dist/push/bundler.d.ts.map +1 -0
- package/dist/push/bundler.js +131 -0
- package/dist/push/bundler.js.map +1 -0
- package/dist/push/index.d.ts +10 -0
- package/dist/push/index.d.ts.map +1 -0
- package/dist/push/index.js +235 -0
- package/dist/push/index.js.map +1 -0
- package/dist/push/kibana_api.d.ts +56 -0
- package/dist/push/kibana_api.d.ts.map +1 -0
- package/dist/push/kibana_api.js +135 -0
- package/dist/push/kibana_api.js.map +1 -0
- package/dist/push/monitor.d.ts +55 -0
- package/dist/push/monitor.d.ts.map +1 -0
- package/dist/push/monitor.js +268 -0
- package/dist/push/monitor.js.map +1 -0
- package/dist/{parse_args.d.ts → push/plugin.d.ts} +9 -6
- package/dist/push/plugin.d.ts.map +1 -0
- package/dist/push/plugin.js +66 -0
- package/dist/push/plugin.js.map +1 -0
- package/dist/push/request.d.ts +45 -0
- package/dist/push/request.d.ts.map +1 -0
- package/dist/push/request.js +109 -0
- package/dist/push/request.js.map +1 -0
- package/dist/push/utils.d.ts +31 -0
- package/dist/push/utils.d.ts.map +1 -0
- package/dist/push/utils.js +64 -0
- package/dist/push/utils.js.map +1 -0
- package/dist/reporters/base.d.ts +14 -6
- package/dist/reporters/base.d.ts.map +1 -1
- package/dist/reporters/base.js +58 -50
- package/dist/reporters/base.js.map +1 -1
- package/dist/reporters/index.d.ts +18 -8
- package/dist/reporters/index.d.ts.map +1 -1
- package/dist/reporters/index.js.map +1 -1
- package/dist/reporters/json.d.ts +17 -62
- package/dist/reporters/json.d.ts.map +1 -1
- package/dist/reporters/json.js +147 -177
- package/dist/reporters/json.js.map +1 -1
- package/dist/reporters/junit.d.ts +7 -1
- package/dist/reporters/junit.d.ts.map +1 -1
- package/dist/reporters/junit.js +90 -95
- package/dist/reporters/junit.js.map +1 -1
- package/dist/sdk/lh-trace-processor.d.ts +35 -9
- package/dist/sdk/lh-trace-processor.d.ts.map +1 -1
- package/dist/sdk/lh-trace-processor.js +114 -53
- package/dist/sdk/lh-trace-processor.js.map +1 -1
- package/dist/sdk/trace-metrics.d.ts +4 -4
- package/dist/sdk/trace-metrics.d.ts.map +1 -1
- package/dist/sdk/trace-metrics.js +3 -4
- package/dist/sdk/trace-metrics.js.map +1 -1
- package/dist/sdk/trace-processor.d.ts +11 -3
- package/dist/sdk/trace-processor.d.ts.map +1 -1
- package/dist/sdk/trace-processor.js +17 -9
- package/dist/sdk/trace-processor.js.map +1 -1
- package/package.json +38 -30
- package/src/cli.ts +223 -158
- package/src/common_types.ts +191 -34
- package/src/config.ts +1 -1
- package/src/core/expect.ts +58 -24
- package/src/core/gatherer.ts +92 -25
- package/src/core/index.ts +36 -15
- package/src/core/logger.ts +8 -12
- package/src/core/runner.ts +158 -148
- package/src/core/transform.ts +160 -0
- package/src/dsl/journey.ts +41 -21
- package/src/dsl/monitor.ts +152 -0
- package/src/dsl/step.ts +9 -2
- package/src/formatter/javascript.ts +414 -0
- package/src/generator/index.ts +308 -0
- package/src/generator/utils.ts +84 -0
- package/src/helpers.ts +182 -16
- package/src/index.ts +21 -22
- package/src/loader.ts +171 -0
- package/src/locations/index.ts +95 -0
- package/src/{reporters/reporter.ts → locations/public-locations.ts} +12 -9
- package/src/options.ts +175 -0
- package/src/plugins/browser-console.ts +33 -8
- package/src/plugins/network.ts +266 -284
- package/src/plugins/performance.ts +6 -22
- package/src/plugins/plugin-manager.ts +49 -31
- package/src/plugins/tracing.ts +11 -9
- package/src/push/bundler.ts +112 -0
- package/src/push/index.ts +291 -0
- package/src/push/kibana_api.ts +191 -0
- package/src/push/monitor.ts +307 -0
- package/src/push/plugin.ts +66 -0
- package/src/push/request.ts +141 -0
- package/src/push/utils.ts +77 -0
- package/src/reporters/base.ts +63 -52
- package/src/reporters/index.ts +26 -3
- package/src/reporters/json.ts +181 -201
- package/src/reporters/junit.ts +98 -93
- package/src/sdk/lh-trace-processor.ts +132 -68
- package/src/sdk/trace-metrics.ts +8 -4
- package/src/sdk/trace-processor.ts +28 -13
- package/templates/.github/workflows/run-synthetics.yml +27 -0
- package/templates/README.md +21 -0
- package/templates/journeys/advanced-example-helpers.ts +54 -0
- package/templates/journeys/advanced-example.journey.ts +43 -0
- package/templates/journeys/example.journey.ts +18 -0
- package/templates/lightweight/heartbeat.yml +9 -0
- package/templates/synthetics.config.ts +35 -0
- package/CHANGELOG.md +0 -181
- package/NOTICE.txt +0 -221
- package/dist/parse_args.d.ts.map +0 -1
- package/dist/parse_args.js +0 -98
- package/dist/parse_args.js.map +0 -1
- package/dist/reporters/reporter.d.ts.map +0 -1
- package/dist/reporters/reporter.js.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1895
- package/src/parse_args.ts +0 -146
package/src/reporters/junit.ts
CHANGED
|
@@ -23,8 +23,14 @@
|
|
|
23
23
|
*
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
import {
|
|
26
|
+
import { mkdir, writeFile } from 'fs/promises';
|
|
27
27
|
import { dirname } from 'path';
|
|
28
|
+
import {
|
|
29
|
+
JourneyEndResult,
|
|
30
|
+
JourneyStartResult,
|
|
31
|
+
StepEndResult,
|
|
32
|
+
} from '../common_types';
|
|
33
|
+
import { Journey, Step } from '../dsl';
|
|
28
34
|
import { formatError, indent, now } from '../helpers';
|
|
29
35
|
import BaseReporter from './base';
|
|
30
36
|
|
|
@@ -51,104 +57,103 @@ export default class JUnitReporter extends BaseReporter {
|
|
|
51
57
|
private totalTests = 0;
|
|
52
58
|
private totalFailures = 0;
|
|
53
59
|
private totalSkipped = 0;
|
|
60
|
+
#journeyMap = new Map<string, XMLEntry>();
|
|
54
61
|
|
|
55
|
-
|
|
56
|
-
|
|
62
|
+
override onJourneyStart(journey: Journey, {}: JourneyStartResult) {
|
|
63
|
+
if (!this.#journeyMap.has(journey.name)) {
|
|
64
|
+
const entry = {
|
|
65
|
+
name: 'testsuite',
|
|
66
|
+
attributes: {
|
|
67
|
+
name: journey.name,
|
|
68
|
+
tests: 0,
|
|
69
|
+
failures: 0,
|
|
70
|
+
skipped: 0,
|
|
71
|
+
errors: 0,
|
|
72
|
+
},
|
|
73
|
+
children: [],
|
|
74
|
+
};
|
|
75
|
+
this.#journeyMap.set(journey.name, entry);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
57
78
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
79
|
+
override onStepEnd(
|
|
80
|
+
journey: Journey,
|
|
81
|
+
step: Step,
|
|
82
|
+
{ status, error, start, end }: StepEndResult
|
|
83
|
+
) {
|
|
84
|
+
if (!this.#journeyMap.has(journey.name)) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const entry = this.#journeyMap.get(journey.name);
|
|
88
|
+
const caseEntry = {
|
|
89
|
+
name: 'testcase',
|
|
90
|
+
attributes: {
|
|
91
|
+
name: step.name,
|
|
92
|
+
classname: journey.name + ' ' + step.name,
|
|
93
|
+
time: end - start,
|
|
94
|
+
},
|
|
95
|
+
children: [],
|
|
96
|
+
};
|
|
74
97
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
98
|
+
entry.attributes.tests++;
|
|
99
|
+
if (status === 'failed') {
|
|
100
|
+
const { name, message, stack } = formatError(error);
|
|
101
|
+
caseEntry.children.push({
|
|
102
|
+
name: 'failure',
|
|
103
|
+
attributes: {
|
|
104
|
+
message,
|
|
105
|
+
type: name,
|
|
106
|
+
},
|
|
107
|
+
text: stack,
|
|
108
|
+
});
|
|
109
|
+
entry.attributes.failures++;
|
|
110
|
+
} else if (status === 'skipped') {
|
|
111
|
+
caseEntry.children.push({
|
|
112
|
+
name: 'skipped',
|
|
113
|
+
attributes: {
|
|
114
|
+
message: 'previous step failed',
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
entry.attributes.skipped++;
|
|
118
|
+
}
|
|
119
|
+
entry.children.push(caseEntry);
|
|
120
|
+
}
|
|
91
121
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
text: stack,
|
|
102
|
-
});
|
|
103
|
-
entry.attributes.failures++;
|
|
104
|
-
} else if (status === 'skipped') {
|
|
105
|
-
caseEntry.children.push({
|
|
106
|
-
name: 'skipped',
|
|
107
|
-
attributes: {
|
|
108
|
-
message: 'previous step failed',
|
|
109
|
-
},
|
|
110
|
-
});
|
|
111
|
-
entry.attributes.skipped++;
|
|
112
|
-
}
|
|
113
|
-
entry.children.push(caseEntry);
|
|
114
|
-
}
|
|
115
|
-
);
|
|
122
|
+
override onJourneyEnd(journey: Journey, {}: JourneyEndResult) {
|
|
123
|
+
if (!this.#journeyMap.has(journey.name)) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const { attributes } = this.#journeyMap.get(journey.name);
|
|
127
|
+
this.totalTests += attributes.tests;
|
|
128
|
+
this.totalFailures += attributes.failures;
|
|
129
|
+
this.totalSkipped += attributes.skipped;
|
|
130
|
+
}
|
|
116
131
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
132
|
+
override async onEnd() {
|
|
133
|
+
const root: XMLEntry = {
|
|
134
|
+
name: 'testsuites',
|
|
135
|
+
attributes: {
|
|
136
|
+
name: '',
|
|
137
|
+
tests: this.totalTests,
|
|
138
|
+
failures: this.totalFailures,
|
|
139
|
+
skipped: this.totalSkipped,
|
|
140
|
+
errors: 0,
|
|
141
|
+
time: parseInt(String(now())) / 1000,
|
|
142
|
+
},
|
|
143
|
+
children: [...this.#journeyMap.values()],
|
|
144
|
+
};
|
|
126
145
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
children: [...journeyMap.values()],
|
|
139
|
-
};
|
|
140
|
-
const output = serializeEntries(root).join('\n');
|
|
141
|
-
/**
|
|
142
|
-
* write the xml output to a file if specified via env flag
|
|
143
|
-
*/
|
|
144
|
-
const fileName = process.env['SYNTHETICS_JUNIT_FILE'];
|
|
145
|
-
if (fileName) {
|
|
146
|
-
mkdirSync(dirname(fileName), { recursive: true });
|
|
147
|
-
writeFileSync(fileName, output);
|
|
148
|
-
} else {
|
|
149
|
-
this.write(output);
|
|
150
|
-
}
|
|
151
|
-
});
|
|
146
|
+
const output = serializeEntries(root).join('\n');
|
|
147
|
+
/**
|
|
148
|
+
* write the xml output to a file if specified via env flag
|
|
149
|
+
*/
|
|
150
|
+
const fileName = process.env['SYNTHETICS_JUNIT_FILE'];
|
|
151
|
+
if (fileName) {
|
|
152
|
+
await mkdir(dirname(fileName), { recursive: true });
|
|
153
|
+
await writeFile(fileName, output);
|
|
154
|
+
} else {
|
|
155
|
+
this.write(output);
|
|
156
|
+
}
|
|
152
157
|
}
|
|
153
158
|
}
|
|
154
159
|
|
|
@@ -16,10 +16,8 @@
|
|
|
16
16
|
* 4. Return all those items in one handy bundle.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
/** @typedef {Omit<LH.Artifacts.
|
|
20
|
-
/** @typedef {
|
|
21
|
-
/** @typedef {Omit<LH.Artifacts.TraceOfTab, 'firstContentfulPaintEvt'|'firstContentfulPaintAllFramesEvt'|'timings'|'timestamps'> & {timings: TraceTimesWithoutFCP, timestamps: TraceTimesWithoutFCP, firstContentfulPaintEvt?: LH.Artifacts.TraceOfTab['firstContentfulPaintEvt'], firstContentfulPaintAllFramesEvt?: LH.Artifacts.TraceOfTab['largestContentfulPaintAllFramesEvt']}} TraceOfTabWithoutFCP */
|
|
22
|
-
/** @typedef {'lastNavigationStart'|'firstResourceSendRequest'} TimeOriginDeterminationMethod */
|
|
19
|
+
/** @typedef {Omit<LH.Artifacts.NavigationTraceTimes, 'firstContentfulPaintAllFrames'|'traceEnd'>} TraceNavigationTimesForFrame */
|
|
20
|
+
/** @typedef {'lastNavigationStart'|'firstResourceSendRequest'|'lighthouseMarker'|'auto'} TimeOriginDeterminationMethod */
|
|
23
21
|
/** @typedef {Omit<LH.TraceEvent, 'name'|'args'> & {name: 'FrameCommittedInBrowser', args: {data: {frame: string, url: string, parent?: string}}}} FrameCommittedEvent */
|
|
24
22
|
/** @typedef {Omit<LH.TraceEvent, 'name'|'args'> & {name: 'largestContentfulPaint::Invalidate'|'largestContentfulPaint::Candidate', args: {data?: {size?: number}, frame: string}}} LCPEvent */
|
|
25
23
|
/** @typedef {Omit<LH.TraceEvent, 'name'|'args'> & {name: 'largestContentfulPaint::Candidate', args: {data: {size: number}, frame: string}}} LCPCandidateEvent */
|
|
@@ -42,6 +40,10 @@ const SCHEDULABLE_TASK_TITLE_ALT3 =
|
|
|
42
40
|
'TaskQueueManager::ProcessTaskFromWorkQueue';
|
|
43
41
|
|
|
44
42
|
class TraceProcessor {
|
|
43
|
+
static get TIMESPAN_MARKER_ID() {
|
|
44
|
+
return '__lighthouseTimespanStart__';
|
|
45
|
+
}
|
|
46
|
+
|
|
45
47
|
/**
|
|
46
48
|
* @return {Error}
|
|
47
49
|
*/
|
|
@@ -63,6 +65,20 @@ class TraceProcessor {
|
|
|
63
65
|
return new Error('No tracingStartedInBrowser event found');
|
|
64
66
|
}
|
|
65
67
|
|
|
68
|
+
/**
|
|
69
|
+
* @return {Error}
|
|
70
|
+
*/
|
|
71
|
+
static createNoFirstContentfulPaintError() {
|
|
72
|
+
return new Error('No FirstContentfulPaint event found');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @return {Error}
|
|
77
|
+
*/
|
|
78
|
+
static createNoLighthouseMarkerError() {
|
|
79
|
+
return new Error('No Lighthouse timespan marker event found');
|
|
80
|
+
}
|
|
81
|
+
|
|
66
82
|
/**
|
|
67
83
|
* Returns true if the event is a navigation start event of a document whose URL seems valid.
|
|
68
84
|
*
|
|
@@ -101,16 +117,16 @@ class TraceProcessor {
|
|
|
101
117
|
traceEvents
|
|
102
118
|
) {
|
|
103
119
|
/*
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
120
|
+
* We have two different sets of indices going on here.
|
|
121
|
+
|
|
122
|
+
* 1. There's the index for an element of `traceEvents`, referred to here as an `ArrayIndex`.
|
|
123
|
+
* `timestampSortedIndices` is an array of `ArrayIndex` elements.
|
|
124
|
+
* 2. There's the index for an element of `timestampSortedIndices`, referred to here as a `TsIndex`.
|
|
125
|
+
* A `TsIndex` is therefore an index to an element which is itself an index.
|
|
126
|
+
*
|
|
127
|
+
* These two helper functions help resolve this layer of indirection.
|
|
128
|
+
* Our final return value is an array of `ArrayIndex` in their final sort order.
|
|
129
|
+
*/
|
|
114
130
|
/** @param {number} i */
|
|
115
131
|
const lookupArrayIndexByTsIndex = i => timestampSortedIndices[i];
|
|
116
132
|
/** @param {number} i */
|
|
@@ -406,25 +422,21 @@ class TraceProcessor {
|
|
|
406
422
|
}
|
|
407
423
|
|
|
408
424
|
/**
|
|
409
|
-
* Provides the top level events on the main thread with timestamps in ms relative to
|
|
425
|
+
* Provides the top level events on the main thread with timestamps in ms relative to timeOrigin.
|
|
410
426
|
* start.
|
|
411
|
-
* @param {LH.Artifacts.
|
|
427
|
+
* @param {LH.Artifacts.ProcessedTrace} trace
|
|
412
428
|
* @param {number=} startTime Optional start time (in ms relative to timeOrigin) of range of interest. Defaults to 0.
|
|
413
429
|
* @param {number=} endTime Optional end time (in ms relative to timeOrigin) of range of interest. Defaults to trace end.
|
|
414
430
|
* @return {Array<ToplevelEvent>}
|
|
415
431
|
*/
|
|
416
|
-
static getMainThreadTopLevelEvents(
|
|
417
|
-
tabTrace,
|
|
418
|
-
startTime = 0,
|
|
419
|
-
endTime = Infinity
|
|
420
|
-
) {
|
|
432
|
+
static getMainThreadTopLevelEvents(trace, startTime = 0, endTime = Infinity) {
|
|
421
433
|
const topLevelEvents = [];
|
|
422
434
|
// note: mainThreadEvents is already sorted by event start
|
|
423
|
-
for (const event of
|
|
435
|
+
for (const event of trace.mainThreadEvents) {
|
|
424
436
|
if (!this.isScheduleableTask(event) || !event.dur) continue;
|
|
425
437
|
|
|
426
|
-
const start = (event.ts -
|
|
427
|
-
const end = (event.ts + event.dur -
|
|
438
|
+
const start = (event.ts - trace.timeOriginEvt.ts) / 1000;
|
|
439
|
+
const end = (event.ts + event.dur - trace.timeOriginEvt.ts) / 1000;
|
|
428
440
|
if (start > endTime || end < startTime) continue;
|
|
429
441
|
|
|
430
442
|
topLevelEvents.push({
|
|
@@ -651,11 +663,10 @@ class TraceProcessor {
|
|
|
651
663
|
* in milliseconds since the time origin in addition to the standard microsecond monotonic timestamps.
|
|
652
664
|
* @param {LH.Trace} trace
|
|
653
665
|
* @param {{timeOriginDeterminationMethod?: TimeOriginDeterminationMethod}} [options]
|
|
654
|
-
* @return {
|
|
666
|
+
* @return {LH.Artifacts.ProcessedTrace}
|
|
655
667
|
*/
|
|
656
|
-
static
|
|
657
|
-
const { timeOriginDeterminationMethod = '
|
|
658
|
-
options || {};
|
|
668
|
+
static processTrace(trace, options) {
|
|
669
|
+
const { timeOriginDeterminationMethod = 'auto' } = options || {};
|
|
659
670
|
|
|
660
671
|
// Parse the trace for our key events and sort them by timestamp. Note: sort
|
|
661
672
|
// *must* be stable to keep events correctly nested.
|
|
@@ -722,22 +733,6 @@ class TraceProcessor {
|
|
|
722
733
|
timeOriginDeterminationMethod
|
|
723
734
|
);
|
|
724
735
|
|
|
725
|
-
// Compute the key frame timings for the main frame.
|
|
726
|
-
const frameTimings = this.computeKeyTimingsForFrame(frameEvents, {
|
|
727
|
-
timeOriginEvt,
|
|
728
|
-
});
|
|
729
|
-
|
|
730
|
-
// Compute FCP for all frames.
|
|
731
|
-
const fcpAllFramesEvt = frameTreeEvents.find(
|
|
732
|
-
e => e.name === 'firstContentfulPaint' && e.ts > timeOriginEvt.ts
|
|
733
|
-
);
|
|
734
|
-
|
|
735
|
-
// Compute LCP for all frames.
|
|
736
|
-
const lcpAllFramesEvt = this.computeValidLCPAllFrames(
|
|
737
|
-
frameTreeEvents,
|
|
738
|
-
timeOriginEvt
|
|
739
|
-
).lcp;
|
|
740
|
-
|
|
741
736
|
// Subset all trace events to just our tab's process (incl threads other than main)
|
|
742
737
|
// stable-sort events to keep them correctly nested.
|
|
743
738
|
const processEvents = TraceProcessor.filteredTraceSort(
|
|
@@ -752,46 +747,89 @@ class TraceProcessor {
|
|
|
752
747
|
// Ensure our traceEnd reflects all page activity.
|
|
753
748
|
const traceEnd = this.computeTraceEnd(trace.traceEvents, timeOriginEvt);
|
|
754
749
|
|
|
755
|
-
/** @param {number|undefined} ts */
|
|
756
|
-
const maybeGetTiming = ts =>
|
|
757
|
-
ts === undefined ? undefined : (ts - timeOriginEvt.ts) / 1000;
|
|
758
750
|
// This could be much more concise with object spread, but the consensus is that explicitness is
|
|
759
751
|
// preferred over brevity here.
|
|
760
752
|
return {
|
|
761
753
|
frames,
|
|
762
754
|
mainThreadEvents,
|
|
755
|
+
frameEvents,
|
|
763
756
|
frameTreeEvents,
|
|
764
757
|
processEvents,
|
|
765
758
|
mainFrameIds,
|
|
759
|
+
timeOriginEvt,
|
|
766
760
|
timings: {
|
|
767
|
-
timeOrigin:
|
|
761
|
+
timeOrigin: 0,
|
|
762
|
+
traceEnd: traceEnd.timing,
|
|
763
|
+
},
|
|
764
|
+
timestamps: {
|
|
765
|
+
timeOrigin: timeOriginEvt.ts,
|
|
766
|
+
traceEnd: traceEnd.timestamp,
|
|
767
|
+
},
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
/**
|
|
772
|
+
* Finds key navigation trace events and computes timings of events in milliseconds since the time
|
|
773
|
+
* origin in addition to the standard microsecond monotonic timestamps.
|
|
774
|
+
* @param {LH.Artifacts.ProcessedTrace} processedTrace
|
|
775
|
+
* @return {LH.Artifacts.ProcessedNavigation}
|
|
776
|
+
*/
|
|
777
|
+
static processNavigation(processedTrace) {
|
|
778
|
+
const { frameEvents, frameTreeEvents, timeOriginEvt, timings, timestamps } =
|
|
779
|
+
processedTrace;
|
|
780
|
+
|
|
781
|
+
// Compute the key frame timings for the main frame.
|
|
782
|
+
const frameTimings = this.computeNavigationTimingsForFrame(frameEvents, {
|
|
783
|
+
timeOriginEvt,
|
|
784
|
+
});
|
|
785
|
+
|
|
786
|
+
// Compute FCP for all frames.
|
|
787
|
+
const fcpAllFramesEvt = frameTreeEvents.find(
|
|
788
|
+
e => e.name === 'firstContentfulPaint' && e.ts > timeOriginEvt.ts
|
|
789
|
+
);
|
|
790
|
+
|
|
791
|
+
if (!fcpAllFramesEvt) {
|
|
792
|
+
throw this.createNoFirstContentfulPaintError();
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// Compute LCP for all frames.
|
|
796
|
+
const lcpAllFramesEvt = this.computeValidLCPAllFrames(
|
|
797
|
+
frameTreeEvents,
|
|
798
|
+
timeOriginEvt
|
|
799
|
+
).lcp;
|
|
800
|
+
|
|
801
|
+
/** @param {number} ts */
|
|
802
|
+
const getTiming = ts => (ts - timeOriginEvt.ts) / 1000;
|
|
803
|
+
/** @param {number=} ts */
|
|
804
|
+
const maybeGetTiming = ts => (ts === undefined ? undefined : getTiming(ts));
|
|
805
|
+
|
|
806
|
+
return {
|
|
807
|
+
timings: {
|
|
808
|
+
timeOrigin: timings.timeOrigin,
|
|
768
809
|
firstPaint: frameTimings.timings.firstPaint,
|
|
769
810
|
firstContentfulPaint: frameTimings.timings.firstContentfulPaint,
|
|
770
|
-
firstContentfulPaintAllFrames:
|
|
771
|
-
fcpAllFramesEvt && fcpAllFramesEvt.ts
|
|
772
|
-
),
|
|
811
|
+
firstContentfulPaintAllFrames: getTiming(fcpAllFramesEvt.ts),
|
|
773
812
|
firstMeaningfulPaint: frameTimings.timings.firstMeaningfulPaint,
|
|
774
813
|
largestContentfulPaint: frameTimings.timings.largestContentfulPaint,
|
|
775
814
|
largestContentfulPaintAllFrames: maybeGetTiming(
|
|
776
815
|
lcpAllFramesEvt && lcpAllFramesEvt.ts
|
|
777
816
|
),
|
|
778
|
-
traceEnd: traceEnd.timing,
|
|
779
817
|
load: frameTimings.timings.load,
|
|
780
818
|
domContentLoaded: frameTimings.timings.domContentLoaded,
|
|
819
|
+
traceEnd: timings.traceEnd,
|
|
781
820
|
},
|
|
782
821
|
timestamps: {
|
|
783
|
-
timeOrigin:
|
|
822
|
+
timeOrigin: timestamps.timeOrigin,
|
|
784
823
|
firstPaint: frameTimings.timestamps.firstPaint,
|
|
785
824
|
firstContentfulPaint: frameTimings.timestamps.firstContentfulPaint,
|
|
786
|
-
firstContentfulPaintAllFrames: fcpAllFramesEvt
|
|
825
|
+
firstContentfulPaintAllFrames: fcpAllFramesEvt.ts,
|
|
787
826
|
firstMeaningfulPaint: frameTimings.timestamps.firstMeaningfulPaint,
|
|
788
827
|
largestContentfulPaint: frameTimings.timestamps.largestContentfulPaint,
|
|
789
828
|
largestContentfulPaintAllFrames: lcpAllFramesEvt && lcpAllFramesEvt.ts,
|
|
790
|
-
traceEnd: traceEnd.timestamp,
|
|
791
829
|
load: frameTimings.timestamps.load,
|
|
792
830
|
domContentLoaded: frameTimings.timestamps.domContentLoaded,
|
|
831
|
+
traceEnd: timestamps.traceEnd,
|
|
793
832
|
},
|
|
794
|
-
timeOriginEvt: frameTimings.timeOriginEvt,
|
|
795
833
|
firstPaintEvt: frameTimings.firstPaintEvt,
|
|
796
834
|
firstContentfulPaintEvt: frameTimings.firstContentfulPaintEvt,
|
|
797
835
|
firstContentfulPaintAllFramesEvt: fcpAllFramesEvt,
|
|
@@ -843,6 +881,21 @@ class TraceProcessor {
|
|
|
843
881
|
* @return {LH.TraceEvent}
|
|
844
882
|
*/
|
|
845
883
|
static computeTimeOrigin(traceEventSubsets, method) {
|
|
884
|
+
const lastNavigationStart = () => {
|
|
885
|
+
// Our time origin will be the last frame navigation in the trace
|
|
886
|
+
const frameEvents = traceEventSubsets.frameEvents;
|
|
887
|
+
return frameEvents.filter(this._isNavigationStartOfInterest).pop();
|
|
888
|
+
};
|
|
889
|
+
|
|
890
|
+
const lighthouseMarker = () => {
|
|
891
|
+
const frameEvents = traceEventSubsets.keyEvents;
|
|
892
|
+
return frameEvents.find(
|
|
893
|
+
evt =>
|
|
894
|
+
evt.name === 'clock_sync' &&
|
|
895
|
+
evt.args.sync_id === TraceProcessor.TIMESPAN_MARKER_ID
|
|
896
|
+
);
|
|
897
|
+
};
|
|
898
|
+
|
|
846
899
|
switch (method) {
|
|
847
900
|
case 'firstResourceSendRequest': {
|
|
848
901
|
// Our time origin will be the timestamp of the first request that's sent in the frame.
|
|
@@ -855,14 +908,20 @@ class TraceProcessor {
|
|
|
855
908
|
return fetchStart;
|
|
856
909
|
}
|
|
857
910
|
case 'lastNavigationStart': {
|
|
858
|
-
|
|
859
|
-
const frameEvents = traceEventSubsets.frameEvents;
|
|
860
|
-
const navigationStart = frameEvents
|
|
861
|
-
.filter(this._isNavigationStartOfInterest)
|
|
862
|
-
.pop();
|
|
911
|
+
const navigationStart = lastNavigationStart();
|
|
863
912
|
if (!navigationStart) throw this.createNoNavstartError();
|
|
864
913
|
return navigationStart;
|
|
865
914
|
}
|
|
915
|
+
case 'lighthouseMarker': {
|
|
916
|
+
const marker = lighthouseMarker();
|
|
917
|
+
if (!marker) throw this.createNoLighthouseMarkerError();
|
|
918
|
+
return marker;
|
|
919
|
+
}
|
|
920
|
+
case 'auto': {
|
|
921
|
+
const marker = lighthouseMarker() || lastNavigationStart();
|
|
922
|
+
if (!marker) throw this.createNoNavstartError();
|
|
923
|
+
return marker;
|
|
924
|
+
}
|
|
866
925
|
}
|
|
867
926
|
}
|
|
868
927
|
|
|
@@ -872,7 +931,7 @@ class TraceProcessor {
|
|
|
872
931
|
* @param {Array<LH.TraceEvent>} frameEvents
|
|
873
932
|
* @param {{timeOriginEvt: LH.TraceEvent}} options
|
|
874
933
|
*/
|
|
875
|
-
static
|
|
934
|
+
static computeNavigationTimingsForFrame(frameEvents, options) {
|
|
876
935
|
const { timeOriginEvt } = options;
|
|
877
936
|
|
|
878
937
|
// Find our first paint of this frame
|
|
@@ -885,6 +944,10 @@ class TraceProcessor {
|
|
|
885
944
|
e => e.name === 'firstContentfulPaint' && e.ts > timeOriginEvt.ts
|
|
886
945
|
);
|
|
887
946
|
|
|
947
|
+
if (!firstContentfulPaint) {
|
|
948
|
+
throw this.createNoFirstContentfulPaintError();
|
|
949
|
+
}
|
|
950
|
+
|
|
888
951
|
// fMP will follow at/after the FP
|
|
889
952
|
let firstMeaningfulPaint = frameEvents.find(
|
|
890
953
|
e => e.name === 'firstMeaningfulPaint' && e.ts > timeOriginEvt.ts
|
|
@@ -918,25 +981,26 @@ class TraceProcessor {
|
|
|
918
981
|
|
|
919
982
|
/** @param {{ts: number}=} event */
|
|
920
983
|
const getTimestamp = event => event && event.ts;
|
|
921
|
-
/** @type {
|
|
984
|
+
/** @type {TraceNavigationTimesForFrame} */
|
|
922
985
|
const timestamps = {
|
|
923
986
|
timeOrigin: timeOriginEvt.ts,
|
|
924
987
|
firstPaint: getTimestamp(firstPaint),
|
|
925
|
-
firstContentfulPaint:
|
|
988
|
+
firstContentfulPaint: firstContentfulPaint.ts,
|
|
926
989
|
firstMeaningfulPaint: getTimestamp(firstMeaningfulPaint),
|
|
927
990
|
largestContentfulPaint: getTimestamp(lcpResult.lcp),
|
|
928
991
|
load: getTimestamp(load),
|
|
929
992
|
domContentLoaded: getTimestamp(domContentLoaded),
|
|
930
993
|
};
|
|
931
994
|
|
|
995
|
+
/** @param {number} ts */
|
|
996
|
+
const getTiming = ts => (ts - timeOriginEvt.ts) / 1000;
|
|
932
997
|
/** @param {number=} ts */
|
|
933
|
-
const maybeGetTiming = ts =>
|
|
934
|
-
|
|
935
|
-
/** @type {TraceTimesWithoutFCPAndTraceEnd} */
|
|
998
|
+
const maybeGetTiming = ts => (ts === undefined ? undefined : getTiming(ts));
|
|
999
|
+
/** @type {TraceNavigationTimesForFrame} */
|
|
936
1000
|
const timings = {
|
|
937
1001
|
timeOrigin: 0,
|
|
938
1002
|
firstPaint: maybeGetTiming(timestamps.firstPaint),
|
|
939
|
-
firstContentfulPaint:
|
|
1003
|
+
firstContentfulPaint: getTiming(timestamps.firstContentfulPaint),
|
|
940
1004
|
firstMeaningfulPaint: maybeGetTiming(timestamps.firstMeaningfulPaint),
|
|
941
1005
|
largestContentfulPaint: maybeGetTiming(timestamps.largestContentfulPaint),
|
|
942
1006
|
load: maybeGetTiming(timestamps.load),
|
package/src/sdk/trace-metrics.ts
CHANGED
|
@@ -24,10 +24,14 @@
|
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
26
|
import { Filmstrip, TraceOutput } from '../common_types';
|
|
27
|
-
import type {
|
|
27
|
+
import type {
|
|
28
|
+
LHProcessedNavigation,
|
|
29
|
+
LHProcessedTrace,
|
|
30
|
+
TraceEvent,
|
|
31
|
+
} from './trace-processor';
|
|
28
32
|
|
|
29
33
|
export class UserTimings {
|
|
30
|
-
static compute(trace:
|
|
34
|
+
static compute(trace: LHProcessedTrace) {
|
|
31
35
|
const { processEvents } = trace;
|
|
32
36
|
const measuresMap = new Map();
|
|
33
37
|
const userTimings: Array<TraceOutput> = [];
|
|
@@ -96,7 +100,7 @@ export class ExperienceMetrics {
|
|
|
96
100
|
};
|
|
97
101
|
}
|
|
98
102
|
|
|
99
|
-
static compute(trace:
|
|
103
|
+
static compute(trace: LHProcessedNavigation) {
|
|
100
104
|
const traces: Array<TraceOutput> = [];
|
|
101
105
|
const { timestamps, timings, lcpInvalidated } = trace;
|
|
102
106
|
|
|
@@ -226,7 +230,7 @@ export class CumulativeLayoutShift {
|
|
|
226
230
|
return maxScore;
|
|
227
231
|
}
|
|
228
232
|
|
|
229
|
-
static compute(trace:
|
|
233
|
+
static compute(trace: LHProcessedTrace) {
|
|
230
234
|
const layoutShiftEvents = this.getLayoutShiftEvents(trace.frameTreeEvents);
|
|
231
235
|
const traces: Array<TraceOutput> = layoutShiftEvents.map(event => {
|
|
232
236
|
return {
|
|
@@ -23,13 +23,14 @@
|
|
|
23
23
|
*
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
import { PerfMetrics } from '../common_types';
|
|
27
26
|
import LighthouseTraceProcessor from './lh-trace-processor';
|
|
28
27
|
import {
|
|
29
28
|
ExperienceMetrics,
|
|
30
29
|
CumulativeLayoutShift,
|
|
31
30
|
UserTimings,
|
|
32
31
|
} from './trace-metrics';
|
|
32
|
+
import { PerfMetrics } from '../common_types';
|
|
33
|
+
import { log } from '../core/logger';
|
|
33
34
|
|
|
34
35
|
const ACCEPTABLE_NAVIGATION_URL_REGEX = /^(file|https?):/;
|
|
35
36
|
|
|
@@ -81,16 +82,22 @@ type LHTraceTime = {
|
|
|
81
82
|
traceEnd: number;
|
|
82
83
|
};
|
|
83
84
|
|
|
84
|
-
export type
|
|
85
|
+
export type LHProcessedNavigation = {
|
|
85
86
|
domContentLoadedEvt: TraceEvent;
|
|
86
87
|
firstContentfulPaintEvt: TraceEvent;
|
|
87
88
|
largestContentfulPaintEvt: TraceEvent;
|
|
88
89
|
loadEvt: TraceEvent;
|
|
89
|
-
|
|
90
|
+
timestamps: LHTraceTime;
|
|
91
|
+
timings: LHTraceTime;
|
|
90
92
|
lcpInvalidated: boolean;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export type LHProcessedTrace = {
|
|
91
96
|
processEvents: Array<TraceEvent>;
|
|
97
|
+
frameEvents: Array<TraceEvent>;
|
|
92
98
|
mainThreadEvents: Array<TraceEvent>;
|
|
93
99
|
frameTreeEvents: Array<TraceEvent>;
|
|
100
|
+
timeOriginEvt: TraceEvent;
|
|
94
101
|
timestamps: Partial<LHTraceTime>;
|
|
95
102
|
timings: Partial<LHTraceTime>;
|
|
96
103
|
};
|
|
@@ -104,7 +111,7 @@ export type LHTrace = {
|
|
|
104
111
|
* metrics based on multiple navigations instead of a single navigation.
|
|
105
112
|
*/
|
|
106
113
|
export class TraceProcessor extends LighthouseTraceProcessor {
|
|
107
|
-
static _isNavigationStartOfInterest(event) {
|
|
114
|
+
static override _isNavigationStartOfInterest(event) {
|
|
108
115
|
return (
|
|
109
116
|
event.name === 'navigationStart' &&
|
|
110
117
|
(!event.args.data ||
|
|
@@ -118,15 +125,23 @@ export class TraceProcessor extends LighthouseTraceProcessor {
|
|
|
118
125
|
const options = {
|
|
119
126
|
timeOriginDeterminationMethod: 'lastNavigationStart',
|
|
120
127
|
};
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
128
|
+
try {
|
|
129
|
+
const processedTrace = this.processTrace({ traceEvents }, options);
|
|
130
|
+
const processedNavigation = this.processNavigation(processedTrace);
|
|
131
|
+
const userTiming = UserTimings.compute(processedTrace);
|
|
132
|
+
const { traces: expTraces, metrics } =
|
|
133
|
+
ExperienceMetrics.compute(processedNavigation);
|
|
134
|
+
const { cls, traces: layoutTraces } =
|
|
135
|
+
CumulativeLayoutShift.compute(processedTrace);
|
|
136
|
+
const perfMetrics: Partial<PerfMetrics> = { cls, ...metrics };
|
|
126
137
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
138
|
+
return {
|
|
139
|
+
traces: userTiming.concat(expTraces, layoutTraces),
|
|
140
|
+
metrics: perfMetrics,
|
|
141
|
+
};
|
|
142
|
+
} catch (e) {
|
|
143
|
+
log(e);
|
|
144
|
+
return {};
|
|
145
|
+
}
|
|
131
146
|
}
|
|
132
147
|
}
|