1// @vitest-environment jsdom
2
3import { OperationResult, OperationResultSource } from '@urql/core';
4import { nextTick, readonly, ref } from 'vue';
5import { vi, expect, it, describe } from 'vitest';
6
7vi.mock('./useClient.ts', async () => ({
8 __esModule: true,
9 ...(await vi.importActual<typeof import('./useClient')>('./useClient.ts')),
10 useClient: () => ref(client),
11}));
12
13import { makeSubject } from 'wonka';
14import { createClient } from '@urql/core';
15import { useSubscription } from './useSubscription';
16
17const client = createClient({ url: '/graphql', exchanges: [] });
18
19describe('useSubscription', () => {
20 it('subscribes to a subscription and updates data', async () => {
21 const subject = makeSubject<any>();
22 const executeQuery = vi
23 .spyOn(client, 'executeSubscription')
24 .mockImplementation(
25 () => subject.source as OperationResultSource<OperationResult>
26 );
27
28 const sub = useSubscription({
29 query: `{ test }`,
30 });
31
32 expect(readonly(sub)).toMatchObject({
33 data: undefined,
34 stale: false,
35 fetching: true,
36 error: undefined,
37 extensions: undefined,
38 operation: undefined,
39 isPaused: false,
40 pause: expect.any(Function),
41 resume: expect.any(Function),
42 executeSubscription: expect.any(Function),
43 });
44
45 expect(executeQuery).toHaveBeenCalledWith(
46 {
47 key: expect.any(Number),
48 query: expect.any(Object),
49 variables: {},
50 },
51 expect.any(Object)
52 );
53
54 expect(sub.fetching.value).toBe(true);
55
56 subject.next({ data: { test: true } });
57 expect(sub.data.value).toHaveProperty('test', true);
58
59 subject.complete();
60 expect(sub.fetching.value).toBe(false);
61 });
62
63 it('updates the executed subscription when inputs change', async () => {
64 const subject = makeSubject<any>();
65 const executeSubscription = vi
66 .spyOn(client, 'executeSubscription')
67 .mockImplementation(
68 () => subject.source as OperationResultSource<OperationResult>
69 );
70
71 const variables = ref({});
72 const sub = useSubscription({
73 query: `{ test }`,
74 variables,
75 });
76
77 expect(executeSubscription).toHaveBeenCalledWith(
78 {
79 key: expect.any(Number),
80 query: expect.any(Object),
81 variables: {},
82 },
83 expect.any(Object)
84 );
85
86 subject.next({ data: { test: true } });
87 expect(sub.data.value).toHaveProperty('test', true);
88
89 variables.value = { test: true };
90 await nextTick();
91 expect(executeSubscription).toHaveBeenCalledTimes(2);
92 expect(executeSubscription).toHaveBeenCalledWith(
93 {
94 key: expect.any(Number),
95 query: expect.any(Object),
96 variables: { test: true },
97 },
98 expect.any(Object)
99 );
100
101 expect(sub.fetching.value).toBe(true);
102 expect(sub.data.value).toHaveProperty('test', true);
103 });
104
105 it('supports a custom scanning handler', async () => {
106 const subject = makeSubject<any>();
107 const executeSubscription = vi
108 .spyOn(client, 'executeSubscription')
109 .mockImplementation(
110 () => subject.source as OperationResultSource<OperationResult>
111 );
112
113 const scanHandler = (currentState: any, nextState: any) => ({
114 counter: (currentState ? currentState.counter : 0) + nextState.counter,
115 });
116
117 const sub = useSubscription(
118 {
119 query: `subscription { counter }`,
120 },
121 scanHandler
122 );
123
124 expect(executeSubscription).toHaveBeenCalledWith(
125 {
126 key: expect.any(Number),
127 query: expect.any(Object),
128 variables: {},
129 },
130 expect.any(Object)
131 );
132
133 subject.next({ data: { counter: 1 } });
134 expect(sub.data.value).toHaveProperty('counter', 1);
135
136 subject.next({ data: { counter: 2 } });
137 expect(sub.data.value).toHaveProperty('counter', 3);
138 });
139});