@telefonica/acceptance-testing 2.9.1 → 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 {
@@ -1115,14 +1116,88 @@ var getPageApi = function getPageApi(page) {
1115
1116
 
1116
1117
  return api;
1117
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
+ };
1118
1193
  var openPage = /*#__PURE__*/function () {
1119
- var _ref12 = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee7(_ref11) {
1194
+ var _ref15 = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee7(_ref14) {
1120
1195
  var userAgent, isDarkMode, viewport, cookies, urlConfig, url, currentUserAgent, page, connectionError;
1121
1196
  return runtime_1.wrap(function _callee7$(_context7) {
1122
1197
  while (1) {
1123
1198
  switch (_context7.prev = _context7.next) {
1124
1199
  case 0:
1125
- 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);
1126
1201
 
1127
1202
  url = function () {
1128
1203
  if (urlConfig.url !== undefined) {
@@ -1206,20 +1281,32 @@ var openPage = /*#__PURE__*/function () {
1206
1281
  });
1207
1282
 
1208
1283
  case 23:
1209
- _context7.prev = 23;
1284
+ if (!needsRequestInterception) {
1285
+ _context7.next = 27;
1286
+ break;
1287
+ }
1288
+
1210
1289
  _context7.next = 26;
1211
- return page["goto"](url);
1290
+ return page.setRequestInterception(true);
1212
1291
 
1213
1292
  case 26:
1214
- _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;
1215
1302
  break;
1216
1303
 
1217
- case 28:
1218
- _context7.prev = 28;
1219
- _context7.t1 = _context7["catch"](23);
1304
+ case 32:
1305
+ _context7.prev = 32;
1306
+ _context7.t1 = _context7["catch"](27);
1220
1307
 
1221
1308
  if (!_context7.t1.message.includes('net::ERR_CONNECTION_REFUSED')) {
1222
- _context7.next = 36;
1309
+ _context7.next = 40;
1223
1310
  break;
1224
1311
  }
1225
1312
 
@@ -1227,33 +1314,33 @@ var openPage = /*#__PURE__*/function () {
1227
1314
  Error.captureStackTrace(connectionError, openPage);
1228
1315
  throw connectionError;
1229
1316
 
1230
- case 36:
1317
+ case 40:
1231
1318
  throw _context7.t1;
1232
1319
 
1233
- case 37:
1234
- _context7.next = 39;
1320
+ case 41:
1321
+ _context7.next = 43;
1235
1322
  return page.waitForFunction('document.fonts.status === "loaded"');
1236
1323
 
1237
- case 39:
1324
+ case 43:
1238
1325
  return _context7.abrupt("return", getPageApi(page));
1239
1326
 
1240
- case 40:
1327
+ case 44:
1241
1328
  case "end":
1242
1329
  return _context7.stop();
1243
1330
  }
1244
1331
  }
1245
- }, _callee7, null, [[23, 28]]);
1332
+ }, _callee7, null, [[27, 32]]);
1246
1333
  }));
1247
1334
 
1248
1335
  return function openPage(_x11) {
1249
- return _ref12.apply(this, arguments);
1336
+ return _ref15.apply(this, arguments);
1250
1337
  };
1251
1338
  }();
1252
1339
 
1253
1340
  var buildQueryMethods = function buildQueryMethods(_temp3) {
1254
- var _ref13 = _temp3 === void 0 ? {} : _temp3,
1255
- page = _ref13.page,
1256
- element = _ref13.element;
1341
+ var _ref16 = _temp3 === void 0 ? {} : _temp3,
1342
+ page = _ref16.page,
1343
+ element = _ref16.element;
1257
1344
 
1258
1345
  var boundQueries = {};
1259
1346
 
@@ -1311,7 +1398,7 @@ var buildQueryMethods = function buildQueryMethods(_temp3) {
1311
1398
  newElementHandle = Object.create(elementHandle);
1312
1399
 
1313
1400
  newElementHandle.screenshot = /*#__PURE__*/function () {
1314
- var _ref15 = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee8(options) {
1401
+ var _ref18 = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee8(options) {
1315
1402
  return runtime_1.wrap(function _callee8$(_context8) {
1316
1403
  while (1) {
1317
1404
  switch (_context8.prev = _context8.next) {
@@ -1342,7 +1429,7 @@ var buildQueryMethods = function buildQueryMethods(_temp3) {
1342
1429
  }));
1343
1430
 
1344
1431
  return function (_x12) {
1345
- return _ref15.apply(this, arguments);
1432
+ return _ref18.apply(this, arguments);
1346
1433
  };
1347
1434
  }();
1348
1435
 
@@ -1381,9 +1468,13 @@ beforeEach( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function
1381
1468
  switch (_context10.prev = _context10.next) {
1382
1469
  case 0:
1383
1470
  _context10.next = 2;
1384
- return global.jestPuppeteer.resetPage();
1471
+ return getGlobalPage().setRequestInterception(false);
1385
1472
 
1386
1473
  case 2:
1474
+ _context10.next = 4;
1475
+ return global.jestPuppeteer.resetPage();
1476
+
1477
+ case 4:
1387
1478
  case "end":
1388
1479
  return _context10.stop();
1389
1480
  }
@@ -1391,34 +1482,42 @@ beforeEach( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function
1391
1482
  }, _callee10);
1392
1483
  })));
1393
1484
  afterEach( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee11() {
1485
+ var page;
1394
1486
  return runtime_1.wrap(function _callee11$(_context11) {
1395
1487
  while (1) {
1396
1488
  switch (_context11.prev = _context11.next) {
1397
1489
  case 0:
1398
1490
  _context11.prev = 0;
1399
- _context11.next = 3;
1400
- 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
1401
1495
 
1402
- case 3:
1403
1496
  _context11.next = 7;
1497
+ return page["goto"]('about:blank');
1498
+
1499
+ case 7:
1500
+ _context11.next = 11;
1404
1501
  break;
1405
1502
 
1406
- case 5:
1407
- _context11.prev = 5;
1503
+ case 9:
1504
+ _context11.prev = 9;
1408
1505
  _context11.t0 = _context11["catch"](0);
1409
1506
 
1410
- case 7:
1507
+ case 11:
1411
1508
  case "end":
1412
1509
  return _context11.stop();
1413
1510
  }
1414
1511
  }
1415
- }, _callee11, null, [[0, 5]]);
1512
+ }, _callee11, null, [[0, 9]]);
1416
1513
  })));
1417
1514
 
1515
+ exports.createApiEndpointMock = createApiEndpointMock;
1418
1516
  exports.getGlobalBrowser = getGlobalBrowser;
1419
1517
  exports.getGlobalPage = getGlobalPage;
1420
1518
  exports.getPageApi = getPageApi;
1421
1519
  exports.getScreen = getScreen;
1520
+ exports.interceptRequest = interceptRequest;
1422
1521
  exports.openPage = openPage;
1423
1522
  exports.screen = screen;
1424
1523
  exports.serverHostName = serverHostName;