Created
January 8, 2024 10:36
-
-
Save mustafadalga/3ecf0857a169cc9c115033b35bc82eaf to your computer and use it in GitHub Desktop.
Unit Testing Vue.js Composables: Verifying Vuex Store Interaction and Reactive Behavior in useCheckUserPosts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { createStore } from "vuex"; | |
import type { Post } from "@/types"; | |
export interface ApisLoadState { | |
isCalled: boolean; | |
isLoaded: boolean; | |
} | |
export interface ApiLoadState extends ApisLoadState { | |
api: string; | |
} | |
export interface State { | |
posts: Post[]; | |
activeUserID: number; | |
apisLoadState: { | |
[key: string]: ApisLoadState; | |
}; | |
} | |
const initialState = () => ({ | |
posts: [], | |
activeUserID: 1, | |
apisLoadState: {}, | |
}); | |
export const store = createStore<State>({ | |
state: initialState, | |
getters: { | |
getPosts: (state: State): State["posts"] => state.posts, | |
getActiveUserID: (state: State): State["activeUserID"] => | |
state.activeUserID, | |
getApisLoadState: (state: State): State["apisLoadState"] => | |
state.apisLoadState, | |
}, | |
mutations: { | |
setPosts(state, posts: Post[]) { | |
state.posts = posts; | |
}, | |
setActiveUserID: (state, id: number) => state.activeUserID = id, | |
setApisLoadState: (state, data: ApiLoadState) => { | |
if (!state.apisLoadState[data.api]) { | |
state.apisLoadState[data.api] = { | |
isCalled: false, | |
isLoaded: false, | |
}; | |
} | |
if (Object.prototype.hasOwnProperty.call(data, "isCalled")) { | |
state.apisLoadState[data.api].isCalled = data.isCalled; | |
} | |
if (Object.prototype.hasOwnProperty.call(data, "isLoaded")) { | |
state.apisLoadState[data.api].isLoaded = data.isLoaded; | |
} | |
}, | |
resetStore: (state) => Object.assign(state, initialState()), | |
}, | |
actions: { | |
async setPosts({ state, commit }) { | |
try { | |
const url = `https://jsonplaceholder.typicode.com/posts?userID=${state.activeUserID}`; | |
const response = await fetch(url); | |
const responseJson = await response.json(); | |
commit("setPosts", responseJson); | |
} catch (error) { | |
console.error( | |
`An error occurred during fetching post detail. Please try again: ${error}` | |
); | |
} | |
}, | |
}, | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { describe, it, beforeEach, vi, expect } from "vitest"; | |
import { defineComponent, onMounted } from "vue"; | |
import { createStore, useStore } from "vuex"; | |
import useCheckUserPosts from "./useCheckUserPosts"; | |
import { mount } from "@vue/test-utils" | |
import type { State } from "@/store"; | |
const store = createStore<State>({ | |
state: { | |
posts: [], | |
activeUserID: 0, | |
apisLoadState: { | |
posts: { | |
isLoaded: false, | |
isCalled: false | |
} | |
} | |
}, | |
getters: { | |
getActiveUserID: (state) => state.activeUserID, | |
}, | |
mutations: { | |
setApisLoadStates: () => { | |
}, | |
setActiveUserID: (state, id: number) => state.activeUserID = id, | |
}, | |
actions: { | |
setPosts: () => { | |
} | |
} | |
}) | |
const TestComponent = defineComponent({ | |
setup() { | |
const store = useStore(); | |
useCheckUserPosts(); | |
function changeActiveUserID() { | |
store.commit("resetStore"); | |
const id = Math.floor(Math.random() * 100) + 1; | |
store.commit("setActiveUserID", id); | |
} | |
onMounted(() => { | |
changeActiveUserID() | |
}) | |
}, | |
template: "<h1></h1>" | |
}) | |
describe("useCheckUserPosts", () => { | |
beforeEach(() => { | |
vi.useFakeTimers() | |
}) | |
it('should watch and fetch posts by active user ID', async () => { | |
const commitSpy = vi.spyOn(store, 'commit'); | |
const dispatchSpy = vi.spyOn(store, 'dispatch'); | |
mount(TestComponent, { | |
global: { | |
plugins: [ store ] | |
}, | |
}); | |
await vi.runAllTimers(); | |
expect(commitSpy).toHaveBeenCalledWith('setApisLoadState', { api: 'posts', isCalled: true }); | |
expect(dispatchSpy).toHaveBeenCalledWith('setPosts'); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { computed, watch } from "vue"; | |
import { useStore } from "vuex"; | |
export default function useCheckUserPosts() { | |
const store = useStore(); | |
const activeUserID = computed(() => store.getters.getActiveUserID); | |
const handler = async () => { | |
store.commit("setApisLoadState", { api: "posts", isCalled: true }); | |
await store.dispatch("setPosts"); | |
store.commit("setApisLoadState", { api: "posts", isLoaded: true }); | |
}; | |
watch(() => activeUserID.value, handler, { immediate: true }); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment