Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[🐛 Bug]: Bug in newWindow makes hard to work with tabs and use functions such as switchWindow/switchToWindow/getWindowHandles #7619

Closed
2 tasks done
avikha opened this issue Oct 28, 2021 · 14 comments · Fixed by #7677

Comments

@avikha
Copy link

avikha commented Oct 28, 2021

WebdriverIO Version

7.16.3

Node.js Version

14.16

Mode

WDIO Testrunner

Which capabilities are you using?

browserName: chrome / chromium
browserVersion: 92
platform': linux / macos
automation protocol: devtools / puppeteer

What happened?

We find the wdio API dealing with tabs and window management slightly confusing and not working in the way it is supposed to.

We strongly believe that the problematic function is newWidow, which makes it hard to manage tabs and use other wdio APIs of switchWindow, switchToWindow, and getWindowHandles.

The first issue that find confusing is having two functions, switchWindiow and switchToWindow. They have similar names, basically responsible for the same functionality, but each has different arguments. It is probably better to have a single function that deals with switching windows/tabs.

From the perspective of business logic and automation functionality, we present many scripts with inconsistent/confusing results.

Problematic code examples

Example 1

it.only('', async () => {
    await browser.url('https://google.com');
    const _0 = await browser.getWindowHandle();
    const _1 = await browser.newWindow('https://espn.com');
    const _2 = await browser.newWindow('https://netflix.com');

    console.log({
        _0,
        _1,
        _2,
    });
    await browser.pause(5000);
});

We would expect it to have three different handles, but they are all the same. So we can spread await browser.wait(2000), which will have a different result between _0, _1 and _2, but still incorrect. It all leads to a place where we cant use the swithToWindow properly.

Example 2

it.only('', async () => {
    await browser.url('https://google.com');
    await browser.newWindow('https://www.si.com/', {
        windowName: 'si-window',
    });

    const siTitle = await browser.getTitle();
    console.log({ siTitle });
});

This one will result in

{ siTitle: 'Google' }

The above is true for the getTitle() function and other browser and element functions. This can be solved by adding await browser.pause(3000), and it seems that the page title and operations are correct after that.

Example 3

it.only('', async () => {
    await browser.url('https://google.com');

    await browser.newWindow('https://www.si.com/', {
        windowName: 'si-window',
    });

    await browser.newWindow('https://espn.com', {
        windowName: 'espn-window',
    });

    await browser.switchWindow('si-window');
    console.log(await browser.getTitle());

    await browser.switchWindow('espn-window');
    console.log(await browser.getTitle());
});

It also won't work. Most cases would end with an error message like

No window found with title, URL or name matching "si-window"

Or messages similar to that one. We've tried to spread some `pause's in different combinations, but it won't help much.

We have some more combinations of scripts, but most of them are going around the same point.

Our workaround and temporary solution

After many tries and retries, we came up with the following workaround that looks consistent. We present two solutions, one is trivial, and another is more elegant.

Trivial Solution - Using await browser.pause and await browser.getWindowHandle

async function newTab_firstTry(url: string): Promise<string> {
    await browser.newWindow(url);
    await browser.pause(3000);
    return browser.getWindowHandle();
}

it.only('', async () => {
    await browser.url('https://google.com');
    await browser.pause(3000);
    const google = await browser.getWindowHandle();

    const espn = await newTab_firstTry('https://www.espn.com');
    const si = await newTab_firstTry('https://www.si.com');
    const cnn = await newTab_firstTry('https://www.cnn.com');

    await browser.switchToWindow(google);
    console.log(await browser.getTitle());

    await browser.switchToWindow(espn);
    console.log(await browser.getTitle());

    await browser.switchToWindow(si);
    console.log(await browser.getTitle());

    await browser.switchToWindow(cnn);
    console.log(await browser.getTitle());

    console.log({
        google,
        espn,
        si,
        cnn,
    });
});

It seems to work fine and to produce the correct result. However, we are afraid of the hard-coded browser.pause and its dependency on it. Our experience shows us that using sleep's or pauses or explicit waits can result in flakiness on ci/cd.

The problem with this solution is that pause is manually hard-coded, and our intuition and experiments show us that the update of the getWindowHandles() list depends on the page (how heavy is the page we load) and

