Skip to content

feat: Add types for Vue 3 #180

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

Merged
merged 14 commits into from
Dec 3, 2020
3 changes: 3 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
module.exports = {
parserOptions: {
parser: '@typescript-eslint/parser',
},
extends: [
'./node_modules/kcd-scripts/eslint.js',
'plugin:vue/vue3-recommended',
Expand Down
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,7 @@ light-weight, simple, and understandable.

## Typings

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

## ESLint support

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

[types-directory]: https://github.com/testing-library/vue-testing-library/blob/master/types
[test-directory]: https://github.com/testing-library/vue-testing-library/blob/master/src/__tests__
[vuex-example]: https://github.com/testing-library/vue-testing-library/blob/master/src/__tests__/vuex.js
[vue-router-example]: https://github.com/testing-library/vue-testing-library/blob/master/src/__tests__/vue-router.js
[vee-validate-example]: https://github.com/testing-library/vue-testing-library/blob/master/src/__tests__/validate-plugin.js
[vue-i18n-example]: https://github.com/testing-library/vue-testing-library/blob/master/src/__tests__/vueI18n.js
[vue-i18n-example]: https://github.com/testing-library/vue-testing-library/blob/master/src/__tests__/vue-i18n.js
[vuetify-example]: https://github.com/testing-library/vue-testing-library/blob/master/src/__tests__/vuetify.js
<!-- prettier-ignore-end -->
3 changes: 0 additions & 3 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ const config = require('kcd-scripts/jest')
module.exports = merge(config, {
testEnvironment: 'jsdom',
moduleFileExtensions: ['js', 'vue'],
moduleNameMapper: {
'@testing-library/vue': '<rootDir>/src/vue-testing-library.js',
},
coverageDirectory: './coverage',
collectCoverageFrom: ['**/src/**/*.js', '!**/src/__tests__/**'],
transform: {
Expand Down
28 changes: 16 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"name": "@testing-library/vue",
"version": "0.0.0-semantically-released",
"description": "Simple and complete Vue DOM testing utilities that encourage good testing practices.",
"main": "dist/vue-testing-library.js",
"main": "dist/index.js",
"types": "types/index.d.ts",
"scripts": {
"format": "kcd-scripts format",
"build": "kcd-scripts build",
Expand All @@ -16,6 +17,7 @@
"node": ">10.18"
},
"files": [
"types",
"dist",
"cleanup-after-each.js"
],
Expand Down Expand Up @@ -45,36 +47,38 @@
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.12.1",
"@testing-library/dom": "^7.26.3",
"@vue/test-utils": "^2.0.0-beta.10",
"@testing-library/dom": "^7.28.1",
"@vue/test-utils": "^2.0.0-beta.12",
"lodash.merge": "^4.6.2"
},
"devDependencies": {
"@babel/plugin-transform-runtime": "^7.12.1",
"@testing-library/jest-dom": "^5.11.5",
"@testing-library/user-event": "^12.2.2",
"@vue/compiler-sfc": "^3.0.2",
"@testing-library/user-event": "^12.4.0",
"@types/estree": "0.0.45",
"@vue/compiler-sfc": "^3.0.4",
"apollo-boost": "^0.4.9",
"apollo-cache-inmemory": "^1.6.6",
"apollo-client": "^2.6.10",
"axios": "^0.20.0",
"dtslint": "^4.0.6",
"eslint-plugin-vue": "^7.1.0",
"graphql": "^15.4.0",
"graphql-tag": "^2.11.0",
"isomorphic-unfetch": "^3.1.0",
"jest-serializer-vue": "^2.0.2",
"kcd-scripts": "^7.0.3",
"kcd-scripts": "^7.5.1",
"msw": "^0.21.3",
"portal-vue": "^2.1.7",
"typescript": "^4.1.2",
"vee-validate": "^4.0.0-beta.16",
"vue": "^3.0.2",
"vee-validate": "^4.0.2",
"vue": "^3.0.4",
"vue-apollo": "^3.0.5",
"vue-i18n": "^9.0.0-beta.6",
"vue-jest": "^5.0.0-alpha.5",
"vue-router": "^4.0.0-rc.1",
"vuetify": "^2.3.16",
"vuex": "^4.0.0-rc.1"
"vue-jest": "^5.0.0-alpha.7",
"vue-router": "^4.0.0-rc.6",
"vuetify": "^2.3.19",
"vuex": "^4.0.0-rc.2"
},
"peerDependencies": {
"vue": ">= 3",
Expand Down
4 changes: 2 additions & 2 deletions src/__tests__/auto-cleanup-skip.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
let render
beforeAll(async () => {
beforeAll(() => {
process.env.VTL_SKIP_AUTO_CLEANUP = 'true'
const vtl = await require('@testing-library/vue')
const vtl = require('..')
render = vtl.render
})

Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/auto-cleanup.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {render} from '@testing-library/vue'
import {render} from '..'
import '@testing-library/jest-dom'

// This verifies that by importing VTL in an environment which supports
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/axios-mock.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import '@testing-library/jest-dom'
import axiosMock from 'axios'
import {render, fireEvent} from '@testing-library/vue'
import {render, fireEvent} from '..'
import Component from './components/Fetch.vue'

test('mocks an API call when load-greeting is clicked', async () => {
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/cleanup-throw.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
test.todo('check if this test still makes sense')

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

// test('cleanup re-throws errors from async lifecycle hooks', async () => {
Expand Down
10 changes: 5 additions & 5 deletions src/__tests__/components/Translations.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<template>
<h2>{{ $t('hello') }}</h2>
<select v-model="$i18n.locale">
<option value="en">English</option>
<option value="ja">Japanese</option>
</select>
<h2>{{ $t('hello') }}</h2>
<select v-model="$i18n.locale">
<option value="en">English</option>
<option value="ja">Japanese</option>
</select>
</template>

<script>
Expand Down
21 changes: 0 additions & 21 deletions src/__tests__/components/VueI18n.vue

This file was deleted.

2 changes: 1 addition & 1 deletion src/__tests__/debug.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable testing-library/no-debug */
import {render} from '@testing-library/vue'
import {render} from '..'
import HelloWorld from './components/HelloWorld'

beforeEach(() => {
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/directive.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {render} from '@testing-library/vue'
import {render} from '..'
import '@testing-library/jest-dom'
import {uppercaseDirective} from './directives/uppercase-directive'
import ComponentUsingDirective from './components/Directive'
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/disappearance.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {render, waitForElementToBeRemoved} from '@testing-library/vue'
import {render, waitForElementToBeRemoved} from '..'
import Disappearance from './components/Disappearance'
import '@testing-library/jest-dom'

Expand Down
19 changes: 18 additions & 1 deletion src/__tests__/fire-event.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {h} from 'vue'
import {render, fireEvent} from '@testing-library/vue'
import {render, fireEvent} from '..'
import Button from './components/Button'

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

expect(console.warn).not.toHaveBeenCalled()
})

test('fireEvent.update handles input file', async () => {
const {getByTestId} = render({
template: `<input type="file" data-testid="test-update" />`,
})

const file = new File(['(⌐□_□)'], 'chucknorris.png', {type: 'image/png'})

const inputEl = getByTestId('test-update')

// You could replace the lines below with
// userEvent.upload(inputEl, file)
Object.defineProperty(inputEl, 'files', {value: [file]})
await fireEvent.update(inputEl)

expect(console.warn).not.toHaveBeenCalled()
})
2 changes: 1 addition & 1 deletion src/__tests__/form.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {render, fireEvent} from '@testing-library/vue'
import {render, fireEvent} from '..'
import '@testing-library/jest-dom'
import Form from './components/Form'

Expand Down
4 changes: 2 additions & 2 deletions src/__tests__/functional.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {render} from '@testing-library/vue'
import '@testing-library/jest-dom'
import {h} from 'vue'
import {render} from '..'
import '@testing-library/jest-dom'

// From docs: Performance gains from 2.x for functional components are now
// negligible in 3.x, so we recommend just using stateful components.
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/render.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {render} from '@testing-library/vue'
import {render} from '..'
import '@testing-library/jest-dom'

test('baseElement defaults to document.body', () => {
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/rerender.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import '@testing-library/jest-dom'
import {defineComponent, h, computed} from 'vue'
import {render} from '@testing-library/vue'
import {render} from '..'
import NumberDisplay from './components/NumberDisplay'

// It'd probably be better if you test the component that's doing the rerendering
Expand Down
10 changes: 5 additions & 5 deletions src/__tests__/select.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {render, fireEvent} from '@testing-library/vue'
import {render, fireEvent} from '..'
import '@testing-library/jest-dom'
import Select from './components/Select'

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

// Get the Select element by using the initially displayed value.
const select = getByDisplayValue('Tyrannosaurus')
expect(select.value).toBe('dino1')
expect(select).toHaveValue('dino1')

// Update it by manually sending a valid option value.
await fireEvent.update(select, 'dino2')
expect(select.value).toBe('dino2')
expect(select).toHaveValue('dino2')

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

// ...even if option is within an <optgroup>.
optionElement = getByText('Diplodocus')
await fireEvent.update(optionElement)
expect(select.value).toBe('dino4')
expect(select).toHaveValue('dino4')
})
2 changes: 1 addition & 1 deletion src/__tests__/simple-button.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {render, fireEvent} from '@testing-library/vue'
import {render, fireEvent} from '..'
import Button from './components/Button'
import '@testing-library/jest-dom'

Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/slots.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import '@testing-library/jest-dom'
import {render} from '@testing-library/vue'
import {render} from '..'
import Card from './components/Card'

// Usage is the same as Vue Test Utils, since slots values are passed using the `slots`
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/stopwatch.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import '@testing-library/jest-dom'
import {render, waitFor, fireEvent} from '@testing-library/vue'
import {render, waitFor, fireEvent} from '..'
import StopWatch from './components/StopWatch.vue'

const sleep = ms =>
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/stubs.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {render} from '@testing-library/vue'
import {render} from '..'
import '@testing-library/jest-dom'
import Stubs from './components/Stubs'

Expand Down
40 changes: 20 additions & 20 deletions src/__tests__/user-event.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import '@testing-library/jest-dom'
import {render} from '@testing-library/vue'
import userEvent from '@testing-library/user-event'
import {render, waitFor} from '..'
import Form from './components/Form'
import Select from './components/Select'

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

const titleInput = getByLabelText(/title of the movie/i)
await userEvent.type(titleInput, fakeReview.title)
expect(titleInput.value).toEqual(fakeReview.title)
userEvent.type(titleInput, fakeReview.title)
expect(titleInput).toHaveValue(fakeReview.title)

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

await userEvent.clear(textArea)
expect(textArea.value).toEqual('')
await userEvent.type(textArea, fakeReview.review)
expect(textArea.value).toEqual(fakeReview.review)
userEvent.clear(textArea)
expect(textArea).toHaveValue('')
userEvent.type(textArea, fakeReview.review)
expect(textArea).toHaveValue(fakeReview.review)

const initialSelectedRating = getByLabelText(/Awful/i)
const wonderfulRadioInput = getByLabelText(/Wonderful/i)
expect(initialSelectedRating).toBeChecked()
expect(wonderfulRadioInput).not.toBeChecked()

await userEvent.click(wonderfulRadioInput)
userEvent.click(wonderfulRadioInput)
expect(wonderfulRadioInput).toBeChecked()
expect(initialSelectedRating).not.toBeChecked()
await waitFor(() => expect(initialSelectedRating).not.toBeChecked())

const recommendInput = getByLabelText(/Would you recommend this movie?/i)
await userEvent.click(recommendInput)
userEvent.click(recommendInput)
expect(recommendInput).toBeChecked()

userEvent.tab()
expect(submitButton).toHaveFocus()
expect(submitButton).toBeEnabled()
await userEvent.type(submitButton, '{enter}')
userEvent.type(submitButton, '{enter}')
expect(emitted().submit[0][0]).toMatchObject(fakeReview)

expect(console.warn).not.toHaveBeenCalled()
})

test('selecting option with user events', async () => {
test('selecting option with user events', () => {
const {getByDisplayValue} = render(Select)
const select = getByDisplayValue('Tyrannosaurus')
expect(select.value).toBe('dino1')
expect(select).toHaveValue('dino1')

await userEvent.selectOptions(select, 'dino2')
expect(select.value).toBe('dino2')
userEvent.selectOptions(select, 'dino2')
expect(select).toHaveValue('dino2')

await userEvent.selectOptions(select, 'dino3')
expect(select.value).not.toBe('dino2')
expect(select.value).toBe('dino3')
userEvent.selectOptions(select, 'dino3')
expect(select).not.toHaveValue('dino2')
expect(select).toHaveValue('dino3')
})
Loading