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>
:
<template>
<div>
</div>
</template>
<script>
export default {
name: "NumberRenderer",
props: {
even: {
type: Boolean,
required: true
}
}
}
</script>
● NumberRenderer › renders even numbers
expect(received).toBe(expected) // Object.is equality
Expected: "2, 4, 6, 8"
Received: ""
It looks like everything is hooked up correctly. Let’s start implementing numbers
:
computed: {
for (let i = 1; i < 10; i++) {
if (i % 2 === 0) {
evens.push(i)
}
}
return evens
}
}
And update the template to use the new computed property:
yarn test:unit
now yields:
FAIL tests/unit/NumberRenderer.spec.js
● NumberRenderer › renders even numbers
expect(received).toBe(expected) // Object.is equality
Expected: "2, 4, 6, 8"
Received: "[
2,
4,
6,
8
]"
The numbers are correct, but we want to render the list formatted nicely. Let’s update the return
value:
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:
it("renders odd numbers", () => {
const localThis = { even: false }
expect(NumberRenderer.computed.numbers.call(localThis)).toBe("1, 3, 5, 7, 9")
})
Running the current test yields:
Update numbers
:
const odds = []
for (let i = 1; i < 10; i++) {
if (i % 2 === 0) {
evens.push(i)
} else {
odds.push(i)
}
}
return this.even === true ? evens.join(", ") : odds.join(", ")
}
Now both tests pass! But what if we hadn’t used call
in the second test? Try updating it like so:
it("renders odd numbers", () => {
const localThis = { even: false }
expect(NumberRenderer.computed.numbers()).toBe("1, 3, 5, 7, 9")
})
The test now fails:
FAIL tests/unit/NumberRenderer.spec.js
● NumberRenderer › renders odd numbers
expect(received).toBe(expected) // Object.is equality
Expected: "1, 3, 5, 7, 9"
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
. Usingcall
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