Skip to content

Commit 01d4cb7

Browse files
committed
docs: Add example for Apollo GraphQL + composition API
1 parent f4ac8d7 commit 01d4cb7

File tree

5 files changed

+177
-120
lines changed

5 files changed

+177
-120
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// This patch is run from post-install script and it is a temporary hack until a pending PR is merged
2+
// More details here:
3+
// https://github.com/vuejs/vue-apollo/issues/1011
4+
5+
const fs = require('fs')
6+
const path = require('path')
7+
8+
const loadTrackingPath = path.resolve(
9+
__dirname,
10+
'../node_modules/@vue/apollo-composable/dist/util/loadingTracking.js'
11+
)
12+
13+
fs.writeFileSync(
14+
loadTrackingPath,
15+
fs.readFileSync(loadTrackingPath, 'utf8').replace(/\.\$root/m, '.root')
16+
)
17+
18+
const useQueryPath = path.resolve(
19+
__dirname,
20+
'../node_modules/@vue/apollo-composable/dist/useQuery.js'
21+
)
22+
23+
fs.writeFileSync(
24+
useQueryPath,
25+
fs
26+
.readFileSync(useQueryPath, 'utf8')
27+
.replace(/(^.*onServerPrefetch)/m, '$1=()=>{}; $1')
28+
.replace(/(.* require\("vue"\);)/m, '')
29+
.replace(/^.*(nextTick)/m, 'vue_demi_1.$1')
30+
)

package.json

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
"test": "kcd-scripts test",
1212
"test:update": "npm test -- --updateSnapshot --coverage",
1313
"validate": "kcd-scripts validate",
14-
"setup": "npm install && npm run validate -s"
14+
"setup": "npm install && npm run validate -s",
15+
"postinstall": "node compatibility-scripts/vue-apollo-patch.js"
1516
},
1617
"engines": {
1718
"node": ">10.18"
@@ -52,14 +53,15 @@
5253
"lodash.merge": "^4.6.2"
5354
},
5455
"devDependencies": {
56+
"@apollo/client": "3.2.3",
5557
"@babel/plugin-transform-runtime": "^7.12.1",
5658
"@testing-library/jest-dom": "^5.11.5",
5759
"@testing-library/user-event": "^12.4.0",
5860
"@types/estree": "0.0.45",
61+
"@vue/apollo-composable": "4.0.0-alpha.10",
5962
"@vue/compiler-sfc": "^3.0.4",
6063
"apollo-boost": "^0.4.9",
6164
"apollo-cache-inmemory": "^1.6.6",
62-
"apollo-client": "^2.6.10",
6365
"axios": "^0.20.0",
6466
"dtslint": "^4.0.6",
6567
"element-plus": "^1.0.1-beta.7",
@@ -81,8 +83,8 @@
8183
"vuex": "^4.0.0-rc.2"
8284
},
8385
"peerDependencies": {
84-
"vue": ">= 3",
85-
"@vue/compiler-sfc": ">= 3"
86+
"@vue/compiler-sfc": ">= 3",
87+
"vue": ">= 3"
8688
},
8789
"husky": {
8890
"hooks": {
Lines changed: 29 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<template>
22
<div>
3-
<div v-if="$apollo.queries.user.loading">Loading</div>
3+
<div v-if="loading">Loading</div>
4+
45
<div v-if="user">
56
<div>Email: {{ user.email }}</div>
67
<form @submit.prevent="updateUser">
@@ -15,47 +16,43 @@
1516
</template>
1617

1718
<script>
18-
import {userQuery, updateUserMutation} from './VueApollo/queries'
19+
import { reactive, ref } from 'vue'
20+
import { useQuery, useMutation, useResult } from "@vue/apollo-composable";
21+
import {updateUserMutation, getUserQuery} from './VueApollo/queries'
22+
import {gql} from 'apollo-boost'
23+
1924
2025
export default {
21-
apollo: {
22-
user: {
23-
query: userQuery,
24-
variables() {
25-
return {id: this.id}
26-
},
27-
},
28-
},
2926
props: {
3027
id: {
3128
type: String,
3229
required: true,
3330
},
3431
},
35-
data() {
32+
setup(props) {
33+
const email = ref('')
34+
35+
const { result, loading, error } = useQuery(getUserQuery, {id: props.id})
36+
const user = useResult(result, null, data => data.user)
37+
38+
const {mutate: updateUser} = useMutation(updateUserMutation,
39+
()=> ({variables:
40+
{
41+
input: {
42+
email: email.value,
43+
id: props.id,
44+
},
45+
}
46+
})
47+
)
48+
3649
return {
37-
user: null,
38-
email: '',
50+
email,
51+
user,
52+
loading,
53+
error,
54+
updateUser,
3955
}
4056
},
41-
methods: {
42-
async updateUser() {
43-
const {
44-
data: {
45-
updateUser: {email},
46-
},
47-
} = await this.$apollo.mutate({
48-
mutation: updateUserMutation,
49-
variables: {
50-
input: {
51-
email: this.email,
52-
id: this.id,
53-
},
54-
},
55-
})
56-
57-
this.user.email = email
58-
},
59-
},
6057
}
6158
</script>
Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
1-
import gql from 'graphql-tag'
1+
import {gql} from 'apollo-boost'
22

3-
export const updateUserMutation = gql`
4-
mutation updateUser($data: UpdateUserInput) {
5-
updateUser(input: $data) {
3+
export const getUserQuery = gql`
4+
query getUser($id: String!) {
5+
user(id: $id) {
66
id
77
email
88
}
99
}
1010
`
11-
12-
export const userQuery = gql`
13-
query User($id: String!) {
14-
user(id: $id) {
11+
export const updateUserMutation = gql`
12+
mutation updateUser($data: UpdateUserInput) {
13+
updateUser(input: $data) {
1514
id
1615
email
1716
}
1817
}
19-
`
18+
`

src/__tests__/vue-apollo.js

Lines changed: 104 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,104 @@
1-
test.todo('Your test suite must contain at least one test.')
2-
// import '@testing-library/jest-dom'
3-
// import fetch from 'isomorphic-unfetch'
4-
// import {render, fireEvent, screen} from '..'
5-
// import VueApollo from 'vue-apollo'
6-
// import {InMemoryCache} from 'apollo-cache-inmemory'
7-
// import ApolloClient from 'apollo-boost'
8-
9-
// // Since vue-apollo doesn't provides a MockProvider for Vue,
10-
// // you need to use some kind of mocks for the queries.
11-
12-
// // We recommend using Mock Service Worker library to declaratively mock API communication
13-
// // in your tests instead of stubbing window.fetch, or relying on third-party adapters.
14-
15-
// import {setupServer} from 'msw/node'
16-
// import {graphql} from 'msw'
17-
18-
// import Component from './components/VueApollo.vue'
19-
20-
// const apolloClient = new ApolloClient({
21-
// uri: 'http://localhost:3020/graphql',
22-
// cache: new InMemoryCache({
23-
// addTypename: false,
24-
// }),
25-
// fetch,
26-
// })
27-
28-
// const server = setupServer(
29-
// ...[
30-
// graphql.mutation('updateUser', (req, res, ctx) => {
31-
// const {variables} = req
32-
33-
// return res(
34-
// ctx.data({
35-
// updateUser: {id: variables.input.id, email: variables.input.email},
36-
// }),
37-
// )
38-
// }),
39-
// graphql.query('User', (req, res, ctx) => {
40-
// return res(ctx.data({user: {id: '1', email: 'alice@example.com'}}))
41-
// }),
42-
// ],
43-
// )
44-
45-
// beforeAll(() => server.listen())
46-
// afterEach(() => server.resetHandlers())
47-
// afterAll(() => server.close())
48-
49-
// test('mocking queries and mutations', async () => {
50-
// render(Component, {props: {id: '1'}}, localVue => {
51-
// localVue.use(VueApollo)
52-
53-
// return {
54-
// apolloProvider: new VueApollo({defaultClient: apolloClient}),
55-
// }
56-
// })
57-
58-
// //Initial rendering will be in the loading state,
59-
// expect(screen.getByText('Loading')).toBeInTheDocument()
60-
61-
// expect(
62-
// await screen.findByText('Email: alice@example.com'),
63-
// ).toBeInTheDocument()
64-
65-
// await fireEvent.update(
66-
// screen.getByLabelText('Email'),
67-
// 'alice+new@example.com',
68-
// )
69-
70-
// await fireEvent.click(screen.getByRole('button', {name: 'Change email'}))
71-
72-
// expect(
73-
// await screen.findByText('Email: alice+new@example.com'),
74-
// ).toBeInTheDocument()
75-
// })
1+
import '@testing-library/jest-dom'
2+
import fetch from 'isomorphic-unfetch'
3+
import {render, fireEvent, screen} from '..'
4+
import { DefaultApolloClient } from '@vue/apollo-composable'
5+
import ApolloClient from 'apollo-boost'
6+
import {setupServer} from 'msw/node'
7+
import {graphql} from 'msw'
8+
import { provide, h } from 'vue'
9+
import Component from './components/VueApollo.vue'
10+
11+
// Since vue-apollo doesn't provide a MockProvider for Vue,
12+
// you need to use some kind of mocks for the queries.
13+
14+
// We are using Mock Service Worker (aka MSW) library to declaratively mock API communication
15+
// in your tests instead of stubbing window.fetch, or relying on third-party adapters.
16+
17+
const server = setupServer(
18+
...[
19+
graphql.query('getUser', (req, res, ctx) => {
20+
const {variables} = req
21+
22+
if (variables.id !== '1') {
23+
return res(
24+
ctx.errors([
25+
{
26+
message: 'User not found',
27+
},
28+
]),
29+
)
30+
}
31+
32+
return res(
33+
ctx.data({
34+
user:
35+
{
36+
id: 1,
37+
email: 'alice@example.com',
38+
__typename: 'User'
39+
},
40+
}),
41+
)
42+
}),
43+
44+
graphql.mutation('updateUser', (req, res, ctx) => {
45+
const {variables} = req
46+
47+
return res(
48+
ctx.data({
49+
updateUser: {
50+
id: variables.input.id,
51+
email: variables.input.email,
52+
__typename: 'User'
53+
},
54+
}),
55+
)
56+
}),
57+
58+
],
59+
)
60+
61+
beforeAll(() => server.listen())
62+
afterEach(() => server.resetHandlers())
63+
afterAll(() => server.close())
64+
65+
const apolloClient = new ApolloClient({
66+
uri: "http://localhost:3000",
67+
fetch,
68+
})
69+
70+
const ComponentWithInjectedApollo = {
71+
// It would be preferable to use global.provide when we pass options to VTU options
72+
// to testing library render function but that option is not yet supported by VTU
73+
setup () {
74+
provide(DefaultApolloClient, apolloClient)
75+
},
76+
render() {
77+
return h(Component)
78+
}
79+
}
80+
81+
test('mocking queries and mutations', async () => {
82+
83+
render(ComponentWithInjectedApollo, {
84+
props: {id: '1'}
85+
})
86+
87+
//Initial rendering will be in the loading state,
88+
expect(screen.getByText('Loading')).toBeInTheDocument()
89+
90+
expect(
91+
await screen.findByText('Email: alice@example.com')
92+
).toBeInTheDocument()
93+
94+
await fireEvent.update(
95+
screen.getByLabelText('Email'),
96+
'alice+new@example.com',
97+
)
98+
99+
await fireEvent.click(screen.getByRole('button', {name: 'Change email'}))
100+
101+
expect(
102+
await screen.findByText('Email: alice+new@example.com'),
103+
).toBeInTheDocument()
104+
})

0 commit comments

Comments
 (0)