2023-01-26 11:48:30 -05:00
import { expect } from 'chai'
2023-02-28 04:15:33 -05:00
import {
screen ,
fireEvent ,
waitForElementToBeRemoved ,
within ,
} from '@testing-library/react'
2023-01-26 11:48:30 -05:00
import PersonalSubscription from '../../../../../../frontend/js/features/subscription/components/dashboard/personal-subscription'
import {
annualActiveSubscription ,
canceledSubscription ,
2023-02-22 07:33:17 -05:00
customSubscription ,
2023-01-26 11:48:30 -05:00
pastDueExpiredSubscription ,
} from '../../fixtures/subscriptions'
2023-02-07 10:38:20 -05:00
import {
cleanUpContext ,
renderWithSubscriptionDashContext ,
} from '../../helpers/render-with-subscription-dash-context'
2023-02-28 04:48:48 -05:00
import { reactivateSubscriptionUrl } from '../../../../../../frontend/js/features/subscription/data/subscription-url'
2023-02-28 04:15:33 -05:00
import fetchMock from 'fetch-mock'
2023-02-28 04:48:48 -05:00
import sinon from 'sinon'
2023-03-16 08:32:48 -04:00
import * as useLocationModule from '../../../../../../frontend/js/shared/hooks/use-location'
2023-01-26 11:48:30 -05:00
describe ( '<PersonalSubscription />' , function ( ) {
afterEach ( function ( ) {
2023-02-07 10:38:20 -05:00
cleanUpContext ( )
2023-01-26 11:48:30 -05:00
} )
describe ( 'no subscription' , function ( ) {
it ( 'returns empty container' , function ( ) {
2023-02-07 10:38:20 -05:00
const { container } = renderWithSubscriptionDashContext (
< PersonalSubscription / >
2023-01-26 11:48:30 -05:00
)
expect ( container . firstChild ) . to . be . null
} )
} )
2023-02-22 07:33:17 -05:00
describe ( 'custom subscription' , function ( ) {
it ( 'displays contact support message' , function ( ) {
renderWithSubscriptionDashContext ( < PersonalSubscription / > , {
metaTags : [ { name : 'ol-subscription' , value : customSubscription } ] ,
} )
screen . getByText ( 'Please' , { exact : false } )
screen . getByText ( 'contact support' , { exact : false } )
screen . getByText ( 'to make changes to your plan' , { exact : false } )
} )
} )
2023-01-26 11:48:30 -05:00
describe ( 'subscription states ' , function ( ) {
2023-03-16 08:32:48 -04:00
let reloadStub : sinon.SinonStub
beforeEach ( function ( ) {
reloadStub = sinon . stub ( )
this . locationStub = sinon . stub ( useLocationModule , 'useLocation' ) . returns ( {
assign : sinon.stub ( ) ,
2024-05-03 03:46:21 -04:00
replace : sinon.stub ( ) ,
2023-03-16 08:32:48 -04:00
reload : reloadStub ,
} )
} )
afterEach ( function ( ) {
this . locationStub . restore ( )
} )
2023-01-26 11:48:30 -05:00
it ( 'renders the active dash' , function ( ) {
2023-02-07 10:38:20 -05:00
renderWithSubscriptionDashContext ( < PersonalSubscription / > , {
metaTags : [
{ name : 'ol-subscription' , value : annualActiveSubscription } ,
] ,
} )
2023-01-26 11:48:30 -05:00
screen . getByText ( 'You are currently subscribed to the' , { exact : false } )
} )
it ( 'renders the canceled dash' , function ( ) {
2023-02-07 10:38:20 -05:00
renderWithSubscriptionDashContext ( < PersonalSubscription / > , {
metaTags : [ { name : 'ol-subscription' , value : canceledSubscription } ] ,
} )
2023-01-26 11:48:30 -05:00
screen . getByText (
'Your subscription has been canceled and will terminate on' ,
{ exact : false }
)
2023-02-22 07:33:17 -05:00
screen . getByText ( canceledSubscription . recurly ! . nextPaymentDueAt , {
2023-01-26 11:48:30 -05:00
exact : false ,
} )
screen . getByText ( 'No further payments will be taken.' , { exact : false } )
screen . getByRole ( 'link' , { name : 'View Your Invoices' } )
screen . getByRole ( 'button' , { name : 'Reactivate your subscription' } )
} )
2023-02-28 04:48:48 -05:00
it ( 'reactivates canceled plan' , async function ( ) {
renderWithSubscriptionDashContext ( < PersonalSubscription / > , {
metaTags : [ { name : 'ol-subscription' , value : canceledSubscription } ] ,
} )
const reactivateBtn = screen . getByRole < HTMLButtonElement > ( 'button' , {
name : 'Reactivate your subscription' ,
} )
// 1st click - fail
fetchMock . postOnce ( reactivateSubscriptionUrl , 400 )
fireEvent . click ( reactivateBtn )
expect ( reactivateBtn . disabled ) . to . be . true
await fetchMock . flush ( true )
expect ( reactivateBtn . disabled ) . to . be . false
2023-03-16 08:32:48 -04:00
expect ( reloadStub ) . not . to . have . been . called
2023-02-28 04:48:48 -05:00
fetchMock . reset ( )
// 2nd click - success
fetchMock . postOnce ( reactivateSubscriptionUrl , 200 )
fireEvent . click ( reactivateBtn )
await fetchMock . flush ( true )
2023-03-16 08:32:48 -04:00
expect ( reloadStub ) . to . have . been . calledOnce
2023-02-28 04:48:48 -05:00
expect ( reactivateBtn . disabled ) . to . be . true
fetchMock . reset ( )
} )
2023-01-26 11:48:30 -05:00
it ( 'renders the expired dash' , function ( ) {
2023-02-07 10:38:20 -05:00
renderWithSubscriptionDashContext ( < PersonalSubscription / > , {
metaTags : [
{ name : 'ol-subscription' , value : pastDueExpiredSubscription } ,
] ,
} )
2023-01-26 11:48:30 -05:00
screen . getByText ( 'Your subscription has expired.' )
} )
it ( 'renders error message when an unknown subscription state' , function ( ) {
2023-01-26 12:01:54 -05:00
const withStateDeleted = Object . assign (
{ } ,
JSON . parse ( JSON . stringify ( annualActiveSubscription ) )
)
2023-01-26 11:48:30 -05:00
withStateDeleted . recurly . state = undefined
2023-02-07 10:38:20 -05:00
renderWithSubscriptionDashContext ( < PersonalSubscription / > , {
metaTags : [ { name : 'ol-subscription' , value : withStateDeleted } ] ,
} )
2023-01-26 11:48:30 -05:00
screen . getByText (
'There is a problem with your subscription. Please contact us for more information.'
)
} )
} )
describe ( 'past due subscription' , function ( ) {
it ( 'renders error alert' , function ( ) {
2023-02-07 10:38:20 -05:00
renderWithSubscriptionDashContext ( < PersonalSubscription / > , {
metaTags : [
{ name : 'ol-subscription' , value : pastDueExpiredSubscription } ,
] ,
} )
2023-01-26 11:48:30 -05:00
screen . getByRole ( 'alert' )
screen . getByText (
'Your account currently has a past due invoice. You will not be able to change your plan until this is resolved.' ,
{ exact : false }
)
const invoiceLinks = screen . getAllByText ( 'View Your Invoices' , {
exact : false ,
} )
expect ( invoiceLinks . length ) . to . equal ( 2 )
} )
} )
2023-01-26 12:01:54 -05:00
describe ( 'Recurly JS' , function ( ) {
const recurlyFailedToLoadText =
'Sorry, there was an error talking to our payment provider. Please try again in a few moments. If you are using any ad or script blocking extensions in your browser, you may need to temporarily disable them.'
it ( 'shows an alert and hides "Change plan" option when Recurly did not load' , function ( ) {
2023-02-07 10:38:20 -05:00
renderWithSubscriptionDashContext ( < PersonalSubscription / > , {
metaTags : [
{ name : 'ol-subscription' , value : annualActiveSubscription } ,
] ,
recurlyNotLoaded : true ,
} )
2023-01-26 12:01:54 -05:00
screen . getByRole ( 'alert' )
screen . getByText ( recurlyFailedToLoadText )
expect ( screen . queryByText ( 'Change plan' ) ) . to . be . null
} )
it ( 'should not show an alert and should show "Change plan" option when Recurly did load' , function ( ) {
2023-02-07 10:38:20 -05:00
renderWithSubscriptionDashContext ( < PersonalSubscription / > , {
metaTags : [
{ name : 'ol-subscription' , value : annualActiveSubscription } ,
] ,
} )
2023-01-26 12:01:54 -05:00
expect ( screen . queryByRole ( 'alert' ) ) . to . be . null
screen . getByText ( 'Change plan' )
} )
} )
2023-02-28 04:15:33 -05:00
it ( 'shows different recurly email address section' , async function ( ) {
fetchMock . post ( '/user/subscription/account/email' , 200 )
const usersEmail = 'foo@example.com'
renderWithSubscriptionDashContext ( < PersonalSubscription / > , {
metaTags : [
{ name : 'ol-subscription' , value : annualActiveSubscription } ,
{ name : 'ol-usersEmail' , value : usersEmail } ,
] ,
} )
const billingText = screen . getByText (
/your billing email address is currently/i
) . textContent
expect ( billingText ) . to . contain (
` Your billing email address is currently ${ annualActiveSubscription . recurly . account . email } . ` +
` If needed you can update your billing address to ${ usersEmail } `
)
const submitBtn = screen . getByRole < HTMLButtonElement > ( 'button' , {
name : /update/i ,
} )
expect ( submitBtn . disabled ) . to . be . false
fireEvent . click ( submitBtn )
expect ( submitBtn . disabled ) . to . be . true
expect (
screen . getByRole < HTMLButtonElement > ( 'button' , { name : /updating/i } )
. disabled
) . to . be . true
await waitForElementToBeRemoved ( ( ) = >
screen . getByText ( /your billing email address is currently/i )
)
within ( screen . getByRole ( 'alert' ) ) . getByText (
/your billing email address was successfully updated/i
)
expect ( screen . queryByRole ( 'button' , { name : /update/i } ) ) . to . be . null
expect ( screen . queryByRole ( 'button' , { name : /updating/i } ) ) . to . be . null
} )
2023-01-26 11:48:30 -05:00
} )