index.test.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. 'use strict'
  2. const tap = require('tap')
  3. const messageTrackerFactory = require('../../../../lib/client/message-tracker/')
  4. tap.test('options', t => {
  5. t.test('requires an options object', async t => {
  6. try {
  7. messageTrackerFactory()
  8. } catch (error) {
  9. t.match(error, /options object is required/)
  10. }
  11. try {
  12. messageTrackerFactory([])
  13. } catch (error) {
  14. t.match(error, /options object is required/)
  15. }
  16. try {
  17. messageTrackerFactory('')
  18. } catch (error) {
  19. t.match(error, /options object is required/)
  20. }
  21. try {
  22. messageTrackerFactory(42)
  23. } catch (error) {
  24. t.match(error, /options object is required/)
  25. }
  26. })
  27. t.test('requires id to be a string', async t => {
  28. try {
  29. messageTrackerFactory({ id: {} })
  30. } catch (error) {
  31. t.match(error, /options\.id string is required/)
  32. }
  33. try {
  34. messageTrackerFactory({ id: [] })
  35. } catch (error) {
  36. t.match(error, /options\.id string is required/)
  37. }
  38. try {
  39. messageTrackerFactory({ id: 42 })
  40. } catch (error) {
  41. t.match(error, /options\.id string is required/)
  42. }
  43. })
  44. t.test('requires parser to be an object', async t => {
  45. try {
  46. messageTrackerFactory({ id: 'foo', parser: 'bar' })
  47. } catch (error) {
  48. t.match(error, /options\.parser object is required/)
  49. }
  50. try {
  51. messageTrackerFactory({ id: 'foo', parser: 42 })
  52. } catch (error) {
  53. t.match(error, /options\.parser object is required/)
  54. }
  55. try {
  56. messageTrackerFactory({ id: 'foo', parser: [] })
  57. } catch (error) {
  58. t.match(error, /options\.parser object is required/)
  59. }
  60. })
  61. t.end()
  62. })
  63. tap.test('.pending', t => {
  64. t.test('returns 0 for no messages', async t => {
  65. const tracker = messageTrackerFactory({ id: 'foo', parser: {} })
  66. t.equal(tracker.pending, 0)
  67. })
  68. t.test('returns 1 for 1 message', async t => {
  69. const tracker = messageTrackerFactory({ id: 'foo', parser: {} })
  70. tracker.track({}, () => {})
  71. t.equal(tracker.pending, 1)
  72. })
  73. t.end()
  74. })
  75. tap.test('#abandon', t => {
  76. t.test('returns false if message does not exist', async t => {
  77. const tracker = messageTrackerFactory({ id: 'foo', parser: {} })
  78. const result = tracker.abandon(1)
  79. t.equal(result, false)
  80. })
  81. t.test('returns true if message is abandoned', async t => {
  82. const tracker = messageTrackerFactory({ id: 'foo', parser: {} })
  83. tracker.track({}, {})
  84. const result = tracker.abandon(1)
  85. t.equal(result, true)
  86. })
  87. t.end()
  88. })
  89. tap.test('#fetch', t => {
  90. t.test('returns handler for fetched message', async t => {
  91. const tracker = messageTrackerFactory({ id: 'foo', parser: {} })
  92. tracker.track({}, handler)
  93. const { callback: fetched } = tracker.fetch(1)
  94. t.equal(fetched, handler)
  95. function handler () {}
  96. })
  97. t.test('returns handler for fetched abandoned message', async t => {
  98. const tracker = messageTrackerFactory({ id: 'foo', parser: {} })
  99. tracker.track({}, handler)
  100. tracker.track({ abandon: 'message' }, () => {})
  101. tracker.abandon(1)
  102. const { callback: fetched } = tracker.fetch(1)
  103. t.equal(fetched, handler)
  104. function handler () {}
  105. })
  106. t.test('returns null when message does not exist', async t => {
  107. const tracker = messageTrackerFactory({ id: 'foo', parser: {} })
  108. const fetched = tracker.fetch(1)
  109. t.equal(fetched, null)
  110. })
  111. t.end()
  112. })
  113. tap.test('#purge', t => {
  114. t.test('invokes cb for each tracked message', async t => {
  115. t.plan(4)
  116. let count = 0
  117. const tracker = messageTrackerFactory({ id: 'foo', parser: {} })
  118. tracker.track({}, handler1)
  119. tracker.track({}, handler2)
  120. tracker.purge(cb)
  121. function cb (msgID, handler) {
  122. if (count === 0) {
  123. t.equal(msgID, 1)
  124. t.equal(handler, handler1)
  125. count += 1
  126. return
  127. }
  128. t.equal(msgID, 2)
  129. t.equal(handler, handler2)
  130. }
  131. function handler1 () {}
  132. function handler2 () {}
  133. })
  134. t.end()
  135. })
  136. tap.test('#remove', t => {
  137. t.test('removes from the current track', async t => {
  138. const tracker = messageTrackerFactory({ id: 'foo', parser: {} })
  139. tracker.track({}, () => {})
  140. tracker.remove(1)
  141. t.equal(tracker.pending, 0)
  142. })
  143. // Not a great test. It exercises the desired code path, but we probably
  144. // should expose some insight into the abandoned track.
  145. t.test('removes from the abandoned track', async t => {
  146. const tracker = messageTrackerFactory({ id: 'foo', parser: {} })
  147. tracker.track({}, () => {})
  148. tracker.track({ abandon: 'message' }, () => {})
  149. tracker.abandon(1)
  150. tracker.remove(1)
  151. t.equal(tracker.pending, 1)
  152. })
  153. t.end()
  154. })
  155. tap.test('#track', t => {
  156. t.test('add messageId and tracks message', async t => {
  157. const tracker = messageTrackerFactory({ id: 'foo', parser: {} })
  158. const msg = {}
  159. tracker.track(msg, handler)
  160. t.same(msg, { messageId: 1 })
  161. const { callback: cb } = tracker.fetch(1)
  162. t.equal(cb, handler)
  163. function handler () {}
  164. })
  165. t.end()
  166. })