@@ -5,4 +5,80 @@ func createEmail() -> String {
55 let before = UUID ( ) . uuidString. prefix ( 8 )
66 let after = UUID ( ) . uuidString. prefix ( 6 )
77 return " \( before) @ \( after) .com "
8+ }
9+
10+ func verifyEmailInEmulator( email: String ,
11+ idToken: String ,
12+ projectID: String = " flutterfire-e2e-tests " ,
13+ emulatorHost: String = " localhost:9099 " ) async throws {
14+ let base = " http:// \( emulatorHost) "
15+
16+
17+ // Step 1: Trigger email verification (creates OOB code in emulator)
18+ var sendReq = URLRequest (
19+ url: URL ( string: " \( base) /identitytoolkit.googleapis.com/v1/accounts:sendOobCode?key=fake-api-key " ) !
20+ )
21+ sendReq. httpMethod = " POST "
22+ sendReq. setValue ( " application/json " , forHTTPHeaderField: " Content-Type " )
23+ sendReq. httpBody = try JSONSerialization . data ( withJSONObject: [
24+ " requestType " : " VERIFY_EMAIL " ,
25+ " idToken " : idToken
26+ ] )
27+
28+
29+ let ( _, sendResp) = try await URLSession . shared. data ( for: sendReq)
30+ guard let http = sendResp as? HTTPURLResponse , http. statusCode == 200 else {
31+ throw NSError ( domain: " EmulatorError " , code: 1 ,
32+ userInfo: [ NSLocalizedDescriptionKey: " Failed to send verification email " ] )
33+ }
34+
35+
36+ // Step 2: Fetch OOB codes from emulator
37+ let oobURL = URL ( string: " \( base) /emulator/v1/projects/ \( projectID) /oobCodes " ) !
38+ let ( oobData, oobResp) = try await URLSession . shared. data ( from: oobURL)
39+ guard ( oobResp as? HTTPURLResponse ) ? . statusCode == 200 else {
40+ throw NSError ( domain: " EmulatorError " , code: 2 ,
41+ userInfo: [ NSLocalizedDescriptionKey: " Failed to fetch OOB codes " ] )
42+ }
43+
44+
45+ struct OobEnvelope : Decodable { let oobCodes : [ OobItem ] }
46+ struct OobItem : Decodable {
47+ let oobCode : String
48+ let email : String
49+ let requestType : String
50+ let creationTime : String ?
51+ }
52+
53+
54+ let envelope = try JSONDecoder ( ) . decode ( OobEnvelope . self, from: oobData)
55+
56+
57+ // Step 3: Find most recent VERIFY_EMAIL code for this email
58+ let iso = ISO8601DateFormatter ( )
59+ let codeItem = envelope. oobCodes
60+ . filter {
61+ $0. email. caseInsensitiveCompare ( email) == . orderedSame && $0. requestType == " VERIFY_EMAIL "
62+ }
63+ . sorted {
64+ let d0 = $0. creationTime. flatMap { iso. date ( from: $0) } ?? . distantPast
65+ let d1 = $1. creationTime. flatMap { iso. date ( from: $0) } ?? . distantPast
66+ return d0 > d1
67+ }
68+ . first
69+
70+
71+ guard let oobCode = codeItem? . oobCode else {
72+ throw NSError ( domain: " EmulatorError " , code: 3 ,
73+ userInfo: [ NSLocalizedDescriptionKey: " No VERIFY_EMAIL OOB code found for \( email) " ] )
74+ }
75+
76+
77+ // Step 4: Apply the OOB code (simulate clicking verification link)
78+ let verifyURL = URL ( string: " \( base) /emulator/action?mode=verifyEmail&oobCode= \( oobCode) &apiKey=fake-api-key " ) !
79+ let ( _, verifyResp) = try await URLSession . shared. data ( from: verifyURL)
80+ guard ( verifyResp as? HTTPURLResponse ) ? . statusCode == 200 else {
81+ throw NSError ( domain: " EmulatorError " , code: 4 ,
82+ userInfo: [ NSLocalizedDescriptionKey: " Failed to apply OOB code " ] )
83+ }
884}
0 commit comments