Skip to content

Cannot stub child component properly with shallowMount method. #2021

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
wadakatu opened this issue Nov 2, 2022 · 2 comments
Closed

Cannot stub child component properly with shallowMount method. #2021

wadakatu opened this issue Nov 2, 2022 · 2 comments

Comments

@wadakatu
Copy link

wadakatu commented Nov 2, 2022

Subject of the issue

I cannot stub a child component properly, even though I use shallowMount method.
I got an error which has nothing to do with a parent component.

There are two vue components.
PhotoModalComponent.vue and LikeComponent.vue.

I am trying to test PhotoModalComponent.vue.
This component has a child component which is LikeComponent.vue.
Therefore, I used shallowMount to stub the child component, because I don't want it to pollute PhotoModalComponent's test.
However, I got an error TypeError: Cannot read properties of undefined (reading 'state') after I execute the test with npm test command.

I see this error as a bug, because state exists only in LikeComponent.vue which is a child component in this case.
Therefore, the child component pollutes parent component`s test for some reason.

These vue files and a test file are as follows.

PhotoModalComponent.vue

<template>
    <transition name="component-fade">
        <div id="overlay" @click.self="$emit('close')">
            <div id="modal-content" @click.self="$emit('close')">
                <div id="modal-content-top">
                    <img :src="val.url" alt="This photo taken by Wadakatu.">
                </div>
                <div id="modal-content-bottom">
                    <like-component :id="photoId"></like-component>
                </div>
            </div>
        </div>
    </transition>
</template>

<script>
export default {
    name: "PhotoModalComponent.vue",
    components: {
        'like-component': () => import('./LikeComponent'),
    },
    props: {
        val: Object,
    },
    computed: {
        photoId: {
            get() {
                return this.$props.val.id;
            },
        }
    },
}
</script>

<style scoped>
.....
</style>

LikeComponent.vue

<template>
    <button id="likeButton" class="button dark" :class="{liked:likeStatus(id)}" :disabled="isProcessing"
            @click="pushLike(id)">
        <div class="hand">
            <div class="thumb"></div>
        </div>
        <span>Like<span>d</span></span>
    </button>
</template>

<script>
export default {
    name: "LikeComponent.vue",
    data() {
        return {
            isProcessing: false,
        };
    },
    props: {
        id: {
            type: String,
        },
    },
    methods: {
        async pushLike(photoId) {
            let self = this;
            self.isProcessing = true;
            document.getElementById('likeButton').classList.toggle('liked');
            await self.$store.dispatch('photo/searchLikedPhoto', photoId)
                .then(async function (result) {
                    if (!result) {
                        await self.proceedLike(photoId);
                    } else {
                        await self.removeLike(photoId);
                    }
                })
                .catch(function (error) {
                    document.getElementById('likeButton').classList.toggle('liked');
                });
            self.isProcessing = false;
        },
        async likePhoto(photoId) {
            await axios.post(`/api/like`, {id: photoId});
        },
        async unlikePhoto(photoId) {
            await axios.post('/api/unlike', {id: photoId});
        },
        async proceedLike(photoId) {
            await this.likePhoto(photoId).catch(
                e => {
                    this.$store.commit('error/setCode', e.status);
                }
            );
            await this.$store.commit('photo/setLike', photoId);
            this.good++;
            this.like = true;
        },
        async removeLike(photoId) {
            await this.unlikePhoto(photoId).catch(
                e => {
                    this.$store.commit('error/setCode', e.status);
                }
            );
            await this.$store.commit('photo/unsetLike', photoId);
            this.good < 0 ? this.good = 0 : this.good--;
            this.isLiked = false;
            this.like = false;
        },
        likeStatus(photoId) {
            let self = this;
            const likeObj = self.$store.state.photo.like;
            return likeObj.includes(photoId);
        }
    },
}
</script>

<style scoped>
...
</style>

PhotoModal.spec.js

import {shallowMount} from "@vue/test-utils";
import Component from '@/PhotoModalComponent.vue';

describe('Testing computed', () => {
    test('Testing get photoId', () => {
        const wrapper = shallowMount(Component, {
            propsData: {
                val: {
                    id: 10,
                    url: '/test',
                }
            },
        });
        console.log(wrapper);
    });
});

Expected behaviour

No error.

Actual behaviour

An error occured.

Cannot read properties of undefined (reading 'state')

I have no idea what is going on.
I hope someone can help me to get rid of this error.
Thank you.

@lmiller1990
Copy link
Member

lmiller1990 commented Nov 4, 2022

What happens if you write

 components: {
        'like-component': LikeComponent
    },

?

I think we have another issue about this, but basically stubs is applied when the component is mounted, and since you are lazily loading the child, it's not available when stubs are applied, thus is it not stubbed.

If you are using Jest, you could just stub the import entirely, I think - that would achieve the same thing.

@wadakatu
Copy link
Author

wadakatu commented Nov 5, 2022

@lmiller1990

Thank you for your answer.
I tried your suggestion, and it succeeded to get rid of the error.

(FYI) Moreover, I tried this workaround and it works as well.

@wadakatu wadakatu closed this as completed Nov 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants