Skip to content

Commit 823845e

Browse files
authored
chore(clerk-js,e2e): Test case for cancelling a plan (#6333)
1 parent 3f1270d commit 823845e

File tree

6 files changed

+90
-21
lines changed

6 files changed

+90
-21
lines changed

.changeset/lovely-ghosts-fall.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@clerk/clerk-js': patch
3+
---
4+
5+
Marking root of subscription modal with `cl-subscriptionDetails-root`.

.changeset/slow-zoos-work.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@clerk/testing': patch
3+
---
4+
5+
Adding subscription details page object.

integration/tests/pricing-table.test.ts

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -142,19 +142,6 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withBilling] })('pricing tabl
142142
await newFakeUser.deleteIfExists();
143143
});
144144

145-
// test('can manage and cancel subscription', async ({ page, context }) => {
146-
// const u = createTestUtils({ app, page, context });
147-
// await u.po.signIn.goTo();
148-
// await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeUser.email, password: fakeUser.password });
149-
// await u.po.page.goToRelative('/pricing-table');
150-
151-
// await u.po.pricingTable.waitForMounted();
152-
// await u.po.pricingTable.clickManageSubscription();
153-
// await u.po.page.getByRole('button', { name: 'Cancel subscription' }).click();
154-
// await u.po.page.getByRole('alertdialog').getByRole('button', { name: 'Cancel subscription' }).click();
155-
// await expect(u.po.page.getByRole('button', { name: /resubscribe|re-subscribe/i }).first()).toBeVisible();
156-
// });
157-
158145
test.describe('redirects', () => {
159146
test('default navigates to afterSignInUrl', async ({ page, context }) => {
160147
const u = createTestUtils({ app, page, context });
@@ -260,6 +247,51 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withBilling] })('pricing tabl
260247
await fakeUser.deleteIfExists();
261248
});
262249

