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

feature: allow stubbing components by definition, not by name #715

Open
xanf opened this issue Jun 30, 2021 · 5 comments
Open

feature: allow stubbing components by definition, not by name #715

xanf opened this issue Jun 30, 2021 · 5 comments
Labels
enhancement New feature or request

Comments

@xanf
Copy link
Collaborator

xanf commented Jun 30, 2021

stubs has an important limitation for years - you can't stub anonymous component. Let me show that in code:

const AnonymousComponent = { template: '<div>anonymous</div>' }
const Component = {
  computed: {
    cmp() {
      return AnonymousComponent;
    }
  },
  template: '<div><component :is="cmp" /></div>',
}

const wrapper = mount(Component, {
  global: {
    stubs: {
      // How do I stub AnonymousComponent?
    }
  }
})

If you feel that this is rare use-case, it will come quite frequent when all fancy setup() / <script setup> things will come in play:

const AnonymousComponent = { template: '<div>anonymous</div>' }
const Comp = {
  render() {
    return h(AnonymousComponent)
  }
}

const wrapper = mount(Comp, {
  global: {
    stubs: {
       // How do I stub AnonymousComponent?
    }
  }
})

In real world, AnonymousComponent is usually coming from third-party library so "just add name" is not a solution. Obviously there is an escape hatch - one can use jest.mock to mock AnonymousComponent import and provide stub in that way, but it looks ugly, complex, and (most important) - creates two different ways of solving same task (stubbing components)

The core reason of the problem is obvious - we're using name as an identifier for components to stub. I also see certain caveats here - for example registeredName which is used for stubbing definitely feels like implementation detail for me - I want to treat my components as black box as much as possible and I don't care how components: { ... } is defined

So, basically an idea is to allow passing component definition to stubs. Luckily, we've supported array syntax in stubs for long time, so the only change will be to allow that arrays to contain a new type of "stub definition", something like:

{ component: AnonymousComponent, stub: MySuperStub }

So, the usage will be:

const wrapper = mount(Comp, {
  global: {
    stubs: [
       { component: AnonymousComponent, stub: MySuperStub }, // using concrete stub      
       { component: SomeOtherComponent, stub: true },  // let VTU generate the stub,
       'HelloCmp', // mixing old array-style stubs, ugly, but works,
       { component: 'StubByName', stub: true } // Old good stub-by-name
    ]
  }
})

This change, while being completely additive and non-breaking will simplify life for every person who is stubbing here :)
WDYT?

@lmiller1990 lmiller1990 added the enhancement New feature or request label Jul 6, 2021
@lmiller1990
Copy link
Member

lmiller1990 commented Jul 6, 2021

I personally have no idea how useful this would be for the majority of users, but since it's not a breaking change, I don't have anything against it. I agree "just add a name" is not a very good solution.

The only real consideration is here is the complexity- do you see 1) significant difficultly in implementing or 2) unsolvable edge cases?

@xanf
Copy link
Collaborator Author

xanf commented Jul 6, 2021

I personally have no idea how useful this would be for the majority of users, but since it's not a breaking change, I don't have anything against it. I agree "just add a name" is not a very good solution.

The only real consideration is here is the complexity- do you see 1) significant difficultly in implementing or 2) unsolvable edge cases?

No, actually I have a working prototype and it does not bring any complexity while really solving important pain points for shallow users. I'll open PR within couple of days

@lmiller1990
Copy link
Member

Sounds good!

Also your many fixes are now out in rc.10 - thanks a lot for that. https://github.com/vuejs/vue-test-utils-next/releases/tag/v2.0.0-rc.10

@freakzlike
Copy link
Collaborator

I currently have a util to stub a component but render the slots and also with slot data.
Here I have a quick example:

<template>
  <BigLayout>
    <template #header="{ toolbar }">
      {{ toolbar ? 'Header in toolbar' : 'Header not in toolbar' }}
    </template>
    
    <span>Some Content</span>
  </BigLayout>
</template>

I want to stub the BigLayout but still render the header slot with some data.

With the new stub definition we could implement this and be able to add more enhancement to the stubs:

const wrapper = mount(Comp, {
  global: {
    stubs: [
      {
        stub: true,
        component: BigLayout,
        scopedSlots: {
          header: { toolbar: true }
        }
      }
    ]
  }
})

@ironicnet
Copy link

I currently have a util to stub a component but render the slots and also with slot data. Here I have a quick example:

<template>
  <BigLayout>
    <template #header="{ toolbar }">
      {{ toolbar ? 'Header in toolbar' : 'Header not in toolbar' }}
    </template>
    
    <span>Some Content</span>
  </BigLayout>
</template>

I want to stub the BigLayout but still render the header slot with some data.

With the new stub definition we could implement this and be able to add more enhancement to the stubs:

const wrapper = mount(Comp, {
  global: {
    stubs: [
      {
        stub: true,
        component: BigLayout,
        scopedSlots: {
          header: { toolbar: true }
        }
      }
    ]
  }
})

I like this. I also have utils to handling scoped slots and rendering those.

I know this is kind of old, but this is a issue still happening.
I will draft an Issue to bring the rendering of slots / dynamic / named slots back

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