Code Monkey home page Code Monkey logo

Comments (12)

afontcu avatar afontcu commented on May 18, 2024 1

Hi! Thanks for the detailed answer.

I've set up a PR to try to bound queries to the parent node: #100

from vue-testing-library.

afontcu avatar afontcu commented on May 18, 2024 1

Hi! I can't think of any downsides of the top of my head, as long as Vuetify issue with multiple Vue instances is still a thing (I guess it is!). This is something that should be fixed on their own, so I'd say having a comfortable workaround should do the trick 👍

from vue-testing-library.

bennettdams avatar bennettdams commented on May 18, 2024 1

The example above works only for Vuetify components that don't use the $vuetify instance property

(e. g. <v-menu> will always throw an undefined error in the test).

You can bypass this by using { vuetify: new Vuetify(), ...options },.

For any future readers, here is the complete setup:

Maybe interesting for the documentation/examples?

test-setup.js executed via Jest's setupFiles in the jest.config.js

import Vue from "vue";
import Vuetify from "vuetify";

// We need to use a global Vue instance, otherwise Vuetify will complain about
// read-only attributes.
// More info: https://github.com/vuetifyjs/vuetify/issues/4068
//            https://vuetifyjs.com/en/getting-started/unit-testing
Vue.use(Vuetify);

test-helper.js used in the tests instead of VTL's render

import { render as VTLRender } from "@testing-library/vue";
import Vuetify from "vuetify";

/**
 * Custom render wrapper to integrate Vuetify with Vue Testing Library.
 *
 * Vuetify requires you to wrap your app with a `v-app` component that provides
 * a `<div data-app="true">` node.
 *
 * More info:
 *    https://github.com/vuetifyjs/vuetify/issues/4068
 *    https://vuetifyjs.com/en/getting-started/unit-testing
 *
 * @param {*}           component Component from test to render
 * @param {*}           options Render options
 * @param {() => void}  callback Render callback
 * @return {*}          Render function of VTL including Vuetify `data-app`
 */
export const renderWithVuetify = (component, options, callback) => {
  return VTLRender(
    // anonymous component
    {
      // Vue's render function
      render(createElement) {
        // wrap the component with a <div data-app="true"> node and render the test component
        return createElement("div", { attrs: { "data-app": true } }, [
          createElement(component)
        ]);
      }
    },
    { vuetify: new Vuetify(), ...options },
    callback
  );
};

Actual component test

import { renderWithVuetify } from "../test-helper";
import MyComponent from "../../src/views/MyComponent.vue";

describe("MyComponent.vue", () => {
  test("Some test...", () => {
    const { getByText } = renderWithVuetify(MyComponent);

    expect(getByText(/some text/));
  });
});

from vue-testing-library.

afontcu avatar afontcu commented on May 18, 2024

Hi! Thanks for the detailed issue.

We've got similar requests/issues through other channels regarding modals and, in general, elements that render outside of the parent component DOM node tree.

I do believe there's a divergence between Vue Testing Lib and React Testing Lib, since their queries are bound to the whole document, not the wrapper of the rendered element.

Bounding queries to the outermost element (the body, as to speak) would fix your issue, wouldn't it? It is something I plan on working soon, and I'll use your example to test it out. I'll keep you posted.

For the time being, and from the top of my head, would creating a custom renderer solve your issue?

import { render as VTLRender } from '@testing-library/vue'

const renderWithVuetify = (comp, options, cb) => {
  return VTLRender({
    // render function
    render(h) {
      // wrap your component with a <div data-app="true"> node
      return h('div', { attrs: { 'data-app': true }}, comp)
    },
    options,
    cb
  })
}


// and then, somewhere else:

const { getByText } = renderWithVuetify(MyComp)

(Can't test it right now, so syntax might be a bit off).

from vue-testing-library.

afontcu avatar afontcu commented on May 18, 2024

Oh, by the way, Vue.use(Vuetify) should be performed using the callback function provided by render() (example):

const { getByText } = render(MyComp, {}, vue => {
  vue.use(Vuetify)
})

this is something that could be done inside your custom renderer, too, so you don't have to repeat it every time.

from vue-testing-library.

ChristophWalter avatar ChristophWalter commented on May 18, 2024

Thanks for your fast response!

Bounding queries to the outermost element (the body, as to speak) would fix your issue, wouldn't it?

Yes, this would work. 👍

For the time being, and from the top of my head, would creating a custom renderer solve your issue?

I did it quite similar and it works. Just not sure on how to pass all events up, so emitted() still works. Here is the (fixed) example:

import { render as VTLRender } from '@testing-library/vue'

function renderWithVuetify(component, options, callback) {
	return VTLRender(
		{
			render(h) {
				return h('div', { attrs: { 'data-app': true } }, [
					h(component, {
						props: options.props,
					}),
				])
			},
		},
		options,
		callback
	)
}

Oh, by the way, Vue.use(Vuetify) should be performed using the callback function provided by render() (example):

Yeah, it should... But vuetify has an issue with multiple vue instances if it is initialized like that. This might be already fixed in the current version. In the meantime I use the jest setup file to set this once for every test. Here is the vuetify issue: vuetifyjs/vuetify#4068

from vue-testing-library.

afontcu avatar afontcu commented on May 18, 2024

🎉 This issue has been resolved in version 4.0.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

from vue-testing-library.

bennettdams avatar bennettdams commented on May 18, 2024

Thanks to this conversation I created a wrapper to use Vuetfiy, but there is one thing that I'm not sure about.

I would like to eliminate the need of writing Vue.use(Vuetify) in every test, so I now do that when overwriting the render function as discussed in this conversation.

In the end it is another global Vue instance, so are there any downsides of doing it like that?
Could/should you somehow use the callback of the render function?

export const renderWithVuetify = (component, options, callback) => {
  Vue.use(Vuetify);  // downsides?
  return VTLRender(
    {
      render(h) {
        // wrap the component with a <div data-app="true"> node
        return h("div", { attrs: { "data-app": true } }, [h(component)]);
      }
    },
    options,
    callback
  );
};
// in the test
// const { getByText } = renderWithVuetify(MyComponent);

Or should the test pass its Vue instance via the wrapper function?

export const renderWithVuetify = (component, vueInstance, options, callback) => {
  vueInstance.use(Vuetify);  // downsides?
  return VTLRender(
  ....
// in the test
// const { getByText } = renderWithVuetify(MyComponent, Vue);

from vue-testing-library.

afontcu avatar afontcu commented on May 18, 2024

Looks like a nice improvement for the Vuetify example. Fancy to open up a PR with the appropriate modifications? 🤗

from vue-testing-library.

bennettdams avatar bennettdams commented on May 18, 2024

Will do!

Update: Done! #114

from vue-testing-library.

emilsgulbis avatar emilsgulbis commented on May 18, 2024

renderWithVuetify helper is great, but unfortunately looks like updateProps doesnt work in this situation, i guess thats because it's trying to update props for data-app wrap component!?

from vue-testing-library.

ChamNouki avatar ChamNouki commented on May 18, 2024

same things for emitted helper returning the events emitted by data-app wrap component?

from vue-testing-library.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.