Search code examples
ionic-frameworkselenium-webdriverselenium-chromedriverwebdriver-io

WebdriverIO can't click on (Ionic) tab


I'm using WebdriverIO to test some basic functionality on an Ionic (+ Angular) application. The framework setup works all right, but I can't find a way to click on certain HTML elements. For instance, this is some HTML sample:

<div class="tabbar show-tabbar" role="tablist" style="top: 166px; display: flex;">
  <a class="tab-button has-title has-title-only" href="#" role="tab" id="tab-t0-0" aria-controls="tabpanel-t0-0"
      aria-selected="true">
    <span class="tab-button-text">Blah</span>
    <div class="button-effect"></div>
  </a>
  <a class="tab-button has-title has-title-only" href="#" role="tab" id="tab-t0-1" aria-controls="tabpanel-t0-1"
      aria-selected="false">
    <span class="tab-button-text">Foo</span>
    <div class="button-effect"
        style="transform: translate3d(83px, -103px, 0px) scale(1); height: 240px; width: 240px; opacity: 0; transition: transform 395ms ease 0s, opacity 277ms ease 118ms;"></div>
  </a>
  <a class="tab-button has-title has-title-only" href="#" role="tab" id="tab-t0-2" aria-controls="tabpanel-t0-2"
      aria-selected="false">
    <span class="tab-button-text">Bar</span>
    <div class="button-effect"
        style="transform: translate3d(3px, -99px, 0px) scale(1); height: 240px; width: 240px; opacity: 0; transition: transform 395ms ease 0s, opacity 277ms ease 118ms;"></div>
  </a>
  <div class="tab-highlight animate" style="transform: translate3d(570px, 0px, 0px) scaleX(285);"></div>
</div>

And this is a super-simple test case that I'm doing to test the functionality:

import { expect } from "chai";

describe("Some Test", () => {
  const logingUrl: string = "url0";

  const appUrl: string = "url1";

  it("Some Test Again", () => {
    browser.url(logingUrl);
    browser.url(appUrl);
    const tab = $("#tab-t0-2");
    tab.click();
    expect(tab.getAttribute("aria-selected")).to.equal("true");
  });
});

..but every time I run it, I get some weird error message that the element is no clickable at some point. Any clues?

[0-0] element click intercepted in "Some Test Again"
element click intercepted: Element <a class="tab-button has-title has-title-only" href="#" role="tab" id="tab-t0-2" aria-controls="tabpanel-t0-2" aria-selected="false">...</a> is not clickable at point (666, 170). Other element would receive the click: <ion-backdrop disable-activated="" role="presentation" tappable="" class="backdrop-no-tappable" style="opacity: 0.5;"></ion-backdrop>
  (Session info: headless chrome=75.0.3770.100)

Solution

  • This is one of those classic Angular/Ionic backdrop gotcha's.

    Let's start with the error message: element #tab-t0-2 is not clickable at point (coordinates), another element would receive the click: ion-backdrop.

    This tells us that your targeted element cannot be clicked as the ion-backdrop tag is rendered on top of it. The ion-backdrop component is a short animation (usually used for modals), in this case, the semi dimming of the background (opacity: 0.5).

    ✖ Solution 1: Easy way to counter it? Explicitly expect for it to disappear, then click the targeted element.

    it("Some Test Again", () => {
      browser.url(logingUrl);
      browser.url(appUrl);
    
      // Explicitly wait for the backdrop animation to disappear:
      const backdrop = $('.backdrop-no-tappable');
      backdrop.waitForExist(5000, true, 'Backdrop still present');
    
      const tab = $("#tab-t0-2");
      tab.click();
      expect(tab.getAttribute("aria-selected")).to.equal("true");
    });
    

    ✖ Solution 2: Another thing you can try is only click on the tab element, once it is fully visible and intractable in the DOM (this is kind of a best-practice):

      const tab = $("#tab-t0-2");
      tab.waitForDisplayed(5000);
      // For 'wdio-v4' users: 
      // tab.waitForVisible(5000);
      tab.click();
      expect(tab.getAttribute("aria-selected")).to.equal("true");