No More Posting New Topics!

If you have a question or an issue, please start a thread in our Github Discussions Forum.
This forum is closed for new threads/ topics.

Navigation

    Quasar Framework

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search

    Unit testing and simulating input

    Framework
    q-input testing vue-test-utils
    7
    18
    4080
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • M
      maxant last edited by

      I am using vue-test-utils.
      I have a form with a q-input of type textarea:

      https://github.com/maxant/kafka-data-consistency/blob/master/ui/claims.js#L83

                             <q-input
                                  id="claims-form-description"
                                  class="col-8"
                                  v-model="form.description"
                                  type="textarea"
                                  float-label="Description"
                                  rows="4"
                                  @blur="blurDescription"
                                  :error="$v.form.description.$error"
                              />
      

      I want to make my unit test enter data, if possible. I guess I could just set the value into the model.
      Then I want to simulate a blur, so that the “blurDescription” function is called:

      methods: {
          blurDescription() {
              this.$v.form.description.$touch()
          },
      

      I should then be able to check that $v is updated, so that I can test that the validation works. But I cannot get the blur to work. I’ve tried the following:

      wrapper.find("#claims-form-description.q-input-area").trigger("blur")
      wrapper.find("#claims-form-description").trigger("blur")
      

      Neither causes my blur method to be called. What is the correct way to do this?

      Also, are there any utility functions provided by quasar which hide quasar internal stuff, so that I can e.g. programatically click on buttons or enter text into inputs?

      1 Reply Last reply Reply Quote 0
      • nothingismagick
        nothingismagick last edited by

        Hi - are you using v1? and if so are you using the @quasar/testing app-extension?

        1 Reply Last reply Reply Quote 0
        • M
          maxant last edited by

          nope, version 2 @nothingismagick

          1 Reply Last reply Reply Quote 0
          • nothingismagick
            nothingismagick last edited by

            Version 2 isn’t out yet - so I guess you are from the future. With v1 I meant @quasar/cli v1.0.0-beta

            1 Reply Last reply Reply Quote 1
            • M
              maxant last edited by

              haha @nothingismagick 🙂

              I guess I meant 0.17.8

              Not using cli.
              I had a quick look at this yesterday: https://github.com/quasarframework/quasar-testing
              But couldn’t see anything that would help me enter text into a q-input or bluring it. Basically I don’t want to have to know that a q-unit contains divs and text areas and stuff like that. I just want to find my element by ID, and be able to call methods on that object like “click()”, “setValue(…)”, “blur()”, etc. Is that possible or on a roadmap?

              1 Reply Last reply Reply Quote 0
              • M
                maxant last edited by maxant

                @nothingismagick I noticed that I can use the “ref” attribute and then access that ref like this:

                wrapper.find("#claims-form-description").vnode.componentInstance.$refs
                

                And that ref has some interesting stuff on it, e.g. an input (I’m testing with a q-input), and that in turn has a “click” and “blur” method:

                wrapper.find("#claims-form-description").vnode.componentInstance.$refs.input.click()
                

                Or perhaps even better:

                wrapper.vm.$refs.other.blur()
                

                But they don’t seem to do anything. Should they do something? Is there any docs about this stuff?

                1 Reply Last reply Reply Quote 0
                • M
                  maxant last edited by

                  I’ve made progress.
                  I had a number of problems:

                  • using lazy-rules, which requires focus and blur to be programatically executed, which in turn doesnt work when the debug window is open
                  • setting a value in the data is not enough to get validation to be executed, you need to use a setTimeout(f, 0)
                  • vue-test-utils wrapper has a method called “setValue” - that doesnt work with q-input 😞

                  I’ve got a working example. I’ll tidy it up and post it here tomorrow.

                  M 1 Reply Last reply Reply Quote 0
                  • M
                    maxant @maxant last edited by

                    A further problem was that jsdelivr.net only has vue-test-utils version 1.0.0-beta.11, which has a date of 11th Jan 2018?!?!

                    NPM is already at version 1.0.0-beta.29. So I switched to unpkg.com:

                    <script src="https://unpkg.com/@vue/test-utils@1.0.0-beta.29/dist/vue-test-utils.umd.js"></script>
                    

                    Now the wrapper which I get when I select the q-input finally has a setValue function, and things are working MUCH better.

                    I still have to mess around with focusing the element, but that makes sense, because I’m using lazy rules. wrapper.find(...).trigger("focus") doesn’t seem to work on a q-input but I can use native Javascript which works find. Maybe because I appended the wrapper.element to a div in my browser while running the tests. Note: I’m not following the docs here, and I’m running the tests in the browser using QUnit so that I can interact with the widgets if I need to, if a test isn’t working the way I expect it to.

                    The focus and blur process required in the test is complicated but lazy-rules just works that way, so I have no other choice:

                    • rules are not validated until the field is focused
                    • rules are not validated the first time until the field loses focus
                    • rules are continuously validated after returning to the field

                    In order to get the validation to fire after blurring the first time I had to do a “nextTick”, i.e. await on a setTimeout(..., 0). I guess quasar/vue are waiting for some messages in the queue to be processed by the event loop. See the link to my example code below for more details.

                    Once you understand that and program the test to expect that behaviour, the test works quite well.

                    An example is here:

                    https://github.com/maxant/kafka-data-consistency/blob/14f62badf13188ed153ae38de00aa9dc2042f27c/ui/claims.spec.js

                    If you check that project out and serve https://github.com/maxant/kafka-data-consistency/blob/14f62badf13188ed153ae38de00aa9dc2042f27c/ui/tests.html using a simple web server like nodes http-server, you can see all the tests running in the browser, and you can see the components 🙂

                    So, summary:

                    • wrapper.setValue(...) from vue-test-utils works fine with a q-input.
                    • same for q-btns
                    • if you use lazy-rules then expect to have to focus and blur the q-input
                    • wrapper.find(...).trigger("blur") or “focus” doesnt work => instead use native calls
                    • that might only work if the component is appended and actually visible in the browser… not sure
                    • my original question was whether quasar provided any utility functions to help test widgets, but I don’t currently believe any extra stuff is required - vue-test-utils suffices

                    Thanks for the help!
                    Ant

                    1 Reply Last reply Reply Quote 2
                    • D
                      dariosalvi last edited by dariosalvi

                      I have the same problem, but I am using Quasar v1.5 and Quasar testing tools.

                      So my problem is that I have a component with a q-input and I would like to change its value and see how that affects the rest of the component.

                      Simplifying a bit, I have a component with a q-input inside. It is filled in with a value that comes from the props of the containing component. Like:

                      <template>
                      <div>
                        <q-input v-model="value" @input="update()"></q-input>
                      </div>
                      </template>
                      
                      <script>
                      export default {
                        name: 'QINPUTDEMO,
                        props: [ 'value' ],
                        methods: {
                          update () {
                            this.$emit('input', this.value)
                          }
                        }
                      }
                      </script>
                      

                      So you use it like here:

                      <template>
                       <p>An example using the q-input demo</p>
                       <q-input-demo v-model="txt"/>
                      </template>
                      
                      <script>
                      export default {
                        data () {
                          return {
                            txt: 'test'
                          }
                        }
                      }
                      </script>
                      

                      In my test, I would like to write into the q-input and verify that the text has changed correctly:

                      it('sets the translated texts', async () => {
                        const qinput = wrapper.find(components.QInput)
                        qinput.setValue('text 1')
                      })
                      

                      When I call setValue() the testing framework says: " [vue-test-utils]: wrapper.setValue() cannot be called on this element".

                      Any idea about how to fix it?

                      1 Reply Last reply Reply Quote 0
                      • D
                        dariosalvi last edited by dariosalvi

                        Hello, little update form my side:

                        I have found out how to set the new value inside inside the q-input: you need to find a regular input instead of a q-input instance:

                        it('sets a value correctly', async () => {
                            const input = wrapper.find('input[type=text]')
                            input.setValue('test 1')
                            expect(wrapper.vm.value).toBe('test 1')
                        }
                        

                        This actually sets the text inside the q-input and also trigger the input event. Problems: if the q-input manages a prop directly (as in the example above), the test will pass, but Vue will complain with a:

                        Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders.

                        To avoid this, I have tried using data inside the q-input v-model instead of props directly:

                        <template>
                        <div>
                          <q-input  v-model="text" @input="update()"></q-input>
                        </div>
                        </template>
                        
                        <script>
                        export default {
                          name: 'QINPUT',
                          props: [ 'value' ],
                          data () {
                            return {
                              text: this.value
                            }
                          },
                          methods: {
                            update () {
                              this.$emit('input', this.text)
                            }
                          }
                        }
                        </script>
                        

                        Note that here v-model=“text” instead of value. The effect is that the warning disappears, but after calling setValue(), the change is not propagated to wrapper.vm.value, even if I use await wrapper.vm.$nextTick() and the test fails.

                        So I haven’t found a way to properly test components that modify an input. This is a pity because most of my components are actually editors of some type of information. This guide here doesn’t help either.

                        S 1 Reply Last reply Reply Quote 0
                        • S
                          seanaye @dariosalvi last edited by

                          @dariosalvi Have you found a solution to this? I’m getting started with quasar + jest and I am running into the same issue. I have a component which wraps a q-input. I would like to test that v-model on my custom component works correctly but when I change the value props there is no input event emitted. The component works as expected through manual testing so the problem must be with jest

                          1 Reply Last reply Reply Quote 0
                          • T
                            tedchwang last edited by tedchwang

                            Here’s what I’m doing, in essence, and it looks to work fine.

                            In the .vue file:

                            <q-input v-model="formDataEmail" name="email" ref="email" />
                            

                            In the .spec.js file:

                              it("accepts email input", async () => {
                                const email = "a1@b2.cd";
                                const emailInput = wrapper.find("input[name=email]");
                                await emailInput.setValue(email);
                                expect(wrapper.vm.formDataEmail).toBe(email);
                              });
                            

                            So, the above works fine and we can at least use the name attribute to do the selection unambiguously.

                            However, using findComponent() to get the input element does not work, although it’ll be nice if it does:

                              it("accepts email input", async () => {
                                const email = "a1@b2.cd";
                                const emailInput = wrapper.findComponent({ ref: "email" });
                                await emailInput.setValue(email);
                                expect(wrapper.vm.formData.email).toBe(email);
                              });
                            
                            //gives: [vue-test-utils]: wrapper.setValue() cannot be called on this element
                            
                            A 1 Reply Last reply Reply Quote 0
                            • A
                              akira28 @tedchwang last edited by

                              @tedchwang
                              can you help me?
                              using this way mine insists on this error:
                              d8a37e02-81ad-4e05-9cc0-2f0cbc2499ef-image.png

                              thanks…

                              1 Reply Last reply Reply Quote 0
                              • C
                                charlieknoll last edited by

                                I think you may need to put email in quotes:

                                "input[name='email']"
                                
                                A 1 Reply Last reply Reply Quote 0
                                • A
                                  akira28 @charlieknoll last edited by

                                  @charlieknoll

                                  unfortunately it doesn’t work

                                  385105bb-dde4-4e79-9c78-cdf96a409515-image.png

                                  A 1 Reply Last reply Reply Quote 0
                                  • A
                                    akira28 @akira28 last edited by

                                    This is my code

                                    e861a992-3453-420c-8a63-2daf3c56061b-image.png

                                    1 Reply Last reply Reply Quote 0
                                    • C
                                      charlieknoll last edited by

                                      Can you get a reference to the element running this in your console?

                                      document.querySelector("input[name='email']")
                                      
                                      A 1 Reply Last reply Reply Quote 0
                                      • A
                                        akira28 @charlieknoll last edited by

                                        @charlieknoll
                                        So what is happening is that I can’t use the trigger, setValue on the Quasar components:

                                        Apparently it can’t run because it’s a Quasar component, if I put a <button> it works.
                                        494c4781-694f-4903-a9d7-043ab3b517d9-image.png

                                        af66e3a7-c6b2-4940-842b-7e2e2e6d8ef0-image.png

                                        1 Reply Last reply Reply Quote 0
                                        • First post
                                          Last post