Unit test a V-If label with Jest is alway true

Solution for Unit test a V-If label with Jest is alway true
is Given Below:

I’m trying to test the following label using Jest:

<label class="no-content-label" v-if="products.length===0 && !isTableBusy">No Content To Show</label>

with the following test:

it('Test No Content To Show When table is not empty', async () => {
        const wrapper = mount(productTable, {
            propsData: {
                products: items1,
                fields: fields1
            }
        })
        expect(wrapper.find(".no-content-label").exists()).toBeFalsy()
        wrapper.destroy();
    }) 

where items are just: [{ a: 1, b: 2, c: 3 }, { a: 4, b: 5, c: 6 }] nut I always getting True even that the components is not showing and should get false.

The full components code:

<template>
  <div id="ProductTable" class="container mt-3 mb-5">
    <h1 class="mainTitle">Product Table Home</h1>
    <b-alert variant="danger" :show="showError" v-for="(error,index) in errorArray" :key="index" dismissible>
      {{ error }}
    </b-alert>
    <b-row class="mb-3">
      <b-col md="3">
        <b-form-input v-model="filterInput" type="search" id="filterInput" placeholder="Type to Search"></b-form-input>
      </b-col>
    </b-row>
    <b-table id="product-table" striped hover head-variant="light"
             :busy="isTableBusy"
             :items="products"
             :filter="filterInput"
             :fields="fields"
             :bordered="bordered"
             :borderless="bordered"
             :total-rows="rows">
      <template #table-busy>
        <div class="text-center text-danger my-2">
          <b-spinner class="align-middle"></b-spinner>
          <strong>Loading...</strong>
        </div>
      </template>
      <template #cell(cogs.unitManufacturingCost)="row">
        {{
          row.item.cogs.unitManufacturingCost ? Number(row.item.cogs.unitManufacturingCost).toLocaleString() + '$' : '0$'
        }}
      </template>
      <template #cell(cogs.shipmentUnitCost)="row">
        {{ row.item.cogs.shipmentUnitCost ? Number(row.item.cogs.shipmentUnitCost).toLocaleString() + '$' : '0$' }}
      </template>
      <template #cell(cogs.monthlyAdvertismentCost)="row">
        {{
          row.item.cogs.monthlyAdvertismentCost ? Number(row.item.cogs.monthlyAdvertismentCost).toLocaleString() + '$' : '0$'
        }}
      </template>
      <template #cell(cogs.manufacturingCountry)="row">
        {{ row.item.cogs.manufacturingCountry ? row.item.cogs.manufacturingCountry : '-' }}
      </template>
      <template #cell(actions)="row">
        <b-button size="md" variant="primary" @click="openEditProductModal(row.item)">
          Edit
        </b-button>
        <edit-product-modal ref="EditProductModal" :item="row.item" @fetchProducts="fetchProducts"></edit-product-modal>
      </template>

    </b-table>
    <label class="no-content-label" v-if="products.length===0 && !isTableBusy">No Content To Show</label>
  </div>
</template>

<script>
import EditProductModal from "@/components/EditProductModal";
import {BAlert} from "bootstrap-vue";
import {BRow} from "bootstrap-vue";
import {BCol} from "bootstrap-vue";
import {BFormInput} from "bootstrap-vue";
import {BTable} from "bootstrap-vue";



export default {
  name: "BootstrapProductTable",
  components: {
    EditProductModal: EditProductModal,
    'b-alert': BAlert,
    'b-row': BRow,
    'b-col': BCol,
    'b-form-input': BFormInput,
    'b-table': BTable,
  },
  data() {
    return {
      filterInput: "",
      bordered: true,
      isTableBusy: false,
      products: [],
      fields: [
        {key: 'productName', label: 'Product Name', sortable: true, sortDirection: 'desc'},
        {key: 'cogs.unitManufacturingCost', label: 'Unit manufacturing cost', sortable: true,},
        {key: 'cogs.shipmentUnitCost', label: 'Shipment unit cost', sortable: true},
        {key: 'cogs.monthlyAdvertismentCost', label: 'Monthly advertising cost', sortable: true,},
        {key: 'cogs.manufacturingCountry', label: 'Manufacturing country', sortable: true,},
        {key: 'actions', label: 'Actions'}
      ],
      errorArray: [],
      showError: false
    }
  },
  computed: {
    rows() {
      return this.products.length;
    }
  },
  created() {
    this.fetchProducts();
  },
  methods: {
    openEditProductModal(row) {
      this.$refs.EditProductModal.show(row)
    },
    async fetchProducts() {
      try {
        this.isTableBusy = true;
        //delay example
        // const delay = ms => new Promise(resolve => setTimeout(resolve, ms))
        // await delay(1000)
        let response;
        response = await this.axios.get(
            "http://localhost:3000/products"
        );
        this.products = response.data;
      } catch (error) {
        this.showError = true;
        this.errorArray = error.response ? error.response.data.errors : [error]
      }
      this.isTableBusy = false;
    }
  }
}
</script>

You are trying to pass products, but your component is not expecting any props.

I see that products are fetched in fetchProducts method. All api calls must be mocked. fields are already set in the component. So all you have to do is to mock api call. That’s why I suggest you to mock fetchProducts method so it will be always returning the same array of products:

const mockProducts = [{ a: 1, b: 2, c: 3 }, { a: 4, b: 5, c: 6 }];

it('Test No Content To Show When table is not empty', async () => {
  const wrapper = mount(productTable, {
    mocks: {
      fetchProducts: () => mockProducts
    }
  })
  expect(wrapper.find(".no-content-label").exists()).toBeFalsy()
    wrapper.destroy();
  }) 

I was finally been able to fix the test by adding an id attribute to the label and finding it by id:

the label:

 <label id="no-content-label" v-if="products.length===0 && !isTableBusy">No Content To Show</label> 

The working tests:

 let wrapper = null
    beforeEach(() => {
        wrapper = mount(ProductTable)
    })
    afterEach(() => {
        wrapper.destroy()
    })
it('Test "No Content To" Show appear When Products are empty', async () => {
        await wrapper.setData({products: []})
        expect(wrapper.find('[id="no-content-label"]').exists()).toBe(true)
        expect(wrapper.find('[id="no-content-label"]').text()).toBe("No Content To Show");
    })
    it('Test "No Content To" not Show do not appear When Products are not empty', async () => {
        await wrapper.setData({products: mockProduct})
        expect(wrapper.find('[id="no-content-label"]').exists()).toBe(false);
    })