Skip to content

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

Open
@xanf

Description

@xanf

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?

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions