@@ -5,6 +5,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest';
55const mocks = vi . hoisted ( ( ) => ( {
66 getUser : vi . fn ( ) ,
77 serverClient : vi . fn ( ) ,
8+ verifyOtp : vi . fn ( ) ,
89 createClient : vi . fn ( ( ) => ( { } ) )
910} ) ) ;
1011
@@ -121,3 +122,36 @@ describe('verify-sms session phone binding', () => {
121122 expect ( res . status ) . toBe ( 403 ) ;
122123 } ) ;
123124} ) ;
125+
126+ describe ( 'verify-sms OTP validation' , ( ) => {
127+ beforeEach ( ( ) => {
128+ vi . resetModules ( ) ;
129+ vi . clearAllMocks ( ) ;
130+ process . env . NEXT_PUBLIC_SUPABASE_URL = 'https://example.supabase.co' ;
131+ process . env . NEXT_PUBLIC_SUPABASE_ANON_KEY = 'anon-key' ;
132+ process . env . SUPABASE_SERVICE_ROLE_KEY = 'service-role-key' ;
133+ mocks . serverClient . mockResolvedValue ( {
134+ auth : {
135+ getUser : mocks . getUser ,
136+ verifyOtp : mocks . verifyOtp
137+ }
138+ } ) ;
139+ } ) ;
140+
141+ it ( 'rejects numeric verification codes before OTP verification' , async ( ) => {
142+ const { POST } = await import ( './route.js' ) ;
143+ const res = await POST ( new Request ( 'https://example.com/api/auth/verify-sms' , {
144+ method : 'POST' ,
145+ headers : { 'content-type' : 'application/json' } ,
146+ body : JSON . stringify ( {
147+ phoneNumber : '+15559999999' ,
148+ verificationCode : 123456
149+ } )
150+ } ) ) ;
151+ const body = await res . json ( ) ;
152+
153+ expect ( res . status ) . toBe ( 400 ) ;
154+ expect ( body . error ) . toBe ( 'Verification code must be 6 digits' ) ;
155+ expect ( mocks . verifyOtp ) . not . toHaveBeenCalled ( ) ;
156+ } ) ;
157+ } ) ;
0 commit comments