[PM-27143] Add default bundle for APITestData in each framework (#2156)

This commit is contained in:
Matt Czech 2025-11-21 11:38:32 -06:00 committed by GitHub
parent fc2dafc7f1
commit 820865c290
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 88 additions and 89 deletions

View File

@ -1,9 +1,4 @@
import TestHelpers import TestHelpers
import XCTest import XCTest
open class BitwardenTestCase: BaseBitwardenTestCase { open class BitwardenTestCase: BaseBitwardenTestCase {}
@MainActor
override open class func setUp() {
TestDataHelpers.defaultBundle = Bundle(for: Self.self)
}
}

View File

@ -0,0 +1,12 @@
import TestHelpers
/// `APITestData` helpers that load the resource from the `AuthenticatorShared` bundle.
extension APITestData {
static func loadFromBundle(resource: String, extension: String) -> APITestData {
loadFromBundle(resource: resource, extension: `extension`, bundle: .authenticatorShared)
}
static func loadFromJsonBundle(resource: String) -> APITestData {
loadFromJsonBundle(resource: resource, bundle: .authenticatorShared)
}
}

View File

@ -0,0 +1,10 @@
import Foundation
class AuthenticatorSharedBundleFinder {
static let bundle = Bundle(for: AuthenticatorSharedBundleFinder.self)
}
public extension Bundle {
/// The bundle for the `AuthenticatorShared` target.
static let authenticatorShared = AuthenticatorSharedBundleFinder.bundle
}

View File

@ -7,8 +7,6 @@ open class BitwardenTestCase: BaseBitwardenTestCase {
override open class func setUp() { override open class func setUp() {
// Apply default appearances for snapshot tests. // Apply default appearances for snapshot tests.
UI.applyDefaultAppearances() UI.applyDefaultAppearances()
TestDataHelpers.defaultBundle = Bundle(for: Self.self)
} }
/// Executes any logic that should be applied before each test runs. /// Executes any logic that should be applied before each test runs.

View File

@ -14,111 +14,70 @@ public extension APITestData {
// MARK: Create Account // MARK: Create Account
/// Test data of an invalid model state with no validation errors. /// Test data of an invalid model state with no validation errors.
static let createAccountNilValidationErrors = loadFromJsonBundle( static let createAccountNilValidationErrors = loadFromJsonBundle(resource: "CreateAccountNilValidationErrors")
resource: "CreateAccountNilValidationErrors",
bundle: BitwardenKitMocksBundleFinder.bundle,
)
/// Test data with a validation error of "User verification failed." /// Test data with a validation error of "User verification failed."
static let deleteAccountRequestFailure = loadFromJsonBundle( static let deleteAccountRequestFailure = loadFromJsonBundle(resource: "DeleteAccountRequestFailure")
resource: "DeleteAccountRequestFailure",
bundle: BitwardenKitMocksBundleFinder.bundle,
)
/// Test data with several leaked passwords. /// Test data with several leaked passwords.
static let hibpLeakedPasswords = loadFromBundle( static let hibpLeakedPasswords = loadFromBundle(resource: "hibpLeakedPasswords", extension: "txt")
resource: "hibpLeakedPasswords",
extension: "txt",
bundle: BitwardenKitMocksBundleFinder.bundle,
)
/// Test data with an invalid username/password error. /// Test data with an invalid username/password error.
static let responseValidationError = loadFromJsonBundle( static let responseValidationError = loadFromJsonBundle(resource: "ResponseValidationError")
resource: "ResponseValidationError",
bundle: BitwardenKitMocksBundleFinder.bundle,
)
// MARK: Pre-Login // MARK: Pre-Login
/// Test data for prelogin success. /// Test data for prelogin success.
static let preLoginSuccess = loadFromJsonBundle( static let preLoginSuccess = loadFromJsonBundle(resource: "PreLoginSuccess")
resource: "PreLoginSuccess",
bundle: BitwardenKitMocksBundleFinder.bundle,
)
// MARK: Register Finish // MARK: Register Finish
/// Test data with a validation error of "Email 'j@a.com' is already taken." /// Test data with a validation error of "Email 'j@a.com' is already taken."
static let registerFinishAccountAlreadyExists = loadFromJsonBundle( static let registerFinishAccountAlreadyExists = loadFromJsonBundle(resource: "RegisterFinishAccountAlreadyExists")
resource: "RegisterFinishAccountAlreadyExists",
bundle: BitwardenKitMocksBundleFinder.bundle,
)
/// Test data with a validation error of /// Test data with a validation error of
/// "The field MasterPasswordHint must be a string with a maximum length of 50." /// "The field MasterPasswordHint must be a string with a maximum length of 50."
static let registerFinishHintTooLong = loadFromJsonBundle( static let registerFinishHintTooLong = loadFromJsonBundle(resource: "RegisterFinishHintTooLong")
resource: "RegisterFinishHintTooLong",
bundle: BitwardenKitMocksBundleFinder.bundle,
)
/// Test data with a validation error of "The Email field is not a supported e-mail address format." /// Test data with a validation error of "The Email field is not a supported e-mail address format."
static let registerFinishInvalidEmailFormat = loadFromJsonBundle( static let registerFinishInvalidEmailFormat = loadFromJsonBundle(resource: "RegisterFinishInvalidEmailFormat")
resource: "RegisterFinishInvalidEmailFormat",
bundle: BitwardenKitMocksBundleFinder.bundle,
)
/// Test data of a request to create an account for `example@email.com` /// Test data of a request to create an account for `example@email.com`
static let registerFinishRequest = loadFromJsonBundle( static let registerFinishRequest = loadFromJsonBundle(resource: "RegisterFinishRequest")
resource: "RegisterFinishRequest",
bundle: BitwardenKitMocksBundleFinder.bundle,
)
/// Test data of a successful account creation. /// Test data of a successful account creation.
static let registerFinishSuccess = loadFromJsonBundle( static let registerFinishSuccess = loadFromJsonBundle(resource: "RegisterFinishSuccess")
resource: "RegisterFinishSuccess",
bundle: BitwardenKitMocksBundleFinder.bundle,
)
// MARK: Request Password Hint // MARK: Request Password Hint
/// Test data for a failure for password hint. /// Test data for a failure for password hint.
static let passwordHintFailure = loadFromJsonBundle( static let passwordHintFailure = loadFromJsonBundle(resource: "PasswordHintFailure")
resource: "PasswordHintFailure",
bundle: BitwardenKitMocksBundleFinder.bundle,
)
// MARK: Start Registration // MARK: Start Registration
/// Test data with a validation error of "Email 'j@a.com' is already taken." /// Test data with a validation error of "Email 'j@a.com' is already taken."
static let startRegistrationEmailAlreadyExists = loadFromJsonBundle( static let startRegistrationEmailAlreadyExists = loadFromJsonBundle(
resource: "StartRegistrationEmailAlreadyExists", resource: "StartRegistrationEmailAlreadyExists",
bundle: BitwardenKitMocksBundleFinder.bundle,
) )
/// Test data with a validation error of "The field Email must be a string with a maximum length of 256." /// Test data with a validation error of "The field Email must be a string with a maximum length of 256."
static let startRegistrationEmailExceedsMaxLength = loadFromJsonBundle( static let startRegistrationEmailExceedsMaxLength = loadFromJsonBundle(
resource: "StartRegistrationEmailExceedsMaxLength", resource: "StartRegistrationEmailExceedsMaxLength",
bundle: BitwardenKitMocksBundleFinder.bundle,
) )
/// Test data with a validation error of /// Test data with a validation error of
static let startRegistrationInvalidEmailFormat = loadFromJsonBundle( static let startRegistrationInvalidEmailFormat = loadFromJsonBundle(
resource: "StartRegistrationInvalidEmailFormat", resource: "StartRegistrationInvalidEmailFormat",
bundle: BitwardenKitMocksBundleFinder.bundle,
) )
/// Test data for success with a registration start. /// Test data for success with a registration start.
static let startRegistrationSuccess = loadFromBundle( static let startRegistrationSuccess = loadFromBundle(
resource: "StartRegistrationSuccess", resource: "StartRegistrationSuccess",
extension: "txt", extension: "txt",
bundle: BitwardenKitMocksBundleFinder.bundle,
) )
// MARK: Verify Email Token // MARK: Verify Email Token
/// Test data indicating that the verify email token link has expired. /// Test data indicating that the verify email token link has expired.
static let verifyEmailTokenExpiredLink = loadFromJsonBundle( static let verifyEmailTokenExpiredLink = loadFromJsonBundle(resource: "VerifyEmailTokenExpiredLink")
resource: "VerifyEmailTokenExpiredLink",
bundle: BitwardenKitMocksBundleFinder.bundle,
)
} }

View File

@ -0,0 +1,12 @@
import TestHelpers
/// `APITestData` helpers that load the resource from the `BitwardenKitMocks` bundle.
extension APITestData {
static func loadFromBundle(resource: String, extension: String) -> APITestData {
loadFromBundle(resource: resource, extension: `extension`, bundle: .bitwardenKitMocks)
}
static func loadFromJsonBundle(resource: String) -> APITestData {
loadFromJsonBundle(resource: resource, bundle: .bitwardenKitMocks)
}
}

View File

@ -3,8 +3,5 @@ import TestHelpers
public extension APITestData { public extension APITestData {
/// A valid server configuration to produce a `ConfigResponseModel`. /// A valid server configuration to produce a `ConfigResponseModel`.
static let validServerConfig = loadFromJsonBundle( static let validServerConfig = loadFromJsonBundle(resource: "ValidServerConfig")
resource: "ValidServerConfig",
bundle: BitwardenKitMocksBundleFinder.bundle,
)
} }

View File

@ -3,8 +3,5 @@ import TestHelpers
public extension APITestData { public extension APITestData {
/// A standard Bitwarden error message of "You do not have permissions to edit this." /// A standard Bitwarden error message of "You do not have permissions to edit this."
static let bitwardenErrorMessage = loadFromJsonBundle( static let bitwardenErrorMessage = loadFromJsonBundle(resource: "BitwardenErrorMessage")
resource: "BitwardenErrorMessage",
bundle: BitwardenKitMocksBundleFinder.bundle,
)
} }

View File

@ -3,3 +3,8 @@ import Foundation
class BitwardenKitMocksBundleFinder { class BitwardenKitMocksBundleFinder {
static let bundle = Bundle(for: BitwardenKitMocksBundleFinder.self) static let bundle = Bundle(for: BitwardenKitMocksBundleFinder.self)
} }
public extension Bundle {
/// The bundle for the `BitwardenKitMocks` target.
static let bitwardenKitMocks = BitwardenKitMocksBundleFinder.bundle
}

View File

@ -0,0 +1,12 @@
import TestHelpers
/// `APITestData` helpers that load the resource from the `BitwardenShared` bundle.
extension APITestData {
static func loadFromBundle(resource: String, extension: String) -> APITestData {
loadFromBundle(resource: resource, extension: `extension`, bundle: .bitwardenShared)
}
static func loadFromJsonBundle(resource: String) -> APITestData {
loadFromJsonBundle(resource: resource, bundle: .bitwardenShared)
}
}

View File

@ -0,0 +1,10 @@
import Foundation
class BitwardenSharedBundleFinder {
static let bundle = Bundle(for: BitwardenSharedBundleFinder.self)
}
public extension Bundle {
/// The bundle for the `BitwardenShared` target.
static let bitwardenShared = BitwardenSharedBundleFinder.bundle
}

View File

@ -5,5 +5,8 @@ import TestHelpers
/// Fixtures for Credential Exchange flows. /// Fixtures for Credential Exchange flows.
enum CXFFixtures { enum CXFFixtures {
/// Fixture to be used on export flow with two basic-auth ciphers. /// Fixture to be used on export flow with two basic-auth ciphers.
static let twoBasicAuthCiphers = TestDataHelpers.loadUTFStringFromJsonBundle(resource: "cxfTwoBasicAuthCiphers") static let twoBasicAuthCiphers = TestDataHelpers.loadUTFStringFromJsonBundle(
resource: "cxfTwoBasicAuthCiphers",
bundle: .bitwardenShared,
)
} }

View File

@ -10,8 +10,6 @@ open class BitwardenTestCase: BaseBitwardenTestCase {
override open class func setUp() { override open class func setUp() {
// Apply default appearances for snapshot tests. // Apply default appearances for snapshot tests.
UI.applyDefaultAppearances() UI.applyDefaultAppearances()
TestDataHelpers.defaultBundle = Bundle(for: Self.self)
} }
/// Executes any logic that should be applied before each test runs. /// Executes any logic that should be applied before each test runs.

View File

@ -8,8 +8,6 @@ open class BitwardenTestCase: BaseBitwardenTestCase {
override open class func setUp() { override open class func setUp() {
// Apply default appearances for snapshot tests. // Apply default appearances for snapshot tests.
UI.applyDefaultAppearances() UI.applyDefaultAppearances()
TestDataHelpers.defaultBundle = Bundle(for: Self.self)
} }
/// Executes any logic that should be applied before each test runs. /// Executes any logic that should be applied before each test runs.

View File

@ -12,13 +12,13 @@ public struct APITestData {
} }
/// Loads test data from a provided file in the test class's bundle. /// Loads test data from a provided file in the test class's bundle.
public static func loadFromBundle(resource: String, extension: String, bundle: Bundle? = nil) -> APITestData { public static func loadFromBundle(resource: String, extension: String, bundle: Bundle) -> APITestData {
let data = TestDataHelpers.loadFromBundle(resource: resource, extension: `extension`, bundle: bundle) let data = TestDataHelpers.loadFromBundle(resource: resource, extension: `extension`, bundle: bundle)
return APITestData(data: data) return APITestData(data: data)
} }
/// Loads test data from a provided JSON file in the test class's bundle. /// Loads test data from a provided JSON file in the test class's bundle.
public static func loadFromJsonBundle(resource: String, bundle: Bundle? = nil) -> APITestData { public static func loadFromJsonBundle(resource: String, bundle: Bundle) -> APITestData {
loadFromBundle(resource: resource, extension: "json", bundle: bundle) loadFromBundle(resource: resource, extension: "json", bundle: bundle)
} }
} }

