@azure/playwright 1.1.3 → 1.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/dist/browser/common/constants.d.ts +1 -4
  2. package/dist/browser/common/constants.d.ts.map +1 -1
  3. package/dist/browser/common/constants.js +1 -4
  4. package/dist/browser/common/constants.js.map +1 -1
  5. package/dist/browser/common/types.d.ts +0 -4
  6. package/dist/browser/common/types.d.ts.map +1 -1
  7. package/dist/browser/common/types.js.map +1 -1
  8. package/dist/browser/reporter/playwrightReporter.d.ts +0 -1
  9. package/dist/browser/reporter/playwrightReporter.d.ts.map +1 -1
  10. package/dist/browser/reporter/playwrightReporter.js +3 -17
  11. package/dist/browser/reporter/playwrightReporter.js.map +1 -1
  12. package/dist/browser/utils/PlaywrightServiceClient.d.ts +1 -2
  13. package/dist/browser/utils/PlaywrightServiceClient.d.ts.map +1 -1
  14. package/dist/browser/utils/PlaywrightServiceClient.js +1 -26
  15. package/dist/browser/utils/PlaywrightServiceClient.js.map +1 -1
  16. package/dist/browser/utils/utils.d.ts +2 -3
  17. package/dist/browser/utils/utils.d.ts.map +1 -1
  18. package/dist/browser/utils/utils.js +8 -21
  19. package/dist/browser/utils/utils.js.map +1 -1
  20. package/dist/commonjs/common/constants.d.ts +1 -4
  21. package/dist/commonjs/common/constants.d.ts.map +1 -1
  22. package/dist/commonjs/common/constants.js +2 -5
  23. package/dist/commonjs/common/constants.js.map +1 -1
  24. package/dist/commonjs/common/types.d.ts +0 -4
  25. package/dist/commonjs/common/types.d.ts.map +1 -1
  26. package/dist/commonjs/common/types.js.map +1 -1
  27. package/dist/commonjs/reporter/playwrightReporter.d.ts +0 -1
  28. package/dist/commonjs/reporter/playwrightReporter.d.ts.map +1 -1
  29. package/dist/commonjs/reporter/playwrightReporter.js +2 -16
  30. package/dist/commonjs/reporter/playwrightReporter.js.map +1 -1
  31. package/dist/commonjs/tsdoc-metadata.json +1 -1
  32. package/dist/commonjs/utils/PlaywrightServiceClient.d.ts +1 -2
  33. package/dist/commonjs/utils/PlaywrightServiceClient.d.ts.map +1 -1
  34. package/dist/commonjs/utils/PlaywrightServiceClient.js +0 -25
  35. package/dist/commonjs/utils/PlaywrightServiceClient.js.map +1 -1
  36. package/dist/commonjs/utils/utils.d.ts +2 -3
  37. package/dist/commonjs/utils/utils.d.ts.map +1 -1
  38. package/dist/commonjs/utils/utils.js +8 -22
  39. package/dist/commonjs/utils/utils.js.map +1 -1
  40. package/dist/esm/common/constants.d.ts +1 -4
  41. package/dist/esm/common/constants.d.ts.map +1 -1
  42. package/dist/esm/common/constants.js +92 -96
  43. package/dist/esm/common/constants.js.map +1 -7
  44. package/dist/esm/common/customerConfig.js +11 -11
  45. package/dist/esm/common/customerConfig.js.map +1 -7
  46. package/dist/esm/common/entraIdAccessToken.js +77 -85
  47. package/dist/esm/common/entraIdAccessToken.js.map +1 -7
  48. package/dist/esm/common/environmentVariables.js +19 -19
  49. package/dist/esm/common/environmentVariables.js.map +1 -7
  50. package/dist/esm/common/executor.js +58 -51
  51. package/dist/esm/common/executor.js.map +1 -7
  52. package/dist/esm/common/httpService.js +29 -34
  53. package/dist/esm/common/httpService.js.map +1 -7
  54. package/dist/esm/common/logger.js +4 -4
  55. package/dist/esm/common/logger.js.map +1 -7
  56. package/dist/esm/common/messages.js +166 -166
  57. package/dist/esm/common/messages.js.map +1 -7
  58. package/dist/esm/common/playwrightServiceConfig.js +91 -91
  59. package/dist/esm/common/playwrightServiceConfig.js.map +1 -7
  60. package/dist/esm/common/state.js +7 -7
  61. package/dist/esm/common/state.js.map +1 -7
  62. package/dist/esm/common/types.d.ts +0 -4
  63. package/dist/esm/common/types.d.ts.map +1 -1
  64. package/dist/esm/common/types.js +4 -0
  65. package/dist/esm/common/types.js.map +1 -7
  66. package/dist/esm/core/global/playwright-service-global-setup.js +17 -17
  67. package/dist/esm/core/global/playwright-service-global-setup.js.map +1 -7
  68. package/dist/esm/core/global/playwright-service-global-teardown.js +13 -16
  69. package/dist/esm/core/global/playwright-service-global-teardown.js.map +1 -7
  70. package/dist/esm/core/initializePlaywrightServiceTestRun.js +21 -13
  71. package/dist/esm/core/initializePlaywrightServiceTestRun.js.map +1 -7
  72. package/dist/esm/core/playwrightService.js +200 -149
  73. package/dist/esm/core/playwrightService.js.map +1 -7
  74. package/dist/esm/core/playwrightServiceEntra.js +42 -44
  75. package/dist/esm/core/playwrightServiceEntra.js.map +1 -7
  76. package/dist/esm/core/playwrightServiceUtils.js +8 -6
  77. package/dist/esm/core/playwrightServiceUtils.js.map +1 -7
  78. package/dist/esm/index.js +9 -7
  79. package/dist/esm/index.js.map +1 -7
  80. package/dist/esm/reporter/index.js +11 -4
  81. package/dist/esm/reporter/index.js.map +1 -7
  82. package/dist/esm/reporter/playwrightReporter.d.ts +0 -1
  83. package/dist/esm/reporter/playwrightReporter.d.ts.map +1 -1
  84. package/dist/esm/reporter/playwrightReporter.js +193 -202
  85. package/dist/esm/reporter/playwrightReporter.js.map +1 -7
  86. package/dist/esm/utils/PlaywrightServiceClient.d.ts +1 -2
  87. package/dist/esm/utils/PlaywrightServiceClient.d.ts.map +1 -1
  88. package/dist/esm/utils/PlaywrightServiceClient.js +61 -121
  89. package/dist/esm/utils/PlaywrightServiceClient.js.map +1 -7
  90. package/dist/esm/utils/cIInfoProvider.js +71 -58
  91. package/dist/esm/utils/cIInfoProvider.js.map +1 -7
  92. package/dist/esm/utils/getPackageVersion.js +17 -12
  93. package/dist/esm/utils/getPackageVersion.js.map +1 -7
  94. package/dist/esm/utils/getPlaywrightVersion.js +13 -15
  95. package/dist/esm/utils/getPlaywrightVersion.js.map +1 -7
  96. package/dist/esm/utils/packageManager.js +37 -37
  97. package/dist/esm/utils/packageManager.js.map +1 -7
  98. package/dist/esm/utils/parseJwt.js +14 -15
  99. package/dist/esm/utils/parseJwt.js.map +1 -7
  100. package/dist/esm/utils/playwrightReporterStorageManager.js +333 -358
  101. package/dist/esm/utils/playwrightReporterStorageManager.js.map +1 -7
  102. package/dist/esm/utils/utils.d.ts +2 -3
  103. package/dist/esm/utils/utils.d.ts.map +1 -1
  104. package/dist/esm/utils/utils.js +338 -380
  105. package/dist/esm/utils/utils.js.map +1 -7
  106. package/dist/react-native/common/constants.d.ts +1 -4
  107. package/dist/react-native/common/constants.d.ts.map +1 -1
  108. package/dist/react-native/common/constants.js +1 -4
  109. package/dist/react-native/common/constants.js.map +1 -1
  110. package/dist/react-native/common/types.d.ts +0 -4
  111. package/dist/react-native/common/types.d.ts.map +1 -1
  112. package/dist/react-native/common/types.js.map +1 -1
  113. package/dist/react-native/reporter/playwrightReporter.d.ts +0 -1
  114. package/dist/react-native/reporter/playwrightReporter.d.ts.map +1 -1
  115. package/dist/react-native/reporter/playwrightReporter.js +3 -17
  116. package/dist/react-native/reporter/playwrightReporter.js.map +1 -1
  117. package/dist/react-native/utils/PlaywrightServiceClient.d.ts +1 -2
  118. package/dist/react-native/utils/PlaywrightServiceClient.d.ts.map +1 -1
  119. package/dist/react-native/utils/PlaywrightServiceClient.js +1 -26
  120. package/dist/react-native/utils/PlaywrightServiceClient.js.map +1 -1
  121. package/dist/react-native/utils/utils.d.ts +2 -3
  122. package/dist/react-native/utils/utils.d.ts.map +1 -1
  123. package/dist/react-native/utils/utils.js +8 -21
  124. package/dist/react-native/utils/utils.js.map +1 -1
  125. package/package.json +6 -6
