@telefonica/acceptance-testing 3.0.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,6 +5,7 @@ import { queries, getDocument } from 'pptr-testing-library';
5
5
  import { configureToMatchImageSnapshot } from 'jest-image-snapshot';
6
6
  import globToRegExp from 'glob-to-regexp';
7
7
  import { execSync } from 'child_process';
8
+ import istanbul from 'istanbul-lib-coverage';
8
9
 
9
10
  function _regeneratorRuntime() {
10
11
  _regeneratorRuntime = function () {
@@ -364,6 +365,27 @@ function _objectWithoutPropertiesLoose(source, excluded) {
364
365
  return target;
365
366
  }
366
367
 
368
+ /**
369
+ * Debug function that logs to the console if the DEBUG_ACCEPTANCE_TESTING environment variable is set
370
+ */
371
+ var debug = function debug() {
372
+ if (process.env.DEBUG_ACCEPTANCE_TESTING) {
373
+ var _console;
374
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
375
+ args[_key] = arguments[_key];
376
+ }
377
+ (_console = console).debug.apply(_console, ['[acceptance-testing]'].concat(args));
378
+ }
379
+ };
380
+ /**
381
+ * Returns true if the current path matches the spied path, including parameters
382
+ */
383
+ var matchPath = function matchPath(spiedPath, currentPath) {
384
+ var normalizedCurrentPath = path.normalize(currentPath);
385
+ var pattern = globToRegExp(spiedPath);
386
+ return pattern.test(normalizedCurrentPath);
387
+ };
388
+
367
389
  var getGlobalPage = function getGlobalPage() {
368
390
  return global.page;
369
391
  };
@@ -385,80 +407,148 @@ var getRootPath = function getRootPath() {
385
407
  var prepareCoverageReportPath = function prepareCoverageReportPath(_ref) {
386
408
  var coveragePath = _ref.coveragePath;
387
409
  var ppidFile = path.join(coveragePath, '.ppid');
410
+ var nycOutputPath = path.join(coveragePath, '.nyc_output');
388
411
  var ppid = process.ppid.toString();
389
412
  if (!fs.existsSync(ppidFile) || fs.readFileSync(ppidFile, 'utf-8') !== ppid) {
390
413
  // the condition is just to make sure we don't remove files outside the repo
391
414
  if (getRootPath() === process.cwd() && path.normalize(coveragePath).startsWith(process.cwd())) {
392
- fs.rmSync(coveragePath, {
415
+ fs.rmSync(nycOutputPath, {
393
416
  recursive: true,
394
417
  force: true
395
418
  });
396
419
  }
397
- fs.mkdirSync(coveragePath, {
420
+ fs.mkdirSync(nycOutputPath, {
398
421
  recursive: true
399
422
  });
400
423
  fs.writeFileSync(ppidFile, ppid);
401
424
  }
402
425
  };
426
+ var workerId = process.env.JEST_WORKER_ID || '0';
427
+ /**
428
+ * Writes the coverage reports into single files, one per each coverage object (path). This makes it easier to merge them.
429
+ * The `workerId` from jest is used to avoid race conditions when multiple workers are running in parallel.
430
+ */
431
+ var writeCombinedCoverage = function writeCombinedCoverage(nycOutputPath, coverage) {
432
+ Object.values(coverage).forEach(function (value) {
433
+ if (value && value.path && value.hash) {
434
+ var _currentCoverage;
435
+ var filename = path.join(nycOutputPath, value.hash + "-" + workerId + ".json");
436
+ var currentCoverage = (_currentCoverage = {}, _currentCoverage[value.path] = value, _currentCoverage);
437
+ var previousCoverage = fs.existsSync(filename) ? JSON.parse(fs.readFileSync(filename, 'utf8')) : {};
438
+ var mergedCoverage = istanbul.createCoverageMap(previousCoverage);
439
+ mergedCoverage.merge(currentCoverage);
440
+ debug('Writing merged coverage:', value.path, value.hash);
441
+ fs.writeFileSync(filename, JSON.stringify(mergedCoverage.toJSON(), null, 2));
442
+ } else {
443
+ debug('Skip write coverage. Missing path or hash:', value);
444
+ }
445
+ });
446
+ };
403
447
  /**
404
- * Asumes the code was instrumented with istanbul and the coverage report stored in `window.__coverage__`.
448
+ * Assumes the code was instrumented with istanbul/nyc and the coverage report stored in `window.__coverage__`.
405
449
  * If not, this function does nothing.
406
450
  */
407
- var collectCoverageIfAvailable = /*#__PURE__*/function () {
451
+ var collectFrontendCoverage = /*#__PURE__*/function () {
408
452
  var _ref3 = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(_ref2) {
409
- var coveragePath, coverage, nycOutputPath;
453
+ var coveragePath, nycOutputPath, coverage;
410
454
  return _regeneratorRuntime().wrap(function _callee$(_context) {
411
455
  while (1) switch (_context.prev = _context.next) {
412
456
  case 0:
413
457
  coveragePath = _ref2.coveragePath;
414
- _context.next = 3;
458
+ nycOutputPath = path.join(coveragePath, '.nyc_output');
459
+ _context.next = 4;
415
460
  return getGlobalPage().evaluate(function () {
416
461
  return window.__coverage__;
417
462
  });
418
- case 3:
463
+ case 4:
419
464
  coverage = _context.sent;
420
465
  if (coverage) {
421
- _context.next = 6;
466
+ _context.next = 8;
422
467
  break;
423
468
  }
469
+ debug('Skipping coverage collection. No coverage found.');
424
470
  return _context.abrupt("return");
425
- case 6:
471
+ case 8:
472
+ debug('Frontend coverage found');
426
473
  prepareCoverageReportPath({
427
474
  coveragePath: coveragePath
428
475
  });
429
- nycOutputPath = path.join(coveragePath, '.nyc_output');
430
476
  fs.mkdirSync(nycOutputPath, {
431
477
  recursive: true
432
478
  });
433
- Object.values(coverage).forEach(function (cov) {
434
- if (cov && cov.path && cov.hash) {
435
- var _JSON$stringify;
436
- fs.writeFileSync(path.join(nycOutputPath, cov.hash + '.json'), JSON.stringify((_JSON$stringify = {}, _JSON$stringify[cov.path] = cov, _JSON$stringify)));
437
- }
438
- });
439
- case 10:
479
+ writeCombinedCoverage(nycOutputPath, coverage);
480
+ case 12:
440
481
  case "end":
441
482
  return _context.stop();
442
483
  }
443
484
  }, _callee);
444
485
  }));
445
- return function collectCoverageIfAvailable(_x) {
486
+ return function collectFrontendCoverage(_x) {
446
487
  return _ref3.apply(this, arguments);
447
488
  };
448
489
  }();
449
-
490
+ var writeCoverage = function writeCoverage(nycOutputPath, nameSuffix, coverage) {
491
+ Object.values(coverage).forEach(function (value) {
492
+ if (value && value.path && value.hash) {
493
+ var _JSON$stringify;
494
+ var filename = path.join(nycOutputPath, "" + value.hash + nameSuffix + ".json");
495
+ debug('Writing coverage:', value.path, value.hash);
496
+ fs.writeFileSync(filename, JSON.stringify((_JSON$stringify = {}, _JSON$stringify[value.path] = value, _JSON$stringify), null, 2));
497
+ } else {
498
+ debug('Skip write coverage. Missing path or hash:', value);
499
+ }
500
+ });
501
+ };
450
502
  /**
451
- * Returns true if the current path matches the spied path, including parameters
503
+ * Collects backend coverage reports from the provided URLs and stores them in the coverage folder
452
504
  */
453
- var matchPath = function matchPath(spiedPath, currentPath) {
454
- var normalizedCurrentPath = path.normalize(currentPath);
455
- var pattern = globToRegExp(spiedPath);
456
- return pattern.test(normalizedCurrentPath);
457
- };
505
+ var collectBackendCoverage = /*#__PURE__*/function () {
506
+ var _ref5 = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(_ref4) {
507
+ var coveragePath, coverageUrls, nycOutputPath, serverReports;
508
+ return _regeneratorRuntime().wrap(function _callee2$(_context2) {
509
+ while (1) switch (_context2.prev = _context2.next) {
510
+ case 0:
511
+ coveragePath = _ref4.coveragePath, coverageUrls = _ref4.coverageUrls;
512
+ nycOutputPath = path.join(coveragePath, '.nyc_output');
513
+ debug('Collecting backend coverage reports', coverageUrls);
514
+ _context2.next = 5;
515
+ return Promise.all(coverageUrls.map(function (url) {
516
+ return fetch(url).then(function (res) {
517
+ var _res$headers$get;
518
+ if (res.ok && res.status === 200 && (_res$headers$get = res.headers.get('content-type')) != null && _res$headers$get.includes('application/json')) {
519
+ return res.json();
520
+ }
521
+ debug('Error fetching coverage report:', {
522
+ url: url,
523
+ status: res.status
524
+ });
525
+ return null;
526
+ })["catch"](function () {
527
+ debug('Error fetching coverage report:', {
528
+ url: url
529
+ });
530
+ return null;
531
+ });
532
+ }));
533
+ case 5:
534
+ serverReports = _context2.sent;
535
+ serverReports.forEach(function (report, index) {
536
+ writeCoverage(nycOutputPath, "-backend" + index, report.coverage);
537
+ });
538
+ case 7:
539
+ case "end":
540
+ return _context2.stop();
541
+ }
542
+ }, _callee2);
543
+ }));
544
+ return function collectBackendCoverage(_x2) {
545
+ return _ref5.apply(this, arguments);
546
+ };
547
+ }();
458
548
 
459
549
  var _excluded = ["captureBeyondViewport"],
460
550
  _excluded2 = ["userAgent", "isDarkMode", "viewport", "cookies"];
461
- var _pkg$acceptanceTests, _ref, _projectConfig$covera;
551
+ var _pkg$acceptanceTests, _ref, _projectConfig$covera, _projectConfig$covera2;
462
552
  var LINUX_DOCKER_HOST_IP = '172.17.0.1';
463
553
  var getGlobalBrowser = function getGlobalBrowser() {
464
554
  return global.browser;
@@ -530,8 +620,10 @@ var serverHostName = /*#__PURE__*/function () {
530
620
  var rootDir = /*#__PURE__*/findRoot( /*#__PURE__*/process.cwd());
531
621
  var pkg = /*#__PURE__*/JSON.parse( /*#__PURE__*/fs.readFileSync( /*#__PURE__*/path.join(rootDir, 'package.json'), 'utf-8'));
532
622
  var projectConfig = (_pkg$acceptanceTests = pkg.acceptanceTests) != null ? _pkg$acceptanceTests : {};
623
+ debug('Project config:', projectConfig);
533
624
  var server = (_ref = isCi ? projectConfig.ciServer : projectConfig.devServer) != null ? _ref : projectConfig.server;
534
625
  var coveragePath = /*#__PURE__*/path.join(rootDir, (_projectConfig$covera = projectConfig.coveragePath) != null ? _projectConfig$covera : 'reports/coverage-acceptance');
626
+ var coverageUrls = (_projectConfig$covera2 = projectConfig.coverageUrls) != null ? _projectConfig$covera2 : [];
535
627
  var serverPort = server == null ? void 0 : server.port;
536
628
  var toMatchImageSnapshot = /*#__PURE__*/configureToMatchImageSnapshot({
537
629
  failureThreshold: 0,
@@ -883,45 +975,46 @@ var openPage = /*#__PURE__*/function () {
883
975
  }
884
976
  return protocol + "://" + hostname + ":" + port + path;
885
977
  }();
978
+ debug('Opening page:', url);
886
979
  _context7.t0 = userAgent;
887
980
  if (_context7.t0) {
888
- _context7.next = 7;
981
+ _context7.next = 8;
889
982
  break;
890
983
  }
891
- _context7.next = 6;
984
+ _context7.next = 7;
892
985
  return getGlobalBrowser().userAgent();
893
- case 6:
894
- _context7.t0 = _context7.sent;
895
986
  case 7:
987
+ _context7.t0 = _context7.sent;
988
+ case 8:
896
989
  currentUserAgent = _context7.t0;
897
990
  page = getGlobalPage$1();
898
- _context7.next = 11;
991
+ _context7.next = 12;
899
992
  return page.bringToFront();
900
- case 11:
993
+ case 12:
901
994
  if (!viewport) {
902
- _context7.next = 14;
995
+ _context7.next = 15;
903
996
  break;
904
997
  }
905
- _context7.next = 14;
998
+ _context7.next = 15;
906
999
  return page.setViewport(viewport);
907
- case 14:
1000
+ case 15:
908
1001
  if (!cookies) {
909
- _context7.next = 17;
1002
+ _context7.next = 18;
910
1003
  break;
911
1004
  }
912
- _context7.next = 17;
1005
+ _context7.next = 18;
913
1006
  return page.setCookie.apply(page, cookies);
914
- case 17:
915
- _context7.next = 19;
1007
+ case 18:
1008
+ _context7.next = 20;
916
1009
  return page.setUserAgent(currentUserAgent + " acceptance-test");
917
- case 19:
918
- _context7.next = 21;
1010
+ case 20:
1011
+ _context7.next = 22;
919
1012
  return page.emulateMediaFeatures([{
920
1013
  name: 'prefers-color-scheme',
921
1014
  value: isDarkMode ? 'dark' : 'light'
922
1015
  }]);
923
- case 21:
924
- _context7.next = 23;
1016
+ case 22:
1017
+ _context7.next = 24;
925
1018
  return page.evaluateOnNewDocument(function (viewport) {
926
1019
  var _viewport$safeAreaIns;
927
1020
  var overriddenSafeAreaInsets = !viewport ? [] : Object.keys((_viewport$safeAreaIns = viewport == null ? void 0 : viewport.safeAreaInset) != null ? _viewport$safeAreaIns : {}).map(function (key) {
@@ -935,44 +1028,44 @@ var openPage = /*#__PURE__*/function () {
935
1028
  document.head.appendChild(style);
936
1029
  });
937
1030
  }, viewport);
938
- case 23:
1031
+ case 24:
939
1032
  if (!needsRequestInterception) {
940
- _context7.next = 27;
1033
+ _context7.next = 28;
941
1034
  break;
942
1035
  }
943
- _context7.next = 26;
1036
+ _context7.next = 27;
944
1037
  return page.setRequestInterception(true);
945
- case 26:
946
- page.on('request', requestInterceptor);
947
1038
  case 27:
948
- _context7.prev = 27;
949
- _context7.next = 30;
1039
+ page.on('request', requestInterceptor);
1040
+ case 28:
1041
+ _context7.prev = 28;
1042
+ _context7.next = 31;
950
1043
  return page["goto"](url);
951
- case 30:
952
- _context7.next = 41;
1044
+ case 31:
1045
+ _context7.next = 42;
953
1046
  break;
954
- case 32:
955
- _context7.prev = 32;
956
- _context7.t1 = _context7["catch"](27);
1047
+ case 33:
1048
+ _context7.prev = 33;
1049
+ _context7.t1 = _context7["catch"](28);
957
1050
  if (!_context7.t1.message.includes('net::ERR_CONNECTION_REFUSED')) {
958
- _context7.next = 40;
1051
+ _context7.next = 41;
959
1052
  break;
960
1053
  }
961
1054
  connectionError = new Error("Could not connect to " + url + ". Is the server running?");
962
1055
  Error.captureStackTrace(connectionError, openPage);
963
1056
  throw connectionError;
964
- case 40:
965
- throw _context7.t1;
966
1057
  case 41:
967
- _context7.next = 43;
1058
+ throw _context7.t1;
1059
+ case 42:
1060
+ _context7.next = 44;
968
1061
  return page.waitForFunction('document.fonts.status === "loaded"');
969
- case 43:
970
- return _context7.abrupt("return", getPageApi(page));
971
1062
  case 44:
1063
+ return _context7.abrupt("return", getPageApi(page));
1064
+ case 45:
972
1065
  case "end":
973
1066
  return _context7.stop();
974
1067
  }
975
- }, _callee7, null, [[27, 32]]);
1068
+ }, _callee7, null, [[28, 33]]);
976
1069
  }));
977
1070
  return function openPage(_x11) {
978
1071
  return _ref16.apply(this, arguments);
@@ -1150,30 +1243,53 @@ afterEach( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().ma
1150
1243
  return _regeneratorRuntime().wrap(function _callee14$(_context14) {
1151
1244
  while (1) switch (_context14.prev = _context14.next) {
1152
1245
  case 0:
1153
- _context14.next = 2;
1154
- return collectCoverageIfAvailable({
1246
+ if (!process.env.COLLECT_ACCEPTANCE_COVERAGE) {
1247
+ _context14.next = 3;
1248
+ break;
1249
+ }
1250
+ _context14.next = 3;
1251
+ return collectFrontendCoverage({
1155
1252
  coveragePath: coveragePath
1156
1253
  });
1157
- case 2:
1158
- _context14.prev = 2;
1254
+ case 3:
1255
+ _context14.prev = 3;
1159
1256
  page = getGlobalPage$1();
1160
1257
  requestHandlers = [];
1161
1258
  needsRequestInterception = false;
1162
1259
  page.off('request', requestInterceptor);
1163
1260
  // clear tab, this way we clear the DOM and stop js execution or pending requests
1164
- _context14.next = 9;
1261
+ _context14.next = 10;
1165
1262
  return page["goto"]('about:blank');
1166
- case 9:
1167
- _context14.next = 13;
1263
+ case 10:
1264
+ _context14.next = 14;
1168
1265
  break;
1169
- case 11:
1170
- _context14.prev = 11;
1171
- _context14.t0 = _context14["catch"](2);
1172
- case 13:
1266
+ case 12:
1267
+ _context14.prev = 12;
1268
+ _context14.t0 = _context14["catch"](3);
1269
+ case 14:
1173
1270
  case "end":
1174
1271
  return _context14.stop();
1175
1272
  }
1176
- }, _callee14, null, [[2, 11]]);
1273
+ }, _callee14, null, [[3, 12]]);
1274
+ })));
1275
+ afterAll( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee15() {
1276
+ return _regeneratorRuntime().wrap(function _callee15$(_context15) {
1277
+ while (1) switch (_context15.prev = _context15.next) {
1278
+ case 0:
1279
+ if (!process.env.COLLECT_ACCEPTANCE_COVERAGE) {
1280
+ _context15.next = 3;
1281
+ break;
1282
+ }
1283
+ _context15.next = 3;
1284
+ return collectBackendCoverage({
1285
+ coveragePath: coveragePath,
1286
+ coverageUrls: coverageUrls
1287
+ });
1288
+ case 3:
1289
+ case "end":
1290
+ return _context15.stop();
1291
+ }
1292
+ }, _callee15);
1177
1293
  })));
