webdriverio / webdriverio

Next-gen browser and mobile automation test framework for Node.js
http://webdriver.io
MIT License
9.04k stars 2.5k forks source link

[🐛 Bug]: switchWindow switches to the latest available window even if requested window was not found #13759

Closed gavvvr closed 1 week ago

gavvvr commented 1 week ago

Have you read the Contributing Guidelines on issues?

WebdriverIO Version

v9.2.1

Node.js Version

v22.6.0

Mode

Standalone Mode

Which capabilities are you using?

{
    browserName: 'chrome'
}

What happened?

Initially, I though it's a problem of wdio-electron-service (see webdriverio-community/wdio-electron-service#762), and formulated it differently. Today I've spent some time debugging the code, understood that it's a problem of webdriverio and came up to the following observation:

What is your expected behavior?

The window switch is not expected, if invalid window was requested from switchWindow()

How to reproduce the bug.

Consider the simplest possible E2E browser testing project generated with npm init wdio@latest .

Here is the test scenario:

await browser.url(`https://the-internet.herokuapp.com/login`);

// Open another website in a new tab
const newTab = await browser.createWindow("tabs");
await browser.switchToWindow(newTab.handle);
await browser.navigateTo(`https://example.com`);

// Switch back to the 1st tab
await browser.switchToWindow((await browser.getWindowHandles())[0]);
// Proof the switch was successful, you will see 'The Inernet' logged
console.log(await browser.getTitle());

// Pass incorrect input to `switchWindow`
try {
  await browser.switchWindow("not-existing-window");
} catch (e) {
  // There is an error, but WDIO swicthed to the latest available window anyway and you'll see 'Example Domain' printed
  console.error(e);
}
console.log(await browser.getTitle());

Relevant log output

You'll have 2 tabs opened ('The Internet' and 'Example Domain').
Initially, 'The Internet' is in focus. (proven by console output).

Unfortunately, `await browser.switchWindow("garbage-input")` will throw error (expected) and at the same time switch the tab to the latest available (not expected). You'll see the unexpected switch happened by 'Example Domain' printed to console.

Code of Conduct

Is there an existing issue for this?

jan-molak commented 1 week ago

It seems like the issue is caused by the for loop implemented in switchWindow, which uses this.switchToWindow(tab) to cycle through all the windows until it finds the one accepted by the matcher.

https://github.com/webdriverio/webdriverio/blob/9dd5b4d1fb54c4f1135eee1cd544972496fa5e83/packages/webdriverio/src/commands/browser/switchWindow.ts#L31-L84

If the requested window is not found, finishing the loop will leave the context focused on the latest available window, and lead to the unexpected behaviour described by @gavvvr.

gavvvr commented 1 week ago

@jan-molak yeah, I saw this :) The fix is already coming ...

christian-bromann commented 1 week ago

Thanks for taking a stab at this @gavvvr 👏