@@ -1,13 +1,6 @@
1
- import {
2
- Constants,
3
- InternalEnvironmentVariables,
4
- ServiceEnvironmentVariable,
5
- RunConfigConstants,
6
- GitHubActionsConstants,
7
- BrowserSessionSourceType,
8
- UrlConstants,
9
- UploadConstants
10
- } from "../common/constants.js";
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+ import { Constants, InternalEnvironmentVariables, ServiceEnvironmentVariable, RunConfigConstants, GitHubActionsConstants, BrowserSessionSourceType, UrlConstants, UploadConstants, } from "../common/constants.js";
11
4
  import { ServiceErrorMessageConstants } from "../common/messages.js";
12
5
  import { coreLogger } from "../common/logger.js";
13
6
  import process from "node:process";
@@ -20,415 +13,380 @@ import { exec } from "child_process";
20
13
  import { getPackageVersionFromFolder } from "./getPackageVersion.js";
21
14
  import { readdirSync, statSync } from "fs";
22
15
  import { join, relative } from "path";
23
- import { getPlaywrightVersion as getPlaywrightVersion2 } from "./getPlaywrightVersion.js";
24
- import { parseJwt as parseJwt2 } from "./parseJwt.js";
25
- const getPackageVersion = () => {
26
- const distVersion = getPackageVersionFromFolder("../../../");
27
- if (distVersion) {
28
- return distVersion;
29
- }
30
- const srcVersion = getPackageVersionFromFolder("../../");
31
- if (srcVersion) {
32
- return srcVersion;
33
- }
34
- return "unknown-version";
35
- };
36
- const exitWithFailureMessage = (error, errorDetails) => {
37
- console.log();
38
- if (error.formatWithErrorDetails && errorDetails) {
39
- console.error(error.formatWithErrorDetails(errorDetails));
40
- } else {
41
- console.error(error.message);
42
- }
43
- process.exit(1);
44
- };
45
- const throwErrorWithFailureMessage = (error, errorDetails) => {
46
- console.log();
47
- const finalMessage = error.formatWithErrorDetails && errorDetails ? error.formatWithErrorDetails(errorDetails) : error.message;
48
- throw new Error(finalMessage);
16
+ // Re-exporting for backward compatibility
17
+ export { getPlaywrightVersion } from "./getPlaywrightVersion.js";
18
+ export { parseJwt } from "./parseJwt.js";
19
+ export const getPackageVersion = () => {
20
+ // hacky way to get package version
21
+ // try from dist folder first (customer perspective)
22
+ const distVersion = getPackageVersionFromFolder("../../../");
23
+ if (distVersion) {
24
+ return distVersion;
25
+ }
26
+ // if not found, try from src folder (internal test suite)
27
+ const srcVersion = getPackageVersionFromFolder("../../");
28
+ if (srcVersion) {
29
+ return srcVersion;
30
+ }
31
+ return "unknown-version";
49
32
  };
50
- const populateValuesFromServiceUrl = () => {
51
- const url = process.env["PLAYWRIGHT_SERVICE_URL"];
52
- if (url) {
53
- const parts = url.split("/");
54
- if (parts.length > 2) {
55
- const subdomainParts = parts[2].split(".");
56
- const region = subdomainParts.length > 0 ? subdomainParts[0] : null;
57
- const domain = subdomainParts.slice(2).join(".");
58
- const accountId = parts[4];
59
- return { region, domain, accountId };
60
- }
61
- }
62
- return null;
33
+ export const exitWithFailureMessage = (error, errorDetails) => {
34
+ console.log();
35
+ if (error.formatWithErrorDetails && errorDetails) {
36
+ console.error(error.formatWithErrorDetails(errorDetails));
37
+ }
38
+ else {
39
+ console.error(error.message);
40
+ }
41
+ // eslint-disable-next-line n/no-process-exit
42
+ process.exit(1);
63
43
  };
64
- const getAccessToken = () => {
65
- return process.env[ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN];
44
+ export const throwErrorWithFailureMessage = (error, errorDetails) => {
45
+ console.log();
46
+ const finalMessage = error.formatWithErrorDetails && errorDetails
47
+ ? error.formatWithErrorDetails(errorDetails)
48
+ : error.message;
49
+ throw new Error(finalMessage);
66
50
  };
67
- const getServiceBaseURL = () => {
68
- return process.env[ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL];
51
+ export const populateValuesFromServiceUrl = () => {
52
+ // Service URL format: wss://<region>.api.playwright.microsoft.com/accounts/<workspace-id>/browsers
53
+ const url = process.env["PLAYWRIGHT_SERVICE_URL"];
54
+ if (url) {
55
+ const parts = url.split("/");
56
+ if (parts.length > 2) {
57
+ const subdomainParts = parts[2].split(".");
58
+ const region = subdomainParts.length > 0 ? subdomainParts[0] : null;
59
+ const domain = subdomainParts.slice(2).join(".");
60
+ const accountId = parts[4];
61
+ return { region: region, domain: domain, accountId: accountId };
62
+ }
63
+ }
64
+ return null;
69
65
  };
70
- const isValidGuid = (guid) => {
71
- if (!guid) {
72
- return false;
73
- }
74
- const guidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
75
- return guidRegex.test(guid);
66
+ export const getAccessToken = () => {
67
+ return process.env[ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_ACCESS_TOKEN];
76
68
  };
77
- const getAndSetRunId = () => {
78
- const runId = randomUUID();
79
- process.env[InternalEnvironmentVariables.MPT_SERVICE_RUN_ID] = runId;
80
- return runId;
69
+ export const getServiceBaseURL = () => {
70
+ return process.env[ServiceEnvironmentVariable.PLAYWRIGHT_SERVICE_URL];
81
71
  };
82
- const getServiceWSEndpoint = (runId, os, apiVersion) => {
83
- return `${getServiceBaseURL()}?runId=${encodeURIComponent(runId)}&os=${os}&sourceType=${BrowserSessionSourceType.PLAYWRIGHT_WORKSPACES_TEST_RUN}&api-version=${apiVersion}`;
72
+ export const isValidGuid = (guid) => {
73
+ if (!guid) {
74
+ return false;
75
+ }
76
+ const guidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
77
+ return guidRegex.test(guid);
84
78
  };
85
- const validateServiceUrl = () => {
86
- const serviceUrl = getServiceBaseURL();
87
- if (!serviceUrl) {
88
- exitWithFailureMessage(ServiceErrorMessageConstants.NO_SERVICE_URL_ERROR);
89
- }
79
+ export const getAndSetRunId = () => {
80
+ const runId = randomUUID();
81
+ process.env[InternalEnvironmentVariables.MPT_SERVICE_RUN_ID] = runId;
82
+ return runId;
90
83
  };
91
- const ValidateRunID = (runID) => {
92
- const isValidRunID = isValidGuid(runID);
93
- if (!isValidRunID) {
94
- const errorMessage = ServiceErrorMessageConstants.INVALID_RUN_ID_FORMAT.message;
95
- throw new Error(errorMessage);
96
- }
84
+ export const getServiceWSEndpoint = (runId, os, apiVersion) => {
85
+ return `${getServiceBaseURL()}?runId=${encodeURIComponent(runId)}&os=${os}&sourceType=${BrowserSessionSourceType.PLAYWRIGHT_WORKSPACES_TEST_RUN}&api-version=${apiVersion}`;
97
86
  };
98
- const validateMptPAT = (validationFailureCallback) => {
99
- try {
100
- const accessToken = getAccessToken();
101
- const result = populateValuesFromServiceUrl();
102
- if (!accessToken) {
103
- validationFailureCallback(ServiceErrorMessageConstants.NO_AUTH_ERROR_PAT_TOKEN);
87
+ export const validateServiceUrl = () => {
88
+ const serviceUrl = getServiceBaseURL();
89
+ if (!serviceUrl) {
90
+ exitWithFailureMessage(ServiceErrorMessageConstants.NO_SERVICE_URL_ERROR);
104
91
  }
105
- const claims = parseJwt(accessToken);
106
- if (!claims.exp) {
107
- validationFailureCallback(ServiceErrorMessageConstants.INVALID_MPT_PAT_ERROR);
92
+ };
93
+ export const ValidateRunID = (runID) => {
94
+ const isValidRunID = isValidGuid(runID);
95
+ if (!isValidRunID) {
96
+ const errorMessage = ServiceErrorMessageConstants.INVALID_RUN_ID_FORMAT.message;
97
+ throw new Error(errorMessage);
108
98
  }
109
- if (Date.now() >= claims.exp * 1e3) {
110
- validationFailureCallback(ServiceErrorMessageConstants.EXPIRED_MPT_PAT_ERROR);
99
+ };
100
+ export const validateMptPAT = (validationFailureCallback) => {
101
+ try {
102
+ const accessToken = getAccessToken();
103
+ const result = populateValuesFromServiceUrl();
104
+ if (!accessToken) {
105
+ validationFailureCallback(ServiceErrorMessageConstants.NO_AUTH_ERROR_PAT_TOKEN);
106
+ }
107
+ const claims = parseJwt(accessToken);
108
+ if (!claims.exp) {
109
+ validationFailureCallback(ServiceErrorMessageConstants.INVALID_MPT_PAT_ERROR);
110
+ }
111
+ if (Date.now() >= claims.exp * 1000) {
112
+ validationFailureCallback(ServiceErrorMessageConstants.EXPIRED_MPT_PAT_ERROR);
113
+ }
114
+ if (result.accountId !== claims.pwid) {
115
+ validationFailureCallback(ServiceErrorMessageConstants.WORKSPACE_MISMATCH_ERROR);
116
+ }
111
117
  }
112
- if (result.accountId !== claims.pwid) {
113
- validationFailureCallback(ServiceErrorMessageConstants.WORKSPACE_MISMATCH_ERROR);
118
+ catch (err) {
119
+ coreLogger.error(err);
120
+ exitWithFailureMessage(ServiceErrorMessageConstants.INVALID_MPT_PAT_ERROR);
114
121
  }
115
- } catch (err) {
116
- coreLogger.error(err);
117
- exitWithFailureMessage(ServiceErrorMessageConstants.INVALID_MPT_PAT_ERROR);
118
- }
119
122
  };
120
123
  const isTokenExpiringSoon = (expirationTime, currentTime) => {
121
- return expirationTime * 1e3 - currentTime <= Constants.SevenDaysInMS;
124
+ return expirationTime * 1000 - currentTime <= Constants.SevenDaysInMS;
122
125
  };
123
126
  const warnAboutTokenExpiry = (expirationTime, currentTime) => {
124
- const daysToExpiration = Math.ceil((expirationTime * 1e3 - currentTime) / Constants.OneDayInMS);
125
- const expirationDate = new Date(expirationTime * 1e3).toLocaleDateString();
126
- const expirationWarning = `Warning: The access token used for this test run will expire in ${daysToExpiration} days on ${expirationDate}. Generate a new token from the portal to avoid failures. For a simpler, more secure solution, switch to Microsoft Entra ID and eliminate token management. https://learn.microsoft.com/entra/identity/`;
127
- console.warn(expirationWarning);
127
+ const daysToExpiration = Math.ceil((expirationTime * 1000 - currentTime) / Constants.OneDayInMS);
128
+ const expirationDate = new Date(expirationTime * 1000).toLocaleDateString();
129
+ const expirationWarning = `Warning: The access token used for this test run will expire in ${daysToExpiration} days on ${expirationDate}. Generate a new token from the portal to avoid failures. For a simpler, more secure solution, switch to Microsoft Entra ID and eliminate token management. https://learn.microsoft.com/entra/identity/`;
130
+ console.warn(expirationWarning);
128
131
  };
129
- const warnIfAccessTokenCloseToExpiry = () => {
130
- const accessToken = getAccessToken();
131
- if (!accessToken) {
132
- throw new Error(ServiceErrorMessageConstants.NO_AUTH_ERROR_PAT_TOKEN.message);
133
- }
134
- const claims = parseJwt(accessToken);
135
- const currentTime = Date.now();
136
- if (isTokenExpiringSoon(claims.exp, currentTime)) {
137
- warnAboutTokenExpiry(claims.exp, currentTime);
138
- }
132
+ export const warnIfAccessTokenCloseToExpiry = () => {
133
+ const accessToken = getAccessToken();
134
+ if (!accessToken) {
135
+ throw new Error(ServiceErrorMessageConstants.NO_AUTH_ERROR_PAT_TOKEN.message);
136
+ }
137
+ const claims = parseJwt(accessToken);
138
+ const currentTime = Date.now();
139
+ if (isTokenExpiringSoon(claims.exp, currentTime)) {
140
+ warnAboutTokenExpiry(claims.exp, currentTime);
141
+ }
139
142
  };
140
- const fetchOrValidateAccessToken = async (credential) => {
141
- const entraIdAccessToken = createEntraIdAccessToken(credential);
142
- if (entraIdAccessToken.doesEntraIdAccessTokenNeedRotation()) {
143
- await entraIdAccessToken.fetchEntraIdAccessToken();
144
- }
145
- const token = getAccessToken();
146
- if (!token) {
147
- throw new Error(ServiceErrorMessageConstants.NO_AUTH_ERROR_ENTRA_TOKEN.message);
148
- }
149
- return token;
143
+ export const fetchOrValidateAccessToken = async (credential) => {
144
+ const entraIdAccessToken = createEntraIdAccessToken(credential);
145
+ // Fetch a token or refresh if needed in a single call
146
+ if (entraIdAccessToken.doesEntraIdAccessTokenNeedRotation()) {
147
+ await entraIdAccessToken.fetchEntraIdAccessToken();
148
+ }
149
+ const token = getAccessToken();
150
+ if (!token) {
151
+ throw new Error(ServiceErrorMessageConstants.NO_AUTH_ERROR_ENTRA_TOKEN.message);
152
+ }
153
+ return token;
150
154
  };
151
- const getVersionInfo = (version) => {
152
- const regex = /^(\d+)(?:\.(\d+))?(?:\.(\d+))?/;
153
- const match = version.match(regex);
154
- const versionInfo = {
155
- major: 0,
156
- minor: 0,
157
- patch: 0
158
- };
159
- versionInfo.major = match && match[1] ? parseInt(match[1], 10) : 0;
160
- versionInfo.minor = match && match[2] ? parseInt(match[2], 10) : 0;
161
- versionInfo.patch = match && match[3] ? parseInt(match[3], 10) : 0;
162
- return versionInfo;
155
+ export const getVersionInfo = (version) => {
156
+ const regex = /^(\d+)(?:\.(\d+))?(?:\.(\d+))?/;
157
+ const match = version.match(regex);
158
+ const versionInfo = {
159
+ major: 0,
160
+ minor: 0,
161
+ patch: 0,
162
+ };
163
+ versionInfo.major = match && match[1] ? parseInt(match[1], 10) : 0;
164
+ versionInfo.minor = match && match[2] ? parseInt(match[2], 10) : 0;
165
+ versionInfo.patch = match && match[3] ? parseInt(match[3], 10) : 0;
166
+ return versionInfo;
163
167
  };
164
- const validatePlaywrightVersion = () => {
165
- const minimumSupportedVersion = Constants.MinimumSupportedPlaywrightVersion;
166
- const installedVersion = getPlaywrightVersion();
167
- const minimumSupportedVersionInfo = getVersionInfo(minimumSupportedVersion);
168
- const installedVersionInfo = getVersionInfo(installedVersion);
169
- const isInstalledVersionGreater = installedVersionInfo.major > minimumSupportedVersionInfo.major || installedVersionInfo.major === minimumSupportedVersionInfo.major && installedVersionInfo.minor >= minimumSupportedVersionInfo.minor;
170
- if (!isInstalledVersionGreater) {
171
- exitWithFailureMessage(ServiceErrorMessageConstants.INVALID_PLAYWRIGHT_VERSION_ERROR);
172
- }
168
+ export const validatePlaywrightVersion = () => {
169
+ const minimumSupportedVersion = Constants.MinimumSupportedPlaywrightVersion;
170
+ const installedVersion = getPlaywrightVersion();
171
+ const minimumSupportedVersionInfo = getVersionInfo(minimumSupportedVersion);
172
+ const installedVersionInfo = getVersionInfo(installedVersion);
173
+ const isInstalledVersionGreater = installedVersionInfo.major > minimumSupportedVersionInfo.major ||
174
+ (installedVersionInfo.major === minimumSupportedVersionInfo.major &&
175
+ installedVersionInfo.minor >= minimumSupportedVersionInfo.minor);
176
+ if (!isInstalledVersionGreater) {
177
+ exitWithFailureMessage(ServiceErrorMessageConstants.INVALID_PLAYWRIGHT_VERSION_ERROR);
178
+ }
173
179
  };
174
- const getTestRunConfig = (config) => {
175
- const maxWorkers = config.workers || config.metadata.actualWorkers;
176
- const frameWorkVersion = config.version;
177
- const testRunConfig = {
178
- framework: {
179
- name: RunConfigConstants.TEST_FRAMEWORK_NAME,
180
- version: frameWorkVersion,
181
- runnerName: RunConfigConstants.TEST_FRAMEWORK_RUNNERNAME
182
- },
183
- sdkLanguage: RunConfigConstants.TEST_SDK_LANGUAGE,
184
- maxWorkers
185
- };
186
- return testRunConfig;
180
+ export const getTestRunConfig = (config) => {
181
+ const maxWorkers = config.workers || config.metadata.actualWorkers;
182
+ const frameWorkVersion = config.version;
183
+ const testRunConfig = {
184
+ framework: {
185
+ name: RunConfigConstants.TEST_FRAMEWORK_NAME,
186
+ version: frameWorkVersion,
187
+ runnerName: RunConfigConstants.TEST_FRAMEWORK_RUNNERNAME,
188
+ },
189
+ sdkLanguage: RunConfigConstants.TEST_SDK_LANGUAGE,
190
+ maxWorkers: maxWorkers,
191
+ };
192
+ return testRunConfig;
187
193
  };
188
- function getTestRunApiUrl() {
189
- const result = populateValuesFromServiceUrl();
190
- const runId = process.env[InternalEnvironmentVariables.MPT_SERVICE_RUN_ID];
191
- if (!result?.region || !result?.domain || !result?.accountId) {
192
- exitWithFailureMessage(ServiceErrorMessageConstants.NO_SERVICE_URL_ERROR);
193
- }
194
- const baseUrl = `https://${result?.region}.${UrlConstants.ReportingApiSubdomain}.${result?.domain}/${UrlConstants.PlaywrightWorkspacesPath}/${result?.accountId}/${UrlConstants.TestRunsPath}`;
195
- const url = runId ? `${baseUrl}/${runId}` : baseUrl;
196
- return `${url}?api-version=${Constants.LatestAPIVersion}`;
194
+ export function getTestRunApiUrl() {
195
+ const result = populateValuesFromServiceUrl();
196
+ const runId = process.env[InternalEnvironmentVariables.MPT_SERVICE_RUN_ID];
197
+ if (!result?.region || !result?.domain || !result?.accountId) {
198
+ exitWithFailureMessage(ServiceErrorMessageConstants.NO_SERVICE_URL_ERROR);
199
+ }
200
+ const baseUrl = `https://${result?.region}.${UrlConstants.ReportingApiSubdomain}.${result?.domain}/${UrlConstants.PlaywrightWorkspacesPath}/${result?.accountId}/${UrlConstants.TestRunsPath}`;
201
+ const url = runId ? `${baseUrl}/${runId}` : baseUrl;
202
+ return `${url}?api-version=${Constants.LatestAPIVersion}`;
197
203
  }
198
- function isNullOrEmpty(str) {
199
- return !str || str.trim() === "";
204
+ export function isNullOrEmpty(str) {
205
+ return !str || str.trim() === "";
200
206
  }
201
207
  async function runCommand(command) {
202
- return new Promise((resolve, reject) => {
203
- exec(command, (error, stdout, stderr) => {
204
- if (error) {
205
- reject(error);
206
- return;
207
- }
208
- if (stderr) {
209
- reject(new Error(stderr));
210
- return;
211
- }
212
- resolve(stdout.trim());
208
+ return new Promise((resolve, reject) => {
209
+ exec(command, (error, stdout, stderr) => {
210
+ if (error) {
211
+ reject(error);
212
+ return;
213
+ }
214
+ if (stderr) {
215
+ reject(new Error(stderr));
216
+ return;
217
+ }
218
+ resolve(stdout.trim());
219
+ });
213
220
  });
214
- });
215
221
  }
216
- async function getRunName(ciInfo) {
217
- if (ciInfo.providerName === CI_PROVIDERS.GITHUB && process.env["GITHUB_EVENT_NAME"] === "pull_request") {
218
- const prNumber = `${process.env["GITHUB_REF_NAME"]?.split("/")[0]}`;
219
- const prLink = `${process.env["GITHUB_REPOSITORY"]}/pull/${prNumber}`;
220
- return `PR# ${prNumber} on Repo: ${process.env["GITHUB_REPOSITORY"]} (${prLink})`;
221
- }
222
- try {
223
- const gitVersion = await runCommand(GitHubActionsConstants.GIT_VERSION_COMMAND);
224
- if (isNullOrEmpty(gitVersion)) {
225
- throw new Error("Git is not installed on the machine");
226
- }
227
- const isInsideWorkTree = await runCommand(GitHubActionsConstants.GIT_REV_PARSE);
228
- if (isInsideWorkTree !== "true") {
229
- throw new Error("Not inside a git repository");
230
- }
231
- const gitCommitMessage = await runCommand(GitHubActionsConstants.GIT_COMMIT_MESSAGE_COMMAND);
232
- return gitCommitMessage;
233
- } catch (err) {
234
- coreLogger.error(`Error in getting git commit message: ${err}.`);
235
- return "";
236
- }
222
+ export async function getRunName(ciInfo) {
223
+ if (ciInfo.providerName === CI_PROVIDERS.GITHUB &&
224
+ process.env["GITHUB_EVENT_NAME"] === "pull_request") {
225
+ const prNumber = `${process.env["GITHUB_REF_NAME"]?.split("/")[0]}`;
226
+ const prLink = `${process.env["GITHUB_REPOSITORY"]}/pull/${prNumber}`;
227
+ return `PR# ${prNumber} on Repo: ${process.env["GITHUB_REPOSITORY"]} (${prLink})`;
228
+ }
229
+ try {
230
+ const gitVersion = await runCommand(GitHubActionsConstants.GIT_VERSION_COMMAND);
231
+ if (isNullOrEmpty(gitVersion)) {
232
+ throw new Error("Git is not installed on the machine");
233
+ }
234
+ const isInsideWorkTree = await runCommand(GitHubActionsConstants.GIT_REV_PARSE);
235
+ if (isInsideWorkTree !== "true") {
236
+ throw new Error("Not inside a git repository");
237
+ }
238
+ const gitCommitMessage = await runCommand(GitHubActionsConstants.GIT_COMMIT_MESSAGE_COMMAND);
239
+ return gitCommitMessage;
240
+ }
241
+ catch (err) {
242
+ coreLogger.error(`Error in getting git commit message: ${err}.`);
243
+ return "";
244
+ }
237
245
  }
238
- function extractErrorMessage(responseBody) {
239
- if (!responseBody) {
240
- return "";
241
- }
242
- try {
243
- const errorResponse = JSON.parse(responseBody);
244
- if (errorResponse.error && errorResponse.error.message) {
245
- return errorResponse.error.message;
246
- }
247
- return responseBody;
248
- } catch (e) {
249
- return responseBody;
250
- }
246
+ export function extractErrorMessage(responseBody) {
247
+ if (!responseBody) {
248
+ return "";
249
+ }
250
+ try {
251
+ const errorResponse = JSON.parse(responseBody);
252
+ if (errorResponse.error && errorResponse.error.message) {
253
+ return errorResponse.error.message;
254
+ }
255
+ return responseBody;
256
+ }
257
+ catch (e) {
258
+ return responseBody;
259
+ }
251
260
  }
252
- function getWorkspaceMetaDataApiUrl() {
253
- const result = populateValuesFromServiceUrl();
254
- if (!result?.region || !result?.domain || !result?.accountId) {
255
- exitWithFailureMessage(ServiceErrorMessageConstants.NO_SERVICE_URL_ERROR);
256
- }
257
- const baseUrl = `https://${result?.region}.${UrlConstants.ApiSubdomain}.${result?.domain}/${UrlConstants.PlaywrightWorkspacesPath}/${result?.accountId}`;
258
- return `${baseUrl}?api-version=${Constants.LatestAPIVersion}`;
261
+ export function getWorkspaceMetaDataApiUrl() {
262
+ const result = populateValuesFromServiceUrl();
263
+ if (!result?.region || !result?.domain || !result?.accountId) {
264
+ exitWithFailureMessage(ServiceErrorMessageConstants.NO_SERVICE_URL_ERROR);
265
+ }
266
+ const baseUrl = `https://${result?.region}.${UrlConstants.ApiSubdomain}.${result?.domain}/${UrlConstants.PlaywrightWorkspacesPath}/${result?.accountId}`;
267
+ return `${baseUrl}?api-version=${Constants.LatestAPIVersion}`;
259
268
  }
260
- function getHtmlReporterOutputFolder(config) {
261
- const defaultFolder = "playwright-report";
262
- if (!config?.reporter) {
269
+ export function getHtmlReporterOutputFolder(config) {
270
+ const defaultFolder = "playwright-report";
271
+ if (!config?.reporter) {
272
+ return defaultFolder;
273
+ }
274
+ for (const reporter of config.reporter) {
275
+ if (Array.isArray(reporter)) {
276
+ const [reporterName, options] = reporter;
277
+ if (reporterName === "html" && options && typeof options === "object") {
278
+ return options.outputFolder || defaultFolder;
279
+ }
280
+ }
281
+ else if (typeof reporter === "string" && reporter === "html") {
282
+ return defaultFolder;
283
+ }
284
+ }
263
285
  return defaultFolder;
264
- }
265
- for (const reporter of config.reporter) {
266
- if (Array.isArray(reporter)) {
267
- const [reporterName, options] = reporter;
268
- if (reporterName === "html" && options && typeof options === "object") {
269
- return options.outputFolder || defaultFolder;
270
- }
271
- } else if (typeof reporter === "string" && reporter === "html") {
272
- return defaultFolder;
273
- }
274
- }
275
- return defaultFolder;
276
286
  }
277
- function getContentType(filePath) {
278
- const ext = filePath.toLowerCase().split(".").pop();
279
- const contentTypes = {
280
- html: "text/html",
281
- css: "text/css",
282
- js: "application/javascript",
283
- json: "application/json",
284
- png: "image/png",
285
- jpg: "image/jpeg",
286
- jpeg: "image/jpeg",
287
- svg: "image/svg+xml",
288
- ico: "image/x-icon",
289
- txt: "text/plain",
290
- ttf: "font/ttf",
291
- woff: "font/woff",
292
- woff2: "font/woff2",
293
- webmanifest: "application/manifest+json",
294
- map: "application/json",
295
- xml: "application/xml",
296
- pdf: "application/pdf",
297
- zip: "application/zip"
298
- };
299
- return contentTypes[ext || ""] || "application/octet-stream";
287
+ export function getContentType(filePath) {
288
+ const ext = filePath.toLowerCase().split(".").pop();
289
+ const contentTypes = {
290
+ html: "text/html",
291
+ css: "text/css",
292
+ js: "application/javascript",
293
+ json: "application/json",
294
+ png: "image/png",
295
+ jpg: "image/jpeg",
296
+ jpeg: "image/jpeg",
297
+ svg: "image/svg+xml",
298
+ ico: "image/x-icon",
299
+ txt: "text/plain",
300
+ ttf: "font/ttf",
301
+ woff: "font/woff",
302
+ woff2: "font/woff2",
303
+ webmanifest: "application/manifest+json",
304
+ map: "application/json",
305
+ xml: "application/xml",
306
+ pdf: "application/pdf",
307
+ zip: "application/zip",
308
+ };
309
+ return contentTypes[ext || ""] || "application/octet-stream";
300
310
  }
301
- function calculateOptimalConcurrency(files) {
302
- const totalFiles = files.length;
303
- const totalSize = files.reduce((sum, f) => sum + f.size, 0);
304
- const avgFileSize = totalSize / totalFiles;
305
- let optimalConcurrency;
306
- if (totalFiles <= 10) {
307
- optimalConcurrency = Math.min(totalFiles, 10);
308
- } else if (avgFileSize < UploadConstants.SMALL_FILE_THRESHOLD) {
309
- optimalConcurrency = Math.min(
310
- UploadConstants.MAX_CONCURRENCY,
311
- Math.max(UploadConstants.BASE_CONCURRENCY, totalFiles / 50)
312
- );
313
- } else if (totalFiles > 1e3) {
314
- optimalConcurrency = Math.min(
315
- UploadConstants.MAX_CONCURRENCY,
316
- UploadConstants.BASE_CONCURRENCY + Math.floor(totalFiles / 200)
317
- );
318
- } else {
319
- optimalConcurrency = Math.min(
320
- UploadConstants.MAX_CONCURRENCY,
321
- UploadConstants.BASE_CONCURRENCY
322
- );
323
- }
324
- return Math.floor(optimalConcurrency);
311
+ export function calculateOptimalConcurrency(files) {
312
+ const totalFiles = files.length;
313
+ const totalSize = files.reduce((sum, f) => sum + f.size, 0);
314
+ const avgFileSize = totalSize / totalFiles;
315
+ let optimalConcurrency;
316
+ if (totalFiles <= 10) {
317
+ optimalConcurrency = Math.min(totalFiles, 10);
318
+ }
319
+ else if (avgFileSize < UploadConstants.SMALL_FILE_THRESHOLD) {
320
+ optimalConcurrency = Math.min(UploadConstants.MAX_CONCURRENCY, Math.max(UploadConstants.BASE_CONCURRENCY, totalFiles / 50));
321
+ }
322
+ else if (totalFiles > 1000) {
323
+ optimalConcurrency = Math.min(UploadConstants.MAX_CONCURRENCY, UploadConstants.BASE_CONCURRENCY + Math.floor(totalFiles / 200));
324
+ }
325
+ else {
326
+ optimalConcurrency = Math.min(UploadConstants.MAX_CONCURRENCY, UploadConstants.BASE_CONCURRENCY);
327
+ }
328
+ return Math.floor(optimalConcurrency);
325
329
  }
326
- function collectAllFiles(folderPath, basePath, runIdFolderPrefix) {
327
- const files = [];
328
- const stack = [folderPath];
329
- while (stack.length > 0) {
330
- const currentPath = stack.pop();
331
- try {
332
- const items = readdirSync(currentPath);
333
- for (const item of items) {
334
- const itemPath = join(currentPath, item);
335
- const stats = statSync(itemPath);
336
- if (stats.isDirectory()) {
337
- stack.push(itemPath);
338
- } else {
339
- let relativePath = relative(basePath, itemPath).split("\\").join("/");
340
- if (runIdFolderPrefix) {
341
- relativePath = `${runIdFolderPrefix}/${relativePath}`;
342
- }
343
- files.push({
344
- fullPath: itemPath,
345
- relativePath,
346
- size: stats.size,
347
- contentType: getContentType(itemPath)
348
- });
330
+ export function collectAllFiles(folderPath, basePath, runIdFolderPrefix) {
331
+ const files = [];
332
+ const stack = [folderPath];
333
+ while (stack.length > 0) {
334
+ const currentPath = stack.pop();
335
+ try {
336
+ const items = readdirSync(currentPath);
337
+ for (const item of items) {
338
+ const itemPath = join(currentPath, item);
339
+ const stats = statSync(itemPath);
340
+ if (stats.isDirectory()) {
341
+ stack.push(itemPath);
342
+ }
343
+ else {
344
+ let relativePath = relative(basePath, itemPath).split("\\").join("/");
345
+ if (runIdFolderPrefix) {
346
+ relativePath = `${runIdFolderPrefix}/${relativePath}`;
347
+ }
348
+ files.push({
349
+ fullPath: itemPath,
350
+ relativePath,
351
+ size: stats.size,
352
+ contentType: getContentType(itemPath),
353
+ });
354
+ }
355
+ }
356
+ }
357
+ catch (error) {
358
+ continue;
349
359
  }
350
- }
351
- } catch (error) {
352
- continue;
353
360
  }
354
- }
355
- return files;
361
+ return files;
356
362
  }
357
- function resolveTenantDomain(tenantId, tenants) {
358
- if (!tenantId || tenants.length === 0) {
359
- return void 0;
360
- }
361
- const matchingTenant = tenants.find((t) => t.tenantId === tenantId);
362
- coreLogger.info(
363
- `Resolved tenant domain: ${JSON.stringify(matchingTenant?.defaultDomain)} for tenant ID: ${tenantId}`
364
- );
365
- return matchingTenant?.defaultDomain;
366
- }
367
- function getPortalTestRunUrl(workspaceMetadata, tenantDomain) {
368
- const { subscriptionId, resourceId, name } = workspaceMetadata ?? {};
369
- if (!subscriptionId || !resourceId || !name) {
370
- throw new Error(
371
- "Missing required workspace metadata: subscriptionId, resourceId, and name are required"
372
- );
373
- }
374
- const resourceIdParts = resourceId.split("/");
375
- const resourceGroupIndex = resourceIdParts.findIndex(
376
- (part) => part.toLowerCase() === UrlConstants.ResourceGroupsPath
377
- );
378
- if (resourceGroupIndex === -1 || resourceGroupIndex + 1 >= resourceIdParts.length) {
379
- throw new Error("Invalid resourceId format: could not extract resource group name");
380
- }
381
- const resourceGroupName = resourceIdParts[resourceGroupIndex + 1];
382
- const tenantFragment = tenantDomain ? `#@${tenantDomain}` : "#";
383
- return `${UrlConstants.AzurePortalBaseUrl}/${tenantFragment}${UrlConstants.ResourcePath}${UrlConstants.SubscriptionsPath}/${encodeURIComponent(subscriptionId)}${UrlConstants.ResourceGroupsUrlPath}/${encodeURIComponent(resourceGroupName)}${UrlConstants.ProvidersPath}/${UrlConstants.LoadTestServiceProvider}/${UrlConstants.PlaywrightWorkspacesResourceType}/${encodeURIComponent(name)}/${UrlConstants.TestRunsRoute}`;
363
+ export function getPortalTestRunUrl(resourceId) {
364
+ if (!resourceId) {
365
+ throw new Error("Missing required parameter: resourceId is required");
366
+ }
367
+ const runId = process.env[InternalEnvironmentVariables.MPT_SERVICE_RUN_ID];
368
+ if (!runId) {
369
+ throw new Error("Run ID is required but not found in environment variables");
370
+ }
371
+ return `${UrlConstants.AzurePortalBaseUrl}/${UrlConstants.TestReportViewPath}/testRunId/${encodeURIComponent(runId)}/resourceId/${encodeURIComponent(resourceId)}`;
384
372
  }
385
- const getStorageAccountNameFromUri = (storageUri) => {
386
- try {
387
- if (!storageUri || typeof storageUri !== "string") {
388
- return null;
373
+ export const getStorageAccountNameFromUri = (storageUri) => {
374
+ try {
375
+ if (!storageUri || typeof storageUri !== "string") {
376
+ return null;
377
+ }
378
+ const url = new URL(storageUri);
379
+ const hostname = url.hostname;
380
+ // Extract storage account name from hostname pattern: {accountname}.blob.core.windows.net
381
+ const match = hostname.match(/^([^.]+)\.blob\.core\.windows\.net$/i);
382
+ if (match && match[1]) {
383
+ return match[1];
384
+ }
385
+ return null;
389
386
  }
390
- const url = new URL(storageUri);
391
- const hostname = url.hostname;
392
- const match = hostname.match(/^([^.]+)\.blob\.core\.windows\.net$/i);
393
- if (match && match[1]) {
394
- return match[1];
387
+ catch (error) {
388
+ console.warn("Failed to extract storage account name from URI:", storageUri, error);
389
+ return null;
395
390
  }
396
- return null;
397
- } catch (error) {
398
- console.warn("Failed to extract storage account name from URI:", storageUri, error);
399
- return null;
400
- }
401
- };
402
- export {
403
- ValidateRunID,
404
- calculateOptimalConcurrency,
405
- collectAllFiles,
406
- exitWithFailureMessage,
407
- extractErrorMessage,
408
- fetchOrValidateAccessToken,
409
- getAccessToken,
410
- getAndSetRunId,
411
- getContentType,
412
- getHtmlReporterOutputFolder,
413
- getPackageVersion,
414
- getPlaywrightVersion2 as getPlaywrightVersion,
415
- getPortalTestRunUrl,
416
- getRunName,
417
- getServiceBaseURL,
418
- getServiceWSEndpoint,
419
- getStorageAccountNameFromUri,
420
- getTestRunApiUrl,
421
- getTestRunConfig,
422
- getVersionInfo,
423
- getWorkspaceMetaDataApiUrl,
424
- isNullOrEmpty,
425
- isValidGuid,
426
- parseJwt2 as parseJwt,
427
- populateValuesFromServiceUrl,
428
- resolveTenantDomain,
429
- throwErrorWithFailureMessage,
430
- validateMptPAT,
431
- validatePlaywrightVersion,
432
- validateServiceUrl,
433
- warnIfAccessTokenCloseToExpiry
434
391
  };
392
+ //# sourceMappingURL=utils.js.map