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

No way to updateProps for child component #263

Open
Maxim-Mazurok opened this issue Feb 3, 2022 · 3 comments
Open

No way to updateProps for child component #263

Maxim-Mazurok opened this issue Feb 3, 2022 · 3 comments

Comments

@Maxim-Mazurok
Copy link
Contributor

Maxim-Mazurok commented Feb 3, 2022

Describe the bug A clear and concise description of what the bug is.

I'm using Vue + TSX + Vuex + Vuetify, and I've created a render helper function to minimise boilerplate and potential errors when testing my components:

import * as tsx from "vue-tsx-support";
import Vuetify from "vuetify";
import { VApp } from "vuetify/lib";
import { routes } from "../src/router";
import { render, RenderOptions } from "@testing-library/vue";
import { storeObject } from "../src/store";

export const renderHelper = (
  parameter: Parameters<typeof tsx.component>[0],
  renderOptions: Parameters<typeof render>[1] = {}
): ReturnType<typeof render> =>
  render(VApp, {
    routes,
    vuetify: new Vuetify(),
    slots: {
      default: tsx.component(parameter),
    },
    store: storeObject as unknown as RenderOptions<Vue>["store"],
    ...renderOptions,
  });

As you can see, I'm rendering VApp component (because some Vuetify components require to be rendered in the VApp context, so instead of trying to guess by non-descriptive errors which components require it, I'm rendering all in VApp).

The actual component being tested it passed as a parameter, and put into the default slot of VApp: tsx.component(parameter).

Now, if I use updateProps() returned by render() - it'll update props on VApp, and not on the actual component that I want to test.

Workaround that I use now:

import WWHeader from "../../src/components/WWHeader";
import { ComponentProps } from "vue-tsx-support/lib/advance";
import { renderHelper } from "../helpers";

it("renders level 6 header and then level 5 header", async () => {
  const { html, updateProps } = renderHelper(
    {
      computed: {
        level: {
          get: function () {
            return ((this as unknown as Vue).$parent.$attrs as ComponentProps<typeof WWHeader>)["level"];
          },
        },
      },
      render() {
        return <WWHeader level={(this as ComponentProps<typeof WWHeader>).level} />;
      },
    },
    { props: { level: 6 } }
  );

  expect(html()).toContain("<h6");

  await updateProps({ level: 5 });

  expect(html()).toContain("<h5");
});

as opposed to a regular test for comparison:

it("renders level 1 header", () => {
  const { html } = renderHelper({
    render() {
      return <WWHeader level={1} />;
    },
  });

  expect(html()).toContain("<h1");
});

Expected behavior

It'd be great if there was an option to updateProps() for the child component of the component being tested. I think this should be useful for virtually everyone using Vuetify (because of the VApp requirement for some components), so I think the user base is pretty big.

Related information:

  • @testing-library/vue version: 5.6.2
  • Vue version: 2.6.14
  • node version: 16.13.0
  • npm (or yarn) version: 8.1.0
@Maxim-Mazurok Maxim-Mazurok added the bug Something isn't working label Feb 3, 2022
@afontcu afontcu removed the bug Something isn't working label Feb 3, 2022
@afontcu
Copy link
Member

afontcu commented Feb 3, 2022

Hi! I don't think there's a way to bind updateProps to a child component. However, have you checked vuetify examples from this repo? Maybe wrapping everything with VApp is not mandatory, which would make updateProps simple to use again

@Maxim-Mazurok
Copy link
Contributor Author

Hi! I don't think there's a way to bind updateProps to a child component.

That'd be useful tho, I think

However, have you checked vuetify examples from this repo? Maybe wrapping everything with VApp is not mandatory, which would make updateProps simple to use again

Good point.
Without using VApp, I'm getting this:

console.warn node_modules/vuetify/es5/util/console.js:46
      [Vuetify] Unable to locate target [data-app]

      found in

      ---> <VMenu>
             <VListItem>
               <LibraryListItem>
                 <Anonymous>
                   <Root>

By changing our render helper function using approach from vuetify tests, I got rid of warnings:

export const renderHelper = (
  parameter: Parameters<typeof tsx.component>[0],
  renderOptions: Parameters<typeof render>[1] = {}
): ReturnType<typeof render> => {
  const root = document.createElement("div");
  root.setAttribute("data-app", "true");

  return render(tsx.component(parameter), {
    routes,
    vuetify: new Vuetify(),
    store: storeObject as unknown as RenderOptions<Vue>["store"],
    container: document.body.appendChild(root),
    ...renderOptions,
  });
};

I didn't want to do that initially because I thought that vuetify components rely on more than just data-app="true" from VApp. But if it's good enough for them, then it must be good enough for us, thank you very much for pointing me in the right direction!

@Maxim-Mazurok
Copy link
Contributor Author

Maxim-Mazurok commented Feb 7, 2022

Actually, this doesn't solve our issue, because there were three components originally:

  1. VApp
  2. "Anonymous" component that we write our JSX in
  3. The actual component being tested

We got rid to the VApp, but we can't get rid of the 2nd component. When we're testing our WWHeader component, the 2nd one looks like this:

{
  render() {
    return <WWHeader level={1} />;
  },
}

There are comments explaining why we need that 2nd component:

/**
 * It helped to see compiled test files (by debugging test in Chrome with source maps turned off in dev tools)
 * to understand why I was getting "h is not defined". It's being injected by this plugin: https://github.com/vuejs/babel-plugin-transform-vue-jsx
 * And it only injects h variable in render() function if it has JSX in it: https://github1s.com/vuejs/babel-plugin-transform-vue-jsx/blob/HEAD/index.js#L50
 * So we can't have render() in one place and JSX in another place as far as I understand, they kinda have to go together.
 */

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

No branches or pull requests

2 participants