Skip to content

findComponent throws an error when used on functional wrapper #1577

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
marina-mosti opened this issue Jun 12, 2020 · 6 comments · Fixed by #1593
Closed

findComponent throws an error when used on functional wrapper #1577

marina-mosti opened this issue Jun 12, 2020 · 6 comments · Fixed by #1593
Labels

Comments

@marina-mosti
Copy link
Contributor

marina-mosti commented Jun 12, 2020

Subject of the issue

When testing a functional component, findComponent to search for components rendered inside throws an error claiming that the component is a DOM element.

Steps to reproduce

Considering the following component, where BaseIcon is a component that renders an icon.

Edit: The inner workings of BaseIcon are not really meaningful, any component that is returned in the render function seems to cause the same problem.

<script>
export default {
  functional: true,
  render (h, context) {
    return h(
      'a',
      {},
      [
        context.slots().default,
        h('BaseIcon', {})
      ]
    )
  }
}
</script>

When running test:

it('shows an icon', () => {
    const wrapper = shallowMount(SimpleLink)
    console.log(wrapper)

    const icon = wrapper.findComponent(BaseIcon)
    expect(icon.exists()).toBe(true)
  })

The following error occurs:

 components/controls/base/SimpleLink.unit.js
  ● Console

    console.log components/controls/base/SimpleLink.unit.js:16
      Wrapper { isFunctionalComponent: true }

  ● SimpleLink › shows an icon

    [vue-test-utils]: You cannot chain findComponent off a DOM element. It can only be used on Vue Components.

      16 |     console.log(wrapper)
      17 | 
    > 18 |     const icon = wrapper.findComponent(BaseIcon)
         |                          ^
      19 |     expect(icon.exists()).toBe(true)
      20 |   })
      21 | })

      at throwError (../node_modules/@vue/test-utils/dist/vue-test-utils.js:1731:9)
      at Wrapper.findComponent (../node_modules/@vue/test-utils/dist/vue-test-utils.js:10500:5)
      at Object.<anonymous> (components/controls/base/SimpleLink.unit.js:18:26)

Expected behaviour

VTU should recognize that the wrapper is a functional component, and not a DOM element, so that I can chain findComponent on it.

Actual behaviour

VTU thinks that the functional component is a DOM element, which makes the use of findComponent an error.
Additionally, when trying to use find instead, it also errors out since BaseIcon is a component.

Possible Solution

🤷‍♀️ No clue, sorry :D

@afontcu afontcu added the bug label Jun 12, 2020
@joepsyko
Copy link

I have the same problem

@J-avery32
Copy link

Same issue here.

@danieldanielecki
Copy link

For some reason, it still threw me an error on this code when finding the wrapper by querying a parent element of the nested component.

const wrapper: Wrapper<ParentComponent> = shallowMount(ParentComponent);
...
it("should have 3 tabs", () => {
  const navContainer: Wrapper<ParentComponent> = wrapper.get(".nav-container");
  const arrayBtn: WrapperArray<ParentComponent> = navContainer.findAllComponents(
    NestedComponent
  );
  expect(arrayBtn.length).toBe(3);
});

However, this one worked out perfectly fine.

const wrapper: Wrapper<ParentComponent> = shallowMount(ParentComponent);
...
it("should have 3 tabs", () => {
  const arrayBtn: WrapperArray<ParentComponent> = wrapper.findAllComponents(
    NestedComponent
  );
  expect(arrayBtn.length).toBe(3);
});

@lmiller1990
Copy link
Member

lmiller1990 commented Apr 12, 2021

You cannot find a component from a DOM element (eg, findComponent cannot be chained from find, same for get and getComponent. This was deprecated because it it is no longer possible in Vue 3 + Vue Test Utils v2.

Just do wrapper.getComponent/findComponent.

@brendan1212
Copy link

brendan1212 commented Apr 12, 2021

@lmiller1990 I'm actually seeing this same error when chaining findComponent and findComponent

// input component
const EmailInput = wrapper.findComponent({ ref: 'EmailInput' })

console.log(EmailInput)
// Wrapper { selector: { ref: 'EmailInput' } }

// html input element inside of input component
const EmailHtmlInput = EmailInput.findComponent({ ref: 'Input' })

EDIT
In my example, EmailInput was actually not returning correctly, as EmailInput.vm was returning undefined. However, I believe we should be receiving an error related to that (running findComponent on an invalid Wrapper) before we receive an error regarding the chaining do's/dont's. Is this accurate?

@lmiller1990
Copy link
Member

You may need to share some code. Basically functional components do not have an instance so vm will also be undefined. They are stateless. findComponent relies on matching up against Vue instances, and if you are using a functional component, there will be no such instance to match.

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

Successfully merging a pull request may close this issue.

7 participants