codeceptjs 3.5.12-beta.5 → 3.5.12-beta.7
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/lib/helper/MockServer.js +215 -0
- package/lib/helper/Playwright.js +43 -22
- package/lib/helper/Puppeteer.js +25 -6
- package/lib/helper/WebDriver.js +25 -4
- package/lib/helper/errors/ElementAssertion.js +38 -0
- package/package.json +6 -5
- package/typings/index.d.ts +16 -0
- package/typings/promiseBasedTypes.d.ts +182 -0
- package/typings/types.d.ts +182 -0
- package/docs/advanced.md +0 -351
- package/docs/ai.md +0 -248
- package/docs/api.md +0 -323
- package/docs/basics.md +0 -979
- package/docs/bdd.md +0 -539
- package/docs/best.md +0 -237
- package/docs/books.md +0 -37
- package/docs/bootstrap.md +0 -135
- package/docs/build/ApiDataFactory.js +0 -410
- package/docs/build/Appium.js +0 -2027
- package/docs/build/Expect.js +0 -422
- package/docs/build/FileSystem.js +0 -228
- package/docs/build/GraphQL.js +0 -229
- package/docs/build/GraphQLDataFactory.js +0 -309
- package/docs/build/JSONResponse.js +0 -338
- package/docs/build/Mochawesome.js +0 -71
- package/docs/build/Nightmare.js +0 -2152
- package/docs/build/OpenAI.js +0 -126
- package/docs/build/Playwright.js +0 -5110
- package/docs/build/Protractor.js +0 -2706
- package/docs/build/Puppeteer.js +0 -3905
- package/docs/build/REST.js +0 -344
- package/docs/build/TestCafe.js +0 -2125
- package/docs/build/WebDriver.js +0 -4240
- package/docs/changelog.md +0 -2572
- package/docs/commands.md +0 -266
- package/docs/community-helpers.md +0 -58
- package/docs/configuration.md +0 -157
- package/docs/continuous-integration.md +0 -22
- package/docs/custom-helpers.md +0 -306
- package/docs/data.md +0 -379
- package/docs/detox.md +0 -235
- package/docs/docker.md +0 -136
- package/docs/email.md +0 -183
- package/docs/examples.md +0 -149
- package/docs/helpers/ApiDataFactory.md +0 -266
- package/docs/helpers/Appium.md +0 -1374
- package/docs/helpers/Detox.md +0 -586
- package/docs/helpers/Expect.md +0 -275
- package/docs/helpers/FileSystem.md +0 -152
- package/docs/helpers/GraphQL.md +0 -151
- package/docs/helpers/GraphQLDataFactory.md +0 -226
- package/docs/helpers/JSONResponse.md +0 -254
- package/docs/helpers/Mochawesome.md +0 -8
- package/docs/helpers/MockRequest.md +0 -377
- package/docs/helpers/Nightmare.md +0 -1305
- package/docs/helpers/OpenAI.md +0 -70
- package/docs/helpers/Playwright.md +0 -2759
- package/docs/helpers/Polly.md +0 -44
- package/docs/helpers/Protractor.md +0 -1769
- package/docs/helpers/Puppeteer-firefox.md +0 -86
- package/docs/helpers/Puppeteer.md +0 -2317
- package/docs/helpers/REST.md +0 -218
- package/docs/helpers/TestCafe.md +0 -1321
- package/docs/helpers/WebDriver.md +0 -2547
- package/docs/hooks.md +0 -340
- package/docs/index.md +0 -111
- package/docs/installation.md +0 -75
- package/docs/internal-api.md +0 -266
- package/docs/locators.md +0 -339
- package/docs/mobile-react-native-locators.md +0 -67
- package/docs/mobile.md +0 -338
- package/docs/pageobjects.md +0 -291
- package/docs/parallel.md +0 -400
- package/docs/playwright.md +0 -632
- package/docs/plugins.md +0 -1259
- package/docs/puppeteer.md +0 -316
- package/docs/quickstart.md +0 -162
- package/docs/react.md +0 -70
- package/docs/reports.md +0 -392
- package/docs/secrets.md +0 -36
- package/docs/shadow.md +0 -68
- package/docs/shared/keys.mustache +0 -31
- package/docs/shared/react.mustache +0 -1
- package/docs/testcafe.md +0 -174
- package/docs/translation.md +0 -247
- package/docs/tutorial.md +0 -271
- package/docs/typescript.md +0 -180
- package/docs/ui.md +0 -59
- package/docs/videos.md +0 -28
- package/docs/visual.md +0 -202
- package/docs/vue.md +0 -143
- package/docs/webapi/amOnPage.mustache +0 -11
- package/docs/webapi/appendField.mustache +0 -11
- package/docs/webapi/attachFile.mustache +0 -12
- package/docs/webapi/blur.mustache +0 -18
- package/docs/webapi/checkOption.mustache +0 -13
- package/docs/webapi/clearCookie.mustache +0 -9
- package/docs/webapi/clearField.mustache +0 -9
- package/docs/webapi/click.mustache +0 -25
- package/docs/webapi/clickLink.mustache +0 -8
- package/docs/webapi/closeCurrentTab.mustache +0 -7
- package/docs/webapi/closeOtherTabs.mustache +0 -8
- package/docs/webapi/dontSee.mustache +0 -11
- package/docs/webapi/dontSeeCheckboxIsChecked.mustache +0 -10
- package/docs/webapi/dontSeeCookie.mustache +0 -8
- package/docs/webapi/dontSeeCurrentUrlEquals.mustache +0 -10
- package/docs/webapi/dontSeeElement.mustache +0 -8
- package/docs/webapi/dontSeeElementInDOM.mustache +0 -8
- package/docs/webapi/dontSeeInCurrentUrl.mustache +0 -4
- package/docs/webapi/dontSeeInField.mustache +0 -11
- package/docs/webapi/dontSeeInSource.mustache +0 -8
- package/docs/webapi/dontSeeInTitle.mustache +0 -8
- package/docs/webapi/doubleClick.mustache +0 -13
- package/docs/webapi/downloadFile.mustache +0 -12
- package/docs/webapi/dragAndDrop.mustache +0 -9
- package/docs/webapi/dragSlider.mustache +0 -11
- package/docs/webapi/executeAsyncScript.mustache +0 -24
- package/docs/webapi/executeScript.mustache +0 -26
- package/docs/webapi/fillField.mustache +0 -16
- package/docs/webapi/focus.mustache +0 -13
- package/docs/webapi/forceClick.mustache +0 -28
- package/docs/webapi/forceRightClick.mustache +0 -18
- package/docs/webapi/grabAllWindowHandles.mustache +0 -7
- package/docs/webapi/grabAttributeFrom.mustache +0 -10
- package/docs/webapi/grabAttributeFromAll.mustache +0 -9
- package/docs/webapi/grabBrowserLogs.mustache +0 -9
- package/docs/webapi/grabCookie.mustache +0 -11
- package/docs/webapi/grabCssPropertyFrom.mustache +0 -11
- package/docs/webapi/grabCssPropertyFromAll.mustache +0 -10
- package/docs/webapi/grabCurrentUrl.mustache +0 -9
- package/docs/webapi/grabCurrentWindowHandle.mustache +0 -6
- package/docs/webapi/grabDataFromPerformanceTiming.mustache +0 -20
- package/docs/webapi/grabElementBoundingRect.mustache +0 -20
- package/docs/webapi/grabGeoLocation.mustache +0 -8
- package/docs/webapi/grabHTMLFrom.mustache +0 -10
- package/docs/webapi/grabHTMLFromAll.mustache +0 -9
- package/docs/webapi/grabNumberOfOpenTabs.mustache +0 -8
- package/docs/webapi/grabNumberOfVisibleElements.mustache +0 -9
- package/docs/webapi/grabPageScrollPosition.mustache +0 -8
- package/docs/webapi/grabPopupText.mustache +0 -5
- package/docs/webapi/grabSource.mustache +0 -8
- package/docs/webapi/grabTextFrom.mustache +0 -10
- package/docs/webapi/grabTextFromAll.mustache +0 -9
- package/docs/webapi/grabTitle.mustache +0 -8
- package/docs/webapi/grabValueFrom.mustache +0 -9
- package/docs/webapi/grabValueFromAll.mustache +0 -8
- package/docs/webapi/grabWebElement.mustache +0 -9
- package/docs/webapi/grabWebElements.mustache +0 -9
- package/docs/webapi/moveCursorTo.mustache +0 -12
- package/docs/webapi/openNewTab.mustache +0 -7
- package/docs/webapi/pressKey.mustache +0 -12
- package/docs/webapi/pressKeyDown.mustache +0 -12
- package/docs/webapi/pressKeyUp.mustache +0 -12
- package/docs/webapi/pressKeyWithKeyNormalization.mustache +0 -60
- package/docs/webapi/refreshPage.mustache +0 -6
- package/docs/webapi/resizeWindow.mustache +0 -6
- package/docs/webapi/rightClick.mustache +0 -14
- package/docs/webapi/saveElementScreenshot.mustache +0 -10
- package/docs/webapi/saveScreenshot.mustache +0 -12
- package/docs/webapi/say.mustache +0 -10
- package/docs/webapi/scrollIntoView.mustache +0 -11
- package/docs/webapi/scrollPageToBottom.mustache +0 -6
- package/docs/webapi/scrollPageToTop.mustache +0 -6
- package/docs/webapi/scrollTo.mustache +0 -12
- package/docs/webapi/see.mustache +0 -11
- package/docs/webapi/seeAttributesOnElements.mustache +0 -9
- package/docs/webapi/seeCheckboxIsChecked.mustache +0 -10
- package/docs/webapi/seeCookie.mustache +0 -8
- package/docs/webapi/seeCssPropertiesOnElements.mustache +0 -9
- package/docs/webapi/seeCurrentUrlEquals.mustache +0 -11
- package/docs/webapi/seeElement.mustache +0 -8
- package/docs/webapi/seeElementInDOM.mustache +0 -8
- package/docs/webapi/seeInCurrentUrl.mustache +0 -8
- package/docs/webapi/seeInField.mustache +0 -12
- package/docs/webapi/seeInPopup.mustache +0 -8
- package/docs/webapi/seeInSource.mustache +0 -7
- package/docs/webapi/seeInTitle.mustache +0 -8
- package/docs/webapi/seeNumberOfElements.mustache +0 -11
- package/docs/webapi/seeNumberOfVisibleElements.mustache +0 -10
- package/docs/webapi/seeTextEquals.mustache +0 -9
- package/docs/webapi/seeTitleEquals.mustache +0 -8
- package/docs/webapi/selectOption.mustache +0 -21
- package/docs/webapi/setCookie.mustache +0 -16
- package/docs/webapi/setGeoLocation.mustache +0 -12
- package/docs/webapi/switchTo.mustache +0 -9
- package/docs/webapi/switchToNextTab.mustache +0 -10
- package/docs/webapi/switchToPreviousTab.mustache +0 -10
- package/docs/webapi/type.mustache +0 -21
- package/docs/webapi/uncheckOption.mustache +0 -13
- package/docs/webapi/wait.mustache +0 -8
- package/docs/webapi/waitForClickable.mustache +0 -11
- package/docs/webapi/waitForDetached.mustache +0 -10
- package/docs/webapi/waitForElement.mustache +0 -11
- package/docs/webapi/waitForEnabled.mustache +0 -6
- package/docs/webapi/waitForFunction.mustache +0 -17
- package/docs/webapi/waitForInvisible.mustache +0 -10
- package/docs/webapi/waitForNumberOfTabs.mustache +0 -9
- package/docs/webapi/waitForText.mustache +0 -13
- package/docs/webapi/waitForValue.mustache +0 -10
- package/docs/webapi/waitForVisible.mustache +0 -10
- package/docs/webapi/waitInUrl.mustache +0 -9
- package/docs/webapi/waitNumberOfVisibleElements.mustache +0 -10
- package/docs/webapi/waitToHide.mustache +0 -10
- package/docs/webapi/waitUrlEquals.mustache +0 -10
- package/docs/webdriver.md +0 -701
- package/docs/wiki/Books-&-Posts.md +0 -27
- package/docs/wiki/Community-Helpers-&-Plugins.md +0 -53
- package/docs/wiki/Converting-Playwright-to-Istanbul-Coverage.md +0 -61
- package/docs/wiki/Examples.md +0 -145
- package/docs/wiki/Google-Summer-of-Code-(GSoC)-2020.md +0 -68
- package/docs/wiki/Home.md +0 -16
- package/docs/wiki/Migration-to-Appium-v2---CodeceptJS.md +0 -83
- package/docs/wiki/Release-Process.md +0 -24
- package/docs/wiki/Roadmap.md +0 -23
- package/docs/wiki/Tests.md +0 -1393
- package/docs/wiki/Upgrading-to-CodeceptJS-3.md +0 -153
- package/docs/wiki/Videos.md +0 -19
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
const { mock, settings } = require('pactum');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ## Configuration
|
|
5
|
+
*
|
|
6
|
+
* This helper should be configured in codecept.conf.(js|ts)
|
|
7
|
+
*
|
|
8
|
+
* @typedef MockServerConfig
|
|
9
|
+
* @type {object}
|
|
10
|
+
* @prop {number} [port=9393] - Mock server port
|
|
11
|
+
* @prop {string} [host="0.0.0.0"] - Mock server host
|
|
12
|
+
* @prop {object} [httpsOpts] - key & cert values are the paths to .key and .crt files
|
|
13
|
+
*/
|
|
14
|
+
let config = {
|
|
15
|
+
port: 9393,
|
|
16
|
+
host: '0.0.0.0',
|
|
17
|
+
httpsOpts: {
|
|
18
|
+
key: '',
|
|
19
|
+
cert: '',
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* MockServer
|
|
25
|
+
*
|
|
26
|
+
* The MockServer Helper in CodeceptJS empowers you to mock any server or service via HTTP or HTTPS, making it an excellent tool for simulating REST endpoints and other HTTP-based APIs.
|
|
27
|
+
*
|
|
28
|
+
* <!-- configuration -->
|
|
29
|
+
*
|
|
30
|
+
* #### Examples
|
|
31
|
+
*
|
|
32
|
+
* You can seamlessly integrate MockServer with other helpers like REST or Playwright. Here's a configuration example inside the `codecept.conf.js` file:
|
|
33
|
+
*
|
|
34
|
+
* ```javascript
|
|
35
|
+
* {
|
|
36
|
+
* helpers: {
|
|
37
|
+
* REST: {...},
|
|
38
|
+
* MockServer: {
|
|
39
|
+
* // default mock server config
|
|
40
|
+
* port: 9393,
|
|
41
|
+
* host: '0.0.0.0',
|
|
42
|
+
* httpsOpts: {
|
|
43
|
+
* key: '',
|
|
44
|
+
* cert: '',
|
|
45
|
+
* },
|
|
46
|
+
* },
|
|
47
|
+
* }
|
|
48
|
+
* }
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* #### Adding Interactions
|
|
52
|
+
*
|
|
53
|
+
* Interactions add behavior to the mock server. Use the `I.addInteractionToMockServer()` method to include interactions. It takes an interaction object as an argument, containing request and response details.
|
|
54
|
+
*
|
|
55
|
+
* ```javascript
|
|
56
|
+
* I.addInteractionToMockServer({
|
|
57
|
+
* request: {
|
|
58
|
+
* method: 'GET',
|
|
59
|
+
* path: '/api/hello'
|
|
60
|
+
* },
|
|
61
|
+
* response: {
|
|
62
|
+
* status: 200,
|
|
63
|
+
* body: {
|
|
64
|
+
* 'say': 'hello to mock server'
|
|
65
|
+
* }
|
|
66
|
+
* }
|
|
67
|
+
* });
|
|
68
|
+
* ```
|
|
69
|
+
*
|
|
70
|
+
* #### Request Matching
|
|
71
|
+
*
|
|
72
|
+
* When a real request is sent to the mock server, it matches the received request with the interactions. If a match is found, it returns the specified response; otherwise, a 404 status code is returned.
|
|
73
|
+
*
|
|
74
|
+
* - Strong match on HTTP Method, Path, Query Params & JSON body.
|
|
75
|
+
* - Loose match on Headers.
|
|
76
|
+
*
|
|
77
|
+
* ##### Strong Match on Query Params
|
|
78
|
+
*
|
|
79
|
+
* You can send different responses based on query parameters:
|
|
80
|
+
*
|
|
81
|
+
* ```javascript
|
|
82
|
+
* I.addInteractionToMockServer({
|
|
83
|
+
* request: {
|
|
84
|
+
* method: 'GET',
|
|
85
|
+
* path: '/api/users',
|
|
86
|
+
* queryParams: {
|
|
87
|
+
* id: 1
|
|
88
|
+
* }
|
|
89
|
+
* },
|
|
90
|
+
* response: {
|
|
91
|
+
* status: 200,
|
|
92
|
+
* body: 'user 1'
|
|
93
|
+
* }
|
|
94
|
+
* });
|
|
95
|
+
*
|
|
96
|
+
* I.addInteractionToMockServer({
|
|
97
|
+
* request: {
|
|
98
|
+
* method: 'GET',
|
|
99
|
+
* path: '/api/users',
|
|
100
|
+
* queryParams: {
|
|
101
|
+
* id: 2
|
|
102
|
+
* }
|
|
103
|
+
* },
|
|
104
|
+
* response: {
|
|
105
|
+
* status: 200,
|
|
106
|
+
* body: 'user 2'
|
|
107
|
+
* }
|
|
108
|
+
* });
|
|
109
|
+
* ```
|
|
110
|
+
*
|
|
111
|
+
* - GET to `/api/users?id=1` will return 'user 1'.
|
|
112
|
+
* - GET to `/api/users?id=2` will return 'user 2'.
|
|
113
|
+
* - For all other requests, it returns a 404 status code.
|
|
114
|
+
*
|
|
115
|
+
* ##### Loose Match on Body
|
|
116
|
+
*
|
|
117
|
+
* When `strict` is set to false, it performs a loose match on query params and response body:
|
|
118
|
+
*
|
|
119
|
+
* ```javascript
|
|
120
|
+
* I.addInteractionToMockServer({
|
|
121
|
+
* strict: false,
|
|
122
|
+
* request: {
|
|
123
|
+
* method: 'POST',
|
|
124
|
+
* path: '/api/users',
|
|
125
|
+
* body: {
|
|
126
|
+
* name: 'john'
|
|
127
|
+
* }
|
|
128
|
+
* },
|
|
129
|
+
* response: {
|
|
130
|
+
* status: 200
|
|
131
|
+
* }
|
|
132
|
+
* });
|
|
133
|
+
* ```
|
|
134
|
+
*
|
|
135
|
+
* - POST to `/api/users` with the body containing `name` as 'john' will return a 200 status code.
|
|
136
|
+
* - POST to `/api/users` without the `name` property in the body will return a 404 status code.
|
|
137
|
+
*
|
|
138
|
+
* Happy testing with MockServer in CodeceptJS! 🚀
|
|
139
|
+
*
|
|
140
|
+
* ## Methods
|
|
141
|
+
*/
|
|
142
|
+
class MockServer {
|
|
143
|
+
constructor(passedConfig) {
|
|
144
|
+
settings.setLogLevel('SILENT');
|
|
145
|
+
config = { ...passedConfig };
|
|
146
|
+
if (global.debugMode) {
|
|
147
|
+
settings.setLogLevel('VERBOSE');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Start the mock server
|
|
153
|
+
* @param {number} [port] start the mock server with given port
|
|
154
|
+
*/
|
|
155
|
+
async startMockServer(port) {
|
|
156
|
+
const _config = { ...config };
|
|
157
|
+
if (port) _config.port = port;
|
|
158
|
+
await mock.setDefaults(_config);
|
|
159
|
+
await mock.start();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Stop the mock server
|
|
164
|
+
*
|
|
165
|
+
*/
|
|
166
|
+
async stopMockServer() {
|
|
167
|
+
await mock.stop();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* An interaction adds behavior to the mock server
|
|
172
|
+
*
|
|
173
|
+
*
|
|
174
|
+
* ```js
|
|
175
|
+
* I.addInteractionToMockServer({
|
|
176
|
+
* request: {
|
|
177
|
+
* method: 'GET',
|
|
178
|
+
* path: '/api/hello'
|
|
179
|
+
* },
|
|
180
|
+
* response: {
|
|
181
|
+
* status: 200,
|
|
182
|
+
* body: {
|
|
183
|
+
* 'say': 'hello to mock server'
|
|
184
|
+
* }
|
|
185
|
+
* }
|
|
186
|
+
* });
|
|
187
|
+
* ```
|
|
188
|
+
* ```js
|
|
189
|
+
* // with query params
|
|
190
|
+
* I.addInteractionToMockServer({
|
|
191
|
+
* request: {
|
|
192
|
+
* method: 'GET',
|
|
193
|
+
* path: '/api/hello',
|
|
194
|
+
* queryParams: {
|
|
195
|
+
* id: 2
|
|
196
|
+
* }
|
|
197
|
+
* },
|
|
198
|
+
* response: {
|
|
199
|
+
* status: 200,
|
|
200
|
+
* body: {
|
|
201
|
+
* 'say': 'hello to mock server'
|
|
202
|
+
* }
|
|
203
|
+
* }
|
|
204
|
+
* });
|
|
205
|
+
* ```
|
|
206
|
+
*
|
|
207
|
+
* @param {CodeceptJS.MockInteraction|object} interaction add behavior to the mock server
|
|
208
|
+
*
|
|
209
|
+
*/
|
|
210
|
+
async addInteractionToMockServer(interaction) {
|
|
211
|
+
await mock.addInteraction(interaction);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
module.exports = MockServer;
|
package/lib/helper/Playwright.js
CHANGED
|
@@ -47,6 +47,9 @@ const {
|
|
|
47
47
|
setRestartStrategy, restartsSession, restartsContext, restartsBrowser,
|
|
48
48
|
} = require('./extras/PlaywrightRestartOpts');
|
|
49
49
|
const { createValueEngine, createDisabledEngine } = require('./extras/PlaywrightPropEngine');
|
|
50
|
+
const {
|
|
51
|
+
seeElementError, dontSeeElementError, dontSeeElementInDOMError, seeElementInDOMError,
|
|
52
|
+
} = require('./errors/ElementAssertion');
|
|
50
53
|
|
|
51
54
|
const pathSeparator = path.sep;
|
|
52
55
|
|
|
@@ -1451,7 +1454,11 @@ class Playwright extends Helper {
|
|
|
1451
1454
|
async seeElement(locator) {
|
|
1452
1455
|
let els = await this._locate(locator);
|
|
1453
1456
|
els = await Promise.all(els.map(el => el.isVisible()));
|
|
1454
|
-
|
|
1457
|
+
try {
|
|
1458
|
+
return empty('visible elements').negate(els.filter(v => v).fill('ELEMENT'));
|
|
1459
|
+
} catch (e) {
|
|
1460
|
+
dontSeeElementError(locator);
|
|
1461
|
+
}
|
|
1455
1462
|
}
|
|
1456
1463
|
|
|
1457
1464
|
/**
|
|
@@ -1461,7 +1468,11 @@ class Playwright extends Helper {
|
|
|
1461
1468
|
async dontSeeElement(locator) {
|
|
1462
1469
|
let els = await this._locate(locator);
|
|
1463
1470
|
els = await Promise.all(els.map(el => el.isVisible()));
|
|
1464
|
-
|
|
1471
|
+
try {
|
|
1472
|
+
return empty('visible elements').assert(els.filter(v => v).fill('ELEMENT'));
|
|
1473
|
+
} catch (e) {
|
|
1474
|
+
seeElementError(locator);
|
|
1475
|
+
}
|
|
1465
1476
|
}
|
|
1466
1477
|
|
|
1467
1478
|
/**
|
|
@@ -1469,7 +1480,11 @@ class Playwright extends Helper {
|
|
|
1469
1480
|
*/
|
|
1470
1481
|
async seeElementInDOM(locator) {
|
|
1471
1482
|
const els = await this._locate(locator);
|
|
1472
|
-
|
|
1483
|
+
try {
|
|
1484
|
+
return empty('elements on page').negate(els.filter(v => v).fill('ELEMENT'));
|
|
1485
|
+
} catch (e) {
|
|
1486
|
+
dontSeeElementInDOMError(locator);
|
|
1487
|
+
}
|
|
1473
1488
|
}
|
|
1474
1489
|
|
|
1475
1490
|
/**
|
|
@@ -1477,7 +1492,11 @@ class Playwright extends Helper {
|
|
|
1477
1492
|
*/
|
|
1478
1493
|
async dontSeeElementInDOM(locator) {
|
|
1479
1494
|
const els = await this._locate(locator);
|
|
1480
|
-
|
|
1495
|
+
try {
|
|
1496
|
+
return empty('elements on a page').assert(els.filter(v => v).fill('ELEMENT'));
|
|
1497
|
+
} catch (e) {
|
|
1498
|
+
seeElementInDOMError(locator);
|
|
1499
|
+
}
|
|
1481
1500
|
}
|
|
1482
1501
|
|
|
1483
1502
|
/**
|
|
@@ -2169,6 +2188,8 @@ class Playwright extends Helper {
|
|
|
2169
2188
|
let chunked = chunkArray(attrs, values.length);
|
|
2170
2189
|
chunked = chunked.filter((val) => {
|
|
2171
2190
|
for (let i = 0; i < val.length; ++i) {
|
|
2191
|
+
// the attribute could be a boolean
|
|
2192
|
+
if (typeof val[i] === 'boolean') return val[i] === values[i];
|
|
2172
2193
|
// if the attribute doesn't exist, returns false as well
|
|
2173
2194
|
if (!val[i] || !val[i].includes(values[i])) return false;
|
|
2174
2195
|
}
|
|
@@ -2974,27 +2995,27 @@ class Playwright extends Helper {
|
|
|
2974
2995
|
throw new Error('Failure in test automation. You use "I.grabRecordedNetworkTraffics", but "I.startRecordingTraffic" was never called before.');
|
|
2975
2996
|
}
|
|
2976
2997
|
|
|
2977
|
-
const
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
}
|
|
2998
|
+
const promises = this.requests.map(async (request) => {
|
|
2999
|
+
const resp = await request.response;
|
|
3000
|
+
let body;
|
|
3001
|
+
try {
|
|
3002
|
+
// There's no 'body' for some requests (redirect etc...)
|
|
3003
|
+
body = JSON.parse((await resp.body()).toString());
|
|
3004
|
+
} catch (e) {
|
|
3005
|
+
// only interested in JSON, not HTML responses.
|
|
3006
|
+
}
|
|
2987
3007
|
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
3008
|
+
return {
|
|
3009
|
+
url: resp.url(),
|
|
3010
|
+
response: {
|
|
3011
|
+
status: resp.status(),
|
|
3012
|
+
statusText: resp.statusText(),
|
|
2991
3013
|
body,
|
|
2992
|
-
}
|
|
2993
|
-
}
|
|
2994
|
-
)
|
|
2995
|
-
await Promise.all(promises);
|
|
3014
|
+
},
|
|
3015
|
+
};
|
|
3016
|
+
});
|
|
2996
3017
|
|
|
2997
|
-
return
|
|
3018
|
+
return Promise.all(promises);
|
|
2998
3019
|
}
|
|
2999
3020
|
|
|
3000
3021
|
/**
|
package/lib/helper/Puppeteer.js
CHANGED
|
@@ -39,6 +39,9 @@ const findReact = require('./extras/React');
|
|
|
39
39
|
const { highlightElement } = require('./scripts/highlightElement');
|
|
40
40
|
const { blurElement } = require('./scripts/blurElement');
|
|
41
41
|
const { focusElement } = require('./scripts/focusElement');
|
|
42
|
+
const {
|
|
43
|
+
dontSeeElementError, seeElementError, dontSeeElementInDOMError, seeElementInDOMError,
|
|
44
|
+
} = require('./errors/ElementAssertion');
|
|
42
45
|
|
|
43
46
|
let puppeteer;
|
|
44
47
|
let perfTiming;
|
|
@@ -1038,8 +1041,11 @@ class Puppeteer extends Helper {
|
|
|
1038
1041
|
els = (await Promise.all(els.map(el => el.boundingBox() && el))).filter(v => v);
|
|
1039
1042
|
// Puppeteer visibility was ignored? | Remove when Puppeteer is fixed
|
|
1040
1043
|
els = await Promise.all(els.map(async el => (await el.evaluate(node => window.getComputedStyle(node).visibility !== 'hidden' && window.getComputedStyle(node).display !== 'none')) && el));
|
|
1041
|
-
|
|
1042
|
-
|
|
1044
|
+
try {
|
|
1045
|
+
return empty('visible elements').negate(els.filter(v => v).fill('ELEMENT'));
|
|
1046
|
+
} catch (e) {
|
|
1047
|
+
dontSeeElementError(locator);
|
|
1048
|
+
}
|
|
1043
1049
|
}
|
|
1044
1050
|
|
|
1045
1051
|
/**
|
|
@@ -1051,8 +1057,11 @@ class Puppeteer extends Helper {
|
|
|
1051
1057
|
els = (await Promise.all(els.map(el => el.boundingBox() && el))).filter(v => v);
|
|
1052
1058
|
// Puppeteer visibility was ignored? | Remove when Puppeteer is fixed
|
|
1053
1059
|
els = await Promise.all(els.map(async el => (await el.evaluate(node => window.getComputedStyle(node).visibility !== 'hidden' && window.getComputedStyle(node).display !== 'none')) && el));
|
|
1054
|
-
|
|
1055
|
-
|
|
1060
|
+
try {
|
|
1061
|
+
return empty('visible elements').assert(els.filter(v => v).fill('ELEMENT'));
|
|
1062
|
+
} catch (e) {
|
|
1063
|
+
seeElementError(locator);
|
|
1064
|
+
}
|
|
1056
1065
|
}
|
|
1057
1066
|
|
|
1058
1067
|
/**
|
|
@@ -1060,7 +1069,11 @@ class Puppeteer extends Helper {
|
|
|
1060
1069
|
*/
|
|
1061
1070
|
async seeElementInDOM(locator) {
|
|
1062
1071
|
const els = await this._locate(locator);
|
|
1063
|
-
|
|
1072
|
+
try {
|
|
1073
|
+
return empty('elements on page').negate(els.filter(v => v).fill('ELEMENT'));
|
|
1074
|
+
} catch (e) {
|
|
1075
|
+
dontSeeElementInDOMError(locator);
|
|
1076
|
+
}
|
|
1064
1077
|
}
|
|
1065
1078
|
|
|
1066
1079
|
/**
|
|
@@ -1068,7 +1081,11 @@ class Puppeteer extends Helper {
|
|
|
1068
1081
|
*/
|
|
1069
1082
|
async dontSeeElementInDOM(locator) {
|
|
1070
1083
|
const els = await this._locate(locator);
|
|
1071
|
-
|
|
1084
|
+
try {
|
|
1085
|
+
return empty('elements on a page').assert(els.filter(v => v).fill('ELEMENT'));
|
|
1086
|
+
} catch (e) {
|
|
1087
|
+
seeElementInDOMError(locator);
|
|
1088
|
+
}
|
|
1072
1089
|
}
|
|
1073
1090
|
|
|
1074
1091
|
/**
|
|
@@ -1825,6 +1842,8 @@ class Puppeteer extends Helper {
|
|
|
1825
1842
|
for (let i = 0; i < val.length; ++i) {
|
|
1826
1843
|
const _actual = Number.isNaN(val[i]) || (typeof values[i]) === 'string' ? val[i] : Number.parseInt(values[i], 10);
|
|
1827
1844
|
const _expected = Number.isNaN(values[i]) || (typeof values[i]) === 'string' ? values[i] : Number.parseInt(values[i], 10);
|
|
1845
|
+
// the attribute could be a boolean
|
|
1846
|
+
if (typeof _actual === 'boolean') return _actual === _expected;
|
|
1828
1847
|
// if the attribute doesn't exist, returns false as well
|
|
1829
1848
|
if (!_actual || !_actual.includes(_expected)) return false;
|
|
1830
1849
|
}
|
package/lib/helper/WebDriver.js
CHANGED
|
@@ -32,6 +32,9 @@ const { highlightElement } = require('./scripts/highlightElement');
|
|
|
32
32
|
const store = require('../store');
|
|
33
33
|
const { focusElement } = require('./scripts/focusElement');
|
|
34
34
|
const { blurElement } = require('./scripts/blurElement');
|
|
35
|
+
const {
|
|
36
|
+
dontSeeElementError, seeElementError, seeElementInDOMError, dontSeeElementInDOMError,
|
|
37
|
+
} = require('./errors/ElementAssertion');
|
|
35
38
|
|
|
36
39
|
const SHADOW = 'shadow';
|
|
37
40
|
const webRoot = 'body';
|
|
@@ -1461,7 +1464,11 @@ class WebDriver extends Helper {
|
|
|
1461
1464
|
const res = await this._locate(locator, true);
|
|
1462
1465
|
assertElementExists(res, locator);
|
|
1463
1466
|
const selected = await forEachAsync(res, async el => el.isDisplayed());
|
|
1464
|
-
|
|
1467
|
+
try {
|
|
1468
|
+
return truth(`elements of ${(new Locator(locator))}`, 'to be seen').assert(selected);
|
|
1469
|
+
} catch (e) {
|
|
1470
|
+
dontSeeElementError(locator);
|
|
1471
|
+
}
|
|
1465
1472
|
}
|
|
1466
1473
|
|
|
1467
1474
|
/**
|
|
@@ -1474,7 +1481,11 @@ class WebDriver extends Helper {
|
|
|
1474
1481
|
return truth(`elements of ${(new Locator(locator))}`, 'to be seen').negate(false);
|
|
1475
1482
|
}
|
|
1476
1483
|
const selected = await forEachAsync(res, async el => el.isDisplayed());
|
|
1477
|
-
|
|
1484
|
+
try {
|
|
1485
|
+
return truth(`elements of ${(new Locator(locator))}`, 'to be seen').negate(selected);
|
|
1486
|
+
} catch (e) {
|
|
1487
|
+
seeElementError(locator);
|
|
1488
|
+
}
|
|
1478
1489
|
}
|
|
1479
1490
|
|
|
1480
1491
|
/**
|
|
@@ -1483,7 +1494,11 @@ class WebDriver extends Helper {
|
|
|
1483
1494
|
*/
|
|
1484
1495
|
async seeElementInDOM(locator) {
|
|
1485
1496
|
const res = await this._res(locator);
|
|
1486
|
-
|
|
1497
|
+
try {
|
|
1498
|
+
return empty('elements').negate(res);
|
|
1499
|
+
} catch (e) {
|
|
1500
|
+
dontSeeElementInDOMError(locator);
|
|
1501
|
+
}
|
|
1487
1502
|
}
|
|
1488
1503
|
|
|
1489
1504
|
/**
|
|
@@ -1492,7 +1507,11 @@ class WebDriver extends Helper {
|
|
|
1492
1507
|
*/
|
|
1493
1508
|
async dontSeeElementInDOM(locator) {
|
|
1494
1509
|
const res = await this._res(locator);
|
|
1495
|
-
|
|
1510
|
+
try {
|
|
1511
|
+
return empty('elements').assert(res);
|
|
1512
|
+
} catch (e) {
|
|
1513
|
+
seeElementInDOMError(locator);
|
|
1514
|
+
}
|
|
1496
1515
|
}
|
|
1497
1516
|
|
|
1498
1517
|
/**
|
|
@@ -1612,6 +1631,8 @@ class WebDriver extends Helper {
|
|
|
1612
1631
|
for (let i = 0; i < val.length; ++i) {
|
|
1613
1632
|
const _actual = Number.isNaN(val[i]) || (typeof values[i]) === 'string' ? val[i] : Number.parseInt(val[i], 10);
|
|
1614
1633
|
const _expected = Number.isNaN(values[i]) || (typeof values[i]) === 'string' ? values[i] : Number.parseInt(values[i], 10);
|
|
1634
|
+
// the attribute could be a boolean
|
|
1635
|
+
if (typeof _actual === 'boolean') return _actual === _expected;
|
|
1615
1636
|
if (_actual !== _expected) return false;
|
|
1616
1637
|
}
|
|
1617
1638
|
return true;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const Locator = require('../../locator');
|
|
2
|
+
|
|
3
|
+
const prefixMessage = 'Element';
|
|
4
|
+
|
|
5
|
+
function seeElementError(locator) {
|
|
6
|
+
if (typeof locator === 'object') {
|
|
7
|
+
locator = JSON.stringify(locator);
|
|
8
|
+
}
|
|
9
|
+
throw new Error(`${prefixMessage} "${(new Locator(locator))}" is still visible on page.`);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function seeElementInDOMError(locator) {
|
|
13
|
+
if (typeof locator === 'object') {
|
|
14
|
+
locator = JSON.stringify(locator);
|
|
15
|
+
}
|
|
16
|
+
throw new Error(`${prefixMessage} "${(new Locator(locator))}" is still seen in DOM.`);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function dontSeeElementError(locator) {
|
|
20
|
+
if (typeof locator === 'object') {
|
|
21
|
+
locator = JSON.stringify(locator);
|
|
22
|
+
}
|
|
23
|
+
throw new Error(`${prefixMessage} "${(new Locator(locator))}" is not visible on page.`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function dontSeeElementInDOMError(locator) {
|
|
27
|
+
if (typeof locator === 'object') {
|
|
28
|
+
locator = JSON.stringify(locator);
|
|
29
|
+
}
|
|
30
|
+
throw new Error(`${prefixMessage} "${(new Locator(locator))}" is not seen in DOM.`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
module.exports = {
|
|
34
|
+
seeElementError,
|
|
35
|
+
dontSeeElementError,
|
|
36
|
+
seeElementInDOMError,
|
|
37
|
+
dontSeeElementInDOMError,
|
|
38
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeceptjs",
|
|
3
|
-
"version": "3.5.12-beta.
|
|
3
|
+
"version": "3.5.12-beta.7",
|
|
4
4
|
"description": "Supercharged End 2 End Testing Framework for NodeJS",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"acceptance",
|
|
@@ -23,7 +23,6 @@
|
|
|
23
23
|
},
|
|
24
24
|
"files": [
|
|
25
25
|
"bin",
|
|
26
|
-
"docs",
|
|
27
26
|
"lib",
|
|
28
27
|
"translations",
|
|
29
28
|
"typings/**/*.d.ts"
|
|
@@ -56,6 +55,7 @@
|
|
|
56
55
|
"test:unit:webbapi:webDriver:devtools": "mocha test/helper/WebDriver_devtools_test.js --exit",
|
|
57
56
|
"test:unit:webbapi:testCafe": "mocha test/helper/TestCafe_test.js",
|
|
58
57
|
"test:unit:expect": "mocha test/helper/Expect_test.js",
|
|
58
|
+
"test:unit:mockServer": "mocha test/helper/MockServer_test.js",
|
|
59
59
|
"test:plugin": "mocha test/plugin/plugin_test.js",
|
|
60
60
|
"def": "./runok.js def",
|
|
61
61
|
"dev:graphql": "node test/data/graphql/index.js",
|
|
@@ -105,6 +105,7 @@
|
|
|
105
105
|
"ms": "2.1.3",
|
|
106
106
|
"openai": "3.2.1",
|
|
107
107
|
"ora-classic": "5.4.2",
|
|
108
|
+
"pactum": "3.6.0",
|
|
108
109
|
"parse-function": "5.6.4",
|
|
109
110
|
"parse5": "7.1.2",
|
|
110
111
|
"promise-retry": "1.1.1",
|
|
@@ -133,7 +134,7 @@
|
|
|
133
134
|
"contributor-faces": "1.1.0",
|
|
134
135
|
"documentation": "12.3.0",
|
|
135
136
|
"dtslint": "4.2.1",
|
|
136
|
-
"electron": "28.
|
|
137
|
+
"electron": "28.1.4",
|
|
137
138
|
"eslint": "8.56.0",
|
|
138
139
|
"eslint-config-airbnb-base": "15.0.0",
|
|
139
140
|
"eslint-plugin-import": "2.29.1",
|
|
@@ -146,7 +147,7 @@
|
|
|
146
147
|
"jsdoc": "3.6.11",
|
|
147
148
|
"jsdoc-typeof-plugin": "1.0.0",
|
|
148
149
|
"json-server": "0.10.1",
|
|
149
|
-
"playwright": "1.
|
|
150
|
+
"playwright": "1.41.1",
|
|
150
151
|
"puppeteer": "21.1.1",
|
|
151
152
|
"qrcode-terminal": "0.12.0",
|
|
152
153
|
"rosie": "2.1.1",
|
|
@@ -161,7 +162,7 @@
|
|
|
161
162
|
"typedoc-plugin-markdown": "3.17.1",
|
|
162
163
|
"typescript": "5.3.3",
|
|
163
164
|
"wdio-docker-service": "1.5.0",
|
|
164
|
-
"webdriverio": "8.
|
|
165
|
+
"webdriverio": "8.28.8",
|
|
165
166
|
"xml2js": "0.6.2",
|
|
166
167
|
"xpath": "0.0.34"
|
|
167
168
|
},
|
package/typings/index.d.ts
CHANGED
|
@@ -382,6 +382,22 @@ declare namespace CodeceptJS {
|
|
|
382
382
|
[key: string]: any;
|
|
383
383
|
};
|
|
384
384
|
|
|
385
|
+
type MockRequest = {
|
|
386
|
+
method: 'GET'|'PUT'|'POST'|'PATCH'|'DELETE'|string;
|
|
387
|
+
path: string;
|
|
388
|
+
queryParams?: object;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
type MockResponse = {
|
|
392
|
+
status: number;
|
|
393
|
+
body?: object;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
type MockInteraction = {
|
|
397
|
+
request: MockRequest;
|
|
398
|
+
response: MockResponse;
|
|
399
|
+
}
|
|
400
|
+
|
|
385
401
|
interface PageScrollPosition {
|
|
386
402
|
x: number;
|
|
387
403
|
y: number;
|