vue-form-wizard icon indicating copy to clipboard operation
vue-form-wizard copied to clipboard

Testing vue-form-wizard as component fails

Open thepill opened this issue 6 years ago • 3 comments

Hello,

i try to test a custom component using jest which uses vue-form-wizard as a child component.

but my test fails with the error message Prop startIndex set to 0 is greater than the number of tabs - 0. Make sure that the starting index is less than the number of tabs registered

the test looks like this:

 describe('Step Stammdaten', () => {
    it('shows all field errors on next click', () => {
      const wrapper = mount(NewEmployeeForm)
      wrapper.vm.$data.loading = false
      wrapper.find('button').trigger('click')
      expect(wrapper.findAll('#Stammdaten0 .form-input-error')).toHaveLength(6)
    })
  })

if i take a snapshot i can see that all id´s of the tab-panels are missing.

Any idea?

thepill avatar Aug 14 '18 11:08 thepill

Hey @thepill

can you show the NewEmployeeForm code ? You could try waiting for nextTick or

import flushPromises from 'flush-promises'

const wrapper = mount(NewEmployeeForm)
await flushPromises();

cristijora avatar Aug 14 '18 13:08 cristijora

Hey @cristijora

thanks for your reply - i tried using flushPromises() but it didn't work, but i might found my problem:

Im using https://github.com/baianat/vee-validate to validate my inputs. If i remove the v-validate tags from my inputs within the tab-content it works!?!

Code (sorry that it is not as simple):

NewEmployeeForm:

<template>
  <div
    v-if="!loading"
    class="wizard">
    <form-wizard
      :finish-button-text="submitButtonText"
      title=""
      subtitle=""
      next-button-text="Weiter"
      back-button-text="Zurück"
      step-size="xs"
      color="#2a887c"
      @on-complete="sendForm">
      <tab-content
        :before-change="beforeChangeFromBasicDataStep"
        title="Stammdaten">
        <div class="form">
          <div class="form-group-container">
            <div class="form-group">
              <input
                v-validate="'required'"
                id="gender-male"
                v-model="form.gender"
                type="radio"
                name="gender"
                value="Herr"
                data-vv-scope="basics"
                data-vv-as="Anrede">
              <label for="gender-male">Herr</label>
            </div>
          </div>
        </div>
      </tab-content>
      <tab-content
        v-if="customer.businessCategories.exchange === true"
        :before-change="beforeChangeFromEMailStep"
        title="E-Mail">

      </tab-content>
      <tab-content
        :before-change="beforeChangeFromPermissionsStep"
        title="System">

      </tab-content>
      <tab-content
        v-if="customer.businessCategories.datev === true"
        title="DATEV">

      </tab-content>
      <tab-content
        :before-change="beforeChangeFromAditionaltep"
        title="Zusätzliche Informationen">

      </tab-content>
      <tab-content title="Abschluss">
        <div>
          <h3>Zusammenfassung</h3>
          <p>Sie erhalten nach Abschluss ebenfalls eine Zusammenfassung per E-Mail.</p>
          <br>
          <form-summary :summary="formSummary"/>
        </div>
      </tab-content>
    </form-wizard>
  </div>
  <div v-else>
    <loading-spinner/>
  </div>
</template>

<script>
import { mapState } from 'vuex'
import utils from 'utils'
import api from 'api'
import FormMixin from 'mixins/FormMixin'
import WarningElement from 'components/basic/WarningElement'
import DatetimePicker from 'components/basic/DatetimePicker'
import MailboxAccessPermissions from 'components/mailbox/MailboxAccessPermissions'
import EmployeeSharePermissions from 'components/employee/EmployeeSharePermissions'
import LoadingSpinner from 'components/basic/LoadingSpinner'
import FormSummary from 'components/basic/forms/FormSummary'
import FormRemarks from 'components/basic/forms/FormRemarks'
import ContactPersonForm from 'components/basic/forms/ContactPersonForm'

