SubscriptionHandler.spec.ts 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. // Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. import { NetworkStatus } from '@apollo/client/core'
  3. import { useSubscription } from '@vue/apollo-composable'
  4. import { createMockSubscription } from 'mock-apollo-client'
  5. import { SampleTypedSubscriptionDocument } from '#tests/fixtures/graphqlSampleTypes.ts'
  6. import type {
  7. SampleUpdatedSubscription,
  8. SampleUpdatedSubscriptionVariables,
  9. } from '#tests/fixtures/graphqlSampleTypes.ts'
  10. import createMockClient from '#tests/support/mock-apollo-client.ts'
  11. import { useNotifications } from '#shared/components/CommonNotifications/index.ts'
  12. import SubscriptionHandler from '../SubscriptionHandler.ts'
  13. import type { IMockSubscription } from 'mock-apollo-client'
  14. const subscriptionFunctionCallSpy = vi.fn()
  15. const subscriptionSampleResult = {
  16. sampleUpdated: { id: 1, title: 'Test Title', text: 'Test Text' },
  17. }
  18. const subscriptionSampleResultUpdated = {
  19. sampleUpdated: { id: 1, title: 'Test Title2', text: 'Test Text2' },
  20. }
  21. const subscriptionSampleErrorResult = {
  22. networkStatus: NetworkStatus.error,
  23. errors: [
  24. {
  25. message: 'GraphQL Error',
  26. extensions: { type: 'Exceptions::UnknownError' },
  27. },
  28. ],
  29. }
  30. let mockSubscription: IMockSubscription
  31. const mockClient = () => {
  32. mockSubscription = createMockSubscription()
  33. createMockClient([
  34. {
  35. operationDocument: SampleTypedSubscriptionDocument,
  36. handler: () => mockSubscription,
  37. },
  38. ])
  39. subscriptionFunctionCallSpy.mockClear()
  40. }
  41. describe('SubscriptionHandler', () => {
  42. const sampleSubscription = (
  43. variables: SampleUpdatedSubscriptionVariables,
  44. options = {},
  45. ) => {
  46. subscriptionFunctionCallSpy()
  47. return useSubscription<
  48. SampleUpdatedSubscription,
  49. SampleUpdatedSubscriptionVariables
  50. >(SampleTypedSubscriptionDocument, variables, options)
  51. }
  52. describe('constructor', () => {
  53. beforeEach(() => {
  54. mockClient()
  55. })
  56. it('instance can be created', () => {
  57. const subscriptionHandlerObject = new SubscriptionHandler(
  58. sampleSubscription({ id: 1 }),
  59. )
  60. expect(subscriptionHandlerObject).toBeInstanceOf(SubscriptionHandler)
  61. })
  62. it('default handler options can be changed', () => {
  63. const errorNotificationMessage = 'A test message.'
  64. const subscriptionHandlerObject = new SubscriptionHandler(
  65. sampleSubscription({ id: 1 }),
  66. {
  67. errorNotificationMessage,
  68. },
  69. )
  70. expect(
  71. subscriptionHandlerObject.handlerOptions.errorNotificationMessage,
  72. ).toBe(errorNotificationMessage)
  73. })
  74. it('given subscription function was executed', () => {
  75. const subscriptionHandlerObject = new SubscriptionHandler(
  76. sampleSubscription({ id: 1 }),
  77. )
  78. expect(subscriptionFunctionCallSpy).toBeCalled()
  79. expect(subscriptionHandlerObject.operationResult).toBeTruthy()
  80. })
  81. })
  82. describe('loading', () => {
  83. beforeEach(() => {
  84. mockClient()
  85. })
  86. it('loading state will be updated', async () => {
  87. expect.assertions(2)
  88. const subscriptionHandlerObject = new SubscriptionHandler(
  89. sampleSubscription({ id: 1 }),
  90. )
  91. expect(subscriptionHandlerObject.loading().value).toBe(true)
  92. const subscribed = subscriptionHandlerObject.onSubscribed()
  93. mockSubscription.next({
  94. data: subscriptionSampleResult,
  95. })
  96. await subscribed
  97. expect(subscriptionHandlerObject.loading().value).toBe(false)
  98. })
  99. })
  100. describe('result/subscribe', () => {
  101. beforeEach(() => {
  102. mockClient()
  103. })
  104. it('subscribed', async () => {
  105. expect.assertions(1)
  106. const subscriptionHandlerObject = new SubscriptionHandler(
  107. sampleSubscription({ id: 1 }),
  108. )
  109. const subscribed = subscriptionHandlerObject.onSubscribed()
  110. mockSubscription.next({
  111. data: subscriptionSampleResult,
  112. })
  113. const result = await subscribed
  114. expect(result).toEqual(subscriptionSampleResult)
  115. })
  116. it('watch on result change', async () => {
  117. expect.assertions(2)
  118. const subscriptionHandlerObject = new SubscriptionHandler(
  119. sampleSubscription({ id: 1 }),
  120. )
  121. const subscribed = subscriptionHandlerObject.onSubscribed()
  122. mockSubscription.next({
  123. data: subscriptionSampleResult,
  124. })
  125. await subscribed
  126. let watchCount = 0
  127. subscriptionHandlerObject.watchOnResult((result) => {
  128. expect(result).toEqual(
  129. watchCount === 0
  130. ? subscriptionSampleResult
  131. : subscriptionSampleResultUpdated,
  132. )
  133. watchCount += 1
  134. })
  135. mockSubscription.next({
  136. data: subscriptionSampleResultUpdated,
  137. })
  138. })
  139. it('register onResult callback', async () => {
  140. expect.assertions(1)
  141. const subscriptionHandlerObject = new SubscriptionHandler(
  142. sampleSubscription({ id: 1 }),
  143. )
  144. const resultCallbackSpy = vi.fn()
  145. const subscribed = subscriptionHandlerObject.onSubscribed()
  146. mockSubscription.next({
  147. data: subscriptionSampleResult,
  148. })
  149. await subscribed
  150. subscriptionHandlerObject.onResult((result) => {
  151. resultCallbackSpy(result)
  152. })
  153. mockSubscription.next({
  154. data: subscriptionSampleResultUpdated,
  155. })
  156. expect(resultCallbackSpy).toHaveBeenCalledWith({
  157. data: subscriptionSampleResultUpdated,
  158. })
  159. })
  160. })
  161. describe('error handling', () => {
  162. describe('GraphQL errors', () => {
  163. beforeEach(() => {
  164. mockClient()
  165. })
  166. it('notification is triggerd', () => {
  167. const subscriptionHandlerObject = new SubscriptionHandler(
  168. sampleSubscription({ id: 1 }),
  169. )
  170. mockSubscription.next(subscriptionSampleErrorResult)
  171. expect(subscriptionHandlerObject.operationError().value).toBeTruthy()
  172. const { notifications } = useNotifications()
  173. expect(notifications.value.length).toBe(1)
  174. })
  175. it('use error callback', () => {
  176. const errorCallbackSpy = vi.fn()
  177. const subscriptionHandlerObject = new SubscriptionHandler(
  178. sampleSubscription({ id: 1 }),
  179. {
  180. errorCallback: (error) => {
  181. errorCallbackSpy(error)
  182. },
  183. },
  184. )
  185. mockSubscription.next(subscriptionSampleErrorResult)
  186. expect(subscriptionHandlerObject.operationError().value).toBeTruthy()
  187. expect(errorCallbackSpy).toHaveBeenCalledWith({
  188. type: 'Exceptions::UnknownError',
  189. message: 'GraphQL Error',
  190. })
  191. })
  192. })
  193. })
  194. describe('use operation result wrapper', () => {
  195. beforeEach(() => {
  196. mockClient()
  197. })
  198. it('use returned query options', () => {
  199. const subscriptionHandlerObject = new SubscriptionHandler(
  200. sampleSubscription({ id: 1 }),
  201. )
  202. expect(subscriptionHandlerObject.options()).toBeTruthy()
  203. })
  204. })
  205. })