Skip to content

Commit 4cbedee

Browse files
reubenmillerDavertMik
authored andcommitted
[Puppeteer] Use default tab instead of opening a new tab when starting the browser and new helper function I.grabNumberOfTabs (codeceptjs#918)
* [WebDriverIO] Added support for nested iframes in the within block * Added the @Nightmare tags to the extended nested iframe tests * Modified default window size because the a few tab tests were failing because the clickable element was not visible. * Added acceptance tests for the within feature for both WebDriverIO and Nightmare * Updated expected window height in webapi tests due to changing it in a previous commit * Fixed initial window size in the SeleniumWebdriver and Nightmare Helpers so it matches with the tests now * Change the example with nested iframes in the docs so it shows the full use of within for the sake of consistency * merged from upstream branch * Init. commit for adding iframe support to the puppeteer helper along with acceptance tests * Adding I.switchTo and iframe array support in within blocks * Minor fix when accessing the current context. When it is an element then the current page is used * Merged nightmare and webdriverio helper files from the upstream master * Updated contribution.md to include the new puppeteer acceptance tests * Refactoring/cleanup before creating a pull request * Updated docker config to work with the puppeteer tests * Updated docs to include the new information about iframes with puppeteer * [Rest] Removed conversion of the body to a json formatted string in the HTTP Requests (codeceptjs#779) * Removed some comments and logic that is obsolete due to new support for within blocks and iframes * [Puppeteer]: WIP: Adding support for I.acceptPopup, I.dismissPopup and I.seeInPopup * [Puppeteer] Refactoring closeCurrentTab because it was failing sometimes due to a timing issue. Now the page object is first switch before closing the page. This error was picked up in the ci tests * Adding function headers and refactoring some func names * Adding support for dialog interactions include the default handling of dialogs when they occur * Remove assert when grabbing text from the popup and changed the references to dialog to popup, and dimiss to cancel (except for the function calls and in the listener * Added delay before interacting with the popup in Puppeteer * [WebDriverIO] Added new function I.grabPopupText() to get the text in the popup without throwing an error if it does not exist. * Added missing Puppeteer test options from codecept master * Removed invalid references to Appium and moved the Popupstore class to a seperate file * Fixing silent bug in Puppeteer where calling I.switchToNextTab and I.switchToPreviousTab would not throw an error if the index did not exist, because the index catered for array wrapping. The test was failing silently because there was not an explicit error being thrown in the case when no exception is thrown by the I.switchToNextTab function * [Protractor] Added support for I.openNewTab, I.switchToNextTab, I.switchToPreviousTab, I.closeCurrentTab and refactoring of I.closeOtherTabs * Added check if the url is chrome's special data:, url. When detected then the localstorage won't be cleared, because this page does not have any localstorage, thus causing an exception * [Protractor] Replaced explicit setting of ignoreSynchronization with a call to browser.waitForAngularEnabled() function which was introduced in Protractor 5.x * [Protractor|Puppeteer|WebDriverIO] Added I.closeOtherTabs and missing tests. Also fixed a type in the doc string * [WebDriverIO|Puppeteer|Protractor] Added support for I.grabSource across the three helpers and added missing tests * [Puppeteer] Added I.seeNumberOfElements * [Protractor] Added I.seeNumberOfElements and tests * Changed assertion error message to use double quotes around parameters so it matches the include.js assertion style. * Adding the Error.message so the message can be accessed in the tests. Before the .message property was an empty string, i.e. '' * [Puppeteer|WebDriverIO|Protractor] Adding I.seeTitleEquals across the Helpers * [Puppeteer|Protractor] Adding support for I.seeTextEquals * [Puppeteer] Extending support of _locateCheckable, I.seeInField and I.dontSeeInField. Corrections were required to the functions after adding all of the tests from WebDriverIO. * [Puppeteer] Adding support for _locateFields * [Puppeteer] Adding support for _locateClickable * [Puppeteer] Adding I.scrollPageToTop and I.scrollPageToBottom * Removed reference to Appium * [Pupppeteer] Adding support for I.waitInUrl and I.waitUrlEquals * [Puppeteer|Nightmare] Added support for I.waitForInvisible * [Puppeteer] Added support for I.seeNumberOfVisibleElements and I.seeNumberOfVisibleElements * Removed reference to Appium in Puppeteer helper * [Puppeteer] Added support for I.grabCssPropertyFrom * [Puppeteer] Added support for I.grabHTMLFrom * [Pupppeteer] Added support for I.seeCssPropertiesOnElements. * [Puppeteer] Added support for I.seeAttributesOnElements and changed I.grabAttributeFrom to have the same behaviour as I.seeAttributesOnElements * [Puppeteer] Added support for I.rightClick * [Mochawesome] Added null checking in _before hook which caused the codeceptjs shell mode to fail. Fixes codeceptjs#896 * [Puppeteer] Added support for I.grabBrowserLogs, and added tests for both Puppeteer and WebDriverIO * [docs] Added option about supporting the --invert option with --grep * [WebDriverIO] Fixing resizeWindow when resizing to 'maximize' which was previously not working. Also added unit test * [Puppeteer] Performing the decodeUrl manually rather than by passing the function in. The function serialization wasn't working for some reason * [WebDriverIO] Changed all arrow functions in webdriverio .execute calls so that it is compatible with older Internet Explorer versions. * [WebDriverIO] Fixed lint issue in tests * [Puppeteer] Fixed I.seeTextEquals function and test. The test was passing when it shouldn't have. Added strict matching option in proceedSee so it aligns with the behaviour in the WebDriverIO helper * [WebDriverIO] Fixing test case for I.seeTextEquals. The catch block was not triggered. Now there is an explicit error to force the assertion in the catch block in case if the expected exception is not thrown (i.e. due to an error in the I.seeTextEquals function it self which causes a false positive * [WebDriverIO] Refactoring how promises are resolved. Instead of resolving promises in parallel, now everything is done in serial. Reason being is that the tests were very flakey because random 'The connection was reset' or 'Invalid argument' errors were occuring. After some research it appears that the issue is with the chromedriver and too many parallel requests [https://bugs.chromium.org/p/chromedriver/issues/detail?id=2152#c9]. Now the tests are a lot more stable! * [WebDriverIO] Removing some debug console statements, and set retries to 0, in order to highlight flakey tests quicker so they can be fixed * [WebDriverIO] Refactoring async filter and foreach functions and proceedSeeField * [Puppeteer] Refactoring proceedSeeInField * [Puppeteer] Refactoring proceedSeeInField * [Puppeteer] Added support for I.dragAndDrop and offset support in I.moveCursorTo * [Puppeteer] Added support for I.scrollTo (though there are no tests yet) * [WebDriverIO] Changed test retries to 1 * [Puppeteer|WebDriverIO|Protractor] Added new I.grabNumberOfTabs function * [Puppeteer] Don't create a new page when launching the browser for the first time because a tab already exists. Fixes codeceptjs#908 * Moved I.grabNumberOfOpenTabs doc string to a common grabNumberOfOpenTabs.mustache doc file
1 parent 30c9369 commit 4cbedee

File tree

7 files changed

+135
-29
lines changed

7 files changed

+135
-29
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Grab number of open tabs
2+
3+
```js
4+
I.grabNumberOfOpenTabs();
5+
```

lib/helper/Protractor.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -874,6 +874,14 @@ class Protractor extends Helper {
874874
return client.switchTo().window(newHandle);
875875
}
876876

877+
/**
878+
* {{> ../webapi/grabNumberOfOpenTabs }}
879+
*/
880+
async grabNumberOfOpenTabs() {
881+
const pages = await this.browser.getAllWindowHandles();
882+
return pages.length;
883+
}
884+
877885
/**
878886
* {{> ../webapi/wait }}
879887
*/

lib/helper/Puppeteer.js

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -216,23 +216,31 @@ class Puppeteer extends Helper {
216216

217217
async _startBrowser() {
218218
this.browser = await puppeteer.launch(this.puppeteerOptions);
219-
this.browser.on('targetcreated', (target) => {
220-
target.page().then((page) => {
221-
if (!page) return;
222-
this.withinLocator = null;
223-
page.on('load', frame => this.context = page.$('body'));
224-
page.on('console', (msg) => {
225-
this.debugSection(msg.type(), msg.args().join(' '));
226-
consoleLogStore.add(msg);
227-
});
219+
const targetCreatedHandler = (page) => {
220+
if (!page) return;
221+
this.withinLocator = null;
222+
page.on('load', frame => this.context = page.$('body'));
223+
page.on('console', (msg) => {
224+
this.debugSection(msg.type(), msg.args().join(' '));
225+
consoleLogStore.add(msg);
228226
});
227+
};
228+
this.browser.on('targetcreated', (target) => {
229+
target.page().then(page => targetCreatedHandler(page));
229230
});
230231

231232
this.browser.on('targetchanged', (target) => {
232233
this.debugSection('Url', target.url());
233234
});
234235

235-
this._setPage(await this.browser.newPage());
236+
const existingPages = await this.browser.pages();
237+
const mainPage = existingPages[0] || await this.browser.newPage();
238+
239+
if (existingPages.length) {
240+
// Run the handler as it will not be triggered if the page already exists
241+
targetCreatedHandler(mainPage);
242+
}
243+
this._setPage(mainPage);
236244

237245
if (this.options.windowSize && this.options.windowSize.indexOf('x') > 0) {
238246
const dimensions = this.options.windowSize.split('x');
@@ -552,7 +560,8 @@ class Puppeteer extends Helper {
552560
async closeCurrentTab() {
553561
const oldPage = this.page;
554562
await this.switchToPreviousTab();
555-
return oldPage.close();
563+
await oldPage.close();
564+
return this._waitForAction();
556565
}
557566

558567
/**
@@ -570,7 +579,8 @@ class Puppeteer extends Helper {
570579
otherPages.forEach((page) => {
571580
p = p.then(() => page.close());
572581
});
573-
return p;
582+
await p;
583+
return this._waitForAction();
574584
}
575585

576586
/**
@@ -582,6 +592,15 @@ class Puppeteer extends Helper {
582592
*/
583593
async openNewTab() {
584594
this._setPage(await this.browser.newPage());
595+
return this._waitForAction();
596+
}
597+
598+
/**
599+
* {{> ../webapi/grabNumberOfOpenTabs }}
600+
*/
601+
async grabNumberOfOpenTabs() {
602+
const pages = await this.browser.pages();
603+
return pages.length;
585604
}
586605

587606
/**

lib/helper/WebDriverIO.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1701,6 +1701,13 @@ class WebDriverIO extends Helper {
17011701
return client.newWindow('about:blank');
17021702
}
17031703

1704+
/**
1705+
* {{> ../webapi/grabNumberOfOpenTabs }}
1706+
*/
1707+
async grabNumberOfOpenTabs() {
1708+
const pages = await this.browser.getTabIds();
1709+
return pages.length;
1710+
}
17041711

17051712
/**
17061713
* {{> ../webapi/refreshPage }}

test/helper/Protractor_test.js

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -380,8 +380,14 @@ describe('Protractor', function () {
380380
});
381381
});
382382

383-
describe('#switchToNextTab, #switchToPreviousTab, #openNewTab, #closeCurrentTab, #closeOtherTabs', () => {
383+
describe('#switchToNextTab, #switchToPreviousTab, #openNewTab, #closeCurrentTab, #closeOtherTabs, #grabNumberOfOpenTabs', () => {
384+
it('should only have 1 tab open when the browser starts and navigates to the first page', () => I.amOnPage('/')
385+
.then(() => I.grabNumberOfOpenTabs())
386+
.then(numPages => assert.equal(numPages, 1)));
387+
384388
it('should switch to next tab', () => I.amOnPage('/')
389+
.then(() => I.grabNumberOfOpenTabs())
390+
.then(numPages => assert.equal(numPages, 1))
385391
.then(() => I.click('Get More Options'))
386392
.then(() => I.seeCurrentUrlEquals('/#/options'))
387393
.then(() => I.openNewTab())
@@ -391,7 +397,9 @@ describe('Protractor', function () {
391397
.then(() => I.switchToPreviousTab())
392398
.then(() => I.seeCurrentUrlEquals('/#/options'))
393399
.then(() => I.switchToNextTab())
394-
.then(() => I.seeCurrentUrlEquals('/#/info')));
400+
.then(() => I.seeCurrentUrlEquals('/#/info'))
401+
.then(() => I.grabNumberOfOpenTabs())
402+
.then(numPages => assert.equal(numPages, 2)));
395403

396404
it('should assert when there is no ability to switch to next tab', () => I.amOnPage('/')
397405
.then(() => I.click('Get More Options'))
@@ -414,10 +422,14 @@ describe('Protractor', function () {
414422
.then(() => I.seeInCurrentUrl('#/info'))
415423
.then(() => I.openNewTab())
416424
.then(() => I.amOnPage('/'))
425+
.then(() => I.grabNumberOfOpenTabs())
426+
.then(numPages => assert.equal(numPages, 2))
417427
.then(() => I.seeInCurrentUrl('#/'))
418428
.then(() => I.dontSeeInCurrentUrl('#/info'))
419429
.then(() => I.closeCurrentTab())
420-
.then(() => I.seeInCurrentUrl('#/info')));
430+
.then(() => I.seeInCurrentUrl('#/info'))
431+
.then(() => I.grabNumberOfOpenTabs())
432+
.then(numPages => assert.equal(numPages, 1)));
421433

422434
it('should close other tabs', () => I.amOnPage('/')
423435
.then(() => I.click('Get more info!'))
@@ -426,15 +438,23 @@ describe('Protractor', function () {
426438
.then(() => I.amOnPage('/'))
427439
.then(() => I.openNewTab())
428440
.then(() => I.amOnPage('/'))
441+
.then(() => I.grabNumberOfOpenTabs())
442+
.then(numPages => assert.equal(numPages, 3))
429443
.then(() => I.click('Get More Options'))
430444
.then(() => I.seeCurrentUrlEquals('/#/options'))
431445
.then(() => I.closeOtherTabs())
432-
.then(() => I.seeCurrentUrlEquals('/#/options')));
446+
.then(() => I.seeCurrentUrlEquals('/#/options'))
447+
.then(() => I.grabNumberOfOpenTabs())
448+
.then(numPages => assert.equal(numPages, 1)));
433449

434450
it('should open new tab', () => I.amOnPage('/')
451+
.then(() => I.grabNumberOfOpenTabs())
452+
.then(numPages => assert.equal(numPages, 1))
435453
.then(() => I.openNewTab())
436454
.then(() => I.amOutsideAngularApp())
437-
.then(() => I.seeInCurrentUrl('about:blank')));
455+
.then(() => I.seeInCurrentUrl('about:blank'))
456+
.then(() => I.grabNumberOfOpenTabs())
457+
.then(numPages => assert.equal(numPages, 2)));
438458

439459
it('should switch to previous tab', () => I.amOnPage('/')
440460
.then(() => I.click('Get more info!'))
@@ -443,7 +463,6 @@ describe('Protractor', function () {
443463
.then(() => I.seeInCurrentUrl('/#/'))
444464
.then(() => I.switchToPreviousTab())
445465
.then(() => I.wait(2))
446-
447466
.then(() => I.seeInCurrentUrl('/#/info')));
448467
});
449468

test/helper/Puppeteer_test.js

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,14 +99,23 @@ describe('Puppeteer', function () {
9999
.then(() => I.dontSee('Hovered', '#show')));
100100
});
101101

102-
describe('#switchToNextTab, #switchToPreviousTab, #openNewTab, #closeCurrentTab, #closeOtherTabs', () => {
102+
describe('#switchToNextTab, #switchToPreviousTab, #openNewTab, #closeCurrentTab, #closeOtherTabs, #grabNumberOfOpenTabs', () => {
103+
it('should only have 1 tab open when the browser starts and navigates to the first page', () => I.amOnPage('/')
104+
.then(() => I.grabNumberOfOpenTabs())
105+
.then(numPages => assert.equal(numPages, 1)));
106+
103107
it('should switch to next tab', () => I.amOnPage('/info')
108+
.then(() => I.grabNumberOfOpenTabs())
109+
.then(numPages => assert.equal(numPages, 1))
104110
.then(() => I.click('New tab'))
105111
.then(() => I.switchToNextTab())
106-
.then(() => I.seeCurrentUrlEquals('/login')));
112+
.then(() => I.seeCurrentUrlEquals('/login'))
113+
.then(() => I.grabNumberOfOpenTabs())
114+
.then(numPages => assert.equal(numPages, 2)));
107115

108116
it('should assert when there is no ability to switch to next tab', () => I.amOnPage('/')
109117
.then(() => I.click('More info'))
118+
.then(() => I.wait(1)) // Wait is required because the url is change by previous statement (maybe related to #914)
110119
.then(() => I.switchToNextTab(2))
111120
.then(() => assert.equal(true, false, 'Throw an error if it gets this far (which it should not)!'))
112121
.catch((e) => {
@@ -117,8 +126,12 @@ describe('Puppeteer', function () {
117126
.then(() => I.click('New tab'))
118127
.then(() => I.switchToNextTab())
119128
.then(() => I.seeInCurrentUrl('/login'))
129+
.then(() => I.grabNumberOfOpenTabs())
130+
.then(numPages => assert.equal(numPages, 2))
120131
.then(() => I.closeCurrentTab())
121-
.then(() => I.seeInCurrentUrl('/info')));
132+
.then(() => I.seeInCurrentUrl('/info'))
133+
.then(() => I.grabNumberOfOpenTabs())
134+
.then(numPages => assert.equal(numPages, 1)));
122135

123136
it('should close other tabs', () => I.amOnPage('/')
124137
.then(() => I.openNewTab())
@@ -128,17 +141,30 @@ describe('Puppeteer', function () {
128141
.then(() => I.switchToNextTab())
129142
.then(() => I.seeInCurrentUrl('/login'))
130143
.then(() => I.closeOtherTabs())
131-
.then(() => I.seeInCurrentUrl('/login')));
144+
.then(() => I.seeInCurrentUrl('/login'))
145+
.then(() => I.grabNumberOfOpenTabs())
146+
.then(numPages => assert.equal(numPages, 1)));
132147

133148
it('should open new tab', () => I.amOnPage('/info')
134149
.then(() => I.openNewTab())
135-
.then(() => I.seeInCurrentUrl('about:blank')));
150+
.then(() => I.seeInCurrentUrl('about:blank'))
151+
.then(() => I.grabNumberOfOpenTabs())
152+
.then(numPages => assert.equal(numPages, 2)));
136153

137154
it('should switch to previous tab', () => I.amOnPage('/info')
138155
.then(() => I.openNewTab())
139156
.then(() => I.seeInCurrentUrl('about:blank'))
140157
.then(() => I.switchToPreviousTab())
141158
.then(() => I.seeInCurrentUrl('/info')));
159+
160+
it('should assert when there is no ability to switch to previous tab', () => I.amOnPage('/info')
161+
.then(() => I.openNewTab())
162+
.then(() => I.waitInUrl('about:blank'))
163+
.then(() => I.switchToPreviousTab(2))
164+
.then(() => I.waitInUrl('/info'))
165+
.catch((e) => {
166+
assert.equal(e.message, 'There is no ability to switch to previous tab with offset 2');
167+
}));
142168
});
143169

144170
describe('popup : #acceptPopup, #seeInPopup, #cancelPopup, #grabPopupText', () => {

test/helper/WebDriverIO_test.js

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -321,23 +321,39 @@ describe('WebDriverIO', function () {
321321
.then(() => wd.dontSee('Hovered', '#show')));
322322
});
323323

324-
describe('#switchToNextTab, #switchToPreviousTab, #openNewTab, #closeCurrentTab, #closeOtherTabs', () => {
324+
describe('#switchToNextTab, #switchToPreviousTab, #openNewTab, #closeCurrentTab, #closeOtherTabs, #grabNumberOfOpenTabs', () => {
325+
it('should only have 1 tab open when the browser starts and navigates to the first page', () => wd.amOnPage('/')
326+
.then(() => wd.grabNumberOfOpenTabs())
327+
.then(numPages => assert.equal(numPages, 1)));
328+
325329
it('should switch to next tab', () => wd.amOnPage('/info')
330+
.then(() => wd.grabNumberOfOpenTabs())
331+
.then(numPages => assert.equal(numPages, 1))
326332
.then(() => wd.click('New tab'))
327333
.then(() => wd.switchToNextTab())
328-
.then(() => wd.waitInUrl('/login')));
334+
.then(() => wd.waitInUrl('/login'))
335+
.then(() => wd.grabNumberOfOpenTabs())
336+
.then(numPages => assert.equal(numPages, 2)));
337+
329338
it('should assert when there is no ability to switch to next tab', () => wd.amOnPage('/')
330339
.then(() => wd.click('More info'))
340+
.then(() => wd.wait(1)) // Wait is required because the url is change by previous statement (maybe related to #914)
331341
.then(() => wd.switchToNextTab(2))
342+
.then(() => assert.equal(true, false, 'Throw an error if it gets this far (which it should not)!'))
332343
.catch((e) => {
333344
assert.equal(e.message, 'There is no ability to switch to next tab with offset 2');
334345
}));
346+
335347
it('should close current tab', () => wd.amOnPage('/info')
336348
.then(() => wd.click('New tab'))
337349
.then(() => wd.switchToNextTab())
338-
.then(() => wd.waitInUrl('/login'))
350+
.then(() => wd.seeInCurrentUrl('/login'))
351+
.then(() => wd.grabNumberOfOpenTabs())
352+
.then(numPages => assert.equal(numPages, 2))
339353
.then(() => wd.closeCurrentTab())
340-
.then(() => wd.waitInUrl('/info')));
354+
.then(() => wd.seeInCurrentUrl('/info'))
355+
.then(() => wd.grabNumberOfOpenTabs())
356+
.then(numPages => assert.equal(numPages, 1)));
341357

342358
it('should close other tabs', () => wd.amOnPage('/')
343359
.then(() => wd.openNewTab())
@@ -347,16 +363,22 @@ describe('WebDriverIO', function () {
347363
.then(() => wd.switchToNextTab())
348364
.then(() => wd.seeInCurrentUrl('/login'))
349365
.then(() => wd.closeOtherTabs())
350-
.then(() => wd.seeInCurrentUrl('/login')));
366+
.then(() => wd.seeInCurrentUrl('/login'))
367+
.then(() => wd.grabNumberOfOpenTabs())
368+
.then(numPages => assert.equal(numPages, 1)));
351369

352370
it('should open new tab', () => wd.amOnPage('/info')
353371
.then(() => wd.openNewTab())
354-
.then(() => wd.waitInUrl('about:blank')));
372+
.then(() => wd.waitInUrl('about:blank'))
373+
.then(() => wd.grabNumberOfOpenTabs())
374+
.then(numPages => assert.equal(numPages, 2)));
375+
355376
it('should switch to previous tab', () => wd.amOnPage('/info')
356377
.then(() => wd.openNewTab())
357378
.then(() => wd.waitInUrl('about:blank'))
358379
.then(() => wd.switchToPreviousTab())
359380
.then(() => wd.waitInUrl('/info')));
381+
360382
it('should assert when there is no ability to switch to previous tab', () => wd.amOnPage('/info')
361383
.then(() => wd.openNewTab())
362384
.then(() => wd.waitInUrl('about:blank'))

0 commit comments

Comments
 (0)