Skip to content

Commit 82b52c6

Browse files
Merge branch 'twitter-package' into refactor-remaining-packages
2 parents ec834b9 + 4a3eb71 commit 82b52c6

File tree

7 files changed

+250
-240
lines changed

7 files changed

+250
-240
lines changed

.github/workflows/swiftui-auth.yml

Lines changed: 111 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -22,35 +22,76 @@ permissions:
2222
contents: read
2323

2424
jobs:
25-
swiftui-auth:
25+
# Package Unit Tests (standalone, no emulator needed)
26+
unit-tests:
27+
name: Package Unit Tests
2628
runs-on: macos-15
27-
timeout-minutes: 60
29+
timeout-minutes: 20
2830
steps:
2931
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938
32+
33+
- name: Install xcpretty
34+
run: gem install xcpretty
35+
36+
- name: Select Xcode version
37+
run: sudo xcode-select -switch /Applications/Xcode_16.4.app/Contents/Developer
38+
39+
- name: Run FirebaseSwiftUI Package Unit Tests
40+
run: |
41+
set -o pipefail
42+
xcodebuild test \
43+
-scheme FirebaseUI-Package \
44+
-destination 'platform=iOS Simulator,name=iPhone 16 Pro' \
45+
-enableCodeCoverage YES \
46+
-resultBundlePath FirebaseSwiftUIPackageTests.xcresult | tee FirebaseSwiftUIPackageTests.log | xcpretty --test --color --simple
47+
48+
- name: Upload test logs
49+
if: failure()
50+
uses: actions/upload-artifact@v4
51+
with:
52+
name: unit-tests-logs
53+
path: FirebaseSwiftUIPackageTests.log
54+
55+
- name: Upload test results
56+
if: failure()
57+
uses: actions/upload-artifact@v4
58+
with:
59+
name: unit-tests-results
60+
path: FirebaseSwiftUIPackageTests.xcresult
61+
62+
# Integration Tests (requires emulator)
63+
integration-tests:
64+
name: Integration Tests
65+
runs-on: macos-15
66+
timeout-minutes: 20
67+
steps:
68+
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938
69+
3070
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a
3171
name: Install Node.js 20
3272
with:
3373
node-version: '20'
74+
3475
- uses: actions/setup-java@8df1039502a15bceb9433410b1a100fbe190c53b
3576
with:
3677
distribution: 'temurin'
3778
java-version: '17'
79+
3880
- name: Install Firebase
39-
run: |
40-
sudo npm i -g firebase-tools
81+
run: sudo npm i -g firebase-tools
82+
4183
- name: Start Firebase Emulator
4284
run: |
43-
sudo chown -R 501:20 "/Users/runner/.npm" && cd ./samples/swiftui/FirebaseSwiftUIExample/FirebaseSwiftUIExample && ./start-firebase-emulator.sh
85+
sudo chown -R 501:20 "/Users/runner/.npm"
86+
cd ./samples/swiftui/FirebaseSwiftUIExample/FirebaseSwiftUIExample
87+
./start-firebase-emulator.sh
88+
4489
- name: Install xcpretty
4590
run: gem install xcpretty
91+
4692
- name: Select Xcode version
47-
run: |
48-
sudo xcode-select -switch /Applications/Xcode_16.4.app/Contents/Developer
49-
- name: Run FirebaseSwiftUI Package Unit Tests
50-
run: |
51-
set -o pipefail
52-
xcodebuild test -scheme FirebaseUI-Package -destination 'platform=iOS Simulator,name=iPhone 16 Pro' -enableCodeCoverage YES -resultBundlePath FirebaseSwiftUIPackageTests.xcresult | tee FirebaseSwiftUIPackageTests.log | xcpretty --test --color --simple
53-
# Build for integration tests (builds app + integration test bundle)
93+
run: sudo xcode-select -switch /Applications/Xcode_16.4.app/Contents/Developer
94+
5495
- name: Build for Integration Tests
5596
run: |
5697
cd ./samples/swiftui/FirebaseSwiftUIExample
@@ -59,7 +100,7 @@ jobs:
59100
-scheme FirebaseSwiftUIExampleTests \
60101
-destination 'platform=iOS Simulator,name=iPhone 16 Pro' \
61102
-enableCodeCoverage YES | xcpretty --color --simple
62-
# Run integration tests
103+
63104
- name: Run Integration Tests
64105
run: |
65106
cd ./samples/swiftui/FirebaseSwiftUIExample
@@ -69,7 +110,54 @@ jobs:
69110
-destination 'platform=iOS Simulator,name=iPhone 16 Pro' \
70111
-enableCodeCoverage YES \
71112
-resultBundlePath FirebaseSwiftUIExampleTests.xcresult | tee FirebaseSwiftUIExampleTests.log | xcpretty --test --color --simple
72-
# Build for UI tests (reuses app build, builds UI test bundle)
113+
114+
- name: Upload test logs
115+
if: failure()
116+
uses: actions/upload-artifact@v4
117+
with:
118+
name: integration-tests-logs
119+
path: samples/swiftui/FirebaseSwiftUIExample/FirebaseSwiftUIExampleTests.log
120+
121+
- name: Upload test results
122+
if: failure()
123+
uses: actions/upload-artifact@v4
124+
with:
125+
name: integration-tests-results
126+
path: samples/swiftui/FirebaseSwiftUIExample/FirebaseSwiftUIExampleTests.xcresult
127+
128+
# UI Tests (requires emulator)
129+
ui-tests:
130+
name: UI Tests
131+
runs-on: macos-15
132+
timeout-minutes: 30
133+
steps:
134+
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938
135+
136+
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a
137+
name: Install Node.js 20
138+
with:
139+
node-version: '20'
140+
141+
- uses: actions/setup-java@8df1039502a15bceb9433410b1a100fbe190c53b
142+
with:
143+
distribution: 'temurin'
144+
java-version: '17'
145+
146+
- name: Install Firebase
147+
run: sudo npm i -g firebase-tools
148+
149+
- name: Start Firebase Emulator
150+
run: |
151+
sudo chown -R 501:20 "/Users/runner/.npm"
152+
cd ./samples/swiftui/FirebaseSwiftUIExample/FirebaseSwiftUIExample
153+
./start-firebase-emulator.sh
154+
155+
- name: Install xcpretty
156+
run: gem install xcpretty
157+
158+
- name: Select Xcode version
159+
run: sudo xcode-select -switch /Applications/Xcode_16.4.app/Contents/Developer
160+
73161
- name: Build for UI Tests
74162
run: |
75163
cd ./samples/swiftui/FirebaseSwiftUIExample
@@ -78,8 +166,8 @@ jobs:
78166
-scheme FirebaseSwiftUIExampleUITests \
79167
-destination 'platform=iOS Simulator,name=iPhone 16 Pro' \
80168
-enableCodeCoverage YES | xcpretty --color --simple
81-
# Run UI tests
82-
- name: Run View UI Tests
169+
170+
- name: Run UI Tests
83171
run: |
84172
cd ./samples/swiftui/FirebaseSwiftUIExample
85173
set -o pipefail
@@ -90,30 +178,17 @@ jobs:
90178
-maximum-concurrent-test-simulator-destinations 2 \
91179
-enableCodeCoverage YES \
92180
-resultBundlePath FirebaseSwiftUIExampleUITests.xcresult | tee FirebaseSwiftUIExampleUITests.log | xcpretty --test --color --simple
181+
93182
- name: Upload test logs
94183
if: failure()
95184
uses: actions/upload-artifact@v4
96185
with:
97-
name: swiftui-auth-test-logs
98-
path: |
99-
FirebaseSwiftUIPackageTests.log
100-
samples/swiftui/FirebaseSwiftUIExample/FirebaseSwiftUIExampleTests.log
101-
samples/swiftui/FirebaseSwiftUIExample/FirebaseSwiftUIExampleUITests.log
102-
- name: Upload FirebaseSwiftUIExampleUITests.xcresult bundle
103-
if: failure()
104-
uses: actions/upload-artifact@v4
105-
with:
106-
name: FirebaseSwiftUIExampleUITests.xcresult
107-
path: samples/swiftui/FirebaseSwiftUIExample/FirebaseSwiftUIExampleUITests.xcresult
108-
- name: Upload FirebaseSwiftUIExampleTests.xcresult bundle
109-
if: failure()
110-
uses: actions/upload-artifact@v4
111-
with:
112-
name: FirebaseSwiftUIExampleTests.xcresult
113-
path: samples/swiftui/FirebaseSwiftUIExample/FirebaseSwiftUIExampleTests.xcresult
114-
- name: Upload FirebaseSwiftUIPackageTests.xcresult bundle
186+
name: ui-tests-logs
187+
path: samples/swiftui/FirebaseSwiftUIExample/FirebaseSwiftUIExampleUITests.log
188+
189+
- name: Upload test results
115190
if: failure()
116191
uses: actions/upload-artifact@v4
117192
with:
118-
name: FirebaseSwiftUIPackageTests.xcresult
119-
path: FirebaseSwiftUIPackageTests.xcresult
193+
name: ui-tests-results
194+
path: samples/swiftui/FirebaseSwiftUIExample/FirebaseSwiftUIExampleUITests.xcresult

