@@ -62,6 +62,18 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withBilling] })('pricing tabl
6262 await u . po . signIn . waitForMounted ( ) ;
6363 await expect ( u . po . page . getByText ( 'Checkout' ) ) . toBeHidden ( ) ;
6464 } ) ;
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+ } ) ;
6577 } ) ;
6678
6779 test . describe ( 'when signed in flow' , ( ) => {
@@ -243,6 +255,96 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withBilling] })('pricing tabl
243255 await newFakeUser . deleteIfExists ( ) ;
244256 } ) ;
245257
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+
246348 test . describe ( 'in UserProfile' , ( ) => {
247349 // test.describe.configure({ mode: 'serial' });
248350 test ( 'renders pricing table, subscribes to a plan, revalidates payment sources on complete and then downgrades to free' , async ( {
0 commit comments