@@ -1013,4 +1013,219 @@ describe('SubscriptionDetails', () => {
10131013 expect ( queryByRole ( 'button' , { name : / O p e n m e n u / i } ) ) . toBeNull ( ) ;
10141014 } ) ;
10151015 } ) ;
1016+
1017+ it ( 'active free trial subscription shows correct labels and behavior' , async ( ) => {
1018+ const { wrapper, fixtures } = await createFixtures ( f => {
1019+ f . withUser ( { email_addresses : [ 'test@clerk.com' ] } ) ;
1020+ } ) ;
1021+
1022+ fixtures . clerk . billing . getSubscription . mockResolvedValue ( {
1023+ activeAt : new Date ( '2021-01-01' ) ,
1024+ createdAt : new Date ( '2021-01-01' ) ,
1025+ pastDueAt : null ,
1026+ id : 'sub_123' ,
1027+ nextPayment : {
1028+ amount : {
1029+ amount : 1000 ,
1030+ amountFormatted : '10.00' ,
1031+ currency : 'USD' ,
1032+ currencySymbol : '$' ,
1033+ } ,
1034+ date : new Date ( '2021-02-01' ) ,
1035+ } ,
1036+ status : 'active' ,
1037+ subscriptionItems : [
1038+ {
1039+ id : 'sub_123' ,
1040+ plan : {
1041+ id : 'plan_123' ,
1042+ name : 'Pro Plan' ,
1043+ fee : {
1044+ amount : 1000 ,
1045+ amountFormatted : '10.00' ,
1046+ currencySymbol : '$' ,
1047+ currency : 'USD' ,
1048+ } ,
1049+ annualFee : {
1050+ amount : 10000 ,
1051+ amountFormatted : '100.00' ,
1052+ currencySymbol : '$' ,
1053+ currency : 'USD' ,
1054+ } ,
1055+ annualMonthlyFee : {
1056+ amount : 8333 ,
1057+ amountFormatted : '83.33' ,
1058+ currencySymbol : '$' ,
1059+ currency : 'USD' ,
1060+ } ,
1061+ description : 'Pro Plan' ,
1062+ hasBaseFee : true ,
1063+ isRecurring : true ,
1064+ isDefault : false ,
1065+ } ,
1066+ createdAt : new Date ( '2021-01-01' ) ,
1067+ periodStart : new Date ( '2021-01-01' ) ,
1068+ periodEnd : new Date ( '2021-02-01' ) ,
1069+ canceledAt : null ,
1070+ paymentSourceId : 'src_123' ,
1071+ planPeriod : 'month' ,
1072+ status : 'active' ,
1073+ isFreeTrial : true ,
1074+ } ,
1075+ ] ,
1076+ } ) ;
1077+
1078+ const { getByRole, getByText, getAllByText, queryByText, userEvent } = render (
1079+ < Drawer . Root
1080+ open
1081+ onOpenChange = { ( ) => { } }
1082+ >
1083+ < SubscriptionDetails />
1084+ </ Drawer . Root > ,
1085+ { wrapper } ,
1086+ ) ;
1087+
1088+ await waitFor ( ( ) => {
1089+ expect ( getByRole ( 'heading' , { name : / S u b s c r i p t i o n / i } ) ) . toBeVisible ( ) ;
1090+ expect ( getByText ( 'Pro Plan' ) ) . toBeVisible ( ) ;
1091+ expect ( getByText ( 'Free trial' ) ) . toBeVisible ( ) ;
1092+ expect ( getByText ( '$10.00 / Month' ) ) . toBeVisible ( ) ;
1093+
1094+ // Free trial specific labels
1095+ expect ( getByText ( 'Trial started on' ) ) . toBeVisible ( ) ;
1096+ expect ( getByText ( 'January 1, 2021' ) ) . toBeVisible ( ) ;
1097+ expect ( getByText ( 'Trial ends on' ) ) . toBeVisible ( ) ;
1098+
1099+ // Should have multiple instances of February 1, 2021 (trial end and first payment)
1100+ const februaryDates = getAllByText ( 'February 1, 2021' ) ;
1101+ expect ( februaryDates . length ) . toBeGreaterThan ( 1 ) ;
1102+
1103+ // Payment related labels should use "first payment" wording
1104+ expect ( getByText ( 'First payment on' ) ) . toBeVisible ( ) ;
1105+ expect ( getByText ( 'First payment amount' ) ) . toBeVisible ( ) ;
1106+ expect ( getByText ( '$10.00' ) ) . toBeVisible ( ) ;
1107+
1108+ // Should not show regular subscription labels
1109+ expect ( queryByText ( 'Subscribed on' ) ) . toBeNull ( ) ;
1110+ expect ( queryByText ( 'Renews at' ) ) . toBeNull ( ) ;
1111+ expect ( queryByText ( 'Next payment on' ) ) . toBeNull ( ) ;
1112+ expect ( queryByText ( 'Next payment amount' ) ) . toBeNull ( ) ;
1113+ } ) ;
1114+
1115+ // Test the menu shows free trial specific options
1116+ const menuButton = getByRole ( 'button' , { name : / O p e n m e n u / i } ) ;
1117+ expect ( menuButton ) . toBeVisible ( ) ;
1118+ await userEvent . click ( menuButton ) ;
1119+
1120+ await waitFor ( ( ) => {
1121+ expect ( getByText ( 'Cancel free trial' ) ) . toBeVisible ( ) ;
1122+ } ) ;
1123+ } ) ;
1124+
1125+ it ( 'allows cancelling a free trial with specific dialog text' , async ( ) => {
1126+ const { wrapper, fixtures } = await createFixtures ( f => {
1127+ f . withUser ( { email_addresses : [ 'test@clerk.com' ] } ) ;
1128+ } ) ;
1129+
1130+ const cancelSubscriptionMock = jest . fn ( ) . mockResolvedValue ( { } ) ;
1131+
1132+ fixtures . clerk . billing . getSubscription . mockResolvedValue ( {
1133+ activeAt : new Date ( '2021-01-01' ) ,
1134+ createdAt : new Date ( '2021-01-01' ) ,
1135+ pastDueAt : null ,
1136+ id : 'sub_123' ,
1137+ nextPayment : {
1138+ amount : {
1139+ amount : 1000 ,
1140+ amountFormatted : '10.00' ,
1141+ currency : 'USD' ,
1142+ currencySymbol : '$' ,
1143+ } ,
1144+ date : new Date ( '2021-02-01' ) ,
1145+ } ,
1146+ status : 'active' ,
1147+ subscriptionItems : [
1148+ {
1149+ id : 'sub_123' ,
1150+ plan : {
1151+ id : 'plan_123' ,
1152+ name : 'Pro Plan' ,
1153+ fee : {
1154+ amount : 1000 ,
1155+ amountFormatted : '10.00' ,
1156+ currencySymbol : '$' ,
1157+ currency : 'USD' ,
1158+ } ,
1159+ annualFee : {
1160+ amount : 10000 ,
1161+ amountFormatted : '100.00' ,
1162+ currencySymbol : '$' ,
1163+ currency : 'USD' ,
1164+ } ,
1165+ annualMonthlyFee : {
1166+ amount : 8333 ,
1167+ amountFormatted : '83.33' ,
1168+ currencySymbol : '$' ,
1169+ currency : 'USD' ,
1170+ } ,
1171+ description : 'Pro Plan' ,
1172+ hasBaseFee : true ,
1173+ isRecurring : true ,
1174+ isDefault : false ,
1175+ } ,
1176+ createdAt : new Date ( '2021-01-01' ) ,
1177+ periodStart : new Date ( '2021-01-01' ) ,
1178+ periodEnd : new Date ( '2021-02-01' ) ,
1179+ canceledAt : null ,
1180+ paymentSourceId : 'src_123' ,
1181+ planPeriod : 'month' ,
1182+ status : 'active' ,
1183+ isFreeTrial : true ,
1184+ cancel : cancelSubscriptionMock ,
1185+ } ,
1186+ ] ,
1187+ } ) ;
1188+
1189+ const { getByRole, getByText, userEvent } = render (
1190+ < Drawer . Root
1191+ open
1192+ onOpenChange = { ( ) => { } }
1193+ >
1194+ < SubscriptionDetails />
1195+ </ Drawer . Root > ,
1196+ { wrapper } ,
1197+ ) ;
1198+
1199+ // Wait for the subscription details to render
1200+ await waitFor ( ( ) => {
1201+ expect ( getByText ( 'Pro Plan' ) ) . toBeVisible ( ) ;
1202+ expect ( getByText ( 'Free trial' ) ) . toBeVisible ( ) ;
1203+ } ) ;
1204+
1205+ // Open the menu
1206+ const menuButton = getByRole ( 'button' , { name : / O p e n m e n u / i } ) ;
1207+ await userEvent . click ( menuButton ) ;
1208+
1209+ // Wait for the cancel option to appear and click it
1210+ await userEvent . click ( getByText ( 'Cancel free trial' ) ) ;
1211+
1212+ await waitFor ( ( ) => {
1213+ // Should show free trial specific cancellation dialog
1214+ expect ( getByText ( 'Cancel free trial for Pro Plan plan?' ) ) . toBeVisible ( ) ;
1215+ expect (
1216+ getByText (
1217+ 'You’re about to cancel your free trial for the Pro Plan plan. If you cancel now, you’ll lose access to the plan’s features right away and won’t be able to start the trial again.' ,
1218+ ) ,
1219+ ) . toBeVisible ( ) ;
1220+ expect ( getByText ( 'Keep free trial' ) ) . toBeVisible ( ) ;
1221+ } ) ;
1222+
1223+ // Click the cancel button in the dialog
1224+ await userEvent . click ( getByText ( 'Cancel free trial' ) ) ;
1225+
1226+ // Assert that the cancelSubscription method was called
1227+ await waitFor ( ( ) => {
1228+ expect ( cancelSubscriptionMock ) . toHaveBeenCalled ( ) ;
1229+ } ) ;
1230+ } ) ;
10161231} ) ;
0 commit comments