@@ -77,6 +77,42 @@ func TestDeleteTeamHard_DeletesAndIsIdempotent(t *testing.T) {
7777 require .False (t , deleted , "re-delete of a gone team is a clean no-op" )
7878}
7979
80+ // TestDeleteTeamHard_CascadesPendingCheckouts is the regression guard for
81+ // migration 069: a team that started a checkout has a pending_checkouts row, and
82+ // before 069 that FK had no ON DELETE CASCADE — so DeleteTeamHard (the e2e reap)
83+ // failed with `pending_checkouts_team_id_fkey` and the cohort team LEAKED. This
84+ // surfaced the instant test-cohort checkout was armed (a cohort Pro upgrade
85+ // creates a pending_checkouts row → the reap 503'd). With the cascade, deleting
86+ // the team removes its pending_checkouts rows and the reap succeeds.
87+ func TestDeleteTeamHard_CascadesPendingCheckouts (t * testing.T ) {
88+ skipUnlessE2EModelsDB (t )
89+ ctx := context .Background ()
90+ db , clean := testhelpers .SetupTestDB (t )
91+ defer clean ()
92+
93+ team , err := models .CreateTestCohortTeam (ctx , db , "cohort-with-checkout" )
94+ require .NoError (t , err )
95+
96+ // Seed a pending_checkouts row (the exact FK that used to block the delete).
97+ subID := "sub_test_" + uuid .NewString ()
98+ _ , err = db .ExecContext (ctx ,
99+ `INSERT INTO pending_checkouts (subscription_id, team_id, customer_email, plan_tier)
100+ VALUES ($1, $2, $3, $4)` ,
101+ subID , team .ID , "cohort@example.com" , "pro" )
102+ require .NoError (t , err , "seed pending_checkouts" )
103+
104+ // Pre-069 this returned the FK-violation error; with the cascade it succeeds.
105+ deleted , err := models .DeleteTeamHard (ctx , db , team .ID )
106+ require .NoError (t , err , "DeleteTeamHard must cascade pending_checkouts, not error on the FK" )
107+ require .True (t , deleted )
108+
109+ // The child row is gone too (cascaded), not orphaned.
110+ var n int
111+ require .NoError (t , db .QueryRowContext (ctx ,
112+ `SELECT count(*) FROM pending_checkouts WHERE subscription_id = $1` , subID ).Scan (& n ))
113+ require .Equal (t , 0 , n , "pending_checkouts row must be cascade-deleted with the team" )
114+ }
115+
80116func TestMarkTeamResourcesForReaper_RetiersAndExpires (t * testing.T ) {
81117 skipUnlessE2EModelsDB (t )
82118 ctx := context .Background ()
0 commit comments