test: useSubscription

This commit is contained in:
Guillaume Chau
2024-03-19 16:59:06 +01:00
parent 89a0240f0b
commit 0f5ae610c5
7 changed files with 159 additions and 40 deletions
@@ -20,6 +20,7 @@
"@vue/apollo-util": "workspace:*",
"graphql": "^16.7.1",
"graphql-tag": "^2.12.6",
"graphql-ws": "^5.15.0",
"pinia": "^2.1.6",
"test-server": "workspace:*",
"vue": "^3.3.4",
@@ -1,6 +1,9 @@
import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client/core'
import { ApolloClient, InMemoryCache, createHttpLink, split } from '@apollo/client/core'
import { onError } from '@apollo/client/link/error'
import { getMainDefinition } from '@apollo/client/utilities'
import { GraphQLWsLink } from '@apollo/client/link/subscriptions'
import { logErrorMessages } from '@vue/apollo-util'
import { createClient } from 'graphql-ws'
const cache = new InMemoryCache()
@@ -10,6 +13,26 @@ const httpLink = createHttpLink({
uri: 'http://localhost:4042/graphql',
})
const wsLink = new GraphQLWsLink(createClient({
url: 'ws://localhost:4042/graphql',
}))
const splitLink = split(
({ query }) => {
const definition = getMainDefinition(query)
if (definition.kind === 'OperationDefinition' &&
definition.operation === 'subscription') {
console.log(`Subscribing to ${definition.name?.value ?? 'anonymous'}`)
}
return (
definition.kind === 'OperationDefinition' &&
definition.operation === 'subscription'
)
},
wsLink,
httpLink,
)
// Handle errors
const errorLink = onError(error => {
logErrorMessages(error)
@@ -17,5 +40,5 @@ const errorLink = onError(error => {
export const apolloClient = new ApolloClient({
cache,
link: errorLink.concat(httpLink),
link: errorLink.concat(splitLink),
})
@@ -0,0 +1,37 @@
<script lang="ts" setup>
import { useSubscription } from '@vue/apollo-composable'
import gql from 'graphql-tag'
import { ref } from 'vue'
const messages = ref<Array<{ id: string, text: string }>>([])
const { onResult } = useSubscription(gql`subscription OnMessageAdded {
messageAdded(channelId: "general") {
id
text
}
}`)
onResult((result) => {
console.log(result.data?.messageAdded)
if (result.data?.messageAdded) {
messages.value.push(result.data.messageAdded)
}
})
</script>
<template>
<div class="space-y-2 p-2 border border-gray-200 rounded-xl">
<div
v-for="message in messages"
:key="message.id"
class="message px-4 py-2 bg-white rounded-lg"
>
{{ message.text }}
</div>
<div v-if="!messages.length">
No messages yet
</div>
</div>
</template>
@@ -0,0 +1,20 @@
<script lang="ts" setup>
import MessageForm from './MessageForm.vue'
import Subscription from './Subscription.vue'
</script>
<template>
<div class="m-12 space-y-4">
<h1 class="text-2xl">
Subscription
</h1>
<MessageForm channel-id="general" />
<div class="flex gap-4">
<Subscription
v-for="n in 3"
:key="n"
class="flex-1"
/>
</div>
</div>
</template>
@@ -79,5 +79,12 @@ export const router = createRouter({
layout: 'blank',
},
},
{
path: '/subscriptions',
component: () => import('./components/Subscriptions.vue'),
meta: {
layout: 'blank',
},
},
],
})
@@ -0,0 +1,16 @@
describe('Subscription', () => {
beforeEach(() => {
cy.task('db:reset')
cy.visit('/')
})
it('receive messages in real time', () => {
cy.visit('/subscriptions')
cy.get('input').type('Meow{enter}')
cy.get('.message').should('have.length', 3)
cy.get('.message').should('contain', 'Meow')
cy.get('input').type('Waf{enter}')
cy.get('.message').should('have.length', 6)
cy.get('.message').should('contain', 'Waf')
})
})
+53 -38
View File
@@ -177,7 +177,7 @@ importers:
dependencies:
'@apollo/client':
specifier: ^3.7.16
version: 3.7.16(graphql@16.7.1)
version: 3.7.16(graphql-ws@5.15.0)(graphql@16.7.1)
'@vue/apollo-composable':
specifier: workspace:*
version: link:../vue-apollo-composable
@@ -190,6 +190,9 @@ importers:
graphql-tag:
specifier: ^2.12.6
version: 2.12.6(graphql@16.7.1)
graphql-ws:
specifier: ^5.15.0
version: 5.15.0(graphql@16.7.1)
pinia:
specifier: ^2.1.6
version: 2.1.6(typescript@5.0.2)(vue@3.3.4)
@@ -241,7 +244,7 @@ importers:
dependencies:
'@apollo/client':
specifier: ^3.7.16
version: 3.7.16(graphql@16.7.1)
version: 3.7.16(graphql-ws@5.15.0)(graphql@16.7.1)
'@vue/apollo-composable':
specifier: workspace:*
version: link:../vue-apollo-composable
@@ -455,7 +458,7 @@ importers:
devDependencies:
'@apollo/client':
specifier: ^3.7.16
version: 3.7.16(graphql@16.7.1)
version: 3.7.16(graphql-ws@5.15.0)(graphql@16.7.1)
'@types/throttle-debounce':
specifier: ^5.0.0
version: 5.0.0
@@ -763,6 +766,42 @@ packages:
graphql: 16.6.0
dev: false
/@apollo/client@3.7.16(graphql-ws@5.15.0)(graphql@16.7.1):
resolution: {integrity: sha512-rdhoc7baSD7ZzcjavEpYN8gZJle1KhjEKj4SJeMgBpcnO4as7oXUVU4LtFpotzZdFlo57qaLrNzfvppSTsKvZQ==}
peerDependencies:
graphql: ^14.0.0 || ^15.0.0 || ^16.0.0
graphql-ws: ^5.5.5
react: ^16.8.0 || ^17.0.0 || ^18.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
subscriptions-transport-ws: ^0.9
peerDependenciesMeta:
graphql:
optional: true
graphql-ws:
optional: true
react:
optional: true
react-dom:
optional: true
subscriptions-transport-ws:
optional: true
dependencies:
'@graphql-typed-document-node/core': 3.1.1(graphql@16.7.1)
'@wry/context': 0.7.0
'@wry/equality': 0.5.3
'@wry/trie': 0.4.3
graphql: 16.7.1
graphql-tag: 2.12.6(graphql@16.7.1)
graphql-ws: 5.15.0(graphql@16.7.1)
hoist-non-react-statics: 3.3.2
optimism: 0.16.2
prop-types: 15.8.1
response-iterator: 0.2.6
symbol-observable: 4.0.0
ts-invariant: 0.10.3
tslib: 2.5.0
zen-observable-ts: 1.2.5
/@apollo/client@3.7.16(graphql@15.8.0)(subscriptions-transport-ws@0.9.19):
resolution: {integrity: sha512-rdhoc7baSD7ZzcjavEpYN8gZJle1KhjEKj4SJeMgBpcnO4as7oXUVU4LtFpotzZdFlo57qaLrNzfvppSTsKvZQ==}
peerDependencies:
@@ -799,41 +838,6 @@ packages:
tslib: 2.5.0
zen-observable-ts: 1.2.5
/@apollo/client@3.7.16(graphql@16.7.1):
resolution: {integrity: sha512-rdhoc7baSD7ZzcjavEpYN8gZJle1KhjEKj4SJeMgBpcnO4as7oXUVU4LtFpotzZdFlo57qaLrNzfvppSTsKvZQ==}
peerDependencies:
graphql: ^14.0.0 || ^15.0.0 || ^16.0.0
graphql-ws: ^5.5.5
react: ^16.8.0 || ^17.0.0 || ^18.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
subscriptions-transport-ws: ^0.9
peerDependenciesMeta:
graphql:
optional: true
graphql-ws:
optional: true
react:
optional: true
react-dom:
optional: true
subscriptions-transport-ws:
optional: true
dependencies:
'@graphql-typed-document-node/core': 3.1.1(graphql@16.7.1)
'@wry/context': 0.7.0
'@wry/equality': 0.5.3
'@wry/trie': 0.4.3
graphql: 16.7.1
graphql-tag: 2.12.6(graphql@16.7.1)
hoist-non-react-statics: 3.3.2
optimism: 0.16.2
prop-types: 15.8.1
response-iterator: 0.2.6
symbol-observable: 4.0.0
ts-invariant: 0.10.3
tslib: 2.5.0
zen-observable-ts: 1.2.5
/@apollo/client@3.7.9(graphql@15.8.0):
resolution: {integrity: sha512-YnJvrJOVWrp4y/zdNvUaM8q4GuSHCEIecsRDTJhK/veT33P/B7lfqGJ24NeLdKMj8tDEuXYF7V0t+th4+rgC+Q==}
peerDependencies:
@@ -10414,6 +10418,17 @@ packages:
graphql: 16.6.0
dev: false
/graphql-ws@5.15.0(graphql@16.7.1):
resolution: {integrity: sha512-xWGAtm3fig9TIhSaNsg0FaDZ8Pyn/3re3RFlP4rhQcmjRDIPpk1EhRuNB+YSJtLzttyuToaDiNhwT1OMoGnJnw==}
engines: {node: '>=10'}
peerDependencies:
graphql: '>=0.11 <=16'
peerDependenciesMeta:
graphql:
optional: true
dependencies:
graphql: 16.7.1
/graphql@15.8.0:
resolution: {integrity: sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw==}
engines: {node: '>= 10.x'}