250+
test('can unsubscribe from a plan', async ({ page, context }) => {
251+
const u = createTestUtils({ app, page, context });
252+
253+
const fakeUser = u.services.users.createFakeUser();
254+
await u.services.users.createBapiUser(fakeUser);
255+
256+
await u.po.signIn.goTo();
257+
await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeUser.email, password: fakeUser.password });
258+
await u.po.page.goToRelative('/user');
259+
260+
await u.po.userProfile.waitForMounted();
261+
await u.po.userProfile.switchToBillingTab();
262+
await expect(u.po.page.getByText(/Free/i)).toBeVisible();
263+
await u.po.page.getByRole('button', { name: 'Switch plans' }).click();
264+
await u.po.pricingTable.startCheckout({ planSlug: 'plus' });
265+
await u.po.checkout.waitForMounted();
266+
await u.po.checkout.fillTestCard();
267+
await u.po.checkout.clickPayOrSubscribe();
268+
await expect(u.po.page.getByText('Payment was successful!')).toBeVisible();
269+
270+
await u.po.checkout.confirmAndContinue();
271+
await u.po.page.locator('.cl-headerBackLink').getByText('Plans').click();
272+
273+
await u.page.waitForTimeout(1000);
274+
await expect(u.po.page.locator('.cl-profileSectionContent__subscriptionsList').getByText('Plus')).toBeVisible();
275+
await u.po.page.getByRole('button', { name: 'Manage subscription' }).first().click();
276+
await u.po.subscriptionDetails.waitForMounted();
277+
await u.po.subscriptionDetails.root.locator('.cl-menuButtonEllipsisBordered').click();
278+
await u.po.subscriptionDetails.root.getByText('Cancel subscription').click();
279+
await u.po.subscriptionDetails.root.locator('.cl-drawerConfirmationRoot').waitFor({ state: 'visible' });
280+
await u.po.subscriptionDetails.root.getByText('Cancel subscription').click();
281+
await u.po.subscriptionDetails.waitForUnmounted();
282+
283+
// Verify the Free plan with Upcoming status exists
284+
await expect(
285+
u.po.page
286+
.locator('.cl-profileSectionContent__subscriptionsList')
287+
.getByText('Free')
288+
.locator('xpath=..')
289+
.getByText('Upcoming'),
290+
).toBeVisible();
291+
292+
await fakeUser.deleteIfExists();
293+
});
294+
263295
test('checkout always revalidates on open', async ({ page, context }) => {
264296
const u = createTestUtils({ app, page, context });
265297

packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
Col,
3333
descriptors,
3434
Flex,
35+
Flow,
3536
Heading,
3637
localizationKeys,
3738
Spinner,
@@ -40,7 +41,7 @@ import {
4041
} from '../../customizables';
4142
import { SubscriptionBadge } from '../Subscriptions/badge';
4243

43-
// We cannot derive the state of confrimation modal from the existance subscription, as it will make the animation laggy when the confimation closes.
44+
// We cannot derive the state of confirmation modal from the existence subscription, as it will make the animation laggy when the confimation closes.
4445
const SubscriptionForCancellationContext = React.createContext<{
4546
subscription: CommerceSubscriptionResource | null;
4647
setSubscription: (subscription: CommerceSubscriptionResource | null) => void;
@@ -55,13 +56,17 @@ const SubscriptionForCancellationContext = React.createContext<{
5556

5657
export const SubscriptionDetails = (props: __internal_SubscriptionDetailsProps) => {
5758
return (
58-
<Drawer.Content>
59-
<SubscriptionDetailsContext.Provider value={{ componentName: 'SubscriptionDetails', ...props }}>
60-
<SubscriberTypeContext.Provider value={props.for}>
61-
<SubscriptionDetailsInternal {...props} />
62-
</SubscriberTypeContext.Provider>
63-
</SubscriptionDetailsContext.Provider>
64-
</Drawer.Content>
59+
<Flow.Root flow='subscriptionDetails'>
60+
<Flow.Part>
61+
<Drawer.Content>
62+
<SubscriptionDetailsContext.Provider value={{ componentName: 'SubscriptionDetails', ...props }}>
63+
<SubscriberTypeContext.Provider value={props.for}>
64+
<SubscriptionDetailsInternal {...props} />
65+
</SubscriberTypeContext.Provider>
66+
</SubscriptionDetailsContext.Provider>
67+
</Drawer.Content>
68+
</Flow.Part>
69+
</Flow.Root>
6570
);
6671
};
6772

packages/testing/src/playwright/unstable/page-objects/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { createPricingTablePageObject } from './pricingTable';
1212
import { createSessionTaskComponentPageObject } from './sessionTask';
1313
import { createSignInComponentPageObject } from './signIn';
1414
import { createSignUpComponentPageObject } from './signUp';
15+
import { createSubscriptionDetailsPageObject } from './subscriptionDetails';
1516
import { createTestingTokenPageObject } from './testingToken';
1617
import { createUserButtonPageObject } from './userButton';
1718
import { createUserProfileComponentPageObject } from './userProfile';
@@ -48,5 +49,6 @@ export const createPageObjects = ({
4849
userVerification: createUserVerificationComponentPageObject(testArgs),
4950
waitlist: createWaitlistComponentPageObject(testArgs),
5051
apiKeys: createAPIKeysComponentPageObject(testArgs),
52+
subscriptionDetails: createSubscriptionDetailsPageObject(testArgs),
5153
};
5254
};
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import type { EnhancedPage } from './app';
2+
import { common } from './common';
3+
4+
export const createSubscriptionDetailsPageObject = (testArgs: { page: EnhancedPage }) => {
5+
const { page } = testArgs;
6+
const self = {
7+
...common(testArgs),
8+
waitForMounted: (selector = '.cl-subscriptionDetails-root') => {
9+
return page.waitForSelector(selector, { state: 'attached' });
10+
},
11+
waitForUnmounted: () => {
12+
return self.root.locator('.cl-drawerRoot').waitFor({ state: 'detached' });
13+
},
14+
closeDrawer: () => {
15+
return self.root.locator('.cl-drawerClose').click();
16+
},
17+
root: page.locator('.cl-subscriptionDetails-root'),
18+
};
19+
return self;
20+
};

0 commit comments

Comments
 (0)