Testcafe: Visibility Checking

Created on 27 Jan 2017  路  29Comments  路  Source: DevExpress/testcafe

Are you requesting a feature or reporting a bug?

Bug

What is the current behavior?

Element is being reported as visible when it's not

What is the expected behavior?

It should be reported as _not_ visible

How would you reproduce the current behavior (if this is a bug)?

Run the code

Provide the test code and the tested page URL (if applicable)

Tested page URL: http://bmcgenomics.biomedcentral.com/articles/10.1186/s12864-016-2850-8

Test code

import { ClientFunction, Selector } from 'testcafe';

fixture `Reduced Test Case`;

test('Visibility Checking', async t => {
    await t.navigateTo('http://bmcgenomics.biomedcentral.com/articles/10.1186/s12864-016-2850-8');
    const el = await Selector('.branding-bar__copyright');
    const el2 = await Selector(el, {
        visibilityCheck: true
    });
    console.log(await el2.visible);
});


Specify your

  • operating system: OS X
  • testcafe version: 0.12.1
  • node.js version: v7.0.0
level 2 API enhancement

Most helpful comment

Hi,

We haven't done any significant changes here yet but I have some thoughts about what we can do.

Let's clarify the requirements. It's useful to have the capability to check the following scenarios in tests:

  • Element is technically visible (has no display:none, visibility:hidden and has a non-zero width and height);
  • Element is inside the viewport (placed in the visible part of the page in the browser);
  • Element can be a target for an action (you can scroll to it (optionally), see it and for example click on it. Element is not overlapped by others. In other words it possible to get it via getElementFromPoint)
  • Element is in the viewport and it is reachable

For the first case, we already have element.visible.
For the second case, we can add element.inViewport.
For the third case, we can add element.reachable.
For the fourth case, we can check both the inViewport and reachable flags.

What do you think? /cc @adamorlowskipoland, @p-bakker, @umaar, @DevExpress/testcafe

All 29 comments

Essentially, I'd like to find out if an element is displayed or not. I assume this is what the visibilityCheck is for? So if the element is on the page, but outside of the viewport, I thought el.visible should be false?

Hi Umar,

el.visible is false in the following cases:

  • display style is none;
  • visibility style is hidden;
  • element has a width or height that is equal zero.

The visibilityCheck option works with the same logic.
This behavior is similar to the jQuery :visible Selector.
With other words, element is visible if it's available for an action (it's inside the viewport or it's possible to scroll to it).

If you want to check is your element is inside the viewport you can create a ClientFunction with custom logic.

Thank you for explaining. Knowing if an element is displayed in the viewport is a very fundamental part of browser testing. Why not solve this problem within testcafe?

I haven't met a request for this feature before. If necessary we can create a solution for this by using ClientFunction or a custom property of the element state.
Also I guess we'll discuss this built-in property with the team.

Yes please do consider this. It's quite important that browser based tests check when things are within the viewport or not. I already started writing my own ClientFunction for this but it's not very elegant since TestCafe doesn't seem to expose getboundingclientrect, but rather, a custom getBoundingClientRectProperty() and so overall, the complete solution is rather custom but as mentioned, IMO it should be part of a modern browser testing framework.

Maybe a good idea to make this clearer in the documentation, because that is, at least for me, the reason my tests weren't working and/or not stable

IMHO the definition of visibility needs to not be defined to this technical definition of visibility, but instead be based on intractable with by the user. This means among other things that an element is not visible if:

  • overlayed by another element (at the position of the event being fired), taking into account pointer-events (https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events)
  • located outside the viewport (taking into account if the user would be able to scroll to it or not)

On of my cases: I have a big panel that is moved off to the side, partially under another element, partly outside the browsers viewport. In no circumstances can the user access this panel, until some code moves this panel into view. I'd expect the selectors of TestCafe to only return the element after it's moved into view where normally the user could interact with it.

Of course I can manage all this myself, but that makes writing tests way more verbose than it should be

Thanks for the proposal! We need some time to rethink it all and propose the solution.

Tnx for taking it into consideration.

One more note: I think currently if you'd have two clickable elements on top of eachother and you instruct TestCafe to click the one that is behind the other, it actually performs the click on the element that is in front.

I'd have to build a stand-alone testcase for really prove it, but this behavior would explain some of the odd behavior I'm seeing

I think currently if you'd have two clickable elements on top of eachother and you instruct TestCafe to click the one that is behind the other, it actually performs the click on the element that is in front.

Yes, TestCafe works now in this way

This might be useful: http://stackoverflow.com/a/27884653/7049810 (at least for part of the solution)

Has something changed since last post?
I'm having the same trouble now...

Hi,

