-
Notifications
You must be signed in to change notification settings - Fork 20
Feedback #36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feedback #36
Changes from all commits
d68a8ba
1afa287
2940d70
ba56b01
d636f90
16f5599
c9561f5
eaa2677
2e0ed32
516fae7
e5b51f1
aaaa4c0
21b9163
24bd8ce
7ef3e20
e9bfb73
41818ad
7aabae7
4faf02d
e6dad3e
8a70d6b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,14 +4,11 @@ Vue components interact with each other via props and by emitting events by call | |
|
||
## The Counter component | ||
|
||
Here is a simple `<Counter>` component. It has a button that increments a `count` property when it is clicked. It also emits an `increment` event with the latest value of `count` by calling `this.$emit('increment', this.count)`: | ||
Here is a simple `<Counter>` component. It features a button that, when clicked, increments an internal count variable and emits its value: | ||
|
||
```js | ||
const Counter = { | ||
template: ` | ||
<button @click="handleClick">Increment</button> | ||
<div>Count: {{ count }}</div> | ||
`, | ||
template: '<button @click="handleClick">Increment</button>', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
data() { | ||
return { | ||
count: 0 | ||
|
@@ -26,84 +23,127 @@ const Counter = { | |
} | ||
``` | ||
|
||
To fully test this component, we should verify that when the button is clicked, the `count` shown in the template is updated. We can also verify that an `increment` event with the latest `count` value is emitted. We will start with the latter. | ||
To fully test this component, we should verify that an `increment` event with the latest `count` value is emitted. | ||
|
||
## `VueWrapper.emitted()` | ||
## Asserting the emitted events | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here people got lost because we moved from explaining thing from a "user perspective" to an "API perspective" |
||
|
||
`VueWrapper` has an `emitted()` method. It returns an object with all the events the component has emitted, and their arguments in an array. Let's see how it works: | ||
To do so, we will rely on the `emitted()` method. It **returns an object with all the events the component has emitted**, and their arguments in an array. Let's see how it works: | ||
|
||
```js | ||
test('emits and event with count when clicked', () => { | ||
test('emits an event when clicked', () => { | ||
const wrapper = mount(Counter) | ||
wrapper.find('button').trigger('click') | ||
|
||
wrapper.find('button').trigger('click') | ||
wrapper.find('button').trigger('click') | ||
|
||
console.log(wrapper.emitted()) // { increment: [ [ 1 ], [ 2 ], [ 3 ] ] } | ||
expect(wrapper.emitted()).toHaveProperty('increment') | ||
}) | ||
``` | ||
|
||
> If you haven't seen `trigger()` before, don't worry. It's used to simulate user interaction. You can learn more in [Forms](/guide/forms). | ||
> If you haven't seen `trigger()` before, don't worry. It's used to simulate user interaction. You can learn more in [Forms](/guide/forms). | ||
|
||
The output of `emitted()` might be a little confusing at first. In this test, we are only interested in the `increment` event, so we can access that with `wrapper.emitted('increment')`. This would return `[ [ 1 ], [ 2 ], [ 3 ] ]`. Let's format it a bit more nicely to see what's going on: | ||
The first thing to notice is that `emitted()` returns an object, where each key matches an emitted event. In this case, `increment`. | ||
|
||
```js | ||
// console.log(wrapper.emitted('increment')) | ||
[ | ||
[ 1 ], // first time is it called, `count` is 1 | ||
[ 2 ], // second time is it called, `count` is 2 | ||
[ 3 ], // third time is it called, `count` is 3 | ||
] | ||
This test should pass. We made sure we emitted an event with the appropriate name. | ||
|
||
## Asserting the arguments of the event | ||
|
||
This is good - but we can do better! We need to check that we emit the right arguments when `this.$emit('increment', this.count)` is called. | ||
|
||
Our next step is to assert that the event contains the `count` value. We do so by passing an argument to `emitted()`. | ||
|
||
```js {9} | ||
test('emits an event with count when clicked', () => { | ||
const wrapper = mount(Counter) | ||
|
||
wrapper.find('button').trigger('click') | ||
wrapper.find('button').trigger('click') | ||
|
||
// `emitted()` accepts an argument. It returns an array with all the | ||
// occurrences of `this.$emit('increment')`. | ||
const incrementEvent = wrapper.emitted('increment') | ||
|
||
// We have "clicked" twice, so the array of `increment` should | ||
// have two values. | ||
expect(incrementEvent).toHaveLength(2) | ||
|
||
// Assert the result of the first click. | ||
// Notice that the value is an array. | ||
expect(incrementEvent[0]).toEqual([1]) | ||
|
||
// Then, the result of the second one. | ||
expect(incrementEvent[1]).toEqual([2]) | ||
}) | ||
``` | ||
|
||
Each entry in the array represents one `increment` event that was emitted. Each entry in the array represents an argument to `this.$emit()`. For example, if the code was `this.$emit('increment, this.count, { status: 'success' })`, and the button was clicked twice, `emitted('increment')` would be: | ||
Let's recap and break down the output of `emitted()`. Each of these keys contains the different values emitted during the test: | ||
|
||
```js | ||
[ | ||
[ // first `increment` event | ||
1, // first argument | ||
{ status: 'success' } // second argument | ||
], | ||
[ // second `increment` event | ||
2, // first argument | ||
{ status: 'success' } // second argument | ||
] | ||
// console.log(wrapper.emitted('increment')) | ||
[ | ||
[ 1 ], // first time it is called, `count` is 1 | ||
[ 2 ], // second time it is called, `count` is 2 | ||
] | ||
``` | ||
|
||
Each element in the array corresponds to an argument in `this.$emit`. | ||
|
||
## Writing a Test | ||
## Asserting complex events | ||
|
||
Now we know that `emitted('eventName')` captures the events, we can write a simple test to assert an `increment` event is emitted: | ||
|
||
```js | ||
test('emits and event with count when clicked', () => { | ||
const wrapper = mount(Counter) | ||
Imagine that now our `<Counter>` component needs to emit an object with additional information. For instance, we need to tell any parent component listening to the `@increment` event if `count` is even or odd: | ||
|
||
wrapper.find('button').trigger('click') | ||
```js {12-15} | ||
const Counter = { | ||
template: `<button @click="handleClick">Increment</button>`, | ||
data() { | ||
return { | ||
count: 0 | ||
} | ||
}, | ||
methods: { | ||
handleClick() { | ||
this.count += 1 | ||
|
||
expect(wrapper.emitted()).toHaveProperty('increment') | ||
}) | ||
this.$emit('increment', { | ||
count: this.count, | ||
isEven: this.count % 2 === 0 | ||
}) | ||
} | ||
} | ||
} | ||
``` | ||
|
||
This is good - but we can do better. With the knowledge that `increment` will return an array, where each element represents an event and it's arguments, we can fully test the component by making assertions against the arguments passed when `this.$emit('increment')` is called: | ||
As we did before, we need to trigger the `click` event on the `<button>` element. Then, we use `emitted('increment')` to make sure the right values are emitted. | ||
|
||
```js | ||
test('emits and event with count when clicked', () => { | ||
test('emits an event with count when clicked', () => { | ||
const wrapper = mount(Counter) | ||
|
||
wrapper.find('button').trigger('click') | ||
wrapper.find('button').trigger('click') | ||
wrapper.find('button').trigger('click') | ||
|
||
expect(wrapper.emitted('increment')).toHaveLength(3) | ||
expect(wrapper.emitted('increment')[0]).toEqual([1]) | ||
expect(wrapper.emitted('increment')[1]).toEqual([2]) | ||
expect(wrapper.emitted('increment')[2]).toEqual([3]) | ||
// We have "clicked" twice, so the array of `increment` should | ||
// have two values. | ||
expect(wrapper.emitted('increment')).toHaveLength(2) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reduced clicks from 3 to 2 because otherwise the snippet grows too large |
||
|
||
// Then, we can make sure each element of `wrapper.emitted('increment')` | ||
// contains an array with the expected object. | ||
expect(wrapper.emitted('increment')[0]).toEqual([ | ||
{ | ||
count: 1, | ||
isEven: false | ||
} | ||
]) | ||
|
||
expect(wrapper.emitted('increment')[1]).toEqual([ | ||
{ | ||
count: 2, | ||
isEven: true | ||
} | ||
]) | ||
}) | ||
``` | ||
|
||
Testing complex event payloads such as Objects is no different from testing simple values such as numbers or strings. | ||
|
||
## Composition API | ||
|
||
If you are using the Composition API, you will be calling `context.emit()` instead of `this.$emit()`. `emitted()` captures events from both, so you can test your component using the same techniques described here. | ||
|
@@ -112,4 +152,4 @@ If you are using the Composition API, you will be calling `context.emit()` inste | |
|
||
- Use `emitted()` to access the events emitted from a Vue component. | ||
- `emitted(eventName)` returns an array, where each element represents one event emitted. | ||
- Arguments are stored in `emitted(eventName)[index]` in an array, in the same order they are emitted. | ||
- Arguments are stored in `emitted(eventName)[index]` in an array in the same order they are emitted. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They didn't get why this test had no assertions