Validate form data with Vuelidate

Essentially, Vuelidate is a Vue mixin. We need to apply it to Vue first. To do that, we make changes to the frontend/src/main.js file, as follows:

import Vuelidate from 'vuelidate'
...
Vue.use(Vuelidate)

And the following are the changes we make to RegisterPage.vue:

<script>
import { required, email, minLength, maxLength, alphaNum } from 'vuelidate/lib/validators'
...
export default {
...
validations: {
form: {
username: {
required,
minLength: minLength(2),
maxLength: maxLength(50),
alphaNum
},
emailAddress: {
required,
email,
maxLength: maxLength(100)
},
password: {
required,
minLength: minLength(6),
maxLength: maxLength(30)
}
}
},
methods: {
submitForm () {
this.$v.$touch()
if (this.$v.$invalid) {
return
}
...
}
}
}
</script>

As you can see, we import several of Vuelidate's built-in validators and then add the validations options object, which has the same structure as our data model. In each field of this validations object, we specify the rules that each field needs. Once that is done, in the submitForm() method, we access the API of Vuelidate through the $v object that Vuelidate created and added to the Vue instance. This $v object holds the current state of validation. We call its $v.$touch() method to trigger the data validation. Then, we verify the result by checking the $v.$invalid property. If the validation fails, its value is true and we simply abort the registration process.

Now, let's run the test to see how things work. You should see that the result says all of the tests have passed. However, there are lots of warnings from Vue.js, saying the following:

Expected mock function to have been called with:
[{"name": "LoginPage"}]
But it was not called.

With a closer look at the warning message, we can see that this warning originates from the following test method:

it('should register when it is a new user', () => {
const stub = jest.fn()
wrapper.vm.$router.push = stub
wrapper.vm.form.username = 'sunny'
wrapper.vm.form.emailAddress = 'sunny@local'
wrapper.vm.form.password = 'Jest!'
wrapper.vm.submitForm()
wrapper.vm.$nextTick(() => {
expect(stub).toHaveBeenCalledWith({name: 'LoginPage'})
})
})

Based on the warning message, vm.$router.push was not called. In fact, this should not be taken as a warning because, in this test method, we verify that the user will be redirected to the login page after a success registration. When the method isn't called, the test should fail. Why did Jest still let that test pass? There must be something seriously wrong. We need to dig deep to find out what happened during the test.

Let's think about this. Before we implemented the data validation, this test passed. So, it must have something to do with the validation rules we just added. With a closer look at the data we used in the test,  we can see that the email address is invalid, and also the password is shorter than 6 characters. It looks like our test data that is supposed to make the test pass actually caused a validation issue. But still, why did Vue.js throw that warning? Shouldn't Jest be the one to take care of the tests?

Let's walk through the test and the code flow to see what happened. Starting from the test method, we used invalid data, and after the submitForm() method was invoked, Vuelidate performed data validation inside of the submitForm() method. The validation failed, and the call was returned immediately to the test method. Therefore, the register() method didn't get invoked. That means no asynchronous execution occurred and the verification inside $nextTick() didn't get evaluated by Jest before the test finished. That's why Jest let the test pass. Later on, no matter whether there is an asynchronous execution or not inside the submitForm() method, the next tick will start eventually. That's when the verification inside $nextTick() got evaluated and failed. Since Jest has already finished the execution of the test method, the only thing it can do is throw the verification failure as an error. And this error was detected by Vue.js, because the verification happened inside the $nextTick() method of Vue.js. Since we didn't provide an error handler to $nextTick(), Vue.js didn't know what to do with this error, and it threw that warning at us, basically saying: Hey, this is an error that you have ignored. Do something about it.

By now, it all makes sense. This is clearly a defect in the test method. To fix this, first of all let's fix all the test data used in this specification as well the registration service's mock data. Then, we can chain a catch() method to $nextTick() using  promise-chain. Or, we can use async/await for asynchronous calls, like the following:

  it('should fail it is not a new user', async () => { 
// In the mock, only [email protected] is new user
wrapper.vm.form.username = 'ted'
wrapper.vm.form.emailAddress = '[email protected]'
wrapper.vm.form.password = 'JestRocks!'
...
await wrapper.vm.$nextTick()
expect(wrapper.find('.failed').isVisible()).toBe(true)
})

To use async/await, we need to add async before the function that contains the asynchronous invocation and then put the await before the invocation that is asynchronous. In this way, JavaScript will wait until that promise settles and returns its result.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.26.22