payment-preview.spec.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. import PaymentPreviewPanel from '../../../../../../frontend/js/features/subscription/components/new/payment-preview/payment-preview-panel'
  2. import { PaymentProvider } from '../../../../../../frontend/js/features/subscription/context/payment-context'
  3. import { plans } from '../../fixtures/plans'
  4. import {
  5. createFakeRecurly,
  6. defaultSubscription,
  7. } from '../../fixtures/recurly-mock'
  8. import { cloneDeep } from 'lodash'
  9. import { Plan } from '../../../../../../types/subscription/plan'
  10. function PaymentPreviewPanelWithPaymentProvider() {
  11. return (
  12. <PaymentProvider publicKey="0000">
  13. <PaymentPreviewPanel />
  14. </PaymentProvider>
  15. )
  16. }
  17. describe('payment preview panel', function () {
  18. beforeEach(function () {
  19. const plan = plans.find(({ planCode }) => planCode === 'collaborator')
  20. if (!plan) {
  21. throw new Error('No plan was found while running the test!')
  22. }
  23. cy.window().then(win => {
  24. win.metaAttributesCache = new Map()
  25. win.metaAttributesCache.set('ol-countryCode', '')
  26. win.metaAttributesCache.set('ol-recurlyApiKey', '0000')
  27. win.metaAttributesCache.set('ol-recommendedCurrency', 'USD')
  28. win.metaAttributesCache.set('ol-plan', plan)
  29. win.metaAttributesCache.set('ol-planCode', plan.planCode)
  30. cy.wrap(plan).as('plan')
  31. // init default recurly
  32. win.recurly = createFakeRecurly(defaultSubscription)
  33. cy.interceptEvents()
  34. })
  35. })
  36. it('renders plan name', function () {
  37. cy.mount(<PaymentPreviewPanelWithPaymentProvider />)
  38. cy.contains(defaultSubscription.items.plan!.name)
  39. })
  40. it('renders collaborators per project', function () {
  41. cy.mount(<PaymentPreviewPanelWithPaymentProvider />)
  42. cy.get<Plan>('@plan').then(plan => {
  43. cy.contains(`${plan.features?.collaborators} collaborators per project`)
  44. })
  45. })
  46. it('renders features list', function () {
  47. cy.mount(<PaymentPreviewPanelWithPaymentProvider />)
  48. cy.contains(/all premium features/i)
  49. cy.findByTestId('features-list').within(() => {
  50. cy.get(':nth-child(1)').contains(/increased compile timeout/i)
  51. cy.get(':nth-child(2)').contains(/sync with dropbox and github/i)
  52. cy.get(':nth-child(3)').contains(/full document history/i)
  53. cy.get(':nth-child(4)').contains(/track changes/i)
  54. cy.get(':nth-child(5)').contains(/advanced reference search/i)
  55. cy.get(':nth-child(6)').contains(/reference manager sync/i)
  56. cy.get(':nth-child(7)').contains(/symbol palette/i)
  57. })
  58. })
  59. it('renders no features list', function () {
  60. cy.window().then(win => {
  61. cy.get<Plan>('@plan').then(plan => {
  62. const { features: _, ...noFeaturesPlan } = plan
  63. win.metaAttributesCache.set('ol-plan', noFeaturesPlan)
  64. })
  65. })
  66. cy.mount(<PaymentPreviewPanelWithPaymentProvider />)
  67. cy.findByTestId('features-list').should('not.exist')
  68. })
  69. describe('price summary', function () {
  70. beforeEach(function () {
  71. cy.mount(<PaymentPreviewPanelWithPaymentProvider />)
  72. cy.findByTestId('price-summary').as('priceSummary')
  73. cy.findByTestId('price-summary-plan').as('priceSummaryPlan')
  74. cy.findByTestId('price-summary-coupon').as('priceSummaryCoupon')
  75. cy.findByTestId('price-summary-vat').as('priceSummaryVat')
  76. cy.findByTestId('price-summary-total').as('priceSummaryTotal')
  77. })
  78. it('renders title', function () {
  79. cy.get('@priceSummary').contains(/payment summary/i)
  80. })
  81. it('renders plan info', function () {
  82. cy.get('@priceSummaryPlan').contains(defaultSubscription.items.plan!.name)
  83. cy.get('@priceSummaryPlan').contains(
  84. `$${defaultSubscription.price.base.plan.unit}`
  85. )
  86. })
  87. it('renders coupon info', function () {
  88. cy.get('@priceSummaryCoupon').contains(
  89. defaultSubscription.items.coupon!.name
  90. )
  91. cy.get('@priceSummaryCoupon').contains(
  92. `Discount of $${defaultSubscription.price.now.discount}`
  93. )
  94. })
  95. it('does not render coupon info when there is no coupon', function () {
  96. cy.window().then(win => {
  97. const { coupon: _, ...items } = defaultSubscription.items
  98. win.recurly = createFakeRecurly({ ...defaultSubscription, items })
  99. })
  100. cy.mount(<PaymentPreviewPanelWithPaymentProvider />)
  101. cy.findByTestId('price-summary-coupon').should('not.exist')
  102. })
  103. it('renders VAT', function () {
  104. cy.get('@priceSummaryVat').contains(
  105. `VAT ${parseFloat(defaultSubscription.price.taxes[0].rate) * 100}%`
  106. )
  107. cy.get('@priceSummaryVat').contains(
  108. `$${defaultSubscription.price.now.tax}`
  109. )
  110. })
  111. describe('total amount', function () {
  112. it('renders "total per month" text', function () {
  113. cy.window().then(win => {
  114. const clone = cloneDeep(defaultSubscription)
  115. clone.items.plan!.period.length = 1
  116. win.recurly = createFakeRecurly(clone)
  117. })
  118. cy.mount(<PaymentPreviewPanelWithPaymentProvider />)
  119. cy.findByTestId('price-summary-total').contains(/total per month/i)
  120. })
  121. it('renders "total per year" text', function () {
  122. cy.window().then(win => {
  123. const clone = cloneDeep(defaultSubscription)
  124. clone.items.plan!.period.length = 2
  125. win.recurly = createFakeRecurly(clone)
  126. })
  127. cy.mount(<PaymentPreviewPanelWithPaymentProvider />)
  128. cy.findByTestId('price-summary-total').contains(/total per year/i)
  129. })
  130. it('renders total amount', function () {
  131. cy.get('@priceSummaryTotal').contains(
  132. `$${defaultSubscription.price.now.total}`
  133. )
  134. })
  135. })
  136. it('renders "change currency" dropdown and changes currency', function () {
  137. cy.get('@priceSummary').within(() => {
  138. cy.get('@priceSummary')
  139. .findByRole('button', { name: /change currency/i })
  140. .as('button')
  141. cy.findByRole('menu').should('not.exist')
  142. cy.get('@button').click()
  143. cy.findByRole('menu').within(() => {
  144. cy.findByRole('menuitem', { name: /usd \(\$\)/i }).contains(
  145. /selected/i
  146. )
  147. cy.findByRole('menuitem', { name: /eur \(€\)/i })
  148. cy.findByRole('menuitem', { name: /gbp \(£\)/i }).click()
  149. cy.get('@priceSummaryPlan').contains(
  150. `£${defaultSubscription.price.base.plan.unit}`
  151. )
  152. cy.get('@priceSummaryCoupon').contains(
  153. `Discount of £${defaultSubscription.price.now.discount}`
  154. )
  155. cy.get('@priceSummaryVat').contains(
  156. `£${defaultSubscription.price.now.tax}`
  157. )
  158. cy.get('@priceSummaryTotal').contains(
  159. `£${defaultSubscription.price.now.total}`
  160. )
  161. })
  162. })
  163. cy.findByTestId('trial-coupon-summary')
  164. .should('not.contain.text', '$')
  165. .should('contain.text', '£')
  166. })
  167. })
  168. describe('trial coupon summary', function () {
  169. it('renders trial price', function () {
  170. cy.mount(<PaymentPreviewPanelWithPaymentProvider />)
  171. cy.findByTestId('trial-coupon-summary').contains(
  172. `First ${defaultSubscription.items.plan!.trial!.length} days free, ` +
  173. `after that $${defaultSubscription.price.now.total} per month`
  174. )
  175. })
  176. it('renders "X price for Y months"', function () {
  177. cy.window()
  178. .then(win => {
  179. const clone = cloneDeep(defaultSubscription)
  180. clone.items.coupon!.applies_for_months = 6
  181. clone.items.coupon!.single_use = false
  182. clone.items.plan!.period.length = 1
  183. win.recurly = createFakeRecurly(clone)
  184. return clone
  185. })
  186. .then((clone: typeof defaultSubscription) => {
  187. cy.mount(<PaymentPreviewPanelWithPaymentProvider />)
  188. cy.findByTestId('trial-coupon-summary').contains(
  189. `$${clone.price.now.total} for your first ${
  190. clone.items.coupon!.applies_for_months
  191. } months`
  192. )
  193. })
  194. })
  195. it('renders "X price for first month"', function () {
  196. cy.window()
  197. .then(win => {
  198. const clone = cloneDeep(defaultSubscription)
  199. clone.items.plan!.period.length = 1
  200. win.recurly = createFakeRecurly(clone)
  201. })
  202. .then(() => {
  203. cy.mount(<PaymentPreviewPanelWithPaymentProvider />)
  204. cy.findByTestId('trial-coupon-summary').contains(
  205. `$${defaultSubscription.price.now.total} for your first month`
  206. )
  207. })
  208. })
  209. it('renders "X price for first year"', function () {
  210. cy.mount(<PaymentPreviewPanelWithPaymentProvider />)
  211. cy.findByTestId('trial-coupon-summary').contains(
  212. `$${defaultSubscription.price.now.total} for your first year`
  213. )
  214. })
  215. it('renders "then X price per month"', function () {
  216. cy.window()
  217. .then(win => {
  218. const clone = cloneDeep(defaultSubscription)
  219. clone.items.coupon!.applies_for_months = 6
  220. clone.items.coupon!.single_use = false
  221. clone.items.plan!.period.length = 1
  222. win.recurly = createFakeRecurly(clone)
  223. })
  224. .then(() => {
  225. cy.mount(<PaymentPreviewPanelWithPaymentProvider />)
  226. cy.findByTestId('trial-coupon-summary').contains(
  227. `Then $26.00 per month`
  228. )
  229. })
  230. })
  231. it('renders "then X price per year"', function () {
  232. cy.mount(<PaymentPreviewPanelWithPaymentProvider />)
  233. cy.findByTestId('trial-coupon-summary').contains(`Then $26.00 per year`)
  234. })
  235. it('renders "normally X price per month"', function () {
  236. cy.window()
  237. .then(win => {
  238. const clone = cloneDeep(defaultSubscription)
  239. clone.items.coupon!.applies_for_months = 0
  240. clone.items.coupon!.single_use = false
  241. clone.items.plan!.period.length = 1
  242. win.recurly = createFakeRecurly(clone)
  243. })
  244. .then(() => {
  245. cy.mount(<PaymentPreviewPanelWithPaymentProvider />)
  246. cy.findByTestId('trial-coupon-summary').contains(
  247. `Normally $26.00 per month`
  248. )
  249. })
  250. })
  251. it('renders "normally X price per year"', function () {
  252. cy.window()
  253. .then(win => {
  254. const clone = cloneDeep(defaultSubscription)
  255. clone.items.coupon!.single_use = false
  256. clone.items.plan!.period.length = 2
  257. win.recurly = createFakeRecurly(clone)
  258. })
  259. .then(() => {
  260. cy.mount(<PaymentPreviewPanelWithPaymentProvider />)
  261. cy.findByTestId('trial-coupon-summary').contains(
  262. `Normally $26.00 per year`
  263. )
  264. })
  265. })
  266. })
  267. it('renders "cancel anytime" content', function () {
  268. cy.mount(<PaymentPreviewPanelWithPaymentProvider />)
  269. cy.contains(
  270. /we’re confident that you’ll love Overleaf, but if not you can cancel anytime/i
  271. ).contains(
  272. /we’ll give you your money back, no questions asked, if you let us know within 30 days/i
  273. )
  274. })
  275. })