@@ -62,6 +62,18 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withBilling] })('pricing tabl
62
62
await u . po . signIn . waitForMounted ( ) ;
63
63
await expect ( u . po . page . getByText ( 'Checkout' ) ) . toBeHidden ( ) ;
64
64
} ) ;
65
+
66
+ test ( 'when signed out, clicking trial plan redirects to sign in' , async ( { page, context } ) => {
67
+ const u = createTestUtils ( { app, page, context } ) ;
68
+ await u . po . page . goToRelative ( '/pricing-table' ) ;
69
+
70
+ await u . po . pricingTable . waitForMounted ( ) ;
71
+ await expect ( u . po . page . getByText ( / S t a r t \d + - d a y f r e e t r i a l / i) ) . toBeVisible ( ) ;
72
+ await u . po . pricingTable . startCheckout ( { planSlug : 'trial' } ) ;
73
+
74
+ await u . po . signIn . waitForMounted ( ) ;
75
+ await expect ( u . po . page . getByText ( 'Checkout' ) ) . toBeHidden ( ) ;
76
+ } ) ;
65
77
} ) ;
66
78
67
79
test . describe ( 'when signed in flow' , ( ) => {
@@ -243,6 +255,96 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withBilling] })('pricing tabl
243
255
await newFakeUser . deleteIfExists ( ) ;
244
256
} ) ;
245
257
258
+ test ( 'starts free trial subscription for new user' , async ( { page, context } ) => {
259
+ const u = createTestUtils ( { app, page, context } ) ;
260
+
261
+ // Create a new user specifically for this trial test
262
+ const trialUser = u . services . users . createFakeUser ( ) ;
263
+ await u . services . users . createBapiUser ( trialUser ) ;
264
+
265
+ try {
266
+ // Sign in the new user
267
+ await u . po . signIn . goTo ( ) ;
268
+ await u . po . signIn . signInWithEmailAndInstantPassword ( {
269
+ email : trialUser . email ,
270
+ password : trialUser . password ,
271
+ } ) ;
272
+
273
+ // Navigate to pricing table
274
+ await u . po . page . goToRelative ( '/pricing-table' ) ;
275
+ await u . po . pricingTable . waitForMounted ( ) ;
276
+
277
+ // Verify trial plan is displayed with trial CTA
278
+ // Note: This assumes there's a plan with trial enabled in the test environment
279
+ // The button text should show "Start [X]-day free trial" for trial-enabled plans
280
+ await expect ( u . po . page . getByText ( / S t a r t \d + - d a y f r e e t r i a l / i) ) . toBeVisible ( ) ;
281
+
282
+ // Start checkout for a trial plan (assuming 'pro' has trial enabled in test env)
283
+ await u . po . pricingTable . startCheckout ( { planSlug : 'trial' } ) ;
284
+ await u . po . checkout . waitForMounted ( ) ;
285
+
286
+ // Verify checkout shows trial details
287
+ await expect ( u . po . checkout . root . getByText ( 'Checkout' ) ) . toBeVisible ( ) ;
288
+ await expect ( u . po . checkout . root . getByText ( 'Free trial' ) ) . toBeVisible ( ) ;
289
+ await expect ( u . po . checkout . root . getByText ( 'Total Due after' ) ) . toBeVisible ( ) ;
290
+
291
+ await u . po . checkout . fillTestCard ( ) ;
292
+ await u . po . checkout . clickPayOrSubscribe ( ) ;
293
+
294
+ await expect ( u . po . checkout . root . getByText ( / T r i a l .* s u c c e s s f u l l y .* s t a r t e d / i) ) . toBeVisible ( ) ;
295
+ await u . po . checkout . confirmAndContinue ( ) ;
296
+
297
+ await u . po . page . goToRelative ( '/pricing-table' ) ;
298
+ await u . po . pricingTable . waitForMounted ( ) ;
299
+
300
+ // Verify the user is now shown as having an active free trial
301
+ // The pricing table should show their current plan as active
302
+ await u . po . pricingTable . waitToBeActive ( { planSlug : 'trial' } ) ;
303
+
304
+ await u . po . page . goToRelative ( '/user' ) ;
305
+ await u . po . userProfile . waitForMounted ( ) ;
306
+ await u . po . userProfile . switchToBillingTab ( ) ;
307
+
308
+ await expect (
309
+ u . po . page
310
+ . locator ( '.cl-profileSectionContent__subscriptionsList' )
311
+ . getByText ( / T r i a l / i)
312
+ . locator ( 'xpath=..' )
313
+ . getByText ( / F r e e t r i a l / i) ,
314
+ ) . toBeVisible ( ) ;
315
+
316
+ await expect ( u . po . page . getByText ( / T r i a l e n d s / i) ) . toBeVisible ( ) ;
317
+
318
+ await u . po . page . getByRole ( 'button' , { name : 'Manage subscription' } ) . first ( ) . click ( ) ;
319
+ await u . po . subscriptionDetails . waitForMounted ( ) ;
320
+ await u . po . subscriptionDetails . root . locator ( '.cl-menuButtonEllipsisBordered' ) . click ( ) ;
321
+ await u . po . subscriptionDetails . root . getByText ( 'Cancel free trial' ) . click ( ) ;
322
+ await u . po . subscriptionDetails . root . locator ( '.cl-drawerConfirmationRoot' ) . waitFor ( { state : 'visible' } ) ;
323
+ await u . po . subscriptionDetails . root . getByRole ( 'button' , { name : 'Cancel free trial' } ) . click ( ) ;
324
+ await u . po . subscriptionDetails . waitForUnmounted ( ) ;
325
+
326
+ await expect (
327
+ u . po . page
328
+ . locator ( '.cl-profileSectionContent__subscriptionsList' )
329
+ . getByText ( / T r i a l / i)
330
+ . locator ( 'xpath=..' )
331
+ . getByText ( / F r e e t r i a l / i) ,
332
+ ) . toBeVisible ( ) ;
333
+
334
+ // Verify the Free plan with Upcoming status exists
335
+ await expect (
336
+ u . po . page
337
+ . locator ( '.cl-profileSectionContent__subscriptionsList' )
338
+ . getByText ( 'Free' )
339
+ . locator ( 'xpath=..' )
340
+ . getByText ( 'Upcoming' ) ,
341
+ ) . toBeVisible ( ) ;
342
+ } finally {
343
+ // Clean up the trial user
344
+ await trialUser . deleteIfExists ( ) ;
345
+ }
346
+ } ) ;
347
+
246
348
test . describe ( 'in UserProfile' , ( ) => {
247
349
// test.describe.configure({ mode: 'serial' });
248
350
test ( 'renders pricing table, subscribes to a plan, revalidates payment sources on complete and then downgrades to free' , async ( {
0 commit comments