export default {
  name: 'NewEmployeeForm',
  components: {
    WarningElement,
    DatetimePicker,
    LoadingSpinner,
    MailboxAccessPermissions,
    EmployeeSharePermissions,
    FormSummary,
    FormRemarks,
    ContactPersonForm
  },
  mixins: [FormMixin],
  data () {
    return {
      form: {
        gender: '',
        firstname: '',
        lastname: '',
        initials: '',
        staffId: undefined,
        phone: '',
        mailbox: false,
        email: undefined,
        datevEmailEncryption: false,
        vpn: 'Nein',
        scanner: false,
        increaseAllowedSimultaneousSessions: true,
        contact: {
          name: '',
          phone: ''
        },
        remarks: {},
        executionDate: undefined,
        blockTenantsInDatev: false
      },
      selectedWindowsReferenceUser: undefined,
      selectedDatevNukoReferenceUser: undefined,
      selectedDatevDMSReferenceUser: undefined,
      loading: true,
      sharePermissions: [],
      sharePermissionsLoading: false,
      showSystemPermissions: false
    }
  },
  computed: {
    ...mapState('employees', {
      employees: state => state.employees
    }),
    minExecutionDate () {
      return utils.getNextWorkingDate(5)
    },
    formSummary () {
      let summary = [
        {title: 'Stammdaten', isSectionHeader: true}
      ]
      return summary
    }
  },
  watch: {
    'selectedWindowsReferenceUser': function (user) {
      this.sharePermissionsLoading = true
      this.$store.dispatch('employees/FETCH_SHARE_PERMISSIONS', user.guid)
        .then(permissions => {
          this.sharePermissions = permissions.filter(s => s.name.toUpperCase().indexOf('WINDVSW') === -1)
          this.sharePermissionsLoading = false
        })
    }
  },
  async mounted () {
    this.$store.dispatch('employees/FETCH_EMPLOYEES')
    await this.$store.dispatch('customer/FETCH_CUSTOMER')
    this.form.executionDate = this.minExecutionDate
    this.loading = false
  },
  methods: {
    beforeChangeFromBasicDataStep () {
      this.form.email = utils.getEmailAdressFromPolicy(this.customer.primaryDomain, '%g.%s', this.form.firstname, this.form.lastname)
      this.form.mailbox = this.customer.businessCategories.exchange
      return this.$validator.validateAll('basics')
    },
    beforeChangeFromEMailStep () {
      return this.$validator.validateAll('mail')
    },
    beforeChangeFromPermissionsStep () {
      return this.$validator.validateAll('permissions')
    },
    beforeChangeFromAditionaltep () {
      return new Promise((resolve, reject) => {
        if (this.form.contact.name.length > 0 && this.form.executionDate !== undefined) {
          resolve(true)
        } else {
          reject(new Error('Missing contact name or execution date'))
        }
      })
    },
    async sendForm () {
      this.waitForSubmitResponse = true
      let formData = this.form
      formData.SystemReferenceUser = this.selectedWindowsReferenceUser.displayName
      formData.DatevNukoReferenceUser = this.selectedDatevNukoReferenceUser !== undefined ? this.selectedDatevNukoReferenceUser.displayName : ''
      formData.DatevDMSReferenceUser = this.selectedDatevDMSReferenceUser !== undefined ? this.selectedDatevDMSReferenceUser.displayName : ''

      let response = await api.sendForm('employees/new', 'POST', formData)
      const success = (response.status === 200)

      this.$router.push({ name: 'FormResultView', query: { success } })
    },
    showEmployeesDisplayNameWithState (employee) {
      return utils.showEmployeesDisplayNameWithState(employee)
    }
  }
}

</script>

<style scoped>

.reference-user {
  margin-bottom: 40px;
}

</style>

Test

import { createLocalVue, mount } from '@vue/test-utils'
import Vuex from 'vuex'
import NewEmployeeForm from 'components/employee/NewEmployeeForm'
import VeeValidate, {Validator} from 'vee-validate'
import VeeValidateDE from 'vee-validate/dist/locale/de'
import VueFormWizard from 'vue-form-wizard'
import flushPromises from 'flush-promises'

const localVue = createLocalVue()
localVue.use(VeeValidate, {errorBagName: 'formErrors'})
Validator.localize('de', VeeValidateDE)
localVue.use(VueFormWizard)
localVue.use(Vuex)

describe('Component NewEmployeeForm', () => {
  let store

  beforeEach(() => {
    const customer = {
      namespaced: true,
      state: {
        cachetime: undefined,
        customer: {
          businessCategories: {}
        }
      },
      actions: {
        FETCH_CUSTOMER: jest.fn()
      }
    }

    const user = {
      namespaced: true,
      state: {
        currentUser: {
          displayName: 'asdasd'
        }
      },
      actions: {
        FETCH_CURRENT_USER: jest.fn()
      },
      getters: {
        currentUser: state => state.currentUser
      }
    }

    const employees = {
      namespaced: true,
      state: {
        employees: []
      }
    }

    store = new Vuex.Store({
      modules: {
        customer,
        user,
        employees
      }
    })
  })

  it('test', async () => {
    const wrapper = mount(NewEmployeeForm, {store, localVue, attachToDocument: true})
    wrapper.vm.$data.loading = false
    await flushPromises()
    expect(wrapper).toMatchSnapshot()
  })
})

Test Snapshot Output

// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Component NewEmployeeForm sets the correct default data 1`] = `
<div class="wizard">
  <div class="vue-form-wizard xs">
    <div class="wizard-header">
      <h4 class="wizard-title"></h4>
      <p class="category"></p>
    </div>
    <div class="wizard-navigation">
      <div class="wizard-progress-with-circle">
        <div class="wizard-progress-bar" style="background-color: rgb(42, 136, 124); color: rgb(42, 136, 124);"></div>
      </div>
      <ul role="tablist" class="wizard-nav wizard-nav-pills"></ul>
      <div class="wizard-tab-content">
        <div role="tabpanel" id="" aria-hidden="true" aria-labelledby="step-" class="wizard-tab-container" style="display: none;">
          <div class="form">
            <div class="form-group-container">
              <div class="form-group">
                <input id="gender-male" type="radio" name="gender" value="Herr" data-vv-scope="basics" data-vv-as="Anrede" aria-required="true" aria-invalid="false">
                <label for="gender-male">Herr</label>
              </div>
            </div>
          </div>
        </div>
        <!---->
        <div role="tabpanel" id="" aria-hidden="true" aria-labelledby="step-" class="wizard-tab-container" style="display: none;"></div>
        <!---->
        <div role="tabpanel" id="" aria-hidden="true" aria-labelledby="step-" class="wizard-tab-container" style="display: none;"></div>
        <div role="tabpanel" id="" aria-hidden="true" aria-labelledby="step-" class="wizard-tab-container" style="display: none;">
          <div>
            <h3>Zusammenfassung</h3>
            <p>Sie erhalten nach Abschluss ebenfalls eine Zusammenfassung per E-Mail.</p>
            <br>
            <div class="form-summary">
              <table>
                <tr>
                  <td class="form-summary-section top-section">Stammdaten</td>
                </tr>
              </table>
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="wizard-card-footer clearfix">
      <div class="wizard-footer-left">
        <!---->
      </div>
      <div class="wizard-footer-right"> <span role="button" tabindex="0"><button tabindex="-1" type="button" class="wizard-btn" style="background-color: rgb(42, 136, 124); border-color: #2a887c; color: white;">
            Weiter
           </button></span></div>
    </div>
  </div>
</div>
`;

thepill avatar Aug 15 '18 07:08 thepill

@thepill well i tried to use veevalidate with form-wizard but idon't know what's wrong .. how did you use it please ? i have two forms to validate so i used scoops

  <div class="row">
    <div class="col-xs-12 col-sm-12 col-md-6 col-md-offset-3 col-lg-6 col-lg-offset-3">
      <div class="form-group">
        <label class="user-type">
          <i class="ci_user ci-service-provider"></i>
          <span> {{ t('service_provider') }}</span>
          <input type="radio" id="role_id" name="role_id" v-model="account_type" value="3"  v-validate="'required|included:3,2'" /><span></span>
        </label>
        <label class="user-type">
          <i class="ci_user ci-user"></i>
          <span>{{ t('customer') }}</span>
          <input type="radio" id="role_id" name="role_id" v-model="account_type" value="2" v-validate="'required|included:3,2'" checked/><span></span>
        </label>
      </div>
    </div>
  </div>
</tab-content>
<tab-content :title="t('account_data')" :before-change="()=>validateStep('step1')">
  <form data-vv-scope="step1"  @on-validate="mergePartialModels">
    <div class="row">
      <div class="col-xs-12 col-sm-12 col-md-6 col-md-offset-3 col-lg-6 col-lg-offset-3">
        <div class="form-group">
          <input id="name" type="text" class="form-control" v-model="name" name="name" :placeholder="t('fullname')" v-validate="{ required: true , min:8 ,max:30}" :class="{'is-danger': errors.has('name') }" required autofocus>
          <span v-show="errors.has('name')" class="help is-danger">{{ errors.first('name') }}</span>
        </div>
        <div class="form-group">
          <input id="email" type="email" class="form-control" v-model="email" name="email" :placeholder="t('email')" required>
        </div>
        <div class="form-group">
          <input type="text" class="form-control" v-model="phone" name="phone" :placeholder="t('phone')" required>
        </div>
        <div class="form-group">
          <input id="password" type="password" class="form-control" v-model="password" name="password" required :placeholder="t('password')">
        </div>
        <div class="form-group">
          <input id="password-confirm" type="password" class="form-control" v-model="password_confirmation" name="password_confirmation" :placeholder="t('password_confirm')" required>
        </div>
      </div>
    </div>
  </form>
</tab-content>
<tab-content title="Last step">
  Yuhuuu! This seems pretty damn simple
</tab-content>

any help please

saraElsanan avatar Jan 10 '19 20:01 saraElsanan