Elegant solution - proposal for newWindow update

async function waitForNewHandle() {
    const handlesBefore = await browser.getWindowHandles();
    getLogger().info(`Current handles [${handlesBefore.toString()}]`);

    await browser.waitUntil(
        async () => {
            const currentHandles = await browser.getWindowHandles();
            getLogger().info(
                `Current number of handles ${currentHandles.length}`
            );
            return currentHandles.length === handlesBefore.length + 1;
        },
        {
            timeout: 30000,
            timeoutMsg: `Expecting number of tabs to be ${
                handlesBefore.length + 1
            }, but it is ${handlesBefore.length}`,
            interval: 1000,
        }
    );
    getLogger().info('Done');
}

async function newTab_secondTry(url: string): Promise<string> {
    getLogger().info(`Opening new tab for: ${url}`);
    await browser.newWindow(url);
    await waitForNewHandle();
    return browser.getWindowHandle();
}

it.only('', async () => {
    await browser.url('https://google.com');
    await browser.pause(2000);

    const bbc = await newTab_secondTry('https://www.bbc.co.uk');
    const espn = await newTab_secondTry('https://www.espn.com');
    const si = await newTab_secondTry('https://www.si.com');
    const cnn = await newTab_secondTry('https://www.cnn.com');

    await browser.switchToWindow(bbc);
    console.log(await browser.getTitle());

    await browser.switchToWindow(espn);
    console.log(await browser.getTitle());

    await browser.switchToWindow(si);
    console.log(await browser.getTitle());

    await browser.switchToWindow(cnn);
    console.log(await browser.getTitle());

    console.log({
        bbc,
        espn,
        si,
        cnn,
    });
});

Our thoughts on the problem

We believe that the problem is due to synchronization issues between the node script and the browser. Our intuition tells us that the newWindow operation is an expensive one, and it takes the browser time to create a new tab, load the page and update the handles. Meanwhile, the newWindow operation is not waiting on the browser and now waiting for the update state. Hence, it returns a bad handle, and the function getWindowHandles() is also inconsistent.

We've checked the webdriverio code for how the newWindow function is implemented and we found out that the problem might occur in

await this.execute(newWindowHelper, url, windowName, windowFeatures)

const tabs = await this.getWindowHandles()
const newTab = tabs.pop()

The this.execute initiates the asynchronous window.open. The command of this.execute finishes while the asynchronous process of creating tab and loading page is still going on. Therefore, proceeding to this.getWindowHandles results in a place where wdio thinks that browser is done, but the browser is not done yet.

The question is, whether the proposed solution above is a good solution or perhaps the correct solution is to use devtools protocol and puppeteer. We were surprised to know that the newWindow uses window.open instead of using the puppeteer / selenium.

What is your expected behavior?

I wrote everything above.

How to reproduce the bug.

I wrote everything above.

Relevant log output

I wrote everything above.

Code of Conduct

  • I agree to follow this project's Code of Conduct

Is there an existing issue for this?

  • I have searched the existing issues
@avikha avikha added Bug 🐛 Needs Triaging ⏳ No one has looked into the issue yet labels Oct 28, 2021
@christian-bromann
Copy link
Member

First off, very well written issue, thanks for taking the time.

The first issue that find confusing is having two functions, switchWindiow and switchToWindow. They have similar names, basically responsible for the same functionality, but each has different arguments. It is probably better to have a single function that deals with switching windows/tabs.

One is a WebdriverIO command and the other is a protocol command. The WebdriverIO one has a special implementation and uses the protocol command. I don't thing it is a good idea to get rid of one as we need some extra logic to make switching windows easier but want to allow users to use the raw protocol command as well if desired.

The question is, whether the proposed solution above is a good solution or perhaps the correct solution is to use devtools protocol and puppeteer.

Wouldn't it improve the stability if we make a window handle check in the newWindow command? Similar to what you proposed in newTab_secondTry. Getting the handle through getWindowHandle requires WebDriver to switch to this new window which I am not 100% sure if this is defined in the protocol, so it could be different based by the browser.

We were surprised to know that the newWindow uses window.open instead of using the puppeteer / selenium.

