Vue-test-utils: How to check an element is displayed (v-show) ?

Created on 4 Jan 2018  路  12Comments  路  Source: vuejs/vue-test-utils

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()
feature request intend to implement

Most helpful comment

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.

All 12 comments

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.

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.

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.

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.

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?

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.

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

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

@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')
  })
})

This will be released in beta.11

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

Focus

Was this page helpful?
0 / 5 - 0 ratings

Related issues

vwxyutarooo picture vwxyutarooo  路  3Comments

matt-sanders picture matt-sanders  路  3Comments

robcresswell picture robcresswell  路  3Comments

vilarinholeo picture vilarinholeo  路  3Comments

dlumbrer picture dlumbrer  路  3Comments