From 5f2e101c54e8cd0248d87089b7535312c07716c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Fontcuberta?= Date: 2023年3月11日 20:09:46 +0100 Subject: [PATCH 1/9] feat: Bump minimum node.js version and DOM Testing Library (#303) BREAKING CHANGE: This PR increases the minimum node.js version to v14, and DOM Testing Library to v9. --- .eslintrc.js | 3 +- .github/workflows/validate.yml | 4 +- babel.config.js | 6 ++ jest.config.js | 5 +- package.json | 59 +++++++++---------- src/__tests__/hello-world-debug.js | 4 +- src/__tests__/user-event.js | 25 ++++---- src/__tests__/vue-apollo.js | 94 ------------------------------ src/__tests__/vuetify.js | 73 ----------------------- types/index.test-d.ts | 2 +- 10 files changed, 59 insertions(+), 216 deletions(-) delete mode 100644 src/__tests__/vue-apollo.js delete mode 100644 src/__tests__/vuetify.js diff --git a/.eslintrc.js b/.eslintrc.js index acb83293..0e331129 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,6 +1,8 @@ module.exports = { + parser: 'vue-eslint-parser', parserOptions: { parser: '@typescript-eslint/parser', + sourceType: 'module', }, extends: [ './node_modules/kcd-scripts/eslint.js', @@ -8,7 +10,6 @@ module.exports = { 'plugin:testing-library/vue', 'prettier', ], - plugins: ['vue'], rules: { 'no-console': 'off', 'import/no-unresolved': 'off', diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index afb9a077..0ef1301e 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -17,7 +17,7 @@ jobs: main: strategy: matrix: - node: [12, 14, 16] + node: [14, 16, 18] runs-on: ubuntu-latest steps: - name: ⬇️ Checkout repo @@ -56,7 +56,7 @@ jobs: - name: ⎔ Setup node uses: actions/setup-node@v2 with: - node-version: 14 + node-version: 16 - name: 📥 Download deps uses: bahmutov/npm-install@v1 diff --git a/babel.config.js b/babel.config.js index 424f157b..31ac5180 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,5 +1,11 @@ module.exports = { sourceType: 'module', + plugins: [ + // Fixes for loose issue from https://github.com/rails/webpacker/issues/3008 + ['@babel/plugin-proposal-class-properties', {loose: true}], + ['@babel/plugin-proposal-private-methods', {loose: true}], + ['@babel/plugin-proposal-private-property-in-object', {loose: true}], + ], presets: [ [ '@babel/preset-env', diff --git a/jest.config.js b/jest.config.js index 9d901b60..a440b667 100644 --- a/jest.config.js +++ b/jest.config.js @@ -3,12 +3,15 @@ const config = require('kcd-scripts/jest') module.exports = merge(config, { testEnvironment: 'jsdom', + testEnvironmentOptions: { + customExportConditions: ['node', 'node-addons'], + }, moduleFileExtensions: ['js', 'vue'], coverageDirectory: './coverage', collectCoverageFrom: ['**/src/**/*.js', '!**/src/__tests__/**'], transform: { '^.+\\.js$': '/node_modules/babel-jest', - '.*\\.(vue)$': '/node_modules/vue-jest', + '^.+\\.vue$': '@vue/vue3-jest', }, snapshotSerializers: ['/node_modules/jest-serializer-vue'], testPathIgnorePatterns: [ diff --git a/package.json b/package.json index 174cbf6e..273f2864 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "setup": "npm install && npm run validate -s" }, "engines": { - "node": ">=12" + "node": ">=14" }, "files": [ "types", @@ -43,39 +43,36 @@ "author": "Daniel Cook", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.15.4", - "@testing-library/dom": "^8.5.0", - "@vue/test-utils": "^2.0.0" + "@babel/runtime": "^7.21.0", + "@testing-library/dom": "^9.0.1", + "@vue/test-utils": "^2.3.1" }, "devDependencies": { - "@apollo/client": "^3.4.11", - "@babel/plugin-transform-runtime": "^7.15.0", - "@testing-library/jest-dom": "^5.14.1", - "@testing-library/user-event": "^13.2.1", - "@types/estree": "^0.0.50", - "@vue/apollo-composable": "^4.0.0-alpha.14", - "@vue/compiler-sfc": "^3.2.12", - "apollo-boost": "^0.4.9", - "axios": "^0.20.0", - "element-plus": "^1.3.0-beta.1", - "eslint-plugin-vue": "^8.2.0", - "graphql": "^15.5.3", - "graphql-tag": "^2.12.4", - "isomorphic-unfetch": "^3.1.0", - "jest-serializer-vue": "^2.0.2", - "kcd-scripts": "^10.0.0", + "@babel/plugin-transform-runtime": "^7.21.0", + "@element-plus/icons-vue": "^2.1.0", + "@testing-library/jest-dom": "^5.16.5", + "@testing-library/user-event": "^14.4.3", + "@types/estree": "^1.0.0", + "@vue/compiler-sfc": "^3.2.47", + "@vue/server-renderer": "^3.2.47", + "@vue/vue3-jest": "^29.2.3", + "axios": "^1.3.4", + "element-plus": "^2.2.36", + "eslint-plugin-vue": "^9.9.0", + "isomorphic-unfetch": "^4.0.2", + "jest-environment-jsdom": "^29.5.0", + "jest-serializer-vue": "^3.1.0", + "kcd-scripts": "^13.0.0", "lodash.merge": "^4.6.2", - "msw": "^0.21.3", - "tsd": "^0.19.1", - "typescript": "^4.4.3", - "vee-validate": "^4.3.5", - "vue": "^3.2.12", - "vue-apollo": "^3.0.5", - "vue-i18n": "^9.2.0-beta.26", - "vue-jest": "^5.0.0-alpha.10", - "vue-router": "^4.0.3", - "vuetify": "^v3.0.0-alpha.12", - "vuex": "^4.0.0" + "msw": "^1.1.0", + "tsd": "^0.27.0", + "typescript": "^4.9.5", + "vee-validate": "^4.7.4", + "vue": "^3.2.47", + "vue-eslint-parser": "^9.1.0", + "vue-i18n": "^9.2.2", + "vue-router": "^4.1.6", + "vuex": "^4.1.0" }, "peerDependencies": { "@vue/compiler-sfc": ">= 3", diff --git a/src/__tests__/hello-world-debug.js b/src/__tests__/hello-world-debug.js index 554feb04..ab2adf4c 100644 --- a/src/__tests__/hello-world-debug.js +++ b/src/__tests__/hello-world-debug.js @@ -1,4 +1,4 @@ -/* eslint-disable testing-library/no-debug */ +/* eslint-disable testing-library/no-debugging-utils */ import {render} from '..' import HelloWorld from './components/HelloWorld' @@ -67,7 +67,7 @@ test('allows same arguments as prettyDOM', () => { expect(console.log).toHaveBeenCalledTimes(1) expect(console.log.mock.calls[0]).toMatchInlineSnapshot(` - Array [ + [
..., ] diff --git a/src/__tests__/user-event.js b/src/__tests__/user-event.js index ed02bfbf..5d38af12 100644 --- a/src/__tests__/user-event.js +++ b/src/__tests__/user-event.js @@ -18,22 +18,23 @@ test('User events in a form', async () => { review: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', rating: '3', } + const user = userEvent.setup() const {getByText, getByLabelText, emitted} = render(Form) const submitButton = getByText('Submit') expect(submitButton).toBeDisabled() const titleInput = getByLabelText(/title of the movie/i) - userEvent.type(titleInput, fakeReview.title) + await user.type(titleInput, fakeReview.title) expect(titleInput).toHaveValue(fakeReview.title) const textArea = getByLabelText(/Your review/i) - userEvent.type(textArea, 'The t-rex went insane!') + await user.type(textArea, 'The t-rex went insane!') expect(textArea).toHaveValue('The t-rex went insane!') - userEvent.clear(textArea) + await user.clear(textArea) expect(textArea).toHaveValue('') - userEvent.type(textArea, fakeReview.review) + await user.type(textArea, fakeReview.review) expect(textArea).toHaveValue(fakeReview.review) const initialSelectedRating = getByLabelText(/Awful/i) @@ -41,32 +42,34 @@ test('User events in a form', async () => { expect(initialSelectedRating).toBeChecked() expect(wonderfulRadioInput).not.toBeChecked() - userEvent.click(wonderfulRadioInput) + await user.click(wonderfulRadioInput) expect(wonderfulRadioInput).toBeChecked() await waitFor(() => expect(initialSelectedRating).not.toBeChecked()) const recommendInput = getByLabelText(/Would you recommend this movie?/i) - userEvent.click(recommendInput) + await user.click(recommendInput) expect(recommendInput).toBeChecked() - userEvent.tab() + await user.tab() expect(submitButton).toHaveFocus() expect(submitButton).toBeEnabled() - userEvent.type(submitButton, '{enter}') + await user.type(submitButton, '{enter}') expect(emitted('submit')[0][0]).toMatchObject(fakeReview) expect(console.warn).not.toHaveBeenCalled() }) -test('selecting option with user events', () => { +test('selecting option with user events', async () => { + const user = userEvent.setup() const {getByDisplayValue} = render(Select) + const select = getByDisplayValue('Tyrannosaurus') expect(select).toHaveValue('dino1') - userEvent.selectOptions(select, 'dino2') + await user.selectOptions(select, 'dino2') expect(select).toHaveValue('dino2') - userEvent.selectOptions(select, 'dino3') + await user.selectOptions(select, 'dino3') expect(select).not.toHaveValue('dino2') expect(select).toHaveValue('dino3') }) diff --git a/src/__tests__/vue-apollo.js b/src/__tests__/vue-apollo.js deleted file mode 100644 index 6d29c517..00000000 --- a/src/__tests__/vue-apollo.js +++ /dev/null @@ -1,94 +0,0 @@ -import '@testing-library/jest-dom' -import fetch from 'isomorphic-unfetch' -import {DefaultApolloClient} from '@vue/apollo-composable' -import ApolloClient from 'apollo-boost' -import {setupServer} from 'msw/node' -import {graphql} from 'msw' -import {render, fireEvent, screen} from '..' -import Component from './components/VueApollo.vue' - -// Since vue-apollo doesn't provide a MockProvider for Vue, -// you need to use some kind of mocks for the queries. - -// We are using Mock Service Worker (aka MSW) library to declaratively mock API communication -// in your tests instead of stubbing window.fetch, or relying on third-party adapters. - -const server = setupServer( - ...[ - graphql.query('getUser', (req, res, ctx) => { - const {variables} = req - - if (variables.id !== '1') { - return res( - ctx.errors([ - { - message: 'User not found', - }, - ]), - ) - } - - return res( - ctx.data({ - user: { - id: 1, - email: 'alice@example.com', - __typename: 'User', - }, - }), - ) - }), - - graphql.mutation('updateUser', (req, res, ctx) => { - const {variables} = req - - return res( - ctx.data({ - updateUser: { - id: variables.input.id, - email: variables.input.email, - __typename: 'User', - }, - }), - ) - }), - ], -) - -beforeAll(() => server.listen()) -afterEach(() => server.resetHandlers()) -afterAll(() => server.close()) - -test('mocking queries and mutations', async () => { - const apolloClient = new ApolloClient({ - uri: 'http://localhost:3000', - fetch, - }) - - render(Component, { - props: {id: '1'}, - global: { - provide: { - [DefaultApolloClient]: apolloClient, - }, - }, - }) - - //Initial rendering will be in the loading state, - expect(screen.getByText('Loading')).toBeInTheDocument() - - expect( - await screen.findByText('Email: alice@example.com'), - ).toBeInTheDocument() - - await fireEvent.update( - screen.getByLabelText('Email'), - 'alice+new@example.com', - ) - - await fireEvent.click(screen.getByRole('button', {name: 'Change email'})) - - expect( - await screen.findByText('Email: alice+new@example.com'), - ).toBeInTheDocument() -}) diff --git a/src/__tests__/vuetify.js b/src/__tests__/vuetify.js deleted file mode 100644 index a933e8ef..00000000 --- a/src/__tests__/vuetify.js +++ /dev/null @@ -1,73 +0,0 @@ -test.todo('Your test suite must contain at least one test.') -// import '@testing-library/jest-dom' -// import Vue from 'vue' -// import {render, fireEvent} from '..' -// import Vuetify from 'vuetify' -// import VuetifyDemoComponent from './components/Vuetify' - -// // We need to use a global Vue instance, otherwise Vuetify will complain about -// // read-only attributes. -// // This could also be done in a custom Jest-test-setup file to execute for all tests. -// // More info: https://github.com/vuetifyjs/vuetify/issues/4068 -// // https://vuetifyjs.com/en/getting-started/unit-testing -// Vue.use(Vuetify) - -// // Custom container to integrate Vuetify with Vue Testing Library. -// // Vuetify requires you to wrap your app with a v-app component that provides -// // a
node. -// const renderWithVuetify = (component, options, callback) => { -// const root = document.createElement('div') -// root.setAttribute('data-app', 'true') - -// return render( -// component, -// { -// container: document.body.appendChild(root), -// // for Vuetify components that use the $vuetify instance property -// vuetify: new Vuetify(), -// ...options, -// }, -// callback, -// ) -// } - -// test('should set [data-app] attribute on outer most div', () => { -// const {container} = renderWithVuetify(VuetifyDemoComponent) - -// expect(container).toHaveAttribute('data-app', 'true') -// }) - -// test('renders a Vuetify-powered component', async () => { -// const {getByText} = renderWithVuetify(VuetifyDemoComponent) - -// await fireEvent.click(getByText('open')) - -// expect(getByText('Lorem ipsum dolor sit amet.')).toMatchInlineSnapshot(` -//
-// Lorem ipsum dolor sit amet. -//
-// `) -// }) - -// test('opens a menu', async () => { -// const {getByRole, getByText, queryByText} = renderWithVuetify( -// VuetifyDemoComponent, -// ) - -// const openMenuButton = getByRole('button', {name: 'open menu'}) - -// // Menu item is not rendered initially -// expect(queryByText('menu item')).not.toBeInTheDocument() - -// await fireEvent.click(openMenuButton) - -// const menuItem = getByText('menu item') -// expect(menuItem).toBeInTheDocument() - -// await fireEvent.click(openMenuButton) - -// expect(menuItem).toBeInTheDocument() -// expect(menuItem).not.toBeVisible() -// }) diff --git a/types/index.test-d.ts b/types/index.test-d.ts index 09ad1fd1..5a0253d7 100644 --- a/types/index.test-d.ts +++ b/types/index.test-d.ts @@ -93,7 +93,7 @@ export function testEmitted() { eslint testing-library/prefer-explicit-assert: "off", testing-library/no-wait-for-empty-callback: "off", - testing-library/no-debug: "off", + testing-library/no-debugging-utils: "off", testing-library/prefer-screen-queries: "off", @typescript-eslint/unbound-method: "off", @typescript-eslint/no-invalid-void-type: "off" From 675a4fbdc9e19a537ef4e14f647c0d3be06d3e78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Fontcuberta?= Date: 2023年3月11日 20:13:36 +0100 Subject: [PATCH 2/9] chore: update actions --- .github/workflows/validate.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 0ef1301e..cc17d29d 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -21,10 +21,10 @@ jobs: runs-on: ubuntu-latest steps: - name: ⬇️ Checkout repo - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: ⎔ Setup node - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} @@ -40,7 +40,7 @@ jobs: run: npm run validate - name: ⬆️ Upload coverage report - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v3 release: needs: main @@ -51,10 +51,10 @@ jobs: github.ref) && github.event_name == 'push' }} steps: - name: ⬇️ Checkout repo - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: ⎔ Setup node - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: 16 From 015de7d9b7c178f7252f0506f13febe9462f21f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Fontcuberta?= Date: 2023年10月20日 09:47:08 +0200 Subject: [PATCH 3/9] chore: Update deps (#307) * Update minor deps * Update major deps --- package.json | 48 ++++++++++++++++++++------------------- src/__tests__/teleport.js | 2 +- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/package.json b/package.json index 273f2864..f2c2a337 100644 --- a/package.json +++ b/package.json @@ -43,35 +43,37 @@ "author": "Daniel Cook", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.21.0", - "@testing-library/dom": "^9.0.1", - "@vue/test-utils": "^2.3.1" + "@babel/runtime": "^7.23.2", + "@testing-library/dom": "^9.3.3", + "@vue/test-utils": "^2.4.1" }, "devDependencies": { - "@babel/plugin-transform-runtime": "^7.21.0", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.21.11", + "@babel/plugin-transform-runtime": "^7.23.2", "@element-plus/icons-vue": "^2.1.0", - "@testing-library/jest-dom": "^5.16.5", - "@testing-library/user-event": "^14.4.3", - "@types/estree": "^1.0.0", - "@vue/compiler-sfc": "^3.2.47", - "@vue/server-renderer": "^3.2.47", - "@vue/vue3-jest": "^29.2.3", - "axios": "^1.3.4", - "element-plus": "^2.2.36", - "eslint-plugin-vue": "^9.9.0", + "@testing-library/jest-dom": "^6.1.4", + "@testing-library/user-event": "^14.5.1", + "@types/estree": "^1.0.3", + "@vue/compiler-sfc": "^3.3.5", + "@vue/server-renderer": "^3.3.5", + "@vue/vue3-jest": "^29.2.6", + "axios": "^1.5.1", + "element-plus": "^2.4.1", + "eslint-plugin-vue": "^9.17.0", "isomorphic-unfetch": "^4.0.2", - "jest-environment-jsdom": "^29.5.0", + "jest-environment-jsdom": "^29.7.0", "jest-serializer-vue": "^3.1.0", - "kcd-scripts": "^13.0.0", + "kcd-scripts": "^14.0.0", "lodash.merge": "^4.6.2", - "msw": "^1.1.0", - "tsd": "^0.27.0", - "typescript": "^4.9.5", - "vee-validate": "^4.7.4", - "vue": "^3.2.47", - "vue-eslint-parser": "^9.1.0", - "vue-i18n": "^9.2.2", - "vue-router": "^4.1.6", + "msw": "^1.3.2", + "tsd": "^0.29.0", + "typescript": "^5.2.2", + "vee-validate": "^4.11.8", + "vue": "^3.3.5", + "vue-eslint-parser": "^9.3.2", + "vue-i18n": "^9.5.0", + "vue-router": "^4.2.5", "vuex": "^4.1.0" }, "peerDependencies": { diff --git a/src/__tests__/teleport.js b/src/__tests__/teleport.js index 04dbf6db..c756df12 100644 --- a/src/__tests__/teleport.js +++ b/src/__tests__/teleport.js @@ -1,5 +1,5 @@ import {defineComponent} from 'vue' -import '@testing-library/jest-dom/extend-expect' +import '@testing-library/jest-dom' import {render, fireEvent} from '..' const ModalButton = defineComponent({ From 88fb8cd38cc260fbb88f2d42e4a66a500b56f44a Mon Sep 17 00:00:00 2001 From: Maxim Mazurok Date: 2023年10月31日 19:34:23 +1100 Subject: [PATCH 4/9] bug: Fix issue on Vite env not cleaning up after test (#297) BREAKING CHANGE: This PR change default behavior for Vitest users. This major should yield no effect to other test frameworks. Throw error when running vitest with no `afterEach` global and no `VTL_SKIP_AUTO_CLEANUP` flag is set. --- src/__tests__/auto-cleanup-vitest-globals.js | 7 +++++++ src/__tests__/auto-cleanup-vitest.js | 10 ++++++++++ src/index.js | 5 +++++ 3 files changed, 22 insertions(+) create mode 100644 src/__tests__/auto-cleanup-vitest-globals.js create mode 100644 src/__tests__/auto-cleanup-vitest.js diff --git a/src/__tests__/auto-cleanup-vitest-globals.js b/src/__tests__/auto-cleanup-vitest-globals.js new file mode 100644 index 00000000..8d320ea0 --- /dev/null +++ b/src/__tests__/auto-cleanup-vitest-globals.js @@ -0,0 +1,7 @@ +// This test verifies that if test is running from vitest with globals - jest will not throw +test('works', () => { + global.afterEach = () => {} // emulate enabled globals + process.env.VITEST = 'true' + + expect(() => require('..')).not.toThrow() +}) diff --git a/src/__tests__/auto-cleanup-vitest.js b/src/__tests__/auto-cleanup-vitest.js new file mode 100644 index 00000000..ef0a5a1f --- /dev/null +++ b/src/__tests__/auto-cleanup-vitest.js @@ -0,0 +1,10 @@ +// This test verifies that if test is running from vitest without globals - jest will throw +test('works', () => { + delete global.afterEach // no globals in vitest by default + process.env.VITEST = 'true' + + expect(() => require('..')).toThrowErrorMatchingInlineSnapshot(` + You are using vitest without globals, this way we can't run cleanup after each test. + See https://testing-library.com/docs/vue-testing-library/setup for details or set the VTL_SKIP_AUTO_CLEANUP variable to 'true' + `) +}) diff --git a/src/index.js b/src/index.js index b9f4dc4e..99a01b7e 100644 --- a/src/index.js +++ b/src/index.js @@ -8,6 +8,11 @@ if (typeof afterEach === 'function' && !process.env.VTL_SKIP_AUTO_CLEANUP) { afterEach(() => { cleanup() }) +} else if (process.env.VITEST === 'true') { + throw new Error( + "You are using vitest without globals, this way we can't run cleanup after each test.\n" + + "See https://testing-library.com/docs/vue-testing-library/setup for details or set the VTL_SKIP_AUTO_CLEANUP variable to 'true'", + ) } export * from '@testing-library/dom' From 1bbeeb404fcf461120548d7a9ae6817f3f184a73 Mon Sep 17 00:00:00 2001 From: Isaiah Thomason <47364027+itenthusiasm@users.noreply.github.com> Date: 2023年11月20日 10:38:57 -0500 Subject: [PATCH 5/9] fix: Revert Errors Regarding Missing Global Hooks (#310) Please bear in mind that after 8.0.1, v7 and v8 share the same behavior as the main difference between versions has been erased. So everyone should be able to jump from v7 to v8 without experiencing any difference. --- src/__tests__/auto-cleanup-vitest-globals.js | 7 ------- src/__tests__/auto-cleanup-vitest.js | 10 ---------- src/index.js | 5 ----- 3 files changed, 22 deletions(-) delete mode 100644 src/__tests__/auto-cleanup-vitest-globals.js delete mode 100644 src/__tests__/auto-cleanup-vitest.js diff --git a/src/__tests__/auto-cleanup-vitest-globals.js b/src/__tests__/auto-cleanup-vitest-globals.js deleted file mode 100644 index 8d320ea0..00000000 --- a/src/__tests__/auto-cleanup-vitest-globals.js +++ /dev/null @@ -1,7 +0,0 @@ -// This test verifies that if test is running from vitest with globals - jest will not throw -test('works', () => { - global.afterEach = () => {} // emulate enabled globals - process.env.VITEST = 'true' - - expect(() => require('..')).not.toThrow() -}) diff --git a/src/__tests__/auto-cleanup-vitest.js b/src/__tests__/auto-cleanup-vitest.js deleted file mode 100644 index ef0a5a1f..00000000 --- a/src/__tests__/auto-cleanup-vitest.js +++ /dev/null @@ -1,10 +0,0 @@ -// This test verifies that if test is running from vitest without globals - jest will throw -test('works', () => { - delete global.afterEach // no globals in vitest by default - process.env.VITEST = 'true' - - expect(() => require('..')).toThrowErrorMatchingInlineSnapshot(` - You are using vitest without globals, this way we can't run cleanup after each test. - See https://testing-library.com/docs/vue-testing-library/setup for details or set the VTL_SKIP_AUTO_CLEANUP variable to 'true' - `) -}) diff --git a/src/index.js b/src/index.js index 99a01b7e..b9f4dc4e 100644 --- a/src/index.js +++ b/src/index.js @@ -8,11 +8,6 @@ if (typeof afterEach === 'function' && !process.env.VTL_SKIP_AUTO_CLEANUP) { afterEach(() => { cleanup() }) -} else if (process.env.VITEST === 'true') { - throw new Error( - "You are using vitest without globals, this way we can't run cleanup after each test.\n" + - "See https://testing-library.com/docs/vue-testing-library/setup for details or set the VTL_SKIP_AUTO_CLEANUP variable to 'true'", - ) } export * from '@testing-library/dom' From 9816ba4d150455570da75f8a9e58857d11c974d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Fontcuberta?= Date: 2023年11月20日 17:41:12 +0100 Subject: [PATCH 6/9] docs: Update README.md --- README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 20a232a0..4208463c 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,6 @@
-[![Build Status][build-badge]][build] [![Coverage Status][coverage-badge]][coverage] [![GitHub version][github-badge]][github] [![npm version][npm-badge]][npm] @@ -66,7 +65,7 @@ npm install --save-dev @testing-library/vue ``` This library has `peerDependencies` listings for `Vue 3` and -`vue-template-compiler`. +`@vue/compiler-sfc`. You may also be interested in installing `jest-dom` so you can use [the custom Jest matchers][jest-dom]. @@ -129,7 +128,7 @@ test('increments value on click', async () => { > You might want to install [`jest-dom`][jest-dom] to add handy assertions such > as `.toBeInTheDocument()`. In the example above, you could write -> `expect(screen.queryByText('Times clicked: 0')).toBeInTheDocument()`. +> `expect(screen.getByText('Times clicked: 0')).toBeInTheDocument()`. > Using `byText` queries it's not the only nor the best way to query for > elements. Read [Which query should I use?][which-query] to discover @@ -243,8 +242,6 @@ instead of filing an issue on GitHub. [![ITenthusiasm](https://avatars2.githubusercontent.com/u/47364027?v3&s=120)](https://github.com/ITenthusiasm) -[build-badge]: https://img.shields.io/github/workflow/status/testing-library/vue-testing-library/validate?logo=github -[build]: https://github.com/testing-library/vue-testing-library/actions?query=workflow%3Avalidate [coverage-badge]: https://img.shields.io/codecov/c/github/testing-library/vue-testing-library.svg [coverage]: https://codecov.io/github/testing-library/vue-testing-library [github-badge]: https://badge.fury.io/gh/testing-library%2Fvue-testing-library.svg From f5a348347a57c991ace8145e1eba82713a779e59 Mon Sep 17 00:00:00 2001 From: Yue Yang Date: Thu, 8 Feb 2024 17:55:44 +0800 Subject: [PATCH 7/9] fix: mark compiler-sfc as optional peer dep (#288) Mark compiler-sfc as an optional peer dependency. --- package.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/package.json b/package.json index f2c2a337..3c2760a6 100644 --- a/package.json +++ b/package.json @@ -80,6 +80,11 @@ "@vue/compiler-sfc": ">= 3", "vue": ">= 3" }, + "peerDependenciesMeta": { + "@vue/compiler-sfc": { + "optional": true + } + }, "husky": { "hooks": { "pre-commit": "kcd-scripts pre-commit" From 3ecde9e25adb2e3f2da309e1d4fa00a89ba8f1b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=9D=E6=99=A8=E5=85=89?= <2293885211@qq.com> Date: 2024年3月18日 15:45:49 +0800 Subject: [PATCH 8/9] fix: allow unmounting with no wrapper element (#312) * fix: check wrapper element to fix #311 --- src/__tests__/render.js | 15 ++++++++++++++- src/render.js | 5 +---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/__tests__/render.js b/src/__tests__/render.js index 151bd8bc..ea55817f 100644 --- a/src/__tests__/render.js +++ b/src/__tests__/render.js @@ -1,4 +1,5 @@ -import {render} from '..' +import {render, cleanup} from '..' +import {h, defineComponent} from 'vue' import '@testing-library/jest-dom' test('baseElement defaults to document.body', () => { @@ -87,3 +88,15 @@ test('unmounts', () => { expect(queryByTestId('node')).not.toBeInTheDocument() }) + +test('unmounts when no wrapper element is present', () => { + const Comp = defineComponent((_, ctx) => () => ctx.slots.default?.()) + + const {unmount} = render({ + render: () => h(Comp, () => h('div')), + }) + + unmount() + + expect(() => cleanup()).not.toThrow() +}) diff --git a/src/render.js b/src/render.js index 6f635cb2..997ba4c0 100644 --- a/src/render.js +++ b/src/render.js @@ -60,10 +60,7 @@ function cleanup() { } function cleanupAtWrapper(wrapper) { - if ( - wrapper.element.parentNode && - wrapper.element.parentNode.parentNode === document.body - ) { + if (wrapper.element?.parentNode?.parentNode === document.body) { document.body.removeChild(wrapper.element.parentNode) } From d46ed8f757e77fe85b369847c21d394bb9706066 Mon Sep 17 00:00:00 2001 From: Chris Heyer Date: 2024年5月18日 10:14:03 +0200 Subject: [PATCH 9/9] feat: Add types for props and slots in render function * Add types for render function * Fix lint errors --- package.json | 2 ++ src/__tests__/render.js | 2 +- types/index.d.ts | 27 ++++++++++++++++++++++----- types/index.test-d.ts | 2 +- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 3c2760a6..a3b7b084 100644 --- a/package.json +++ b/package.json @@ -68,9 +68,11 @@ "lodash.merge": "^4.6.2", "msw": "^1.3.2", "tsd": "^0.29.0", + "type-fest": "~2.19", "typescript": "^5.2.2", "vee-validate": "^4.11.8", "vue": "^3.3.5", + "vue-component-type-helpers": "^2.0.19", "vue-eslint-parser": "^9.3.2", "vue-i18n": "^9.5.0", "vue-router": "^4.2.5", diff --git a/src/__tests__/render.js b/src/__tests__/render.js index ea55817f..235210e3 100644 --- a/src/__tests__/render.js +++ b/src/__tests__/render.js @@ -1,6 +1,6 @@ -import {render, cleanup} from '..' import {h, defineComponent} from 'vue' import '@testing-library/jest-dom' +import {render, cleanup} from '..' test('baseElement defaults to document.body', () => { const {baseElement} = render({template: '
'}) diff --git a/types/index.d.ts b/types/index.d.ts index c6c157d7..d4edc3bf 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,10 +1,13 @@ // Minimum TypeScript Version: 4.0 /* eslint-disable @typescript-eslint/no-explicit-any */ +import {VNodeChild} from 'vue' import {MountingOptions} from '@vue/test-utils' import {queries, EventType, BoundFunctions} from '@testing-library/dom' // eslint-disable-next-line import/no-extraneous-dependencies import {OptionsReceived as PrettyFormatOptions} from 'pretty-format' +import {ComponentProps, ComponentSlots} from 'vue-component-type-helpers' +import {RemoveIndexSignature} from 'type-fest' // NOTE: fireEvent is overridden below export * from '@testing-library/dom' @@ -44,12 +47,26 @@ interface VueTestingLibraryRenderOptions { container?: Element baseElement?: Element } -export type RenderOptions = VueTestingLibraryRenderOptions & - VueTestUtilsRenderOptions -export function render( - TestComponent: any, // this makes me sad :sob: - options?: RenderOptions, +type AllowNonFunctionSlots = { + [K in keyof Slots]: Slots[K] | VNodeChild +} +type ExtractSlots = AllowNonFunctionSlots< + Partial>> +> + +export interface RenderOptions + extends Omit< + VueTestingLibraryRenderOptions & VueTestUtilsRenderOptions, + 'props' | 'slots' +> { + props?: ComponentProps + slots?: ExtractSlots +} + +export function render( + TestComponent: C, + options?: RenderOptions, ): RenderResult export type AsyncFireObject = { diff --git a/types/index.test-d.ts b/types/index.test-d.ts index 5a0253d7..02e9e187 100644 --- a/types/index.test-d.ts +++ b/types/index.test-d.ts @@ -68,7 +68,7 @@ export async function testWaitFor() { export function testOptions() { render(SomeComponent, { attrs: {a: 1}, - props: {c: 1}, // ideally it would fail because `c` is not an existing prop... + props: {foo: 1}, data: () => ({b: 2}), slots: { default: '
',

AltStyle によって変換されたページ (->オリジナル) /