WebdriverIO has two ways to automate the browser, via WebDriver protocol or through Puppeteer (read more on this in our docs). If you have Chromedriver or a any other arbitrary WebDriver running, you run through the WebDriver protocol and make requests to the driver. Here we run a script in the browser that opens the new tab. If you don't run any driver WebdriverIO falls back to Puppeteer and there we do essentially the same.

Another improvement I see here is instead of using JavaScript to open a new window we can just use the createWindow command that now allows to define tabs. This command has been added "recently" to the spec and should be available in all browser supporting W3C WebDriver.

What do you think. Would you be interested to take a stab?

@christian-bromann christian-bromann removed the Needs Triaging ⏳ No one has looked into the issue yet label Oct 28, 2021
@avikha
Copy link
Author

avikha commented Oct 30, 2021

Hey @christian-bromann, thanks for the quick response, and sorry for my late.

One is a WebdriverIO command and the other is a protocol command. The WebdriverIO one has a special implementation and uses the protocol command. I don't thing it is a good idea to get rid of one as we need some extra logic to make switching windows easier but want to allow users to use the raw protocol command as well if desired.

I see

It just wasn't obvious for us to understand the real differences without going to the source code. As a developer or automation engineer, it would've been more natural (or intuitive) to have:

  1. Many APIs for switching strategy, like switchWindowByHandle, switchWindowByUrl, switchWindowByName. And then, it is more explicit and intuitive what the API should do.
  2. Single end-point, where I pass the strategy, and it decides how to operate by that argument.

Either way, to have a clear distinction between the strategies. Here, the switchWindow and switchToWindow are almost the same, and they are both public ...

Anyhow, it is probably breaking change this kind of change.

Wouldn't it improve the stability if we make a window handle check in the newWindow command? Similar to what you proposed in newTab_secondTry. Getting the handle through getWindowHandle requires WebDriver to switch to this new window which I am not 100% sure if this is defined in the protocol, so it could be different based by the browser.

Yes, it would. I just assumed that there might be a better "low-level" solution. For instance, if there is a command (actual puppeteer command) to open the tab, this command will terminate once the browser updates the handle.

WebdriverIO has two ways to automate the browser, via WebDriver protocol or through Puppeteer (read more on this in our docs). If you have Chromedriver or a any other arbitrary WebDriver running, you run through the WebDriver protocol and make requests to the driver. Here we run a script in the browser that opens the new tab. If you don't run any driver WebdriverIO falls back to Puppeteer and there we do essentially the same.

Yes, I'm aware of the differences. Internally, we are using wdio with Puppeteer.

I think that what was odd for us is that the newWindow command runs a script running inside the browser. The selenium/webdriver protocol uses the /session/{session id}/window/new endpoint and creates a new window/tab over HTTP. On the other hand, the puppeteer project also constructs a CDP command and then sends it over ws to the browser.

Are they both, eventually, the same and equivalent to window.open()?

I can fix and push a PR we've talked about, it probably takes me some more time to get more familiar with how to contribute to the code and how to test it.

@praveendvd
Copy link
Contributor

praveendvd commented Oct 31, 2021

Hi @christian-bromann and @avikha

The issue is just with that particular website , it seems it is adding separate window name :

image

if you change it with different website , everything works as expected


describe('This Example show usage of MoveTo() command in webdriverio', () => {
    it('', async () => {
        await browser.url('https://google.com');

        await browser.newWindow('https://www.webdriverio.com/', {
            windowName: 'si-window',
        });
    
        await browser.newWindow('https://espn.com', {
            windowName: 'espn-window',
        });

        await browser.newWindow('https://espn.com', {
            windowName: 'google-window',
        });
    
        await browser.switchWindow('si-window');
        console.log(await browser.getTitle());
    
      //  await browser.switchWindow('espn-window');
        console.log(await browser.getTitle());
    
        //await browser.pause(5000);
    });
});

@praveendvd
Copy link
Contributor

window.open("https://www.si.com/","test");

if you open console of browser and run above command and then run

window.name in the newly opened browser you can see the window.name is not reflected .

But you replace si with any other website windowName will be test

@praveendvd
Copy link
Contributor

