AnalyticsController.test.mjs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. import { vi } from 'vitest'
  2. import sinon from 'sinon'
  3. import MockResponse from '../helpers/MockResponse.js'
  4. const modulePath = new URL(
  5. '../../../../app/src/Features/Analytics/AnalyticsController.mjs',
  6. import.meta.url
  7. ).pathname
  8. describe('AnalyticsController', function () {
  9. beforeEach(async function (ctx) {
  10. ctx.SessionManager = { getLoggedInUserId: sinon.stub() }
  11. ctx.AnalyticsManager = {
  12. updateEditingSession: sinon.stub(),
  13. recordEventForSession: sinon.stub(),
  14. }
  15. ctx.Features = {
  16. hasFeature: sinon.stub().returns(true),
  17. }
  18. vi.doMock(
  19. '../../../../app/src/Features/Analytics/AnalyticsManager.js',
  20. () => ({
  21. default: ctx.AnalyticsManager,
  22. })
  23. )
  24. vi.doMock(
  25. '../../../../app/src/Features/Authentication/SessionManager.js',
  26. () => ({
  27. default: ctx.SessionManager,
  28. })
  29. )
  30. vi.doMock('../../../../app/src/infrastructure/Features.js', () => ({
  31. default: ctx.Features,
  32. }))
  33. vi.doMock('../../../../app/src/infrastructure/GeoIpLookup.js', () => ({
  34. default: (ctx.GeoIpLookup = {
  35. promises: {
  36. getDetails: sinon.stub().resolves(),
  37. },
  38. }),
  39. }))
  40. ctx.controller = (await import(modulePath)).default
  41. ctx.res = new MockResponse()
  42. })
  43. describe('updateEditingSession', function () {
  44. beforeEach(function (ctx) {
  45. ctx.req = {
  46. params: {
  47. projectId: 'a project id',
  48. },
  49. session: {},
  50. body: {
  51. segmentation: {
  52. editorType: 'abc',
  53. },
  54. },
  55. }
  56. ctx.GeoIpLookup.promises.getDetails = sinon
  57. .stub()
  58. .resolves({ country_code: 'XY' })
  59. })
  60. it('delegates to the AnalyticsManager', async function (ctx) {
  61. await new Promise(resolve => {
  62. ctx.SessionManager.getLoggedInUserId.returns('1234')
  63. ctx.res.callback = () => {
  64. sinon.assert.calledWith(
  65. ctx.AnalyticsManager.updateEditingSession,
  66. '1234',
  67. 'a project id',
  68. 'XY',
  69. { editorType: 'abc' }
  70. )
  71. resolve()
  72. }
  73. ctx.controller.updateEditingSession(ctx.req, ctx.res)
  74. })
  75. })
  76. })
  77. describe('recordEvent', function () {
  78. beforeEach(function (ctx) {
  79. const body = {
  80. foo: 'stuff',
  81. _csrf: 'atoken123',
  82. }
  83. ctx.req = {
  84. params: {
  85. event: 'i_did_something',
  86. },
  87. body,
  88. sessionID: 'sessionIDHere',
  89. session: {},
  90. }
  91. ctx.expectedData = Object.assign({}, body)
  92. delete ctx.expectedData._csrf
  93. })
  94. it('should use the session', async function (ctx) {
  95. await new Promise(resolve => {
  96. ctx.controller.recordEvent(ctx.req, ctx.res)
  97. sinon.assert.calledWith(
  98. ctx.AnalyticsManager.recordEventForSession,
  99. ctx.req.session,
  100. ctx.req.params.event,
  101. ctx.expectedData
  102. )
  103. resolve()
  104. })
  105. })
  106. it('should remove the CSRF token before sending to the manager', async function (ctx) {
  107. await new Promise(resolve => {
  108. ctx.controller.recordEvent(ctx.req, ctx.res)
  109. sinon.assert.calledWith(
  110. ctx.AnalyticsManager.recordEventForSession,
  111. ctx.req.session,
  112. ctx.req.params.event,
  113. ctx.expectedData
  114. )
  115. resolve()
  116. })
  117. })
  118. })
  119. })