blob.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.currentBlobReportVersion = exports.BlobReporter = void 0;
  6. var _fs = _interopRequireDefault(require("fs"));
  7. var _path = _interopRequireDefault(require("path"));
  8. var _utils = require("playwright-core/lib/utils");
  9. var _utilsBundle = require("playwright-core/lib/utilsBundle");
  10. var _stream = require("stream");
  11. var _teleEmitter = require("./teleEmitter");
  12. var _zipBundle = require("playwright-core/lib/zipBundle");
  13. var _util = require("../util");
  14. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  15. /**
  16. * Copyright (c) Microsoft Corporation.
  17. *
  18. * Licensed under the Apache License, Version 2.0 (the "License");
  19. * you may not use this file except in compliance with the License.
  20. * You may obtain a copy of the License at
  21. *
  22. * http://www.apache.org/licenses/LICENSE-2.0
  23. *
  24. * Unless required by applicable law or agreed to in writing, software
  25. * distributed under the License is distributed on an "AS IS" BASIS,
  26. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  27. * See the License for the specific language governing permissions and
  28. * limitations under the License.
  29. */
  30. const currentBlobReportVersion = exports.currentBlobReportVersion = 1;
  31. class BlobReporter extends _teleEmitter.TeleReporterEmitter {
  32. constructor(options) {
  33. super(message => this._messages.push(message), false);
  34. this._messages = [];
  35. this._attachments = [];
  36. this._options = void 0;
  37. this._salt = void 0;
  38. this._reportName = void 0;
  39. this._options = options;
  40. if (this._options.fileName && !this._options.fileName.endsWith('.zip')) throw new Error(`Blob report file name must end with .zip extension: ${this._options.fileName}`);
  41. this._salt = (0, _utils.createGuid)();
  42. }
  43. onConfigure(config) {
  44. var _config$shard;
  45. const metadata = {
  46. version: currentBlobReportVersion,
  47. userAgent: (0, _utils.getUserAgent)(),
  48. name: process.env.PWTEST_BOT_NAME,
  49. shard: (_config$shard = config.shard) !== null && _config$shard !== void 0 ? _config$shard : undefined,
  50. pathSeparator: _path.default.sep
  51. };
  52. this._messages.push({
  53. method: 'onBlobReportMetadata',
  54. params: metadata
  55. });
  56. this._reportName = this._computeReportName(config);
  57. super.onConfigure(config);
  58. }
  59. async onEnd(result) {
  60. await super.onEnd(result);
  61. const outputDir = (0, _util.resolveReporterOutputPath)('blob-report', this._options.configDir, this._options.outputDir);
  62. if (!process.env.PWTEST_BLOB_DO_NOT_REMOVE) await (0, _utils.removeFolders)([outputDir]);
  63. await _fs.default.promises.mkdir(outputDir, {
  64. recursive: true
  65. });
  66. const zipFile = new _zipBundle.yazl.ZipFile();
  67. const zipFinishPromise = new _utils.ManualPromise();
  68. const finishPromise = zipFinishPromise.catch(e => {
  69. throw new Error(`Failed to write report ${this._reportName}: ` + e.message);
  70. });
  71. zipFile.on('error', error => zipFinishPromise.reject(error));
  72. const zipFileName = _path.default.join(outputDir, this._reportName);
  73. zipFile.outputStream.pipe(_fs.default.createWriteStream(zipFileName)).on('close', () => {
  74. zipFinishPromise.resolve(undefined);
  75. }).on('error', error => zipFinishPromise.reject(error));
  76. for (const {
  77. originalPath,
  78. zipEntryPath
  79. } of this._attachments) {
  80. var _fs$statSync;
  81. if (!((_fs$statSync = _fs.default.statSync(originalPath, {
  82. throwIfNoEntry: false
  83. })) !== null && _fs$statSync !== void 0 && _fs$statSync.isFile())) continue;
  84. zipFile.addFile(originalPath, zipEntryPath);
  85. }
  86. const lines = this._messages.map(m => JSON.stringify(m) + '\n');
  87. const content = _stream.Readable.from(lines);
  88. zipFile.addReadStream(content, 'report.jsonl');
  89. zipFile.end();
  90. await finishPromise;
  91. }
  92. _computeReportName(config) {
  93. if (this._options.fileName) return this._options.fileName;
  94. let reportName = 'report';
  95. if (config.shard) {
  96. const paddedNumber = `${config.shard.current}`.padStart(`${config.shard.total}`.length, '0');
  97. reportName = `${reportName}-${paddedNumber}`;
  98. }
  99. return `${reportName}.zip`;
  100. }
  101. _serializeAttachments(attachments) {
  102. return super._serializeAttachments(attachments).map(attachment => {
  103. if (!attachment.path) return attachment;
  104. // Add run guid to avoid clashes between shards.
  105. const sha1 = (0, _utils.calculateSha1)(attachment.path + this._salt);
  106. const extension = _utilsBundle.mime.getExtension(attachment.contentType) || 'dat';
  107. const newPath = `resources/${sha1}.${extension}`;
  108. this._attachments.push({
  109. originalPath: attachment.path,
  110. zipEntryPath: newPath
  111. });
  112. return {
  113. ...attachment,
  114. path: newPath
  115. };
  116. });
  117. }
  118. }
  119. exports.BlobReporter = BlobReporter;