Skip to content

How to check an element is displayed (v-show) ? #327

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Toilal opened this issue Jan 4, 2018 · 13 comments
Closed

How to check an element is displayed (v-show) ? #327

Toilal opened this issue Jan 4, 2018 · 13 comments

Comments

@Toilal
Copy link
Contributor

Toilal commented Jan 4, 2018

I try to assert that elements are displayed or not. Those elements are children (or even grand-children) of a v-show node.

Consider the following, I wish to assert display of .item elements.

<div>
  <div v-show="modelAttrA">
    <span class="item">Ax</span>
    <span class="item">Ay</span>
  </div>
  <div v-show="modelAttrB">
    <span class="item">Bx</span>
    <span class="item">By</span>
  </div>
<div>

It seems a common use case, but I can't find any way in vue-test-utils to do that. I can't rely on DOM element properties as I run tests with JEST (JSDOM doesn't layout elements and can't tell if an element is displayed neither). Maybe there's something possible with VueJS VNode API ?

I would expect some kind of displayed method in the Wrapper API.

expect(wrapper.findAll('.item').at(3).displayed()).toBeTruthy()
@lmiller1990
Copy link
Member

lmiller1990 commented Jan 5, 2018

From the Vue.js docs,

v-show: simply applies display: none
v-if: removes element from dom entirely.

Here is an example:

<template>
  <button v-show="false" />
</template>
// testing v-show
expect(wrapper.find('button').hasStyle('display', 'none')).toBe(true)

// testing v-if
expect(wrapper.find('button').exists()).toBe(false)

I think this kind of q and a is best for stackoverflow, though. Does that help?

Edit: I just realized you are looking at children elements of v-show. It's the same thing, though. If the parent is not shown, than the children are not shown, either. So just assert parent is not shown.

@Toilal
Copy link
Contributor Author

Toilal commented Jan 5, 2018

I understand, but I can't find parent() nor ancestor() method to check for display: none style on ancestors of element to assert, and I don't think it's possible to build a CSS selector that would match elements with such ancestors.

It's more a feature request than a Q&A, as a (new) user of vue-test-utils, I just expect to find a visible() method on Wrapper to assert that an element is visible.

@Toilal
Copy link
Contributor Author

Toilal commented Jan 5, 2018

Here's a possible implementation (Working with JEST/JSDOM) :

function isVisible(wrapper: Wrapper<Vue>) {
  const computedStyle = window.getComputedStyle(wrapper.element)
  return computedStyle.display !== 'none'
}

May I open a pull request that adds a displayed() method on wrapper with this implementation ? it seems displayed is the best name, as it relies on display: none CSS style.

@Toilal
Copy link
Contributor Author

Toilal commented Jan 5, 2018

There are other use cases that are hard to solve related to v-show, like getting visible text only.

text() is based on DOM element textContent property which is not CSS aware (from spec), so it actually grabs text recursively from all nodes, even undisplayed ones.

It would be nice to have a visibleText() method that would manually walk through DOM hierarchy to build text string from visible text nodes only. JQuery has a hacky custom CSS selector to implements this, and it's also implemented in some testing tools like Selenium.

@lmiller1990
Copy link
Member

lmiller1990 commented Jan 5, 2018

I can see a use case for visible or displayed (because of how v-show works). I still think you should be asserting on the parent element with the v-show, though. The reason I believe this is I feel that this:

expect(wrapper.findAll('.item').at(3).displayed()).toBeTruthy()

is much less readable than

expect(wrapper.find('.modelAttrB').displayed()).toBeTruthy()

I think visible is more intuitive than displayed. Edd might have some ideas.

Also, this is related to #331 , if we remove hasStyle, how can you test v-show?

@Toilal
Copy link
Contributor Author

Toilal commented Jan 5, 2018

I wrote a simple example on top of this issue, but in real life i'm writing tests for a Tree component.

In the tree view, the tree node holding v-show="false" can be an ancestor of n levels back in the DOM hierachy of the node that has to be asserted, so it's not that simple to select it directly with CSS.

@eddyerburgh
Copy link
Member

Hey I think this is a great idea.

One way I can think of implementing it would be to walk up the DOM tree with parentNode/parentElement and check if the element has a style.display property of 'hidden'. The problem is elements that have visibility set to visible are visible, even if their parents have visibility set to hidden.

I agree with @lmiller1990 . visible is a better name.

Would you like to look into implementing this @Toilal ?

@lmiller1990 We can still check style by accessing the wrapper element:

wrapper.element.style.visibility // hidden

@Toilal
Copy link
Contributor Author

Toilal commented Jan 5, 2018

I'll try to implement this during the week-end

@Toilal
Copy link
Contributor Author

Toilal commented Jan 8, 2018

@eddyerburgh I try to implement this, but my first unit test fails :(

I can't find a way to retrieve parent of a VNode. It seems to be always null. (See #328)

  parent (): Wrapper | ErrorWrapper {
    const parentVNode = this.vnode.parent
    if (parentVNode) {
      return createWrapper(parentVNode, this.update, this.options)
    }
    return new ErrorWrapper('No parent found')
  }
describe('parent', () => {
  it('returns parent element', () => {
    const compiled = compileToFunctions('<div class="parent"><div class="child"></div></div>')
    const wrapper = mount(compiled)
    const child = wrapper.find('.child')
    expect(child.parent().classes()).to.include('parent')
  })
})

Toilal added a commit to Toilal/vue-test-utils that referenced this issue Jan 8, 2018
Toilal added a commit to Toilal/vue-test-utils that referenced this issue Jan 9, 2018
Toilal added a commit to Toilal/vue-test-utils that referenced this issue Jan 9, 2018
Toilal added a commit to Toilal/vue-test-utils that referenced this issue Jan 9, 2018
Toilal added a commit to Toilal/vue-test-utils that referenced this issue Jan 9, 2018
Toilal added a commit to Toilal/vue-test-utils that referenced this issue Jan 12, 2018
Toilal added a commit to Toilal/vue-test-utils that referenced this issue Jan 15, 2018
Toilal added a commit to Toilal/vue-test-utils that referenced this issue Jan 16, 2018
Toilal added a commit to Toilal/vue-test-utils that referenced this issue Jan 16, 2018
Toilal added a commit to Toilal/vue-test-utils that referenced this issue Jan 16, 2018
Toilal added a commit to Toilal/vue-test-utils that referenced this issue Jan 17, 2018
@eddyerburgh
Copy link
Member

This will be released in beta.11

@RiZKiT
Copy link

RiZKiT commented Dec 18, 2018

@Toilal Just for completion, you may ment parent() or parentNode instead of parent?

@ZJH9Rondo
Copy link

Focus

@leonheess
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants