From 05275b91e801e11c3ee294d31ac43ac634021ca2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Fontcuberta?= Date: Wed, 9 Dec 2020 23:18:40 +0100 Subject: [PATCH 01/10] feat: Add vue-router types --- types/index.d.ts | 3 ++- types/test.ts | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/types/index.d.ts b/types/index.d.ts index 5dec7fa4..c886447a 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -4,6 +4,7 @@ import {EmitsOptions} from 'vue' import {MountingOptions} from '@vue/test-utils' import {StoreOptions} from 'vuex' +import {RouteRecordRaw} from 'vue-router' import {queries, EventType, BoundFunctions} from '@testing-library/dom' // eslint-disable-next-line import/no-extraneous-dependencies import {OptionsReceived as PrettyFormatOptions} from 'pretty-format' @@ -33,7 +34,7 @@ type VueTestUtilsRenderOptions = Omit< > type VueTestingLibraryRenderOptions = { store?: StoreOptions<{}> - // router?: ¿¿¿??? + routes?: RouteRecordRaw[] container?: Element baseElement?: Element } diff --git a/types/test.ts b/types/test.ts index b11b466b..aeb5df89 100644 --- a/types/test.ts +++ b/types/test.ts @@ -82,6 +82,7 @@ export function testOptions() { state: {count: 3}, strict: true, }, + routes: [{path: '/', component: () => SomeComponent, name: 'route name'}], baseElement: document.createElement('div'), container: document.createElement('div'), }) From f4ac8d72d9250d45c030695692edc45afe6b100b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Fontcuberta?= Date: Thu, 10 Dec 2020 09:23:31 +0100 Subject: [PATCH 02/10] docs: Add example for external UI library --- package.json | 1 + src/__tests__/element-plus.js | 37 +++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 src/__tests__/element-plus.js diff --git a/package.json b/package.json index a10fa6c2..a316663e 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "apollo-client": "^2.6.10", "axios": "^0.20.0", "dtslint": "^4.0.6", + "element-plus": "^1.0.1-beta.7", "eslint-plugin-vue": "^7.1.0", "graphql": "^15.4.0", "graphql-tag": "^2.11.0", diff --git a/src/__tests__/element-plus.js b/src/__tests__/element-plus.js new file mode 100644 index 00000000..0d1eb633 --- /dev/null +++ b/src/__tests__/element-plus.js @@ -0,0 +1,37 @@ +import ElementPlus from 'element-plus' +import {defineComponent} from 'vue' +import userEvent from '@testing-library/user-event' +import '@testing-library/jest-dom' +import {render, screen, waitFor} from '..' + +const Component = defineComponent({ + template: ` + + + + `, +}) + +test('Stubs out a component', async () => { + render(Component, { + global: { + plugins: [ElementPlus], + }, + }) + + const button = screen.getByText('Hover to activate') + const getContent = () => screen.getByText('this is content') + + expect(getContent()).toBeInTheDocument() + expect(getContent()).not.toBeVisible() + + userEvent.hover(button) + + await waitFor(() => expect(getContent()).toBeVisible()) + + userEvent.unhover(button) + + await waitFor(() => expect(getContent()).not.toBeVisible()) +}) From 01d4cb7f60ca5d3176c02be3efd0e1006767fafe Mon Sep 17 00:00:00 2001 From: Alberto Gualis Date: Sat, 12 Dec 2020 12:48:36 +0100 Subject: [PATCH 03/10] docs: Add example for Apollo GraphQL + composition API --- compatibility-scripts/vue-apollo-patch.js | 30 +++ package.json | 10 +- src/__tests__/components/VueApollo.vue | 61 +++--- src/__tests__/components/VueApollo/queries.js | 17 +- src/__tests__/vue-apollo.js | 179 ++++++++++-------- 5 files changed, 177 insertions(+), 120 deletions(-) create mode 100644 compatibility-scripts/vue-apollo-patch.js diff --git a/compatibility-scripts/vue-apollo-patch.js b/compatibility-scripts/vue-apollo-patch.js new file mode 100644 index 00000000..07e6ed95 --- /dev/null +++ b/compatibility-scripts/vue-apollo-patch.js @@ -0,0 +1,30 @@ +// This patch is run from post-install script and it is a temporary hack until a pending PR is merged +// More details here: +// https://github.com/vuejs/vue-apollo/issues/1011 + +const fs = require('fs') +const path = require('path') + +const loadTrackingPath = path.resolve( + __dirname, + '../node_modules/@vue/apollo-composable/dist/util/loadingTracking.js' +) + +fs.writeFileSync( + loadTrackingPath, + fs.readFileSync(loadTrackingPath, 'utf8').replace(/\.\$root/m, '.root') +) + +const useQueryPath = path.resolve( + __dirname, + '../node_modules/@vue/apollo-composable/dist/useQuery.js' +) + +fs.writeFileSync( + useQueryPath, + fs + .readFileSync(useQueryPath, 'utf8') + .replace(/(^.*onServerPrefetch)/m, '$1=()=>{}; $1') + .replace(/(.* require\("vue"\);)/m, '') + .replace(/^.*(nextTick)/m, 'vue_demi_1.$1') +) \ No newline at end of file diff --git a/package.json b/package.json index a316663e..b758df76 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ "test": "kcd-scripts test", "test:update": "npm test -- --updateSnapshot --coverage", "validate": "kcd-scripts validate", - "setup": "npm install && npm run validate -s" + "setup": "npm install && npm run validate -s", + "postinstall": "node compatibility-scripts/vue-apollo-patch.js" }, "engines": { "node": ">10.18" @@ -52,14 +53,15 @@ "lodash.merge": "^4.6.2" }, "devDependencies": { + "@apollo/client": "3.2.3", "@babel/plugin-transform-runtime": "^7.12.1", "@testing-library/jest-dom": "^5.11.5", "@testing-library/user-event": "^12.4.0", "@types/estree": "0.0.45", + "@vue/apollo-composable": "4.0.0-alpha.10", "@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", "element-plus": "^1.0.1-beta.7", @@ -81,8 +83,8 @@ "vuex": "^4.0.0-rc.2" }, "peerDependencies": { - "vue": ">= 3", - "@vue/compiler-sfc": ">= 3" + "@vue/compiler-sfc": ">= 3", + "vue": ">= 3" }, "husky": { "hooks": { diff --git a/src/__tests__/components/VueApollo.vue b/src/__tests__/components/VueApollo.vue index a491c0e4..298d1e5c 100644 --- a/src/__tests__/components/VueApollo.vue +++ b/src/__tests__/components/VueApollo.vue @@ -1,6 +1,7 @@ diff --git a/src/__tests__/components/VueApollo/queries.js b/src/__tests__/components/VueApollo/queries.js index 05cd43c2..cd85fa2f 100644 --- a/src/__tests__/components/VueApollo/queries.js +++ b/src/__tests__/components/VueApollo/queries.js @@ -1,19 +1,18 @@ -import gql from 'graphql-tag' +import {gql} from 'apollo-boost' -export const updateUserMutation = gql` - mutation updateUser($data: UpdateUserInput) { - updateUser(input: $data) { +export const getUserQuery = gql` + query getUser($id: String!) { + user(id: $id) { id email } } ` - -export const userQuery = gql` - query User($id: String!) { - user(id: $id) { +export const updateUserMutation = gql` + mutation updateUser($data: UpdateUserInput) { + updateUser(input: $data) { id email } } -` +` \ No newline at end of file diff --git a/src/__tests__/vue-apollo.js b/src/__tests__/vue-apollo.js index d7728ed8..dd19b6e2 100644 --- a/src/__tests__/vue-apollo.js +++ b/src/__tests__/vue-apollo.js @@ -1,75 +1,104 @@ -test.todo('Your test suite must contain at least one test.') -// import '@testing-library/jest-dom' -// import fetch from 'isomorphic-unfetch' -// import {render, fireEvent, screen} from '..' -// import VueApollo from 'vue-apollo' -// import {InMemoryCache} from 'apollo-cache-inmemory' -// import ApolloClient from 'apollo-boost' - -// // Since vue-apollo doesn't provides a MockProvider for Vue, -// // you need to use some kind of mocks for the queries. - -// // We recommend using Mock Service Worker library to declaratively mock API communication -// // in your tests instead of stubbing window.fetch, or relying on third-party adapters. - -// import {setupServer} from 'msw/node' -// import {graphql} from 'msw' - -// import Component from './components/VueApollo.vue' - -// const apolloClient = new ApolloClient({ -// uri: 'http://localhost:3020/graphql', -// cache: new InMemoryCache({ -// addTypename: false, -// }), -// fetch, -// }) - -// const server = setupServer( -// ...[ -// graphql.mutation('updateUser', (req, res, ctx) => { -// const {variables} = req - -// return res( -// ctx.data({ -// updateUser: {id: variables.input.id, email: variables.input.email}, -// }), -// ) -// }), -// graphql.query('User', (req, res, ctx) => { -// return res(ctx.data({user: {id: '1', email: 'alice@example.com'}})) -// }), -// ], -// ) - -// beforeAll(() => server.listen()) -// afterEach(() => server.resetHandlers()) -// afterAll(() => server.close()) - -// test('mocking queries and mutations', async () => { -// render(Component, {props: {id: '1'}}, localVue => { -// localVue.use(VueApollo) - -// return { -// apolloProvider: new VueApollo({defaultClient: 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() -// }) +import '@testing-library/jest-dom' +import fetch from 'isomorphic-unfetch' +import {render, fireEvent, screen} from '..' +import { DefaultApolloClient } from '@vue/apollo-composable' +import ApolloClient from 'apollo-boost' +import {setupServer} from 'msw/node' +import {graphql} from 'msw' +import { provide, h } from 'vue' +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()) + +const apolloClient = new ApolloClient({ + uri: "http://localhost:3000", + fetch, +}) + +const ComponentWithInjectedApollo = { + // It would be preferable to use global.provide when we pass options to VTU options + // to testing library render function but that option is not yet supported by VTU + setup () { + provide(DefaultApolloClient, apolloClient) + }, + render() { + return h(Component) + } +} + +test('mocking queries and mutations', async () => { + + render(ComponentWithInjectedApollo, { + props: {id: '1'} + }) + + //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() +}) From 22e7f843c86da23d8e13e9eed3cdb5d0d095f864 Mon Sep 17 00:00:00 2001 From: Alberto Gualis Date: Sat, 12 Dec 2020 12:52:33 +0100 Subject: [PATCH 04/10] Remove not used import --- src/__tests__/components/VueApollo.vue | 30 +++++++++++--------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/__tests__/components/VueApollo.vue b/src/__tests__/components/VueApollo.vue index 298d1e5c..372978d3 100644 --- a/src/__tests__/components/VueApollo.vue +++ b/src/__tests__/components/VueApollo.vue @@ -1,6 +1,6 @@