codeceptjs 3.2.3 → 3.3.0-beta.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/CHANGELOG.md +50 -0
- package/docs/advanced.md +0 -4
- package/docs/api.md +227 -188
- package/docs/build/ApiDataFactory.js +13 -6
- package/docs/build/Appium.js +36 -36
- package/docs/build/GraphQL.js +11 -0
- package/docs/build/JSONResponse.js +297 -0
- package/docs/build/Nightmare.js +48 -48
- package/docs/build/Playwright.js +261 -146
- package/docs/build/Puppeteer.js +76 -67
- package/docs/build/REST.js +36 -0
- package/docs/build/TestCafe.js +44 -44
- package/docs/build/WebDriver.js +69 -69
- package/docs/helpers/ApiDataFactory.md +7 -0
- package/docs/helpers/Appium.md +3 -3
- package/docs/helpers/JSONResponse.md +230 -0
- package/docs/helpers/Playwright.md +282 -218
- package/docs/helpers/Puppeteer.md +9 -1
- package/docs/helpers/REST.md +30 -9
- package/docs/installation.md +2 -0
- package/docs/internal-api.md +265 -0
- package/docs/playwright.md +70 -15
- package/docs/plugins.md +125 -29
- package/docs/puppeteer.md +24 -8
- package/docs/quickstart.md +2 -3
- package/docs/reports.md +43 -2
- package/docs/translation.md +1 -1
- package/docs/videos.md +2 -2
- package/docs/webdriver.md +90 -2
- package/lib/command/init.js +5 -15
- package/lib/config.js +17 -13
- package/lib/helper/ApiDataFactory.js +13 -6
- package/lib/helper/Appium.js +3 -3
- package/lib/helper/GraphQL.js +11 -0
- package/lib/helper/JSONResponse.js +297 -0
- package/lib/helper/Playwright.js +199 -84
- package/lib/helper/Puppeteer.js +12 -3
- package/lib/helper/REST.js +36 -0
- package/lib/helper/extras/Console.js +8 -0
- package/lib/helper/extras/PlaywrightRestartOpts.js +35 -0
- package/lib/interfaces/bdd.js +3 -1
- package/lib/plugin/allure.js +12 -0
- package/lib/plugin/eachElement.js +127 -0
- package/lib/utils.js +20 -0
- package/package.json +6 -4
- package/translations/pt-BR.js +8 -0
- package/typings/index.d.ts +2 -0
- package/typings/types.d.ts +237 -11
package/docs/build/Appium.js
CHANGED
|
@@ -955,7 +955,7 @@ class Appium extends Webdriver {
|
|
|
955
955
|
*
|
|
956
956
|
* [See complete reference](http://webdriver.io/api/mobile/swipe.html)
|
|
957
957
|
*
|
|
958
|
-
* @param {
|
|
958
|
+
* @param {string | object} locator
|
|
959
959
|
* @param {number} xoffset
|
|
960
960
|
* @param {number} yoffset
|
|
961
961
|
* @param {number} [speed=1000] (optional), 1000 by default
|
|
@@ -976,11 +976,11 @@ class Appium extends Webdriver {
|
|
|
976
976
|
* Perform a swipe on the screen.
|
|
977
977
|
*
|
|
978
978
|
* ```js
|
|
979
|
-
* I.
|
|
979
|
+
* I.performSwipe({ x: 300, y: 100 }, { x: 200, y: 100 });
|
|
980
980
|
* ```
|
|
981
981
|
*
|
|
982
|
-
* @param {
|
|
983
|
-
* @param {
|
|
982
|
+
* @param {object} from
|
|
983
|
+
* @param {object} to
|
|
984
984
|
*
|
|
985
985
|
* Appium: support Android and iOS
|
|
986
986
|
*/
|
|
@@ -1010,7 +1010,7 @@ class Appium extends Webdriver {
|
|
|
1010
1010
|
* I.swipeDown(locator, 1200, 1000); // set offset and speed
|
|
1011
1011
|
* ```
|
|
1012
1012
|
*
|
|
1013
|
-
* @param {
|
|
1013
|
+
* @param {string | object} locator
|
|
1014
1014
|
* @param {number} [yoffset] (optional)
|
|
1015
1015
|
* @param {number} [speed=1000] (optional), 1000 by default
|
|
1016
1016
|
* @return {Promise<void>}
|
|
@@ -1039,7 +1039,7 @@ class Appium extends Webdriver {
|
|
|
1039
1039
|
* I.swipeLeft(locator, 1200, 1000); // set offset and speed
|
|
1040
1040
|
* ```
|
|
1041
1041
|
*
|
|
1042
|
-
* @param {
|
|
1042
|
+
* @param {string | object} locator
|
|
1043
1043
|
* @param {number} [xoffset] (optional)
|
|
1044
1044
|
* @param {number} [speed=1000] (optional), 1000 by default
|
|
1045
1045
|
* @return {Promise<void>}
|
|
@@ -1066,7 +1066,7 @@ class Appium extends Webdriver {
|
|
|
1066
1066
|
* I.swipeRight(locator, 1200, 1000); // set offset and speed
|
|
1067
1067
|
* ```
|
|
1068
1068
|
*
|
|
1069
|
-
* @param {
|
|
1069
|
+
* @param {string | object} locator
|
|
1070
1070
|
* @param {number} [xoffset] (optional)
|
|
1071
1071
|
* @param {number} [speed=1000] (optional), 1000 by default
|
|
1072
1072
|
* @return {Promise<void>}
|
|
@@ -1093,7 +1093,7 @@ class Appium extends Webdriver {
|
|
|
1093
1093
|
* I.swipeUp(locator, 1200, 1000); // set offset and speed
|
|
1094
1094
|
* ```
|
|
1095
1095
|
*
|
|
1096
|
-
* @param {
|
|
1096
|
+
* @param {string | object} locator
|
|
1097
1097
|
* @param {number} [yoffset] (optional)
|
|
1098
1098
|
* @param {number} [speed=1000] (optional), 1000 by default
|
|
1099
1099
|
* @return {Promise<void>}
|
|
@@ -1335,7 +1335,7 @@ class Appium extends Webdriver {
|
|
|
1335
1335
|
* ```js
|
|
1336
1336
|
* I.appendField('#myTextField', 'appended');
|
|
1337
1337
|
* ```
|
|
1338
|
-
* @param {
|
|
1338
|
+
* @param {string | object} field located by label|name|CSS|XPath|strict locator
|
|
1339
1339
|
* @param {string} value text value to append.
|
|
1340
1340
|
*
|
|
1341
1341
|
*/
|
|
@@ -1355,8 +1355,8 @@ class Appium extends Webdriver {
|
|
|
1355
1355
|
* I.checkOption('I Agree to Terms and Conditions');
|
|
1356
1356
|
* I.checkOption('agree', '//form');
|
|
1357
1357
|
* ```
|
|
1358
|
-
* @param {
|
|
1359
|
-
* @param {?
|
|
1358
|
+
* @param {string | object} field checkbox located by label | name | CSS | XPath | strict locator.
|
|
1359
|
+
* @param {?string | object} [context=null] (optional, `null` by default) element located by CSS | XPath | strict locator.
|
|
1360
1360
|
*
|
|
1361
1361
|
*/
|
|
1362
1362
|
async checkOption(field) {
|
|
@@ -1387,8 +1387,8 @@ class Appium extends Webdriver {
|
|
|
1387
1387
|
* I.click({css: 'nav a.login'});
|
|
1388
1388
|
* ```
|
|
1389
1389
|
*
|
|
1390
|
-
* @param {
|
|
1391
|
-
* @param {?
|
|
1390
|
+
* @param {string | object} locator clickable link or button located by text, or any element located by CSS|XPath|strict locator.
|
|
1391
|
+
* @param {?string | object} [context=null] (optional, `null` by default) element to search in CSS|XPath|Strict locator.
|
|
1392
1392
|
*
|
|
1393
1393
|
*
|
|
1394
1394
|
*/
|
|
@@ -1406,7 +1406,7 @@ class Appium extends Webdriver {
|
|
|
1406
1406
|
* I.dontSeeCheckboxIsChecked('agree'); // located by name
|
|
1407
1407
|
* ```
|
|
1408
1408
|
*
|
|
1409
|
-
* @param {
|
|
1409
|
+
* @param {string | object} field located by label|name|CSS|XPath|strict locator.
|
|
1410
1410
|
*
|
|
1411
1411
|
*
|
|
1412
1412
|
*/
|
|
@@ -1422,7 +1422,7 @@ class Appium extends Webdriver {
|
|
|
1422
1422
|
* I.dontSeeElement('.modal'); // modal is not shown
|
|
1423
1423
|
* ```
|
|
1424
1424
|
*
|
|
1425
|
-
* @param {
|
|
1425
|
+
* @param {string | object} locator located by CSS|XPath|Strict locator.
|
|
1426
1426
|
*/
|
|
1427
1427
|
async dontSeeElement(locator) {
|
|
1428
1428
|
if (this.isWeb) return super.dontSeeElement(locator);
|
|
@@ -1438,7 +1438,7 @@ class Appium extends Webdriver {
|
|
|
1438
1438
|
* I.dontSeeInField({ css: 'form input.email' }, 'user@user.com'); // field by CSS
|
|
1439
1439
|
* ```
|
|
1440
1440
|
*
|
|
1441
|
-
* @param {
|
|
1441
|
+
* @param {string | object} field located by label|name|CSS|XPath|strict locator.
|
|
1442
1442
|
* @param {string} value value to check.
|
|
1443
1443
|
*
|
|
1444
1444
|
*/
|
|
@@ -1457,7 +1457,7 @@ class Appium extends Webdriver {
|
|
|
1457
1457
|
* ```
|
|
1458
1458
|
*
|
|
1459
1459
|
* @param {string} text which is not present.
|
|
1460
|
-
* @param {
|
|
1460
|
+
* @param {string | object} [context] (optional) element located by CSS|XPath|strict locator in which to perfrom search.
|
|
1461
1461
|
*
|
|
1462
1462
|
*/
|
|
1463
1463
|
async dontSee(text, context = null) {
|
|
@@ -1479,8 +1479,8 @@ class Appium extends Webdriver {
|
|
|
1479
1479
|
* // or by strict locator
|
|
1480
1480
|
* I.fillField({css: 'form#login input[name=username]'}, 'John');
|
|
1481
1481
|
* ```
|
|
1482
|
-
* @param {
|
|
1483
|
-
* @param {
|
|
1482
|
+
* @param {string | object} field located by label|name|CSS|XPath|strict locator.
|
|
1483
|
+
* @param {string | object} value text value to fill.
|
|
1484
1484
|
*
|
|
1485
1485
|
*
|
|
1486
1486
|
*/
|
|
@@ -1498,7 +1498,7 @@ class Appium extends Webdriver {
|
|
|
1498
1498
|
* let pins = await I.grabTextFromAll('#pin li');
|
|
1499
1499
|
* ```
|
|
1500
1500
|
*
|
|
1501
|
-
* @param {
|
|
1501
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
1502
1502
|
* @returns {Promise<string[]>} attribute value
|
|
1503
1503
|
*
|
|
1504
1504
|
*
|
|
@@ -1517,7 +1517,7 @@ class Appium extends Webdriver {
|
|
|
1517
1517
|
* ```
|
|
1518
1518
|
* If multiple elements found returns first element.
|
|
1519
1519
|
*
|
|
1520
|
-
* @param {
|
|
1520
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
1521
1521
|
* @returns {Promise<string>} attribute value
|
|
1522
1522
|
*
|
|
1523
1523
|
*
|
|
@@ -1535,7 +1535,7 @@ class Appium extends Webdriver {
|
|
|
1535
1535
|
* let numOfElements = await I.grabNumberOfVisibleElements('p');
|
|
1536
1536
|
* ```
|
|
1537
1537
|
*
|
|
1538
|
-
* @param {
|
|
1538
|
+
* @param {string | object} locator located by CSS|XPath|strict locator.
|
|
1539
1539
|
* @returns {Promise<number>} number of visible elements
|
|
1540
1540
|
*/
|
|
1541
1541
|
async grabNumberOfVisibleElements(locator) {
|
|
@@ -1553,7 +1553,7 @@ class Appium extends Webdriver {
|
|
|
1553
1553
|
* ```js
|
|
1554
1554
|
* let hint = await I.grabAttributeFrom('#tooltip', 'title');
|
|
1555
1555
|
* ```
|
|
1556
|
-
* @param {
|
|
1556
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
1557
1557
|
* @param {string} attr attribute name.
|
|
1558
1558
|
* @returns {Promise<string>} attribute value
|
|
1559
1559
|
*
|
|
@@ -1571,7 +1571,7 @@ class Appium extends Webdriver {
|
|
|
1571
1571
|
* ```js
|
|
1572
1572
|
* let hints = await I.grabAttributeFromAll('.tooltip', 'title');
|
|
1573
1573
|
* ```
|
|
1574
|
-
* @param {
|
|
1574
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
1575
1575
|
* @param {string} attr attribute name.
|
|
1576
1576
|
* @returns {Promise<string[]>} attribute value
|
|
1577
1577
|
*
|
|
@@ -1588,7 +1588,7 @@ class Appium extends Webdriver {
|
|
|
1588
1588
|
* ```js
|
|
1589
1589
|
* let inputs = await I.grabValueFromAll('//form/input');
|
|
1590
1590
|
* ```
|
|
1591
|
-
* @param {
|
|
1591
|
+
* @param {string | object} locator field located by label|name|CSS|XPath|strict locator.
|
|
1592
1592
|
* @returns {Promise<string[]>} attribute value
|
|
1593
1593
|
*
|
|
1594
1594
|
*
|
|
@@ -1606,7 +1606,7 @@ class Appium extends Webdriver {
|
|
|
1606
1606
|
* ```js
|
|
1607
1607
|
* let email = await I.grabValueFrom('input[name=email]');
|
|
1608
1608
|
* ```
|
|
1609
|
-
* @param {
|
|
1609
|
+
* @param {string | object} locator field located by label|name|CSS|XPath|strict locator.
|
|
1610
1610
|
* @returns {Promise<string>} attribute value
|
|
1611
1611
|
*
|
|
1612
1612
|
*
|
|
@@ -1640,7 +1640,7 @@ class Appium extends Webdriver {
|
|
|
1640
1640
|
* I.scrollIntoView('#submit', { behavior: "smooth", block: "center", inline: "center" });
|
|
1641
1641
|
* ```
|
|
1642
1642
|
*
|
|
1643
|
-
* @param {
|
|
1643
|
+
* @param {string | object} locator located by CSS|XPath|strict locator.
|
|
1644
1644
|
* @param {ScrollIntoViewOptions} scrollIntoViewOptions see https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView.
|
|
1645
1645
|
*
|
|
1646
1646
|
*
|
|
@@ -1659,7 +1659,7 @@ class Appium extends Webdriver {
|
|
|
1659
1659
|
* I.seeCheckboxIsChecked({css: '#signup_form input[type=checkbox]'});
|
|
1660
1660
|
* ```
|
|
1661
1661
|
*
|
|
1662
|
-
* @param {
|
|
1662
|
+
* @param {string | object} field located by label|name|CSS|XPath|strict locator.
|
|
1663
1663
|
*
|
|
1664
1664
|
*
|
|
1665
1665
|
*/
|
|
@@ -1675,7 +1675,7 @@ class Appium extends Webdriver {
|
|
|
1675
1675
|
* ```js
|
|
1676
1676
|
* I.seeElement('#modal');
|
|
1677
1677
|
* ```
|
|
1678
|
-
* @param {
|
|
1678
|
+
* @param {string | object} locator located by CSS|XPath|strict locator.
|
|
1679
1679
|
*
|
|
1680
1680
|
*/
|
|
1681
1681
|
async seeElement(locator) {
|
|
@@ -1693,7 +1693,7 @@ class Appium extends Webdriver {
|
|
|
1693
1693
|
* I.seeInField('form input[type=hidden]','hidden_value');
|
|
1694
1694
|
* I.seeInField('#searchform input','Search');
|
|
1695
1695
|
* ```
|
|
1696
|
-
* @param {
|
|
1696
|
+
* @param {string | object} field located by label|name|CSS|XPath|strict locator.
|
|
1697
1697
|
* @param {string} value value to check.
|
|
1698
1698
|
*
|
|
1699
1699
|
*
|
|
@@ -1713,7 +1713,7 @@ class Appium extends Webdriver {
|
|
|
1713
1713
|
* I.see('Register', {css: 'form.register'}); // use strict locator
|
|
1714
1714
|
* ```
|
|
1715
1715
|
* @param {string} text expected on page.
|
|
1716
|
-
* @param {?
|
|
1716
|
+
* @param {?string | object} [context=null] (optional, `null` by default) element located by CSS|Xpath|strict locator in which to search for text.
|
|
1717
1717
|
*
|
|
1718
1718
|
*/
|
|
1719
1719
|
async see(text, context) {
|
|
@@ -1740,7 +1740,7 @@ class Appium extends Webdriver {
|
|
|
1740
1740
|
* ```js
|
|
1741
1741
|
* I.selectOption('Which OS do you use?', ['Android', 'iOS']);
|
|
1742
1742
|
* ```
|
|
1743
|
-
* @param {
|
|
1743
|
+
* @param {string | object} select field located by label|name|CSS|XPath|strict locator.
|
|
1744
1744
|
* @param {string|Array<*>} option visible text or value of option.
|
|
1745
1745
|
*
|
|
1746
1746
|
*
|
|
@@ -1760,7 +1760,7 @@ class Appium extends Webdriver {
|
|
|
1760
1760
|
* I.waitForElement('.btn.continue', 5); // wait for 5 secs
|
|
1761
1761
|
* ```
|
|
1762
1762
|
*
|
|
1763
|
-
* @param {
|
|
1763
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
1764
1764
|
* @param {number} [sec] (optional, `1` by default) time in seconds to wait
|
|
1765
1765
|
*
|
|
1766
1766
|
*/
|
|
@@ -1777,7 +1777,7 @@ class Appium extends Webdriver {
|
|
|
1777
1777
|
* I.waitForVisible('#popup');
|
|
1778
1778
|
* ```
|
|
1779
1779
|
*
|
|
1780
|
-
* @param {
|
|
1780
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
1781
1781
|
* @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
1782
1782
|
*
|
|
1783
1783
|
*
|
|
@@ -1795,7 +1795,7 @@ class Appium extends Webdriver {
|
|
|
1795
1795
|
* I.waitForInvisible('#popup');
|
|
1796
1796
|
* ```
|
|
1797
1797
|
*
|
|
1798
|
-
* @param {
|
|
1798
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
1799
1799
|
* @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
1800
1800
|
*
|
|
1801
1801
|
*/
|
|
@@ -1816,7 +1816,7 @@ class Appium extends Webdriver {
|
|
|
1816
1816
|
*
|
|
1817
1817
|
* @param {string }text to wait for.
|
|
1818
1818
|
* @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
1819
|
-
* @param {
|
|
1819
|
+
* @param {string | object} [context] (optional) element located by CSS|XPath|strict locator.
|
|
1820
1820
|
*
|
|
1821
1821
|
*/
|
|
1822
1822
|
async waitForText(text, sec = null, context = null) {
|
package/docs/build/GraphQL.js
CHANGED
|
@@ -59,6 +59,12 @@ class GraphQL extends Helper {
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
static _config() {
|
|
63
|
+
return [
|
|
64
|
+
{ name: 'endpoint', message: 'Endpoint of API you are going to test', default: 'http://localhost:3000/graphql' },
|
|
65
|
+
];
|
|
66
|
+
}
|
|
67
|
+
|
|
62
68
|
/**
|
|
63
69
|
* Executes query via axios call
|
|
64
70
|
*
|
|
@@ -92,6 +98,11 @@ class GraphQL extends Helper {
|
|
|
92
98
|
);
|
|
93
99
|
response = err.response;
|
|
94
100
|
}
|
|
101
|
+
|
|
102
|
+
if (this.config.onResponse) {
|
|
103
|
+
await this.config.onResponse(response);
|
|
104
|
+
}
|
|
105
|
+
|
|
95
106
|
this.debugSection('Response', JSON.stringify(response.data));
|
|
96
107
|
return response;
|
|
97
108
|
}
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
const chai = require('chai');
|
|
2
|
+
const joi = require('joi');
|
|
3
|
+
const chaiDeepMatch = require('chai-deep-match');
|
|
4
|
+
const Helper = require('../helper');
|
|
5
|
+
|
|
6
|
+
chai.use(chaiDeepMatch);
|
|
7
|
+
|
|
8
|
+
const { expect } = chai;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* This helper allows performing assertions on JSON responses paired with following helpers:
|
|
12
|
+
*
|
|
13
|
+
* * REST
|
|
14
|
+
* * GraphQL
|
|
15
|
+
* * Playwright
|
|
16
|
+
*
|
|
17
|
+
* It can check status codes, response data, response structure.
|
|
18
|
+
*
|
|
19
|
+
*
|
|
20
|
+
* ## Configuration
|
|
21
|
+
*
|
|
22
|
+
* * `requestHelper` - a helper which will perform requests. `REST` by default, also `Playwright` or `GraphQL` can be used. Custom helpers must have `onResponse` hook in their config, which will be executed when request is performed.
|
|
23
|
+
*
|
|
24
|
+
* ### Examples
|
|
25
|
+
*
|
|
26
|
+
* Zero-configuration when paired with REST:
|
|
27
|
+
*
|
|
28
|
+
* ```js
|
|
29
|
+
* // inside codecept.conf.js
|
|
30
|
+
*{
|
|
31
|
+
* helpers: {
|
|
32
|
+
* REST: {
|
|
33
|
+
* endpoint: 'http://site.com/api',
|
|
34
|
+
* },
|
|
35
|
+
* JSONResponse: {}
|
|
36
|
+
* }
|
|
37
|
+
*}
|
|
38
|
+
* ```
|
|
39
|
+
* Explicitly setting request helper if you use `makeApiRequest` of Playwright to perform requests and not paired REST:
|
|
40
|
+
*
|
|
41
|
+
* ```js
|
|
42
|
+
* // inside codecept.conf.js
|
|
43
|
+
* // ...
|
|
44
|
+
* helpers: {
|
|
45
|
+
* Playwright: {
|
|
46
|
+
* url: 'https://localhost',
|
|
47
|
+
* browser: 'chromium',
|
|
48
|
+
* },
|
|
49
|
+
* JSONResponse: {
|
|
50
|
+
* requestHelper: 'Playwright',
|
|
51
|
+
* }
|
|
52
|
+
* }
|
|
53
|
+
* ```
|
|
54
|
+
* ## Access From Helpers
|
|
55
|
+
*
|
|
56
|
+
* If you plan to add custom assertions it is recommended to create a helper that will retrieve response object from JSONResponse:
|
|
57
|
+
*
|
|
58
|
+
*
|
|
59
|
+
* ```js
|
|
60
|
+
* // inside custom helper
|
|
61
|
+
* const response = this.helpers.JSONResponse.response;
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* ## Methods
|
|
65
|
+
*/
|
|
66
|
+
class JSONResponse extends Helper {
|
|
67
|
+
constructor(config = {}) {
|
|
68
|
+
super(config);
|
|
69
|
+
this.options = {
|
|
70
|
+
requestHelper: 'REST',
|
|
71
|
+
};
|
|
72
|
+
this.options = { ...this.options, ...config };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
_beforeSuite() {
|
|
76
|
+
this.response = null;
|
|
77
|
+
if (!this.helpers[this.options.requestHelper]) {
|
|
78
|
+
throw new Error(`Error setting JSONResponse, helper ${this.options.requestHelper} is not enabled in config, helpers: ${Object.keys(this.helpers)}`);
|
|
79
|
+
}
|
|
80
|
+
// connect to REST helper
|
|
81
|
+
this.helpers[this.options.requestHelper].config.onResponse = (response) => {
|
|
82
|
+
this.response = response;
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
_before() {
|
|
87
|
+
this.response = null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
static _checkRequirements() {
|
|
91
|
+
try {
|
|
92
|
+
require('joi');
|
|
93
|
+
require('chai');
|
|
94
|
+
} catch (e) {
|
|
95
|
+
return ['joi'];
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Checks that response code is equal to the provided one
|
|
101
|
+
*
|
|
102
|
+
* ```js
|
|
103
|
+
* I.seeResponseCodeIs(200);
|
|
104
|
+
* ```
|
|
105
|
+
*
|
|
106
|
+
* @param {number} code
|
|
107
|
+
*/
|
|
108
|
+
seeResponseCodeIs(code) {
|
|
109
|
+
this._checkResponseReady();
|
|
110
|
+
expect(this.response.status).to.eql(code, 'Response code is not the same as expected');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Checks that response code is not equal to the provided one
|
|
115
|
+
*
|
|
116
|
+
* ```js
|
|
117
|
+
* I.dontSeeResponseCodeIs(500);
|
|
118
|
+
* ```
|
|
119
|
+
*
|
|
120
|
+
* @param {number} code
|
|
121
|
+
*/
|
|
122
|
+
dontSeeResponseCodeIs(code) {
|
|
123
|
+
this._checkResponseReady();
|
|
124
|
+
expect(this.response.status).not.to.eql(code);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Checks that the response code is 4xx
|
|
129
|
+
*/
|
|
130
|
+
seeResponseCodeIsClientError() {
|
|
131
|
+
this._checkResponseReady();
|
|
132
|
+
expect(this.response.status).to.be.gte(400);
|
|
133
|
+
expect(this.response.status).to.be.lt(500);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Checks that the response code is 3xx
|
|
138
|
+
*/
|
|
139
|
+
seeResponseCodeIsRedirection() {
|
|
140
|
+
this._checkResponseReady();
|
|
141
|
+
expect(this.response.status).to.be.gte(300);
|
|
142
|
+
expect(this.response.status).to.be.lt(400);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Checks that the response code is 5xx
|
|
147
|
+
*/
|
|
148
|
+
seeResponseCodeIsServerError() {
|
|
149
|
+
this._checkResponseReady();
|
|
150
|
+
expect(this.response.status).to.be.gte(500);
|
|
151
|
+
expect(this.response.status).to.be.lt(600);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Checks that the response code is 2xx
|
|
156
|
+
* Use it instead of seeResponseCodeIs(200) if server can return 204 instead.
|
|
157
|
+
*
|
|
158
|
+
* ```js
|
|
159
|
+
* I.seeResponseCodeIsSuccessful();
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
seeResponseCodeIsSuccessful() {
|
|
163
|
+
this._checkResponseReady();
|
|
164
|
+
expect(this.response.status).to.be.gte(200);
|
|
165
|
+
expect(this.response.status).to.be.lt(300);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Checks for deep inclusion of a provided json in a response data.
|
|
170
|
+
*
|
|
171
|
+
* ```js
|
|
172
|
+
* // response.data == { user: { name: 'jon', email: 'jon@doe.com' } }
|
|
173
|
+
*
|
|
174
|
+
* I.seeResponseContainsJson({ user: { email: 'jon@doe.com' } });
|
|
175
|
+
* ```
|
|
176
|
+
*
|
|
177
|
+
* @param {object} json
|
|
178
|
+
*/
|
|
179
|
+
seeResponseContainsJson(json = {}) {
|
|
180
|
+
this._checkResponseReady();
|
|
181
|
+
expect(this.response.data).to.deep.match(json);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Checks for deep inclusion of a provided json in a response data.
|
|
186
|
+
*
|
|
187
|
+
* ```js
|
|
188
|
+
* // response.data == { data: { user: 1 } }
|
|
189
|
+
*
|
|
190
|
+
* I.dontSeeResponseContainsJson({ user: 2 });
|
|
191
|
+
* ```
|
|
192
|
+
*
|
|
193
|
+
* @param {object} json
|
|
194
|
+
*/
|
|
195
|
+
dontSeeResponseContainsJson(json = {}) {
|
|
196
|
+
this._checkResponseReady();
|
|
197
|
+
expect(this.response.data).not.to.deep.match(json);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Checks for deep inclusion of a provided json in a response data.
|
|
202
|
+
*
|
|
203
|
+
* ```js
|
|
204
|
+
* // response.data == { user: { name: 'jon', email: 'jon@doe.com' } }
|
|
205
|
+
*
|
|
206
|
+
* I.seeResponseContainsKeys(['user']);
|
|
207
|
+
* ```
|
|
208
|
+
*
|
|
209
|
+
* @param {array} keys
|
|
210
|
+
*/
|
|
211
|
+
seeResponseContainsKeys(keys = []) {
|
|
212
|
+
this._checkResponseReady();
|
|
213
|
+
expect(this.response.data).to.include.keys(keys);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Executes a callback function passing in `response` object and chai assertions with `expect`
|
|
218
|
+
* Use it to perform custom checks of response data
|
|
219
|
+
*
|
|
220
|
+
* ```js
|
|
221
|
+
* I.seeResponseValidByCallback({ data, status, expect } => {
|
|
222
|
+
* expect(status).to.eql(200);
|
|
223
|
+
* expect(data).keys.to.include(['user', 'company']);
|
|
224
|
+
* });
|
|
225
|
+
* ```
|
|
226
|
+
*
|
|
227
|
+
* @param {function} fn
|
|
228
|
+
*/
|
|
229
|
+
seeResponseValidByCallback(fn) {
|
|
230
|
+
this._checkResponseReady();
|
|
231
|
+
fn({ ...this.response, expect });
|
|
232
|
+
const body = fn.toString();
|
|
233
|
+
fn.toString = () => `${body.split('\n')[1]}...`;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Checks that response data equals to expected:
|
|
238
|
+
*
|
|
239
|
+
* ```js
|
|
240
|
+
* // response.data is { error: 'Not allowed' }
|
|
241
|
+
*
|
|
242
|
+
* I.seeResponseEquals({ error: 'Not allowed' })
|
|
243
|
+
* ```
|
|
244
|
+
* @param {object} resp
|
|
245
|
+
*/
|
|
246
|
+
seeResponseEquals(resp) {
|
|
247
|
+
this._checkResponseReady();
|
|
248
|
+
expect(this.response.data).to.deep.equal(resp);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Validates JSON structure of response using [joi library](https://joi.dev).
|
|
253
|
+
* See [joi API](https://joi.dev/api/) for complete reference on usage.
|
|
254
|
+
*
|
|
255
|
+
* Use pre-initialized joi instance by passing function callback:
|
|
256
|
+
*
|
|
257
|
+
* ```js
|
|
258
|
+
* // response.data is { name: 'jon', id: 1 }
|
|
259
|
+
*
|
|
260
|
+
* I.seeResponseMatchesJsonSchema(joi => {
|
|
261
|
+
* return joi.object({
|
|
262
|
+
* name: joi.string();
|
|
263
|
+
* id: joi.number();
|
|
264
|
+
* })
|
|
265
|
+
* });
|
|
266
|
+
*
|
|
267
|
+
* // or pass a valid schema
|
|
268
|
+
* const joi = require('joi);
|
|
269
|
+
*
|
|
270
|
+
* I.seeResponseMatchesJsonSchema(joi.object({
|
|
271
|
+
* name: joi.string();
|
|
272
|
+
* id: joi.number();
|
|
273
|
+
* });
|
|
274
|
+
* ```
|
|
275
|
+
*
|
|
276
|
+
* @param {any} fnOrSchema
|
|
277
|
+
*/
|
|
278
|
+
seeResponseMatchesJsonSchema(fnOrSchema) {
|
|
279
|
+
this._checkResponseReady();
|
|
280
|
+
let schema = fnOrSchema;
|
|
281
|
+
if (typeof fnOrSchema === 'function') {
|
|
282
|
+
schema = fnOrSchema(joi);
|
|
283
|
+
const body = fnOrSchema.toString();
|
|
284
|
+
fnOrSchema.toString = () => `${body.split('\n')[1]}...`;
|
|
285
|
+
}
|
|
286
|
+
if (!schema) throw new Error('Empty Joi schema provided, see https://joi.dev/ for details');
|
|
287
|
+
if (!joi.isSchema(schema)) throw new Error('Invalid Joi schema provided, see https://joi.dev/ for details');
|
|
288
|
+
schema.toString = () => schema.describe();
|
|
289
|
+
joi.assert(this.response.data, schema);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
_checkResponseReady() {
|
|
293
|
+
if (!this.response) throw new Error('Response is not available');
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
module.exports = JSONResponse;
|