代码之家  ›  专栏  ›  技术社区  ›  user762579

vue单元测试-触发事件(表单提交)后未按预期更新数据

  •  0
  • user762579  · 技术社区  · 7 年前

    我正在测试表单数据是否在提交后发送。

    import Vue from "vue";
    import Vuex from "vuex";
    import { mount, shallowMount } from "@vue/test-utils";
    
    import VeeValidate from "vee-validate";
    import i18n from "@/locales";
    import Vuetify from "vuetify";
    
    import ContactForm from "@/components/Home/ContactForm.vue";
    
    Vue.use(VeeValidate, { errorBagName: "errors" });
    Vue.use(Vuetify);
    
    Vue.use(Vuex);
    
    describe("ContactForm.vue", () => {
      let store;
      let wrapper;
      let options;
      let input;
    
      const v = new VeeValidate.Validator();
    
    
      beforeEach(() => {
        const el = document.createElement("div");
        el.setAttribute("data-app", true);
        document.body.appendChild(el);
      });
    
      it("should sendMessage - valid form", async () => {
        // given
        store = new Vuex.Store({
          state: {
            language: "en",
            loading: false
          }
        })
        options = {
          sync: false,
          provide: {
            $validator () {
              return new VeeValidate.Validator();
            }
          },
          i18n,
          store
        };
        wrapper = mount(ContactForm, options);
        // when
        const radioInput = wrapper.findAll('input[type="radio"]');
        radioInput.at(1).setChecked(); // input element value is changed, v-model is not
        radioInput.at(1).trigger("change"); // v-model updated
    
        input = wrapper.find('input[name="givenName"]');
        input.element.value = "John"; // input element value is changed, v-model is not
        input.trigger("input"); // v-model updated
    
        input = wrapper.find('input[name="familyName"]');
        input.element.value = "Doe"; // input element value is changed, v-model is not
        input.trigger("input"); // v-model updated
    
        input = wrapper.find('input[name="email"]');
        input.element.value = "john.doe@example.com"; // input element value is changed, v-model is not
        input.trigger("input"); // v-model updated
    
        input = wrapper.find('textarea[name="messageContent"]');
        input.element.value = "Hello World!"; // input element value is changed, v-model is not
        input.trigger("input"); // v-model updated
    
        const contactForm = wrapper.find("form");
        contactForm.trigger("submit");
        await wrapper.vm.$nextTick();
    
        // then
        console.log("DATA: ", wrapper.vm.$data.contactLang);
        expect(wrapper.vm.validForm).toEqual(true);
      });
    
    });
    

    验证成功(因此组件中的validForm设置为true)

    控制台.log

        ✕ should sendMessage - valid form (476ms)
    
      ● ContactForm.vue › should sendMessage - valid form
    
        expect(received).toEqual(expected)
    
        Expected value to equal:
          true
        Received:
          false
    

    组件vue是

    联系人表单.vue

    <template>
      <form id="contactForm" @submit="sendMessage()">
        <input v-model="contactLang" type='hidden' data-vv-name="contactLang" v-validate="'required'" name='contactLang'>
        <v-layout row wrap align-center>
          <v-flex xs12 sm3 md3 lg3>
            <v-radio-group row :mandatory="false" v-model="gender" name="gender">
              <v-radio :label='genderLabel("f")' value="f" name="female"></v-radio>
              <v-radio :label='genderLabel("m")' value="m" name="male"></v-radio>
            </v-radio-group>
          </v-flex>
          <v-flex xs12 sm4 md4 lg4>
            <v-text-field
              v-model="givenName"
              browser-autocomplete="off"
              :label="$t('lang.views.home.contactForm.givenName')"
              data-vv-name="givenName"
              :error-messages="errors.collect('givenName')"
              v-validate="'required'"
              name="givenName">
            </v-text-field>
          </v-flex>
          <v-flex xs12 sm5 md5 lg5>
             <v-text-field
              v-model="familyName"
              browser-autocomplete="off"
              :label="$t('lang.views.home.contactForm.familyName')"
              data-vv-name="familyName"
              :error-messages="errors.collect('familyName')"
              v-validate="'required'"
              name="familyName">
            </v-text-field>
          </v-flex>
        </v-layout>
        <v-text-field
          browser-autocomplete="off"
          v-model="email"
          :label="$t('lang.views.home.contactForm.email')"
          data-vv-name="email"
          :error-messages="errors.collect('email')"
          v-validate="'required|email'"
          name="email">
        </v-text-field>
        <v-textarea v-model="messageContent" :label="$t('lang.views.home.contactForm.message')" :error-messages="errors.collect('messageContent')" :rules="[(v) => v.length <= 200 || 'Max 200 characters']" :counter="200" v-validate="'required'" data-vv-name="messageContent" name="messageContent"></v-textarea>
        <v-btn id="btnClear" round @click.native="clear">{{ $t('lang.views.global.clear') }}</v-btn>
        <v-btn round large color="primary" type="submit">{{ $t('lang.views.global.send') }}
          <v-icon right>email</v-icon><span slot="loader" class="custom-loader"><v-icon light>cached</v-icon></span>
        </v-btn>
      </form>
    </template>
    
    <script>
    import swal from "sweetalert2";
    import { mapState } from "vuex";
    import appValidationDictionarySetup from "@/locales/appValidationDictionary";
    
    export default {
      name: "contactForm",
      $_veeValidate: { validator: "new" },
      data() {
        return {
          contactLang: "",
          gender: "f",
          givenName: "",
          familyName: "",
          email: "",
          messageContent: "",
          validForm: false
        };
      },
       ...
      methods: {
       ...
        sendMessage: function() {
          console.log("sendMessage()...");
          this.$validator
            .validateAll()
            .then(isValid => {
              console.log("VALIDATION RESULT: ", isValid);
              this.validForm = isValid;
              if (!isValid) {
                console.log("VALIDATION ERROR");
                // console.log("Errors: ", this.$validator.errors.items.length);
                const alertTitle = this.$validator.dictionary.container[
                  this.language
                ].custom.error;
                const textMsg = this.$validator.dictionary.container[this.language]
                  .custom.correct_all;
                swal({
                  title: alertTitle,
                  text: textMsg,
                  type: "error",
                  confirmButtonText: "OK"
                });
                return;
              }
              console.log("validation success, form submitted validForm: ", this.validForm);
              return;
            })
            .catch(e => {
              // catch error from validateAll() promise
              console.log("error validation promise: ", e);
              this.validForm = false;
              return;
            });
        },
        clear: function() {
          this.contactLang = "";
          this.gender = "f";
          this.givenName = "";
          this.familyName = "";
          this.email = "";
          this.messageContent = "";
          this.validForm = false;
          this.$validator.reset();
        }
      },
      mounted() {
        appValidationDictionarySetup(this.$validator);
        this.$validator.localize(this.language);
        this.contactLang = this.language;
      }
    };
    </script>
    
    
    </style>
    

    以及控制台.log调试是

     console.log src/components/Home/ContactForm.vue:90
        sendMessage()...
    
      console.log tests/unit/ContactForm.spec.js:242
        DATA:  en
    
      console.log src/components/Home/ContactForm.vue:94
        VALIDATION RESULT:  true
    

          console.log src/components/Home/ContactForm.vue:90
            sendMessage()...
    
          console.log tests/unit/ContactForm.spec.js:242
            DATA:  en
    
          console.log src/components/Home/ContactForm.vue:94
            VALIDATION RESULT:  true
    
          console.log src/components/Home/ContactForm.vue:112
            validation success, form submitted validForm:  true
    

    我想有异步问题。。。超时?

    感谢您的反馈

    2 回复  |  直到 7 年前
        1
  •  1
  •   Bruno Peres    5 年前

    解决了的 这实际上是一个超时问题

    expect.assertions(1); // Otherwise jest will give a false positive
    await contactForm.trigger("submit");
    
    // then
    setTimeout(() => {
      expect(wrapper.vm.validForm).toEqual(true);
    }, 2000);
    
        2
  •  1
  •   Bruno Peres    5 年前

    我建议用玩笑的骗子

    jest.useFakeTimers()
    
    contactForm.trigger("submit");
    await wrapper.vm.$nextTick();
    
    // then
    jest.runTimersToTime(2000)
    expect(wrapper.vm.validForm).toEqual(true);
    

    我建议先让测试失败以避免误报

    更多关于小丑骗子的信息 https://jestjs.io/docs/en/timer-mocks.html

        3
  •  0
  •   Francisco Rodeño Sanchez    6 年前

    it("submit form call method login", () => {
        const login = jest.fn()
        const wrapper = shallowMount(Login, {
            methods: {
                login
            }
        })
    
        wrapper.findAll("v-form").at(0).trigger("submit")
    
        expect(login).toBeCalled()
    })