We haven't done any significant changes here yet but I have some thoughts about what we can do.

Let's clarify the requirements. It's useful to have the capability to check the following scenarios in tests:

  • Element is technically visible (has no display:none, visibility:hidden and has a non-zero width and height);
  • Element is inside the viewport (placed in the visible part of the page in the browser);
  • Element can be a target for an action (you can scroll to it (optionally), see it and for example click on it. Element is not overlapped by others. In other words it possible to get it via getElementFromPoint)
  • Element is in the viewport and it is reachable

For the first case, we already have element.visible.
For the second case, we can add element.inViewport.
For the third case, we can add element.reachable.
For the fourth case, we can check both the inViewport and reachable flags.

What do you think? /cc @adamorlowskipoland, @p-bakker, @umaar, @DevExpress/testcafe

Sounds really good. It gives a lot of new flexibility so it's a YES from me.

yeah, I think that pretty much covers all need.

Just wondering how the css 'transform: scale(0)' or 'transform: translate(....)' affects the above

Guys I have some uncertainties about inViewport, and reachable options.
For the inViewport option - what part of the element should be visible? The center of the element? The whole element? Or it should be configurable? Maybe, inViewport should be a function with an argument like: { offsetX: <number>, offsetY: <number>, wholeElement: <boolean> }
I'd like to see your opinion based on your real testing cases. /cc @adamorlowskipoland, @p-bakker, everyone else

IMHO inViewport should mean intersection between the element bounding box and the viewport, eg any part of the element crossing the viewport will trigger it. Maybe we should have different tastes like insideViewport and intersectViewport to differentiate between wholy or partly covered.

+1 for this thread; my team is having similar issues.

We have panels with animations from right to left, so TestCaf茅 sometimes is not able to determine when the close button is visible in the top right corner (it's in the DOM, but outside the viewport). It's flaky, because it depends on how fast the animation run.

For our case, inViewport would be ideal, meaning the whole element is in the viewport.

Another +1 for this thread I agree with the insideViewport (though maybe viewportContains) and intersectViewport (viewportOverlaps?) idea.

+1 for this thread, does anyone have a suggested workaround for filtering elements only found in viewport?

The visibility check of Testcafe is way to simple IMHO. It does not match a human like visibility. The Selenium's one depends on opacity, overflow, positioning, zIndex, ... See https://github.com/SeleniumHQ/selenium/blob/b4e5fe326d1f70061633ef290745f35893178ba5/javascript/atoms/dom.js#L460

Do people are interesting in having this in Testcafe ?
For performance purpose, we could have a technical and a human visible check. Autoscroll to find an element should be an option to.

@DevSide
Thank you for your feedback.
We do not have immediate plans to implement it. However, I find your suggestion interesting and we'll consider its implementation in the future.

Do you have any update in this issue? I'm using TestCafe and having an issue - I'm getting visibility true even when the element not present in the screen. And its blocking as my rest script is dependent on the visibility of the element.

@manikuntalab Thank you for your interest in TestCafe.
We have different plans about the improvement of our visibility checking mechanism.
You can see some of them in this milestone. But the bigger part of them related to adding this new functionality (such as the el.isInViewport and the scroll option for actions) is still under consideration.
You will be able to find them in the milestone as soon as we come up with some precise ideas.

Same issue as @manikuntalab so pinging up the topic. Counting on improvements soon!

This is a very basic and important requirement. How come this is not prioritized? I think @DevSide made an extremely good point when saying:

[the current visibility test] does not match a human-like visibility.

Human-like behaviors should be crucial for an e2e framework.

Thank you for your input. We will take it into account when looking into this issue.

馃憢 Hey, I'm not sure if an issue I'm seeing is related to this thread... We have a couple of elements which are visible dependent on the viewport size: class="hidden-xs" and class="visible-xs"

As an example:
Page: https://www.change.org/p/the-world-send-matt-damon-to-mars-to-recover-opportunity/psf/share?source_location=combo_psf&psf_variant=combo&skip=1

PetitionShareAsk = Selector('.psf-combo-embedded-card').find('h1').filterVisible();

Running my tests in chrome returns true for t.expect(PetitionShareAsk.visible).ok()... however false when running in chrome:emulation:device=iphone X.

Is there a way to filter visibility based on viewport size?

Hi @rob4629,

I couldn't reproduce the behavior you've described. I composed a simple test based on the information you provided, and it passes as in emulation mode so without emulation.

Anyway, I believe this is a separate issue. As far as I understand, Bootstrap assigns display: none style property to .hidden-xs/.visible-xs elements, so TestCafe should deal with them correctly.

Was this page helpful?
0 / 5 - 0 ratings