Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeError: Cannot read property 'split' of undefined #839

Closed
PratsBhatt opened this issue Jul 20, 2018 · 11 comments
Closed

TypeError: Cannot read property 'split' of undefined #839

PratsBhatt opened this issue Jul 20, 2018 · 11 comments
Labels

Comments

@PratsBhatt
Copy link

Version

1.0.0-beta.20

Reproduction link

https://codesandbox.io/s/mzlzo73j7p

Steps to reproduce

Sorry unable to provide with the code as I would have to do a lot of boiler plate code as there are few dependencies such as Vuetify, Vuex and graphql.

I am providing a pseudo code. You can find the code in the test/test.js

Issue:
When I am trying to test a button click event I am getting error 'TypeError: Cannot read property 'split' of undefined'.
On button click an action is triggered that triggers mutation and updates the store.
I am writing integration tests that actually mocks the graphql server and provides with the fake data.

Note:
I have vuex store.
I am using Vuetify as the component library.

Steps to Reproduce:
const btn = wrapper.findAll({name: 'v-btn'});
btn.at(1).trigger('click');
After this I get above mentioned error.

I would like to know if there is something I can do to resolve the issue.

What is expected?

Expected behavior is that on the button click event the store should get updated with the mock data that was supplied.

What is actually happening?

Actually error is occurring - TypeError: Cannot read property 'split' of undefined


I have read few issue surrounding this which comments on transition. I have followed #52
and applied
stubs: {
'transition': TransitionStub,
'transition-group': TransitionGroupStub
}
With no success. I am not aware of what is actually happening it would be great if anybody can throw some light.

@eddyerburgh
Copy link
Member

Without a reproduction I can't debug. But this might be an issue with the sync mode.

Try set the sync mounting option to false and use Vue.nextTick/ setTimeout to await watcher updates:

test('use Vue.nextTick', (done) => {
  const wrapper = mount(TestComponent, { sync: false })
  wrapper.trigger('click')
  Vue.nextTick(() => {
    expect(wrapper.text()).toBe('updated')
    done()
  })
})

@PratsBhatt
Copy link
Author

Hello @eddyerburgh I understand your point, I will try to create a repo asap. Actually there are too many dependencies and that was the reason I wrote psuedo code only.

I tried sync=false, didn't work I got the same error.

console.error node_modules/vue/dist/vue.runtime.common.js:1739 TypeError: Cannot read property 'split' of undefined

In the mean while I will try to provide with more details.
Actually I have 2 more test cases above that checks the data when entered in the text box. They all run fine.

It would be helpful if you could throw some more light on this matter.
Thank you once again. Great work.

@eddyerburgh
Copy link
Member

Unfortunately there isn't anything I can do without a reproduction, can you create a minimal reproduction for me?

@martosoler
Copy link

Hi,

I'm having a similar error when testing a simple Login component:

TypeError: Cannot read property 'split' of undefined
          at getTransitionInfo (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:7005:58)
          at VueComponent.hasMove (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:7935:18)
          at VueComponent.updated (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:7881:35)
          at callHook (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:2919:21)
          at callUpdatedHooks (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:3020:7)
          at flushSchedulerQueue (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:3005:3)
          at Array.<anonymous> (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:1835:12)
          at flushCallbacks (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:1756:14)
          at <anonymous>
          at process._tickCallback (internal/process/next_tick.js:188:7)

The component is:

<template>
  <v-card>
    <v-form @submit.prevent="submit">
      <v-card-title primary-title class="primary white--text">
        <div class="headline">Login</div>
      </v-card-title>
      <v-card-text>
        <v-text-field
          v-validate="'required|email'"
          v-model="email"
          :error-messages="errors.collect('email')"
          label="E-mail"
          data-vv-name="email"
          required
        ></v-text-field>
        <v-text-field
          v-validate="'required|min:6'"
          v-model="password"
          :error-messages="errors.collect('password')"
          label="Password"
          data-vv-name="password"
          required
          :append-icon="showPassword ? 'visibility_off' : 'visibility'"
          :type="showPassword ? 'text' : 'password'"
          @click:append="showPassword = !showPassword"
        ></v-text-field>
        <span v-if="this.erroLogin" class="v-messages error--text">{{ this.erroLogin }}</span>
      </v-card-text>
      <v-card-actions class="pa-3">
        <router-link :to="{ name: 'forgot' }">Forgot Password?</router-link>
        <v-spacer></v-spacer>
        <v-btn color="primary" type="submit" id="login-btn">Login</v-btn>
      </v-card-actions>
    </v-form>
  </v-card>
</template>
<script>
import firebase from 'firebase';

export default {
  name: 'login',
  data() {
    return {
      email: '',
      password: '',
      showPassword: false,
      erroLogin: null,
    };
  },
  methods: {
    submit() {
      this.$validator.validateAll().then(isValid => {
        if (isValid) {
          firebase
            .auth()
            .signInWithEmailAndPassword(this.email, this.password)
            .then(
              () => {
                this.erroLogin = null;
                this.$router.push({ name: 'home' });
              },
              err => {
                this.erroLogin = this.getErrorMessage(err.code);
              },
            );
        }
      });
    },
    getErrorMessage(errorCode) {
      ...
    },
  },
};
</script>

And the test:

import Vue from 'vue';

import Vuetify from 'vuetify';
import { mount, createLocalVue } from '@vue/test-utils';
import VeeValidate from 'vee-validate';
import VueRouter from 'vue-router';
import Login from './Login';

jest.mock('firebase');

Vue.config.silent = true;

const localVue = createLocalVue();

