@telefonica/acceptance-testing 2.8.0 → 2.10.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.
package/README.md CHANGED
@@ -106,3 +106,52 @@ you need a different jest config file name you can manually setup some scripts i
106
106
 
107
107
  Just take into account that the `jest-environment-puppeteer` must always be configured in your jest config
108
108
  file. Also note that tests run in UI mode by default, unless you set the `HEADLESS=1` env var.
109
+
110
+ ## Intercepting requests
111
+
112
+ If you can intercept and mock requests in your acceptance tests you can use the `interceptRequest` function:
113
+
114
+ ```ts
115
+ import {openPage, screen, interceptRequest} from '@telefonica/acceptance-testing';
116
+
117
+ test('example screenshot test', async () => {
118
+ const imageSpy = interceptRequest((req) => req.url().endsWith('.jpg'));
119
+
120
+ imageSpy.mockReturnValue({
121
+ status: 200,
122
+ contentType: 'image/jpeg',
123
+ body: myMockedJpeg,
124
+ });
125
+
126
+ const page = await openPage({path: '/foo'});
127
+
128
+ expect(imageSpy).toHaveBeenCalled();
129
+ });
130
+ ```
131
+
132
+ To mock JSON api endpoints you can use `interceptRequest` too, but we also provide a more conveninent api
133
+ wrapper over `interceptRequest`: `createApiEndpointMock`
134
+
135
+ ```ts
136
+ import {openPage, screen, createApiEndpointMock} from '@telefonica/acceptance-testing';
137
+
138
+ test('example screenshot test', async () => {
139
+ const api = createApiEndpointMock({basePath: 'https://my-api-endpoint.com'});
140
+
141
+ const getSpy = api.spyOn('/some-path').mockReturnValue({a: 1, b: 2});
142
+ const postSpy = api.spyOn('/other-path', 'POST').mockReturnValue({c: 3});
143
+
144
+ const page = await openPage({path: '/foo'});
145
+
146
+ expect(getSpy).toHaveBeenCalled();
147
+
148
+ await page.click(await screen.findByRole('button', {name: 'Send'}));
149
+
150
+ expect(postSpy).toHaveBeenCalled();
151
+ });
152
+ ```
153
+
154
+ `createApiEndpointMock` automatically mocks CORS response headers and preflight (`OPTIONS`) requests for you.
155
+
156
+ You can also use globs for paths if you need: `api.spyOn('/some/*/path')`. We use the
157
+ [`glob-to-regexp`](https://www.npmjs.com/package/glob-to-regexp) lib internally.
@@ -9,6 +9,7 @@ var fs = _interopDefault(require('fs'));
9
9
  var findRoot = _interopDefault(require('find-root'));
10
10
  var pptrTestingLibrary = require('pptr-testing-library');
11
11
  var jestImageSnapshot = require('jest-image-snapshot');
12
+ var globToRegExp = _interopDefault(require('glob-to-regexp'));
12
13
 
13
14
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
14
15
  try {
@@ -1044,17 +1045,22 @@ var getPageApi = function getPageApi(page) {
1044
1045
  while (1) {
1045
1046
  switch (_context5.prev = _context5.next) {
1046
1047
  case 0:
1047
- _context5.next = 2;
1048
+ if (options != null && options.skipNetworkWait) {
1049
+ _context5.next = 3;
1050
+ break;
1051
+ }
1052
+
1053
+ _context5.next = 3;
1048
1054
  return page.waitForNetworkIdle();
1049
1055
 
1050
- case 2:
1051
- _context5.next = 4;
1056
+ case 3:
1057
+ _context5.next = 5;
1052
1058
  return waitForPaintEnd(page, options);
1053
1059
 
1054
- case 4:
1060
+ case 5:
1055
1061
  return _context5.abrupt("return", page.screenshot(normalizeSreenshotOptions(options)));
1056
1062
 
1057
- case 5:
1063
+ case 6:
1058
1064
  case "end":
1059
1065
  return _context5.stop();
1060
1066
  }
@@ -1110,14 +1116,88 @@ var getPageApi = function getPageApi(page) {
1110
1116
 
1111
1117
  return api;
1112
1118
  };
1119
+ var needsRequestInterception = false;
1120
+ var requestHandlers = [];
1121
+
1122
+ var requestInterceptor = function requestInterceptor(req) {
1123
+ var _requestHandlers$find;
1124
+
1125
+ var _ref11 = (_requestHandlers$find = requestHandlers.find(function (_ref12) {
1126
+ var matcher = _ref12.matcher;
1127
+ return matcher(req);
1128
+ })) != null ? _requestHandlers$find : {
1129
+ handler: null
1130
+ },
1131
+ handler = _ref11.handler;
1132
+
1133
+ if (!handler) {
1134
+ req["continue"]();
1135
+ return;
1136
+ }
1137
+
1138
+ var response = handler(req);
1139
+ req.respond(response);
1140
+ };
1141
+
1142
+ var interceptRequest = function interceptRequest(matcher) {
1143
+ needsRequestInterception = true;
1144
+ var spy = jest.fn();
1145
+ requestHandlers.push({
1146
+ matcher: matcher,
1147
+ handler: spy
1148
+ });
1149
+ return spy;
1150
+ };
1151
+ var createApiEndpointMock = function createApiEndpointMock(_ref13) {
1152
+ var baseUrl = _ref13.baseUrl;
1153
+ interceptRequest(function (req) {
1154
+ return req.method() === 'OPTIONS' && req.url().startsWith(baseUrl);
1155
+ }).mockImplementation(function () {
1156
+ return {
1157
+ status: 204,
1158
+ headers: {
1159
+ 'Access-Control-Allow-Origin': '*',
1160
+ 'Access-Control-Allow-Methods': 'POST,PATCH,PUT,GET,OPTIONS',
1161
+ 'Access-Control-Allow-Headers': 'Content-Type,Authorization'
1162
+ }
1163
+ };
1164
+ });
1165
+ return {
1166
+ spyOn: function spyOn(path, method) {
1167
+ if (method === void 0) {
1168
+ method = 'GET';
1169
+ }
1170
+
1171
+ var matcher = function matcher(req) {
1172
+ var url = req.url();
1173
+ var urlPath = url.substring(baseUrl.length);
1174
+ return req.method() === method && url.startsWith(baseUrl) && !!urlPath.match(globToRegExp(path));
1175
+ };
1176
+
1177
+ var spy = jest.fn();
1178
+ interceptRequest(matcher).mockImplementation(function (req) {
1179
+ var resBody = spy(req);
1180
+ return {
1181
+ status: 200,
1182
+ headers: {
1183
+ 'Access-Control-Allow-Origin': '*'
1184
+ },
1185
+ contentType: 'application/json',
1186
+ body: JSON.stringify(resBody)
1187
+ };
1188
+ });
1189
+ return spy;
1190
+ }
1191
+ };
1192
+ };
1113
1193
  var openPage = /*#__PURE__*/function () {
1114
- var _ref12 = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee7(_ref11) {
1194
+ var _ref15 = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee7(_ref14) {
1115
1195
  var userAgent, isDarkMode, viewport, cookies, urlConfig, url, currentUserAgent, page, connectionError;
1116
1196
  return runtime_1.wrap(function _callee7$(_context7) {
1117
1197
  while (1) {
1118
1198
  switch (_context7.prev = _context7.next) {
1119
1199
  case 0:
1120
- userAgent = _ref11.userAgent, isDarkMode = _ref11.isDarkMode, viewport = _ref11.viewport, cookies = _ref11.cookies, urlConfig = /*#__PURE__*/_objectWithoutPropertiesLoose(_ref11, _excluded2);
1200
+ userAgent = _ref14.userAgent, isDarkMode = _ref14.isDarkMode, viewport = _ref14.viewport, cookies = _ref14.cookies, urlConfig = /*#__PURE__*/_objectWithoutPropertiesLoose(_ref14, _excluded2);
1121
1201
 
1122
1202
  url = function () {
1123
1203
  if (urlConfig.url !== undefined) {
@@ -1201,20 +1281,32 @@ var openPage = /*#__PURE__*/function () {
1201
1281
  });
1202
1282
 
1203
1283
  case 23:
1204
- _context7.prev = 23;
1284
+ if (!needsRequestInterception) {
1285
+ _context7.next = 27;
1286
+ break;
1287
+ }
1288
+
1205
1289
  _context7.next = 26;
1206
- return page["goto"](url);
1290
+ return page.setRequestInterception(true);
1207
1291
 
1208
1292
  case 26:
1209
- _context7.next = 37;
1293
+ page.on('request', requestInterceptor);
1294
+
1295
+ case 27:
1296
+ _context7.prev = 27;
1297
+ _context7.next = 30;
1298
+ return page["goto"](url);
1299
+
1300
+ case 30:
1301
+ _context7.next = 41;
1210
1302
  break;
1211
1303
 
1212
- case 28:
1213
- _context7.prev = 28;
1214
- _context7.t1 = _context7["catch"](23);
1304
+ case 32:
1305
+ _context7.prev = 32;
1306
+ _context7.t1 = _context7["catch"](27);
1215
1307
 
1216
1308
  if (!_context7.t1.message.includes('net::ERR_CONNECTION_REFUSED')) {
1217
- _context7.next = 36;
1309
+ _context7.next = 40;
1218
1310
  break;
1219
1311
  }
1220
1312
 
@@ -1222,33 +1314,33 @@ var openPage = /*#__PURE__*/function () {
1222
1314
  Error.captureStackTrace(connectionError, openPage);
1223
1315
  throw connectionError;
1224
1316
 
1225
- case 36:
1317
+ case 40:
1226
1318
  throw _context7.t1;
1227
1319
 
1228
- case 37:
1229
- _context7.next = 39;
1320
+ case 41:
1321
+ _context7.next = 43;
1230
1322
  return page.waitForFunction('document.fonts.status === "loaded"');
1231
1323
 
1232
- case 39:
1324
+ case 43:
1233
1325
  return _context7.abrupt("return", getPageApi(page));
1234
1326
 
1235
- case 40:
1327
+ case 44:
1236
1328
  case "end":
1237
1329
  return _context7.stop();
1238
1330
  }
1239
1331
  }
1240
- }, _callee7, null, [[23, 28]]);
1332
+ }, _callee7, null, [[27, 32]]);
1241
1333
  }));
1242
1334
 
1243
1335
  return function openPage(_x11) {
1244
- return _ref12.apply(this, arguments);
1336
+ return _ref15.apply(this, arguments);
1245
1337
  };
1246
1338
  }();
1247
1339
 
1248
1340
  var buildQueryMethods = function buildQueryMethods(_temp3) {
1249
- var _ref13 = _temp3 === void 0 ? {} : _temp3,
1250
- page = _ref13.page,
1251
- element = _ref13.element;
1341
+ var _ref16 = _temp3 === void 0 ? {} : _temp3,
1342
+ page = _ref16.page,
1343
+ element = _ref16.element;
1252
1344
 
1253
1345
  var boundQueries = {};
1254
1346
 
@@ -1306,24 +1398,29 @@ var buildQueryMethods = function buildQueryMethods(_temp3) {
1306
1398
  newElementHandle = Object.create(elementHandle);
1307
1399
 
1308
1400
  newElementHandle.screenshot = /*#__PURE__*/function () {
1309
- var _ref15 = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee8(options) {
1401
+ var _ref18 = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee8(options) {
1310
1402
  return runtime_1.wrap(function _callee8$(_context8) {
1311
1403
  while (1) {
1312
1404
  switch (_context8.prev = _context8.next) {
1313
1405
  case 0:
1314
- _context8.next = 2;
1406
+ if (options != null && options.skipNetworkWait) {
1407
+ _context8.next = 3;
1408
+ break;
1409
+ }
1410
+
1411
+ _context8.next = 3;
1315
1412
  return (page != null ? page : getGlobalPage()).waitForNetworkIdle();
1316
1413
 
1317
- case 2:
1318
- _context8.next = 4;
1414
+ case 3:
1415
+ _context8.next = 5;
1319
1416
  return waitForPaintEnd(elementHandle, _extends({}, options, {
1320
1417
  fullPage: false
1321
1418
  }));
1322
1419
 
1323
- case 4:
1420
+ case 5:
1324
1421
  return _context8.abrupt("return", elementHandle.screenshot(normalizeSreenshotOptions(options)));
1325
1422
 
1326
- case 5:
1423
+ case 6:
1327
1424
  case "end":
1328
1425
  return _context8.stop();
1329
1426
  }
@@ -1332,7 +1429,7 @@ var buildQueryMethods = function buildQueryMethods(_temp3) {
1332
1429
  }));
1333
1430
 
1334
1431
  return function (_x12) {
1335
- return _ref15.apply(this, arguments);
1432
+ return _ref18.apply(this, arguments);
1336
1433
  };
1337
1434
  }();
1338
1435
 
@@ -1371,9 +1468,13 @@ beforeEach( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function
1371
1468
  switch (_context10.prev = _context10.next) {
1372
1469
  case 0:
1373
1470
  _context10.next = 2;
1374
- return global.jestPuppeteer.resetPage();
1471
+ return getGlobalPage().setRequestInterception(false);
1375
1472
 
1376
1473
  case 2:
1474
+ _context10.next = 4;
1475
+ return global.jestPuppeteer.resetPage();
1476
+
1477
+ case 4:
1377
1478
  case "end":
1378
1479
  return _context10.stop();
1379
1480
  }
@@ -1381,34 +1482,42 @@ beforeEach( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function
1381
1482
  }, _callee10);
1382
1483
  })));
1383
1484
  afterEach( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee11() {
1485
+ var page;
1384
1486
  return runtime_1.wrap(function _callee11$(_context11) {
1385
1487
  while (1) {
1386
1488
  switch (_context11.prev = _context11.next) {
1387
1489
  case 0:
1388
1490
  _context11.prev = 0;
1389
- _context11.next = 3;
1390
- return getGlobalPage()["goto"]('about:blank');
1491
+ page = getGlobalPage();
1492
+ requestHandlers = [];
1493
+ needsRequestInterception = false;
1494
+ page.off('request', requestInterceptor); // clear tab, this way we clear the DOM and stop js execution or pending requests
1391
1495
 
1392
- case 3:
1393
1496
  _context11.next = 7;
1497
+ return page["goto"]('about:blank');
1498
+
1499
+ case 7:
1500
+ _context11.next = 11;
1394
1501
  break;
1395
1502
 
1396
- case 5:
1397
- _context11.prev = 5;
1503
+ case 9:
1504
+ _context11.prev = 9;
1398
1505
  _context11.t0 = _context11["catch"](0);
1399
1506
 
1400
- case 7:
1507
+ case 11:
1401
1508
  case "end":
1402
1509
  return _context11.stop();
1403
1510
  }
1404
1511
  }
1405
- }, _callee11, null, [[0, 5]]);
1512
+ }, _callee11, null, [[0, 9]]);
1406
1513
  })));
1407
1514
 
1515
+ exports.createApiEndpointMock = createApiEndpointMock;
1408
1516
  exports.getGlobalBrowser = getGlobalBrowser;
1409
1517
  exports.getGlobalPage = getGlobalPage;
1410
1518
  exports.getPageApi = getPageApi;
1411
1519
  exports.getScreen = getScreen;
1520
+ exports.interceptRequest = interceptRequest;
1412
1521
  exports.openPage = openPage;
1413
1522
  exports.screen = screen;
1414
1523
  exports.serverHostName = serverHostName;