Skip to content

Commit 3ef7112

Browse files
authored
feat: Add types for Vue 3 (#180)
* Add basic types * Rename main file to properly get types * Fix import statement * Fix compiler options lib * Extract temporary-defined types to its own file * Remove duplicate test * Fix link * Improve tests * Remove unnecessary chars * Add support for file inputs * Update deps * Fix rerender typing test * Remove typecheck step until we figure out how to overcome ts-ignore in node_modules. lol * Update deps
1 parent 7e1882a commit 3ef7112

40 files changed

+286
-139
lines changed

.eslintrc.js

+3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
module.exports = {
2+
parserOptions: {
3+
parser: '@typescript-eslint/parser',
4+
},
25
extends: [
36
'./node_modules/kcd-scripts/eslint.js',
47
'plugin:vue/vue3-recommended',

README.md

+3-4
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,7 @@ light-weight, simple, and understandable.
171171

172172
## Typings
173173

174-
The TypeScript type definitions are in the [DefinitelyTyped repo][types] and
175-
bundled with Vue Testing Library.
174+
The TypeScript type definitions are in the [types][types-directory] directory.
176175

177176
## ESLint support
178177

@@ -247,7 +246,6 @@ instead of filing an issue on GitHub.
247246
[license]: https://github.com/testing-library/vue-testing-library/blob/master/LICENSE
248247
[discord]: https://testing-library.com/discord
249248
[discord-badge]: https://img.shields.io/discord/723559267868737556.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2&style=flat-square
250-
[types]: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/testing-library__vue
251249
[jest-dom]: https://github.com/testing-library/jest-dom
252250
[which-query]: https://testing-library.com/docs/guide-which-query
253251
[guiding-principle]: https://twitter.com/kentcdodds/status/977018512689455106
@@ -261,10 +259,11 @@ instead of filing an issue on GitHub.
261259
[add-issue-bug]: https://github.com/testing-library/vue-testing-library/issues/new?assignees=&labels=bug&template=bug_report.md&title=
262260
[add-issue]: (https://github.com/testing-library/vue-testing-library/issues/new)
263261

262+
[types-directory]: https://github.com/testing-library/vue-testing-library/blob/master/types
264263
[test-directory]: https://github.com/testing-library/vue-testing-library/blob/master/src/__tests__
265264
[vuex-example]: https://github.com/testing-library/vue-testing-library/blob/master/src/__tests__/vuex.js
266265
[vue-router-example]: https://github.com/testing-library/vue-testing-library/blob/master/src/__tests__/vue-router.js
267266
[vee-validate-example]: https://github.com/testing-library/vue-testing-library/blob/master/src/__tests__/validate-plugin.js
268-
[vue-i18n-example]: https://github.com/testing-library/vue-testing-library/blob/master/src/__tests__/vueI18n.js
267+
[vue-i18n-example]: https://github.com/testing-library/vue-testing-library/blob/master/src/__tests__/vue-i18n.js
269268
[vuetify-example]: https://github.com/testing-library/vue-testing-library/blob/master/src/__tests__/vuetify.js
270269
<!-- prettier-ignore-end -->

jest.config.js

-3
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,6 @@ const config = require('kcd-scripts/jest')
44
module.exports = merge(config, {
55
testEnvironment: 'jsdom',
66
moduleFileExtensions: ['js', 'vue'],
7-
moduleNameMapper: {
8-
'@testing-library/vue': '<rootDir>/src/vue-testing-library.js',
9-
},
107
coverageDirectory: './coverage',
118
collectCoverageFrom: ['**/src/**/*.js', '!**/src/__tests__/**'],
129
transform: {

package.json

+16-12
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
"name": "@testing-library/vue",
33
"version": "0.0.0-semantically-released",
44
"description": "Simple and complete Vue DOM testing utilities that encourage good testing practices.",
5-
"main": "dist/vue-testing-library.js",
5+
"main": "dist/index.js",
6+
"types": "types/index.d.ts",
67
"scripts": {
78
"format": "kcd-scripts format",
89
"build": "kcd-scripts build",
@@ -16,6 +17,7 @@
1617
"node": ">10.18"
1718
},
1819
"files": [
20+
"types",
1921
"dist",
2022
"cleanup-after-each.js"
2123
],
@@ -45,36 +47,38 @@
4547
"license": "MIT",
4648
"dependencies": {
4749
"@babel/runtime": "^7.12.1",
48-
"@testing-library/dom": "^7.26.3",
49-
"@vue/test-utils": "^2.0.0-beta.10",
50+
"@testing-library/dom": "^7.28.1",
51+
"@vue/test-utils": "^2.0.0-beta.12",
5052
"lodash.merge": "^4.6.2"
5153
},
5254
"devDependencies": {
5355
"@babel/plugin-transform-runtime": "^7.12.1",
5456
"@testing-library/jest-dom": "^5.11.5",
55-
"@testing-library/user-event": "^12.2.2",
56-
"@vue/compiler-sfc": "^3.0.2",
57+
"@testing-library/user-event": "^12.4.0",
58+
"@types/estree": "0.0.45",
59+
"@vue/compiler-sfc": "^3.0.4",
5760
"apollo-boost": "^0.4.9",
5861
"apollo-cache-inmemory": "^1.6.6",
5962
"apollo-client": "^2.6.10",
6063
"axios": "^0.20.0",
64+
"dtslint": "^4.0.6",
6165
"eslint-plugin-vue": "^7.1.0",
6266
"graphql": "^15.4.0",
6367
"graphql-tag": "^2.11.0",
6468
"isomorphic-unfetch": "^3.1.0",
6569
"jest-serializer-vue": "^2.0.2",
66-
"kcd-scripts": "^7.0.3",
70+
"kcd-scripts": "^7.5.1",
6771
"msw": "^0.21.3",
6872
"portal-vue": "^2.1.7",
6973
"typescript": "^4.1.2",
70-
"vee-validate": "^4.0.0-beta.16",
71-
"vue": "^3.0.2",
74+
"vee-validate": "^4.0.2",
75+
"vue": "^3.0.4",
7276
"vue-apollo": "^3.0.5",
7377
"vue-i18n": "^9.0.0-beta.6",
74-
"vue-jest": "^5.0.0-alpha.5",
75-
"vue-router": "^4.0.0-rc.1",
76-
"vuetify": "^2.3.16",
77-
"vuex": "^4.0.0-rc.1"
78+
"vue-jest": "^5.0.0-alpha.7",
79+
"vue-router": "^4.0.0-rc.6",
80+
"vuetify": "^2.3.19",
81+
"vuex": "^4.0.0-rc.2"
7882
},
7983
"peerDependencies": {
8084
"vue": ">= 3",

src/__tests__/auto-cleanup-skip.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
let render
2-
beforeAll(async () => {
2+
beforeAll(() => {
33
process.env.VTL_SKIP_AUTO_CLEANUP = 'true'
4-
const vtl = await require('@testing-library/vue')
4+
const vtl = require('..')
55
render = vtl.render
66
})
77

src/__tests__/auto-cleanup.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {render} from '@testing-library/vue'
1+
import {render} from '..'
22
import '@testing-library/jest-dom'
33

44
// This verifies that by importing VTL in an environment which supports

src/__tests__/axios-mock.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import '@testing-library/jest-dom'
22
import axiosMock from 'axios'
3-
import {render, fireEvent} from '@testing-library/vue'
3+
import {render, fireEvent} from '..'
44
import Component from './components/Fetch.vue'
55

66
test('mocks an API call when load-greeting is clicked', async () => {

src/__tests__/cleanup-throw.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
test.todo('check if this test still makes sense')
22

3-
// import {render, cleanup} from '@testing-library/vue'
3+
// import {render, cleanup} from '..'
44
// import {nextTick} from 'vue'
55

66
// test('cleanup re-throws errors from async lifecycle hooks', async () => {

src/__tests__/components/Translations.vue

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<template>
2-
<h2>{{ $t('hello') }}</h2>
3-
<select v-model="$i18n.locale">
4-
<option value="en">English</option>
5-
<option value="ja">Japanese</option>
6-
</select>
2+
<h2>{{ $t('hello') }}</h2>
3+
<select v-model="$i18n.locale">
4+
<option value="en">English</option>
5+
<option value="ja">Japanese</option>
6+
</select>
77
</template>
88

99
<script>

src/__tests__/components/VueI18n.vue

-21
This file was deleted.

src/__tests__/debug.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* eslint-disable testing-library/no-debug */
2-
import {render} from '@testing-library/vue'
2+
import {render} from '..'
33
import HelloWorld from './components/HelloWorld'
44

55
beforeEach(() => {

src/__tests__/directive.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {render} from '@testing-library/vue'
1+
import {render} from '..'
22
import '@testing-library/jest-dom'
33
import {uppercaseDirective} from './directives/uppercase-directive'
44
import ComponentUsingDirective from './components/Directive'

src/__tests__/disappearance.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {render, waitForElementToBeRemoved} from '@testing-library/vue'
1+
import {render, waitForElementToBeRemoved} from '..'
22
import Disappearance from './components/Disappearance'
33
import '@testing-library/jest-dom'
44

src/__tests__/fire-event.js

+18-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {h} from 'vue'
2-
import {render, fireEvent} from '@testing-library/vue'
2+
import {render, fireEvent} from '..'
33
import Button from './components/Button'
44

55
const eventTypes = [
@@ -231,3 +231,20 @@ test('fireEvent.update does not crash if non-input element is passed in', async
231231

232232
expect(console.warn).not.toHaveBeenCalled()
233233
})
234+
235+
test('fireEvent.update handles input file', async () => {
236+
const {getByTestId} = render({
237+
template: `<input type="file" data-testid="test-update" />`,
238+
})
239+
240+
const file = new File(['(⌐□_□)'], 'chucknorris.png', {type: 'image/png'})
241+
242+
const inputEl = getByTestId('test-update')
243+
244+
// You could replace the lines below with
245+
// userEvent.upload(inputEl, file)
246+
Object.defineProperty(inputEl, 'files', {value: [file]})
247+
await fireEvent.update(inputEl)
248+
249+
expect(console.warn).not.toHaveBeenCalled()
250+
})

src/__tests__/form.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {render, fireEvent} from '@testing-library/vue'
1+
import {render, fireEvent} from '..'
22
import '@testing-library/jest-dom'
33
import Form from './components/Form'
44

src/__tests__/functional.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import {render} from '@testing-library/vue'
2-
import '@testing-library/jest-dom'
31
import {h} from 'vue'
2+
import {render} from '..'
3+
import '@testing-library/jest-dom'
44

55
// From docs: Performance gains from 2.x for functional components are now
66
// negligible in 3.x, so we recommend just using stateful components.

src/__tests__/render.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {render} from '@testing-library/vue'
1+
import {render} from '..'
22
import '@testing-library/jest-dom'
33

44
test('baseElement defaults to document.body', () => {

src/__tests__/rerender.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import '@testing-library/jest-dom'
22
import {defineComponent, h, computed} from 'vue'
3-
import {render} from '@testing-library/vue'
3+
import {render} from '..'
44
import NumberDisplay from './components/NumberDisplay'
55

66
// It'd probably be better if you test the component that's doing the rerendering

src/__tests__/select.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {render, fireEvent} from '@testing-library/vue'
1+
import {render, fireEvent} from '..'
22
import '@testing-library/jest-dom'
33
import Select from './components/Select'
44

@@ -9,19 +9,19 @@ test('Select component', async () => {
99

1010
// Get the Select element by using the initially displayed value.
1111
const select = getByDisplayValue('Tyrannosaurus')
12-
expect(select.value).toBe('dino1')
12+
expect(select).toHaveValue('dino1')
1313

1414
// Update it by manually sending a valid option value.
1515
await fireEvent.update(select, 'dino2')
16-
expect(select.value).toBe('dino2')
16+
expect(select).toHaveValue('dino2')
1717

1818
// We can trigger an update event by directly getting the <option> element.
1919
optionElement = getByText('Deinonychus')
2020
await fireEvent.update(optionElement)
21-
expect(select.value).toBe('dino3')
21+
expect(select).toHaveValue('dino3')
2222

2323
// ...even if option is within an <optgroup>.
2424
optionElement = getByText('Diplodocus')
2525
await fireEvent.update(optionElement)
26-
expect(select.value).toBe('dino4')
26+
expect(select).toHaveValue('dino4')
2727
})

src/__tests__/simple-button.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {render, fireEvent} from '@testing-library/vue'
1+
import {render, fireEvent} from '..'
22
import Button from './components/Button'
33
import '@testing-library/jest-dom'
44

src/__tests__/slots.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import '@testing-library/jest-dom'
2-
import {render} from '@testing-library/vue'
2+
import {render} from '..'
33
import Card from './components/Card'
44

55
// Usage is the same as Vue Test Utils, since slots values are passed using the `slots`

src/__tests__/stopwatch.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import '@testing-library/jest-dom'
2-
import {render, waitFor, fireEvent} from '@testing-library/vue'
2+
import {render, waitFor, fireEvent} from '..'
33
import StopWatch from './components/StopWatch.vue'
44

55
const sleep = ms =>

src/__tests__/stubs.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {render} from '@testing-library/vue'
1+
import {render} from '..'
22
import '@testing-library/jest-dom'
33
import Stubs from './components/Stubs'
44

src/__tests__/user-event.js

+20-20
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import '@testing-library/jest-dom'
2-
import {render} from '@testing-library/vue'
32
import userEvent from '@testing-library/user-event'
3+
import {render, waitFor} from '..'
44
import Form from './components/Form'
55
import Select from './components/Select'
66

@@ -24,49 +24,49 @@ test('User events in a form', async () => {
2424
expect(submitButton).toBeDisabled()
2525

2626
const titleInput = getByLabelText(/title of the movie/i)
27-
await userEvent.type(titleInput, fakeReview.title)
28-
expect(titleInput.value).toEqual(fakeReview.title)
27+
userEvent.type(titleInput, fakeReview.title)
28+
expect(titleInput).toHaveValue(fakeReview.title)
2929

3030
const textArea = getByLabelText(/Your review/i)
31-
await userEvent.type(textArea, 'The t-rex went insane!')
32-
expect(textArea.value).toEqual('The t-rex went insane!')
31+
userEvent.type(textArea, 'The t-rex went insane!')
32+
expect(textArea).toHaveValue('The t-rex went insane!')
3333

34-
await userEvent.clear(textArea)
35-
expect(textArea.value).toEqual('')
36-
await userEvent.type(textArea, fakeReview.review)
37-
expect(textArea.value).toEqual(fakeReview.review)
34+
userEvent.clear(textArea)
35+
expect(textArea).toHaveValue('')
36+
userEvent.type(textArea, fakeReview.review)
37+
expect(textArea).toHaveValue(fakeReview.review)
3838

3939
const initialSelectedRating = getByLabelText(/Awful/i)
4040
const wonderfulRadioInput = getByLabelText(/Wonderful/i)
4141
expect(initialSelectedRating).toBeChecked()
4242
expect(wonderfulRadioInput).not.toBeChecked()
4343

44-
await userEvent.click(wonderfulRadioInput)
44+
userEvent.click(wonderfulRadioInput)
4545
expect(wonderfulRadioInput).toBeChecked()
46-
expect(initialSelectedRating).not.toBeChecked()
46+
await waitFor(() => expect(initialSelectedRating).not.toBeChecked())
4747

4848
const recommendInput = getByLabelText(/Would you recommend this movie?/i)
49-
await userEvent.click(recommendInput)
49+
userEvent.click(recommendInput)
5050
expect(recommendInput).toBeChecked()
5151

5252
userEvent.tab()
5353
expect(submitButton).toHaveFocus()
5454
expect(submitButton).toBeEnabled()
55-
await userEvent.type(submitButton, '{enter}')
55+
userEvent.type(submitButton, '{enter}')
5656
expect(emitted().submit[0][0]).toMatchObject(fakeReview)
5757

5858
expect(console.warn).not.toHaveBeenCalled()
5959
})
6060

61-
test('selecting option with user events', async () => {
61+
test('selecting option with user events', () => {
6262
const {getByDisplayValue} = render(Select)
6363
const select = getByDisplayValue('Tyrannosaurus')
64-
expect(select.value).toBe('dino1')
64+
expect(select).toHaveValue('dino1')
6565

66-
await userEvent.selectOptions(select, 'dino2')
67-
expect(select.value).toBe('dino2')
66+
userEvent.selectOptions(select, 'dino2')
67+
expect(select).toHaveValue('dino2')
6868

69-
await userEvent.selectOptions(select, 'dino3')
70-
expect(select.value).not.toBe('dino2')
71-
expect(select.value).toBe('dino3')
69+
userEvent.selectOptions(select, 'dino3')
70+
expect(select).not.toHaveValue('dino2')
71+
expect(select).toHaveValue('dino3')
7272
})

0 commit comments

Comments
 (0)