diff --git a/package.json b/package.json index 19450b9..d37c015 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "prepare": "husky install" }, "dependencies": { + "@pinia/testing": "^0.1.3", "pinia": "^2.1.6", "vue": "^3.3.4", "vue-router": "^4.2.4" diff --git a/src/features/integersList/searchRandomIntegers.ts b/src/features/integersList/searchRandomIntegers.ts index d64a242..63cfbae 100644 --- a/src/features/integersList/searchRandomIntegers.ts +++ b/src/features/integersList/searchRandomIntegers.ts @@ -8,11 +8,24 @@ export type SearchRandomIntegersParams = { min: number num: number } -export const searchRandomIntegers = async (params: SearchRandomIntegersParams): Promise => { - const { num, min, max, col, base, format } = params - return await POST( - `/integers/?num=${num}&min=${min}&max=${max}&col=${col}&base=${base}&format=${format}`, - null - ) +export type SearchRandomIntegersDependencies = { + httpPost: typeof POST } + +export type SearchRandomIntegersResponse = (params: SearchRandomIntegersParams) => Promise + +export const createSearchRandomIntegers = + (dependencies: SearchRandomIntegersDependencies): SearchRandomIntegersResponse => + async (params) => { + const { num, min, max, col, base, format } = params + const { httpPost } = dependencies + return await httpPost( + `/integers/?num=${num}&min=${min}&max=${max}&col=${col}&base=${base}&format=${format}`, + null + ) + } + +export const searchRandomIntegers: SearchRandomIntegersResponse = createSearchRandomIntegers({ + httpPost: POST +}) diff --git a/src/stores/useRandomIntegers.store.ts b/src/stores/useRandomIntegers.store.ts index e8e4a9c..0268ead 100644 --- a/src/stores/useRandomIntegers.store.ts +++ b/src/stores/useRandomIntegers.store.ts @@ -1,25 +1,33 @@ import { searchRandomIntegers, - SearchRandomIntegersParams + SearchRandomIntegersParams, + SearchRandomIntegersResponse } from '@/features/integersList/searchRandomIntegers.ts' import { ref } from 'vue' import { defineStore } from 'pinia' -export const useRandomIntegersStore = defineStore('integersList', () => { - const integersArray = ref>([]) - const searchIntegers = async (params: SearchRandomIntegersParams) => { - integersArray.value = groupIntegersByValue(await searchRandomIntegers(params)) - } +export type IntegersStoreDependencies = { + searchRandomIntegers: SearchRandomIntegersResponse +} +export const createRandomIntegersStore = ({ searchRandomIntegers }: IntegersStoreDependencies) => + defineStore('integersList', () => { + const integersArray = ref>({}) - const groupIntegersByValue = (integersArray: string[]) => { - const occurrences: Record = {}; + const searchIntegers = async (params: SearchRandomIntegersParams) => { + integersArray.value = groupIntegersByValue(await searchRandomIntegers(params)) + } - integersArray.forEach((integer) => { - occurrences[integer] = (occurrences[integer] || 0) + 1; - }); + const groupIntegersByValue = (integersArray: string[]) => { + const occurrences: Record = {} - return occurrences; - } + integersArray.forEach((integer) => { + occurrences[integer] = (occurrences[integer] || 0) + 1 + }) - return { integersArray, searchIntegers } -}) + return occurrences + } + + return { integersArray, searchIntegers } + }) + +export const useRandomIntegersStore = () => createRandomIntegersStore({ searchRandomIntegers })() diff --git a/src/utils/http/httpClient.ts b/src/utils/http/httpClient.ts index 6c72ddd..18dbaee 100644 --- a/src/utils/http/httpClient.ts +++ b/src/utils/http/httpClient.ts @@ -1,5 +1,5 @@ -export const httpClient = async (input: RequestInfo, init?: RequestInit): Promise => { - const response = await fetch(input, init) +export const httpClient = async (url: string, options?: RequestInit): Promise => { + const response = await fetch(url, options) if (!response.ok) { throw new Error(`[${response.status}] ${response.statusText}`) } diff --git a/tests/components/button.spec.ts b/tests/components/button.spec.ts index 0f9ef8f..834d3d8 100644 --- a/tests/components/button.spec.ts +++ b/tests/components/button.spec.ts @@ -6,11 +6,7 @@ import { shallowMount, VueWrapper } from '@vue/test-utils' describe('Button', () => { let wrapper: VueWrapper beforeEach(() => { - wrapper = shallowMount(Button, { - props: { - recordValues: { 20: 2, 15: 1 } - } - }) + wrapper = shallowMount(Button) }) it('should render properly', () => { diff --git a/tests/features/integersList/searchRandomIntegers.spec.ts b/tests/features/integersList/searchRandomIntegers.spec.ts index 43339be..31ca6e5 100644 --- a/tests/features/integersList/searchRandomIntegers.spec.ts +++ b/tests/features/integersList/searchRandomIntegers.spec.ts @@ -1,7 +1,34 @@ -import { describe, expect } from 'vitest' +import { beforeEach, describe, expect, it, vitest } from 'vitest' +import { + createSearchRandomIntegers, + SearchRandomIntegersDependencies, + SearchRandomIntegersParams, SearchRandomIntegersResponse +} from '../../../src/features/integersList/searchRandomIntegers' +import { Mocks } from '../../utils' describe('Search Random Integers Feature', () => { - it('should return true', () => { - expect(1 + 1).toBe(2) + let mocks: Mocks + let searchRandomIntegers: SearchRandomIntegersResponse + beforeEach(() => { + mocks = { httpPost: vitest.fn() } + searchRandomIntegers = createSearchRandomIntegers(mocks) + }) + + it('should properly call POST', async () => { + const params: SearchRandomIntegersParams = { + base: 2, + col: 1, + format: 'plain', + max: 10, + min: 0, + num: 200 + } + + await searchRandomIntegers(params) + + expect(mocks.httpPost).toHaveBeenCalledWith( + `/integers/?num=200&min=0&max=10&col=1&base=2&format=plain`, + null + ) }) }) diff --git a/tests/pages/home-page.spec.ts b/tests/pages/home-page.spec.ts new file mode 100644 index 0000000..f1bb452 --- /dev/null +++ b/tests/pages/home-page.spec.ts @@ -0,0 +1,27 @@ +import PageLayout from '@/layouts/page-layout.vue' +import { createTestingPinia } from '@pinia/testing' +import { describe, it, expect, beforeEach, vi } from 'vitest' + +import { shallowMount, VueWrapper } from '@vue/test-utils' +import { setActivePinia } from 'pinia' +import HomePage from '@/pages/home-page.vue' +import { useRandomIntegersStore } from '../../src/stores/useRandomIntegers.store' + +describe('Home page', () => { + let wrapper: VueWrapper + beforeEach(async () => { + setActivePinia(createTestingPinia()) + vi.mocked(useRandomIntegersStore().searchIntegers) + wrapper = shallowMount(HomePage) + }) + + it('should display a page layout', () => { + const pageLayout = wrapper.findComponent(PageLayout) + + expect(pageLayout.exists()).toBe(true) + }) + + it('should load integers list before accessing home page', () => { + expect(useRandomIntegersStore().searchIntegers).toHaveBeenCalled() + }) +}) diff --git a/tests/pages/home.page.spec.ts b/tests/pages/home.page.spec.ts deleted file mode 100644 index 173c1a1..0000000 --- a/tests/pages/home.page.spec.ts +++ /dev/null @@ -1,21 +0,0 @@ -import PageLayout from "@/layouts/page-layout.vue"; -import {describe, it, expect, beforeEach} from 'vitest' - -import {shallowMount, VueWrapper} from '@vue/test-utils' -import { createPinia, setActivePinia } from 'pinia' -import HomePage from '@/pages/home-page.vue' -describe('Home page', () => { - let wrapper: VueWrapper - beforeEach(() => { - setActivePinia(createPinia()) - wrapper = shallowMount(HomePage) - }) - - it('should display a page layout', () => { - const pageLayout = wrapper.findComponent(PageLayout) - - console.log(wrapper.html()) - - expect(pageLayout.exists()).toBe(true) - }) -}) diff --git a/tests/stores/useRandomIntegers.store.spec.ts b/tests/stores/useRandomIntegers.store.spec.ts index c498c16..e164d67 100644 --- a/tests/stores/useRandomIntegers.store.spec.ts +++ b/tests/stores/useRandomIntegers.store.spec.ts @@ -1,8 +1,57 @@ - -import { describe, expect } from 'vitest' +import { createPinia, setActivePinia } from 'pinia' +import { beforeEach, describe, expect, it, vitest } from 'vitest' +import { + createRandomIntegersStore, + IntegersStoreDependencies, + useRandomIntegersStore +} from '../../src/stores/useRandomIntegers.store' +import { Mocks } from '../utils' describe('Search Random Integers Feature', () => { - it('should return true', () => { - expect(1 + 1).toBe(2) - }) + let mocks: Mocks + let randomIntegersStore: ReturnType + + beforeEach(() => { + setActivePinia(createPinia()) + mocks = { + searchRandomIntegers: vitest.fn().mockReturnValue(['1']) + } + randomIntegersStore = createRandomIntegersStore(mocks) + }) + + it('should have default value in the store', () => { + expect(randomIntegersStore()).toEqual( + expect.objectContaining({ + integersArray: {} + }) + ) + }) + + it('should call search integers with correct params', () => { + const params = { + base: undefined, + col: 0, + format: undefined, + max: 0, + min: 0, + num: 0 + } + randomIntegersStore().searchIntegers(params) + + expect(mocks.searchRandomIntegers).toHaveBeenCalledWith(params) + }) + + it('should set integers array', async () => { + const params = { + base: undefined, + col: 0, + format: undefined, + max: 0, + min: 0, + num: 0 + } + await randomIntegersStore().searchIntegers(params) + + expect(randomIntegersStore().integersArray).toEqual({1: 1}) + }) }) diff --git a/tests/test.spec.ts b/tests/test.spec.ts deleted file mode 100644 index e69de29..0000000 diff --git a/tests/utils.ts b/tests/utils.ts new file mode 100644 index 0000000..665be5f --- /dev/null +++ b/tests/utils.ts @@ -0,0 +1,7 @@ +import type { Mock } from 'vitest' + +export type Mocks = Type extends (...arg: infer Params) => infer ReturnType + ? Mock + : Type extends object + ? { [key in keyof Type]: Mocks } + : Type diff --git a/yarn.lock b/yarn.lock index 7da4ac7..a567123 100644 --- a/yarn.lock +++ b/yarn.lock @@ -658,6 +658,13 @@ resolved "https://registry.yarnpkg.com/@one-ini/wasm/-/wasm-0.1.1.tgz#6013659736c9dbfccc96e8a9c2b3de317df39323" integrity sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw== +"@pinia/testing@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@pinia/testing/-/testing-0.1.3.tgz#ee46a5a51d437f845ddc9c7b048c98b6a435e68b" + integrity sha512-D2Ds2s69kKFaRf2KCcP1NhNZEg5+we59aRyQalwRm7ygWfLM25nDH66267U3hNvRUOTx8ofL24GzodZkOmB5xw== + dependencies: + vue-demi ">=0.14.5" + "@pkgjs/parseargs@^0.11.0": version "0.11.0" resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"