current-plan-widget.test.tsx 8.9 KB

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