Skip to content

docs: Add example for Apollo GraphQL + composition API #192

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 11 commits into from
Dec 17, 2020
8 changes: 0 additions & 8 deletions .babelrc

This file was deleted.

14 changes: 14 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module.exports = {
sourceType: 'module',
presets: [
[
'@babel/preset-env',
{
targets: {
node: 'current',
esmodules: true,
},
},
],
],
}
34 changes: 34 additions & 0 deletions compatibility-scripts/vue-apollo-patch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// 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 useQueryPath = path.resolve(
__dirname,
'../node_modules/@vue/apollo-composable/dist/useQuery.js',
)

const vueApolloComposablePath = path.resolve(
__dirname,
'../node_modules/@vue/apollo-composable/dist/vue-apollo-composable.js',
)

fs.writeFileSync(
useQueryPath,
fs.readFileSync(useQueryPath, 'utf8').replace(/^onServerPrefetch, /mu, ''),
)

fs.writeFileSync(
useQueryPath,
fs
.readFileSync(useQueryPath, 'utf8')
.replace(/onServerPrefetch === null.*?\}\);/msu, ''),
)

fs.writeFileSync(
vueApolloComposablePath,
fs
.readFileSync(vueApolloComposablePath, 'utf8')
.replace(/vue_demi_5.onServerPrefetch === null.*?\}\);/msu, ''),
)
8 changes: 7 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,14 @@ module.exports = merge(config, {
},
snapshotSerializers: ['<rootDir>/node_modules/jest-serializer-vue'],
testPathIgnorePatterns: [
'<rootDir>/node_modules',
'<rootDir>/node_modules/',
'<rootDir>/src/__tests__/components',
'<rootDir>/src/__tests__/directives',
],
moduleNameMapper: {
'@vue/apollo-composable': [
'<rootDir>/node_modules/@vue/apollo-composable/dist/index.js',
],
},
transformIgnorePatterns: ['node_modules/(?!(@vue/apollo-composable)/)'],
})
11 changes: 6 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -52,14 +53,14 @@
"lodash.merge": "^4.6.2"
},
"devDependencies": {
"@apollo/client": "3.3.6",
"@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.12",
"@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",
Expand All @@ -81,8 +82,8 @@
"vuex": "^4.0.0-rc.2"
},
"peerDependencies": {
"vue": ">= 3",
"@vue/compiler-sfc": ">= 3"
"@vue/compiler-sfc": ">= 3",
"vue": ">= 3"
},
"husky": {
"hooks": {
Expand Down
57 changes: 25 additions & 32 deletions src/__tests__/components/VueApollo.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<template>
<div>
<div v-if="$apollo.queries.user.loading">Loading</div>
<div v-if="loading">Loading</div>

<div v-if="user">
<div>Email: {{ user.email }}</div>
<form @submit.prevent="updateUser">
Expand All @@ -15,47 +16,39 @@
</template>

<script>
import {userQuery, updateUserMutation} from './VueApollo/queries'
import {reactive, ref} from 'vue'
import {useQuery, useMutation, useResult} from '@vue/apollo-composable'
import {updateUserMutation, getUserQuery} from './VueApollo/queries'

export default {
apollo: {
user: {
query: userQuery,
variables() {
return {id: this.id}
},
},
},
props: {
id: {
type: String,
required: true,
},
},
data() {
return {
user: null,
email: '',
}
},
methods: {
async updateUser() {
const {
data: {
updateUser: {email},
},
} = await this.$apollo.mutate({
mutation: updateUserMutation,
variables: {
input: {
email: this.email,
id: this.id,
},
setup(props) {
const email = ref('')

const {result, loading, error} = useQuery(getUserQuery, {id: props.id})
const user = useResult(result, null, data => data.user)

const {mutate: updateUser} = useMutation(updateUserMutation, () => ({
variables: {
input: {
email: email.value,
id: props.id,
},
})
},
}))

this.user.email = email
},
return {
email,
user,
loading,
error,
updateUser,
}
},
}
</script>
17 changes: 8 additions & 9 deletions src/__tests__/components/VueApollo/queries.js
Original file line number Diff line number Diff line change
@@ -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
}
}
`
`
139 changes: 79 additions & 60 deletions src/__tests__/vue-apollo.js
Original file line number Diff line number Diff line change
@@ -1,75 +1,94 @@
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'
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 Component from './components/VueApollo.vue'

// // Since vue-apollo doesn't provides a MockProvider for Vue,
// // you need to use some kind of mocks for the queries.
// Since vue-apollo doesn't provide 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.
// 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.

// import {setupServer} from 'msw/node'
// import {graphql} from 'msw'
const server = setupServer(
...[
graphql.query('getUser', (req, res, ctx) => {
const {variables} = req

// import Component from './components/VueApollo.vue'
if (variables.id !== '1') {
return res(
ctx.errors([
{
message: 'User not found',
},
]),
)
}

// const apolloClient = new ApolloClient({
// uri: 'http://localhost:3020/graphql',
// cache: new InMemoryCache({
// addTypename: false,
// }),
// fetch,
// })
return res(
ctx.data({
user: {
id: 1,
email: '[email protected]',
__typename: 'User',
},
}),
)
}),

// const server = setupServer(
// ...[
// graphql.mutation('updateUser', (req, res, ctx) => {
// const {variables} = req
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: '[email protected]'}}))
// }),
// ],
// )
return res(
ctx.data({
updateUser: {
id: variables.input.id,
email: variables.input.email,
__typename: 'User',
},
}),
)
}),
],
)

// beforeAll(() => server.listen())
// afterEach(() => server.resetHandlers())
// afterAll(() => server.close())
beforeAll(() => server.listen())
afterEach(() => server.resetHandlers())
afterAll(() => server.close())

// test('mocking queries and mutations', async () => {
// render(Component, {props: {id: '1'}}, localVue => {
// localVue.use(VueApollo)
test('mocking queries and mutations', async () => {
const apolloClient = new ApolloClient({
uri: 'http://localhost:3000',
fetch,
})

// return {
// apolloProvider: new VueApollo({defaultClient: apolloClient}),
// }
// })
render(Component, {
props: {id: '1'},
global: {
provide: {
[DefaultApolloClient]: apolloClient,
},
},
})

// //Initial rendering will be in the loading state,
// expect(screen.getByText('Loading')).toBeInTheDocument()
//Initial rendering will be in the loading state,
expect(screen.getByText('Loading')).toBeInTheDocument()

// expect(
// await screen.findByText('Email: [email protected]'),
// ).toBeInTheDocument()
expect(
await screen.findByText('Email: [email protected]'),
).toBeInTheDocument()

// await fireEvent.update(
// screen.getByLabelText('Email'),
// '[email protected]',
// )
await fireEvent.update(
screen.getByLabelText('Email'),
'[email protected]',
)

// await fireEvent.click(screen.getByRole('button', {name: 'Change email'}))
await fireEvent.click(screen.getByRole('button', {name: 'Change email'}))

// expect(
// await screen.findByText('Email: [email protected]'),
// ).toBeInTheDocument()
// })
expect(
await screen.findByText('Email: [email protected]'),
).toBeInTheDocument()
})