Find the Vue.js 3 version here.

You can find the test described on this page .

Testing computed properties are especially simple, since they are just plain old JavaScript functions.

Let’s start with looking at two different ways to test a computed property. We will develop a <NumberRenderer> component, that renders either odd or even numbers, based on a numbers computed property.

Writing the test

The <NumberRenderer> component will receive an even prop, that is a boolean. If even is true, the component should render 2, 4, 6, and 8. If false, it should render 1, 3, 5, 7 and 9. The list of values will be calculated in a computed property called numbers.

The test:

Before running the test, let’s set up <NumberRenderer>:

  1. <template>
  2. <div>
  3. </div>
  4. </template>
  5. <script>
  6. export default {
  7. name: "NumberRenderer",
  8. props: {
  9. even: {
  10. type: Boolean,
  11. required: true
  12. }
  13. }
  14. }
  15. </script>
  1. NumberRenderer renders even numbers
  2. expect(received).toBe(expected) // Object.is equality
  3. Expected: "2, 4, 6, 8"
  4. Received: ""

It looks like everything is hooked up correctly. Let’s start implementing numbers:

  1. computed: {
  2. for (let i = 1; i < 10; i++) {
  3. if (i % 2 === 0) {
  4. evens.push(i)
  5. }
  6. }
  7. return evens
  8. }
  9. }

And update the template to use the new computed property:

yarn test:unit now yields:

  1. FAIL tests/unit/NumberRenderer.spec.js
  2. NumberRenderer renders even numbers
  3. expect(received).toBe(expected) // Object.is equality
  4. Expected: "2, 4, 6, 8"
  5. Received: "[
  6. 2,
  7. 4,
  8. 6,
  9. 8
  10. ]"

The numbers are correct, but we want to render the list formatted nicely. Let’s update the return value:

  1. return evens.join(", ")

Now yarn test:unit passes!

Testing with call

We will now add a test for the case of even: false. This time, we will see an alternative way to test a computed property, without actually rendering the component.

The test, first:

  1. it("renders odd numbers", () => {
  2. const localThis = { even: false }
  3. expect(NumberRenderer.computed.numbers.call(localThis)).toBe("1, 3, 5, 7, 9")
  4. })

Running the current test yields:

Update numbers:

  1. const odds = []
  2. for (let i = 1; i < 10; i++) {
  3. if (i % 2 === 0) {
  4. evens.push(i)
  5. } else {
  6. odds.push(i)
  7. }
  8. }
  9. return this.even === true ? evens.join(", ") : odds.join(", ")
  10. }

Now both tests pass! But what if we hadn’t used call in the second test? Try updating it like so:

  1. it("renders odd numbers", () => {
  2. const localThis = { even: false }
  3. expect(NumberRenderer.computed.numbers()).toBe("1, 3, 5, 7, 9")
  4. })

The test now fails:

  1. FAIL tests/unit/NumberRenderer.spec.js
  2. NumberRenderer renders odd numbers
  3. expect(received).toBe(expected) // Object.is equality
  4. Expected: "1, 3, 5, 7, 9"
  5. Received: "2, 4, 6, 8"

vue automatically binds props to this. We are not rendering the component with mount, though, so Vue isn’t binding anything to this. If you do console.log(this), you can see the context is simply the computed object:

So we need to use call, which lets us bind an alternative this object, in our case, one with a even property.

Both techniques presented are useful for testing computed properties. Call can be useful when:

  • You are testing a component that does some time consuming operations in a lifecycle methods you would like to avoid executing in your computed unit test.
  • You want to stub out some values on this. Using call and passing a custom context can be useful.

Conclusion

  • computed properties can be using mount making assertions on the rendered markup
  • complex computed properties can be independently tested by using