localVue.use(Vuetify);
localVue.use(VeeValidate);
localVue.use(VueRouter);

describe('Login', () => {
  describe('Error handling', () => {
    const routes = [
      { path: '/forgot', name: 'forgot' },
    ];

    const router = new VueRouter({ routes });

    const wrapper = mount(Login, {
      localVue,
      router,
      sync: false,
    });

    it('should call Firebase login', (done) => {
      wrapper.setData({ email: 'test@email.com', password: 'password' });

      const loginButton = wrapper.find('#login-btn');
      loginButton.trigger('click');

      Vue.nextTick(() => {
        console.log(wrapper.vm.$route.name);
        done();
      });
    });
  });

What's weird is that the test passes but the console is showing that stacktrace.

The project is using Vue, Vuetify and VeeValidate.

@PratsBhatt
Copy link
Author

Hello @martosoler,

Thank you for providing with a reproduction code. I have seen when the code is as below then the test fails on execution.

it('should call Firebase login', () => { wrapper.setData({ email: 'test@email.com', password: 'password' }); return wrapper.vm.$nextTick().then(() => { const loginButton = wrapper.find('#login-btn'); loginButton.trigger('click'); console.log(wrapper.vm.$route.name); });
I am not sure if it's the correct way to do it actually.

@martosoler
Copy link

I tried upgrading the version of vue-test-utils to the lastest (1.0.0-beta.23) but the issue is still there, the only new thing I have found is that the stacktrace appears every time I use flushPromises():

it('should go to home after sucessfull login', async () => {
      authentication.login = jest.fn(() => Promise.resolve(''));

      wrapper.setData({ email: 'test@test.com', password: 'password' });
      await flushPromises();

      wrapper.find('#login-btn').trigger('click');
      await flushPromises();

      expect(authentication.login).toHaveBeenCalledWith('test@test.com', 'password');
      expect(wrapper.vm.$route.name).toBe('home');
    });

Note: I have abstracted Firebase library call into a authentication module
So, in the above call the following stacktrace appears twice:

 PASS  src/components/User/Login/Login.spec.js
  ● Console

    console.error node_modules/vue/dist/vue.runtime.common.js:1739
      TypeError: Cannot read property 'split' of undefined
          at getTransitionInfo (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:7005:58)
          at VueComponent.hasMove (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:7935:18)
          at VueComponent.updated (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:7881:35)
          at callHook (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:2919:21)
          at callUpdatedHooks (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:3020:7)
          at flushSchedulerQueue (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:3005:3)
          at Array.<anonymous> (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:1835:12)
          at flushCallbacks (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:1756:14)
          at <anonymous>
    console.error node_modules/vue/dist/vue.runtime.common.js:1739
      TypeError: Cannot read property 'split' of undefined
          at getTransitionInfo (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:7005:58)
          at VueComponent.hasMove (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:7935:18)
          at VueComponent.updated (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:7881:35)
          at callHook (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:2919:21)
          at callUpdatedHooks (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:3020:7)
          at flushSchedulerQueue (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:3005:3)
          at Array.<anonymous> (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:1835:12)
          at flushCallbacks (/Users/devgurus/projects/newleads/newleads-admin-site/node_modules/vue/dist/vue.runtime.common.js:1756:14)
          at <anonymous>

I can see that the error is being thrown in the getTransitionInfo function but I'm not using transitions anywhere in my code, I suspect Vuetify or VeeValidate might be using it internally.

@eddyerburgh
Copy link
Member

eddyerburgh commented Aug 4, 2018

Yes @martosoler that's an issue with an un stubbed TransitionGroup. Are you able to provide a reproduction?

The error is thrown because you're running in an environment without transition styles (I'm guessing JSDOM). A quick workaround is to monkey patch window.getComputedStyles before you run your tests:

const { getComputedStyle } = window
window.getComputedStyle = function getComputedStyleStub(el) {
	return {
		...getComputedStyle(el),
		transitionDelay: '',
		transitionDuration: '',
		animationDelay: '',
		animationDuration: '',
	}
}

@tbsvttr
Copy link

tbsvttr commented Aug 6, 2018

I have the same problem with:

  • Vue 2.5.16
  • Vuetify 1.1.9
  • Vue Test Utils 1.0.0 Beta 16
  • Jest 23.1.0
    (and a lot of other stuff)

I mount all my test wrappers with sync: false.

@eddyerburgh That monkey patch solved the issue for me. Any chance to solve this in a more clean way?

@eddyerburgh
Copy link
Member

eddyerburgh commented Aug 6, 2018 via email

@Mourdraug
Copy link

@eddyerburgh I was finally able to reproduce this in simpler project, I tried to simplify it more, but simple move-transition didn't trigger it, so it still uses Vuetify. There are 2 identical specs, only one uses workaround you provided.

https://github.com/Mourdraug/transition-bug-repro

@zeroarst
Copy link

zeroarst commented Sep 20, 2018

For me I need to do both things to completely pass the test and get rid of error in console.

const { getComputedStyle } = window
window.getComputedStyle = function getComputedStyleStub(el) {
	return {
		...getComputedStyle(el),
		transitionDelay: '',
		transitionDuration: '',
		animationDelay: '',
		animationDuration: '',
	}
}
test('use Vue.nextTick', (done) => {
  const wrapper = mount(TestComponent, { sync: false })
  wrapper.trigger('click')
  Vue.nextTick(() => {
    expect(wrapper.text()).toBe('updated')
    done()
  })
})

This happens when the test dimisses the VueMaterial MdDialog.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants