current-plan-widget.test.tsx 9.1 KB

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