samples/swiftui/FirebaseSwiftUIExample/FirebaseSwiftUIExample/TestView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ struct TestView: View {
3333
Auth.auth().useEmulator(withHost: "localhost", port: 9099)
3434
Auth.auth().settings?.isAppVerificationDisabledForTesting = true
3535
Task {
36-
try await testCreateUser()
36+
try signOut()
3737
}
3838

3939
let isMfaEnabled = ProcessInfo.processInfo.arguments.contains("--mfa-enabled")

samples/swiftui/FirebaseSwiftUIExample/FirebaseSwiftUIExample/UITestUtils.swift

Lines changed: 3 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -8,123 +8,9 @@ import FirebaseAuth
88
import SwiftUI
99

1010
// UI Test Runner keys
11-
public let testRunner = CommandLine.arguments.contains("--auth-emulator")
12-
let verifyEmail = CommandLine.arguments.contains("--verify-email")
11+
public let testRunner = CommandLine.arguments.contains("--test-view-enabled")
1312

14-
public var testEmail: String? {
15-
guard let emailIndex = CommandLine.arguments.firstIndex(of: "--create-user"),
16-
CommandLine.arguments.indices.contains(emailIndex + 1)
17-
else { return nil }
18-
return CommandLine.arguments[emailIndex + 1]
13+
func signOut() throws {
14+
try Auth.auth().signOut()
1915
}
2016

21-
func testCreateUser() async throws {
22-
if let email = testEmail {
23-
let password = "123456"
24-
let auth = Auth.auth()
25-
let result = try await auth.createUser(withEmail: email, password: password)
26-
if verifyEmail {
27-
try await setEmailVerifiedInEmulator(for: result.user)
28-
}
29-
try auth.signOut()
30-
}
31-
}
32-
33-
/// Marks the given Firebase `user` as email-verified **in the Auth emulator**.
34-
/// Works in CI even if the email address doesn't exist.
35-
/// - Parameters:
36-
/// - user: The signed-in Firebase user you want to verify.
37-
/// - projectID: Your emulator project ID (e.g. "demo-project" or whatever you're using locally).
38-
/// - emulatorHost: Host:port for the Auth emulator. Defaults to localhost:9099.
39-
func setEmailVerifiedInEmulator(for user: User,
40-
projectID: String = "flutterfire-e2e-tests",
41-
emulatorHost: String = "localhost:9099") async throws {
42-
43-
guard let email = user.email else {
44-
throw NSError(domain: "EmulatorError", code: 1,
45-
userInfo: [
46-
NSLocalizedDescriptionKey: "User has no email; cannot look up OOB code in emulator",
47-
])
48-
}
49-
50-
// 1) Trigger a verification email -> creates an OOB code in the emulator.
51-
try await sendVerificationEmail(user)
52-
53-
// 2) Read OOB codes from the emulator and find the VERIFY_EMAIL code for this user.
54-
let base = "http://\(emulatorHost)"
55-
let oobURL = URL(string: "\(base)/emulator/v1/projects/\(projectID)/oobCodes")!
56-
57-
let (oobData, oobResp) = try await URLSession.shared.data(from: oobURL)
58-
guard (oobResp as? HTTPURLResponse)?.statusCode == 200 else {
59-
let body = String(data: oobData, encoding: .utf8) ?? ""
60-
throw NSError(domain: "EmulatorError", code: 2,
61-
userInfo: [
62-
NSLocalizedDescriptionKey: "Failed to fetch oobCodes. Response: \(body)",
63-
])
64-
}
65-
66-
struct OobEnvelope: Decodable { let oobCodes: [OobItem] }
67-
struct OobItem: Decodable {
68-
let oobCode: String
69-
let email: String
70-
let requestType: String
71-
let creationTime: String? // RFC3339/ISO8601; optional for safety
72-
}
73-
74-
let envelope = try JSONDecoder().decode(OobEnvelope.self, from: oobData)
75-
76-
// Pick the most recent VERIFY_EMAIL code for this email (in case there are multiple).
77-
let iso = ISO8601DateFormatter()
78-
let codeItem = envelope.oobCodes
79-
.filter {
80-
$0.email.caseInsensitiveCompare(email) == .orderedSame && $0.requestType == "VERIFY_EMAIL"
81-
}
82-
.sorted {
83-
let d0 = $0.creationTime.flatMap { iso.date(from: $0) } ?? .distantPast
84-
let d1 = $1.creationTime.flatMap { iso.date(from: $0) } ?? .distantPast
85-
return d0 > d1
86-
}
87-
.first
88-
89-
guard let oobCode = codeItem?.oobCode else {
90-
throw NSError(domain: "EmulatorError", code: 3,
91-
userInfo: [
92-
NSLocalizedDescriptionKey: "No VERIFY_EMAIL oobCode found for \(email) in emulator",
93-
])
94-
}
95-
96-
// 3) Apply the OOB code via the emulator's identitytoolkit endpoint.
97-
// Note: API key value does not matter when talking to the emulator.
98-
var applyReq = URLRequest(
99-
url: URL(string: "\(base)/identitytoolkit.googleapis.com/v1/accounts:update?key=anything")!
100-
)
101-
applyReq.httpMethod = "POST"
102-
applyReq.setValue("application/json", forHTTPHeaderField: "Content-Type")
103-
applyReq.httpBody = try JSONSerialization.data(withJSONObject: ["oobCode": oobCode], options: [])
104-
105-
let (applyData, applyResp) = try await URLSession.shared.data(for: applyReq)
106-
guard let http = applyResp as? HTTPURLResponse, http.statusCode == 200 else {
107-
let body = String(data: applyData, encoding: .utf8) ?? ""
108-
throw NSError(domain: "EmulatorError", code: 4,
109-
userInfo: [
110-
NSLocalizedDescriptionKey: "Applying oobCode failed. Status \((applyResp as? HTTPURLResponse)?.statusCode ?? -1). Body: \(body)",
111-
])
112-
}
113-
114-
115-
// 4) Reload the user to reflect the new verification state.
116-
try await user.reload()
117-
}
118-
119-
/// Small async helper to call FirebaseAuth's callback-based `sendEmailVerification` on iOS.
120-
private func sendVerificationEmail(_ user: User) async throws {
121-
try await withCheckedThrowingContinuation { (cont: CheckedContinuation<Void, Error>) in
122-
user.sendEmailVerification { error in
123-
if let error = error {
124-
cont.resume(throwing: error)
125-
} else {
126-
cont.resume()
127-
}
128-
}
129-
}
130-
}

0 commit comments

Comments
 (0)