codeceptjs 4.0.0-beta.4 → 4.0.0-beta.6.esm-aria

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.
Files changed (188) hide show
  1. package/README.md +89 -119
  2. package/bin/codecept.js +53 -54
  3. package/docs/webapi/clearCookie.mustache +1 -1
  4. package/lib/actor.js +70 -102
  5. package/lib/ai.js +131 -121
  6. package/lib/assert/empty.js +11 -12
  7. package/lib/assert/equal.js +16 -21
  8. package/lib/assert/error.js +2 -2
  9. package/lib/assert/include.js +11 -15
  10. package/lib/assert/throws.js +3 -5
  11. package/lib/assert/truth.js +10 -7
  12. package/lib/assert.js +18 -18
  13. package/lib/codecept.js +112 -101
  14. package/lib/colorUtils.js +48 -50
  15. package/lib/command/check.js +206 -0
  16. package/lib/command/configMigrate.js +13 -14
  17. package/lib/command/definitions.js +24 -36
  18. package/lib/command/dryRun.js +16 -16
  19. package/lib/command/generate.js +38 -39
  20. package/lib/command/gherkin/init.js +36 -38
  21. package/lib/command/gherkin/snippets.js +76 -74
  22. package/lib/command/gherkin/steps.js +21 -18
  23. package/lib/command/info.js +49 -15
  24. package/lib/command/init.js +41 -37
  25. package/lib/command/interactive.js +22 -13
  26. package/lib/command/list.js +11 -10
  27. package/lib/command/run-multiple/chunk.js +50 -47
  28. package/lib/command/run-multiple/collection.js +5 -5
  29. package/lib/command/run-multiple/run.js +3 -3
  30. package/lib/command/run-multiple.js +27 -47
  31. package/lib/command/run-rerun.js +6 -7
  32. package/lib/command/run-workers.js +15 -66
  33. package/lib/command/run.js +8 -8
  34. package/lib/command/utils.js +22 -21
  35. package/lib/command/workers/runTests.js +131 -241
  36. package/lib/config.js +111 -49
  37. package/lib/container.js +589 -244
  38. package/lib/data/context.js +16 -18
  39. package/lib/data/dataScenarioConfig.js +9 -9
  40. package/lib/data/dataTableArgument.js +7 -7
  41. package/lib/data/table.js +6 -12
  42. package/lib/effects.js +307 -0
  43. package/lib/els.js +160 -0
  44. package/lib/event.js +24 -19
  45. package/lib/globals.js +141 -0
  46. package/lib/heal.js +89 -81
  47. package/lib/helper/AI.js +3 -2
  48. package/lib/helper/ApiDataFactory.js +19 -19
  49. package/lib/helper/Appium.js +47 -51
  50. package/lib/helper/FileSystem.js +35 -15
  51. package/lib/helper/GraphQL.js +1 -1
  52. package/lib/helper/GraphQLDataFactory.js +4 -4
  53. package/lib/helper/JSONResponse.js +72 -45
  54. package/lib/helper/Mochawesome.js +14 -11
  55. package/lib/helper/Playwright.js +832 -434
  56. package/lib/helper/Puppeteer.js +393 -292
  57. package/lib/helper/REST.js +32 -27
  58. package/lib/helper/WebDriver.js +320 -219
  59. package/lib/helper/errors/ConnectionRefused.js +6 -6
  60. package/lib/helper/errors/ElementAssertion.js +11 -16
  61. package/lib/helper/errors/ElementNotFound.js +5 -9
  62. package/lib/helper/errors/RemoteBrowserConnectionRefused.js +5 -5
  63. package/lib/helper/extras/Console.js +11 -11
  64. package/lib/helper/extras/PlaywrightLocator.js +110 -0
  65. package/lib/helper/extras/PlaywrightPropEngine.js +18 -18
  66. package/lib/helper/extras/PlaywrightRestartOpts.js +23 -23
  67. package/lib/helper/extras/Popup.js +22 -22
  68. package/lib/helper/extras/React.js +29 -30
  69. package/lib/helper/network/actions.js +33 -48
  70. package/lib/helper/network/utils.js +76 -83
  71. package/lib/helper/scripts/blurElement.js +6 -6
  72. package/lib/helper/scripts/focusElement.js +6 -6
  73. package/lib/helper/scripts/highlightElement.js +9 -9
  74. package/lib/helper/scripts/isElementClickable.js +34 -34
  75. package/lib/helper.js +2 -1
  76. package/lib/history.js +23 -20
  77. package/lib/hooks.js +10 -10
  78. package/lib/html.js +90 -100
  79. package/lib/index.js +48 -21
  80. package/lib/listener/config.js +8 -9
  81. package/lib/listener/emptyRun.js +54 -0
  82. package/lib/listener/exit.js +10 -12
  83. package/lib/listener/{retry.js → globalRetry.js} +10 -10
  84. package/lib/listener/globalTimeout.js +166 -0
  85. package/lib/listener/helpers.js +43 -24
  86. package/lib/listener/mocha.js +4 -5
  87. package/lib/listener/result.js +11 -0
  88. package/lib/listener/steps.js +26 -23
  89. package/lib/listener/store.js +20 -0
  90. package/lib/locator.js +213 -192
  91. package/lib/mocha/asyncWrapper.js +264 -0
  92. package/lib/mocha/bdd.js +167 -0
  93. package/lib/mocha/cli.js +341 -0
  94. package/lib/mocha/factory.js +160 -0
  95. package/lib/{interfaces → mocha}/featureConfig.js +33 -13
  96. package/lib/{interfaces → mocha}/gherkin.js +75 -45
  97. package/lib/mocha/hooks.js +121 -0
  98. package/lib/mocha/index.js +21 -0
  99. package/lib/mocha/inject.js +46 -0
  100. package/lib/{interfaces → mocha}/scenarioConfig.js +32 -8
  101. package/lib/mocha/suite.js +89 -0
  102. package/lib/mocha/test.js +178 -0
  103. package/lib/mocha/types.d.ts +42 -0
  104. package/lib/mocha/ui.js +229 -0
  105. package/lib/output.js +86 -64
  106. package/lib/parser.js +44 -44
  107. package/lib/pause.js +160 -139
  108. package/lib/plugin/analyze.js +403 -0
  109. package/lib/plugin/{autoLogin.js → auth.js} +137 -43
  110. package/lib/plugin/autoDelay.js +19 -15
  111. package/lib/plugin/coverage.js +22 -27
  112. package/lib/plugin/customLocator.js +5 -5
  113. package/lib/plugin/customReporter.js +53 -0
  114. package/lib/plugin/heal.js +49 -17
  115. package/lib/plugin/pageInfo.js +140 -0
  116. package/lib/plugin/pauseOnFail.js +4 -3
  117. package/lib/plugin/retryFailedStep.js +60 -19
  118. package/lib/plugin/screenshotOnFail.js +80 -83
  119. package/lib/plugin/stepByStepReport.js +70 -31
  120. package/lib/plugin/stepTimeout.js +7 -13
  121. package/lib/plugin/subtitles.js +10 -9
  122. package/lib/recorder.js +167 -126
  123. package/lib/rerun.js +94 -50
  124. package/lib/result.js +161 -0
  125. package/lib/secret.js +18 -17
  126. package/lib/session.js +95 -89
  127. package/lib/step/base.js +239 -0
  128. package/lib/step/comment.js +10 -0
  129. package/lib/step/config.js +50 -0
  130. package/lib/step/func.js +46 -0
  131. package/lib/step/helper.js +50 -0
  132. package/lib/step/meta.js +99 -0
  133. package/lib/step/record.js +74 -0
  134. package/lib/step/retry.js +11 -0
  135. package/lib/step/section.js +55 -0
  136. package/lib/step.js +18 -332
  137. package/lib/steps.js +54 -0
  138. package/lib/store.js +37 -5
  139. package/lib/template/heal.js +2 -11
  140. package/lib/timeout.js +60 -0
  141. package/lib/transform.js +8 -8
  142. package/lib/translation.js +32 -18
  143. package/lib/utils.js +354 -250
  144. package/lib/workerStorage.js +16 -16
  145. package/lib/workers.js +366 -282
  146. package/package.json +107 -95
  147. package/translations/de-DE.js +5 -4
  148. package/translations/fr-FR.js +5 -4
  149. package/translations/index.js +23 -9
  150. package/translations/it-IT.js +5 -4
  151. package/translations/ja-JP.js +5 -4
  152. package/translations/nl-NL.js +76 -0
  153. package/translations/pl-PL.js +5 -4
  154. package/translations/pt-BR.js +5 -4
  155. package/translations/ru-RU.js +5 -4
  156. package/translations/utils.js +18 -0
  157. package/translations/zh-CN.js +5 -4
  158. package/translations/zh-TW.js +5 -4
  159. package/typings/index.d.ts +177 -186
  160. package/typings/promiseBasedTypes.d.ts +3573 -5941
  161. package/typings/types.d.ts +4042 -6370
  162. package/lib/cli.js +0 -256
  163. package/lib/helper/ExpectHelper.js +0 -391
  164. package/lib/helper/Nightmare.js +0 -1504
  165. package/lib/helper/Protractor.js +0 -1863
  166. package/lib/helper/SoftExpectHelper.js +0 -381
  167. package/lib/helper/TestCafe.js +0 -1414
  168. package/lib/helper/clientscripts/nightmare.js +0 -213
  169. package/lib/helper/extras/PlaywrightReactVueLocator.js +0 -43
  170. package/lib/helper/testcafe/testControllerHolder.js +0 -42
  171. package/lib/helper/testcafe/testcafe-utils.js +0 -62
  172. package/lib/interfaces/bdd.js +0 -81
  173. package/lib/listener/artifacts.js +0 -19
  174. package/lib/listener/timeout.js +0 -109
  175. package/lib/mochaFactory.js +0 -113
  176. package/lib/plugin/allure.js +0 -15
  177. package/lib/plugin/commentStep.js +0 -136
  178. package/lib/plugin/debugErrors.js +0 -67
  179. package/lib/plugin/eachElement.js +0 -127
  180. package/lib/plugin/fakerTransform.js +0 -49
  181. package/lib/plugin/retryTo.js +0 -127
  182. package/lib/plugin/selenoid.js +0 -384
  183. package/lib/plugin/standardActingHelpers.js +0 -3
  184. package/lib/plugin/tryTo.js +0 -115
  185. package/lib/plugin/wdio.js +0 -249
  186. package/lib/scenario.js +0 -224
  187. package/lib/ui.js +0 -236
  188. package/lib/within.js +0 -70
