fhoeben/hsac-fitnesse-fixtures

No interaction possible with "invisible" input fields

Gamadril opened this issue · 2 comments

After updating our UI from vuetify 2 to vuetify 3 no interactions is possible with input fields.
The significant change I see is the way how input field is now embedded in the vutify TextField component. In the new version the input field has the 'opactiy: 0' set which will change to 1 if the element is focused/active.
It seems that 'enter' just 'doesn't see' the corresponding input field. Also 'click' ignores it.
The current workaround is to use JS to focus the element to go on with the test, but is there an 'official' way to avoid it?

Here are the tests to show the problem.

vutify 2 (working)

|script                |browser test                                            |
|seconds before timeout|3                                                       |
|set browser size to maximum                                                    |
|open                  |https://v2.vuetifyjs.com/en/components/text-fields/#misc|
|ensure                |is visible       |State/Province/Region                 |
|enter                 |TEST             |as       |State/Province/Region       |

vuetify 3 (not working)

|script                |browser test                                         |
|seconds before timeout|3                                                    |
|set browser size to maximum                                                 |
|open                  |https://vuetifyjs.com/en/components/text-fields/#misc|
|ensure                |is visible      |State/Province/Region               |
|enter                 |TEST            |as      |State/Province/Region      |

vuetify 3 (working with workaround)

|script                |browser test                                                    |
|seconds before timeout|3                                                               |
|set browser size to maximum                                                            |
|open                  |https://vuetifyjs.com/en/components/text-fields/#misc           |
|ensure                |is visible          |State/Province/Region                      |
|execute script        |document.querySelectorAll('#custom-validation input')[3].focus()|
|enter                 |TEST                |as          |State/Province/Region         |

Annoying these JavaScript frameworks.

I don't believe there currently is a 'standard' way to deal with this. A subclass of BrowserTest could probably hide the magic to shift focus, so the test scripts are not polluted with it. Similar tricks were needed for Angular 1 and RichFaces validations.

Having said that I expect fixing the 'click' behaviour might be possible in the generic browser test. I believe the labels are not hidden/opaque until focused so that could be an extra trick to learn browser test (I'm actually surprised it doesn't at the moment), but I haven't really looked into it.

I managed to make click and enter work using a custom subclass.
The problems with this element turned out to be twofold:

  • when clicking BrowserTest tries to click the label, but Selenium does not want to do that because the input (although transparent) is above it and would therefore get the click (I worked around this by clicking the label using Javascript directly).
  • when entering a value the value is not intractable since it is transparent (as you found this can be fixed by focusing the element).

With a setup like this you can isolate the changes to code so the actual test/wiki pages only have to use another fixture, but their steps are the same.

|script                |vue3 test                                             |
|seconds before timeout|3                                                     |
|open                  |https://vuetifyjs.com/en/components/text-fields/#misc |
|ensure                |is visible|City                                       |
|click                 |City                                                  |
|type                  |hello                                                 |
|check                 |value of  |City                 |hello                |
|ensure                |is visible|State/Province/Region                      |
|enter                 |TEST      |as                   |State/Province/Region|
|check                 |value of  |State/Province/Region|TEST                 |

package nl.hsac.fitnesse.fixture.slim.web;

import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;

public class Vue3Test<T extends WebElement> extends BrowserTest<T>{
    @Override
    protected boolean isInteractable(WebElement element) {
        boolean interactable = super.isInteractable(element);
        if (element != null && !interactable) {
            focusElement(element);
            interactable = super.isInteractable(element);
        }
        return interactable;
    }

    @Override
    protected boolean clickElement(WebElement element) {
        return doIfInteractable(element, () -> {
            try {
                element.click();
            } catch (WebDriverException e) {
                if (clickExceptionIsAboutHiddenByOtherElement(e) && isVueHiddenElement(element)) {
                    clickWithJavascript(element);
                } else {
                    throw e;
                }
            }
        });
    }

    private Object focusElement(WebElement element) {
        return getSeleniumHelper().executeJavascript("arguments[0].focus()", element);
    }

    private boolean isVueHiddenElement(WebElement element) {
        return element.getTagName().equalsIgnoreCase("label");
    }

    private void clickWithJavascript(WebElement element) {
        getSeleniumHelper().executeJavascript("arguments[0].click()", element);
    }
}

Maybe you can use this as a starting point and see what is needed to make a fixture that is fully functional with Vue, for your suite? I would be happy to add it if you submit a PR with it.