View File

@ -3,34 +3,27 @@ import Foundation
/// A type that wraps fixture data for use in mocking responses during tests. /// A type that wraps fixture data for use in mocking responses during tests.
/// ///
public enum TestDataHelpers { public enum TestDataHelpers {
/// The default bundle to try loading files from.
public static var defaultBundle: Bundle?
/// Loads the data from the provided file. /// Loads the data from the provided file.
public static func loadFromBundle(resource: String, extension: String, bundle: Bundle? = nil) -> Data { public static func loadFromBundle(resource: String, extension: String, bundle: Bundle) -> Data {
let resolvedBundle = bundle ?? defaultBundle guard let url = bundle.url(forResource: resource, withExtension: `extension`) else {
guard let resolvedBundle else {
fatalError("Default test data bundle from not set properly in the test case.")
}
guard let url = resolvedBundle.url(forResource: resource, withExtension: `extension`) else {
// swiftlint:disable:next line_length // swiftlint:disable:next line_length
fatalError("Unable to locate file \(resource).\(`extension`) in the bundle \(resolvedBundle.bundleURL.lastPathComponent).") fatalError("Unable to locate file \(resource).\(`extension`) in the bundle \(bundle.bundleURL.lastPathComponent).")
} }
do { do {
return try Data(contentsOf: url) return try Data(contentsOf: url)
} catch { } catch {
// swiftlint:disable:next line_length // swiftlint:disable:next line_length
fatalError("Unable to load data from \(resource).\(`extension`) in the bundle \(resolvedBundle.bundleURL.lastPathComponent). Error: \(error)") fatalError("Unable to load data from \(resource).\(`extension`) in the bundle \(bundle.bundleURL.lastPathComponent). Error: \(error)")
} }
} }
/// Convenience function for loading data from a JSON file. /// Convenience function for loading data from a JSON file.
public static func loadFromJsonBundle(resource: String, bundle: Bundle? = nil) -> Data { public static func loadFromJsonBundle(resource: String, bundle: Bundle) -> Data {
loadFromBundle(resource: resource, extension: "json", bundle: bundle) loadFromBundle(resource: resource, extension: "json", bundle: bundle)
} }
/// Convenience function for loading a JSON file into a UTF-8 string. /// Convenience function for loading a JSON file into a UTF-8 string.
public static func loadUTFStringFromJsonBundle(resource: String, bundle: Bundle? = nil) -> String? { public static func loadUTFStringFromJsonBundle(resource: String, bundle: Bundle) -> String? {
let data = loadFromJsonBundle(resource: resource, bundle: bundle) let data = loadFromJsonBundle(resource: resource, bundle: bundle)
return String(data: data, encoding: .utf8) return String(data: data, encoding: .utf8)
} }