@@ -1,1863 +0,0 @@
1
- let EC
2
- let Key
3
- let Button
4
- let ProtractorBy
5
- let ProtractorExpectedConditions
6
-
7
- const path = require('path')
8
-
9
- const Helper = require('@codeceptjs/helper')
10
- const stringIncludes = require('../assert/include').includes
11
- const { urlEquals, equals } = require('../assert/equal')
12
- const { empty } = require('../assert/empty')
13
- const { truth } = require('../assert/truth')
14
- const { xpathLocator, fileExists, convertCssPropertiesToCamelCase, screenshotOutputFolder } = require('../utils')
15
- const { isColorProperty, convertColorToRGBA } = require('../colorUtils')
16
- const ElementNotFound = require('./errors/ElementNotFound')
17
- const ConnectionRefused = require('./errors/ConnectionRefused')
18
- const Locator = require('../locator')
19
-
20
- let withinStore = {}
21
- let Runner
22
-
23
- /**
24
- * Protractor helper is based on [Protractor library](http://www.protractortest.org) and used for testing web applications.
25
- *
26
- * Protractor requires [Selenium Server and ChromeDriver/GeckoDriver to be installed](http://codecept.io/quickstart/#prepare-selenium-server).
27
- * To test non-Angular applications please make sure you have `angular: false` in configuration file.
28
- *
29
- * ### Configuration
30
- *
31
- * This helper should be configured in codecept.conf.ts or codecept.conf.js
32
- *
33
- * * `url` - base url of website to be tested
34
- * * `browser` - browser in which perform testing
35
- * * `angular` (optional, default: true): disable this option to run tests for non-Angular applications.
36
- * * `driver` - which protractor driver to use (local, direct, session, hosted, sauce, browserstack). By default set to 'hosted' which requires selenium server to be started.
37
- * * `restart` (optional, default: true) - restart browser between tests.
38
- * * `smartWait`: (optional) **enables [SmartWait](http://codecept.io/acceptance/#smartwait)**; wait for additional milliseconds for element to appear. Enable for 5 secs: "smartWait": 5000
39
- * * `disableScreenshots` (optional, default: false) - don't save screenshot on failure
40
- * * `fullPageScreenshots` (optional, default: false) - make full page screenshots on failure.
41
- * * `uniqueScreenshotNames` (optional, default: false) - option to prevent screenshot override if you have scenarios with the same name in different suites
42
- * * `keepBrowserState` (optional, default: false) - keep browser state between tests when `restart` set to false.
43
- * * `seleniumAddress` - Selenium address to connect (default: http://localhost:4444/wd/hub)
44
- * * `rootElement` - Root element of AngularJS application (default: body)
45
- * * `getPageTimeout` (optional) sets default timeout for a page to be loaded. 10000 by default.
46
- * * `waitForTimeout`: (optional) sets default wait time in _ms_ for all `wait*` functions. 1000 by default.
47
- * * `scriptsTimeout`: (optional) timeout in milliseconds for each script run on the browser, 10000 by default.
48
- * * `windowSize`: (optional) default window size. Set to `maximize` or a dimension in the format `640x480`.
49
- * * `manualStart` (optional, default: false) - do not start browser before a test, start it manually inside a helper with `this.helpers.WebDriver._startBrowser()`
50
- * * `capabilities`: {} - list of [Desired Capabilities](https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities)
51
- * * `proxy`: set proxy settings
52
- *
53
- * other options are the same as in [Protractor config](https://github.com/angular/protractor/blob/master/docs/referenceConf.js).
54
- *
55
- * #### Sample Config
56
- *
57
- * ```json
58
- * {
59
- * "helpers": {
60
- * "Protractor" : {
61
- * "url": "http://localhost",
62
- * "browser": "chrome",
63
- * "smartWait": 5000,
64
- * "restart": false
65
- * }
66
- * }
67
- * }
68
- * ```
69
- *
70
- * #### Config for Non-Angular application:
71
- *
72
- * ```json
73
- * {
74
- * "helpers": {
75
- * "Protractor" : {
76
- * "url": "http://localhost",
77
- * "browser": "chrome",
78
- * "angular": false
79
- * }
80
- * }
81
- * }
82
- * ```
83
- *
84
- * #### Config for Headless Chrome
85
- *
86
- * ```json
87
- * {
88
- * "helpers": {
89
- * "Protractor" : {
90
- * "url": "http://localhost",
91
- * "browser": "chrome",
92
- * "capabilities": {
93
- * "chromeOptions": {
94
- * "args": [ "--headless", "--disable-gpu", "--no-sandbox" ]
95
- * }
96
- * }
97
- * }
98
- * }
99
- * }
100
- * ```
101
- *
102
- * ## Access From Helpers
103
- *
104
- * Receive a WebDriverIO client from a custom helper by accessing `browser` property:
105
- *
106
- * ```js
107
- * this.helpers['Protractor'].browser
108
- * ```
109
- *
110
- * ## Methods
111
- */
112
- class Protractor extends Helper {
113
- constructor(config) {
114
- // process.env.SELENIUM_PROMISE_MANAGER = false; // eslint-disable-line
115
- super(config)
116
-
117
- this.isRunning = false
118
- this._setConfig(config)
119
-
120
- console.log(
121
- 'Protractor helper is deprecated as well as Protractor itself.\nThis helper will be removed in next major release',
122
- )
123
- }
124
-
125
- _validateConfig(config) {
126
- const defaults = {
127
- browser: 'chrome',
128
- url: 'http://localhost',
129
- seleniumAddress: 'http://localhost:4444/wd/hub',
130
- fullPageScreenshots: false,
131
- rootElement: 'body',
132
- allScriptsTimeout: 10000,
133
- scriptTimeout: 10000,
134
- waitForTimeout: 1000, // ms
135
- windowSize: null,
136
- getPageTimeout: 10000,
137
- driver: 'hosted',
138
- capabilities: {},
139
- angular: true,
140
- restart: true,
141
- }
142
-
143
- config = Object.assign(defaults, config)
144
-
145
- if (!config.allScriptsTimeout) config.allScriptsTimeout = config.scriptsTimeout
146
- if (!config.scriptTimeout) config.scriptTimeout = config.scriptsTimeout
147
- if (config.proxy) config.capabilities.proxy = config.proxy
148
- if (config.browser) config.capabilities.browserName = config.browser
149
-
150
- config.waitForTimeoutInSeconds = config.waitForTimeout / 1000 // convert to seconds
151
- return config
152
- }
153
-
154
- async _init() {
155
- process.on('unhandledRejection', (reason) => {
156
- if (reason.message.indexOf('ECONNREFUSED') > 0) {
157
- this.browser = null
158
- }
159
- })
160
-
161
- Runner = require('protractor/built/runner').Runner
162
- ProtractorBy = require('protractor').ProtractorBy
163
- Key = require('protractor').Key
164
- Button = require('protractor').Button
165
- ProtractorExpectedConditions = require('protractor').ProtractorExpectedConditions
166
-
167
- return Promise.resolve()
168
- }
169
-
170
- static _checkRequirements() {
171
- try {
172
- require('protractor')
173
- require('assert').ok(require('protractor/built/runner').Runner)
174
- } catch (e) {
175
- return ['protractor@^5.3.0']
176
- }
177
- }
178
-
179
- static _config() {
180
- return [
181
- { name: 'url', message: 'Base url of site to be tested', default: 'http://localhost' },
182
- {
183
- name: 'driver',
184
- message: 'Protractor driver (local, direct, session, hosted, sauce, browserstack)',
185
- default: 'hosted',
186
- },
187
- { name: 'browser', message: 'Browser in which testing will be performed', default: 'chrome' },
188
- { name: 'rootElement', message: 'Root element of AngularJS application', default: 'body' },
189
- {
190
- name: 'angular',
191
- message: 'Enable AngularJS synchronization',
192
- default: false,
193
- type: 'confirm',
194
- },
195
- ]
196
- }
197
-
198
- async _beforeStep() {
199
- if (!this.insideAngular) {
200
- return this.amOutsideAngularApp()
201
- }
202
- }
203
-
204
- async _beforeSuite() {
205
- if (!this.options.restart && !this.options.manualStart && !this.isRunning) {
206
- this.debugSection('Session', 'Starting singleton browser session')
207
- return this._startBrowser()
208
- }
209
- }
210
-
211
- async _startBrowser() {
212
- try {
213
- const runner = new Runner(this.options)
214
- this.browser = runner.createBrowser()
215
- await this.browser.ready
216
- } catch (err) {
217
- if (err.toString().indexOf('ECONNREFUSED')) {
218
- throw new ConnectionRefused(err)
219
- }
220
- throw err
221
- }
222
- if (this.options.angular) {
223
- await this.amInsideAngularApp()
224
- } else {
225
- await this.amOutsideAngularApp()
226
- }
227
-
228
- loadGlobals(this.browser)
229
-
230
- if (this.options.windowSize === 'maximize') {
231
- await this.resizeWindow(this.options.windowSize)
232
- } else if (this.options.windowSize) {
233
- const size = this.options.windowSize.split('x')
234
- await this.resizeWindow(parseInt(size[0], 10), parseInt(size[1], 10))
235
- }
236
- this.context = this.options.rootElement
237
- this.isRunning = true
238
- return this.browser.ready
239
- }
240
-
241
- async _before() {
242
- if (this.options.restart && !this.options.manualStart) return this._startBrowser()
243
- if (!this.isRunning && !this.options.manualStart) return this._startBrowser()
244
- }
245
-
246
- async _after() {
247
- if (!this.browser) return
248
- if (!this.isRunning) return
249
- if (this.options.restart) {
250
- this.isRunning = false
251
- return this.browser.quit()
252
- }
253
- if (this.options.keepBrowserState) return
254
-
255
- const dialog = await this.grabPopupText()
256
- if (dialog) {
257
- await this.cancelPopup()
258
- }
259
- if (!this.options.keepCookies) {
260
- await this.browser.manage().deleteAllCookies()
261
- }
262
- let url
263
- try {
264
- url = await this.browser.getCurrentUrl()
265
- } catch (err) {
266
- // Ignore, as above will throw if no webpage has been loaded
267
- }
268
- if (url && !/data:,/i.test(url)) {
269
- await this.browser.executeScript('localStorage.clear();')
270
- }
271
- return this.closeOtherTabs()
272
- }
273
-
274
- async _failed() {
275
- await this._withinEnd()
276
- }
277
-
278
- async _finishTest() {
279
- if (!this.options.restart && this.isRunning) return this.browser.quit()
280
- }
281
-
282
- async _withinBegin(locator) {
283
- withinStore.elFn = this.browser.findElement
284
- withinStore.elsFn = this.browser.findElements
285
-
286
- const frame = isFrameLocator(locator)
287
-
288
- if (frame) {
289
- if (Array.isArray(frame)) {
290
- withinStore.frame = frame.join('>')
291
- return this.switchTo(null).then(() =>
292
- frame.reduce((p, frameLocator) => p.then(() => this.switchTo(frameLocator)), Promise.resolve()),
293
- )
294
- }
295
- withinStore.frame = frame
296
- return this.switchTo(locator)
297
- }
298
-
299
- this.context = locator
300
- const context = await global.element(guessLocator(locator) || global.by.css(locator))
301
- if (!context) throw new ElementNotFound(locator)
302
-
303
- this.browser.findElement = (l) => (l ? context.element(l).getWebElement() : context.getWebElement())
304
- this.browser.findElements = (l) => context.all(l).getWebElements()
305
- return context
306
- }
307
-
308
- async _withinEnd() {
309
- if (!isWithin()) return
310
- if (withinStore.frame) {
311
- withinStore = {}
312
- return this.switchTo(null)
313
- }
314
- this.browser.findElement = withinStore.elFn
315
- this.browser.findElements = withinStore.elsFn
316
- withinStore = {}
317
- this.context = this.options.rootElement
318
- }
319
-
320
- _session() {
321
- const defaultSession = this.browser
322
- return {
323
- start: async (opts) => {
324
- opts = this._validateConfig(Object.assign(this.options, opts))
325
- this.debugSection('New Browser', JSON.stringify(opts))
326
- const runner = new Runner(opts)
327
- const res = await this.browser.executeScript('return [window.outerWidth, window.outerHeight]')
328
- const browser = runner.createBrowser(null, this.browser)
329
- await browser.ready
330
- await browser.waitForAngularEnabled(this.insideAngular)
331
- await browser.manage().window().setSize(parseInt(res[0], 10), parseInt(res[1], 10))
332
- return browser.ready
333
- },
334
- stop: async (browser) => {
335
- return browser.close()
336
- },
337
- loadVars: async (browser) => {
338
- if (isWithin()) throw new Error("Can't start session inside within block")
339
- this.browser = browser
340
- loadGlobals(this.browser)
341
- },
342
- restoreVars: async () => {
343
- if (isWithin()) await this._withinEnd()
344
- this.browser = defaultSession
345
- loadGlobals(this.browser)
346
- },
347
- }
348
- }
349
-
350
- /**
351
- * Use [Protractor](https://www.protractortest.org/#/api) API inside a test.
352
- *
353
- * First argument is a description of an action.
354
- * Second argument is async function that gets this helper as parameter.
355
- *
356
- * { [`browser`](https://www.protractortest.org/#/api?view=ProtractorBrowser)) } object from Protractor API is available.
357
- *
358
- * ```js
359
- * I.useProtractorTo('change url via in-page navigation', async ({ browser }) {
360
- * await browser.setLocation('api');
361
- * });
362
- * ```
363
- *
364
- * @param {string} description used to show in logs.
365
- * @param {function} fn async functuion that executed with Protractor helper as argument
366
- */
367
- useProtractorTo(description, fn) {
368
- return this._useTo(...arguments)
369
- }
370
-
371
- /**
372
- * Switch to non-Angular mode,
373
- * start using WebDriver instead of Protractor in this session
374
- */
375
- async amOutsideAngularApp() {
376
- if (!this.browser) return
377
- await this.browser.waitForAngularEnabled(false)
378
- return Promise.resolve((this.insideAngular = false))
379
- }
380
-
381
- /**
382
- * Enters Angular mode (switched on by default)
383
- * Should be used after "amOutsideAngularApp"
384
- */
385
- async amInsideAngularApp() {
386
- await this.browser.waitForAngularEnabled(true)
387
- return Promise.resolve((this.insideAngular = true))
388
- }
389
-
390
- /**
391
- * Get elements by different locator types, including strict locator
392
- * Should be used in custom helpers:
393
- *
394
- * ```js
395
- * this.helpers['Protractor']._locate({name: 'password'}).then //...
396
- * ```
397
- * To use SmartWait and wait for element to appear on a page, add `true` as second arg:
398
- *
399
- * ```js
400
- * this.helpers['Protractor']._locate({name: 'password'}, true).then //...
401
- * ```
402
- *
403
- */
404
- async _locate(locator, smartWait = false) {
405
- return this._smartWait(() => this.browser.findElements(guessLocator(locator) || global.by.css(locator)), smartWait)
406
- }
407
-
408
- async _smartWait(fn, enabled = true) {
409
- if (!this.options.smartWait || !enabled) return fn()
410
- await this.browser.manage().timeouts().implicitlyWait(this.options.smartWait)
411
- const res = await fn()
412
- await this.browser.manage().timeouts().implicitlyWait(0)
413
- return res
414
- }
415
-
416
- /**
417
- * Find a checkbox by providing human readable text:
418
- *
419
- * ```js
420
- * this.helpers['Protractor']._locateCheckable('I agree with terms and conditions').then // ...
421
- * ```
422
- */
423
- async _locateCheckable(locator) {
424
- return findCheckable.call(this, this.browser, locator)
425
- }
426
-
427
- /**
428
- * Find a clickable element by providing human readable text:
429
- *
430
- * ```js
431
- * this.helpers['Protractor']._locateClickable('Next page').then // ...
432
- * ```
433
- */
434
- async _locateClickable(locator) {
435
- return findClickable.call(this, this.browser, locator)
436
- }
437
-
438
- /**
439
- * Find field elements by providing human readable text:
440
- *
441
- * ```js
442
- * this.helpers['Protractor']._locateFields('Your email').then // ...
443
- * ```
444
- */
445
- async _locateFields(locator) {
446
- return findFields.call(this, this.browser, locator)
447
- }
448
-
449
- /**
450
- * {{> amOnPage }}
451
- */
452
- async amOnPage(url) {
453
- if (!/^\w+\:\/\//.test(url)) {
454
- url = this.options.url + url
455
- }
456
- const res = await this.browser.get(url)
457
- this.debug(`Visited ${url}`)
458
- return res
459
- }
460
-
461
- /**
462
- * {{> click }}
463
- */
464
- async click(locator, context = null) {
465
- let matcher = this.browser
466
- if (context) {
467
- const els = await this._locate(context, true)
468
- assertElementExists(els, context)
469
- matcher = els[0]
470
- }
471
- const el = await findClickable.call(this, matcher, locator)
472
- return el.click()
473
- }
474
-
475
- /**
476
- * {{> doubleClick }}
477
- */
478
- async doubleClick(locator, context = null) {
479
- let matcher = this.browser
480
- if (context) {
481
- const els = await this._locate(context, true)
482
- assertElementExists(els, context)
483
- matcher = els[0]
484
- }
485
- const el = await findClickable.call(this, matcher, locator)
486
- return this.browser.actions().doubleClick(el).perform()
487
- }
488
-
489
- /**
490
- * {{> rightClick }}
491
- */
492
- async rightClick(locator, context = null) {
493
- /**
494
- * just press button if no selector is given
495
- */
496
- if (locator === undefined) {
497
- return this.browser.actions().click(Button.RIGHT).perform()
498
- }
499
- let matcher = this.browser
500
- if (context) {
501
- const els = await this._locate(context, true)
502
- assertElementExists(els, context)
503
- matcher = els[0]
504
- }
505
- const el = await findClickable.call(this, matcher, locator)
506
-
507
- await this.browser.actions().mouseMove(el).perform()
508
- return this.browser.actions().click(Button.RIGHT).perform()
509
- }
510
-
511
- /**
512
- * {{> moveCursorTo }}
513
- */
514
- async moveCursorTo(locator, offsetX = null, offsetY = null) {
515
- let offset = null
516
- if (offsetX !== null || offsetY !== null) {
517
- offset = { x: offsetX, y: offsetY }
518
- }
519
- const els = await this._locate(locator, true)
520
- assertElementExists(els, locator)
521
- return this.browser.actions().mouseMove(els[0], offset).perform()
522
- }
523
-
524
- /**
525
- * {{> see }}
526
- */
527
- async see(text, context = null) {
528
- return proceedSee.call(this, 'assert', text, context)
529
- }
530
-
531
- /**
532
- * {{> seeTextEquals }}
533
- */
534
- async seeTextEquals(text, context = null) {
535
- return proceedSee.call(this, 'assert', text, context, true)
536
- }
537
-
538
- /**
539
- * {{> dontSee }}
540
- */
541
- dontSee(text, context = null) {
542
- return proceedSee.call(this, 'negate', text, context)
543
- }
544
-
545
- /**
546
- * {{> grabBrowserLogs }}
547
- */
548
- async grabBrowserLogs() {
549
- return this.browser.manage().logs().get('browser')
550
- }
551
-
552
- /**
553
- * {{> grabCurrentUrl }}
554
- */
555
- async grabCurrentUrl() {
556
- return this.browser.getCurrentUrl()
557
- }
558
-
559
- /**
560
- * {{> selectOption }}
561
- */
562
- async selectOption(select, option) {
563
- const fields = await findFields(this.browser, select)
564
- assertElementExists(fields, select, 'Selectable field')
565
- if (!Array.isArray(option)) {
566
- option = [option]
567
- }
568
- const field = fields[0]
569
- const promises = []
570
- for (const key in option) {
571
- const opt = xpathLocator.literal(option[key])
572
- let els = await field.findElements(global.by.xpath(Locator.select.byVisibleText(opt)))
573
- if (!els.length) {
574
- els = await field.findElements(global.by.xpath(Locator.select.byValue(opt)))
575
- }
576
- els.forEach((el) => promises.push(el.click()))
577
- }
578
-
579
- return Promise.all(promises)
580
- }
581
-
582
- /**
583
- * {{> fillField }}
584
- */
585
- async fillField(field, value) {
586
- const els = await findFields(this.browser, field)
587
- await els[0].clear()
588
- return els[0].sendKeys(value.toString())
589
- }
590
-
591
- /**
592
- * {{> pressKey }}
593
- * {{ keys }}
594
- */
595
- async pressKey(key) {
596
- let modifier
597
- if (Array.isArray(key) && ~['Control', 'Command', 'Shift', 'Alt'].indexOf(key[0])) {
598
- modifier = Key[key[0].toUpperCase()]
599
- key = key[1]
600
- }
601
-
602
- // guess special key in Selenium Webdriver list
603
- if (Key[key.toUpperCase()]) {
604
- key = Key[key.toUpperCase()]
605
- }
606
-
607
- const action = this.browser.actions()
608
- if (modifier) action.keyDown(modifier)
609
- action.sendKeys(key)
610
- if (modifier) action.keyUp(modifier)
611
- return action.perform()
612
- }
613
-
614
- /**
615
- * {{> attachFile }}
616
- */
617
- async attachFile(locator, pathToFile) {
618
- const file = path.join(global.codecept_dir, pathToFile)
619
- if (!fileExists(file)) {
620
- throw new Error(`File at ${file} can not be found on local system`)
621
- }
622
- const els = await findFields(this.browser, locator)
623
- assertElementExists(els, locator, 'Field')
624
- if (this.options.browser !== 'phantomjs') {
625
- const remote = require('selenium-webdriver/remote')
626
- this.browser.setFileDetector(new remote.FileDetector())
627
- }
628
- return els[0].sendKeys(file)
629
- }
630
-
631
- /**
632
- * {{> seeInField }}
633
- */
634
- async seeInField(field, value) {
635
- const _value = typeof value === 'boolean' ? value : value.toString()
636
- return proceedSeeInField.call(this, 'assert', field, _value)
637
- }
638
-
639
- /**
640
- * {{> dontSeeInField }}
641
- */
642
- async dontSeeInField(field, value) {
643
- const _value = typeof value === 'boolean' ? value : value.toString()
644
- return proceedSeeInField.call(this, 'negate', field, _value)
645
- }
646
-
647
- /**
648
- * {{> appendField }}
649
- */
650
- async appendField(field, value) {
651
- const els = await findFields(this.browser, field)
652
- assertElementExists(els, field, 'Field')
653
- return els[0].sendKeys(value.toString())
654
- }
655
-
656
- /**
657
- * {{> clearField }}
658
- */
659
- async clearField(field) {
660
- const els = await findFields(this.browser, field)
661
- assertElementExists(els, field, 'Field')
662
- return els[0].clear()
663
- }
664
-
665
- /**
666
- * {{> checkOption }}
667
- */
668
- async checkOption(field, context = null) {
669
- let matcher = this.browser
670
- if (context) {
671
- const els = await this._locate(context, true)
672
- assertElementExists(els, context)
673
- matcher = els[0]
674
- }
675
- const els = await findCheckable(matcher, field)
676
- assertElementExists(els, field, 'Checkbox or radio')
677
- const isSelected = await els[0].isSelected()
678
- if (!isSelected) return els[0].click()
679
- }
680
-
681
- /**
682
- * {{> uncheckOption }}
683
- */
684
- async uncheckOption(field, context = null) {
685
- let matcher = this.browser
686
- if (context) {
687
- const els = await this._locate(context, true)
688
- assertElementExists(els, context)
689
- matcher = els[0]
690
- }
691
- const els = await findCheckable(matcher, field)
692
- assertElementExists(els, field, 'Checkbox or radio')
693
- const isSelected = await els[0].isSelected()
694
- if (isSelected) return els[0].click()
695
- }
696
-
697
- /**
698
- * {{> seeCheckboxIsChecked }}
699
- */
700
- async seeCheckboxIsChecked(field) {
701
- return proceedIsChecked.call(this, 'assert', field)
702
- }
703
-
704
- /**
705
- * {{> dontSeeCheckboxIsChecked }}
706
- */
707
- async dontSeeCheckboxIsChecked(field) {
708
- return proceedIsChecked.call(this, 'negate', field)
709
- }
710
-
711
- /**
712
- * {{> grabTextFromAll }}
713
- */
714
- async grabTextFromAll(locator) {
715
- const els = await this._locate(locator)
716
- const texts = []
717
- for (const el of els) {
718
- texts.push(await el.getText())
719
- }
720
- return texts
721
- }
722
-
723
- /**
724
- * {{> grabTextFrom }}
725
- */
726
- async grabTextFrom(locator) {
727
- const texts = await this.grabTextFromAll(locator)
728
- assertElementExists(texts, locator)
729
- if (texts.length > 1) {
730
- this.debugSection('GrabText', `Using first element out of ${texts.length}`)
731
- }
732
-
733
- return texts[0]
734
- }
735
-
736
- /**
737
- * {{> grabHTMLFromAll }}
738
- */
739
- async grabHTMLFromAll(locator) {
740
- const els = await this._locate(locator)
741
-
742
- const html = await Promise.all(
743
- els.map((el) => {
744
- return this.browser.executeScript('return arguments[0].innerHTML;', el)
745
- }),
746
- )
747
-
748
- return html
749
- }
750
-
751
- /**
752
- * {{> grabHTMLFrom }}
753
- */
754
- async grabHTMLFrom(locator) {
755
- const html = await this.grabHTMLFromAll(locator)
756
- assertElementExists(html, locator)
757
- if (html.length > 1) {
758
- this.debugSection('GrabHTMl', `Using first element out of ${html.length}`)
759
- }
760
-
761
- return html[0]
762
- }
763
-
764
- /**
765
- * {{> grabValueFromAll }}
766
- */
767
- async grabValueFromAll(locator) {
768
- const els = await findFields(this.browser, locator)
769
- const values = await Promise.all(els.map((el) => el.getAttribute('value')))
770
-
771
- return values
772
- }
773
-
774
- /**
775
- * {{> grabValueFrom }}
776
- */
777
- async grabValueFrom(locator) {
778
- const values = await this.grabValueFromAll(locator)
779
- assertElementExists(values, locator, 'Field')
780
- if (values.length > 1) {
781
- this.debugSection('GrabValue', `Using first element out of ${values.length}`)
782
- }
783
-
784
- return values[0]
785
- }
786
-
787
- /**
788
- * {{> grabCssPropertyFromAll }}
789
- */
790
- async grabCssPropertyFromAll(locator, cssProperty) {
791
- const els = await this._locate(locator, true)
792
- const values = await Promise.all(els.map((el) => el.getCssValue(cssProperty)))
793
-
794
- return values
795
- }
796
-
797
- /**
798
- * {{> grabCssPropertyFrom }}
799
- */
800
- async grabCssPropertyFrom(locator, cssProperty) {
801
- const cssValues = await this.grabCssPropertyFromAll(locator, cssProperty)
802
- assertElementExists(cssValues, locator)
803
-
804
- if (cssValues.length > 1) {
805
- this.debugSection('GrabCSS', `Using first element out of ${cssValues.length}`)
806
- }
807
-
808
- return cssValues[0]
809
- }
810
-
811
- /**
812
- * {{> grabAttributeFromAll }}
813
- */
814
- async grabAttributeFromAll(locator, attr) {
815
- const els = await this._locate(locator)
816
- const array = []
817
-
818
- for (let index = 0; index < els.length; index++) {
819
- const el = els[index]
820
- array.push(await el.getAttribute(attr))
821
- }
822
- return array
823
- }
824
-
825
- /**
826
- * {{> grabAttributeFrom }}
827
- */
828
- async grabAttributeFrom(locator, attr) {
829
- const attrs = await this.grabAttributeFromAll(locator, attr)
830
- assertElementExists(attrs, locator)
831
- if (attrs.length > 1) {
832
- this.debugSection('GrabAttribute', `Using first element out of ${attrs.length}`)
833
- }
834
-
835
- return attrs[0]
836
- }
837
-
838
- /**
839
- * {{> seeInTitle }}
840
- */
841
- async seeInTitle(text) {
842
- return this.browser.getTitle().then((title) => stringIncludes('web page title').assert(text, title))
843
- }
844
-
845
- /**
846
- * {{> seeTitleEquals }}
847
- */
848
- async seeTitleEquals(text) {
849
- const title = await this.browser.getTitle()
850
- return equals('web page title').assert(title, text)
851
- }
852
-
853
- /**
854
- * {{> dontSeeInTitle }}
855
- */
856
- async dontSeeInTitle(text) {
857
- return this.browser.getTitle().then((title) => stringIncludes('web page title').negate(text, title))
858
- }
859
-
860
- /**
861
- * {{> grabTitle }}
862
- */
863
- async grabTitle() {
864
- return this.browser.getTitle().then((title) => {
865
- this.debugSection('Title', title)
866
- return title
867
- })
868
- }
869
-
870
- /**
871
- * {{> seeElement }}
872
- */
873
- async seeElement(locator) {
874
- let els = await this._locate(locator, true)
875
- els = await Promise.all(els.map((el) => el.isDisplayed()))
876
- return empty('elements').negate(els.filter((v) => v).fill('ELEMENT'))
877
- }
878
-
879
- /**
880
- * {{> dontSeeElement }}
881
- */
882
- async dontSeeElement(locator) {
883
- let els = await this._locate(locator, false)
884
- els = await Promise.all(els.map((el) => el.isDisplayed()))
885
- return empty('elements').assert(els.filter((v) => v).fill('ELEMENT'))
886
- }
887
-
888
- /**
889
- * {{> seeElementInDOM }}
890
- */
891
- async seeElementInDOM(locator) {
892
- return this.browser
893
- .findElements(guessLocator(locator) || global.by.css(locator))
894
- .then((els) => empty('elements').negate(els.fill('ELEMENT')))
895
- }
896
-
897
- /**
898
- * {{> dontSeeElementInDOM }}
899
- */
900
- async dontSeeElementInDOM(locator) {
901
- return this.browser
902
- .findElements(guessLocator(locator) || global.by.css(locator))
903
- .then((els) => empty('elements').assert(els.fill('ELEMENT')))
904
- }
905
-
906
- /**
907
- * {{> seeInSource }}
908
- */
909
- async seeInSource(text) {
910
- return this.browser.getPageSource().then((source) => stringIncludes('HTML source of a page').assert(text, source))
911
- }
912
-
913
- /**
914
- * {{> grabSource }}
915
- */
916
- async grabSource() {
917
- return this.browser.getPageSource()
918
- }
919
-
920
- /**
921
- * {{> dontSeeInSource }}
922
- */
923
- async dontSeeInSource(text) {
924
- return this.browser.getPageSource().then((source) => stringIncludes('HTML source of a page').negate(text, source))
925
- }
926
-
927
- /**
928
- * {{> seeNumberOfElements }}
929
- */
930
- async seeNumberOfElements(locator, num) {
931
- const elements = await this._locate(locator)
932
- return equals(
933
- `expected number of elements (${new Locator(locator)}) is ${num}, but found ${elements.length}`,
934
- ).assert(elements.length, num)
935
- }
936
-
937
- /**
938
- * {{> seeNumberOfVisibleElements }}
939
- */
940
- async seeNumberOfVisibleElements(locator, num) {
941
- const res = await this.grabNumberOfVisibleElements(locator)
942
- return equals(`expected number of visible elements (${new Locator(locator)}) is ${num}, but found ${res}`).assert(
943
- res,
944
- num,
945
- )
946
- }
947
-
948
- /**
949
- * {{> grabNumberOfVisibleElements }}
950
- */
951
- async grabNumberOfVisibleElements(locator) {
952
- let els = await this._locate(locator)
953
- els = await Promise.all(els.map((el) => el.isDisplayed()))
954
- return els.length
955
- }
956
-
957
- /**
958
- * {{> seeCssPropertiesOnElements }}
959
- */
960
- async seeCssPropertiesOnElements(locator, cssProperties) {
961
- const els = await this._locate(locator)
962
- assertElementExists(els, locator)
963
-
964
- const cssPropertiesCamelCase = convertCssPropertiesToCamelCase(cssProperties)
965
-
966
- const attributeNames = Object.keys(cssPropertiesCamelCase)
967
- const expectedValues = attributeNames.map((name) => cssPropertiesCamelCase[name])
968
- const missingAttributes = []
969
-
970
- for (const el of els) {
971
- const attributeValues = await Promise.all(attributeNames.map((attr) => el.getCssValue(attr)))
972
-
973
- const missing = attributeValues.filter((actual, i) => {
974
- const prop = attributeNames[i]
975
- let propValue = actual
976
- if (isColorProperty(prop) && propValue) {
977
- propValue = convertColorToRGBA(propValue)
978
- }
979
- return propValue !== expectedValues[i]
980
- })
981
- if (missing.length) {
982
- missingAttributes.push(...missing)
983
- }
984
- }
985
- return equals(
986
- `all elements (${new Locator(locator)}) to have CSS property ${JSON.stringify(cssProperties)}`,
987
- ).assert(missingAttributes.length, 0)
988
- }
989
-
990
- /**
991
- * {{> seeAttributesOnElements }}
992
- */
993
- async seeAttributesOnElements(locator, attributes) {
994
- const els = await this._locate(locator)
995
- assertElementExists(els, locator)
996
-
997
- const attributeNames = Object.keys(attributes)
998
- const expectedValues = attributeNames.map((name) => attributes[name])
999
- const missingAttributes = []
1000
-
1001
- for (const el of els) {
1002
- const attributeValues = await Promise.all(attributeNames.map((attr) => el.getAttribute(attr)))
1003
- const missing = attributeValues.filter((actual, i) => {
1004
- if (expectedValues[i] instanceof RegExp) {
1005
- return expectedValues[i].test(actual)
1006
- }
1007
- return actual !== expectedValues[i]
1008
- })
1009
- if (missing.length) {
1010
- missingAttributes.push(...missing)
1011
- }
1012
- }
1013
-
1014
- return equals(`all elements (${new Locator(locator)}) to have attributes ${JSON.stringify(attributes)}`).assert(
1015
- missingAttributes.length,
1016
- 0,
1017
- )
1018
- }
1019
-
1020
- /**
1021
- * {{> executeScript }}
1022
- */
1023
- async executeScript() {
1024
- return this.browser.executeScript.apply(this.browser, arguments)
1025
- }
1026
-
1027
- /**
1028
- * {{> executeAsyncScript }}
1029
- */
1030
- async executeAsyncScript() {
1031
- this.browser.manage().timeouts().setScriptTimeout(this.options.scriptTimeout)
1032
- return this.browser.executeAsyncScript.apply(this.browser, arguments)
1033
- }
1034
-
1035
- /**
1036
- * {{> seeInCurrentUrl }}
1037
- */
1038
- async seeInCurrentUrl(url) {
1039
- return this.browser.getCurrentUrl().then((currentUrl) => stringIncludes('url').assert(url, currentUrl))
1040
- }
1041
-
1042
- /**
1043
- * {{> dontSeeInCurrentUrl }}
1044
- */
1045
- async dontSeeInCurrentUrl(url) {
1046
- return this.browser.getCurrentUrl().then((currentUrl) => stringIncludes('url').negate(url, currentUrl))
1047
- }
1048
-
1049
- /**
1050
- * {{> seeCurrentUrlEquals }}
1051
- */
1052
- async seeCurrentUrlEquals(url) {
1053
- return this.browser.getCurrentUrl().then((currentUrl) => urlEquals(this.options.url).assert(url, currentUrl))
1054
- }
1055
-
1056
- /**
1057
- * {{> dontSeeCurrentUrlEquals }}
1058
- */
1059
- async dontSeeCurrentUrlEquals(url) {
1060
- return this.browser.getCurrentUrl().then((currentUrl) => urlEquals(this.options.url).negate(url, currentUrl))
1061
- }
1062
-
1063
- /**
1064
- * {{> saveElementScreenshot }}
1065
- *
1066
- */
1067
- async saveElementScreenshot(locator, fileName) {
1068
- const outputFile = screenshotOutputFolder(fileName)
1069
-
1070
- const writeFile = (png, outputFile) => {
1071
- const fs = require('fs')
1072
- const stream = fs.createWriteStream(outputFile)
1073
- stream.write(Buffer.from(png, 'base64'))
1074
- stream.end()
1075
- return new Promise((resolve) => stream.on('finish', resolve)) // eslint-disable-line no-promise-executor-return
1076
- }
1077
-
1078
- const res = await this._locate(locator)
1079
- assertElementExists(res, locator)
1080
- if (res.length > 1) this.debug(`[Elements] Using first element out of ${res.length}`)
1081
- const elem = res[0]
1082
- this.debug(`Screenshot of ${new Locator(locator)} element has been saved to ${outputFile}`)
1083
- const png = await elem.takeScreenshot()
1084
- return writeFile(png, outputFile)
1085
- }
1086
-
1087
- /**
1088
- * {{> saveScreenshot }}
1089
- */
1090
- async saveScreenshot(fileName, fullPage = false) {
1091
- const outputFile = screenshotOutputFolder(fileName)
1092
-
1093
- const writeFile = (png, outputFile) => {
1094
- const fs = require('fs')
1095
- const stream = fs.createWriteStream(outputFile)
1096
- stream.write(Buffer.from(png, 'base64'))
1097
- stream.end()
1098
- return new Promise((resolve) => stream.on('finish', resolve)) // eslint-disable-line no-promise-executor-return
1099
- }
1100
-
1101
- if (!fullPage) {
1102
- this.debug(`Screenshot has been saved to ${outputFile}`)
1103
- const png = await this.browser.takeScreenshot()
1104
- return writeFile(png, outputFile)
1105
- }
1106
-
1107
- let { width, height } = await this.browser.executeScript(() => ({
1108
- height: document.body.scrollHeight,
1109
- width: document.body.scrollWidth,
1110
- }))
1111
-
1112
- if (height < 100) height = 500
1113
-
1114
- await this.browser.manage().window().setSize(width, height)
1115
- this.debug(`Screenshot has been saved to ${outputFile}, size: ${width}x${height}`)
1116
- const png = await this.browser.takeScreenshot()
1117
- return writeFile(png, outputFile)
1118
- }
1119
-
1120
- /**
1121
- * {{> clearCookie }}
1122
- */
1123
- async clearCookie(cookie = null) {
1124
- if (!cookie) {
1125
- return this.browser.manage().deleteAllCookies()
1126
- }
1127
- return this.browser.manage().deleteCookie(cookie)
1128
- }
1129
-
1130
- /**
1131
- * {{> seeCookie }}
1132
- */
1133
- async seeCookie(name) {
1134
- return this.browser
1135
- .manage()
1136
- .getCookie(name)
1137
- .then((res) => truth(`cookie ${name}`, 'to be set').assert(res))
1138
- }
1139
-
1140
- /**
1141
- * {{> dontSeeCookie }}
1142
- */
1143
- async dontSeeCookie(name) {
1144
- return this.browser
1145
- .manage()
1146
- .getCookie(name)
1147
- .then((res) => truth(`cookie ${name}`, 'to be set').negate(res))
1148
- }
1149
-
1150
- /**
1151
- * {{> grabCookie }}
1152
- *
1153
- * Returns cookie in JSON [format](https://code.google.com/p/selenium/wiki/JsonWireProtocol#Cookie_JSON_Object).
1154
- */
1155
- async grabCookie(name) {
1156
- if (!name) return this.browser.manage().getCookies()
1157
- return this.browser.manage().getCookie(name)
1158
- }
1159
-
1160
- /**
1161
- * Accepts the active JavaScript native popup window, as created by window.alert|window.confirm|window.prompt.
1162
- * Don't confuse popups with modal windows, as created by [various
1163
- * libraries](http://jster.net/category/windows-modals-popups). Appium: support only web testing
1164
- */
1165
- async acceptPopup() {
1166
- return this.browser.switchTo().alert().accept()
1167
- }
1168
-
1169
- /**
1170
- * Dismisses the active JavaScript popup, as created by window.alert|window.confirm|window.prompt.
1171
- */
1172
- async cancelPopup() {
1173
- return this.browser.switchTo().alert().dismiss()
1174
- }
1175
-
1176
- /**
1177
- * {{> seeInPopup }}
1178
- */
1179
- async seeInPopup(text) {
1180
- const popupAlert = await this.browser.switchTo().alert()
1181
- const res = await popupAlert.getText()
1182
- if (res === null) {
1183
- throw new Error('Popup is not opened')
1184
- }
1185
- stringIncludes('text in popup').assert(text, res)
1186
- }
1187
-
1188
- /**
1189
- * Grab the text within the popup. If no popup is visible then it will return null
1190
- *
1191
- * ```js
1192
- * await I.grabPopupText();
1193
- * ```
1194
- */
1195
- async grabPopupText() {
1196
- try {
1197
- const dialog = await this.browser.switchTo().alert()
1198
-
1199
- if (dialog) {
1200
- return dialog.getText()
1201
- }
1202
- } catch (e) {
1203
- if (e.message.match(/no.*?(alert|modal)/i)) {
1204
- // Don't throw an error
1205
- return null
1206
- }
1207
- throw e
1208
- }
1209
- }
1210
-
1211
- /**
1212
- * {{> resizeWindow }}
1213
- */
1214
- async resizeWindow(width, height) {
1215
- if (width === 'maximize') {
1216
- const res = await this.browser.executeScript('return [screen.width, screen.height]')
1217
- return this.browser.manage().window().setSize(parseInt(res[0], 10), parseInt(res[1], 10))
1218
- }
1219
- return this.browser.manage().window().setSize(parseInt(width, 10), parseInt(height, 10))
1220
- }
1221
-
1222
- /**
1223
- * {{> dragAndDrop }}
1224
- */
1225
- async dragAndDrop(srcElement, destElement) {
1226
- const srcEl = await this._locate(srcElement, true)
1227
- const destEl = await this._locate(destElement, true)
1228
- assertElementExists(srcEl, srcElement)
1229
- assertElementExists(destEl, destElement)
1230
- return this.browser.actions().dragAndDrop(srcEl[0], destEl[0]).perform()
1231
- }
1232
-
1233
- /**
1234
- * Close all tabs except for the current one.
1235
- *
1236
- * ```js
1237
- * I.closeOtherTabs();
1238
- * ```
1239
- */
1240
- async closeOtherTabs() {
1241
- const client = this.browser
1242
-
1243
- const handles = await client.getAllWindowHandles()
1244
- const currentHandle = await client.getWindowHandle()
1245
- const otherHandles = handles.filter((handle) => handle !== currentHandle)
1246
-
1247
- if (!otherHandles || !otherHandles.length) return
1248
- let p = Promise.resolve()
1249
- otherHandles.forEach((handle) => {
1250
- p = p.then(() =>
1251
- client
1252
- .switchTo()
1253
- .window(handle)
1254
- .then(() => client.close()),
1255
- )
1256
- })
1257
- p = p.then(() => client.switchTo().window(currentHandle))
1258
- return p
1259
- }
1260
-
1261
- /**
1262
- * Close current tab
1263
- *
1264
- * ```js
1265
- * I.closeCurrentTab();
1266
- * ```
1267
- */
1268
- async closeCurrentTab() {
1269
- const client = this.browser
1270
-
1271
- const currentHandle = await client.getWindowHandle()
1272
- const nextHandle = await this._getWindowHandle(-1)
1273
-
1274
- await client.switchTo().window(currentHandle)
1275
- await client.close()
1276
- return client.switchTo().window(nextHandle)
1277
- }
1278
-
1279
- /**
1280
- * Get the window handle relative to the current handle. i.e. the next handle or the previous.
1281
- * @param {Number} offset Offset from current handle index. i.e. offset < 0 will go to the previous handle and positive number will go to the next window handle in sequence.
1282
- */
1283
- async _getWindowHandle(offset = 0) {
1284
- const client = this.browser
1285
- const handles = await client.getAllWindowHandles()
1286
- const index = handles.indexOf(await client.getWindowHandle())
1287
- const nextIndex = index + offset
1288
-
1289
- return handles[nextIndex]
1290
- // return handles[(index + offset) % handles.length];
1291
- }
1292
-
1293
- /**
1294
- * Open new tab and switch to it
1295
- *
1296
- * ```js
1297
- * I.openNewTab();
1298
- * ```
1299
- */
1300
- async openNewTab() {
1301
- const client = this.browser
1302
- await this.executeScript('window.open("about:blank")')
1303
- const handles = await client.getAllWindowHandles()
1304
- await client.switchTo().window(handles[handles.length - 1])
1305
- }
1306
-
1307
- /**
1308
- * Switch focus to a particular tab by its number. It waits tabs loading and then switch tab
1309
- *
1310
- * ```js
1311
- * I.switchToNextTab();
1312
- * I.switchToNextTab(2);
1313
- * ```
1314
- */
1315
- async switchToNextTab(num = 1) {
1316
- const client = this.browser
1317
- const newHandle = await this._getWindowHandle(num)
1318
-
1319
- if (!newHandle) {
1320
- throw new Error(`There is no ability to switch to next tab with offset ${num}`)
1321
- }
1322
- return client.switchTo().window(newHandle)
1323
- }
1324
-
1325
- /**
1326
- * Switch focus to a particular tab by its number. It waits tabs loading and then switch tab
1327
- *
1328
- * ```js
1329
- * I.switchToPreviousTab();
1330
- * I.switchToPreviousTab(2);
1331
- * ```
1332
- */
1333
- async switchToPreviousTab(num = 1) {
1334
- const client = this.browser
1335
- const newHandle = await this._getWindowHandle(-1 * num)
1336
-
1337
- if (!newHandle) {
1338
- throw new Error(`There is no ability to switch to previous tab with offset ${num}`)
1339
- }
1340
- return client.switchTo().window(newHandle)
1341
- }
1342
-
1343
- /**
1344
- * {{> grabNumberOfOpenTabs }}
1345
- */
1346
- async grabNumberOfOpenTabs() {
1347
- const pages = await this.browser.getAllWindowHandles()
1348
- return pages.length
1349
- }
1350
-
1351
- /**
1352
- * {{> switchTo }}
1353
- */
1354
- async switchTo(locator) {
1355
- if (Number.isInteger(locator)) {
1356
- return this.browser.switchTo().frame(locator)
1357
- }
1358
- if (!locator) {
1359
- return this.browser.switchTo().frame(null)
1360
- }
1361
-
1362
- const els = await this._locate(withStrictLocator.call(this, locator), true)
1363
- assertElementExists(els, locator)
1364
- return this.browser.switchTo().frame(els[0])
1365
- }
1366
-
1367
- /**
1368
- * {{> wait }}
1369
- */
1370
- wait(sec) {
1371
- return this.browser.sleep(sec * 1000)
1372
- }
1373
-
1374
- /**
1375
- * {{> waitForElement }}
1376
- */
1377
- async waitForElement(locator, sec = null) {
1378
- const aSec = sec || this.options.waitForTimeoutInSeconds
1379
- const el = global.element(guessLocator(locator) || global.by.css(locator))
1380
- return this.browser.wait(EC.presenceOf(el), aSec * 1000)
1381
- }
1382
-
1383
- async waitUntilExists(locator, sec = null) {
1384
- console.log(`waitUntilExists deprecated:
1385
- * use 'waitForElement' to wait for element to be attached
1386
- * use 'waitForDetached to wait for element to be removed'`)
1387
- return this.waitForDetached(locator, sec)
1388
- }
1389
-
1390
- /**
1391
- * {{> waitForDetached }}
1392
- */
1393
- async waitForDetached(locator, sec = null) {
1394
- const aSec = sec || this.options.waitForTimeoutInSeconds
1395
- const el = global.element(guessLocator(locator) || global.by.css(locator))
1396
- return this.browser.wait(EC.not(EC.presenceOf(el)), aSec * 1000).catch((err) => {
1397
- if (err.message && err.message.indexOf('Wait timed out after') > -1) {
1398
- throw new Error(`element (${JSON.stringify(locator)}) still on page after ${sec} sec`)
1399
- } else throw err
1400
- })
1401
- }
1402
-
1403
- /**
1404
- * Waits for element to become clickable for number of seconds.
1405
- *
1406
- * ```js
1407
- * I.waitForClickable('#link');
1408
- * ```
1409
- */
1410
- async waitForClickable(locator, sec = null) {
1411
- const aSec = sec || this.options.waitForTimeoutInSeconds
1412
- const el = global.element(guessLocator(locator) || global.by.css(locator))
1413
- return this.browser.wait(EC.elementToBeClickable(el), aSec * 1000)
1414
- }
1415
-
1416
- /**
1417
- * {{> waitForVisible }}
1418
- */
1419
- async waitForVisible(locator, sec = null) {
1420
- const aSec = sec || this.options.waitForTimeoutInSeconds
1421
- const el = global.element(guessLocator(locator) || global.by.css(locator))
1422
- return this.browser.wait(EC.visibilityOf(el), aSec * 1000)
1423
- }
1424
-
1425
- /**
1426
- * {{> waitToHide }}
1427
- */
1428
- async waitToHide(locator, sec = null) {
1429
- return this.waitForInvisible(locator, sec)
1430
- }
1431
-
1432
- /**
1433
- * {{> waitForInvisible }}
1434
- */
1435
- async waitForInvisible(locator, sec = null) {
1436
- const aSec = sec || this.options.waitForTimeoutInSeconds
1437
- const el = global.element(guessLocator(locator) || global.by.css(locator))
1438
- return this.browser.wait(EC.invisibilityOf(el), aSec * 1000)
1439
- }
1440
-
1441
- async waitForStalenessOf(locator, sec = null) {
1442
- console.log(`waitForStalenessOf deprecated.
1443
- * Use waitForDetached to wait for element to be removed from page
1444
- * Use waitForInvisible to wait for element to be hidden on page`)
1445
- return this.waitForInvisible(locator, sec)
1446
- }
1447
-
1448
- /**
1449
- * {{> waitNumberOfVisibleElements }}
1450
- */
1451
- async waitNumberOfVisibleElements(locator, num, sec = null) {
1452
- function visibilityCountOf(loc, expectedCount) {
1453
- return function () {
1454
- return global.element
1455
- .all(loc)
1456
- .filter((el) => el.isDisplayed())
1457
- .count()
1458
- .then((count) => count === expectedCount)
1459
- }
1460
- }
1461
-
1462
- const aSec = sec || this.options.waitForTimeoutInSeconds
1463
- const guessLoc = guessLocator(locator) || global.by.css(locator)
1464
-
1465
- return this.browser.wait(visibilityCountOf(guessLoc, num), aSec * 1000).catch(() => {
1466
- throw Error(`The number of elements (${new Locator(locator)}) is not ${num} after ${aSec} sec`)
1467
- })
1468
- }
1469
-
1470
- /**
1471
- * {{> waitForEnabled }}
1472
- */
1473
- async waitForEnabled(locator, sec = null) {
1474
- const aSec = sec || this.options.waitForTimeoutInSeconds
1475
- const el = global.element(guessLocator(locator) || global.by.css(locator))
1476
-
1477
- return this.browser.wait(EC.elementToBeClickable(el), aSec * 1000).catch(() => {
1478
- throw Error(`element (${new Locator(locator)}) still not enabled after ${aSec} sec`)
1479
- })
1480
- }
1481
-
1482
- /**
1483
- * {{> waitForValue }}
1484
- */
1485
- async waitForValue(field, value, sec = null) {
1486
- const aSec = sec || this.options.waitForTimeoutInSeconds
1487
-
1488
- const valueToBeInElementValue = (loc) => {
1489
- return async () => {
1490
- const els = await findFields(this.browser, loc)
1491
-
1492
- if (!els) {
1493
- return false
1494
- }
1495
- const values = await Promise.all(els.map((el) => el.getAttribute('value')))
1496
- return values.filter((part) => part.indexOf(value) >= 0).length > 0
1497
- }
1498
- }
1499
-
1500
- return this.browser.wait(valueToBeInElementValue(field, value), aSec * 1000).catch(() => {
1501
- throw Error(
1502
- `element (${field}) is not in DOM or there is no element(${field}) with value "${value}" after ${aSec} sec`,
1503
- )
1504
- })
1505
- }
1506
-
1507
- /**
1508
- * {{> waitForFunction }}
1509
- */
1510
- async waitForFunction(fn, argsOrSec = null, sec = null) {
1511
- let args = []
1512
- if (argsOrSec) {
1513
- if (Array.isArray(argsOrSec)) {
1514
- args = argsOrSec
1515
- } else if (typeof argsOrSec === 'number') {
1516
- sec = argsOrSec
1517
- }
1518
- }
1519
-
1520
- const aSec = sec || this.options.waitForTimeoutInSeconds
1521
- return this.browser.wait(() => this.browser.executeScript.call(this.browser, fn, ...args), aSec * 1000)
1522
- }
1523
-
1524
- /**
1525
- * {{> waitInUrl }}
1526
- */
1527
- async waitInUrl(urlPart, sec = null) {
1528
- const aSec = sec || this.options.waitForTimeoutInSeconds
1529
- const waitTimeout = aSec * 1000
1530
-
1531
- return this.browser.wait(EC.urlContains(urlPart), waitTimeout).catch(async (e) => {
1532
- const currUrl = await this.browser.getCurrentUrl()
1533
- if (/wait timed out after/i.test(e.message)) {
1534
- throw new Error(`expected url to include ${urlPart}, but found ${currUrl}`)
1535
- } else {
1536
- throw e
1537
- }
1538
- })
1539
- }
1540
-
1541
- /**
1542
- * {{> waitUrlEquals }}
1543
- */
1544
- async waitUrlEquals(urlPart, sec = null) {
1545
- const aSec = sec || this.options.waitForTimeoutInSeconds
1546
- const waitTimeout = aSec * 1000
1547
- const baseUrl = this.options.url
1548
- if (urlPart.indexOf('http') < 0) {
1549
- urlPart = baseUrl + urlPart
1550
- }
1551
-
1552
- return this.browser.wait(EC.urlIs(urlPart), waitTimeout).catch(async (e) => {
1553
- const currUrl = await this.browser.getCurrentUrl()
1554
- if (/wait timed out after/i.test(e.message)) {
1555
- throw new Error(`expected url to be ${urlPart}, but found ${currUrl}`)
1556
- } else {
1557
- throw e
1558
- }
1559
- })
1560
- }
1561
-
1562
- /**
1563
- * {{> waitForText }}
1564
- */
1565
- async waitForText(text, sec = null, context = null) {
1566
- if (!context) {
1567
- context = this.context
1568
- }
1569
- const el = global.element(guessLocator(context) || global.by.css(context))
1570
- const aSec = sec || this.options.waitForTimeoutInSeconds
1571
- return this.browser.wait(EC.textToBePresentInElement(el, text), aSec * 1000)
1572
- }
1573
-
1574
- // ANGULAR SPECIFIC
1575
-
1576
- /**
1577
- * Moves to url
1578
- */
1579
- moveTo(path) {
1580
- return this.browser.setLocation(path)
1581
- }
1582
-
1583
- /**
1584
- * {{> refreshPage }}
1585
- */
1586
- refreshPage() {
1587
- return this.browser.refresh()
1588
- }
1589
-
1590
- /**
1591
- * Reloads page
1592
- */
1593
- refresh() {
1594
- console.log('Deprecated in favor of refreshPage')
1595
- return this.browser.refresh()
1596
- }
1597
-
1598
- /**
1599
- * {{> scrollTo }}
1600
- */
1601
- async scrollTo(locator, offsetX = 0, offsetY = 0) {
1602
- if (typeof locator === 'number' && typeof offsetX === 'number') {
1603
- offsetY = offsetX
1604
- offsetX = locator
1605
- locator = null
1606
- }
1607
-
1608
- if (locator) {
1609
- const res = await this._locate(locator, true)
1610
- if (!res || res.length === 0) {
1611
- return truth(`elements of ${new Locator(locator)}`, 'to be seen').assert(false)
1612
- }
1613
- const elem = res[0]
1614
- const location = await elem.getLocation()
1615
-
1616
- return this.executeScript(
1617
- function (x, y) {
1618
- return window.scrollTo(x, y)
1619
- },
1620
- location.x + offsetX,
1621
- location.y + offsetY,
1622
- )
1623
- }
1624
-
1625
- return this.executeScript(
1626
- function (x, y) {
1627
- return window.scrollTo(x, y)
1628
- },
1629
- offsetX,
1630
- offsetY,
1631
- )
1632
- }
1633
-
1634
- /**
1635
- * {{> scrollPageToTop }}
1636
- */
1637
- async scrollPageToTop() {
1638
- return this.executeScript('window.scrollTo(0, 0);')
1639
- }
1640
-
1641
- /**
1642
- * {{> scrollPageToBottom }}
1643
- */
1644
- async scrollPageToBottom() {
1645
- return this.executeScript(function () {
1646
- const body = document.body
1647
- const html = document.documentElement
1648
- window.scrollTo(
1649
- 0,
1650
- Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight),
1651
- )
1652
- })
1653
- }
1654
-
1655
- /**
1656
- * {{> grabPageScrollPosition }}
1657
- */
1658
- async grabPageScrollPosition() {
1659
- function getScrollPosition() {
1660
- return {
1661
- x: window.pageXOffset,
1662
- y: window.pageYOffset,
1663
- }
1664
- }
1665
-
1666
- return this.executeScript(getScrollPosition)
1667
- }
1668
-
1669
- /**
1670
- * Injects Angular module.
1671
- *
1672
- * ```js
1673
- * I.haveModule('modName', function() {
1674
- * angular.module('modName', []).value('foo', 'bar');
1675
- * });
1676
- * ```
1677
- */
1678
- haveModule(modName, fn) {
1679
- return this.browser.addMockModule(modName, fn)
1680
- }
1681
-
1682
- /**
1683
- * Removes mocked Angular module. If modName not specified - clears all mock modules.
1684
- *
1685
- * ```js
1686
- * I.resetModule(); // clears all
1687
- * I.resetModule('modName');
1688
- * ```
1689
- */
1690
- resetModule(modName) {
1691
- if (!modName) {
1692
- return this.browser.clearMockModules()
1693
- }
1694
- return this.browser.removeMockModule(modName)
1695
- }
1696
-
1697
- /**
1698
- * {{> setCookie }}
1699
- */
1700
- setCookie(cookie) {
1701
- return this.browser.manage().addCookie(cookie)
1702
- }
1703
- }
1704
-
1705
- module.exports = Protractor
1706
-
1707
- async function findCheckable(client, locator) {
1708
- const matchedLocator = guessLocator(locator)
1709
- if (matchedLocator) {
1710
- return client.findElements(matchedLocator)
1711
- }
1712
- const literal = xpathLocator.literal(locator)
1713
- let els = await client.findElements(global.by.xpath(Locator.checkable.byText(literal)))
1714
- if (els.length) {
1715
- return els
1716
- }
1717
- els = await client.findElements(global.by.xpath(Locator.checkable.byName(literal)))
1718
- if (els.length) {
1719
- return els
1720
- }
1721
- return client.findElements(global.by.css(locator))
1722
- }
1723
-
1724
- function withStrictLocator(locator) {
1725
- locator = new Locator(locator)
1726
- if (locator.isAccessibilityId()) return withAccessiblitiyLocator.call(this, locator.value)
1727
- return locator.simplify()
1728
- }
1729
-
1730
- function withAccessiblitiyLocator(locator) {
1731
- if (this.isWeb === false) {
1732
- return `accessibility id:${locator.slice(1)}`
1733
- }
1734
- return `[aria-label="${locator.slice(1)}"]`
1735
- // hook before webdriverio supports native ~ locators in web
1736
- }
1737
-
1738
- async function findFields(client, locator) {
1739
- const matchedLocator = guessLocator(locator)
1740
- if (matchedLocator) {
1741
- return client.findElements(matchedLocator)
1742
- }
1743
- const literal = xpathLocator.literal(locator)
1744
-
1745
- let els = await client.findElements(global.by.xpath(Locator.field.labelEquals(literal)))
1746
- if (els.length) {
1747
- return els
1748
- }
1749
-
1750
- els = await client.findElements(global.by.xpath(Locator.field.labelContains(literal)))
1751
- if (els.length) {
1752
- return els
1753
- }
1754
- els = await client.findElements(global.by.xpath(Locator.field.byName(literal)))
1755
- if (els.length) {
1756
- return els
1757
- }
1758
- return client.findElements(global.by.css(locator))
1759
- }
1760
-
1761
- async function proceedSee(assertType, text, context) {
1762
- let description
1763
- let locator
1764
- if (!context) {
1765
- if (this.context === this.options.rootElement) {
1766
- locator = guessLocator(this.context) || global.by.css(this.context)
1767
- description = 'web application'
1768
- } else {
1769
- // inside within block
1770
- locator = global.by.xpath('.//*')
1771
- description = `current context ${new Locator(context).toString()}`
1772
- }
1773
- } else {
1774
- locator = guessLocator(context) || global.by.css(context)
1775
- description = `element ${new Locator(context).toString()}`
1776
- }
1777
- const enableSmartWait = !!this.context && assertType === 'assert'
1778
- const els = await this._smartWait(() => this.browser.findElements(locator), enableSmartWait)
1779
- const promises = []
1780
- let source = ''
1781
- els.forEach((el) => promises.push(el.getText().then((elText) => (source += `| ${elText}`))))
1782
- await Promise.all(promises)
1783
- return stringIncludes(description)[assertType](text, source)
1784
- }
1785
-
1786
- async function proceedSeeInField(assertType, field, value) {
1787
- const els = await findFields(this.browser, field)
1788
- assertElementExists(els, field, 'Field')
1789
- const el = els[0]
1790
- const tag = await el.getTagName()
1791
- const fieldVal = await el.getAttribute('value')
1792
- if (tag === 'select') {
1793
- // locate option by values and check them
1794
- const literal = xpathLocator.literal(fieldVal)
1795
- const textEl = await el.findElement(global.by.xpath(Locator.select.byValue(literal)))
1796
- const text = await textEl.getText()
1797
- return equals(`select option by ${field}`)[assertType](value, text)
1798
- }
1799
- return stringIncludes(`field by ${field}`)[assertType](value, fieldVal)
1800
- }
1801
-
1802
- async function proceedIsChecked(assertType, option) {
1803
- const els = await findCheckable(this.browser, option)
1804
- assertElementExists(els, option, 'Option')
1805
- const elsSelected = []
1806
- els.forEach((el) => elsSelected.push(el.isSelected()))
1807
- const values = await Promise.all(elsSelected)
1808
- const selected = values.reduce((prev, cur) => prev || cur)
1809
- return truth(`checkable ${option}`, 'to be checked')[assertType](selected)
1810
- }
1811
-
1812
- async function findClickable(matcher, locator) {
1813
- locator = new Locator(locator)
1814
- if (!locator.isFuzzy()) {
1815
- const els = await this._locate(locator, true)
1816
- assertElementExists(els, locator.value)
1817
- return els[0]
1818
- }
1819
- const literal = xpathLocator.literal(locator.value)
1820
- const narrowLocator = Locator.clickable.narrow(literal)
1821
- let els = await matcher.findElements(global.by.xpath(narrowLocator))
1822
- if (els.length) {
1823
- return els[0]
1824
- }
1825
-
1826
- els = await matcher.findElements(global.by.xpath(Locator.clickable.wide(literal)))
1827
- if (els.length) {
1828
- return els[0]
1829
- }
1830
- return matcher.findElement(global.by.css(locator.value))
1831
- }
1832
-
1833
- function guessLocator(locator) {
1834
- const l = new Locator(locator)
1835
- if (l.isFuzzy()) return false
1836
- if (l.type) return global.by[l.type](l.value)
1837
- return false
1838
- }
1839
-
1840
- function assertElementExists(res, locator, prefix, suffix) {
1841
- if (!res.length) {
1842
- throw new ElementNotFound(locator, prefix, suffix)
1843
- }
1844
- }
1845
-
1846
- function isFrameLocator(locator) {
1847
- locator = new Locator(locator)
1848
- if (locator.isFrame()) return locator.value
1849
- return false
1850
- }
1851
-
1852
- function isWithin() {
1853
- return Object.keys(withinStore).length !== 0
1854
- }
1855
-
1856
- function loadGlobals(browser) {
1857
- global.browser = browser
1858
- global.$ = browser.$
1859
- global.$$ = browser.$$
1860
- global.element = browser.element
1861
- global.by = global.By = new ProtractorBy()
1862
- global.ExpectedConditions = EC = new ProtractorExpectedConditions(browser)
1863
- }