LinusBorg / vue-simple-portal

A simpler Portal implementation focussed on moving slot content to the end of the body element
Other
223 stars 28 forks source link

Access to $refs within the portal when using vue-test-utils #14

Closed phaust closed 5 years ago

phaust commented 5 years ago

First of all, thanks for writing and maintaining this component :)

I try to access the $refs of a mounted component within a unit test (vue-test-utils and jest).

My template (simplified) looks something like:

<div class="select">
  <portal>
    <div ref="dropdown"></div>
  </portal>
</div>

The unit test (simplified):

const component = mount(select);
console.log(component.vm.$refs.dropdown);

The select component uses vue-simple-portal as local component. It works absolutely fine within my application but when I'm trying to test the component with a unit test it seems the $ref which is placed inside the portal isn't available in the component.

There are no $refs in the log output of the unit test but if I don't use <portal></portal> the $refs are listed.

Am I on the wrong track testing my component that way or do I have access to the $refs inside the portal some other way?

csytan commented 5 years ago

I'm also experiencing this problem within the mounted() hook. Perhaps it's because of the moving of the element after creation?

I don't have a fix to offer, but here's a temporary workaround for those in need of one:

Edit: all you need is the $nextTick()!

<template>
    <Portal>
        <input
            ref="titleElement"
            v-model="title"/>
    </Portal>
</template>

<script>
import { Portal } from '@linusborg/vue-simple-portal';

export default {
    components: {
        Portal
    },
    data() {
        return {
            title: 'vue-simple-portal rocks!'
        };
    },
    async mounted() {
        // Wait till after vue-simple-portal finishes the move
        await this.$nextTick();

        // Get the title element and focus it
        this.$refs.titleElement.focus();
    }
};
</script>

P.S.: Thanks @LinusBorg for creating & maintaining this library 🎉. I really like how it's the result of much iteration and feedback from your existing plugin portal-vue. Great explainers on the front page 👍

LinusBorg commented 5 years ago

@csytan @phaust yes, accessing $refs requires a $nexTick. The reaosn is that we manually mount a wrapper component (containing the portal slot content) to the target after our own component has rendered.

tcamde commented 5 years ago

Had the same problem and solved it with a different workaround. If you wrap the whole component inside the Portal instead of putting the Portal inside your component it also works.

For example: <portal v-if="showMyComponent"><my-component /></portal>

Instead of inside my-component.vue: ``