0

I am learning Jest for unit testing and I seem to be hitting a hurdle.

I am trying to check that when my menu a is clicked, that the 'active' class is applied.

This is my code:

HTML

 <div class="form-group">
        <div class="col-12">
          <ul class="nav nav-tabs" id="myTab" role="tablist">
            <li class="nav-item">
              <a id="activeBlogs-tab" class="nav-link active" data-toggle="tab" href="#activeBlogs" role="tab"
                  aria-controls="activeBlogs" aria-selected="true" style="border-right: 1px solid lightgray">
                Active blogs
              </a>
            </li>
            <li class="nav-item">
              <a id="closedBlogs-tab" class="nav-link" data-toggle="tab" href="#closedBlogs" role="tab" aria-selected="false"
                  aria-controls="closedBlogs">
                Closed blogs
              </a>
            </li>
            <li id="addTab" class="nav-item ml-auto">
              <router-link to="/add" class="nav-link bg-info text-white" exact>Add a new blog</router-link>
            </li>
          </ul>
        </div>
      </div>

Test

it('Checks "ClosedBlogs" component displayed when clicking "Closed Blogs tab"', () => {
    //wrapper.find('#closedBlogs-tab').trigger('click')


    // const mockCallBack = jest.fn();

    // const closedMenuClick = shallow((<a onClick={mockCallBack}>Closed blogs</a>));
    // closedMenuClick.find('#closedBlogs-tab').simulate('click');

    //wrapper.find('#closedBlogs-tab').simulate('click');

    const fourthStar = wrapper.find('#closedBlogs-tab')
    fourthStar.trigger('click')
    expect(fourthStar.classes()).toBe("nav-link active")

    // expect(wrapper.find('#activeBlogs-tab').attributes().class).toBe("nav-link")
    // expect(wrapper.find('#activeBlogs').attributes().class).toBe("tab-pane fade")

    // expect(wrapper.find('#closedBlogs-tab').attributes().class).toBe("nav-link active")
    // expect(wrapper.find('#closedBlogs').attributes().class).toBe("tab-pane fade active")
})

All commented out code is what I have tried but they all error with various errors as shown below

 Expected: "tab-pane fade active"
    Received: "tab-pane fade show active"

      77 | 
      78 |         expect(wrapper.find('#activeBlogs-tab').attributes().class).toBe("nav-link active")
    > 79 |         expect(wrapper.find('#activeBlogs').attributes().class).toBe("tab-pane fade active")
         |                                                                 ^
      80 |     })
Expected: "nav-link active"
Received: "nav-link"

  65 |         // expect(wrapper.find('#activeBlogs').attributes().class).toBe("tab-pane fade")
  66 | 
> 67 |         expect(wrapper.find('#closedBlogs-tab').attributes().class).toBe("nav-link active")
     |                                                                     ^
  68 |         expect(wrapper.find('#closedBlogs').attributes().class).toBe("tab-pane fade active")
  69 |     })
Expected: "nav-link active"
Received: ["nav-link"]

  59 |         fourthStar.trigger('click')
  60 |         //expect(fourthStar.classes()).toContain('active')
> 61 |         expect(fourthStar.classes()).toBe("nav-link active")
     |                                      ^
  62 | 
  63 |         // expect(wrapper.find('#activeBlogs-tab').attributes().class).toBe("nav-link")
  64 |         // expect(wrapper.find('#activeBlogs').attributes().class).toBe("tab-pane fade")
Expected value: "active"
Received array: ["nav-link"]

  58 |         const fourthStar = wrapper.find('#closedBlogs-tab')
  59 |         fourthStar.trigger('click')
> 60 |         expect(fourthStar.classes()).toContain('active')
     |                                      ^
  61 | 
  62 |         // expect(wrapper.find('#activeBlogs-tab').attributes().class).toBe("nav-link")
  63 |         // expect(wrapper.find('#activeBlogs').attributes().class).toBe("tab-pane fade")
halfer
  • 19,824
  • 17
  • 99
  • 186
murday1983
  • 3,806
  • 14
  • 54
  • 105

1 Answers1

0

It's exciting that you're learning to test your JS code :)

In December 2019, there was a breaking change in the Vue Test Utils (v1.0.0-beta.30), that disabled the sync mode. This means that the DOM will not re-render upon every change like we're used to with the Vue framework. I'm sharing this because guides/tutorials you may have read, might be "outdated".

Whenever we're testing changes to the DOM, we have to manually trigger the re-rendering ourselves with wrapper.vm.$nextTick(). This change speeds up our test suites as it prevents potential multi re-renderings during one test.

So! You were very close with this one:

fourthStar.trigger('click')
expect(fourthStar.classes()).toContain('active')

However, it should be like this:

fourthStar.trigger('click')
await wrapper.vm.$nextTick()
expect(fourthStar.classes()).toContain('active')

Please remember: the test's callback function must be declared async to allow the await keyword.

I've put together full copy+paste friendly component and test for your convenience :)

ClassComponent.vue

<template>
    <button class="btn" :class="{active: isActive}" @click="isActive = ! isActive">Click me</button>
</template>

<script>
    export default {
        data(){
            return {
                isActive: false
            }
        }
    }
</script>

ClassComponent.spec.js

import {mount} from "@vue/test-utils";
import ClassComponent from "./ClassComponent";

it('applies active class when clicked', async () => {
    const wrapper = mount(ClassComponent)
    const button = wrapper.find('button')
    expect(button.classes()).not.toContain('active')
    button.trigger('click')
    await wrapper.vm.$nextTick()
    expect(button.classes()).toContain('active')
});

Notice the async/await keywords

RAH
  • 3,167
  • 1
  • 15
  • 10