Search code examples
javascriptvue.jsvuejs2jestjsvue-test-utils

How to target first child of selector when testing component with jest


I'm trying to write a test to to target if a default prop is passed in the HTML correctly using jest and vue-test-utils. I can not seem to find my target selector. I want to be able to test that a particular p tag contains the proper text. In this case if a name prop is passed, it renders that. If not, then the default function renders the default payTo value.

I've been trying several combinations of chaining to the wrapper to no avail.

console.log(wrapper.html()) // presents all the page html
console.log(wrapper.classes()) // array showing only one class ('.row-space-between')

Here is my component:

<template>
  <div class="row-space-between">
    <div>
      <h3>{{ $t('label.payTo') }}</h3>
      <p>{{ merchantName.payTo }}</p> // TARGET SELECTOR
    </div>
    <div class="align-right">
      <h3>{{ $t('label.estimatedTotal') }}</h3>
      <p>{{ amount }}</p>
    </div>
  </div>
</template>

<script>
export default {
  name: 'PayTo',
  props: {
    'merchant-name': {
      type: Object,
      // default: {} with type obj or arr default function is required
      default: function () {
        return { merchantName: {
          payTo: 'Order Total'
         }
       }
    },
    amount: {
      type: String,
      default: ''
    }
  }
}

And here is my test:

describe('PayTo.vue', () => {
  let wrapper

  beforeEach(() => {
    wrapper = shallowMount(PayTo, {
      mocks: {
        $t
      },
      propsData: {
        merchantName: {
          payTo: 'foo-merchant-name'
        },
        amount: '$110.00'
      }
    })
  })
  it('[positive] should render correct contents', () => {
    // PayTo.props.merchantName.default()
    expect(wrapper.html()).toMatchSnapshot()
  })

  // The following two tests satisfy testing the default function in PayTo.vue props validation if not tested, coverage falls to zero

  // This test is meaningless until I can be more specific in targeting

  it('[positive] should display `AWS`', () => {
    wrapper.setProps({
      merchantName: {
        payTo: 'AWS'
      }
    })
    expect(wrapper.contains('p'))
  })

  it('[negative] should display `Order Total`', () => {
    wrapper.setProps({
      merchantName: {
        payTo: 'Order Total'
      }
    })
    console.log(wrapper.contains('div > p'))
    expect(wrapper.contains('p'))
  })

Solution

  • The :first-child pseudo-class could be used here:

    expect(wrapper.contains("div:first-child > p")).toBeTruthy()
    

    I would also verify the text in p matches the expected value:

    expect(wrapper.find("div:first-child > p").text()).toBe("Order Total")
    

    Also note your merchant-name prop's default value should not contain another merchantName key. Otherwise, when that prop is not specified, payTo would be accessed by merchantName.merchantName.payTo.

    props: {
      "merchant-name": {
        type: Object,
        default: function() {
          return {
            // merchantName: {  // DON'T DO THIS
            //  payTo: "Order Total"
            // }
    
            payTo: "Order Total"
          }
        }
      },
    }
    

    Edit Selectors in @vue/test-utils