fhoeben / hsac-fitnesse-fixtures

An environment to define and run integration tests. It contains Fitnesse fixture (base) classes and a baseline FitNesse installation.
Apache License 2.0
110 stars 99 forks source link

No interaction possible with "invisible" input fields #569

Open Gamadril opened 11 months ago

Gamadril commented 11 months ago

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         |
fhoeben commented 11 months ago

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.

fhoeben commented 11 months ago

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

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.