@mablhq/mabl-cli 1.55.4 → 1.56.6

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/api/featureSet.js CHANGED
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.FeatureSet = exports.FindImplementationVersion = void 0;
4
4
  const types_1 = require("../browserLauncher/types");
5
5
  const ACCESSIBILITY_CHECK_FEATURE_FLAG = 'accessibility_checks';
6
+ const PERFORMANCE_TESTING_BROWSER_RUNS_FEATURE_FLAG = 'performance_testing_browser_runs';
6
7
  const SMARTER_WAIT_FEATURE_FLAG = 'smarter_wait';
7
8
  var FindImplementationVersion;
8
9
  (function (FindImplementationVersion) {
@@ -24,5 +25,8 @@ class FeatureSet {
24
25
  hasAccessibilityChecksEnabled() {
25
26
  return this.featureFlags.has(ACCESSIBILITY_CHECK_FEATURE_FLAG);
26
27
  }
28
+ hasPerformanceTestingBrowserRunsFeatureEnabled() {
29
+ return this.featureFlags.has(PERFORMANCE_TESTING_BROWSER_RUNS_FEATURE_FLAG);
30
+ }
27
31
  }
28
32
  exports.FeatureSet = FeatureSet;
@@ -1,26 +1,6 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
24
4
  };
25
5
  Object.defineProperty(exports, "__esModule", { value: true });
26
6
  exports.MablApiClient = void 0;
@@ -29,7 +9,7 @@ const env_1 = require("../env/env");
29
9
  const mablApi_1 = require("../mablApi");
30
10
  const cliConfigProvider_1 = require("../providers/cliConfigProvider");
31
11
  const basicApiClient_1 = require("./basicApiClient");
32
- const queryString = __importStar(require("query-string"));
12
+ const query_string_1 = __importDefault(require("query-string"));
33
13
  const featureSet_1 = require("./featureSet");
34
14
  class MablApiClient extends basicApiClient_1.BasicApiClient {
35
15
  constructor(options) {
@@ -48,7 +28,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
48
28
  async getPlans(options) {
49
29
  var _a, _b;
50
30
  try {
51
- const queryArg = queryString.stringify(options);
31
+ const queryArg = query_string_1.default.stringify(options);
52
32
  const plans = await this.makeGetRequest(`${this.baseApiUrl}/schedule/runPolicy/?${queryArg}`);
53
33
  sortTemporallyAscending((_a = plans.run_policies) !== null && _a !== void 0 ? _a : []);
54
34
  return (_b = plans.run_policies) !== null && _b !== void 0 ? _b : [];
@@ -67,7 +47,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
67
47
  }
68
48
  async getApplications(workspaceId, limit) {
69
49
  try {
70
- const applicationQueryString = queryString.stringify({
50
+ const applicationQueryString = query_string_1.default.stringify({
71
51
  organization_id: workspaceId,
72
52
  limit,
73
53
  });
@@ -84,7 +64,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
84
64
  const queryStringArgs = {
85
65
  decrypt: decryptVariables,
86
66
  };
87
- const envQueryString = queryString.stringify(queryStringArgs);
67
+ const envQueryString = query_string_1.default.stringify(queryStringArgs);
88
68
  return await this.makeGetRequest(`${this.baseApiUrl}/v1/environments/${environmentId}?${envQueryString}`);
89
69
  }
90
70
  catch (error) {
@@ -117,7 +97,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
117
97
  }
118
98
  async getEnvironments(workspaceId, limit) {
119
99
  try {
120
- const environmentQueryString = queryString.stringify({
100
+ const environmentQueryString = query_string_1.default.stringify({
121
101
  organization_id: workspaceId,
122
102
  limit,
123
103
  });
@@ -139,7 +119,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
139
119
  }
140
120
  async selectLinkServer(workspaceId, label) {
141
121
  try {
142
- const queryParams = queryString.stringify({
122
+ const queryParams = query_string_1.default.stringify({
143
123
  workspace_id: workspaceId,
144
124
  label,
145
125
  });
@@ -187,7 +167,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
187
167
  }
188
168
  async getCredentials(workspaceId, limit) {
189
169
  try {
190
- const credentialsQueryString = queryString.stringify({
170
+ const credentialsQueryString = query_string_1.default.stringify({
191
171
  organization_id: workspaceId,
192
172
  limit,
193
173
  });
@@ -198,7 +178,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
198
178
  }
199
179
  }
200
180
  async getCredential(credentialId, withSecrets, withComputedTotpCount) {
201
- const queryStringParams = queryString.stringify({
181
+ const queryStringParams = query_string_1.default.stringify({
202
182
  with_secrets: withSecrets,
203
183
  with_computed_totp_count: withComputedTotpCount,
204
184
  });
@@ -211,7 +191,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
211
191
  }
212
192
  async getDeploymentEvents(workspaceId, limit) {
213
193
  try {
214
- const deploymentQueryString = queryString.stringify({
194
+ const deploymentQueryString = query_string_1.default.stringify({
215
195
  workspace_id: workspaceId,
216
196
  limit,
217
197
  });
@@ -239,7 +219,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
239
219
  }
240
220
  async queryDeploymentEntities(workspaceId, environmentId, applicationId, limit = 50) {
241
221
  try {
242
- const queryStringParams = queryString.stringify({
222
+ const queryStringParams = query_string_1.default.stringify({
243
223
  organization_id: workspaceId,
244
224
  environment_id: environmentId,
245
225
  application_id: applicationId,
@@ -370,7 +350,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
370
350
  cliExport: forExportFormat,
371
351
  sourceControlTag: branchName,
372
352
  };
373
- const journeyQueryString = queryString.stringify(queryStringArgs);
353
+ const journeyQueryString = query_string_1.default.stringify(queryStringArgs);
374
354
  return await this.makeGetRequest(`${this.baseApiUrl}/test/journey/${journeyId}?${journeyQueryString}`);
375
355
  }
376
356
  catch (error) {
@@ -380,7 +360,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
380
360
  async getJourneys(options) {
381
361
  var _a;
382
362
  try {
383
- const queryArg = queryString.stringify(options);
363
+ const queryArg = query_string_1.default.stringify(options);
384
364
  const journeys = (_a = (await this.makeGetRequest(`${this.baseApiUrl}/test/journeys?${queryArg}`)).journeys) !== null && _a !== void 0 ? _a : [];
385
365
  sortTemporallyAscending(journeys);
386
366
  return journeys;
@@ -394,7 +374,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
394
374
  const queryStringArgs = {
395
375
  sourceControlTag: branchName,
396
376
  };
397
- const flowQueryString = queryString.stringify(queryStringArgs);
377
+ const flowQueryString = query_string_1.default.stringify(queryStringArgs);
398
378
  return await this.makeGetRequest(`${this.baseApiUrl}/flows/${flowId}?${flowQueryString}`);
399
379
  }
400
380
  catch (error) {
@@ -404,7 +384,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
404
384
  async getFlows(options) {
405
385
  var _a;
406
386
  try {
407
- const queryArg = queryString.stringify(options);
387
+ const queryArg = query_string_1.default.stringify(options);
408
388
  const flows = (_a = (await this.makeGetRequest(`${this.baseApiUrl}/flows?${queryArg}`)).flows) !== null && _a !== void 0 ? _a : [];
409
389
  sortTemporallyAscending(flows);
410
390
  return flows;
@@ -442,7 +422,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
442
422
  }
443
423
  async getBranches(workspaceId, limit, statusFilter) {
444
424
  try {
445
- const branchQueryString = queryString.stringify({
425
+ const branchQueryString = query_string_1.default.stringify({
446
426
  workspace_id: workspaceId,
447
427
  limit,
448
428
  status: statusFilter,
@@ -463,7 +443,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
463
443
  }
464
444
  async queryDataTables(workspaceId, limit, cursor) {
465
445
  try {
466
- const dataTablesQueryString = queryString.stringify({
446
+ const dataTablesQueryString = query_string_1.default.stringify({
467
447
  workspace_id: workspaceId,
468
448
  limit,
469
449
  cursor,
@@ -492,7 +472,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
492
472
  }
493
473
  async queryScenarios(dataTableId, limit, cursor) {
494
474
  try {
495
- const scenariosQueryString = queryString.stringify({
475
+ const scenariosQueryString = query_string_1.default.stringify({
496
476
  data_table_id: dataTableId,
497
477
  limit,
498
478
  cursor,
@@ -559,7 +539,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
559
539
  from: fromBranchName,
560
540
  to: toBranchName,
561
541
  };
562
- const mergeQueryString = queryString.stringify(queryStringArgs);
542
+ const mergeQueryString = query_string_1.default.stringify(queryStringArgs);
563
543
  const url = `${this.baseApiUrl}/branch/${workspaceId}/merge?${mergeQueryString}`;
564
544
  return await this.makePostRequest(url, {});
565
545
  }
@@ -777,7 +757,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
777
757
  }
778
758
  }
779
759
  async terminateJourneyRun(journeyRunId, terminationReason) {
780
- const terminateParams = queryString.stringify({
760
+ const terminateParams = query_string_1.default.stringify({
781
761
  terminationReason: terminationReason.toString(),
782
762
  });
783
763
  try {
@@ -807,7 +787,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
807
787
  }
808
788
  async getUsers(workspaceId, limit) {
809
789
  try {
810
- const userQueryString = queryString.stringify({
790
+ const userQueryString = query_string_1.default.stringify({
811
791
  organization_id: workspaceId,
812
792
  limit,
813
793
  });
@@ -819,6 +799,17 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
819
799
  throw toApiError(`Failed to get users`, error);
820
800
  }
821
801
  }
802
+ async getStepIdsInJourneyByFlow(journeyInvariantId, flowIds) {
803
+ try {
804
+ const stepIdsQueryString = query_string_1.default.stringify({
805
+ flow_variant_ids: [flowIds],
806
+ });
807
+ return await this.makeGetRequest(`${this.baseApiUrl}/test/journey/${journeyInvariantId}/stepIdsByFlow?${stepIdsQueryString}`).then((result) => result !== null && result !== void 0 ? result : []);
808
+ }
809
+ catch (error) {
810
+ throw toApiError(`Failed to get step ids in journey by flow`, error);
811
+ }
812
+ }
822
813
  async recordTimeSeriesMetricMeasurement(type, value, options) {
823
814
  try {
824
815
  return this.makePostRequest(`${this.baseApiUrl}/metrics/timeSeries`, createTimeSeriesMetricMeasurement(type, value, options));
@@ -132,5 +132,11 @@ class ChromiumPageDelegate {
132
132
  (0, logUtils_1.logInternal)(`Unable to enable screencast mode. No CDP session found. Error: ${e}`);
133
133
  }
134
134
  }
135
+ async getContentAsMhtml() {
136
+ const document = await this.getCDPSession().send('Page.captureSnapshot', {
137
+ format: 'mhtml',
138
+ });
139
+ return Promise.resolve(document.data);
140
+ }
135
141
  }
136
142
  exports.ChromiumPageDelegate = ChromiumPageDelegate;
@@ -71,5 +71,8 @@ class NonChromiumAbstractPageDelegate {
71
71
  enableScreencastMode() {
72
72
  return Promise.resolve();
73
73
  }
74
+ getContentAsMhtml() {
75
+ return Promise.resolve(undefined);
76
+ }
74
77
  }
75
78
  exports.NonChromiumAbstractPageDelegate = NonChromiumAbstractPageDelegate;
@@ -76,19 +76,26 @@ class PlaywrightFrame extends browserLauncher_1.Frame {
76
76
  }
77
77
  return { world: forcedWorld, value: arg };
78
78
  };
79
- const originalEvaluateExpressionFunction = serverFrame.evaluateExpressionAndWaitForSignals.bind(serverFrame);
80
- const functionOverride = async function (expression, isFunction, arg, _world) {
79
+ const originalEvaluateExpressionFunction = serverFrame.evaluateExpression.bind(serverFrame);
80
+ const functionOverride = async function (expression, options = {}, arg) {
81
81
  const { world, value } = await this.checkWorldFunction(arg);
82
- return originalEvaluateExpressionFunction(expression, isFunction, value, world);
82
+ return originalEvaluateExpressionFunction(expression, {
83
+ isFunction: options.isFunction,
84
+ exposeUtilityScript: options.exposeUtilityScript,
85
+ world,
86
+ }, value);
83
87
  };
84
- serverFrame.evaluateExpressionAndWaitForSignals =
85
- functionOverride.bind(serverFrame);
86
- const originalEvaluateExpressionHandleFunction = serverFrame.evaluateExpressionHandleAndWaitForSignals.bind(serverFrame);
87
- const functionHandleOverride = async function (expression, isFunction, arg, _world) {
88
+ serverFrame.evaluateExpression = functionOverride.bind(serverFrame);
89
+ const originalEvaluateExpressionHandleFunction = serverFrame.evaluateExpressionHandle.bind(serverFrame);
90
+ const functionHandleOverride = async function (expression, options = {}, arg) {
88
91
  const { world, value } = await this.checkWorldFunction(arg);
89
- return originalEvaluateExpressionHandleFunction(expression, isFunction, value, world);
92
+ return originalEvaluateExpressionHandleFunction(expression, {
93
+ isFunction: options.isFunction,
94
+ exposeUtilityScript: options.exposeUtilityScript,
95
+ world,
96
+ }, value);
90
97
  };
91
- serverFrame.evaluateExpressionHandleAndWaitForSignals =
98
+ serverFrame.evaluateExpressionHandle =
92
99
  functionHandleOverride.bind(serverFrame);
93
100
  }
94
101
  async $(selector) {
@@ -159,8 +159,8 @@ class PlaywrightPage extends events_1.default {
159
159
  (0, logUtils_1.logInternal)(`Unable to register event ${event.toString()}. Error: ${error}`);
160
160
  }
161
161
  }
162
- async screenshot(clip) {
163
- return { data: (await this.page.screenshot({ clip })).toString('base64') };
162
+ async screenshot(options) {
163
+ return this.page.screenshot(options);
164
164
  }
165
165
  sendCharacter(key) {
166
166
  return this.page.keyboard.insertText(key);
@@ -358,5 +358,8 @@ class PlaywrightPage extends events_1.default {
358
358
  }
359
359
  return this.playwrightFrames.get(frameId);
360
360
  }
361
+ async getContentAsMhtml() {
362
+ return this.delegate.getContentAsMhtml();
363
+ }
361
364
  }
362
365
  exports.PlaywrightPage = PlaywrightPage;
@@ -0,0 +1,277 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.CloudMonitoringPerformanceMetrics = exports.DEFAULT_CLOUD_MONITORING_METRICS_EXPORT_PERIOD_MS = void 0;
27
+ const api_1 = __importStar(require("@opentelemetry/api"));
28
+ const resources_1 = require("@opentelemetry/resources");
29
+ const sdk_metrics_1 = require("@opentelemetry/sdk-metrics");
30
+ const opentelemetry_cloud_monitoring_exporter_1 = require("@google-cloud/opentelemetry-cloud-monitoring-exporter");
31
+ const distributions_1 = require("./distributions");
32
+ const DEBUG = false;
33
+ const METRIC_NAME_PREFIX = 'mabl/tests/performance';
34
+ exports.DEFAULT_CLOUD_MONITORING_METRICS_EXPORT_PERIOD_MS = 8000;
35
+ const DEFAULT_METER_PROVIDER_SHUTDOWN_TIMEOUT_MS = 3 * exports.DEFAULT_CLOUD_MONITORING_METRICS_EXPORT_PERIOD_MS + 1000;
36
+ class CloudMonitoringPerformanceMetrics {
37
+ constructor(projectId, runnerId, cloudMonitoringMetricsExportPeriodMs = exports.DEFAULT_CLOUD_MONITORING_METRICS_EXPORT_PERIOD_MS, meterProviderShutdownTimeoutMs = DEFAULT_METER_PROVIDER_SHUTDOWN_TIMEOUT_MS) {
38
+ this.projectId = projectId;
39
+ this.runnerId = runnerId;
40
+ this.cloudMonitoringMetricsExportPeriodMs = cloudMonitoringMetricsExportPeriodMs;
41
+ this.meterProviderShutdownTimeoutMs = meterProviderShutdownTimeoutMs;
42
+ if (DEBUG) {
43
+ api_1.diag.setLogger(new api_1.DiagConsoleLogger(), api_1.DiagLogLevel.ALL);
44
+ }
45
+ this.stepMetricsInstrumentNames = this.generateStepMetricsInstrumentNames();
46
+ this.testMetricsInstrumentNames = this.generateTestMetricsInstrumentNames();
47
+ this.meterProvider = this.initializeOpenTelemetry();
48
+ this.meter = this.meterProvider.getMeter(runnerId);
49
+ this.step = this.initializeStepMetrics();
50
+ this.test = this.initializeTestMetrics();
51
+ }
52
+ async shutdown() {
53
+ await this.meterProvider.shutdown({
54
+ timeoutMillis: this.meterProviderShutdownTimeoutMs,
55
+ });
56
+ }
57
+ generateStepMetricsInstrumentNames() {
58
+ return {
59
+ ...this.generateCommonInstrumentNames('step'),
60
+ firstContentfulPaint: this.generateInstrumentName('step', 'firstContentfulPaint'),
61
+ largestContentfulPaint: this.generateInstrumentName('step', 'largestContentfulPaint'),
62
+ cumulativeLayoutShift: this.generateInstrumentName('step', 'cumulativeLayoutShift'),
63
+ timeToFirstByte: this.generateInstrumentName('step', 'timeToFirstByte'),
64
+ domContentLoaded: this.generateInstrumentName('step', 'domContentLoaded'),
65
+ };
66
+ }
67
+ generateTestMetricsInstrumentNames() {
68
+ return {
69
+ ...this.generateCommonInstrumentNames('test'),
70
+ executionTime: this.generateInstrumentName('test', 'execution', 'time'),
71
+ runnerCount: this.generateCountInstrumentName('test', 'runner'),
72
+ };
73
+ }
74
+ initializeOpenTelemetry() {
75
+ const StepMetricsViews = {
76
+ executionCount: new sdk_metrics_1.View({
77
+ aggregation: new sdk_metrics_1.SumAggregation(),
78
+ instrumentName: this.stepMetricsInstrumentNames.executionCount,
79
+ }),
80
+ failCount: new sdk_metrics_1.View({
81
+ aggregation: new sdk_metrics_1.SumAggregation(),
82
+ instrumentName: this.stepMetricsInstrumentNames.failCount,
83
+ }),
84
+ passCount: new sdk_metrics_1.View({
85
+ aggregation: new sdk_metrics_1.SumAggregation(),
86
+ instrumentName: this.stepMetricsInstrumentNames.passCount,
87
+ }),
88
+ firstContentfulPaint: new sdk_metrics_1.View({
89
+ aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.FCPBucketBoundaries, true),
90
+ instrumentName: this.stepMetricsInstrumentNames.firstContentfulPaint,
91
+ }),
92
+ largestContentfulPaint: new sdk_metrics_1.View({
93
+ aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.LCPBucketBoundaries, true),
94
+ instrumentName: this.stepMetricsInstrumentNames.largestContentfulPaint,
95
+ }),
96
+ cumulativeLayoutShift: new sdk_metrics_1.View({
97
+ aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.CLSBucketBoundaries, true),
98
+ instrumentName: this.stepMetricsInstrumentNames.cumulativeLayoutShift,
99
+ }),
100
+ timeToFirstByte: new sdk_metrics_1.View({
101
+ aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.TTFBBucketBoundaries, true),
102
+ instrumentName: this.stepMetricsInstrumentNames.timeToFirstByte,
103
+ }),
104
+ domContentLoaded: new sdk_metrics_1.View({
105
+ aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.DCLBucketBoundaries, true),
106
+ instrumentName: this.stepMetricsInstrumentNames.domContentLoaded,
107
+ }),
108
+ firstContentfulPaintCategory: new sdk_metrics_1.View({
109
+ aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.FCPCategoryBucketBoundaries, false),
110
+ instrumentName: this.stepMetricsInstrumentNames.firstContentfulPaintCategory,
111
+ }),
112
+ largestContentfulPaintCategory: new sdk_metrics_1.View({
113
+ aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.LCPCategoryBucketBoundaries, false),
114
+ instrumentName: this.stepMetricsInstrumentNames.largestContentfulPaintCategory,
115
+ }),
116
+ cumulativeLayoutShiftCategory: new sdk_metrics_1.View({
117
+ aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.CLSCategoryBucketBoundaries, false),
118
+ instrumentName: this.stepMetricsInstrumentNames.cumulativeLayoutShiftCategory,
119
+ }),
120
+ timeToFirstByteCategory: new sdk_metrics_1.View({
121
+ aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.TTFBCategoryBucketBoundaries, false),
122
+ instrumentName: this.stepMetricsInstrumentNames.timeToFirstByteCategory,
123
+ }),
124
+ domContentLoadedCategory: new sdk_metrics_1.View({
125
+ aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.DCLCategoryBucketBoundaries, false),
126
+ instrumentName: this.stepMetricsInstrumentNames.domContentLoadedCategory,
127
+ }),
128
+ };
129
+ const TestMetricsViews = {
130
+ executionCount: new sdk_metrics_1.View({
131
+ aggregation: new sdk_metrics_1.SumAggregation(),
132
+ instrumentName: this.testMetricsInstrumentNames.executionCount,
133
+ }),
134
+ executionTime: new sdk_metrics_1.View({
135
+ aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.ElapsedExecutionTimeBucketBoundaries, true),
136
+ instrumentName: this.testMetricsInstrumentNames.executionTime,
137
+ }),
138
+ failCount: new sdk_metrics_1.View({
139
+ aggregation: new sdk_metrics_1.SumAggregation(),
140
+ instrumentName: this.testMetricsInstrumentNames.failCount,
141
+ }),
142
+ passCount: new sdk_metrics_1.View({
143
+ aggregation: new sdk_metrics_1.SumAggregation(),
144
+ instrumentName: this.testMetricsInstrumentNames.passCount,
145
+ }),
146
+ runnerCount: new sdk_metrics_1.View({
147
+ aggregation: new sdk_metrics_1.LastValueAggregation(),
148
+ instrumentName: this.testMetricsInstrumentNames.runnerCount,
149
+ }),
150
+ firstContentfulPaintCategory: new sdk_metrics_1.View({
151
+ aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.FCPCategoryBucketBoundaries, false),
152
+ instrumentName: this.stepMetricsInstrumentNames.firstContentfulPaintCategory,
153
+ }),
154
+ largestContentfulPaintCategory: new sdk_metrics_1.View({
155
+ aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.LCPCategoryBucketBoundaries, false),
156
+ instrumentName: this.stepMetricsInstrumentNames.largestContentfulPaintCategory,
157
+ }),
158
+ cumulativeLayoutShiftCategory: new sdk_metrics_1.View({
159
+ aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.CLSCategoryBucketBoundaries, false),
160
+ instrumentName: this.stepMetricsInstrumentNames.cumulativeLayoutShiftCategory,
161
+ }),
162
+ timeToFirstByteCategory: new sdk_metrics_1.View({
163
+ aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.TTFBCategoryBucketBoundaries, false),
164
+ instrumentName: this.stepMetricsInstrumentNames.timeToFirstByteCategory,
165
+ }),
166
+ domContentLoadedCategory: new sdk_metrics_1.View({
167
+ aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.DCLCategoryBucketBoundaries, false),
168
+ instrumentName: this.stepMetricsInstrumentNames.domContentLoadedCategory,
169
+ }),
170
+ };
171
+ const meterProvider = new sdk_metrics_1.MeterProvider({
172
+ resource: new resources_1.Resource({
173
+ 'service.namespace': 'execution',
174
+ 'service.name': 'performance-test-runner',
175
+ 'host.id': this.runnerId,
176
+ }),
177
+ views: [
178
+ ...Object.values(StepMetricsViews),
179
+ ...Object.values(TestMetricsViews),
180
+ ],
181
+ });
182
+ const exporter = new opentelemetry_cloud_monitoring_exporter_1.MetricExporter({
183
+ prefix: 'custom.googleapis.com',
184
+ projectId: this.projectId,
185
+ });
186
+ meterProvider.addMetricReader(new sdk_metrics_1.PeriodicExportingMetricReader({
187
+ exportIntervalMillis: this.cloudMonitoringMetricsExportPeriodMs,
188
+ exporter,
189
+ }));
190
+ api_1.default.metrics.setGlobalMeterProvider(this.meterProvider);
191
+ return meterProvider;
192
+ }
193
+ initializeStepMetrics() {
194
+ return {
195
+ executionCount: this.initializeStepCount('executionCount'),
196
+ failCount: this.initializeStepCount('failCount'),
197
+ passCount: this.initializeStepCount('passCount'),
198
+ firstContentfulPaint: this.initializeStepTimeHistogram('firstContentfulPaint'),
199
+ largestContentfulPaint: this.initializeStepTimeHistogram('largestContentfulPaint'),
200
+ cumulativeLayoutShift: this.initializeStepTimeHistogram('cumulativeLayoutShift'),
201
+ timeToFirstByte: this.initializeStepTimeHistogram('timeToFirstByte'),
202
+ domContentLoaded: this.initializeStepTimeHistogram('domContentLoaded'),
203
+ firstContentfulPaintCategory: this.initializeStepTimeHistogram('firstContentfulPaintCategory'),
204
+ largestContentfulPaintCategory: this.initializeStepTimeHistogram('largestContentfulPaintCategory'),
205
+ cumulativeLayoutShiftCategory: this.initializeStepTimeHistogram('cumulativeLayoutShiftCategory'),
206
+ timeToFirstByteCategory: this.initializeStepTimeHistogram('timeToFirstByteCategory'),
207
+ domContentLoadedCategory: this.initializeStepTimeHistogram('domContentLoadedCategory'),
208
+ };
209
+ }
210
+ initializeTestMetrics() {
211
+ return {
212
+ executionCount: this.initializeTestCount('executionCount'),
213
+ executionTime: this.initializeTestTimeHistogram('executionTime'),
214
+ failCount: this.initializeTestCount('failCount'),
215
+ passCount: this.initializeTestCount('passCount'),
216
+ runnerCount: this.initializeTestCount('runnerCount'),
217
+ firstContentfulPaintCategory: this.initializeTestTimeHistogram('firstContentfulPaintCategory'),
218
+ largestContentfulPaintCategory: this.initializeTestTimeHistogram('largestContentfulPaintCategory'),
219
+ cumulativeLayoutShiftCategory: this.initializeTestTimeHistogram('cumulativeLayoutShiftCategory'),
220
+ timeToFirstByteCategory: this.initializeTestTimeHistogram('timeToFirstByteCategory'),
221
+ domContentLoadedCategory: this.initializeTestTimeHistogram('domContentLoadedCategory'),
222
+ };
223
+ }
224
+ initializeStepCount(instrumentName) {
225
+ return this.initializeCounter(this.stepMetricsInstrumentNames[instrumentName]);
226
+ }
227
+ initializeTestCount(instrumentName) {
228
+ return this.initializeCounter(this.testMetricsInstrumentNames[instrumentName]);
229
+ }
230
+ initializeCounter(instrumentName) {
231
+ return this.meter.createCounter(instrumentName, {
232
+ valueType: api_1.ValueType.INT,
233
+ });
234
+ }
235
+ initializeStepTimeHistogram(instrumentName) {
236
+ return this.initializeTimeHistogram(this.stepMetricsInstrumentNames[instrumentName]);
237
+ }
238
+ initializeTestTimeHistogram(instrumentName) {
239
+ return this.initializeTimeHistogram(this.testMetricsInstrumentNames[instrumentName]);
240
+ }
241
+ initializeTimeHistogram(instrumentName) {
242
+ const histogram = this.meter.createHistogram(instrumentName, {
243
+ unit: instrumentName ===
244
+ this.stepMetricsInstrumentNames.cumulativeLayoutShift ||
245
+ instrumentName ===
246
+ this.stepMetricsInstrumentNames.cumulativeLayoutShiftCategory
247
+ ? undefined
248
+ : 'ms',
249
+ });
250
+ return histogram;
251
+ }
252
+ generateCommonInstrumentNames(granularity) {
253
+ return {
254
+ executionCount: this.generateCountInstrumentName(granularity, 'execution'),
255
+ failCount: this.generateResultInstrumentName(granularity, 'fail'),
256
+ passCount: this.generateResultInstrumentName(granularity, 'pass'),
257
+ firstContentfulPaintCategory: this.generateCWVCategoryInstrumentName(granularity, 'firstContentfulPaint'),
258
+ largestContentfulPaintCategory: this.generateCWVCategoryInstrumentName(granularity, 'largestContentfulPaint'),
259
+ cumulativeLayoutShiftCategory: this.generateCWVCategoryInstrumentName(granularity, 'cumulativeLayoutShift'),
260
+ timeToFirstByteCategory: this.generateCWVCategoryInstrumentName(granularity, 'timeToFirstByte'),
261
+ domContentLoadedCategory: this.generateCWVCategoryInstrumentName(granularity, 'domContentLoaded'),
262
+ };
263
+ }
264
+ generateCountInstrumentName(granularity, type) {
265
+ return this.generateInstrumentName(granularity, type, 'count');
266
+ }
267
+ generateResultInstrumentName(granularity, type) {
268
+ return this.generateInstrumentName(granularity, 'result', type);
269
+ }
270
+ generateCWVCategoryInstrumentName(granularity, type) {
271
+ return this.generateInstrumentName(granularity, type, 'category');
272
+ }
273
+ generateInstrumentName(granularity, ...path) {
274
+ return `${METRIC_NAME_PREFIX}/${granularity}/${path.join('/')}`;
275
+ }
276
+ }
277
+ exports.CloudMonitoringPerformanceMetrics = CloudMonitoringPerformanceMetrics;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateBucketBoundaries = exports.DCLCategoryBucketBoundaries = exports.DCLBucketBoundaries = exports.TTFBCategoryBucketBoundaries = exports.TTFBBucketBoundaries = exports.CLSCategoryBucketBoundaries = exports.CLSBucketBoundaries = exports.LCPCategoryBucketBoundaries = exports.LCPBucketBoundaries = exports.FCPCategoryBucketBoundaries = exports.FCPBucketBoundaries = exports.ElapsedExecutionTimeBucketBoundaries = void 0;
4
+ exports.ElapsedExecutionTimeBucketBoundaries = generateBucketBoundaries({ limit: 60000, width: 1000 }, { limit: 300000, width: 5000 }, { limit: 3600000, width: 60000 });
5
+ exports.FCPBucketBoundaries = generateBucketBoundaries({ limit: 1800, width: 25 }, { limit: 3000, width: 50 }, { limit: 6000, width: 100 }, { limit: 30000, width: 500 }, { limit: 50000, width: 1000 });
6
+ exports.FCPCategoryBucketBoundaries = [1800.01, 3000.01];
7
+ exports.LCPBucketBoundaries = generateBucketBoundaries({ limit: 1500, width: 25 }, { limit: 2500, width: 50 }, { limit: 4000, width: 75 }, { limit: 8000, width: 250 }, { limit: 30000, width: 500 }, { limit: 60000, width: 1000 });
8
+ exports.LCPCategoryBucketBoundaries = [2500.01, 4000.01];
9
+ exports.CLSBucketBoundaries = generateBucketBoundaries({ limit: 0.1, width: 0.001 }, { limit: 0.25, width: 0.0025 }, { limit: 0.5, width: 0.01 }, { limit: 1, width: 0.05 });
10
+ exports.CLSCategoryBucketBoundaries = [0.1001, 0.2501];
11
+ exports.TTFBBucketBoundaries = generateBucketBoundaries({ limit: 1000, width: 25 }, { limit: 2000, width: 50 }, { limit: 5000, width: 75 }, { limit: 10000, width: 250 }, { limit: 30000, width: 500 }, { limit: 60000, width: 1000 });
12
+ exports.TTFBCategoryBucketBoundaries = [800.01, 1800.01];
13
+ exports.DCLBucketBoundaries = generateBucketBoundaries({ limit: 1000, width: 25 }, { limit: 2000, width: 50 }, { limit: 5000, width: 75 }, { limit: 10000, width: 250 }, { limit: 30000, width: 500 }, { limit: 60000, width: 1000 });
14
+ exports.DCLCategoryBucketBoundaries = [1000.01, 2000.01];
15
+ function generateBucketBoundaries(...rules) {
16
+ if (!rules.length) {
17
+ throw new Error('At least one rule must be specified');
18
+ }
19
+ return rules
20
+ .reduce((boundaries, rule, index) => {
21
+ const { limit, width } = rule;
22
+ const previousLimit = boundaries[index][boundaries[index].length - 1];
23
+ if (width <= 0) {
24
+ throw new Error(`Invalid rule specification at index ${index}: width must be positive but was ${width}`);
25
+ }
26
+ if (limit <= previousLimit) {
27
+ throw new Error(`Invalid rule specification at index ${index}: limit ${limit} must be strictly greater than previous limit ${previousLimit}`);
28
+ }
29
+ if (previousLimit + width > limit) {
30
+ throw new Error(`Invalid rule specification at index ${index}: previous limit ${previousLimit} + width ${width} must not exceed limit ${limit}`);
31
+ }
32
+ const correctionFactor = 10000;
33
+ const bucketCount = Math.floor((limit * correctionFactor - previousLimit * correctionFactor) /
34
+ (width * correctionFactor));
35
+ const buckets = [...Array(bucketCount)].map((_value, index) => (previousLimit * correctionFactor +
36
+ width * correctionFactor * (index + 1)) /
37
+ correctionFactor);
38
+ boundaries.push(buckets);
39
+ return boundaries;
40
+ }, [[0]])
41
+ .flat()
42
+ .slice(1);
43
+ }
44
+ exports.generateBucketBoundaries = generateBucketBoundaries;