@christian-bromann the only fix I could think of is setting window.name= "something" explicitly again in newWindow command after switching to that window internally . But i don't know if its worth

@christian-bromann
Copy link
Member

Either way, to have a clear distinction between the strategies. Here, the switchWindow and switchToWindow are almost the same, and they are both public ...

I agree with that. It might make sense to think about a more clear distinction between protocol commands and WebdriverIO commands. As this would be a breaking change we can consider this for v8.

Yes, it would. I just assumed that there might be a better "low-level" solution.

As WebDriver users might experience the same issue it would be good if the solution can be for both protocols. We should keep protocol commands as low level as possible (no extra waits /logic etc.) so we can have a set of command building blocks that we can use in higher level commands. I however agree with the idea to have the Puppeteer driver be more smart about window management. There are surely more improvements to make.

Are they both, eventually, the same and equivalent to window.open()?

Not sure, I doubt it.

I can fix and push a PR we've talked about, it probably takes me some more time to get more familiar with how to contribute to the code and how to test it.

Cool, let's coordinate with @praveendvd as it seems he looked already into this.

@praveendvd it seems that window name always needs to be different. I remember there was a similar issue where having different window names has fixed the issue. What would you propose?

@praveendvd
Copy link
Contributor

@christian-bromann the issue I fixed was that if we use newWindow command without specifying a windowname then only one new window opens ,

Now we replaced, it with blank so it opens new window each time .

About this issue,

I am not able to reproduce the first one where all new window having same handle ,

The second issue where we get error saying si-window doesn't exist , is due to the behavior of that particular website. It changes the windowName that we set through newWindow command . It happens only for that particular website

@christian-bromann
Copy link
Member

Correct analysis @praveendvd , here is a reproducible example:

const { remote } = require('webdriverio')

let browser

const opts = {
    capabilities: {
        browserName: 'chrome',
    }
}

;(async function () {
    browser = await remote(opts)
    await browser.url('https://google.com')

    await browser.newWindow('https://json.org/', {
        windowName: 'some-window-name',
    })
    console.log(await browser.execute(() => window.name)) // outputs: "some-window-name"

    /**
     * change name
     */
    await browser.execute(() => {
        window.name = 'foobar'
    })
    console.log(await browser.execute(() => window.name)) // outputs: "foobar"

    await browser.deleteSession()
})().catch(async (e) => {
    console.error(e.stack)
    await browser.deleteSession()
})

If your app modifies the window name you should use the url or title to match the correct window name. I will close this as I don't believe there is something we can do here. If you have a suggestion for improvements I am happy to re-open. Thanks!

@avikha
Copy link
Author

avikha commented Nov 9, 2021

Hey @christian-bromann and @praveendvd

In our opinion, the problem with tabs still exists. It doesn't matter the window name or whether the application overrides it or. We've tried it with many sites (even some dummy sites created by us) and in many ways.

In our opinion, as I explained above, it is more of a "core" issue where the browser and the wdio are not in sync, and awaits are not helping them to get into sync.

As we see it, the problem is in lines 61-64 in newWindow.ts

await this.execute(newWindowHelper, url, windowName, windowFeatures)

const tabs = await this.getWindowHandles()
const newTab = tabs.pop()

The await this.execute(newWindowHelper ...) executes within the browser, and it runs the window.open which in its turn makes the browser run another asynchronous process of creating a new tab/context and navigating to the URL. The await for the this.execute is awaits for the browser to complete the window.open, but it does not awaits for other asynchronous processes that are initiated by that script.

By the time this.execute is done, the creation of the tab/context still happening in the background, so the browser continues to work, but the wdio script thinks that it is done. This is why the getWindowHandles() won't retrieve back the correct handles. Unless you are explicitly waiting for that.

In our internal framework, we've solved this problem with the newTab_secondTry solution, I've presented above. The solution is waiting for the handles to update (which takes time).

