current-plan-widget.test.tsx 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. import { expect } from 'chai'
  2. import sinon from 'sinon'
  3. import { fireEvent, render, screen } from '@testing-library/react'
  4. import {
  5. CommonsPlanSubscription,
  6. GroupPlanSubscription,
  7. IndividualPlanSubscription,
  8. } from '../../../../../types/project/dashboard/subscription'
  9. import { DeepReadonly } from '../../../../../types/utils'
  10. import * as eventTracking from '../../../../../frontend/js/infrastructure/event-tracking'
  11. import CurrentPlanWidget from '../../../../../frontend/js/features/project-list/components/current-plan-widget/current-plan-widget'
  12. describe('<CurrentPlanWidget />', function () {
  13. const freePlanTooltipMessage =
  14. /click to find out how you could benefit from overleaf premium features/i
  15. const paidPlanTooltipMessage =
  16. /click to find out how to make the most of your overleaf premium features/i
  17. beforeEach(function () {
  18. window.metaAttributesCache = window.metaAttributesCache || new Map()
  19. })
  20. describe('free plan', function () {
  21. let sendMBSpy: sinon.SinonSpy
  22. beforeEach(function () {
  23. sendMBSpy = sinon.spy(eventTracking, 'sendMB')
  24. window.metaAttributesCache.set('ol-usersBestSubscription', {
  25. type: 'free',
  26. })
  27. render(<CurrentPlanWidget />)
  28. })
  29. afterEach(function () {
  30. sendMBSpy.restore()
  31. })
  32. it('shows text and tooltip on mouseover', function () {
  33. const link = screen.getByRole('link', {
  34. name: /you’re on the free plan/i,
  35. })
  36. fireEvent.mouseOver(link)
  37. screen.getByRole('tooltip', { name: freePlanTooltipMessage })
  38. })
  39. it('clicks on upgrade button', function () {
  40. const upgradeLink = screen.getByRole('link', { name: /upgrade/i })
  41. fireEvent.click(upgradeLink)
  42. expect(sendMBSpy).to.be.calledOnce
  43. expect(sendMBSpy).calledWith('upgrade-button-click', {
  44. source: 'dashboard-top',
  45. page: '/',
  46. })
  47. })
  48. })
  49. describe('paid plan', function () {
  50. describe('trial', function () {
  51. const subscription = {
  52. type: 'individual',
  53. plan: {
  54. name: 'Abc',
  55. },
  56. subscription: {
  57. name: 'Example Name',
  58. },
  59. remainingTrialDays: -1,
  60. } as DeepReadonly<IndividualPlanSubscription>
  61. beforeEach(function () {
  62. window.metaAttributesCache.set('ol-usersBestSubscription', {
  63. ...subscription,
  64. })
  65. })
  66. it('shows remaining days', function () {
  67. const newSubscription: IndividualPlanSubscription = {
  68. ...subscription,
  69. remainingTrialDays: 5,
  70. }
  71. window.metaAttributesCache.set(
  72. 'ol-usersBestSubscription',
  73. newSubscription
  74. )
  75. render(<CurrentPlanWidget />)
  76. screen.getByRole('link', {
  77. name: new RegExp(
  78. `${newSubscription.remainingTrialDays} more days on your overleaf premium trial`,
  79. 'i'
  80. ),
  81. })
  82. })
  83. it('shows last day message', function () {
  84. window.metaAttributesCache.set('ol-usersBestSubscription', {
  85. ...subscription,
  86. remainingTrialDays: 1,
  87. })
  88. render(<CurrentPlanWidget />)
  89. screen.getByRole('link', {
  90. name: /this is the last day of your overleaf premium trial/i,
  91. })
  92. })
  93. })
  94. describe('individual', function () {
  95. const subscription = {
  96. type: 'individual',
  97. plan: {
  98. name: 'Abc',
  99. },
  100. subscription: {
  101. teamName: 'Example Team',
  102. name: 'Example Name',
  103. },
  104. remainingTrialDays: -1,
  105. } as DeepReadonly<IndividualPlanSubscription>
  106. beforeEach(function () {
  107. window.metaAttributesCache.set('ol-usersBestSubscription', {
  108. ...subscription,
  109. })
  110. })
  111. it('shows text and tooltip on mouseover', function () {
  112. render(<CurrentPlanWidget />)
  113. const link = screen.getByRole('link', {
  114. name: /you’re using overleaf premium/i,
  115. })
  116. fireEvent.mouseOver(link)
  117. screen.getByRole('tooltip', {
  118. name: new RegExp(`on the ${subscription.plan.name}`, 'i'),
  119. })
  120. screen.getByRole('tooltip', { name: paidPlanTooltipMessage })
  121. })
  122. })
  123. describe('group', function () {
  124. const subscription = {
  125. type: 'group',
  126. plan: {
  127. name: 'Abc',
  128. },
  129. subscription: {
  130. name: 'Example Name',
  131. },
  132. remainingTrialDays: -1,
  133. } as DeepReadonly<GroupPlanSubscription>
  134. beforeEach(function () {
  135. window.metaAttributesCache.set('ol-usersBestSubscription', {
  136. ...subscription,
  137. })
  138. })
  139. it('shows text and tooltip on mouseover (without subscription team name)', function () {
  140. render(<CurrentPlanWidget />)
  141. const link = screen.getByRole('link', {
  142. name: /you’re using overleaf premium/i,
  143. })
  144. fireEvent.mouseOver(link)
  145. expect(subscription.subscription.teamName).to.be.undefined
  146. screen.getByRole('tooltip', {
  147. name: new RegExp(
  148. `on the ${subscription.plan.name} plan as a member of a group subscription`,
  149. 'i'
  150. ),
  151. })
  152. screen.getByRole('tooltip', { name: paidPlanTooltipMessage })
  153. })
  154. it('shows text and tooltip on mouseover (with subscription team name)', function () {
  155. const newSubscription = {
  156. ...subscription,
  157. subscription: {
  158. teamName: 'Example Team',
  159. },
  160. }
  161. window.metaAttributesCache.set(
  162. 'ol-usersBestSubscription',
  163. newSubscription
  164. )
  165. render(<CurrentPlanWidget />)
  166. const link = screen.getByRole('link', {
  167. name: /you’re using overleaf premium/i,
  168. })
  169. fireEvent.mouseOver(link)
  170. screen.getByRole('tooltip', {
  171. name: new RegExp(
  172. `on the ${newSubscription.plan.name} plan as a member of a group subscription, ${newSubscription.subscription.teamName}`,
  173. 'i'
  174. ),
  175. })
  176. screen.getByRole('tooltip', { name: paidPlanTooltipMessage })
  177. })
  178. })
  179. describe('commons', function () {
  180. it('shows text and tooltip on mouseover', function () {
  181. const subscription = {
  182. type: 'commons',
  183. plan: {
  184. name: 'Abc',
  185. },
  186. subscription: {
  187. name: 'Example Name',
  188. },
  189. } as DeepReadonly<CommonsPlanSubscription>
  190. window.metaAttributesCache.set('ol-usersBestSubscription', {
  191. ...subscription,
  192. })
  193. render(<CurrentPlanWidget />)
  194. const link = screen.getByRole('link', {
  195. name: /you’re using overleaf premium/i,
  196. })
  197. fireEvent.mouseOver(link)
  198. screen.getByRole('tooltip', {
  199. name: new RegExp(
  200. `on the ${subscription.plan.name} plan because of your affiliation with ${subscription.subscription.name}`,
  201. 'i'
  202. ),
  203. })
  204. screen.getByRole('tooltip', { name: paidPlanTooltipMessage })
  205. })
  206. })
  207. })
  208. describe('features page split test', function () {
  209. let sendMBSpy: sinon.SinonSpy
  210. const variants = [
  211. { name: 'default', link: '/learn/how-to/Overleaf_premium_features' },
  212. { name: 'new', link: '/about/features-overview' },
  213. ]
  214. const plans = [
  215. { type: 'free' },
  216. {
  217. type: 'individual',
  218. plan: {
  219. name: 'Abc',
  220. },
  221. },
  222. {
  223. type: 'group',
  224. plan: {
  225. name: 'Abc',
  226. },
  227. subscription: {
  228. teamName: 'Example Team',
  229. name: 'Example Name',
  230. },
  231. },
  232. {
  233. type: 'commons',
  234. plan: {
  235. name: 'Abc',
  236. },
  237. subscription: {
  238. name: 'Example Name',
  239. },
  240. },
  241. ]
  242. beforeEach(function () {
  243. sendMBSpy = sinon.spy(eventTracking, 'sendMB')
  244. })
  245. afterEach(function () {
  246. sendMBSpy.restore()
  247. })
  248. for (const variant of variants) {
  249. describe(`${variant.name} variant`, function () {
  250. beforeEach(function () {
  251. window.metaAttributesCache.set('ol-splitTestVariants', {
  252. 'features-page': variant.name,
  253. })
  254. })
  255. afterEach(function () {
  256. window.metaAttributesCache.delete('ol-splitTestVariants')
  257. })
  258. for (const plan of plans) {
  259. it(`links to ${variant.name} features page on ${plan.type} plan and sends analytics event`, function () {
  260. window.metaAttributesCache.set('ol-usersBestSubscription', {
  261. ...plan,
  262. })
  263. render(<CurrentPlanWidget />)
  264. const links = screen.getAllByRole('link')
  265. expect(links[0].getAttribute('href')).to.equal(variant.link)
  266. fireEvent.click(links[0])
  267. expect(sendMBSpy).to.be.calledOnce
  268. expect(sendMBSpy).calledWith('features-page-link', {
  269. splitTest: 'features-page',
  270. splitTestVariant: variant.name,
  271. page: '/',
  272. })
  273. window.metaAttributesCache.delete('ol-usersBestSubscription')
  274. })
  275. }
  276. })
  277. }
  278. })
  279. })