我遇到了Vue Test Utils的问题 . 当我进行单元测试时,我总是遇到:

TypeError {line:73983,sourceURL:'http://localhost:9876/base/index.js?045b00affe888fcd6b346c4fe50eadd13d471383 ', stack: ' mounted @ http://localhost:9876/base/index.js?045b00affe888fcd6b346c4fe50eadd13d471383:73983:30 .....

这只发生在Vue组件中有mounted()函数时

Settings.vue

mounted() {
  this.$refs.address.update(this.profile.address)
},

Settings.spec.js

it('calls updateUserInformation before mount', () => {
        const spy = sinon.spy(Settings.methods, 'updateUserInformation')
        shallow(Settings, { propsData })
        Vue.nextTick().then(() => {
          spy.should.have.calledOnce()
        })
    })

我正在使用 Mocha & Chaivue-test-utils . 有谁知道为什么会这样?

先感谢您!

更新

Settings.vue 组件HTML

<vue-google-autocomplete
  ref="address"
  id="map"
  classname="input"
  placeholder="Address"
  v-on:placechanged="getAddressPlaceChanged"
  v-on:inputChange="getAddressInputChange"
  :country="['sg']"
>
</vue-google-autocomplete>

Settings.vue 组件Javascript

export default {
    components: {
      GoogleMaps,
      AutoComplete,
      VueGoogleAutocomplete,
      Partner,
    },
    watch: {
      // whenever school changes, this function will run
      school() {
        // Check if school value is an empty string or character is lesser than FIX_STR_LENGTH
        if (this.school === '' || this.school.length < this.FIX_STR_LENGTH) {
          this.removeMarker('school')
        }
        this.fetchSchools()
      },
    },
    methods: {
      async onSubmit() {
        // Check if input fields are empty
        if (this.address !== undefined && this.phoneNumber !== null && this.school !== '') {
          const { placeResultData = {}, addressData = {} } = this.address
          let isSuccessful = false
          let tempLat = null
          let tempLong = null
          let tempAddress = null
          // Check if address is an empty object
          if (_.isEmpty(this.address)) {
            const { latlong = {}, address = '' } = this.profile
            const [lat, long] = latlong.coordinates
            tempLat = lat
            tempLong = long
            tempAddress = address
          } else {
            // User changed address location
            tempLat = addressData.latitude
            tempLong = addressData.longitude
            tempAddress = placeResultData.formatted_address
          }
          // Validate school address array
          let tempSchoolAddress = []
          if (this.selectedSchool !== null) {
            tempSchoolAddress.push(this.selectedSchool.postal_code)
          } else {
            tempSchoolAddress = this.profile.schoolAddress
          }
          // Construct user object for registration/update
          const user = new User(
            this.profile.name,
            tempAddress,
            tempLat,
            tempLong,
            tempSchoolAddress,
          )
          // If user does not exist in database, perform a POST API registration request
          if (this.userExist === false) {
            // Add user properties for user registration
            user.phoneNumber = this.phoneNumber
            await UserSession.register(user, localStorage.getItem('id_token')).then((response) => {
              const { data = {} } = response
              const profile = data.user
              this.updateUserInformation(profile)
              isSuccessful = true
              this.profile = profile
            }).catch((error) => {
              console.log(error.response)
            })
          }
          // Perform a PUT API update request
          await UserSession.update(user, localStorage.getItem('id_token')).then((response) => {
            const { data = {} } = response
            const profile = data.user
            this.updateUserInformation(profile)
            isSuccessful = true
            this.profile = profile
          }).catch((error) => {
            console.log(error.response)
          })
          if (isSuccessful) {
            this.profileChanged()
            this.hasChanged = true
          }
        }
      },
      profileChanged() {
        this.$emit('profileChanged', this.profile)
      },
      addMarker(name, params) {
        if (params === null || params === '') {
          return
        }
        gMapSession.default(params).then((response) => {
          const { location = {} } = response.data.results[0].geometry
          // Remove existing marker before replacing it
          this.removeMarker(name)
          this.markers.push({
            position: location,
            name,
          })
          this.zoom = 11
        }).catch((error) => {
          console.log(error.response)
        })
      },
      removeMarker(name) {
        let index = 0
        let exist = false
        for (let i = 0; i < this.markers.length; i++) {
          if (this.markers[i].name === name) {
            index = i
            exist = true
            break
          }
        }
        if (exist) {
          this.markers.splice(index, 1)
        }
      },
      // Function called when user selects an option from the school autocomplete dropdown
      getSelectedSchoolData(event) {
        this.selectedSchool = event
        // Check if selected school is defined
        if (this.selectedSchool !== undefined && this.selectedSchool !== null) {
          this.addMarker('school', this.selectedSchool.postal_code)
        } else {
          this.removeMarker('school')
        }
      },
      // Function called when user types in the address autocomplete input field
      getAddressInputChange(data) {
        const { newVal = {} } = data
        if (newVal === '' || newVal.length < this.FIX_STR_LENGTH) {
          this.removeMarker('user')
        }
      },
      // Function called when user selects an option from the address autocomplete dropdown
      getAddressPlaceChanged(addressData, placeResultData) {
        this.address = {
          placeResultData,
          addressData,
        }
        if (addressData !== undefined && addressData !== null) {
          this.addMarker('user', addressData.postal_code)
        } else {
          this.removeMarker('user')
        }
      },
      async updateUserInformation(profile) {
        this.phoneNumber = profile.phoneNumber
        this.addMarker('user', profile.address)
        // TODO: schoolAddress is an array and UI must cater to multiple schools
        await SchoolSession.default(profile.schoolAddress[0]).then(async (res) => {
          const { result = {} } = res.data
          const { records = [] } = result
          // Assume that a single postal code contains only 1 school
          this.school = records[0].school_name
          this.addMarker('school', records[0].postal_code)
        })
      },
      // Fetch school information base on school search query
      fetchSchools: _.debounce(function getSchools() {
        if (this.school.trim() === '') {
          this.schools = []
          return
        }
        const vm = this
        SchoolSession.default(this.school).then((response) => {
          // JSON responses are automatically parsed.
          const { records = {} } = response.data.result
          vm.schools = records
        }).catch((error) => {
          console.log(error.response)
        })
      }, 500),
    },
    data() {
      return {
        FIX_STR_LENGTH: 5,
        school: '',
        address: '',
        schools: [],
        markers: [],
        phoneNumber: null,
        selectedSchool: null,
        userExist: false,
        hasChanged: false,
        center: { lat: 1.3521, lng: 103.8198 },
        zoom: 7,
      }
    },
    async created() {
      this.profile = this.$attrs
      // Check if user was a registered member by phone number
      if (this.profile.phoneNumber === undefined) {
        return
      }
      // User exist in the database
      this.userExist = !this.userExist
      // Update form information
      this.updateUserInformation(this.profile)
    },
    mounted() {
      this.$refs.address.update(this.profile.address)
    },
  }