Skip to content

Mounting only the slots of stubbed child components #69

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

Closed
TheJaredWilcurt opened this issue Apr 16, 2020 · 6 comments
Closed

Mounting only the slots of stubbed child components #69

TheJaredWilcurt opened this issue Apr 16, 2020 · 6 comments
Labels
enhancement New feature or request

Comments

@TheJaredWilcurt
Copy link
Contributor

Original: vuejs/vue-test-utils#1216


What problem does this feature solve?

We currently have a helper file in our codebase we pull in to testing files, it contains this beauty:

/**
 * Create a component stub that will render all included slots from the
 * parent component. This lets you test the slots you've included in child component
 * without having to fully mount the child component.
 *
 * * Notes on implementation *
 * There is no one place this is clearly laid out. This thread gave the starting point:
 *
 * https://github.com./vuejs/vue-test-utils/issues/85
 *
 * but modifying the function requires understanding Vue's functional components
 * and the `render` function:
 *
 * https://vuejs.org/v2/guide/render-function.html
 *
 * especially the arguments that `createElement` can take:
 *
 * https://vuejs.org/v2/guide/render-function.html#createElement-Arguments
 *
 * In short, this produces a <div> with only the child components slots, but none of
 * its other functionality.
 *
 * @return {object} The functional component definition
 */
componentStubWithSlots: function () {
  return {
    render: function (createElement) {
      return createElement('div', [Object.values(this.$slots)]);
    }
  };
}

It would be nice if there was a more elegant way of handling this, or at least better documented (not requiring links to 3 different places).

What does the proposed API look like?

That helper function gets used like so:

test('Show only mine checkbox adds showOnlyMine to the query params', async () => {
  const wrapper = shallow(reservationsList, {
    store,
    localVue,
    stubs: {
      RouterLink: RouterLinkStub,
      'base-table': helpers.componentStubWithSlots()
    },
    mocks: { $ga }
  });

  let checkbox = wrapper.find('[data-test="showOnlyMineCheckbox"]');
  checkbox.trigger('click');

  expect(wrapper.vm.paramsForGettingListItems)
    .toEqual({ showOnlyMine: true });
});

I think it would be nicer if there was something like that built in, so we could just do this:

test('Show only mine checkbox adds showOnlyMine to the query params', async () => {
  const wrapper = shallow(reservationsList, {
    store,
    localVue,
    stubs: {
      RouterLink: RouterLinkStub
    },
    stubComponentSlots: [
      'base-table'
    ],
    mocks: { $ga }
  });

  let checkbox = wrapper.find('[data-test="showOnlyMineCheckbox"]');
  checkbox.trigger('click');

  expect(wrapper.vm.paramsForGettingListItems)
    .toEqual({ showOnlyMine: true });
});

We use this helper a lot, it seems like the kind of common "utility" that would be in Vue-Test-Utils.

@dobromir-hristov
Copy link
Contributor

So what does does, is render all the slots of a component? For simpler cases (pure unit tests) I guess that would be OK, when you dont rely on scopedSlots or slots rendering conditionally.

Even though it makes sense, I think this will either have to stay in user land, or will be exported as a separate utility, similar to what you have now.

Current implementation is: stubbed components are just plain elements tags, that do not render any of their slots.

@lmiller1990
Copy link
Member

lmiller1990 commented Apr 17, 2020

It's not documented anywhere because it's not intended behavior, but rather a side effect of poorly implemented shallow, which should be stubbing all children (and their slots).

You are welcome to play with the transformVNodeArgs function used here - it's built into core with stubbing in mind. Maybe we can expose some kind of plugin for this. What is supposed to happen? Does the child's lifecycle hooks get called? What if it has more components with more slots? If we are attempting to provide this feature (core or plugin) we should define exactly what it should (and should not) do.

I agree that this probably doesn't really belong as a core behavior; no other testing frameworks do this, and they get by fine (including Enzyme, which has a shallow function).

@lmiller1990 lmiller1990 added the enhancement New feature or request label Apr 18, 2020
@lmiller1990
Copy link
Member

lmiller1990 commented Apr 21, 2020

@dobromir-hristov is looking into this. The idea is looking to be to provide this as a config users can enable, so you can have the behavior you like. eg config.shallowMount = { renderSlots: true } or something, since the default is stubbing them.

@TheJaredWilcurt
Copy link
Contributor Author

Another use case for this to shallow mount a view/component that contains a 3rd-party component. Where you don't want to load the complexity of that 3rd party component, but you do want to test your code being passed into the slot. It can make snapshots more useful and less cluttered.

@lmiller1990
Copy link
Member

Let's chat about this in here #108

This could be a helper. I don't mind having this feature.

@tulioFcastro
Copy link

use the renderStubDefaultSlot: true to solve it.

shallowMount(Component, {
   props: { ... },
   global: { renderStubDefaultSlot: true },
   slots: { default: '...' }
});

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

No branches or pull requests

4 participants