1178
1294
  /**
1179
1295
  * Returns a new path to the file that can be used by chromium in acceptance tests
@@ -1249,44 +1365,44 @@ var waitForElementToBeRemoved = function waitForElementToBeRemoved(element, time
1249
1365
  }
1250
1366
  var startStack = new Error().stack;
1251
1367
  var wait = /*#__PURE__*/function () {
1252
- var _ref25 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee15() {
1368
+ var _ref26 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee16() {
1253
1369
  var t0, box;
1254
- return _regeneratorRuntime().wrap(function _callee15$(_context15) {
1255
- while (1) switch (_context15.prev = _context15.next) {
1370
+ return _regeneratorRuntime().wrap(function _callee16$(_context16) {
1371
+ while (1) switch (_context16.prev = _context16.next) {
1256
1372
  case 0:
1257
1373
  t0 = Date.now();
1258
1374
  case 1:
1259
1375
  if (!(Date.now() - t0 < timeout)) {
1260
- _context15.next = 11;
1376
+ _context16.next = 11;
1261
1377
  break;
1262
1378
  }
1263
- _context15.next = 4;
1379
+ _context16.next = 4;
1264
1380
  return element.boundingBox();
1265
1381
  case 4:
1266
- box = _context15.sent;
1382
+ box = _context16.sent;
1267
1383
  if (box) {
1268
- _context15.next = 7;
1384
+ _context16.next = 7;
1269
1385
  break;
1270
1386
  }
1271
- return _context15.abrupt("return");
1387
+ return _context16.abrupt("return");
1272
1388
  case 7:
1273
- _context15.next = 9;
1389
+ _context16.next = 9;
1274
1390
  return new Promise(function (resolve) {
1275
1391
  return setTimeout(resolve, interval);
1276
1392
  });
1277
1393
  case 9:
1278
- _context15.next = 1;
1394
+ _context16.next = 1;
1279
1395
  break;
1280
1396
  case 11:
1281
1397
  throw new Error('Element not removed');
1282
1398
  case 12:
1283
1399
  case "end":
1284
- return _context15.stop();
1400
+ return _context16.stop();
1285
1401
  }
1286
- }, _callee15);
1402
+ }, _callee16);
1287
1403
  }));
1288
1404
  return function wait() {
1289
- return _ref25.apply(this, arguments);
1405
+ return _ref26.apply(this, arguments);
1290
1406
  };
1291
1407
  }();
1292
1408
  return wait()["catch"](function (error) {