@azure/playwright 1.1.0 → 1.1.1
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/dist/browser/common/messages.d.ts +5 -0
- package/dist/browser/common/messages.d.ts.map +1 -1
- package/dist/browser/common/messages.js +5 -0
- package/dist/browser/common/messages.js.map +1 -1
- package/dist/browser/reporter/playwrightReporter.d.ts.map +1 -1
- package/dist/browser/reporter/playwrightReporter.js +9 -12
- package/dist/browser/reporter/playwrightReporter.js.map +1 -1
- package/dist/browser/utils/playwrightReporterStorageManager.d.ts.map +1 -1
- package/dist/browser/utils/playwrightReporterStorageManager.js +98 -13
- package/dist/browser/utils/playwrightReporterStorageManager.js.map +1 -1
- package/dist/commonjs/common/messages.d.ts +5 -0
- package/dist/commonjs/common/messages.d.ts.map +1 -1
- package/dist/commonjs/common/messages.js +5 -0
- package/dist/commonjs/common/messages.js.map +1 -1
- package/dist/commonjs/reporter/playwrightReporter.d.ts.map +1 -1
- package/dist/commonjs/reporter/playwrightReporter.js +9 -12
- package/dist/commonjs/reporter/playwrightReporter.js.map +1 -1
- package/dist/commonjs/utils/playwrightReporterStorageManager.d.ts.map +1 -1
- package/dist/commonjs/utils/playwrightReporterStorageManager.js +98 -13
- package/dist/commonjs/utils/playwrightReporterStorageManager.js.map +1 -1
- package/dist/esm/common/messages.d.ts +5 -0
- package/dist/esm/common/messages.d.ts.map +1 -1
- package/dist/esm/common/messages.js +5 -0
- package/dist/esm/common/messages.js.map +1 -1
- package/dist/esm/reporter/playwrightReporter.d.ts.map +1 -1
- package/dist/esm/reporter/playwrightReporter.js +9 -12
- package/dist/esm/reporter/playwrightReporter.js.map +1 -1
- package/dist/esm/utils/playwrightReporterStorageManager.d.ts.map +1 -1
- package/dist/esm/utils/playwrightReporterStorageManager.js +98 -13
- package/dist/esm/utils/playwrightReporterStorageManager.js.map +1 -1
- package/dist/react-native/common/messages.d.ts +5 -0
- package/dist/react-native/common/messages.d.ts.map +1 -1
- package/dist/react-native/common/messages.js +5 -0
- package/dist/react-native/common/messages.js.map +1 -1
- package/dist/react-native/reporter/playwrightReporter.d.ts.map +1 -1
- package/dist/react-native/reporter/playwrightReporter.js +9 -12
- package/dist/react-native/reporter/playwrightReporter.js.map +1 -1
- package/dist/react-native/utils/playwrightReporterStorageManager.d.ts.map +1 -1
- package/dist/react-native/utils/playwrightReporterStorageManager.js +98 -13
- package/dist/react-native/utils/playwrightReporterStorageManager.js.map +1 -1
- package/package.json +4 -4
|
@@ -78,6 +78,11 @@ export declare const ServiceErrorMessageConstants: {
|
|
|
78
78
|
key: string;
|
|
79
79
|
message: string;
|
|
80
80
|
};
|
|
81
|
+
STORAGE_ACCOUNT_DELETED: {
|
|
82
|
+
key: string;
|
|
83
|
+
message: string;
|
|
84
|
+
formatWithStorageAccount: (storageAccountName: string) => string;
|
|
85
|
+
};
|
|
81
86
|
REPORTER_REQUIRES_ENTRA_AUTH: {
|
|
82
87
|
key: string;
|
|
83
88
|
message: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../src/common/messages.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+CA0DE,MAAM,KAAG,MAAM;;;;;;;;;;;;;;;;;+CAkBf,MAAM,KAAG,MAAM;;;;;;;;;uDAWP,MAAM,KAAG,MAAM
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../src/common/messages.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+CA0DE,MAAM,KAAG,MAAM;;;;;;;;;;;;;;;;;+CAkBf,MAAM,KAAG,MAAM;;;;;;;;;uDAWP,MAAM,KAAG,MAAM;;;;;;;;;uDAWf,MAAM,KAAG,MAAM;;;;;;;;;;;;;;;;;;;;;kCA0BpC,MAAM,KAAG,MAAM;;;;;uCAMV,MAAM,KAAG,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;6BA0BzB,MAAM,KAAG,MAAM;;;;;4CAKA,MAAM,aAAa,MAAM,UAAU,MAAM,KAAG,MAAM;;;;;iCAM7D,MAAM,KAAG,MAAM;;;;;+CAKD,MAAM,KAAG,MAAM;;;;;;;;;;CAYzD,CAAC"}
|
|
@@ -80,6 +80,11 @@ export const ServiceErrorMessageConstants = {
|
|
|
80
80
|
key: "UnableToExtractWorkspaceId",
|
|
81
81
|
message: "Unable to extract workspace ID from service URL",
|
|
82
82
|
},
|
|
83
|
+
STORAGE_ACCOUNT_DELETED: {
|
|
84
|
+
key: "StorageAccountDeleted",
|
|
85
|
+
message: "The storage account linked to your Playwright Workspace may have been deleted. Please link a different storage account to your Playwright Workspace before trying again. To learn more on how to link a new storage account, refer to https://aka.ms/pww-reporting-migration",
|
|
86
|
+
formatWithStorageAccount: (storageAccountName) => `The storage account linked to your Playwright Workspace (${storageAccountName}) may have been deleted. Please link a different storage account to your Playwright Workspace before trying again. To learn more on how to link a new storage account, refer to https://aka.ms/pww-reporting-migration`,
|
|
87
|
+
},
|
|
83
88
|
REPORTER_REQUIRES_ENTRA_AUTH: {
|
|
84
89
|
key: "ReporterRequiresEntraAuth",
|
|
85
90
|
message: "Playwright Workspaces Reporter can only be used with ENTRA_ID authentication. For more information, see https://aka.ms/pww/docs/authentication",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../../src/common/messages.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC,MAAM,CAAC,MAAM,4BAA4B,GAAG;IAC1C,oBAAoB,EAAE;QACpB,GAAG,EAAE,mBAAmB;QACxB,OAAO,EACL,8GAA8G;KACjH;IACD,uBAAuB,EAAE;QACvB,GAAG,EAAE,uBAAuB;QAC5B,OAAO,EAAE,qCAAqC;KAC/C;IACD,gCAAgC,EAAE;QAChC,GAAG,EAAE,+BAA+B;QACpC,OAAO,EACL,0IAA0I;KAC7I;IACD,wCAAwC,EAAE;QACxC,GAAG,EAAE,qCAAqC;QAC1C,OAAO,EACL,8KAA8K;KACjL;IACD,4CAA4C,EAAE;QAC5C,GAAG,EAAE,yCAAyC;QAC9C,OAAO,EACL,4IAA4I;KAC/I;IACD,wBAAwB,EAAE;QACxB,GAAG,EAAE,oBAAoB;QACzB,OAAO,EACL,mHAAmH;KACtH;IACD,uBAAuB,EAAE;QACvB,GAAG,EAAE,qBAAqB;QAC1B,OAAO,EACL,kKAAkK;KACrK;IACD,yBAAyB,EAAE;QACzB,GAAG,EAAE,uBAAuB;QAC5B,OAAO,EACL,2GAA2G;KAC9G;IACD,qBAAqB,EAAE;QACrB,GAAG,EAAE,oBAAoB;QACzB,OAAO,EACL,iGAAiG;KACpG;IACD,qBAAqB,EAAE;QACrB,GAAG,EAAE,oBAAoB;QACzB,OAAO,EAAE,+EAA+E;KACzF;IACD,wBAAwB,EAAE;QACxB,GAAG,EAAE,sBAAsB;QAC3B,OAAO,EACL,sLAAsL;KACzL;IACD,yBAAyB,EAAE;QACzB,GAAG,EAAE,uBAAuB;QAC5B,OAAO,EACL,+HAA+H;QACjI,sBAAsB,EAAE,CAAC,YAAoB,EAAU,EAAE,CACvD,sEAAsE,YAAY,qEAAqE;KAC1J;IACD,iCAAiC,EAAE;QACjC,GAAG,EAAE,+BAA+B;QACpC,OAAO,EAAE,4KAA4K;KACtL;IACD,qBAAqB,EAAE;QACrB,GAAG,EAAE,oBAAoB;QACzB,OAAO,EAAE,qFAAqF;KAC/F;IACD,uBAAuB,EAAE;QACvB,GAAG,EAAE,sBAAsB;QAC3B,OAAO,EAAE,oFAAoF;KAC9F;IACD,+BAA+B,EAAE;QAC/B,GAAG,EAAE,6BAA6B;QAClC,OAAO,EAAE,mEAAmE;QAC5E,sBAAsB,EAAE,CAAC,YAAoB,EAAU,EAAE,CACvD,4EAA4E,YAAY,kEAAkE;KAC7J;IACD,qBAAqB,EAAE;QACrB,GAAG,EAAE,oBAAoB;QACzB,OAAO,EAAE,+DAA+D;KACzE;IACD,4BAA4B,EAAE;QAC5B,GAAG,EAAE,4BAA4B;QACjC,OAAO,EACL,gNAAgN;QAClN,wBAAwB,EAAE,CAAC,kBAA0B,EAAU,EAAE,CAC/D,4JAA4J,kBAAkB,0DAA0D;KAC3O;IACD,8BAA8B,EAAE;QAC9B,GAAG,EAAE,4BAA4B;QACjC,OAAO,EAAE,iDAAiD;KAC3D;IACD,4BAA4B,EAAE;QAC5B,GAAG,EAAE,2BAA2B;QAChC,OAAO,EACL,gJAAgJ;KACnJ;IACD,sBAAsB,EAAE;QACtB,GAAG,EAAE,sBAAsB;QAC3B,OAAO,EACL,0WAA0W;KAC7W;IACD,+BAA+B,EAAE;QAC/B,GAAG,EAAE,8BAA8B;QACnC,OAAO,EACL,oJAAoJ;KACvJ;IACD,4BAA4B,EAAE;QAC5B,GAAG,EAAE,4BAA4B;QACjC,OAAO,EACL,kOAAkO;KACrO;IACD,mBAAmB,EAAE;QACnB,GAAG,EAAE,mBAAmB;QACxB,OAAO,EAAE,4CAA4C;QACrD,eAAe,EAAE,CAAC,MAAc,EAAU,EAAE,CAC1C,kBAAkB,MAAM,8BAA8B;KACzD;IACD,gCAAgC,EAAE;QAChC,GAAG,EAAE,8BAA8B;QACnC,OAAO,EAAE,kCAAkC;QAC3C,gBAAgB,EAAE,CAAC,UAAkB,EAAU,EAAE,CAC/C,qCAAqC,UAAU,0DAA0D;KAC5G;IACD,iBAAiB,EAAE;QACjB,GAAG,EAAE,kBAAkB;QACvB,OAAO,EAAE,0CAA0C;KACpD;IACD,oBAAoB,EAAE;QACpB,GAAG,EAAE,qBAAqB;QAC1B,OAAO,EAAE,oDAAoD;KAC9D;IACD,wBAAwB,EAAE;QACxB,GAAG,EAAE,wBAAwB;QAC7B,OAAO,EAAE,kCAAkC;KAC5C;IACD,wBAAwB,EAAE;QACxB,GAAG,EAAE,wBAAwB;QAC7B,OAAO,EAAE,6CAA6C;KACvD;IACD,uBAAuB,EAAE;QACvB,GAAG,EAAE,uBAAuB;QAC5B,OAAO,EAAE,iCAAiC;KAC3C;IACD,oBAAoB,EAAE;QACpB,GAAG,EAAE,mBAAmB;QACxB,OAAO,EAAE,wBAAwB;QACjC,aAAa,EAAE,CAAC,GAAW,EAAU,EAAE,CAAC,yBAAyB,GAAG,EAAE;KACvE;IACD,mBAAmB,EAAE;QACnB,GAAG,EAAE,oBAAoB;QACzB,OAAO,EAAE,gCAAgC;QACzC,iBAAiB,EAAE,CAAC,cAAsB,EAAE,SAAiB,EAAE,MAAc,EAAU,EAAE,CACvF,4CAA4C,cAAc,wBAAwB,SAAS,aAAa,MAAM,EAAE;KACnH;IACD,gCAAgC,EAAE;QAChC,GAAG,EAAE,8BAA8B;QACnC,OAAO,EAAE,kCAAkC;QAC3C,eAAe,EAAE,CAAC,KAAa,EAAU,EAAE,CAAC,KAAK;KAClD;IACD,wBAAwB,EAAE;QACxB,GAAG,EAAE,uBAAuB;QAC5B,OAAO,EAAE,0DAA0D;QACnE,sBAAsB,EAAE,CAAC,YAAoB,EAAU,EAAE,CACvD,qCAAqC,YAAY,iCAAiC;KACrF;IACD,yBAAyB,EAAE;QACzB,GAAG,EAAE,wBAAwB;QAC7B,OAAO,EAAE,wCAAwC;KAClD;IACD,gCAAgC,EAAE;QAChC,GAAG,EAAE,+BAA+B;QACpC,OAAO,EACL,mKAAmK;KACtK;CACF,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nexport const ServiceErrorMessageConstants = {\n NO_SERVICE_URL_ERROR: {\n key: \"NoServiceUrlError\",\n message:\n \"The value for the PLAYWRIGHT_SERVICE_URL variable is not set correctly. Please verify the URL and try again.\",\n },\n INVALID_GLOBAL_FUNCTION: {\n key: \"InvalidGlobalFunction\",\n message: \"File must export a single function.\",\n },\n INVALID_PLAYWRIGHT_VERSION_ERROR: {\n key: \"InvalidPlaywrightVersionError\",\n message:\n \"The Playwright version you are using is not supported. See the list of supported versions at https://aka.ms/pww/docs/supported-versions.\",\n },\n PLAYWRIGHT_VERSION_TOO_OLD_FOR_REPORTING: {\n key: \"PlaywrightVersionTooOldForReporting\",\n message:\n \"To use the Playwright Workspaces reporting feature, you need Playwright version 1.57 or later installed. Update the Playwright package to a supported version and try again.\",\n },\n MULTIPLE_SETUP_FILE_PLAYWRIGHT_VERSION_ERROR: {\n key: \"MultipleSetupFilePlaywrightVersionError\",\n message:\n \"The Playwright version you are using does not support multiple setup/teardown files. Please update to Playwright version 1.49.0 or higher.\",\n },\n WORKSPACE_MISMATCH_ERROR: {\n key: \"InvalidAccessToken\",\n message:\n \"The provided access token does not match the specified workspace URL. Please verify that both values are correct.\",\n },\n NO_AUTH_ERROR_PAT_TOKEN: {\n key: \"NoAuthErrorPatToken\",\n message:\n \"Please set PLAYWRIGHT_SERVICE_ACCESS_TOKEN env variable when using ACCESS_TOKEN authentication. For more information, see https://aka.ms/pww/docs/authentication\",\n },\n NO_AUTH_ERROR_ENTRA_TOKEN: {\n key: \"NoAuthErrorEntraToken\",\n message:\n \"Could not authenticate with the service. For more information, see https://aka.ms/pww/docs/authentication\",\n },\n INVALID_MPT_PAT_ERROR: {\n key: \"InvalidMptPatError\",\n message:\n \"The PLAYWRIGHT_SERVICE_ACCESS_TOKEN provided is invalid. Please make sure to set a valid token.\",\n },\n EXPIRED_MPT_PAT_ERROR: {\n key: \"ExpiredMptPatError\",\n message: \"The PLAYWRIGHT_SERVICE_ACCESS_TOKEN provided has expired. Create a new token.\",\n },\n NO_CRED_ENTRA_AUTH_ERROR: {\n key: \"NoCredEntraAuthError\",\n message:\n \"Missing 'credential' parameter which is required when using ENTRA_ID authentication, Azure credential not provided. See https://aka.ms/pww/docs/authentication for more information.\",\n },\n FAILED_TO_CREATE_TEST_RUN: {\n key: \"FailedToCreateTestRun\",\n message:\n \"Failed to create the test run in the Playwright workspaces. For more information, see https://aka.ms/pww/docs/troubleshooting\",\n formatWithErrorDetails: (errorDetails: string): string =>\n `Failed to create the test run in the Playwright workspaces. Error: ${errorDetails}. For more information, see https://aka.ms/pww/docs/troubleshooting`,\n },\n INVALID_PARAM_WITH_SERVICE_CONFIG: {\n key: \"InvalidParamWithServiceConfig\",\n message: `Remove serviceAuth, runId, and runName from getConnectOptions when using createAzurePlaywrightConfig. Configure these options through createAzurePlaywrightConfig instead.`,\n },\n INVALID_RUN_ID_FORMAT: {\n key: \"InvalidRunIdFormat\",\n message: \"The Run ID must be a valid GUID format. Please provide a valid GUID for the Run ID.\",\n },\n INVALID_AUTH_TYPE_ERROR: {\n key: \"InvalidAuthTypeError\",\n message: \"Invalid authentication type specified. Please use either ENTRA_ID or ACCESS_TOKEN.\",\n },\n FAILED_TO_GET_WORKSPACE_DETAILS: {\n key: \"FailedToGetWorkspaceDetails\",\n message: \"Failed to retrieve workspace details from the Playwright service.\",\n formatWithErrorDetails: (errorDetails: string): string =>\n `Failed to retrieve workspace details from the Playwright service. Error: ${errorDetails}. Please verify your service URL and authentication credentials.`,\n },\n STORAGE_URI_NOT_FOUND: {\n key: \"StorageUriNotFound\",\n message: \"Storage Account is not linked with this Playwright Workspace.\",\n },\n STORAGE_AUTHORIZATION_FAILED: {\n key: \"StorageAuthorizationFailed\",\n message:\n \"The user is not authorized to perform this operation. Please make sure you have the Storage Blob Data Contributor role assigned to the storage account. For more information, see https://aka.ms/pww-reporting\",\n formatWithStorageAccount: (storageAccountName: string): string =>\n `The user is not authorized to perform this operation. Please make sure you have the Storage Blob Data Contributor role assigned to the storage account - ${storageAccountName}. For more information, see https://aka.ms/pww-reporting`,\n },\n UNABLE_TO_EXTRACT_WORKSPACE_ID: {\n key: \"UnableToExtractWorkspaceId\",\n message: \"Unable to extract workspace ID from service URL\",\n },\n REPORTER_REQUIRES_ENTRA_AUTH: {\n key: \"ReporterRequiresEntraAuth\",\n message:\n \"Playwright Workspaces Reporter can only be used with ENTRA_ID authentication. For more information, see https://aka.ms/pww/docs/authentication\",\n },\n HTML_REPORTER_REQUIRED: {\n key: \"HtmlReporterRequired\",\n message:\n \"Playwright Workspaces Reporter requires the 'html' reporter to be configured in your Playwright configuration. Please add the 'html' reporter before playwright workspace reporter to generate test reports that can be uploaded to Azure Storage. Example: reporter: [['html'], ['@azure/playwright/reporter']]. For more information, see https://aka.ms/pww-reporting\",\n },\n WORKSPACE_METADATA_FETCH_FAILED: {\n key: \"WorkspaceMetadataFetchFailed\",\n message:\n \"Failed to retrieve workspace configuration. Reporting will be disabled for this run. Please check your authentication credentials and service URL.\",\n },\n WORKSPACE_REPORTING_DISABLED: {\n key: \"WorkspaceReportingDisabled\",\n message:\n \"Playwright Workspaces reporting: DISABLED. Reporting is not enabled for the Playwright Workspace. To learn more about how to enable reporting and link a storage account, For more information, see https://aka.ms/pww-reporting\",\n },\n UPLOAD_FAILED_FILES: {\n key: \"UploadFailedFiles\",\n message: \"Upload failed: files could not be uploaded\",\n formatWithCount: (failed: number): string =>\n `Upload failed: ${failed} files could not be uploaded`,\n },\n PLAYWRIGHT_TEST_REPORT_NOT_FOUND: {\n key: \"PlaywrightTestReportNotFound\",\n message: \"Playwright test report not found\",\n formatWithFolder: (folderName: string): string =>\n `Playwright test report not found: ${folderName}. For more information, see https://aka.ms/pww-reporting`,\n },\n REPORTING_ENABLED: {\n key: \"ReportingEnabled\",\n message: \"Playwright Workspaces reporting: ENABLED\",\n },\n COLLECTING_ARTIFACTS: {\n key: \"CollectingArtifacts\",\n message: \"Collecting artifacts: screenshots, videos, traces.\",\n },\n REPORTING_STATUS_SUCCESS: {\n key: \"ReportingStatusSuccess\",\n message: \"Reporting upload status: SUCCESS\",\n },\n REPORTING_STATUS_PARTIAL: {\n key: \"ReportingStatusPartial\",\n message: \"Reporting upload status: Partially Uploaded\",\n },\n REPORTING_STATUS_FAILED: {\n key: \"ReportingStatusFailed\",\n message: \"Reporting upload status: FAILED\",\n },\n TEST_REPORT_VIEW_URL: {\n key: \"TestReportViewUrl\",\n message: \"Published report URL: \",\n formatWithUrl: (url: string): string => `Published report URL: ${url}`,\n },\n UPLOADING_ARTIFACTS: {\n key: \"UploadingArtifacts\",\n message: \"Uploading artifacts to storage\",\n formatWithDetails: (storageAccount: string, container: string, folder: string): string =>\n `Uploading artifacts to: storage account= ${storageAccount}, storage container= ${container}, folder= ${folder}`,\n },\n FAILED_TO_GET_WORKSPACE_METADATA: {\n key: \"FailedToGetWorkspaceMetadata\",\n message: \"Failed to get workspace metadata\",\n formatWithError: (error: string): string => error,\n },\n TEST_RUN_CREATION_FAILED: {\n key: \"TestRunCreationFailed\",\n message: \"Failed to create test run. Test execution will continue.\",\n formatWithErrorDetails: (errorDetails: string): string =>\n `Failed to create test run. Error: ${errorDetails}. Test execution will continue.`,\n },\n REPORTING_TEST_RUN_FAILED: {\n key: \"ReportingTestRunFailed\",\n message: \"Test run creation failed during setup.\",\n },\n REPORTER_REQUIRES_SERVICE_CONFIG: {\n key: \"ReporterRequiresServiceConfig\",\n message:\n \"Playwright Workspaces Reporter requires the use of service configuration via createAzurePlaywrightConfig. For more information, see https://aka.ms/pww-reporting.\",\n },\n};\n"]}
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../../src/common/messages.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nexport const ServiceErrorMessageConstants = {\n NO_SERVICE_URL_ERROR: {\n key: \"NoServiceUrlError\",\n message:\n \"The value for the PLAYWRIGHT_SERVICE_URL variable is not set correctly. Please verify the URL and try again.\",\n },\n INVALID_GLOBAL_FUNCTION: {\n key: \"InvalidGlobalFunction\",\n message: \"File must export a single function.\",\n },\n INVALID_PLAYWRIGHT_VERSION_ERROR: {\n key: \"InvalidPlaywrightVersionError\",\n message:\n \"The Playwright version you are using is not supported. See the list of supported versions at https://aka.ms/pww/docs/supported-versions.\",\n },\n PLAYWRIGHT_VERSION_TOO_OLD_FOR_REPORTING: {\n key: \"PlaywrightVersionTooOldForReporting\",\n message:\n \"To use the Playwright Workspaces reporting feature, you need Playwright version 1.57 or later installed. Update the Playwright package to a supported version and try again.\",\n },\n MULTIPLE_SETUP_FILE_PLAYWRIGHT_VERSION_ERROR: {\n key: \"MultipleSetupFilePlaywrightVersionError\",\n message:\n \"The Playwright version you are using does not support multiple setup/teardown files. Please update to Playwright version 1.49.0 or higher.\",\n },\n WORKSPACE_MISMATCH_ERROR: {\n key: \"InvalidAccessToken\",\n message:\n \"The provided access token does not match the specified workspace URL. Please verify that both values are correct.\",\n },\n NO_AUTH_ERROR_PAT_TOKEN: {\n key: \"NoAuthErrorPatToken\",\n message:\n \"Please set PLAYWRIGHT_SERVICE_ACCESS_TOKEN env variable when using ACCESS_TOKEN authentication. For more information, see https://aka.ms/pww/docs/authentication\",\n },\n NO_AUTH_ERROR_ENTRA_TOKEN: {\n key: \"NoAuthErrorEntraToken\",\n message:\n \"Could not authenticate with the service. For more information, see https://aka.ms/pww/docs/authentication\",\n },\n INVALID_MPT_PAT_ERROR: {\n key: \"InvalidMptPatError\",\n message:\n \"The PLAYWRIGHT_SERVICE_ACCESS_TOKEN provided is invalid. Please make sure to set a valid token.\",\n },\n EXPIRED_MPT_PAT_ERROR: {\n key: \"ExpiredMptPatError\",\n message: \"The PLAYWRIGHT_SERVICE_ACCESS_TOKEN provided has expired. Create a new token.\",\n },\n NO_CRED_ENTRA_AUTH_ERROR: {\n key: \"NoCredEntraAuthError\",\n message:\n \"Missing 'credential' parameter which is required when using ENTRA_ID authentication, Azure credential not provided. See https://aka.ms/pww/docs/authentication for more information.\",\n },\n FAILED_TO_CREATE_TEST_RUN: {\n key: \"FailedToCreateTestRun\",\n message:\n \"Failed to create the test run in the Playwright workspaces. For more information, see https://aka.ms/pww/docs/troubleshooting\",\n formatWithErrorDetails: (errorDetails: string): string =>\n `Failed to create the test run in the Playwright workspaces. Error: ${errorDetails}. For more information, see https://aka.ms/pww/docs/troubleshooting`,\n },\n INVALID_PARAM_WITH_SERVICE_CONFIG: {\n key: \"InvalidParamWithServiceConfig\",\n message: `Remove serviceAuth, runId, and runName from getConnectOptions when using createAzurePlaywrightConfig. Configure these options through createAzurePlaywrightConfig instead.`,\n },\n INVALID_RUN_ID_FORMAT: {\n key: \"InvalidRunIdFormat\",\n message: \"The Run ID must be a valid GUID format. Please provide a valid GUID for the Run ID.\",\n },\n INVALID_AUTH_TYPE_ERROR: {\n key: \"InvalidAuthTypeError\",\n message: \"Invalid authentication type specified. Please use either ENTRA_ID or ACCESS_TOKEN.\",\n },\n FAILED_TO_GET_WORKSPACE_DETAILS: {\n key: \"FailedToGetWorkspaceDetails\",\n message: \"Failed to retrieve workspace details from the Playwright service.\",\n formatWithErrorDetails: (errorDetails: string): string =>\n `Failed to retrieve workspace details from the Playwright service. Error: ${errorDetails}. Please verify your service URL and authentication credentials.`,\n },\n STORAGE_URI_NOT_FOUND: {\n key: \"StorageUriNotFound\",\n message: \"Storage Account is not linked with this Playwright Workspace.\",\n },\n STORAGE_AUTHORIZATION_FAILED: {\n key: \"StorageAuthorizationFailed\",\n message:\n \"The user is not authorized to perform this operation. Please make sure you have the Storage Blob Data Contributor role assigned to the storage account. For more information, see https://aka.ms/pww-reporting\",\n formatWithStorageAccount: (storageAccountName: string): string =>\n `The user is not authorized to perform this operation. Please make sure you have the Storage Blob Data Contributor role assigned to the storage account - ${storageAccountName}. For more information, see https://aka.ms/pww-reporting`,\n },\n UNABLE_TO_EXTRACT_WORKSPACE_ID: {\n key: \"UnableToExtractWorkspaceId\",\n message: \"Unable to extract workspace ID from service URL\",\n },\n STORAGE_ACCOUNT_DELETED: {\n key: \"StorageAccountDeleted\",\n message:\n \"The storage account linked to your Playwright Workspace may have been deleted. Please link a different storage account to your Playwright Workspace before trying again. To learn more on how to link a new storage account, refer to https://aka.ms/pww-reporting-migration\",\n formatWithStorageAccount: (storageAccountName: string): string =>\n `The storage account linked to your Playwright Workspace (${storageAccountName}) may have been deleted. Please link a different storage account to your Playwright Workspace before trying again. To learn more on how to link a new storage account, refer to https://aka.ms/pww-reporting-migration`,\n },\n REPORTER_REQUIRES_ENTRA_AUTH: {\n key: \"ReporterRequiresEntraAuth\",\n message:\n \"Playwright Workspaces Reporter can only be used with ENTRA_ID authentication. For more information, see https://aka.ms/pww/docs/authentication\",\n },\n HTML_REPORTER_REQUIRED: {\n key: \"HtmlReporterRequired\",\n message:\n \"Playwright Workspaces Reporter requires the 'html' reporter to be configured in your Playwright configuration. Please add the 'html' reporter before playwright workspace reporter to generate test reports that can be uploaded to Azure Storage. Example: reporter: [['html'], ['@azure/playwright/reporter']]. For more information, see https://aka.ms/pww-reporting\",\n },\n WORKSPACE_METADATA_FETCH_FAILED: {\n key: \"WorkspaceMetadataFetchFailed\",\n message:\n \"Failed to retrieve workspace configuration. Reporting will be disabled for this run. Please check your authentication credentials and service URL.\",\n },\n WORKSPACE_REPORTING_DISABLED: {\n key: \"WorkspaceReportingDisabled\",\n message:\n \"Playwright Workspaces reporting: DISABLED. Reporting is not enabled for the Playwright Workspace. To learn more about how to enable reporting and link a storage account, For more information, see https://aka.ms/pww-reporting\",\n },\n UPLOAD_FAILED_FILES: {\n key: \"UploadFailedFiles\",\n message: \"Upload failed: files could not be uploaded\",\n formatWithCount: (failed: number): string =>\n `Upload failed: ${failed} files could not be uploaded`,\n },\n PLAYWRIGHT_TEST_REPORT_NOT_FOUND: {\n key: \"PlaywrightTestReportNotFound\",\n message: \"Playwright test report not found\",\n formatWithFolder: (folderName: string): string =>\n `Playwright test report not found: ${folderName}. For more information, see https://aka.ms/pww-reporting`,\n },\n REPORTING_ENABLED: {\n key: \"ReportingEnabled\",\n message: \"Playwright Workspaces reporting: ENABLED\",\n },\n COLLECTING_ARTIFACTS: {\n key: \"CollectingArtifacts\",\n message: \"Collecting artifacts: screenshots, videos, traces.\",\n },\n REPORTING_STATUS_SUCCESS: {\n key: \"ReportingStatusSuccess\",\n message: \"Reporting upload status: SUCCESS\",\n },\n REPORTING_STATUS_PARTIAL: {\n key: \"ReportingStatusPartial\",\n message: \"Reporting upload status: Partially Uploaded\",\n },\n REPORTING_STATUS_FAILED: {\n key: \"ReportingStatusFailed\",\n message: \"Reporting upload status: FAILED\",\n },\n TEST_REPORT_VIEW_URL: {\n key: \"TestReportViewUrl\",\n message: \"Published report URL: \",\n formatWithUrl: (url: string): string => `Published report URL: ${url}`,\n },\n UPLOADING_ARTIFACTS: {\n key: \"UploadingArtifacts\",\n message: \"Uploading artifacts to storage\",\n formatWithDetails: (storageAccount: string, container: string, folder: string): string =>\n `Uploading artifacts to: storage account= ${storageAccount}, storage container= ${container}, folder= ${folder}`,\n },\n FAILED_TO_GET_WORKSPACE_METADATA: {\n key: \"FailedToGetWorkspaceMetadata\",\n message: \"Failed to get workspace metadata\",\n formatWithError: (error: string): string => error,\n },\n TEST_RUN_CREATION_FAILED: {\n key: \"TestRunCreationFailed\",\n message: \"Failed to create test run. Test execution will continue.\",\n formatWithErrorDetails: (errorDetails: string): string =>\n `Failed to create test run. Error: ${errorDetails}. Test execution will continue.`,\n },\n REPORTING_TEST_RUN_FAILED: {\n key: \"ReportingTestRunFailed\",\n message: \"Test run creation failed during setup.\",\n },\n REPORTER_REQUIRES_SERVICE_CONFIG: {\n key: \"ReporterRequiresServiceConfig\",\n message:\n \"Playwright Workspaces Reporter requires the use of service configuration via createAzurePlaywrightConfig. For more information, see https://aka.ms/pww-reporting.\",\n },\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"playwrightReporter.d.ts","sourceRoot":"","sources":["../../../src/reporter/playwrightReporter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAetE;;GAEG;AAEH,MAAM,CAAC,OAAO,OAAO,kBAAmB,YAAW,QAAQ;IACzD,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,iBAAiB,CAAkC;IAC3D,OAAO,CAAC,kBAAkB,CAAS;IAEnC;;;;OAIG;IAEG,OAAO,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"playwrightReporter.d.ts","sourceRoot":"","sources":["../../../src/reporter/playwrightReporter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAetE;;GAEG;AAEH,MAAM,CAAC,OAAO,OAAO,kBAAmB,YAAW,QAAQ;IACzD,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,iBAAiB,CAAkC;IAC3D,OAAO,CAAC,kBAAkB,CAAS;IAEnC;;;;OAIG;IAEG,OAAO,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAqFhD;;OAEG;IAEG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAiCd,gBAAgB;IAsB9B,OAAO,CAAC,iCAAiC;CAqC1C"}
|
|
@@ -66,25 +66,24 @@ export default class PlaywrightReporter {
|
|
|
66
66
|
return;
|
|
67
67
|
}
|
|
68
68
|
coreLogger.info("Authentication validation passed - using ENTRA_ID");
|
|
69
|
+
// Validate HTML reporter configuration
|
|
70
|
+
if (!this.validateHtmlReporterConfiguration(config)) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
69
73
|
// Get workspace metadata for later use
|
|
70
74
|
try {
|
|
71
75
|
const playwrightServiceApiClient = new PlaywrightServiceClient();
|
|
72
76
|
this.workspaceMetadata = await playwrightServiceApiClient.getWorkspaceMetadata();
|
|
73
77
|
if (!this.workspaceMetadata?.storageUri) {
|
|
74
78
|
console.error(ServiceErrorMessageConstants.WORKSPACE_REPORTING_DISABLED.message);
|
|
75
|
-
this.isReportingEnabled = false;
|
|
76
79
|
return;
|
|
77
80
|
}
|
|
78
81
|
this.isReportingEnabled = true;
|
|
79
|
-
|
|
80
|
-
if (this.isReportingEnabled) {
|
|
81
|
-
console.log(ServiceErrorMessageConstants.REPORTING_ENABLED.message);
|
|
82
|
-
}
|
|
82
|
+
console.log(ServiceErrorMessageConstants.REPORTING_ENABLED.message);
|
|
83
83
|
}
|
|
84
84
|
catch (error) {
|
|
85
85
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
86
86
|
console.error(`${ServiceErrorMessageConstants.WORKSPACE_METADATA_FETCH_FAILED.message}Error: ${errorMessage} `);
|
|
87
|
-
this.isReportingEnabled = false;
|
|
88
87
|
}
|
|
89
88
|
}
|
|
90
89
|
/**
|
|
@@ -142,8 +141,7 @@ export default class PlaywrightReporter {
|
|
|
142
141
|
validateHtmlReporterConfiguration(config) {
|
|
143
142
|
if (!config.reporter || !Array.isArray(config.reporter)) {
|
|
144
143
|
console.error(ServiceErrorMessageConstants.HTML_REPORTER_REQUIRED.message);
|
|
145
|
-
|
|
146
|
-
return;
|
|
144
|
+
return false;
|
|
147
145
|
}
|
|
148
146
|
const htmlReporterIndex = config.reporter.findIndex((reporter) => {
|
|
149
147
|
const reporterName = typeof reporter === "string" ? reporter : reporter?.[0];
|
|
@@ -158,16 +156,15 @@ export default class PlaywrightReporter {
|
|
|
158
156
|
// Validate HTML reporter exists
|
|
159
157
|
if (htmlReporterIndex === -1) {
|
|
160
158
|
console.error(ServiceErrorMessageConstants.HTML_REPORTER_REQUIRED.message);
|
|
161
|
-
|
|
162
|
-
return;
|
|
159
|
+
return false;
|
|
163
160
|
}
|
|
164
161
|
// Validate HTML reporter comes before Azure reporter (if Azure reporter exists)
|
|
165
162
|
if (azureReporterIndex !== -1 && htmlReporterIndex > azureReporterIndex) {
|
|
166
163
|
console.error(ServiceErrorMessageConstants.HTML_REPORTER_REQUIRED.message);
|
|
167
|
-
|
|
168
|
-
return;
|
|
164
|
+
return false;
|
|
169
165
|
}
|
|
170
166
|
coreLogger.info("HTML reporter validation passed - HTML reporter is configured and properly ordered");
|
|
167
|
+
return true;
|
|
171
168
|
}
|
|
172
169
|
}
|
|
173
170
|
//# sourceMappingURL=playwrightReporter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"playwrightReporter.js","sourceRoot":"","sources":["../../../src/reporter/playwrightReporter.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\nimport type { FullConfig, Reporter } from \"@playwright/test/reporter\";\nimport { PlaywrightReporterStorageManager } from \"../utils/playwrightReporterStorageManager.js\";\nimport {\n getHtmlReporterOutputFolder,\n getPortalTestRunUrl,\n getVersionInfo,\n} from \"../utils/utils.js\";\nimport { coreLogger } from \"../common/logger.js\";\nimport { PlaywrightServiceConfig } from \"../common/playwrightServiceConfig.js\";\nimport { ServiceAuth, InternalEnvironmentVariables } from \"../common/constants.js\";\nimport { ServiceErrorMessageConstants } from \"../common/messages.js\";\nimport { PlaywrightServiceClient } from \"../utils/PlaywrightServiceClient.js\";\nimport { getPlaywrightVersion } from \"../utils/getPlaywrightVersion.js\";\nimport type { WorkspaceMetaData, UploadResult } from \"../common/types.js\";\n\n/**\n * Azure Playwright Reporter - Uploads generated Playwright test report folder to Azure Storage.\n */\n\nexport default class PlaywrightReporter implements Reporter {\n private config: FullConfig | undefined;\n private workspaceMetadata: WorkspaceMetaData | null = null;\n private isReportingEnabled = false;\n\n /**\n * Called when test run begins. Stores configuration for later use and validates serviceAuthType and\n * retrieves workspace metadata.\n * @param config - Playwright test configuration\n */\n\n async onBegin(config: FullConfig): Promise<void> {\n coreLogger.info(`Reporter configuration: ${JSON.stringify(config.reporter, null, 2)}`);\n\n this.config = config;\n\n // Check Playwright version for reporting feature compatibility\n try {\n const playwrightVersion = getPlaywrightVersion();\n const playwrightVersionInfo = getVersionInfo(playwrightVersion);\n\n // Check if version is < 1.57\n const isReportingSupportedVersion =\n playwrightVersionInfo.major > 1 ||\n (playwrightVersionInfo.major === 1 && playwrightVersionInfo.minor >= 57);\n\n if (!isReportingSupportedVersion) {\n console.error(\n ServiceErrorMessageConstants.PLAYWRIGHT_VERSION_TOO_OLD_FOR_REPORTING.message,\n );\n this.isReportingEnabled = false;\n return;\n }\n } catch (error) {\n coreLogger.error(`Failed to get Playwright version: ${error}`);\n console.error(ServiceErrorMessageConstants.PLAYWRIGHT_VERSION_TOO_OLD_FOR_REPORTING.message);\n this.isReportingEnabled = false;\n return;\n }\n\n // Check if using service config\n const usingServiceConfig =\n process.env[InternalEnvironmentVariables.USING_SERVICE_CONFIG] === \"true\";\n coreLogger.info(`Using service config: ${usingServiceConfig}`);\n if (!usingServiceConfig) {\n console.error(ServiceErrorMessageConstants.REPORTER_REQUIRES_SERVICE_CONFIG.message);\n this.isReportingEnabled = false;\n return;\n }\n\n // Check if test run creation was successful\n const testRunCreationSuccess =\n process.env[InternalEnvironmentVariables.TEST_RUN_CREATION_SUCCESS] === \"true\";\n if (!testRunCreationSuccess) {\n console.error(ServiceErrorMessageConstants.REPORTING_STATUS_FAILED.message);\n console.error(ServiceErrorMessageConstants.REPORTING_TEST_RUN_FAILED.message);\n this.isReportingEnabled = false;\n return;\n }\n\n // Check authentication\n const playwrightServiceConfig = PlaywrightServiceConfig.instance;\n coreLogger.info(`Current authentication type: ${playwrightServiceConfig.serviceAuthType}`);\n const isUsingAccessToken = playwrightServiceConfig.serviceAuthType === ServiceAuth.ACCESS_TOKEN;\n if (isUsingAccessToken) {\n console.error(ServiceErrorMessageConstants.REPORTER_REQUIRES_ENTRA_AUTH.message);\n this.isReportingEnabled = false;\n return;\n }\n coreLogger.info(\"Authentication validation passed - using ENTRA_ID\");\n\n // Get workspace metadata for later use\n try {\n const playwrightServiceApiClient = new PlaywrightServiceClient();\n this.workspaceMetadata = await playwrightServiceApiClient.getWorkspaceMetadata();\n\n if (!this.workspaceMetadata?.storageUri) {\n console.error(ServiceErrorMessageConstants.WORKSPACE_REPORTING_DISABLED.message);\n this.isReportingEnabled = false;\n return;\n }\n\n this.isReportingEnabled = true;\n\n this.validateHtmlReporterConfiguration(config);\n if (this.isReportingEnabled) {\n console.log(ServiceErrorMessageConstants.REPORTING_ENABLED.message);\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n console.error(\n `${ServiceErrorMessageConstants.WORKSPACE_METADATA_FETCH_FAILED.message}Error: ${errorMessage} `,\n );\n this.isReportingEnabled = false;\n }\n }\n\n /**\n * Called when test run ends. Uploads Playwright test report to Azure Storage if reporting is enabled.\n */\n\n async onEnd(): Promise<void> {\n if (this.isReportingEnabled) {\n console.log(ServiceErrorMessageConstants.COLLECTING_ARTIFACTS.message);\n const uploadResult = await this.uploadHtmlReport();\n\n if (uploadResult.success) {\n if (\n uploadResult.partialSuccess &&\n uploadResult.failedFileDetails &&\n uploadResult.failedFileDetails.length > 0\n ) {\n console.log(\"Warning: Failed to upload the following files:\");\n uploadResult.failedFileDetails.forEach((fileDetail) => {\n console.log(` - ${fileDetail.fileName}, ERROR: ${fileDetail.error}`);\n });\n console.log(ServiceErrorMessageConstants.REPORTING_STATUS_PARTIAL.message);\n } else {\n console.log(ServiceErrorMessageConstants.REPORTING_STATUS_SUCCESS.message);\n }\n // Display portal URL for both full and partial success\n if (this.workspaceMetadata) {\n const portalUrl = getPortalTestRunUrl(this.workspaceMetadata);\n console.log(ServiceErrorMessageConstants.TEST_REPORT_VIEW_URL.formatWithUrl(portalUrl));\n }\n } else {\n console.error(ServiceErrorMessageConstants.REPORTING_STATUS_FAILED.message);\n if (uploadResult.errorMessage) {\n console.error(`Error: ${uploadResult.errorMessage}`);\n }\n }\n }\n }\n\n private async uploadHtmlReport(): Promise<UploadResult> {\n try {\n const outputFolder = getHtmlReporterOutputFolder(this.config);\n coreLogger.info(`Resolved Playwright test report output folder: ${outputFolder}`);\n const storageManager = new PlaywrightReporterStorageManager();\n coreLogger.info(\"Starting Playwright test report upload process\");\n const uploadResult = await storageManager.uploadPlaywrightHtmlReportAfterTests(\n outputFolder,\n this.workspaceMetadata,\n );\n\n if (uploadResult.success) {\n coreLogger.info(`Playwright Test report uploaded successfully to Azure Storage.`);\n }\n return uploadResult;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n coreLogger.error(`Upload failed: ${errorMessage}`);\n return { success: false, errorMessage };\n }\n }\n\n private validateHtmlReporterConfiguration(config: FullConfig): void {\n if (!config.reporter || !Array.isArray(config.reporter)) {\n console.error(ServiceErrorMessageConstants.HTML_REPORTER_REQUIRED.message);\n this.isReportingEnabled = false;\n return;\n }\n\n const htmlReporterIndex = config.reporter.findIndex((reporter) => {\n const reporterName = typeof reporter === \"string\" ? reporter : reporter?.[0];\n return reporterName === \"html\";\n });\n\n const azureReporterIndex = config.reporter.findIndex((reporter) => {\n const reporterName = typeof reporter === \"string\" ? reporter : reporter?.[0];\n return (\n typeof reporterName === \"string\" &&\n reporterName.includes(\"playwright\") &&\n reporterName.includes(\"reporter\")\n );\n });\n\n // Validate HTML reporter exists\n if (htmlReporterIndex === -1) {\n console.error(ServiceErrorMessageConstants.HTML_REPORTER_REQUIRED.message);\n this.isReportingEnabled = false;\n return;\n }\n\n // Validate HTML reporter comes before Azure reporter (if Azure reporter exists)\n if (azureReporterIndex !== -1 && htmlReporterIndex > azureReporterIndex) {\n console.error(ServiceErrorMessageConstants.HTML_REPORTER_REQUIRED.message);\n this.isReportingEnabled = false;\n return;\n }\n\n coreLogger.info(\n \"HTML reporter validation passed - HTML reporter is configured and properly ordered\",\n );\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"playwrightReporter.js","sourceRoot":"","sources":["../../../src/reporter/playwrightReporter.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\nimport type { FullConfig, Reporter } from \"@playwright/test/reporter\";\nimport { PlaywrightReporterStorageManager } from \"../utils/playwrightReporterStorageManager.js\";\nimport {\n getHtmlReporterOutputFolder,\n getPortalTestRunUrl,\n getVersionInfo,\n} from \"../utils/utils.js\";\nimport { coreLogger } from \"../common/logger.js\";\nimport { PlaywrightServiceConfig } from \"../common/playwrightServiceConfig.js\";\nimport { ServiceAuth, InternalEnvironmentVariables } from \"../common/constants.js\";\nimport { ServiceErrorMessageConstants } from \"../common/messages.js\";\nimport { PlaywrightServiceClient } from \"../utils/PlaywrightServiceClient.js\";\nimport { getPlaywrightVersion } from \"../utils/getPlaywrightVersion.js\";\nimport type { WorkspaceMetaData, UploadResult } from \"../common/types.js\";\n\n/**\n * Azure Playwright Reporter - Uploads generated Playwright test report folder to Azure Storage.\n */\n\nexport default class PlaywrightReporter implements Reporter {\n private config: FullConfig | undefined;\n private workspaceMetadata: WorkspaceMetaData | null = null;\n private isReportingEnabled = false;\n\n /**\n * Called when test run begins. Stores configuration for later use and validates serviceAuthType and\n * retrieves workspace metadata.\n * @param config - Playwright test configuration\n */\n\n async onBegin(config: FullConfig): Promise<void> {\n coreLogger.info(`Reporter configuration: ${JSON.stringify(config.reporter, null, 2)}`);\n\n this.config = config;\n\n // Check Playwright version for reporting feature compatibility\n try {\n const playwrightVersion = getPlaywrightVersion();\n const playwrightVersionInfo = getVersionInfo(playwrightVersion);\n\n // Check if version is < 1.57\n const isReportingSupportedVersion =\n playwrightVersionInfo.major > 1 ||\n (playwrightVersionInfo.major === 1 && playwrightVersionInfo.minor >= 57);\n\n if (!isReportingSupportedVersion) {\n console.error(\n ServiceErrorMessageConstants.PLAYWRIGHT_VERSION_TOO_OLD_FOR_REPORTING.message,\n );\n this.isReportingEnabled = false;\n return;\n }\n } catch (error) {\n coreLogger.error(`Failed to get Playwright version: ${error}`);\n console.error(ServiceErrorMessageConstants.PLAYWRIGHT_VERSION_TOO_OLD_FOR_REPORTING.message);\n this.isReportingEnabled = false;\n return;\n }\n\n // Check if using service config\n const usingServiceConfig =\n process.env[InternalEnvironmentVariables.USING_SERVICE_CONFIG] === \"true\";\n coreLogger.info(`Using service config: ${usingServiceConfig}`);\n if (!usingServiceConfig) {\n console.error(ServiceErrorMessageConstants.REPORTER_REQUIRES_SERVICE_CONFIG.message);\n this.isReportingEnabled = false;\n return;\n }\n\n // Check if test run creation was successful\n const testRunCreationSuccess =\n process.env[InternalEnvironmentVariables.TEST_RUN_CREATION_SUCCESS] === \"true\";\n if (!testRunCreationSuccess) {\n console.error(ServiceErrorMessageConstants.REPORTING_STATUS_FAILED.message);\n console.error(ServiceErrorMessageConstants.REPORTING_TEST_RUN_FAILED.message);\n this.isReportingEnabled = false;\n return;\n }\n\n // Check authentication\n const playwrightServiceConfig = PlaywrightServiceConfig.instance;\n coreLogger.info(`Current authentication type: ${playwrightServiceConfig.serviceAuthType}`);\n const isUsingAccessToken = playwrightServiceConfig.serviceAuthType === ServiceAuth.ACCESS_TOKEN;\n if (isUsingAccessToken) {\n console.error(ServiceErrorMessageConstants.REPORTER_REQUIRES_ENTRA_AUTH.message);\n this.isReportingEnabled = false;\n return;\n }\n coreLogger.info(\"Authentication validation passed - using ENTRA_ID\");\n\n // Validate HTML reporter configuration\n if (!this.validateHtmlReporterConfiguration(config)) {\n return;\n }\n\n // Get workspace metadata for later use\n try {\n const playwrightServiceApiClient = new PlaywrightServiceClient();\n this.workspaceMetadata = await playwrightServiceApiClient.getWorkspaceMetadata();\n\n if (!this.workspaceMetadata?.storageUri) {\n console.error(ServiceErrorMessageConstants.WORKSPACE_REPORTING_DISABLED.message);\n return;\n }\n\n this.isReportingEnabled = true;\n console.log(ServiceErrorMessageConstants.REPORTING_ENABLED.message);\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n console.error(\n `${ServiceErrorMessageConstants.WORKSPACE_METADATA_FETCH_FAILED.message}Error: ${errorMessage} `,\n );\n }\n }\n\n /**\n * Called when test run ends. Uploads Playwright test report to Azure Storage if reporting is enabled.\n */\n\n async onEnd(): Promise<void> {\n if (this.isReportingEnabled) {\n console.log(ServiceErrorMessageConstants.COLLECTING_ARTIFACTS.message);\n const uploadResult = await this.uploadHtmlReport();\n\n if (uploadResult.success) {\n if (\n uploadResult.partialSuccess &&\n uploadResult.failedFileDetails &&\n uploadResult.failedFileDetails.length > 0\n ) {\n console.log(\"Warning: Failed to upload the following files:\");\n uploadResult.failedFileDetails.forEach((fileDetail) => {\n console.log(` - ${fileDetail.fileName}, ERROR: ${fileDetail.error}`);\n });\n console.log(ServiceErrorMessageConstants.REPORTING_STATUS_PARTIAL.message);\n } else {\n console.log(ServiceErrorMessageConstants.REPORTING_STATUS_SUCCESS.message);\n }\n // Display portal URL for both full and partial success\n if (this.workspaceMetadata) {\n const portalUrl = getPortalTestRunUrl(this.workspaceMetadata);\n console.log(ServiceErrorMessageConstants.TEST_REPORT_VIEW_URL.formatWithUrl(portalUrl));\n }\n } else {\n console.error(ServiceErrorMessageConstants.REPORTING_STATUS_FAILED.message);\n if (uploadResult.errorMessage) {\n console.error(`Error: ${uploadResult.errorMessage}`);\n }\n }\n }\n }\n\n private async uploadHtmlReport(): Promise<UploadResult> {\n try {\n const outputFolder = getHtmlReporterOutputFolder(this.config);\n coreLogger.info(`Resolved Playwright test report output folder: ${outputFolder}`);\n const storageManager = new PlaywrightReporterStorageManager();\n coreLogger.info(\"Starting Playwright test report upload process\");\n const uploadResult = await storageManager.uploadPlaywrightHtmlReportAfterTests(\n outputFolder,\n this.workspaceMetadata,\n );\n\n if (uploadResult.success) {\n coreLogger.info(`Playwright Test report uploaded successfully to Azure Storage.`);\n }\n return uploadResult;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n coreLogger.error(`Upload failed: ${errorMessage}`);\n return { success: false, errorMessage };\n }\n }\n\n private validateHtmlReporterConfiguration(config: FullConfig): boolean {\n if (!config.reporter || !Array.isArray(config.reporter)) {\n console.error(ServiceErrorMessageConstants.HTML_REPORTER_REQUIRED.message);\n return false;\n }\n\n const htmlReporterIndex = config.reporter.findIndex((reporter) => {\n const reporterName = typeof reporter === \"string\" ? reporter : reporter?.[0];\n return reporterName === \"html\";\n });\n\n const azureReporterIndex = config.reporter.findIndex((reporter) => {\n const reporterName = typeof reporter === \"string\" ? reporter : reporter?.[0];\n return (\n typeof reporterName === \"string\" &&\n reporterName.includes(\"playwright\") &&\n reporterName.includes(\"reporter\")\n );\n });\n\n // Validate HTML reporter exists\n if (htmlReporterIndex === -1) {\n console.error(ServiceErrorMessageConstants.HTML_REPORTER_REQUIRED.message);\n return false;\n }\n\n // Validate HTML reporter comes before Azure reporter (if Azure reporter exists)\n if (azureReporterIndex !== -1 && htmlReporterIndex > azureReporterIndex) {\n console.error(ServiceErrorMessageConstants.HTML_REPORTER_REQUIRED.message);\n return false;\n }\n\n coreLogger.info(\n \"HTML reporter validation passed - HTML reporter is configured and properly ordered\",\n );\n return true;\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"playwrightReporterStorageManager.d.ts","sourceRoot":"","sources":["../../../src/utils/playwrightReporterStorageManager.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAaxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE1E,qBAAa,gCAAgC;IAErC,sBAAsB,CAC1B,UAAU,EAAE,eAAe,EAC3B,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,MAAM,EACpB,gBAAgB,EAAE,iBAAiB,GAClC,OAAO,CAAC,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"playwrightReporterStorageManager.d.ts","sourceRoot":"","sources":["../../../src/utils/playwrightReporterStorageManager.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAaxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE1E,qBAAa,gCAAgC;IAErC,sBAAsB,CAC1B,UAAU,EAAE,eAAe,EAC3B,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,MAAM,EACpB,gBAAgB,EAAE,iBAAiB,GAClC,OAAO,CAAC,YAAY,CAAC;YAwHV,oBAAoB;IA+H5B,oCAAoC,CACxC,gBAAgB,CAAC,EAAE,MAAM,EACzB,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,IAAI,GAC3C,OAAO,CAAC,YAAY,CAAC;YAiDV,sBAAsB;YA4GtB,4BAA4B;YAwB5B,4BAA4B;YA4E5B,yBAAyB;YA8CzB,sBAAsB;CAsCrC"}
|
|
@@ -12,6 +12,7 @@ export class PlaywrightReporterStorageManager {
|
|
|
12
12
|
// Uploads the HTML report folder to Azure Storage
|
|
13
13
|
async uploadHtmlReportFolder(credential, runId, outputFolder, workspaceDetails) {
|
|
14
14
|
coreLogger.info(`Starting HTML report upload for runId: ${runId}, outputFolder: ${outputFolder}`);
|
|
15
|
+
const storageAccountName = getStorageAccountNameFromUri(workspaceDetails?.storageUri || "") || "unknown";
|
|
15
16
|
try {
|
|
16
17
|
coreLogger.info(`Received workspace details: ${JSON.stringify(workspaceDetails, null, 2)}`);
|
|
17
18
|
if (!workspaceDetails.storageUri) {
|
|
@@ -42,7 +43,6 @@ export class PlaywrightReporterStorageManager {
|
|
|
42
43
|
coreLogger.info(`Container ${containerName} already exists.`);
|
|
43
44
|
}
|
|
44
45
|
const folderName = runId;
|
|
45
|
-
const storageAccountName = getStorageAccountNameFromUri(workspaceDetails?.storageUri || "") || "unknown";
|
|
46
46
|
console.log(ServiceErrorMessageConstants.UPLOADING_ARTIFACTS.formatWithDetails(storageAccountName, containerName, folderName));
|
|
47
47
|
await this.modifyTraceIndexHtml(outputFolder);
|
|
48
48
|
const uploadResults = await this.uploadFolderInParallel(containerClient, outputFolder, outputFolder, folderName);
|
|
@@ -80,6 +80,16 @@ export class PlaywrightReporterStorageManager {
|
|
|
80
80
|
}
|
|
81
81
|
catch (error) {
|
|
82
82
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
83
|
+
const hasStorageAccountDeletedError = errorMessage.includes("ENOTFOUND") ||
|
|
84
|
+
errorMessage.includes("getaddrinfo") ||
|
|
85
|
+
errorMessage.includes("not found") ||
|
|
86
|
+
errorMessage.includes("404");
|
|
87
|
+
if (hasStorageAccountDeletedError) {
|
|
88
|
+
return {
|
|
89
|
+
success: false,
|
|
90
|
+
errorMessage: ServiceErrorMessageConstants.STORAGE_ACCOUNT_DELETED.formatWithStorageAccount(storageAccountName),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
83
93
|
coreLogger.error(`Failed to upload HTML report: ${error}`);
|
|
84
94
|
return { success: false, errorMessage };
|
|
85
95
|
}
|
|
@@ -87,12 +97,16 @@ export class PlaywrightReporterStorageManager {
|
|
|
87
97
|
async modifyTraceIndexHtml(outputFolder) {
|
|
88
98
|
coreLogger.info(`Starting trace modification for folder: ${outputFolder}`);
|
|
89
99
|
const indexPath = join(outputFolder, "trace/index.html");
|
|
100
|
+
const localIndexPath = join(outputFolder, "trace/index.local.html");
|
|
90
101
|
if (!existsSync(indexPath)) {
|
|
91
102
|
coreLogger.error(`trace/index.html not found at path: ${indexPath}`);
|
|
92
103
|
return;
|
|
93
104
|
}
|
|
94
105
|
coreLogger.info(`Found trace/index.html at: ${indexPath}`);
|
|
95
106
|
try {
|
|
107
|
+
const originalHtml = readFileSync(indexPath, "utf-8");
|
|
108
|
+
writeFileSync(localIndexPath, originalHtml, "utf-8");
|
|
109
|
+
coreLogger.info(`Backed up original trace viewer to: ${localIndexPath}`);
|
|
96
110
|
const redirectTraceviewerScript = `<!DOCTYPE html>
|
|
97
111
|
<html>
|
|
98
112
|
<head>
|
|
@@ -101,21 +115,92 @@ export class PlaywrightReporterStorageManager {
|
|
|
101
115
|
</head>
|
|
102
116
|
<body>
|
|
103
117
|
<script>
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
118
|
+
/**
|
|
119
|
+
* Trace Viewer Redirect Logic
|
|
120
|
+
*
|
|
121
|
+
* This script handles two scenarios:
|
|
122
|
+
* 1. Azure Portal Access (with SAS tokens): Redirects to public Playwright trace viewer at https://trace.playwright.dev/
|
|
123
|
+
* - Preserves SAS tokens on the trace URL to allow the public viewer to access the trace file from Azure Storage
|
|
124
|
+
* 2. Local Development: Uses the local copy of the trace viewer (index.local.html)
|
|
125
|
+
* - Preserves all query parameters including the trace parameter
|
|
126
|
+
*
|
|
127
|
+
* The script detects the scenario by checking:
|
|
128
|
+
* - Presence of SAS tokens (sig, sv parameters) indicates Azure Portal access
|
|
129
|
+
* - localhost/file protocol indicates local development
|
|
130
|
+
*
|
|
131
|
+
* Authentication token preservation:
|
|
132
|
+
* - For Azure Portal: SAS tokens are added to the trace URL (not the viewer URL) so the viewer can fetch the trace
|
|
133
|
+
* - For local dev: All parameters are forwarded to the local viewer
|
|
134
|
+
*/
|
|
135
|
+
(function() {
|
|
136
|
+
function shouldRedirect() {
|
|
137
|
+
try {
|
|
138
|
+
const currentUrl = new URL(location.href);
|
|
139
|
+
const traceParam = currentUrl.searchParams.get('trace');
|
|
140
|
+
if (!traceParam) return false;
|
|
141
|
+
|
|
142
|
+
// Check if current URL (the index.html itself) has SAS tokens - indicates Azure Portal access
|
|
143
|
+
const currentHasSas = currentUrl.searchParams.has('sig') || currentUrl.searchParams.has('sv');
|
|
144
|
+
|
|
145
|
+
// Check if we're on localhost or file protocol (cover common local dev scenarios)
|
|
146
|
+
const hostname = currentUrl.hostname;
|
|
147
|
+
const protocol = currentUrl.protocol;
|
|
148
|
+
const isLoopbackV4 =
|
|
149
|
+
hostname === 'localhost' ||
|
|
150
|
+
hostname === '127.0.0.1' ||
|
|
151
|
+
hostname.startsWith('127.');
|
|
152
|
+
const isLoopbackV6 =
|
|
153
|
+
hostname === '::1' ||
|
|
154
|
+
hostname === '[::1]';
|
|
155
|
+
const isCustomLocalName =
|
|
156
|
+
hostname.endsWith('.localhost') ||
|
|
157
|
+
hostname.endsWith('.local');
|
|
158
|
+
const isLocalHost =
|
|
159
|
+
protocol === 'file:' ||
|
|
160
|
+
isLoopbackV4 ||
|
|
161
|
+
isLoopbackV6 ||
|
|
162
|
+
isCustomLocalName;
|
|
107
163
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
164
|
+
// Redirect to public trace viewer if:
|
|
165
|
+
// 1. Current page is accessed with SAS tokens (Azure Portal scenario)
|
|
166
|
+
// 2. Not running on localhost/file protocol
|
|
167
|
+
return currentHasSas && !isLocalHost;
|
|
168
|
+
} catch (e) {
|
|
169
|
+
console.error('Trace redirect detection failed', e);
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
113
172
|
}
|
|
114
|
-
}
|
|
115
173
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
174
|
+
if (shouldRedirect()) {
|
|
175
|
+
const url = new URL(location.href);
|
|
176
|
+
const traceParam = url.searchParams.get('trace');
|
|
177
|
+
const trace = new URL(traceParam, url);
|
|
178
|
+
|
|
179
|
+
// Copy all query parameters from the current URL to the trace URL (preserve SAS tokens)
|
|
180
|
+
for (const [key, value] of url.searchParams.entries()) {
|
|
181
|
+
if (key !== 'trace') {
|
|
182
|
+
trace.searchParams.set(key, value);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const publicTraceViewer = new URL('https://trace.playwright.dev/');
|
|
187
|
+
publicTraceViewer.searchParams.set('trace', trace.toString());
|
|
188
|
+
|
|
189
|
+
location.replace(publicTraceViewer.toString());
|
|
190
|
+
} else {
|
|
191
|
+
// Use the local copy of the Playwright trace viewer when running locally
|
|
192
|
+
// Preserve all query parameters including the trace parameter
|
|
193
|
+
const currentUrl = new URL(location.href);
|
|
194
|
+
const localViewerUrl = new URL('index.local.html', currentUrl);
|
|
195
|
+
|
|
196
|
+
// Copy all query parameters to the local viewer URL
|
|
197
|
+
for (const [key, value] of currentUrl.searchParams.entries()) {
|
|
198
|
+
localViewerUrl.searchParams.set(key, value);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
location.replace(localViewerUrl.toString());
|
|
202
|
+
}
|
|
203
|
+
})();
|
|
119
204
|
</script>
|
|
120
205
|
</body>
|
|
121
206
|
</html>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"playwrightReporterStorageManager.js","sourceRoot":"","sources":["../../../src/utils/playwrightReporterStorageManager.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport { BlobServiceClient, ContainerClient, BlockBlobClient } from \"@azure/storage-blob\";\nimport type { TokenCredential } from \"@azure/core-auth\";\nimport { coreLogger } from \"../common/logger.js\";\nimport { readFileSync, writeFileSync, existsSync, createReadStream } from \"fs\";\nimport { join } from \"path\";\nimport { UploadConstants } from \"../common/constants.js\";\nimport { ServiceErrorMessageConstants } from \"../common/messages.js\";\nimport {\n populateValuesFromServiceUrl,\n calculateOptimalConcurrency,\n collectAllFiles,\n getStorageAccountNameFromUri,\n} from \"./utils.js\";\nimport { PlaywrightServiceConfig } from \"../common/playwrightServiceConfig.js\";\nimport type { WorkspaceMetaData, UploadResult } from \"../common/types.js\";\n\nexport class PlaywrightReporterStorageManager {\n // Uploads the HTML report folder to Azure Storage\n async uploadHtmlReportFolder(\n credential: TokenCredential,\n runId: string,\n outputFolder: string,\n workspaceDetails: WorkspaceMetaData,\n ): Promise<UploadResult> {\n coreLogger.info(\n `Starting HTML report upload for runId: ${runId}, outputFolder: ${outputFolder}`,\n );\n try {\n coreLogger.info(`Received workspace details: ${JSON.stringify(workspaceDetails, null, 2)}`);\n\n if (!workspaceDetails.storageUri) {\n coreLogger.error(\"Storage URI not found in workspace details\");\n return {\n success: false,\n errorMessage: ServiceErrorMessageConstants.STORAGE_URI_NOT_FOUND.message,\n };\n }\n\n const blobServiceClient = new BlobServiceClient(workspaceDetails?.storageUri, credential);\n coreLogger.info(\"blobServiceClient created successfully.\");\n const serviceUrlInfo = populateValuesFromServiceUrl();\n if (!serviceUrlInfo?.accountId) {\n coreLogger.error(\"Unable to extract workspace ID from service URL\");\n return {\n success: false,\n errorMessage: ServiceErrorMessageConstants.UNABLE_TO_EXTRACT_WORKSPACE_ID.message,\n };\n }\n\n const containerName = serviceUrlInfo.accountId.toLowerCase().replace(/[^a-z0-9-]/g, \"-\");\n const containerClient = blobServiceClient.getContainerClient(containerName);\n\n const containerExists = await containerClient.exists();\n if (!containerExists) {\n coreLogger.info(`Container ${containerName} does not exist. Creating new container.`);\n await containerClient.create();\n } else {\n coreLogger.info(`Container ${containerName} already exists.`);\n }\n\n const folderName = runId;\n const storageAccountName =\n getStorageAccountNameFromUri(workspaceDetails?.storageUri || \"\") || \"unknown\";\n console.log(\n ServiceErrorMessageConstants.UPLOADING_ARTIFACTS.formatWithDetails(\n storageAccountName,\n containerName,\n folderName,\n ),\n );\n\n await this.modifyTraceIndexHtml(outputFolder);\n const uploadResults = await this.uploadFolderInParallel(\n containerClient,\n outputFolder,\n outputFolder,\n folderName,\n );\n\n if (uploadResults.totalFiles === 0) {\n return { success: false, errorMessage: \"No files found to upload\" };\n }\n\n const failedFiles = uploadResults.totalFiles - uploadResults.uploadedFiles.length;\n if (failedFiles > 0) {\n if (uploadResults.failedFileDetails) {\n const hasAuthorizationError = uploadResults.failedFileDetails.some(\n (fileDetail) =>\n fileDetail.error.includes(\"not authorized to perform this operation\") ||\n fileDetail.error.includes(\"AuthorizationFailure\"),\n );\n\n if (hasAuthorizationError) {\n return {\n success: false,\n errorMessage:\n ServiceErrorMessageConstants.STORAGE_AUTHORIZATION_FAILED.formatWithStorageAccount(\n storageAccountName,\n ),\n };\n }\n }\n\n // Get list of failed file names by comparing total files with uploaded files\n const uploadedSet = new Set(uploadResults.uploadedFiles);\n const allFiles = collectAllFiles(outputFolder, outputFolder, folderName);\n const failedFileNames = allFiles\n .filter((file) => !uploadedSet.has(file.relativePath))\n .map((file) => file.relativePath);\n\n return {\n success: false,\n partialSuccess: true,\n failedFileCount: failedFiles,\n totalFiles: uploadResults.totalFiles,\n failedFiles: failedFileNames,\n failedFileDetails: uploadResults.failedFileDetails,\n };\n }\n\n return { success: true };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n coreLogger.error(`Failed to upload HTML report: ${error}`);\n return { success: false, errorMessage };\n }\n }\n private async modifyTraceIndexHtml(outputFolder: string): Promise<void> {\n coreLogger.info(`Starting trace modification for folder: ${outputFolder}`);\n const indexPath = join(outputFolder, \"trace/index.html\");\n\n if (!existsSync(indexPath)) {\n coreLogger.error(`trace/index.html not found at path: ${indexPath}`);\n return;\n }\n coreLogger.info(`Found trace/index.html at: ${indexPath}`);\n\n try {\n const redirectTraceviewerScript = `<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\">\n <title>Redirecting to Trace Viewer...</title>\n</head>\n<body>\n <script>\n const url = new URL(location.href);\n const traceParam = url.searchParams.get('trace');\n const trace = new URL(traceParam);\n\n // Copy all query parameters from the current URL to the trace URL\n // This includes SAS tokens (sv, sr, sig, etc.) that are on the main URL\n for (const [key, value] of url.searchParams.entries()) {\n if (key !== 'trace') {\n trace.searchParams.set(key, value);\n }\n }\n\n const publicTraceViewer = new URL('https://trace.playwright.dev/');\n publicTraceViewer.searchParams.set('trace', trace.toString());\n location.href = publicTraceViewer.toString();\n </script>\n</body>\n</html>\n`;\n\n writeFileSync(indexPath, redirectTraceviewerScript, \"utf-8\");\n coreLogger.info(\"Successfully updated TraceViewer index file\");\n } catch (error) {\n coreLogger.error(\n `Error modifying trace/index.html: ${error instanceof Error ? error.message : String(error)}`,\n );\n return;\n }\n }\n\n // Uploads the entire Playwright HTML report folder after tests complete.\n\n async uploadPlaywrightHtmlReportAfterTests(\n outputFolderName?: string,\n workspaceMetadata?: WorkspaceMetaData | null,\n ): Promise<UploadResult> {\n try {\n coreLogger.info(\n `Starting post-test HTML report upload, folder name: ${outputFolderName || \"default (playwright-report)\"}`,\n );\n const cred = PlaywrightServiceConfig.instance.credential;\n if (!cred) {\n coreLogger.error(\"No credential found for authentication\");\n return {\n success: false,\n errorMessage: ServiceErrorMessageConstants.NO_CRED_ENTRA_AUTH_ERROR.message,\n };\n }\n coreLogger.info(\"Credential found for authentication\");\n\n const folderName = outputFolderName || \"playwright-report\";\n const outputFolderPath = join(process.cwd(), folderName);\n\n if (!existsSync(outputFolderPath)) {\n coreLogger.error(`HTML report folder not found: ${outputFolderPath}`);\n return {\n success: false,\n errorMessage:\n ServiceErrorMessageConstants.PLAYWRIGHT_TEST_REPORT_NOT_FOUND.formatWithFolder(\n folderName,\n ),\n };\n }\n coreLogger.info(`HTML report folder found: ${outputFolderPath}`);\n\n const testRunId = PlaywrightServiceConfig.instance.runId;\n coreLogger.info(`Starting upload for test run ID: ${testRunId}`);\n const result = await this.uploadHtmlReportFolder(\n cred,\n testRunId,\n outputFolderPath,\n workspaceMetadata!,\n );\n coreLogger.info(`Completed upload for test run ID: ${testRunId}`);\n return result;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n coreLogger.error(`Upload failed: ${errorMessage}`);\n return { success: false, errorMessage };\n }\n }\n\n // Parallel Upload Engine - Core upload orchestration with performance optimization\n\n private async uploadFolderInParallel(\n containerClient: ContainerClient,\n folderPath: string,\n basePath: string,\n runIdFolderPrefix?: string,\n ): Promise<{\n uploadedFiles: string[];\n failedFiles: string[];\n failedFileDetails?: Array<{ fileName: string; error: string }>;\n totalFiles: number;\n totalSize: number;\n uploadTime: number;\n }> {\n // Sort by size descending - upload large files first for better parallelization\n const filesToUpload = collectAllFiles(folderPath, basePath, runIdFolderPrefix).sort(\n (a, b) => b.size - a.size,\n );\n\n if (filesToUpload.length === 0) {\n return { uploadedFiles: [], failedFiles: [], totalFiles: 0, totalSize: 0, uploadTime: 0 };\n }\n\n const totalSize = filesToUpload.reduce((sum, file) => sum + file.size, 0);\n\n const concurrency = calculateOptimalConcurrency(filesToUpload);\n coreLogger.info(\n `Calculated optimal concurrency: ${concurrency} for ${filesToUpload.length} files (total size: ${(totalSize / 1024 / 1024).toFixed(2)} MB)`,\n );\n const uploadStartTime = Date.now();\n coreLogger.info(`Starting parallel upload with ${concurrency} concurrent operations`);\n const results = await this.uploadWithConcurrencyControl(\n containerClient,\n filesToUpload,\n concurrency,\n );\n\n const uploadEndTime = Date.now();\n const uploadTime = uploadEndTime - uploadStartTime;\n coreLogger.info(`Upload completed in ${uploadTime}ms (${(uploadTime / 1000).toFixed(2)}s)`);\n\n const failed = results.filter((r) => r.status === \"rejected\").length;\n const successful = results.filter((r) => r.status === \"fulfilled\").length;\n coreLogger.info(\n `Upload results: ${successful} successful, ${failed} failed out of ${results.length} total files`,\n );\n\n if (failed > 0) {\n const errors = results\n .filter((r): r is PromiseRejectedResult => r.status === \"rejected\")\n .map((r) => r.reason.message)\n .slice(0, 5); // Show first 5 errors\n\n errors.forEach((error, index) => {\n coreLogger.error(` ${index + 1}. ${error}`);\n });\n\n // Get failed file names and their error messages\n const uploadedSet = new Set(\n results\n .filter((r): r is PromiseFulfilledResult<string> => r.status === \"fulfilled\")\n .map((r) => r.value),\n );\n const failedFileNames = filesToUpload\n .filter((file) => !uploadedSet.has(file.relativePath))\n .map((file) => file.relativePath);\n\n // Create detailed error mapping\n const failedFileDetails: Array<{ fileName: string; error: string }> = [];\n results.forEach((result, index) => {\n if (result.status === \"rejected\") {\n const fileName = filesToUpload[index]?.relativePath || `File at index ${index}`;\n const errorMessage =\n result.reason instanceof Error ? result.reason.message : String(result.reason);\n failedFileDetails.push({ fileName, error: errorMessage });\n }\n });\n\n // Log error but don't throw to prevent breaking HTML reporter\n coreLogger.error(\n `Upload failed: ${failed} files could not be uploaded. Sample errors: ${errors.join(\", \")}`,\n );\n return {\n uploadedFiles: results\n .filter((r): r is PromiseFulfilledResult<string> => r.status === \"fulfilled\")\n .map((r) => r.value),\n failedFiles: failedFileNames,\n failedFileDetails,\n totalFiles: filesToUpload.length,\n totalSize,\n uploadTime,\n };\n }\n\n const uploadedFiles = results\n .filter((r): r is PromiseFulfilledResult<string> => r.status === \"fulfilled\")\n .map((r) => r.value);\n\n return {\n uploadedFiles,\n failedFiles: [],\n totalFiles: filesToUpload.length,\n totalSize,\n uploadTime,\n };\n }\n\n // Concurrency Control System - Manages parallel execution with controlled resource usage\n\n private async uploadWithConcurrencyControl(\n containerClient: ContainerClient,\n files: Array<{ fullPath: string; relativePath: string; size: number; contentType: string }>,\n concurrency: number,\n ): Promise<PromiseSettledResult<string>[]> {\n const uploadTasks = files.map((fileInfo) => async (): Promise<string> => {\n try {\n await this.uploadSingleFileOptimized(containerClient, fileInfo);\n return fileInfo.relativePath;\n } catch (error) {\n coreLogger.error(\n `Failed to upload file: ${fileInfo.relativePath} - ${\n error instanceof Error ? error.message : \"Unknown error\"\n }`,\n );\n throw error;\n }\n });\n\n return this.executeWithOptimizedBatching(uploadTasks, concurrency);\n }\n\n // Optimized Batch Execution Engine - High-performance task processing system\n\n private async executeWithOptimizedBatching<T>(\n tasks: Array<() => Promise<T>>,\n concurrency: number,\n ): Promise<PromiseSettledResult<T>[]> {\n const results: PromiseSettledResult<T>[] = new Array(tasks.length);\n let completedTasks = 0;\n\n // Splits tasks into optimal batches to balance memory usage vs. throughput\n const batchSize = Math.min(UploadConstants.BATCH_SIZE, concurrency * 2);\n const batches: Array<Array<() => Promise<T>>> = [];\n\n // Each batch will be processed with full concurrency before moving to next batch\n for (let i = 0; i < tasks.length; i += batchSize) {\n batches.push(tasks.slice(i, i + batchSize));\n }\n\n // Process each batch sequentially to maintain memory efficiency\n coreLogger.info(`Processing ${batches.length} batches with ${batchSize} tasks per batch`);\n for (let batchIndex = 0; batchIndex < batches.length; batchIndex++) {\n const batch = batches[batchIndex];\n const batchStartIndex = batchIndex * batchSize;\n coreLogger.info(\n `Starting batch ${batchIndex + 1}/${batches.length} with ${batch.length} tasks`,\n );\n\n // Transform each task into a promise that captures results at correct index\n const batchPromises = batch.map(async (task, taskIndex) => {\n const globalIndex = batchStartIndex + taskIndex;\n try {\n const result = await task();\n results[globalIndex] = { status: \"fulfilled\", value: result };\n return result;\n } catch (error) {\n results[globalIndex] = { status: \"rejected\", reason: error };\n coreLogger.error(\n `Task failed at index ${globalIndex}: ${\n error instanceof Error ? error.message : \"Unknown error\"\n }`,\n );\n return;\n }\n });\n\n const executing: Promise<any>[] = [];\n\n for (const promise of batchPromises) {\n if (executing.length >= concurrency) {\n await Promise.race(executing);\n }\n const wrappedPromise = promise\n .then((result) => {\n completedTasks++;\n return result;\n })\n .catch(() => {\n completedTasks++;\n })\n .finally(() => {\n // Cleanup: remove completed promise from executing array\n const index = executing.indexOf(wrappedPromise);\n if (index > -1) executing.splice(index, 1);\n });\n\n executing.push(wrappedPromise);\n }\n\n // Wait for all promises in current batch to complete before moving to next batch\n await Promise.allSettled(executing);\n coreLogger.info(`Completed batch ${batchIndex + 1}/${batches.length}`);\n }\n\n return results;\n }\n\n // Individual File Upload with Retry Logic\n\n private async uploadSingleFileOptimized(\n containerClient: ContainerClient,\n fileInfo: { fullPath: string; relativePath: string; contentType: string; size: number },\n ): Promise<void> {\n coreLogger.info(\n `Uploading file: ${fileInfo.relativePath} (${(fileInfo.size / 1024).toFixed(2)} KB, ${fileInfo.contentType})`,\n );\n const blockBlobClient = containerClient.getBlockBlobClient(fileInfo.relativePath);\n const maxRetries = UploadConstants.MAX_RETRY_ATTEMPTS;\n const baseDelay = UploadConstants.RETRY_BASE_DELAY;\n\n for (let attempt = 1; attempt <= maxRetries; attempt++) {\n try {\n await this.performOptimizedUpload(blockBlobClient, fileInfo);\n return;\n } catch (error) {\n const isLastAttempt = attempt === maxRetries;\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n coreLogger.info(\n `Upload attempt ${attempt} failed for ${fileInfo.relativePath}: ${errorMessage}`,\n );\n\n if (isLastAttempt) {\n coreLogger.error(\n `All retry attempts exhausted for ${fileInfo.relativePath}: ${errorMessage}`,\n );\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(\n `Upload failed for ${fileInfo.relativePath} after ${maxRetries} attempts: ${errorMessage}`,\n );\n }\n\n // Exponential backoff with jitter (Azure SDK pattern)\n const delay = baseDelay * Math.pow(2, attempt - 1) + Math.random() * 500;\n coreLogger.info(\n `Retrying upload for ${fileInfo.relativePath} in ${delay.toFixed(0)}ms (attempt ${attempt + 1}/${maxRetries})`,\n );\n await new Promise((_resolve) => setTimeout(_resolve, delay));\n }\n }\n }\n\n // Multi-Strategy Upload Engine - Optimized upload based on file characteristics\n\n private async performOptimizedUpload(\n blockBlobClient: BlockBlobClient,\n fileInfo: { fullPath: string; relativePath: string; contentType: string; size: number },\n ): Promise<void> {\n if (fileInfo.size <= UploadConstants.SMALL_FILE_THRESHOLD) {\n // DIRECT UPLOAD: Optimal for small files (≤1MB)\n const fileContent = readFileSync(fileInfo.fullPath);\n await blockBlobClient.upload(fileContent, fileContent.length, {\n blobHTTPHeaders: {\n blobContentType: fileInfo.contentType,\n },\n });\n } else if (fileInfo.size <= UploadConstants.LARGE_FILE_THRESHOLD) {\n // BLOCK UPLOAD: Optimal for medium files (1MB - 100MB)\n const fileContent = readFileSync(fileInfo.fullPath);\n await blockBlobClient.uploadData(fileContent, {\n blobHTTPHeaders: {\n blobContentType: fileInfo.contentType,\n },\n blockSize: UploadConstants.OPTIMIZED_BLOCK_SIZE,\n concurrency: UploadConstants.PER_FILE_CONCURRENCY,\n });\n } else {\n // STREAMING UPLOAD: Optimal for large files (>100MB)\n const stream = createReadStream(fileInfo.fullPath);\n await blockBlobClient.uploadStream(\n stream,\n UploadConstants.STREAM_BUFFER_SIZE,\n UploadConstants.LARGE_FILE_CONCURRENCY,\n {\n blobHTTPHeaders: {\n blobContentType: fileInfo.contentType,\n },\n },\n );\n }\n coreLogger.info(`Successfully uploaded: ${fileInfo.relativePath}`);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"playwrightReporterStorageManager.js","sourceRoot":"","sources":["../../../src/utils/playwrightReporterStorageManager.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC,OAAO,EAAE,iBAAiB,EAAoC,MAAM,qBAAqB,CAAC;AAE1F,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,IAAI,CAAC;AAC/E,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EACL,4BAA4B,EAC5B,2BAA2B,EAC3B,eAAe,EACf,4BAA4B,GAC7B,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AAG/E,MAAM,OAAO,gCAAgC;IAC3C,kDAAkD;IAClD,KAAK,CAAC,sBAAsB,CAC1B,UAA2B,EAC3B,KAAa,EACb,YAAoB,EACpB,gBAAmC;QAEnC,UAAU,CAAC,IAAI,CACb,0CAA0C,KAAK,mBAAmB,YAAY,EAAE,CACjF,CAAC;QAEF,MAAM,kBAAkB,GACtB,4BAA4B,CAAC,gBAAgB,EAAE,UAAU,IAAI,EAAE,CAAC,IAAI,SAAS,CAAC;QAEhF,IAAI,CAAC;YACH,UAAU,CAAC,IAAI,CAAC,+BAA+B,IAAI,CAAC,SAAS,CAAC,gBAAgB,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;YAE5F,IAAI,CAAC,gBAAgB,CAAC,UAAU,EAAE,CAAC;gBACjC,UAAU,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;gBAC/D,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,YAAY,EAAE,4BAA4B,CAAC,qBAAqB,CAAC,OAAO;iBACzE,CAAC;YACJ,CAAC;YAED,MAAM,iBAAiB,GAAG,IAAI,iBAAiB,CAAC,gBAAgB,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;YAC1F,UAAU,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;YAC3D,MAAM,cAAc,GAAG,4BAA4B,EAAE,CAAC;YACtD,IAAI,CAAC,cAAc,EAAE,SAAS,EAAE,CAAC;gBAC/B,UAAU,CAAC,KAAK,CAAC,iDAAiD,CAAC,CAAC;gBACpE,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,YAAY,EAAE,4BAA4B,CAAC,8BAA8B,CAAC,OAAO;iBAClF,CAAC;YACJ,CAAC;YAED,MAAM,aAAa,GAAG,cAAc,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;YACzF,MAAM,eAAe,GAAG,iBAAiB,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC;YAE5E,MAAM,eAAe,GAAG,MAAM,eAAe,CAAC,MAAM,EAAE,CAAC;YACvD,IAAI,CAAC,eAAe,EAAE,CAAC;gBACrB,UAAU,CAAC,IAAI,CAAC,aAAa,aAAa,0CAA0C,CAAC,CAAC;gBACtF,MAAM,eAAe,CAAC,MAAM,EAAE,CAAC;YACjC,CAAC;iBAAM,CAAC;gBACN,UAAU,CAAC,IAAI,CAAC,aAAa,aAAa,kBAAkB,CAAC,CAAC;YAChE,CAAC;YAED,MAAM,UAAU,GAAG,KAAK,CAAC;YACzB,OAAO,CAAC,GAAG,CACT,4BAA4B,CAAC,mBAAmB,CAAC,iBAAiB,CAChE,kBAAkB,EAClB,aAAa,EACb,UAAU,CACX,CACF,CAAC;YAEF,MAAM,IAAI,CAAC,oBAAoB,CAAC,YAAY,CAAC,CAAC;YAC9C,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,sBAAsB,CACrD,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,UAAU,CACX,CAAC;YAEF,IAAI,aAAa,CAAC,UAAU,KAAK,CAAC,EAAE,CAAC;gBACnC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,0BAA0B,EAAE,CAAC;YACtE,CAAC;YAED,MAAM,WAAW,GAAG,aAAa,CAAC,UAAU,GAAG,aAAa,CAAC,aAAa,CAAC,MAAM,CAAC;YAClF,IAAI,WAAW,GAAG,CAAC,EAAE,CAAC;gBACpB,IAAI,aAAa,CAAC,iBAAiB,EAAE,CAAC;oBACpC,MAAM,qBAAqB,GAAG,aAAa,CAAC,iBAAiB,CAAC,IAAI,CAChE,CAAC,UAAU,EAAE,EAAE,CACb,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,0CAA0C,CAAC;wBACrE,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CACpD,CAAC;oBAEF,IAAI,qBAAqB,EAAE,CAAC;wBAC1B,OAAO;4BACL,OAAO,EAAE,KAAK;4BACd,YAAY,EACV,4BAA4B,CAAC,4BAA4B,CAAC,wBAAwB,CAChF,kBAAkB,CACnB;yBACJ,CAAC;oBACJ,CAAC;gBACH,CAAC;gBAED,6EAA6E;gBAC7E,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC;gBACzD,MAAM,QAAQ,GAAG,eAAe,CAAC,YAAY,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC;gBACzE,MAAM,eAAe,GAAG,QAAQ;qBAC7B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;qBACrD,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;gBAEpC,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,cAAc,EAAE,IAAI;oBACpB,eAAe,EAAE,WAAW;oBAC5B,UAAU,EAAE,aAAa,CAAC,UAAU;oBACpC,WAAW,EAAE,eAAe;oBAC5B,iBAAiB,EAAE,aAAa,CAAC,iBAAiB;iBACnD,CAAC;YACJ,CAAC;YAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC3B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC5E,MAAM,6BAA6B,GACjC,YAAY,CAAC,QAAQ,CAAC,WAAW,CAAC;gBAClC,YAAY,CAAC,QAAQ,CAAC,aAAa,CAAC;gBACpC,YAAY,CAAC,QAAQ,CAAC,WAAW,CAAC;gBAClC,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YAC/B,IAAI,6BAA6B,EAAE,CAAC;gBAClC,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,YAAY,EACV,4BAA4B,CAAC,uBAAuB,CAAC,wBAAwB,CAC3E,kBAAkB,CACnB;iBACJ,CAAC;YACJ,CAAC;YACD,UAAU,CAAC,KAAK,CAAC,iCAAiC,KAAK,EAAE,CAAC,CAAC;YAC3D,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC;QAC1C,CAAC;IACH,CAAC;IACO,KAAK,CAAC,oBAAoB,CAAC,YAAoB;QACrD,UAAU,CAAC,IAAI,CAAC,2CAA2C,YAAY,EAAE,CAAC,CAAC;QAC3E,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,EAAE,kBAAkB,CAAC,CAAC;QACzD,MAAM,cAAc,GAAG,IAAI,CAAC,YAAY,EAAE,wBAAwB,CAAC,CAAC;QAEpE,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC3B,UAAU,CAAC,KAAK,CAAC,uCAAuC,SAAS,EAAE,CAAC,CAAC;YACrE,OAAO;QACT,CAAC;QACD,UAAU,CAAC,IAAI,CAAC,8BAA8B,SAAS,EAAE,CAAC,CAAC;QAE3D,IAAI,CAAC;YACH,MAAM,YAAY,GAAG,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YACtD,aAAa,CAAC,cAAc,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC;YACrD,UAAU,CAAC,IAAI,CAAC,uCAAuC,cAAc,EAAE,CAAC,CAAC;YAEzE,MAAM,yBAAyB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiGvC,CAAC;YAEI,aAAa,CAAC,SAAS,EAAE,yBAAyB,EAAE,OAAO,CAAC,CAAC;YAC7D,UAAU,CAAC,IAAI,CAAC,6CAA6C,CAAC,CAAC;QACjE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,UAAU,CAAC,KAAK,CACd,qCAAqC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAC9F,CAAC;YACF,OAAO;QACT,CAAC;IACH,CAAC;IAED,yEAAyE;IAEzE,KAAK,CAAC,oCAAoC,CACxC,gBAAyB,EACzB,iBAA4C;QAE5C,IAAI,CAAC;YACH,UAAU,CAAC,IAAI,CACb,uDAAuD,gBAAgB,IAAI,6BAA6B,EAAE,CAC3G,CAAC;YACF,MAAM,IAAI,GAAG,uBAAuB,CAAC,QAAQ,CAAC,UAAU,CAAC;YACzD,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,UAAU,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;gBAC3D,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,YAAY,EAAE,4BAA4B,CAAC,wBAAwB,CAAC,OAAO;iBAC5E,CAAC;YACJ,CAAC;YACD,UAAU,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC;YAEvD,MAAM,UAAU,GAAG,gBAAgB,IAAI,mBAAmB,CAAC;YAC3D,MAAM,gBAAgB,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,UAAU,CAAC,CAAC;YAEzD,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;gBAClC,UAAU,CAAC,KAAK,CAAC,iCAAiC,gBAAgB,EAAE,CAAC,CAAC;gBACtE,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,YAAY,EACV,4BAA4B,CAAC,gCAAgC,CAAC,gBAAgB,CAC5E,UAAU,CACX;iBACJ,CAAC;YACJ,CAAC;YACD,UAAU,CAAC,IAAI,CAAC,6BAA6B,gBAAgB,EAAE,CAAC,CAAC;YAEjE,MAAM,SAAS,GAAG,uBAAuB,CAAC,QAAQ,CAAC,KAAK,CAAC;YACzD,UAAU,CAAC,IAAI,CAAC,oCAAoC,SAAS,EAAE,CAAC,CAAC;YACjE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,sBAAsB,CAC9C,IAAI,EACJ,SAAS,EACT,gBAAgB,EAChB,iBAAkB,CACnB,CAAC;YACF,UAAU,CAAC,IAAI,CAAC,qCAAqC,SAAS,EAAE,CAAC,CAAC;YAClE,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC5E,UAAU,CAAC,KAAK,CAAC,kBAAkB,YAAY,EAAE,CAAC,CAAC;YACnD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC;QAC1C,CAAC;IACH,CAAC;IAED,mFAAmF;IAE3E,KAAK,CAAC,sBAAsB,CAClC,eAAgC,EAChC,UAAkB,EAClB,QAAgB,EAChB,iBAA0B;QAS1B,gFAAgF;QAChF,MAAM,aAAa,GAAG,eAAe,CAAC,UAAU,EAAE,QAAQ,EAAE,iBAAiB,CAAC,CAAC,IAAI,CACjF,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAC1B,CAAC;QAEF,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,OAAO,EAAE,aAAa,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;QAC5F,CAAC;QAED,MAAM,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAE1E,MAAM,WAAW,GAAG,2BAA2B,CAAC,aAAa,CAAC,CAAC;QAC/D,UAAU,CAAC,IAAI,CACb,mCAAmC,WAAW,QAAQ,aAAa,CAAC,MAAM,uBAAuB,CAAC,SAAS,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAC5I,CAAC;QACF,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACnC,UAAU,CAAC,IAAI,CAAC,iCAAiC,WAAW,wBAAwB,CAAC,CAAC;QACtF,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,4BAA4B,CACrD,eAAe,EACf,aAAa,EACb,WAAW,CACZ,CAAC;QAEF,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACjC,MAAM,UAAU,GAAG,aAAa,GAAG,eAAe,CAAC;QACnD,UAAU,CAAC,IAAI,CAAC,uBAAuB,UAAU,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAE5F,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,MAAM,CAAC;QACrE,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,MAAM,CAAC;QAC1E,UAAU,CAAC,IAAI,CACb,mBAAmB,UAAU,gBAAgB,MAAM,kBAAkB,OAAO,CAAC,MAAM,cAAc,CAClG,CAAC;QAEF,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;YACf,MAAM,MAAM,GAAG,OAAO;iBACnB,MAAM,CAAC,CAAC,CAAC,EAA8B,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC;iBAClE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;iBAC5B,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,sBAAsB;YAEtC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;gBAC9B,UAAU,CAAC,KAAK,CAAC,MAAM,KAAK,GAAG,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC;YAChD,CAAC,CAAC,CAAC;YAEH,iDAAiD;YACjD,MAAM,WAAW,GAAG,IAAI,GAAG,CACzB,OAAO;iBACJ,MAAM,CAAC,CAAC,CAAC,EAAuC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC;iBAC5E,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CACvB,CAAC;YACF,MAAM,eAAe,GAAG,aAAa;iBAClC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;iBACrD,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAEpC,gCAAgC;YAChC,MAAM,iBAAiB,GAA+C,EAAE,CAAC;YACzE,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;gBAChC,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;oBACjC,MAAM,QAAQ,GAAG,aAAa,CAAC,KAAK,CAAC,EAAE,YAAY,IAAI,iBAAiB,KAAK,EAAE,CAAC;oBAChF,MAAM,YAAY,GAChB,MAAM,CAAC,MAAM,YAAY,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;oBACjF,iBAAiB,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC;gBAC5D,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,8DAA8D;YAC9D,UAAU,CAAC,KAAK,CACd,kBAAkB,MAAM,gDAAgD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC5F,CAAC;YACF,OAAO;gBACL,aAAa,EAAE,OAAO;qBACnB,MAAM,CAAC,CAAC,CAAC,EAAuC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC;qBAC5E,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;gBACtB,WAAW,EAAE,eAAe;gBAC5B,iBAAiB;gBACjB,UAAU,EAAE,aAAa,CAAC,MAAM;gBAChC,SAAS;gBACT,UAAU;aACX,CAAC;QACJ,CAAC;QAED,MAAM,aAAa,GAAG,OAAO;aAC1B,MAAM,CAAC,CAAC,CAAC,EAAuC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC;aAC5E,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAEvB,OAAO;YACL,aAAa;YACb,WAAW,EAAE,EAAE;YACf,UAAU,EAAE,aAAa,CAAC,MAAM;YAChC,SAAS;YACT,UAAU;SACX,CAAC;IACJ,CAAC;IAED,yFAAyF;IAEjF,KAAK,CAAC,4BAA4B,CACxC,eAAgC,EAChC,KAA2F,EAC3F,WAAmB;QAEnB,MAAM,WAAW,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,KAAK,IAAqB,EAAE;YACtE,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,yBAAyB,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;gBAChE,OAAO,QAAQ,CAAC,YAAY,CAAC;YAC/B,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,UAAU,CAAC,KAAK,CACd,0BAA0B,QAAQ,CAAC,YAAY,MAC7C,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAC3C,EAAE,CACH,CAAC;gBACF,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC,4BAA4B,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IACrE,CAAC;IAED,6EAA6E;IAErE,KAAK,CAAC,4BAA4B,CACxC,KAA8B,EAC9B,WAAmB;QAEnB,MAAM,OAAO,GAA8B,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACnE,IAAI,cAAc,GAAG,CAAC,CAAC;QAEvB,2EAA2E;QAC3E,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,UAAU,EAAE,WAAW,GAAG,CAAC,CAAC,CAAC;QACxE,MAAM,OAAO,GAAmC,EAAE,CAAC;QAEnD,iFAAiF;QACjF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,SAAS,EAAE,CAAC;YACjD,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC;QAC9C,CAAC;QAED,gEAAgE;QAChE,UAAU,CAAC,IAAI,CAAC,cAAc,OAAO,CAAC,MAAM,iBAAiB,SAAS,kBAAkB,CAAC,CAAC;QAC1F,KAAK,IAAI,UAAU,GAAG,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,CAAC;YACnE,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;YAClC,MAAM,eAAe,GAAG,UAAU,GAAG,SAAS,CAAC;YAC/C,UAAU,CAAC,IAAI,CACb,kBAAkB,UAAU,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,SAAS,KAAK,CAAC,MAAM,QAAQ,CAChF,CAAC;YAEF,4EAA4E;YAC5E,MAAM,aAAa,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE;gBACxD,MAAM,WAAW,GAAG,eAAe,GAAG,SAAS,CAAC;gBAChD,IAAI,CAAC;oBACH,MAAM,MAAM,GAAG,MAAM,IAAI,EAAE,CAAC;oBAC5B,OAAO,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;oBAC9D,OAAO,MAAM,CAAC;gBAChB,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,OAAO,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;oBAC7D,UAAU,CAAC,KAAK,CACd,wBAAwB,WAAW,KACjC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAC3C,EAAE,CACH,CAAC;oBACF,OAAO;gBACT,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,MAAM,SAAS,GAAmB,EAAE,CAAC;YAErC,KAAK,MAAM,OAAO,IAAI,aAAa,EAAE,CAAC;gBACpC,IAAI,SAAS,CAAC,MAAM,IAAI,WAAW,EAAE,CAAC;oBACpC,MAAM,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBAChC,CAAC;gBACD,MAAM,cAAc,GAAG,OAAO;qBAC3B,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;oBACf,cAAc,EAAE,CAAC;oBACjB,OAAO,MAAM,CAAC;gBAChB,CAAC,CAAC;qBACD,KAAK,CAAC,GAAG,EAAE;oBACV,cAAc,EAAE,CAAC;gBACnB,CAAC,CAAC;qBACD,OAAO,CAAC,GAAG,EAAE;oBACZ,yDAAyD;oBACzD,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;oBAChD,IAAI,KAAK,GAAG,CAAC,CAAC;wBAAE,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;gBAC7C,CAAC,CAAC,CAAC;gBAEL,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YACjC,CAAC;YAED,iFAAiF;YACjF,MAAM,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;YACpC,UAAU,CAAC,IAAI,CAAC,mBAAmB,UAAU,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QACzE,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,0CAA0C;IAElC,KAAK,CAAC,yBAAyB,CACrC,eAAgC,EAChC,QAAuF;QAEvF,UAAU,CAAC,IAAI,CACb,mBAAmB,QAAQ,CAAC,YAAY,KAAK,CAAC,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,QAAQ,CAAC,WAAW,GAAG,CAC9G,CAAC;QACF,MAAM,eAAe,GAAG,eAAe,CAAC,kBAAkB,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QAClF,MAAM,UAAU,GAAG,eAAe,CAAC,kBAAkB,CAAC;QACtD,MAAM,SAAS,GAAG,eAAe,CAAC,gBAAgB,CAAC;QAEnD,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,UAAU,EAAE,OAAO,EAAE,EAAE,CAAC;YACvD,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,sBAAsB,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;gBAC7D,OAAO;YACT,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,aAAa,GAAG,OAAO,KAAK,UAAU,CAAC;gBAC7C,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;gBAC9E,UAAU,CAAC,IAAI,CACb,kBAAkB,OAAO,eAAe,QAAQ,CAAC,YAAY,KAAK,YAAY,EAAE,CACjF,CAAC;gBAEF,IAAI,aAAa,EAAE,CAAC;oBAClB,UAAU,CAAC,KAAK,CACd,oCAAoC,QAAQ,CAAC,YAAY,KAAK,YAAY,EAAE,CAC7E,CAAC;oBACF,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;wBAC3B,MAAM,KAAK,CAAC;oBACd,CAAC;oBACD,MAAM,IAAI,KAAK,CACb,qBAAqB,QAAQ,CAAC,YAAY,UAAU,UAAU,cAAc,YAAY,EAAE,CAC3F,CAAC;gBACJ,CAAC;gBAED,sDAAsD;gBACtD,MAAM,KAAK,GAAG,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC;gBACzE,UAAU,CAAC,IAAI,CACb,uBAAuB,QAAQ,CAAC,YAAY,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,OAAO,GAAG,CAAC,IAAI,UAAU,GAAG,CAC/G,CAAC;gBACF,MAAM,IAAI,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;YAC/D,CAAC;QACH,CAAC;IACH,CAAC;IAED,gFAAgF;IAExE,KAAK,CAAC,sBAAsB,CAClC,eAAgC,EAChC,QAAuF;QAEvF,IAAI,QAAQ,CAAC,IAAI,IAAI,eAAe,CAAC,oBAAoB,EAAE,CAAC;YAC1D,gDAAgD;YAChD,MAAM,WAAW,GAAG,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACpD,MAAM,eAAe,CAAC,MAAM,CAAC,WAAW,EAAE,WAAW,CAAC,MAAM,EAAE;gBAC5D,eAAe,EAAE;oBACf,eAAe,EAAE,QAAQ,CAAC,WAAW;iBACtC;aACF,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,QAAQ,CAAC,IAAI,IAAI,eAAe,CAAC,oBAAoB,EAAE,CAAC;YACjE,uDAAuD;YACvD,MAAM,WAAW,GAAG,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACpD,MAAM,eAAe,CAAC,UAAU,CAAC,WAAW,EAAE;gBAC5C,eAAe,EAAE;oBACf,eAAe,EAAE,QAAQ,CAAC,WAAW;iBACtC;gBACD,SAAS,EAAE,eAAe,CAAC,oBAAoB;gBAC/C,WAAW,EAAE,eAAe,CAAC,oBAAoB;aAClD,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,qDAAqD;YACrD,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACnD,MAAM,eAAe,CAAC,YAAY,CAChC,MAAM,EACN,eAAe,CAAC,kBAAkB,EAClC,eAAe,CAAC,sBAAsB,EACtC;gBACE,eAAe,EAAE;oBACf,eAAe,EAAE,QAAQ,CAAC,WAAW;iBACtC;aACF,CACF,CAAC;QACJ,CAAC;QACD,UAAU,CAAC,IAAI,CAAC,0BAA0B,QAAQ,CAAC,YAAY,EAAE,CAAC,CAAC;IACrE,CAAC;CACF","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport { BlobServiceClient, ContainerClient, BlockBlobClient } from \"@azure/storage-blob\";\nimport type { TokenCredential } from \"@azure/core-auth\";\nimport { coreLogger } from \"../common/logger.js\";\nimport { readFileSync, writeFileSync, existsSync, createReadStream } from \"fs\";\nimport { join } from \"path\";\nimport { UploadConstants } from \"../common/constants.js\";\nimport { ServiceErrorMessageConstants } from \"../common/messages.js\";\nimport {\n populateValuesFromServiceUrl,\n calculateOptimalConcurrency,\n collectAllFiles,\n getStorageAccountNameFromUri,\n} from \"./utils.js\";\nimport { PlaywrightServiceConfig } from \"../common/playwrightServiceConfig.js\";\nimport type { WorkspaceMetaData, UploadResult } from \"../common/types.js\";\n\nexport class PlaywrightReporterStorageManager {\n // Uploads the HTML report folder to Azure Storage\n async uploadHtmlReportFolder(\n credential: TokenCredential,\n runId: string,\n outputFolder: string,\n workspaceDetails: WorkspaceMetaData,\n ): Promise<UploadResult> {\n coreLogger.info(\n `Starting HTML report upload for runId: ${runId}, outputFolder: ${outputFolder}`,\n );\n\n const storageAccountName =\n getStorageAccountNameFromUri(workspaceDetails?.storageUri || \"\") || \"unknown\";\n\n try {\n coreLogger.info(`Received workspace details: ${JSON.stringify(workspaceDetails, null, 2)}`);\n\n if (!workspaceDetails.storageUri) {\n coreLogger.error(\"Storage URI not found in workspace details\");\n return {\n success: false,\n errorMessage: ServiceErrorMessageConstants.STORAGE_URI_NOT_FOUND.message,\n };\n }\n\n const blobServiceClient = new BlobServiceClient(workspaceDetails?.storageUri, credential);\n coreLogger.info(\"blobServiceClient created successfully.\");\n const serviceUrlInfo = populateValuesFromServiceUrl();\n if (!serviceUrlInfo?.accountId) {\n coreLogger.error(\"Unable to extract workspace ID from service URL\");\n return {\n success: false,\n errorMessage: ServiceErrorMessageConstants.UNABLE_TO_EXTRACT_WORKSPACE_ID.message,\n };\n }\n\n const containerName = serviceUrlInfo.accountId.toLowerCase().replace(/[^a-z0-9-]/g, \"-\");\n const containerClient = blobServiceClient.getContainerClient(containerName);\n\n const containerExists = await containerClient.exists();\n if (!containerExists) {\n coreLogger.info(`Container ${containerName} does not exist. Creating new container.`);\n await containerClient.create();\n } else {\n coreLogger.info(`Container ${containerName} already exists.`);\n }\n\n const folderName = runId;\n console.log(\n ServiceErrorMessageConstants.UPLOADING_ARTIFACTS.formatWithDetails(\n storageAccountName,\n containerName,\n folderName,\n ),\n );\n\n await this.modifyTraceIndexHtml(outputFolder);\n const uploadResults = await this.uploadFolderInParallel(\n containerClient,\n outputFolder,\n outputFolder,\n folderName,\n );\n\n if (uploadResults.totalFiles === 0) {\n return { success: false, errorMessage: \"No files found to upload\" };\n }\n\n const failedFiles = uploadResults.totalFiles - uploadResults.uploadedFiles.length;\n if (failedFiles > 0) {\n if (uploadResults.failedFileDetails) {\n const hasAuthorizationError = uploadResults.failedFileDetails.some(\n (fileDetail) =>\n fileDetail.error.includes(\"not authorized to perform this operation\") ||\n fileDetail.error.includes(\"AuthorizationFailure\"),\n );\n\n if (hasAuthorizationError) {\n return {\n success: false,\n errorMessage:\n ServiceErrorMessageConstants.STORAGE_AUTHORIZATION_FAILED.formatWithStorageAccount(\n storageAccountName,\n ),\n };\n }\n }\n\n // Get list of failed file names by comparing total files with uploaded files\n const uploadedSet = new Set(uploadResults.uploadedFiles);\n const allFiles = collectAllFiles(outputFolder, outputFolder, folderName);\n const failedFileNames = allFiles\n .filter((file) => !uploadedSet.has(file.relativePath))\n .map((file) => file.relativePath);\n\n return {\n success: false,\n partialSuccess: true,\n failedFileCount: failedFiles,\n totalFiles: uploadResults.totalFiles,\n failedFiles: failedFileNames,\n failedFileDetails: uploadResults.failedFileDetails,\n };\n }\n\n return { success: true };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n const hasStorageAccountDeletedError =\n errorMessage.includes(\"ENOTFOUND\") ||\n errorMessage.includes(\"getaddrinfo\") ||\n errorMessage.includes(\"not found\") ||\n errorMessage.includes(\"404\");\n if (hasStorageAccountDeletedError) {\n return {\n success: false,\n errorMessage:\n ServiceErrorMessageConstants.STORAGE_ACCOUNT_DELETED.formatWithStorageAccount(\n storageAccountName,\n ),\n };\n }\n coreLogger.error(`Failed to upload HTML report: ${error}`);\n return { success: false, errorMessage };\n }\n }\n private async modifyTraceIndexHtml(outputFolder: string): Promise<void> {\n coreLogger.info(`Starting trace modification for folder: ${outputFolder}`);\n const indexPath = join(outputFolder, \"trace/index.html\");\n const localIndexPath = join(outputFolder, \"trace/index.local.html\");\n\n if (!existsSync(indexPath)) {\n coreLogger.error(`trace/index.html not found at path: ${indexPath}`);\n return;\n }\n coreLogger.info(`Found trace/index.html at: ${indexPath}`);\n\n try {\n const originalHtml = readFileSync(indexPath, \"utf-8\");\n writeFileSync(localIndexPath, originalHtml, \"utf-8\");\n coreLogger.info(`Backed up original trace viewer to: ${localIndexPath}`);\n\n const redirectTraceviewerScript = `<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\">\n <title>Redirecting to Trace Viewer...</title>\n</head>\n<body>\n <script>\n /**\n * Trace Viewer Redirect Logic\n * \n * This script handles two scenarios:\n * 1. Azure Portal Access (with SAS tokens): Redirects to public Playwright trace viewer at https://trace.playwright.dev/\n * - Preserves SAS tokens on the trace URL to allow the public viewer to access the trace file from Azure Storage\n * 2. Local Development: Uses the local copy of the trace viewer (index.local.html)\n * - Preserves all query parameters including the trace parameter\n * \n * The script detects the scenario by checking:\n * - Presence of SAS tokens (sig, sv parameters) indicates Azure Portal access\n * - localhost/file protocol indicates local development\n * \n * Authentication token preservation:\n * - For Azure Portal: SAS tokens are added to the trace URL (not the viewer URL) so the viewer can fetch the trace\n * - For local dev: All parameters are forwarded to the local viewer\n */\n (function() {\n function shouldRedirect() {\n try {\n const currentUrl = new URL(location.href);\n const traceParam = currentUrl.searchParams.get('trace');\n if (!traceParam) return false;\n\n // Check if current URL (the index.html itself) has SAS tokens - indicates Azure Portal access\n const currentHasSas = currentUrl.searchParams.has('sig') || currentUrl.searchParams.has('sv');\n \n // Check if we're on localhost or file protocol (cover common local dev scenarios)\n const hostname = currentUrl.hostname;\n const protocol = currentUrl.protocol;\n const isLoopbackV4 =\n hostname === 'localhost' ||\n hostname === '127.0.0.1' ||\n hostname.startsWith('127.');\n const isLoopbackV6 =\n hostname === '::1' ||\n hostname === '[::1]';\n const isCustomLocalName =\n hostname.endsWith('.localhost') ||\n hostname.endsWith('.local');\n const isLocalHost =\n protocol === 'file:' ||\n isLoopbackV4 ||\n isLoopbackV6 ||\n isCustomLocalName;\n\n // Redirect to public trace viewer if:\n // 1. Current page is accessed with SAS tokens (Azure Portal scenario)\n // 2. Not running on localhost/file protocol\n return currentHasSas && !isLocalHost;\n } catch (e) {\n console.error('Trace redirect detection failed', e);\n return false;\n }\n }\n\n if (shouldRedirect()) {\n const url = new URL(location.href);\n const traceParam = url.searchParams.get('trace');\n const trace = new URL(traceParam, url);\n\n // Copy all query parameters from the current URL to the trace URL (preserve SAS tokens)\n for (const [key, value] of url.searchParams.entries()) {\n if (key !== 'trace') {\n trace.searchParams.set(key, value);\n }\n }\n\n const publicTraceViewer = new URL('https://trace.playwright.dev/');\n publicTraceViewer.searchParams.set('trace', trace.toString());\n\n location.replace(publicTraceViewer.toString());\n } else {\n // Use the local copy of the Playwright trace viewer when running locally\n // Preserve all query parameters including the trace parameter\n const currentUrl = new URL(location.href);\n const localViewerUrl = new URL('index.local.html', currentUrl);\n \n // Copy all query parameters to the local viewer URL\n for (const [key, value] of currentUrl.searchParams.entries()) {\n localViewerUrl.searchParams.set(key, value);\n }\n \n location.replace(localViewerUrl.toString());\n }\n })();\n </script>\n</body>\n</html>\n`;\n\n writeFileSync(indexPath, redirectTraceviewerScript, \"utf-8\");\n coreLogger.info(\"Successfully updated TraceViewer index file\");\n } catch (error) {\n coreLogger.error(\n `Error modifying trace/index.html: ${error instanceof Error ? error.message : String(error)}`,\n );\n return;\n }\n }\n\n // Uploads the entire Playwright HTML report folder after tests complete.\n\n async uploadPlaywrightHtmlReportAfterTests(\n outputFolderName?: string,\n workspaceMetadata?: WorkspaceMetaData | null,\n ): Promise<UploadResult> {\n try {\n coreLogger.info(\n `Starting post-test HTML report upload, folder name: ${outputFolderName || \"default (playwright-report)\"}`,\n );\n const cred = PlaywrightServiceConfig.instance.credential;\n if (!cred) {\n coreLogger.error(\"No credential found for authentication\");\n return {\n success: false,\n errorMessage: ServiceErrorMessageConstants.NO_CRED_ENTRA_AUTH_ERROR.message,\n };\n }\n coreLogger.info(\"Credential found for authentication\");\n\n const folderName = outputFolderName || \"playwright-report\";\n const outputFolderPath = join(process.cwd(), folderName);\n\n if (!existsSync(outputFolderPath)) {\n coreLogger.error(`HTML report folder not found: ${outputFolderPath}`);\n return {\n success: false,\n errorMessage:\n ServiceErrorMessageConstants.PLAYWRIGHT_TEST_REPORT_NOT_FOUND.formatWithFolder(\n folderName,\n ),\n };\n }\n coreLogger.info(`HTML report folder found: ${outputFolderPath}`);\n\n const testRunId = PlaywrightServiceConfig.instance.runId;\n coreLogger.info(`Starting upload for test run ID: ${testRunId}`);\n const result = await this.uploadHtmlReportFolder(\n cred,\n testRunId,\n outputFolderPath,\n workspaceMetadata!,\n );\n coreLogger.info(`Completed upload for test run ID: ${testRunId}`);\n return result;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n coreLogger.error(`Upload failed: ${errorMessage}`);\n return { success: false, errorMessage };\n }\n }\n\n // Parallel Upload Engine - Core upload orchestration with performance optimization\n\n private async uploadFolderInParallel(\n containerClient: ContainerClient,\n folderPath: string,\n basePath: string,\n runIdFolderPrefix?: string,\n ): Promise<{\n uploadedFiles: string[];\n failedFiles: string[];\n failedFileDetails?: Array<{ fileName: string; error: string }>;\n totalFiles: number;\n totalSize: number;\n uploadTime: number;\n }> {\n // Sort by size descending - upload large files first for better parallelization\n const filesToUpload = collectAllFiles(folderPath, basePath, runIdFolderPrefix).sort(\n (a, b) => b.size - a.size,\n );\n\n if (filesToUpload.length === 0) {\n return { uploadedFiles: [], failedFiles: [], totalFiles: 0, totalSize: 0, uploadTime: 0 };\n }\n\n const totalSize = filesToUpload.reduce((sum, file) => sum + file.size, 0);\n\n const concurrency = calculateOptimalConcurrency(filesToUpload);\n coreLogger.info(\n `Calculated optimal concurrency: ${concurrency} for ${filesToUpload.length} files (total size: ${(totalSize / 1024 / 1024).toFixed(2)} MB)`,\n );\n const uploadStartTime = Date.now();\n coreLogger.info(`Starting parallel upload with ${concurrency} concurrent operations`);\n const results = await this.uploadWithConcurrencyControl(\n containerClient,\n filesToUpload,\n concurrency,\n );\n\n const uploadEndTime = Date.now();\n const uploadTime = uploadEndTime - uploadStartTime;\n coreLogger.info(`Upload completed in ${uploadTime}ms (${(uploadTime / 1000).toFixed(2)}s)`);\n\n const failed = results.filter((r) => r.status === \"rejected\").length;\n const successful = results.filter((r) => r.status === \"fulfilled\").length;\n coreLogger.info(\n `Upload results: ${successful} successful, ${failed} failed out of ${results.length} total files`,\n );\n\n if (failed > 0) {\n const errors = results\n .filter((r): r is PromiseRejectedResult => r.status === \"rejected\")\n .map((r) => r.reason.message)\n .slice(0, 5); // Show first 5 errors\n\n errors.forEach((error, index) => {\n coreLogger.error(` ${index + 1}. ${error}`);\n });\n\n // Get failed file names and their error messages\n const uploadedSet = new Set(\n results\n .filter((r): r is PromiseFulfilledResult<string> => r.status === \"fulfilled\")\n .map((r) => r.value),\n );\n const failedFileNames = filesToUpload\n .filter((file) => !uploadedSet.has(file.relativePath))\n .map((file) => file.relativePath);\n\n // Create detailed error mapping\n const failedFileDetails: Array<{ fileName: string; error: string }> = [];\n results.forEach((result, index) => {\n if (result.status === \"rejected\") {\n const fileName = filesToUpload[index]?.relativePath || `File at index ${index}`;\n const errorMessage =\n result.reason instanceof Error ? result.reason.message : String(result.reason);\n failedFileDetails.push({ fileName, error: errorMessage });\n }\n });\n\n // Log error but don't throw to prevent breaking HTML reporter\n coreLogger.error(\n `Upload failed: ${failed} files could not be uploaded. Sample errors: ${errors.join(\", \")}`,\n );\n return {\n uploadedFiles: results\n .filter((r): r is PromiseFulfilledResult<string> => r.status === \"fulfilled\")\n .map((r) => r.value),\n failedFiles: failedFileNames,\n failedFileDetails,\n totalFiles: filesToUpload.length,\n totalSize,\n uploadTime,\n };\n }\n\n const uploadedFiles = results\n .filter((r): r is PromiseFulfilledResult<string> => r.status === \"fulfilled\")\n .map((r) => r.value);\n\n return {\n uploadedFiles,\n failedFiles: [],\n totalFiles: filesToUpload.length,\n totalSize,\n uploadTime,\n };\n }\n\n // Concurrency Control System - Manages parallel execution with controlled resource usage\n\n private async uploadWithConcurrencyControl(\n containerClient: ContainerClient,\n files: Array<{ fullPath: string; relativePath: string; size: number; contentType: string }>,\n concurrency: number,\n ): Promise<PromiseSettledResult<string>[]> {\n const uploadTasks = files.map((fileInfo) => async (): Promise<string> => {\n try {\n await this.uploadSingleFileOptimized(containerClient, fileInfo);\n return fileInfo.relativePath;\n } catch (error) {\n coreLogger.error(\n `Failed to upload file: ${fileInfo.relativePath} - ${\n error instanceof Error ? error.message : \"Unknown error\"\n }`,\n );\n throw error;\n }\n });\n\n return this.executeWithOptimizedBatching(uploadTasks, concurrency);\n }\n\n // Optimized Batch Execution Engine - High-performance task processing system\n\n private async executeWithOptimizedBatching<T>(\n tasks: Array<() => Promise<T>>,\n concurrency: number,\n ): Promise<PromiseSettledResult<T>[]> {\n const results: PromiseSettledResult<T>[] = new Array(tasks.length);\n let completedTasks = 0;\n\n // Splits tasks into optimal batches to balance memory usage vs. throughput\n const batchSize = Math.min(UploadConstants.BATCH_SIZE, concurrency * 2);\n const batches: Array<Array<() => Promise<T>>> = [];\n\n // Each batch will be processed with full concurrency before moving to next batch\n for (let i = 0; i < tasks.length; i += batchSize) {\n batches.push(tasks.slice(i, i + batchSize));\n }\n\n // Process each batch sequentially to maintain memory efficiency\n coreLogger.info(`Processing ${batches.length} batches with ${batchSize} tasks per batch`);\n for (let batchIndex = 0; batchIndex < batches.length; batchIndex++) {\n const batch = batches[batchIndex];\n const batchStartIndex = batchIndex * batchSize;\n coreLogger.info(\n `Starting batch ${batchIndex + 1}/${batches.length} with ${batch.length} tasks`,\n );\n\n // Transform each task into a promise that captures results at correct index\n const batchPromises = batch.map(async (task, taskIndex) => {\n const globalIndex = batchStartIndex + taskIndex;\n try {\n const result = await task();\n results[globalIndex] = { status: \"fulfilled\", value: result };\n return result;\n } catch (error) {\n results[globalIndex] = { status: \"rejected\", reason: error };\n coreLogger.error(\n `Task failed at index ${globalIndex}: ${\n error instanceof Error ? error.message : \"Unknown error\"\n }`,\n );\n return;\n }\n });\n\n const executing: Promise<any>[] = [];\n\n for (const promise of batchPromises) {\n if (executing.length >= concurrency) {\n await Promise.race(executing);\n }\n const wrappedPromise = promise\n .then((result) => {\n completedTasks++;\n return result;\n })\n .catch(() => {\n completedTasks++;\n })\n .finally(() => {\n // Cleanup: remove completed promise from executing array\n const index = executing.indexOf(wrappedPromise);\n if (index > -1) executing.splice(index, 1);\n });\n\n executing.push(wrappedPromise);\n }\n\n // Wait for all promises in current batch to complete before moving to next batch\n await Promise.allSettled(executing);\n coreLogger.info(`Completed batch ${batchIndex + 1}/${batches.length}`);\n }\n\n return results;\n }\n\n // Individual File Upload with Retry Logic\n\n private async uploadSingleFileOptimized(\n containerClient: ContainerClient,\n fileInfo: { fullPath: string; relativePath: string; contentType: string; size: number },\n ): Promise<void> {\n coreLogger.info(\n `Uploading file: ${fileInfo.relativePath} (${(fileInfo.size / 1024).toFixed(2)} KB, ${fileInfo.contentType})`,\n );\n const blockBlobClient = containerClient.getBlockBlobClient(fileInfo.relativePath);\n const maxRetries = UploadConstants.MAX_RETRY_ATTEMPTS;\n const baseDelay = UploadConstants.RETRY_BASE_DELAY;\n\n for (let attempt = 1; attempt <= maxRetries; attempt++) {\n try {\n await this.performOptimizedUpload(blockBlobClient, fileInfo);\n return;\n } catch (error) {\n const isLastAttempt = attempt === maxRetries;\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n coreLogger.info(\n `Upload attempt ${attempt} failed for ${fileInfo.relativePath}: ${errorMessage}`,\n );\n\n if (isLastAttempt) {\n coreLogger.error(\n `All retry attempts exhausted for ${fileInfo.relativePath}: ${errorMessage}`,\n );\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(\n `Upload failed for ${fileInfo.relativePath} after ${maxRetries} attempts: ${errorMessage}`,\n );\n }\n\n // Exponential backoff with jitter (Azure SDK pattern)\n const delay = baseDelay * Math.pow(2, attempt - 1) + Math.random() * 500;\n coreLogger.info(\n `Retrying upload for ${fileInfo.relativePath} in ${delay.toFixed(0)}ms (attempt ${attempt + 1}/${maxRetries})`,\n );\n await new Promise((_resolve) => setTimeout(_resolve, delay));\n }\n }\n }\n\n // Multi-Strategy Upload Engine - Optimized upload based on file characteristics\n\n private async performOptimizedUpload(\n blockBlobClient: BlockBlobClient,\n fileInfo: { fullPath: string; relativePath: string; contentType: string; size: number },\n ): Promise<void> {\n if (fileInfo.size <= UploadConstants.SMALL_FILE_THRESHOLD) {\n // DIRECT UPLOAD: Optimal for small files (≤1MB)\n const fileContent = readFileSync(fileInfo.fullPath);\n await blockBlobClient.upload(fileContent, fileContent.length, {\n blobHTTPHeaders: {\n blobContentType: fileInfo.contentType,\n },\n });\n } else if (fileInfo.size <= UploadConstants.LARGE_FILE_THRESHOLD) {\n // BLOCK UPLOAD: Optimal for medium files (1MB - 100MB)\n const fileContent = readFileSync(fileInfo.fullPath);\n await blockBlobClient.uploadData(fileContent, {\n blobHTTPHeaders: {\n blobContentType: fileInfo.contentType,\n },\n blockSize: UploadConstants.OPTIMIZED_BLOCK_SIZE,\n concurrency: UploadConstants.PER_FILE_CONCURRENCY,\n });\n } else {\n // STREAMING UPLOAD: Optimal for large files (>100MB)\n const stream = createReadStream(fileInfo.fullPath);\n await blockBlobClient.uploadStream(\n stream,\n UploadConstants.STREAM_BUFFER_SIZE,\n UploadConstants.LARGE_FILE_CONCURRENCY,\n {\n blobHTTPHeaders: {\n blobContentType: fileInfo.contentType,\n },\n },\n );\n }\n coreLogger.info(`Successfully uploaded: ${fileInfo.relativePath}`);\n }\n}\n"]}
|
|
@@ -78,6 +78,11 @@ export declare const ServiceErrorMessageConstants: {
|
|
|
78
78
|
key: string;
|
|
79
79
|
message: string;
|
|
80
80
|
};
|
|
81
|
+
STORAGE_ACCOUNT_DELETED: {
|
|
82
|
+
key: string;
|
|
83
|
+
message: string;
|
|
84
|
+
formatWithStorageAccount: (storageAccountName: string) => string;
|
|
85
|
+
};
|
|
81
86
|
REPORTER_REQUIRES_ENTRA_AUTH: {
|
|
82
87
|
key: string;
|
|
83
88
|
message: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../src/common/messages.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+CA0DE,MAAM,KAAG,MAAM;;;;;;;;;;;;;;;;;+CAkBf,MAAM,KAAG,MAAM;;;;;;;;;uDAWP,MAAM,KAAG,MAAM
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../src/common/messages.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+CA0DE,MAAM,KAAG,MAAM;;;;;;;;;;;;;;;;;+CAkBf,MAAM,KAAG,MAAM;;;;;;;;;uDAWP,MAAM,KAAG,MAAM;;;;;;;;;uDAWf,MAAM,KAAG,MAAM;;;;;;;;;;;;;;;;;;;;;kCA0BpC,MAAM,KAAG,MAAM;;;;;uCAMV,MAAM,KAAG,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;6BA0BzB,MAAM,KAAG,MAAM;;;;;4CAKA,MAAM,aAAa,MAAM,UAAU,MAAM,KAAG,MAAM;;;;;iCAM7D,MAAM,KAAG,MAAM;;;;;+CAKD,MAAM,KAAG,MAAM;;;;;;;;;;CAYzD,CAAC"}
|
|
@@ -83,6 +83,11 @@ exports.ServiceErrorMessageConstants = {
|
|
|
83
83
|
key: "UnableToExtractWorkspaceId",
|
|
84
84
|
message: "Unable to extract workspace ID from service URL",
|
|
85
85
|
},
|
|
86
|
+
STORAGE_ACCOUNT_DELETED: {
|
|
87
|
+
key: "StorageAccountDeleted",
|
|
88
|
+
message: "The storage account linked to your Playwright Workspace may have been deleted. Please link a different storage account to your Playwright Workspace before trying again. To learn more on how to link a new storage account, refer to https://aka.ms/pww-reporting-migration",
|
|
89
|
+
formatWithStorageAccount: (storageAccountName) => `The storage account linked to your Playwright Workspace (${storageAccountName}) may have been deleted. Please link a different storage account to your Playwright Workspace before trying again. To learn more on how to link a new storage account, refer to https://aka.ms/pww-reporting-migration`,
|
|
90
|
+
},
|
|
86
91
|
REPORTER_REQUIRES_ENTRA_AUTH: {
|
|
87
92
|
key: "ReporterRequiresEntraAuth",
|
|
88
93
|
message: "Playwright Workspaces Reporter can only be used with ENTRA_ID authentication. For more information, see https://aka.ms/pww/docs/authentication",
|