Skip to content

Add update method for model updates #34

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

Merged
merged 6 commits into from
Jun 1, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
{
"name": "@testing-library/vue",
"version": "1.0.2",
"description": "Simple and complete Vue DOM testing utilities that encourage good testing practices.",
Expand Down
36 changes: 36 additions & 0 deletions src/vue-testing-library.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,42 @@ fireEvent.touch = async (elem) => {
await fireEvent.blur(elem)
}

fireEvent.update = async (elem, value) => {
const tagName = elem.tagName
const type = elem.type

switch (tagName) {
case 'OPTION':
elem.selected = value

const parentElement = this.element.parentElement.tagName === 'OPTGROUP'
? this.element.parentElement.parentElement
: this.element.parentElement

return fireEvent.change(parentElement)

case 'INPUT':
if (type === 'checkbox') {
elem.checked = value
return fireEvent.change(elem)
} else if (type === 'radio') {
elem.selected = value
return fireEvent.change(elem)
} else {
elem.value = value
return fireEvent.input(elem)
}

case 'TEXTAREA':
elem.value = value
return fireEvent.input(elem)

case 'SELECT':
elem.value = value
await fireEvent.change(elem)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

quick question! Should this line return, instead of await? If not, why does it need to be different?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missed that, updated now.

WRT change and input, I hadn't considered that update may replace them all. I would rather expose them and allow the user the choice of which to use than deprecate them. What do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This actually leads me to another question...

I feel that just writing .input or .change, like the native events, makes a lot of sense. And it would be quite weird if fireEvent.input only worked in certain cases (when v-model is not used).

So... what if input and change would handle v-model properly, instead of creating a new event? Would it be hard?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could mask input or change, however we're still moving away from what is the idiomatic usage and taking away options from the end user (to use input or change as they are natively).

I'm not sure if there is an ideal solution here tbh, although I think update as it is here is probably the most flexible solution.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right. Also adding a method is a non breaking change, while modifying the implementation of .input and .change might be. Let's add the update method and see how it goes!

}
}

export * from '@testing-library/dom'
export {
cleanup,
Expand Down
14 changes: 12 additions & 2 deletions tests/__tests__/components/Login.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@
name="password"
aria-labelledby="password-label"
>
<label id="remember-me-label">Remember Me</label>
<input
type="checkbox"
id="remember-me"
name="remember-me"
aria-labelledby="remember-me-label"
v-model="rememberMe"
/>
<button type="submit">Submit</button>
</form>
</div>
Expand All @@ -32,14 +40,16 @@ export default {
data () {
return {
username: '',
password: ''
password: '',
rememberMe: false
}
},
methods: {
submit () {
this.onSubmit({
username: this.username,
password: this.password
password: this.password,
rememberMe: this.rememberMe
})
}
}
Expand Down
15 changes: 10 additions & 5 deletions tests/__tests__/form.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,22 @@ import { render, fireEvent } from '@testing-library/vue'
import Login from './components/Login'

test('login form submits', async () => {
const fakeUser = { username: 'jackiechan', password: 'hiya! 🥋' }
const fakeUser = { username: 'jackiechan', password: 'hiya! 🥋', rememberMe: true }
const handleSubmit = jest.fn()
const { getByText, updateState } = render(
const { getByLabelText, getByText } = render(
Login, { props: { onSubmit: handleSubmit } }
)

const submitButtonNode = getByText('Submit')

// Act - this is waiting on an issue in @vue/test-utils to allow v-model to be updated by
// changes to DOM elements
updateState(fakeUser)
const userNameInput = getByLabelText('Username')
await fireEvent.update(userNameInput, fakeUser.username)

const passwordInput = getByLabelText('Password')
await fireEvent.update(passwordInput, fakeUser.password)

const rememberMeInput = getByLabelText('Remember Me')
await fireEvent.update(rememberMeInput, true)

// NOTE: in jsdom, it's not possible to trigger a form submission
// by clicking on the submit button. This is really unfortunate.
Expand Down