angrykoala / wendigo

A proper monster for front-end automated testing

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to handle another tab and/or popups

subiron opened this issue · comments

commented

Hi!
Is it possible to switch page context to the newly opened tab or popup window?
can't find it in the API.
For example:

                await browser.open("https://ch.viivexchange.com/login/");
                let selector="img[title=saml-swissrx]";
                await browser.waitFor(selector);
                const swissrxButton = await browser.query(selector);
                await browser.click(swissrxButton);
                ...

new popup window is shown after a click and it looks it is impossible to interact with it.

or another question is it possible to directly access underlying puppeter api?

Regards

Hi @subiron

It is possible to access the puppeteer page directly through browser.page, would this be enough or you need access to other parts of the puppeteer API?

If you feel there should be an easier way of doing this, please feel free to propose an interface for this case or an example (using wendigo or puppeteer) of what you plan to achieve.

commented

thanks for a quick response.
I was missing puppeteer's browser object but I can see now that page object has browser() method that returns original puppeteer-browser object.
nevertheless, I wanted to switch context to the popup page but also to keep the possibility to use wendigo API.
I endup with following solution:

let originalPage = browser.page; //temp copy for later use (switch back context)
let puppeteerBrowser = browser.page.browser(); // this part I was missing 

const popUpPagePromise = new Promise(x => puppeteerBrowser.once('targetcreated', target => x(target.page())));
await browser.click(swissrxButton); //button that will triger openning up of a popup (as a seperate window)
browser.page = await popUpPagePromise;// replace page object inside wendigo browser to use wendigo api for popUp scope
await browser.type("#Password", "blblblb"); //works in context of popup !
console.log(await browser.title() + "   " + await browser.url()); //title and url of a popup window !

// ok lets get back to out main page(/tab/window)
browser.page = originalPage;
console.log(await browser.title()) //back on original page

I'm worried if there are any consequences of replacing page object inside wendigo's browser object but for now, it looks that everything is working fine.

See here how it's done in puppeteer:
https://pocketadmin.tech/en/puppeteer-popup-window/

Well, there may be some unwanted side effects (some methods may not work as expected due to code injection made by wendigo), but it may be a reasonable workaround for now, I'll try and come up with a better solution for handling popups/tabs without having to rely on hacks.

Maybe a way to create a new WendigoBrowser with a custom context (a.k.a. page) or a "Popup handler" that contains reference to the targets created by the page

After some checks, to solve this there are two main issues that need to be addressed:

  • Provide an interface to get a browser tabs (and popups) through browser.pages() method.
  • On each targetcreated event, the whole wendigo setup (_afterPageLoad) must be called for the new page, this could substitute the current "on load" event used for normal links.

Proposed API:

  • browser.page return the current active page (a.k.a. tab) of the browser (works as before).
  • browser.pages return all pages.
  • browser.selectPage(index) to change active page
  • browser.close() should close all pages (works as before)
  • browser.closePage(index) should close the page with given index

Due to how puppeteer handles tabs, popups would be handled the same way as tabs

Things to discuss:

  • browser.browser returns the native Puppeteer browser -> naming may be confused, check alternatives to browser
  • Consider using browser.tab and browser.tabs instead of page/pages
  • browser.pageIndex should return the current page index (?)

Possible changes for v3.0 (breaking changes):

  • browser.page -> browser.currentPage or browser.activePage (maybe browser.currentTab?)
  • browser.page and browser.pages should be methods instead of getters
commented

If I may suggest 'browser' as the main object is confusing. I you say about renameing it to just 'wendigo'?
and then
wendigo.pages //[page1, page2...]
wendigo.browser// (puppeter browser)
wendigo.page /(current page)
wendigo.switchContext(pageIndex / page object/ promise)

Well, I agree in the possible confusion of the main name for wendigo's browser, however a few things:

  • Wendigo is already the main exported name
  • I consider Browser to be an intuitive name for common usage (browser.open() or browser.click() are quite self-explanatory)

In the end, this naming is mostly for docs, because it is a local variable you could easily use whatever you want e.g. const wendigo = Wendigo.createBrowser()

I'm actually thinking on using context as name for the Puppeteer native variable, as it will probably be a Context exported intead of a browser. (Due to how incognito works in Puppeteer, the internal variable used in wendigo is context insteadof browser)

The following methods will be added on Wendigo 2.5.0:

  • browser.pages() will return all the pages of the browser (tabs and popups)
  • browser.selectPage(index) changes the active page to the page with given index and reloads it
  • browser.closePage(index) closes the page with given index

These methods are still under revision and may change or behave unpredictably, but should be enough to gracefully solve your problem @subiron

In future issues I will address some improvements for these problems