I've tried to apply the same solution inside the newWindow.ts file, but it seems that it makes some tests fail because I guess that they are using a mock instead of the real browser. Anyhow, it requires more time code research/familiarity. Which unfortunately I don't have time for right now. :(

@christian-bromann
Copy link
Member

@avikha sorry for loosing track of the actual issue. Reopening.

@christian-bromann
Copy link
Member

christian-bromann commented Nov 9, 2021

@avikha can you help us provide a reproducible example on this? Again your example mentioned above fails due to the fact that the esports website overwrites the window name. This example:

    await browser.url('https://google.com')
    await browser.newWindow('https://www.si.com/', {
        windowName: 'si-window',
    })

    const siTitle = await browser.getTitle()
    console.log({ siTitle })

also works as expected, it prints:

{ siTitle: 'Sports Illustrated' }

@avikha
Copy link
Author

avikha commented Nov 10, 2021

Hey @christian-bromann,

Here is an example of the tabs problems with the newWindow and getWindowHandles.

it.only("many pages and many handles", async () => {
  await browser.url("https://google.com");
  const _0 = await browser.getWindowHandle();

  const _1 = await browser.newWindow("https://facebook.com", {
    windowName: "window1",
  });

  const _2 = await browser.newWindow("https://twitter.com", {
    windowName: "window2",
  });

  // Here, I expect to get a list with three window handles, because there are three open tabs. 
  const allHandles = await browser.getWindowHandles();

  console.log("all handles");
  console.log(allHandles); // This one prints list with single handle, not as expected.

  console.log("handles got from newWindow");
  // This one prints 3 equal handles.
  console.log({
    _0,
    _1,
    _2,
  });
});

The actual output from the script:

Execution of 1 workers started at 2021-11-10T06:42:55.901Z

2021-11-10T06:42:56.256Z INFO @wdio/cli:launcher: Run onPrepare hook
2021-11-10T06:42:56.258Z INFO @wdio/cli:launcher: Run onWorkerStart hook
2021-11-10T06:42:56.258Z INFO @wdio/local-runner: Start worker 0-0 with arg: run,./wdio.conf.ts,--spec,example.e2e.ts
[0-0] 2021-11-10T06:42:56.573Z INFO @wdio/local-runner: Run worker command: run
[0-0] RUNNING in chrome - /test/specs/example.e2e.ts
[0-0] 2021-11-10T06:42:57.276Z INFO devtools:puppeteer: Initiate new session using the DevTools protocol
[0-0] 2021-11-10T06:42:57.277Z INFO devtools: Launch Google Chrome with flags: --enable-automation --disable-popup-blocking --disable-extensions --disable-background-networking --disable-background-timer-throttling --disable-backgrounding-occluded-windows --disable-sync --metrics-recording-only --disable-default-apps --mute-audio --no-first-run --no-default-browser-check --disable-hang-monitor --disable-prompt-on-repost --disable-client-side-phishing-detection --password-store=basic --use-mock-keychain --disable-component-extensions-with-background-pages --disable-breakpad --disable-dev-shm-usage --disable-ipc-flooding-protection --disable-renderer-backgrounding --force-fieldtrials=*BackgroundTracing/default/ --enable-features=NetworkService,NetworkServiceInProcess --disable-features=site-per-process,TranslateUI,BlinkGenPropertyTrees --window-position=0,0 --window-size=1200,900
[0-0] 2021-11-10T06:42:57.809Z INFO devtools: Connect Puppeteer with browser on port 62322
[0-0] 2021-11-10T06:42:58.404Z INFO devtools: COMMAND navigateTo("https://google.com/")
[0-0] 2021-11-10T06:42:59.920Z INFO devtools: RESULT null
[0-0] 2021-11-10T06:42:59.924Z INFO devtools: COMMAND getWindowHandle()
[0-0] 2021-11-10T06:42:59.924Z INFO devtools: RESULT 5091069a-43cd-4400-a7cd-88d173093b6b
[0-0] 2021-11-10T06:42:59.926Z INFO devtools: COMMAND executeScript(<fn>, <object>)
[0-0] 2021-11-10T06:43:00.006Z INFO devtools: COMMAND getWindowHandles()
[0-0] 2021-11-10T06:43:00.006Z INFO devtools: RESULT [ '5091069a-43cd-4400-a7cd-88d173093b6b' ]
[0-0] 2021-11-10T06:43:00.009Z INFO devtools: COMMAND switchToWindow("5091069a-43cd-4400-a7cd-88d173093b6b")
[0-0] 2021-11-10T06:43:00.023Z INFO devtools: RESULT 5091069a-43cd-4400-a7cd-88d173093b6b
[0-0] 2021-11-10T06:43:00.073Z INFO devtools: COMMAND executeScript(<fn>, <object>)
[0-0] 2021-11-10T06:43:00.135Z INFO devtools: COMMAND getWindowHandles()
[0-0] 2021-11-10T06:43:00.135Z INFO devtools: RESULT [ '5091069a-43cd-4400-a7cd-88d173093b6b' ]
[0-0] 2021-11-10T06:43:00.136Z INFO devtools: COMMAND switchToWindow("5091069a-43cd-4400-a7cd-88d173093b6b")
[0-0] 2021-11-10T06:43:00.142Z INFO devtools: RESULT 5091069a-43cd-4400-a7cd-88d173093b6b
[0-0] 2021-11-10T06:43:00.165Z INFO devtools: COMMAND getWindowHandles()
[0-0] 2021-11-10T06:43:00.165Z INFO devtools: RESULT [ '5091069a-43cd-4400-a7cd-88d173093b6b' ]
[0-0] all handles
[0-0] [ '5091069a-43cd-4400-a7cd-88d173093b6b' ]
[0-0] handles got from newWindow
[0-0] {
[0-0]   _0: '5091069a-43cd-4400-a7cd-88d173093b6b',
[0-0]   _1: '5091069a-43cd-4400-a7cd-88d173093b6b',
[0-0]   _2: '5091069a-43cd-4400-a7cd-88d173093b6b'
[0-0] }
[0-0] 2021-11-10T06:43:05.171Z INFO devtools: COMMAND deleteSession()
[0-0] 2021-11-10T06:43:05.172Z INFO devtools: RESULT null
[0-0] PASSED in chrome - /test/specs/example.e2e.ts
2021-11-10T06:43:05.289Z INFO @wdio/cli:launcher: Run onComplete hook

This is the same as "Example 1" presented in my initial post. You can see, that there is only one handle in allHandles list, and that all of the other three handles are equal.

Our guess is that window.open(...) executed by the newWindow (and the browser.execute inside it) starts an internal async process within the browser, but the wdio script thinks that it is done and continues on. By the time it gets to getWimdowHandles, the "creation of" tabs inside the browser is not done yet and the handles are not updated.

If you add the following code right after const _2 = await ...

await browser.waitUntil(
  async () => {
    const allHandles = await browser.getWindowHandles();
    return allHandles.length === 3;
  },
  {
    timeout: 3000,
    timeoutMsg: "After three seconds, there is only one handle",
  }
);

Then you can see that the getWindowHandles returns 3 handles, and the list of allHandles has 3 handles init. As it should and expected.

I've tried to implement the same solution in newWindow.ts, but it seems to fail some unit tests. I guess, perhaps because unit tests are using mocks and I didn't have enough time to get to the core of that.

@avikha
Copy link
Author

avikha commented Nov 10, 2021

By the way, @christian-bromann, I ran your example above, and here is the result. But, unfortunately, it is still not working as expected. At least, for me.

Execution of 1 workers started at 2021-11-10T07:07:52.210Z

2021-11-10T07:07:52.558Z INFO @wdio/cli:launcher: Run onPrepare hook
2021-11-10T07:07:52.559Z INFO @wdio/cli:launcher: Run onWorkerStart hook
2021-11-10T07:07:52.560Z INFO @wdio/local-runner: Start worker 0-0 with arg: run,./wdio.conf.ts,--spec,example.e2e.ts
[0-0] 2021-11-10T07:07:52.867Z INFO @wdio/local-runner: Run worker command: run
[0-0] RUNNING in chrome - /test/specs/example.e2e.ts
[0-0] 2021-11-10T07:07:53.575Z INFO devtools:puppeteer: Initiate new session using the DevTools protocol
[0-0] 2021-11-10T07:07:53.575Z INFO devtools: Launch Google Chrome with flags: --enable-automation --disable-popup-blocking --disable-extensions --disable-background-networking --disable-background-timer-throttling --disable-backgrounding-occluded-windows --disable-sync --metrics-recording-only --disable-default-apps --mute-audio --no-first-run --no-default-browser-check --disable-hang-monitor --disable-prompt-on-repost --disable-client-side-phishing-detection --password-store=basic --use-mock-keychain --disable-component-extensions-with-background-pages --disable-breakpad --disable-dev-shm-usage --disable-ipc-flooding-protection --disable-renderer-backgrounding --force-fieldtrials=*BackgroundTracing/default/ --enable-features=NetworkService,NetworkServiceInProcess --disable-features=site-per-process,TranslateUI,BlinkGenPropertyTrees --window-position=0,0 --window-size=1200,900
[0-0] 2021-11-10T07:07:54.108Z INFO devtools: Connect Puppeteer with browser on port 62585
[0-0] 2021-11-10T07:07:54.642Z INFO devtools: COMMAND navigateTo("https://google.com/")
[0-0] 2021-11-10T07:07:55.918Z INFO devtools: RESULT null
[0-0] 2021-11-10T07:07:55.922Z INFO devtools: COMMAND executeScript(<fn>, <object>)
[0-0] 2021-11-10T07:07:56.018Z INFO devtools: COMMAND getWindowHandles()
[0-0] 2021-11-10T07:07:56.019Z INFO devtools: RESULT [ '1fec2e08-9079-488f-970e-c390e3049ebf' ]
[0-0] 2021-11-10T07:07:56.025Z INFO devtools: COMMAND switchToWindow("1fec2e08-9079-488f-970e-c390e3049ebf")
[0-0] 2021-11-10T07:07:56.043Z INFO devtools: RESULT 1fec2e08-9079-488f-970e-c390e3049ebf
[0-0] 2021-11-10T07:07:56.103Z INFO devtools: COMMAND getTitle()
[0-0] 2021-11-10T07:07:56.104Z INFO devtools: RESULT Google
[0-0] { siTitle: 'Google' }
[0-0] 2021-11-10T07:07:56.107Z INFO devtools: COMMAND deleteSession()
[0-0] 2021-11-10T07:07:56.108Z INFO devtools: RESULT null
[0-0] PASSED in chrome - /test/specs/example.e2e.ts
2021-11-10T07:07:56.226Z INFO @wdio/cli:launcher: Run onComplete hook

 "spec" Reporter:
------------------------------------------------------------------
[Chrome 95.0.4638.69 darwin #0-0] Running: Chrome (v95.0.4638.69) on darwin
[Chrome 95.0.4638.69 darwin #0-0] Session ID: d650ce20-75b4-4917-b000-a00cd737c0cb
[Chrome 95.0.4638.69 darwin #0-0]
[Chrome 95.0.4638.69 darwin #0-0] » /test/specs/example.e2e.ts
[Chrome 95.0.4638.69 darwin #0-0] Many pages
[Chrome 95.0.4638.69 darwin #0-0]    ✓ Example
[Chrome 95.0.4638.69 darwin #0-0]
[Chrome 95.0.4638.69 darwin #0-0] 1 passing (1.4s)


Spec Files:      1 passed, 1 total (100% completed) in 00:00:04 

From this part of the logs

[0-0] 2021-11-10T07:07:55.922Z INFO devtools: COMMAND executeScript(<fn>, <object>)
[0-0] 2021-11-10T07:07:56.018Z INFO devtools: COMMAND getWindowHandles()
[0-0] 2021-11-10T07:07:56.019Z INFO devtools: RESULT [ '1fec2e08-9079-488f-970e-c390e3049ebf' ]
[0-0] 2021-11-10T07:07:56.025Z INFO devtools: COMMAND switchToWindow("1fec2e08-9079-488f-970e-c390e3049ebf")
[0-0] 2021-11-10T07:07:56.043Z INFO devtools: RESULT 1fec2e08-9079-488f-970e-c390e3049ebf

We can see that it executes the window.open() script and then queries for window handles but retrieves only one handle, the first one (google's one), and then it switches there and gets it the wrong title.

Please note that I'm using the puppeteer/dev-tools protocol for automation.

@christian-bromann
Copy link
Member

Thanks for your thorough comments. I added a patch that will fix the issue. Let's continue our convo there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants