generated from StanfordBDHG/SwiftPackageTemplate
-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rework FirestoreAccountStorage implementation (#25)
# Rework FirestoreAccountStorage implementation ## ♻️ Current situation & Problem This PR fixes several issues identified within #24. As it turns out, we completely forgot to add testing for this component. This follow-up PR addresses some of the issues and adds proper UI testing. ## ⚙️ Release Notes * Fixes several issues with the `FirestoreAccountStorage` module ## 📚 Documentation -- ## ✅ Testing We added testing for the respective components. ## 📝 Code of Conduct & Contributing Guidelines By submitting creating this pull request, you agree to follow our [Code of Conduct](https://github.com/StanfordSpezi/.github/blob/main/CODE_OF_CONDUCT.md) and [Contributing Guidelines](https://github.com/StanfordSpezi/.github/blob/main/CONTRIBUTING.md): - [x] I agree to follow the [Code of Conduct](https://github.com/StanfordSpezi/.github/blob/main/CODE_OF_CONDUCT.md) and [Contributing Guidelines](https://github.com/StanfordSpezi/.github/blob/main/CONTRIBUTING.md).
- Loading branch information
Showing
13 changed files
with
335 additions
and
56 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
42 changes: 42 additions & 0 deletions
42
Tests/UITests/TestApp/FirebaseAccountStorage/AccountStorageTestStandard.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// | ||
// This source file is part of the Stanford Spezi open-source project | ||
// | ||
// SPDX-FileCopyrightText: 2022 Stanford University and the project authors (see CONTRIBUTORS.md) | ||
// | ||
// SPDX-License-Identifier: MIT | ||
// | ||
|
||
import FirebaseFirestore | ||
import Spezi | ||
import SpeziAccount | ||
import SpeziFirebaseAccountStorage | ||
|
||
|
||
actor AccountStorageTestStandard: Standard, AccountStorageStandard { | ||
static var collection: CollectionReference { | ||
Firestore.firestore().collection("users") | ||
} | ||
|
||
@Dependency var storage = FirestoreAccountStorage(storeIn: collection) | ||
|
||
|
||
func create(_ identifier: AdditionalRecordId, _ details: SignupDetails) async throws { | ||
try await storage.create(identifier, details) | ||
} | ||
|
||
func load(_ identifier: AdditionalRecordId, _ keys: [any AccountKey.Type]) async throws -> PartialAccountDetails { | ||
try await storage.load(identifier, keys) | ||
} | ||
|
||
func modify(_ identifier: AdditionalRecordId, _ modifications: SpeziAccount.AccountModifications) async throws { | ||
try await storage.modify(identifier, modifications) | ||
} | ||
|
||
func clear(_ identifier: AdditionalRecordId) async { | ||
await storage.clear(identifier) | ||
} | ||
|
||
func delete(_ identifier: AdditionalRecordId) async throws { | ||
try await storage.delete(identifier) | ||
} | ||
} |
53 changes: 53 additions & 0 deletions
53
Tests/UITests/TestApp/FirebaseAccountStorage/BiographyKey.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// | ||
// This source file is part of the Spezi open-source project | ||
// | ||
// SPDX-FileCopyrightText: 2023 Stanford University and the project authors (see CONTRIBUTORS.md) | ||
// | ||
// SPDX-License-Identifier: MIT | ||
// | ||
|
||
import SpeziAccount | ||
import SpeziValidation | ||
import SwiftUI | ||
|
||
|
||
struct BiographyKey: AccountKey { | ||
typealias Value = String | ||
|
||
|
||
static let name: LocalizedStringResource = "Biography" // we don't bother to translate | ||
static let category: AccountKeyCategory = .personalDetails | ||
} | ||
|
||
|
||
extension AccountKeys { | ||
var biography: BiographyKey.Type { | ||
BiographyKey.self | ||
} | ||
} | ||
|
||
|
||
extension AccountValues { | ||
var biography: String? { | ||
storage[BiographyKey.self] | ||
} | ||
} | ||
|
||
|
||
extension BiographyKey { | ||
public struct DataEntry: DataEntryView { | ||
public typealias Key = BiographyKey | ||
|
||
|
||
@Binding private var biography: Value | ||
|
||
public init(_ value: Binding<Value>) { | ||
self._biography = value | ||
} | ||
|
||
public var body: some View { | ||
VerifiableTextField(Key.name, text: $biography) | ||
.autocorrectionDisabled() | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// | ||
// This source file is part of the Stanford Spezi open-source project | ||
// | ||
// SPDX-FileCopyrightText: 2023 Stanford University and the project authors (see CONTRIBUTORS.md) | ||
// | ||
// SPDX-License-Identifier: MIT | ||
// | ||
|
||
import Foundation | ||
|
||
|
||
enum FeatureFlags { | ||
static let accountStorageTests = ProcessInfo.processInfo.arguments.contains("--account-storage") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
86 changes: 86 additions & 0 deletions
86
Tests/UITests/TestAppUITests/FirebaseAccountStorageTests.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
// | ||
// This source file is part of the Stanford Spezi open-source project | ||
// | ||
// SPDX-FileCopyrightText: 2023 Stanford University and the project authors (see CONTRIBUTORS.md) | ||
// | ||
// SPDX-License-Identifier: MIT | ||
// | ||
|
||
import XCTest | ||
import XCTestExtensions | ||
|
||
|
||
final class FirebaseAccountStorageTests: XCTestCase { | ||
@MainActor | ||
override func setUp() async throws { | ||
try await super.setUp() | ||
|
||
continueAfterFailure = false | ||
|
||
try disablePasswordAutofill() | ||
|
||
try await FirebaseClient.deleteAllAccounts() | ||
try await Task.sleep(for: .seconds(0.5)) | ||
} | ||
|
||
@MainActor | ||
func testAdditionalAccountStorage() async throws { | ||
let app = XCUIApplication() | ||
app.launchArguments = ["--account-storage"] | ||
app.launch() | ||
|
||
XCTAssert(app.buttons["FirebaseAccount"].waitForExistence(timeout: 10.0)) | ||
app.buttons["FirebaseAccount"].tap() | ||
|
||
if app.buttons["Logout"].waitForExistence(timeout: 5.0) && app.buttons["Logout"].isHittable { | ||
app.buttons["Logout"].tap() | ||
} | ||
|
||
|
||
try app.signup( | ||
username: "[email protected]", | ||
password: "TestPassword1", | ||
givenName: "Test1", | ||
familyName: "Username1", | ||
biography: "Hello Stanford" | ||
) | ||
|
||
|
||
XCTAssertTrue(app.buttons["Account Overview"].waitForExistence(timeout: 2.0)) | ||
app.buttons["Account Overview"].tap() | ||
XCTAssertTrue(app.staticTexts["Biography, Hello Stanford"].waitForExistence(timeout: 2.0)) | ||
|
||
|
||
// TEST ACCOUNT EDIT | ||
XCTAssertTrue(app.navigationBars.buttons["Edit"].exists) | ||
app.navigationBars.buttons["Edit"].tap() | ||
|
||
try app.textFields["Biography"].enter(value: "2") | ||
|
||
XCTAssertTrue(app.navigationBars.buttons["Done"].exists) | ||
app.navigationBars.buttons["Done"].tap() | ||
|
||
XCTAssertTrue(app.staticTexts["Biography, Hello Stanford2"].waitForExistence(timeout: 2.0)) | ||
|
||
// TEST ACCOUNT DELETION | ||
XCTAssertTrue(app.navigationBars.buttons["Edit"].exists) | ||
app.navigationBars.buttons["Edit"].tap() | ||
|
||
XCTAssertTrue(app.buttons["Delete Account"].waitForExistence(timeout: 4.0)) | ||
app.buttons["Delete Account"].tap() | ||
|
||
let alert = "Are you sure you want to delete your account?" | ||
XCTAssertTrue(XCUIApplication().alerts[alert].waitForExistence(timeout: 6.0)) | ||
XCUIApplication().alerts[alert].scrollViews.otherElements.buttons["Delete"].tap() | ||
|
||
XCTAssertTrue(app.alerts["Authentication Required"].waitForExistence(timeout: 2.0)) | ||
XCTAssertTrue(app.alerts["Authentication Required"].secureTextFields["Password"].waitForExistence(timeout: 0.5)) | ||
app.typeText("TestPassword1") // the password field has focus already | ||
XCTAssertTrue(app.alerts["Authentication Required"].buttons["Login"].waitForExistence(timeout: 0.5)) | ||
app.alerts["Authentication Required"].buttons["Login"].tap() | ||
|
||
sleep(2) | ||
let accountsNew = try await FirebaseClient.getAllAccounts() | ||
XCTAssertTrue(accountsNew.isEmpty) | ||
} | ||
} |
Oops, something went wrong.