feat: integrate vitest

This commit is contained in:
Anthony Fu 2021-12-26 13:16:12 +08:00
parent 1f405bbc0d
commit c0201aed28
12 changed files with 183 additions and 14 deletions

View File

@ -1,5 +1,3 @@
{
"extends": [
"@antfu"
]
"extends": "@antfu"
}

View File

@ -48,6 +48,9 @@ jobs:
- name: Type Check
run: pnpm run typecheck
- name: Unit Test
run: pnpm run test:unit
- name: Cypress PNPM Patch
run: cp pnpm-lock.yaml package-lock.json

View File

@ -46,7 +46,7 @@ Mocking up web app with <b>Vitesse</b><sup><em>(speed)</em></sup><br>
- 🦾 TypeScript, of course
- ⚙️ E2E Testing with [Cypress](https://cypress.io/) on [GitHub Actions](https://github.com/features/actions)
- ⚙️ Unit Testing with [Vitest](https://github.com/vitest-dev/vitest), E2E Testing with [Cypress](https://cypress.io/) on [GitHub Actions](https://github.com/features/actions)
- ☁️ Deploy on Netlify, zero-config
@ -90,7 +90,8 @@ Mocking up web app with <b>Vitesse</b><sup><em>(speed)</em></sup><br>
### Dev tools
- [TypeScript](https://www.typescriptlang.org/)
- [Cypress](https://cypress.io/) - E2E Testing
- [Vitest](https://github.com/vitest-dev/vitest) - Unit testing powered by Vite
- [Cypress](https://cypress.io/) - E2E testing
- [pnpm](https://pnpm.js.org/) - fast, disk space efficient package manager
- [`vite-ssg`](https://github.com/antfu/vite-ssg) - Server-side generation
- [critters](https://github.com/GoogleChromeLabs/critters) - Critical CSS

View File

@ -1,12 +1,14 @@
{
"private": true,
"scripts": {
"build": "cross-env NODE_ENV=production vite-ssg build",
"build": "vite-ssg build",
"dev": "vite --port 3333 --open",
"lint": "eslint \"**/*.{vue,ts,js}\"",
"test": "cypress open",
"preview": "vite preview",
"preview-https": "serve dist",
"test": "vitest",
"test:e2e": "cypress open",
"test:unit": "vitest",
"typecheck": "vue-tsc --noEmit"
},
"dependencies": {
@ -29,6 +31,7 @@
"@vitejs/plugin-vue": "^2.0.1",
"@vue/compiler-sfc": "^3.2.26",
"@vue/server-renderer": "^3.2.26",
"@vue/test-utils": "^2.0.0-rc.18",
"critters": "^0.0.15",
"cross-env": "^7.0.3",
"cypress": "^9.1.1",
@ -50,6 +53,7 @@
"vite-plugin-vue-layouts": "^0.5.0",
"vite-plugin-windicss": "^1.6.1",
"vite-ssg": "^0.17.2",
"vitest": "^0.0.113",
"vue-tsc": "^0.30.0"
}
}

View File

@ -9,6 +9,7 @@ specifiers:
'@vitejs/plugin-vue': ^2.0.1
'@vue/compiler-sfc': ^3.2.26
'@vue/server-renderer': ^3.2.26
'@vue/test-utils': ^2.0.0-rc.18
'@vueuse/core': ^7.4.1
'@vueuse/head': ^0.7.4
critters: ^0.0.15
@ -35,6 +36,7 @@ specifiers:
vite-plugin-vue-layouts: ^0.5.0
vite-plugin-windicss: ^1.6.1
vite-ssg: ^0.17.2
vitest: ^0.0.113
vue: ^3.2.26
vue-demi: ^0.12.1
vue-i18n: ^9.1.9
@ -61,6 +63,7 @@ devDependencies:
'@vitejs/plugin-vue': 2.0.1_vite@2.7.6+vue@3.2.26
'@vue/compiler-sfc': 3.2.26
'@vue/server-renderer': 3.2.26_vue@3.2.26
'@vue/test-utils': 2.0.0-rc.18_vue@3.2.26
critters: 0.0.15
cross-env: 7.0.3
cypress: 9.1.1
@ -82,6 +85,7 @@ devDependencies:
vite-plugin-vue-layouts: 0.5.0_8d12181306819baa2f4c8b15fe034bbb
vite-plugin-windicss: 1.6.1_vite@2.7.6
vite-ssg: 0.17.2_0f81590d5699f4ef820dd76648bd0938
vitest: 0.0.113_vite@2.7.6
vue-tsc: 0.30.0_typescript@4.5.4
packages:
@ -1643,6 +1647,16 @@ packages:
engines: {node: '>= 10'}
dev: true
/@types/chai-subset/1.3.3:
resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==}
dependencies:
'@types/chai': 4.3.0
dev: true
/@types/chai/4.3.0:
resolution: {integrity: sha512-/ceqdqeRraGolFTcfoXNiqjyQhZzbINDngeoAq9GoHa8PPK1yNzTaxWjA6BFWp5Ua9JpXEMSS4s5i9tS0hOJtw==}
dev: true
/@types/estree/0.0.39:
resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==}
dev: true
@ -1994,6 +2008,14 @@ packages:
/@vue/shared/3.2.26:
resolution: {integrity: sha512-vPV6Cq+NIWbH5pZu+V+2QHE9y1qfuTq49uNWw4f7FDEeZaDU2H2cx5jcUZOAKW7qTrUS4k6qZPbMy1x4N96nbA==}
/@vue/test-utils/2.0.0-rc.18_vue@3.2.26:
resolution: {integrity: sha512-aifolXjVdsogjaLmDoZ0FU8vN+R67aWmg9OuVeED4w5Ij5GFQLrlhM19uhWe/r5xXUL4fXMk3pX5wW6FJP1NcQ==}
peerDependencies:
vue: ^3.0.1
dependencies:
vue: 3.2.26
dev: true
/@vueuse/core/7.4.1_vue@3.2.26:
resolution: {integrity: sha512-8UeLPCAieeQLXFHF1/28SIEK6ILLPb/4hp03hR+xkXF00gB/YUp0CEVcRAL9uQ8HTZa3S2T/jTISMc1ZjilM0A==}
peerDependencies:
@ -2258,6 +2280,10 @@ packages:
engines: {node: '>=0.8'}
dev: true
/assertion-error/1.1.0:
resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==}
dev: true
/astral-regex/2.0.0:
resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
engines: {node: '>=8'}
@ -2476,6 +2502,18 @@ packages:
resolution: {integrity: sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=}
dev: true
/chai/4.3.4:
resolution: {integrity: sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA==}
engines: {node: '>=4'}
dependencies:
assertion-error: 1.1.0
check-error: 1.0.2
deep-eql: 3.0.1
get-func-name: 2.0.0
pathval: 1.1.1
type-detect: 4.0.8
dev: true
/chalk/2.4.2:
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
engines: {node: '>=4'}
@ -2499,6 +2537,10 @@ packages:
is-regex: 1.1.4
dev: true
/check-error/1.0.2:
resolution: {integrity: sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=}
dev: true
/check-more-types/2.24.0:
resolution: {integrity: sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA=}
engines: {node: '>= 0.8.0'}
@ -2902,6 +2944,13 @@ packages:
resolution: {integrity: sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==}
dev: true
/deep-eql/3.0.1:
resolution: {integrity: sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==}
engines: {node: '>=0.12'}
dependencies:
type-detect: 4.0.8
dev: true
/deep-equal/2.0.5:
resolution: {integrity: sha512-nPiRgmbAtm1a3JsnLCf6/SLfXcjyN5v8L1TXzdCmHrXJ4hx+gW/w1YCcn7z8gJtSiDArZCgYtbao3QqLm/N1Sw==}
dependencies:
@ -4024,6 +4073,10 @@ packages:
engines: {node: 6.* || 8.* || >= 10.*}
dev: true
/get-func-name/2.0.0:
resolution: {integrity: sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=}
dev: true
/get-intrinsic/1.1.1:
resolution: {integrity: sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==}
dependencies:
@ -5450,6 +5503,10 @@ packages:
engines: {node: '>=8'}
dev: true
/pathval/1.1.1:
resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==}
dev: true
/pend/1.2.0:
resolution: {integrity: sha1-elfrVQpng/kRUzH89GY9XI4AelA=}
dev: true
@ -6398,6 +6455,16 @@ packages:
resolution: {integrity: sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=}
dev: true
/tinypool/0.0.6:
resolution: {integrity: sha512-E9vY6eq/Q7fUlSt69cY3y7qXNbVOFaxP+lAEDMKMObLrmO0MmEdUPyjOMgepoMDw/ps/sazl7WIQglnUrunnLg==}
engines: {node: '>=14.0.0'}
dev: true
/tinyspy/0.2.6:
resolution: {integrity: sha512-HXNA1PZ9p95rWK7h3DvWaDK06XmsjN3ldZjacW/1F0viVfPanTGSQ6l2iQyjNElD0Nd5ogfq/hT0sx2Hdyz4wQ==}
engines: {node: '>=14.0.0'}
dev: true
/tmp/0.2.1:
resolution: {integrity: sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==}
engines: {node: '>=8.17.0'}
@ -6508,6 +6575,11 @@ packages:
prelude-ls: 1.2.1
dev: true
/type-detect/4.0.8:
resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}
engines: {node: '>=4'}
dev: true
/type-fest/0.16.0:
resolution: {integrity: sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==}
engines: {node: '>=10'}
@ -6940,6 +7012,32 @@ packages:
fsevents: 2.3.2
dev: true
/vitest/0.0.113_vite@2.7.6:
resolution: {integrity: sha512-GRIZqFEkR0uGddoSp9uyevkS6GEMRZtIX1laCvsnsnrz3tAKR/RTLPjXBqXhFZwjueUDRyJEwD4KGD+1KXOsgw==}
engines: {node: '>=14.14.0'}
hasBin: true
peerDependencies:
c8: '*'
happy-dom: '*'
jsdom: '*'
vite: ^2.7.1
peerDependenciesMeta:
c8:
optional: true
happy-dom:
optional: true
jsdom:
optional: true
dependencies:
'@types/chai': 4.3.0
'@types/chai-subset': 1.3.3
chai: 4.3.4
local-pkg: 0.4.0
tinypool: 0.0.6
tinyspy: 0.2.6
vite: 2.7.6
dev: true
/void-elements/3.1.0:
resolution: {integrity: sha1-YU9/v42AHwu18GYfWy9XhXUOTwk=}
engines: {node: '>=0.10.0'}

13
src/auto-imports.d.ts vendored
View File

@ -1,9 +1,15 @@
// Generated by 'unplugin-auto-import'
// We suggest you to commit this file into source control
declare global {
const afterAll: typeof import('vitest')['afterAll']
const afterEach: typeof import('vitest')['afterEach']
const assert: typeof import('vitest')['assert']
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
const beforeAll: typeof import('vitest')['beforeAll']
const beforeEach: typeof import('vitest')['beforeEach']
const biSyncRef: typeof import('@vueuse/core')['biSyncRef']
const chai: typeof import('vitest')['chai']
const computed: typeof import('vue')['computed']
const computedInject: typeof import('@vueuse/core')['computedInject']
const controlledComputed: typeof import('@vueuse/core')['controlledComputed']
@ -19,9 +25,11 @@ declare global {
const debouncedWatch: typeof import('@vueuse/core')['debouncedWatch']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
const describe: typeof import('vitest')['describe']
const eagerComputed: typeof import('@vueuse/core')['eagerComputed']
const effectScope: typeof import('vue')['effectScope']
const EffectScope: typeof import('vue')['EffectScope']
const expect: typeof import('vitest')['expect']
const extendRef: typeof import('@vueuse/core')['extendRef']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
@ -31,6 +39,7 @@ declare global {
const isDefined: typeof import('@vueuse/core')['isDefined']
const isReadonly: typeof import('vue')['isReadonly']
const isRef: typeof import('vue')['isRef']
const it: typeof import('vitest')['it']
const makeDestructurable: typeof import('@vueuse/core')['makeDestructurable']
const markRaw: typeof import('vue')['markRaw']
const nextTick: typeof import('vue')['nextTick']
@ -63,8 +72,10 @@ declare global {
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
const suite: typeof import('vitest')['suite']
const syncRef: typeof import('@vueuse/core')['syncRef']
const templateRef: typeof import('@vueuse/core')['templateRef']
const test: typeof import('vitest')['test']
const throttledRef: typeof import('@vueuse/core')['throttledRef']
const throttledWatch: typeof import('@vueuse/core')['throttledWatch']
const toRaw: typeof import('vue')['toRaw']
@ -194,6 +205,8 @@ declare global {
const useWindowFocus: typeof import('@vueuse/core')['useWindowFocus']
const useWindowScroll: typeof import('@vueuse/core')['useWindowScroll']
const useWindowSize: typeof import('@vueuse/core')['useWindowSize']
const vi: typeof import('vitest')['vi']
const vitest: typeof import('vitest')['vitest']
const watch: typeof import('vue')['watch']
const watchAtMost: typeof import('@vueuse/core')['watchAtMost']
const watchEffect: typeof import('vue')['watchEffect']

8
src/components.d.ts vendored
View File

@ -4,13 +4,7 @@
declare module 'vue' {
export interface GlobalComponents {
CarbonCampsite: typeof import('~icons/carbon/campsite')['default']
CarbonDicomOverlay: typeof import('~icons/carbon/dicom-overlay')['default']
CarbonLanguage: typeof import('~icons/carbon/language')['default']
CarbonLogoGithub: typeof import('~icons/carbon/logo-github')['default']
CarbonMoon: typeof import('~icons/carbon/moon')['default']
CarbonPedestrian: typeof import('~icons/carbon/pedestrian')['default']
CarbonSun: typeof import('~icons/carbon/sun')['default']
Counter: typeof import('./components/Counter.vue')['default']
Footer: typeof import('./components/Footer.vue')['default']
README: typeof import('./components/README.md')['default']
}

View File

@ -0,0 +1,19 @@
<script setup lang="ts">
const props = defineProps<{
initial: number
}>()
const { count, inc, dec } = useCounter(props.initial)
</script>
<template>
<div>
{{ count }}
<button class="inc" @click="inc()">
+
</button>
<button class="dec" @click="dec()">
-
</button>
</div>
</template>

View File

@ -0,0 +1,3 @@
// Vitest Snapshot v1
exports[`Counter.vue > should render 1`] = `"<div>10 <button class=\\"inc\\"> + </button><button class=\\"dec\\"> - </button></div>"`;

5
test/basic.test.ts Normal file
View File

@ -0,0 +1,5 @@
describe('tests', () => {
it('should works', () => {
expect(1 + 1).toEqual(2)
})
})

21
test/component.test.ts Normal file
View File

@ -0,0 +1,21 @@
import { mount } from '@vue/test-utils'
import Counter from '../src/components/Counter.vue'
describe('Counter.vue', () => {
it('should render', () => {
const wrapper = mount(Counter, { props: { initial: 10 } })
expect(wrapper.text()).toContain('10')
expect(wrapper.html()).toMatchSnapshot()
})
it('should be interactive', async() => {
const wrapper = mount(Counter, { props: { initial: 0 } })
expect(wrapper.text()).toContain('0')
expect(wrapper.find('.inc').exists()).toBe(true)
await wrapper.get('button').trigger('click')
expect(wrapper.text()).toContain('1')
})
})

View File

@ -44,6 +44,7 @@ export default defineConfig({
'vue-i18n',
'@vueuse/head',
'@vueuse/core',
'vitest',
],
dts: 'src/auto-imports.d.ts',
}),
@ -165,4 +166,13 @@ export default defineConfig({
'vue-demi',
],
},
// https://github.com/vitest-dev/vitest
test: {
include: ['test/**/*.test.ts'],
environment: 'jsdom',
deps: {
inline: ['@vue', '@vueuse', 'vue-demi'],
},
},
})