@@ -5,4 +5,80 @@ func createEmail() -> String {
5
5
let before = UUID ( ) . uuidString. prefix ( 8 )
6
6
let after = UUID ( ) . uuidString. prefix ( 6 )
7
7
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
+ }
8
84
}
0 commit comments