mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-10 13:37:11 +00:00
Tracing and integration test tweaks (#3336)
* Disable image and document picker integration tests as they randomly fail to load and are flakey. * Delete any pre-existing log files * Various tracing tweaks and fixes: - delete the custom tracing log levels as we can't control their ouput - implement comparable on them - change default levels only if the new chosen level increases their verbosity * Make logging targets mandatory and fix their logging levels * Switch back to using the `run_tests` reset simulator flag as `fastlane snapshot reset_simulators` was too generic and slow * Switch all integration test taps to `tapCenter` (nee forceTap) after noticing missed taps on CI. * Make the logging file prefix explicit, let the main app not use one. * Rename tracing configuration `target` to `currentTarget`
This commit is contained in:
parent
df6d0a999f
commit
9d23dec2e9
6
.github/workflows/integration-tests.yml
vendored
6
.github/workflows/integration-tests.yml
vendored
@ -30,8 +30,8 @@ jobs:
|
||||
run:
|
||||
source ci_scripts/ci_common.sh && setup_github_actions_environment
|
||||
|
||||
- name: Reset simulators
|
||||
run: SNAPSHOT_FORCE_DELETE=1 bundle exec fastlane snapshot reset_simulators
|
||||
- name: Delete old log files
|
||||
run: find '/Users/Shared' -name 'console*' -delete
|
||||
|
||||
- name: Run tests
|
||||
run: bundle exec fastlane integration_tests
|
||||
@ -44,7 +44,7 @@ jobs:
|
||||
run: (grep ' TRACE ' /Users/Shared -qR)
|
||||
|
||||
- name: Check logs don't contain private messages
|
||||
run: (! grep 'Go down in flames' /Users/Shared -qR)
|
||||
run: "! grep 'Go down in flames' /Users/Shared -R"
|
||||
|
||||
- name: Zip results # for faster upload
|
||||
if: failure()
|
||||
|
3
.github/workflows/unit_tests.yml
vendored
3
.github/workflows/unit_tests.yml
vendored
@ -36,9 +36,6 @@ jobs:
|
||||
run:
|
||||
swiftformat --lint .
|
||||
|
||||
- name: Reset simulators
|
||||
run: SNAPSHOT_FORCE_DELETE=1 bundle exec fastlane snapshot reset_simulators
|
||||
|
||||
- name: Run tests
|
||||
run: bundle exec fastlane unit_tests
|
||||
|
||||
|
3
.github/workflows/unit_tests_enterprise.yml
vendored
3
.github/workflows/unit_tests_enterprise.yml
vendored
@ -45,9 +45,6 @@ jobs:
|
||||
- name: SwiftFormat
|
||||
run: swiftformat --lint .
|
||||
|
||||
- name: Reset simulators
|
||||
run: SNAPSHOT_FORCE_DELETE=1 bundle exec fastlane snapshot reset_simulators
|
||||
|
||||
- name: Run tests
|
||||
run: bundle exec fastlane unit_tests skip_previews:true
|
||||
|
||||
|
@ -70,7 +70,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
||||
|
||||
let appSettings = appHooks.appSettingsHook.configure(AppSettings())
|
||||
|
||||
MXLog.configure(logLevel: appSettings.logLevel)
|
||||
MXLog.configure(currentTarget: "elementx", filePrefix: nil, logLevel: appSettings.logLevel)
|
||||
|
||||
let appName = InfoPlistReader.main.bundleDisplayName
|
||||
let appVersion = InfoPlistReader.main.bundleShortVersionString
|
||||
|
@ -9,7 +9,7 @@ import XCTest
|
||||
|
||||
extension XCUIElement {
|
||||
func clearAndTypeText(_ text: String) {
|
||||
forceTap()
|
||||
tapCenter()
|
||||
|
||||
guard let currentValue = value as? String else {
|
||||
XCTFail("Tried to clear and type text into a non string value")
|
||||
@ -24,7 +24,7 @@ extension XCUIElement {
|
||||
}
|
||||
}
|
||||
|
||||
func forceTap() {
|
||||
func tapCenter() {
|
||||
let coordinate: XCUICoordinate = coordinate(withNormalizedOffset: .init(dx: 0.5, dy: 0.5))
|
||||
coordinate.tap()
|
||||
}
|
||||
|
@ -22,21 +22,18 @@ enum MXLog {
|
||||
private static var didConfigureOnce = false
|
||||
|
||||
private static var rootSpan: Span!
|
||||
private static var target: String!
|
||||
private static var currentTarget: String!
|
||||
|
||||
static func configure(target: String? = nil,
|
||||
static func configure(currentTarget: String,
|
||||
filePrefix: String?,
|
||||
logLevel: TracingConfiguration.LogLevel) {
|
||||
guard !didConfigureOnce else { return }
|
||||
|
||||
RustTracing.setup(configuration: .init(logLevel: logLevel, target: target))
|
||||
RustTracing.setup(configuration: .init(logLevel: logLevel, currentTarget: currentTarget, filePrefix: filePrefix))
|
||||
|
||||
if let target {
|
||||
self.target = target
|
||||
} else {
|
||||
self.target = Constants.target
|
||||
}
|
||||
self.currentTarget = currentTarget
|
||||
|
||||
rootSpan = Span(file: #file, line: #line, level: .info, target: self.target, name: "root")
|
||||
rootSpan = Span(file: #file, line: #line, level: .info, target: self.currentTarget, name: "root")
|
||||
rootSpan.enter()
|
||||
|
||||
didConfigureOnce = true
|
||||
@ -138,7 +135,7 @@ enum MXLog {
|
||||
rootSpan.enter()
|
||||
}
|
||||
|
||||
return Span(file: file, line: UInt32(line), level: level, target: target, name: name)
|
||||
return Span(file: file, line: UInt32(line), level: level, target: currentTarget, name: name)
|
||||
}
|
||||
|
||||
// periphery:ignore:parameters function,column,context
|
||||
@ -157,6 +154,6 @@ enum MXLog {
|
||||
rootSpan.enter()
|
||||
}
|
||||
|
||||
logEvent(file: (file as NSString).lastPathComponent, line: UInt32(line), level: level, target: target, message: "\(message)")
|
||||
logEvent(file: (file as NSString).lastPathComponent, line: UInt32(line), level: level, target: currentTarget, message: "\(message)")
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ enum RustTracing {
|
||||
// Log everything on integration tests to check whether
|
||||
// the logs contain any sensitive data. See `UserFlowTests.swift`
|
||||
let filter = if ProcessInfo.isRunningIntegrationTests {
|
||||
TracingConfiguration(logLevel: .trace, target: nil).filter
|
||||
TracingConfiguration(logLevel: .trace, currentTarget: "integrationtests", filePrefix: nil).filter
|
||||
} else {
|
||||
configuration.filter
|
||||
}
|
||||
|
@ -11,9 +11,8 @@ import Collections
|
||||
// We can filter by level, crate and even file. See more details here:
|
||||
// https://docs.rs/tracing-subscriber/0.2.7/tracing_subscriber/filter/struct.EnvFilter.html#examples
|
||||
struct TracingConfiguration {
|
||||
enum LogLevel: Codable, Hashable {
|
||||
enum LogLevel: String, Codable, Hashable, Comparable {
|
||||
case error, warn, info, debug, trace
|
||||
case custom(String)
|
||||
|
||||
var title: String {
|
||||
switch self {
|
||||
@ -27,34 +26,32 @@ struct TracingConfiguration {
|
||||
return "Debug"
|
||||
case .trace:
|
||||
return "Trace"
|
||||
case .custom:
|
||||
return "Custom"
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate var rawValue: String {
|
||||
switch self {
|
||||
case .error:
|
||||
return "error"
|
||||
case .warn:
|
||||
return "warn"
|
||||
case .info:
|
||||
return "info"
|
||||
case .debug:
|
||||
return "debug"
|
||||
case .trace:
|
||||
return "trace"
|
||||
case .custom(let filter):
|
||||
return filter
|
||||
static func < (lhs: TracingConfiguration.LogLevel, rhs: TracingConfiguration.LogLevel) -> Bool {
|
||||
switch (lhs, rhs) {
|
||||
case (.error, _):
|
||||
true
|
||||
case (.warn, .error):
|
||||
false
|
||||
case (.warn, _):
|
||||
true
|
||||
case (.info, .error), (.info, .warn):
|
||||
false
|
||||
case (.info, _):
|
||||
true
|
||||
case (.debug, .error), (.debug, .warn), (.debug, .info):
|
||||
false
|
||||
case (.debug, _):
|
||||
true
|
||||
case (.trace, _):
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Target: String {
|
||||
case common = ""
|
||||
|
||||
case elementx
|
||||
|
||||
case hyper, matrix_sdk_ffi, matrix_sdk_crypto
|
||||
|
||||
case matrix_sdk_client = "matrix_sdk::client"
|
||||
@ -66,9 +63,8 @@ struct TracingConfiguration {
|
||||
case matrix_sdk_ui_timeline = "matrix_sdk_ui::timeline"
|
||||
}
|
||||
|
||||
// The `common` target is excluded because 3rd-party crates might end up logging user data.
|
||||
static let targets: OrderedDictionary<Target, LogLevel> = [
|
||||
.common: .info, // Never set this lower than info - 3rd-party crates may start logging user data.
|
||||
.elementx: .info,
|
||||
.hyper: .warn,
|
||||
.matrix_sdk_ffi: .info,
|
||||
.matrix_sdk_client: .trace,
|
||||
@ -92,41 +88,38 @@ struct TracingConfiguration {
|
||||
/// - Parameter logLevel: the desired log level
|
||||
/// - Parameter target: the name of the target being configured
|
||||
/// - Returns: a custom tracing configuration
|
||||
init(logLevel: LogLevel, target: String?) {
|
||||
fileName = if let target {
|
||||
"\(RustTracing.filePrefix)-\(target)"
|
||||
init(logLevel: LogLevel, currentTarget: String, filePrefix: String?) {
|
||||
fileName = if let filePrefix {
|
||||
"\(RustTracing.filePrefix)-\(filePrefix)"
|
||||
} else {
|
||||
RustTracing.filePrefix
|
||||
}
|
||||
|
||||
if case let .custom(filter) = logLevel {
|
||||
self.filter = filter
|
||||
return
|
||||
}
|
||||
|
||||
let overrides = Self.targets.keys.reduce(into: [Target: LogLevel]()) { partialResult, target in
|
||||
// Keep the defaults here
|
||||
let ignoredTargets: [Target] = [.common, // Never remove common from the ignored targets (see above for more info).
|
||||
.hyper,
|
||||
.matrix_sdk_ffi,
|
||||
.matrix_sdk_oidc,
|
||||
.matrix_sdk_client,
|
||||
.matrix_sdk_crypto,
|
||||
.matrix_sdk_crypto_account,
|
||||
.matrix_sdk_http_client]
|
||||
let ignoredTargets: [Target] = [.hyper]
|
||||
|
||||
if ignoredTargets.contains(target) {
|
||||
return
|
||||
}
|
||||
|
||||
guard let defaultTargetLogLevel = Self.targets[target] else {
|
||||
return
|
||||
}
|
||||
|
||||
// Only change the targets that have default values
|
||||
// smaller than the desired log level
|
||||
if defaultTargetLogLevel < logLevel {
|
||||
partialResult[target] = logLevel
|
||||
}
|
||||
}
|
||||
|
||||
var newTargets = Self.targets
|
||||
for (target, logLevel) in overrides {
|
||||
newTargets.updateValue(logLevel, forKey: target)
|
||||
}
|
||||
|
||||
let components = newTargets.map { (target: Target, logLevel: LogLevel) in
|
||||
var components = newTargets.map { (target: Target, logLevel: LogLevel) in
|
||||
guard !target.rawValue.isEmpty else {
|
||||
return logLevel.rawValue
|
||||
}
|
||||
@ -134,6 +127,10 @@ struct TracingConfiguration {
|
||||
return "\(target.rawValue)=\(logLevel.rawValue)"
|
||||
}
|
||||
|
||||
// With `common` not being used we manually need to specify the log
|
||||
// level for passed in targets
|
||||
components.append("\(currentTarget)=\(logLevel.rawValue)")
|
||||
|
||||
filter = components.joined(separator: ",")
|
||||
}
|
||||
}
|
||||
|
@ -135,18 +135,6 @@ struct DeveloperOptionsScreen: View {
|
||||
private struct LogLevelConfigurationView: View {
|
||||
@Binding var logLevel: TracingConfiguration.LogLevel
|
||||
|
||||
@State private var customTracingConfiguration: String
|
||||
|
||||
init(logLevel: Binding<TracingConfiguration.LogLevel>) {
|
||||
_logLevel = logLevel
|
||||
|
||||
if case .custom(let configuration) = logLevel.wrappedValue {
|
||||
customTracingConfiguration = configuration
|
||||
} else {
|
||||
customTracingConfiguration = TracingConfiguration(logLevel: .info, target: nil).filter
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Picker(selection: $logLevel) {
|
||||
ForEach(logLevels, id: \.self) { logLevel in
|
||||
@ -156,24 +144,11 @@ private struct LogLevelConfigurationView: View {
|
||||
Text("Log level")
|
||||
Text("Requires app reboot")
|
||||
}
|
||||
|
||||
if case .custom = logLevel {
|
||||
TextEditor(text: $customTracingConfiguration)
|
||||
.textInputAutocapitalization(.never)
|
||||
.autocorrectionDisabled()
|
||||
.onChange(of: customTracingConfiguration) { newValue in
|
||||
logLevel = .custom(newValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Allows the picker to work with associated values
|
||||
private var logLevels: [TracingConfiguration.LogLevel] {
|
||||
if case let .custom(filter) = logLevel {
|
||||
return [.error, .warn, .info, .debug, .trace, .custom(filter)]
|
||||
} else {
|
||||
return [.error, .warn, .info, .debug, .trace, .custom("")]
|
||||
}
|
||||
[.error, .warn, .info, .debug, .trace]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ class UITestsAppCoordinator: AppCoordinatorProtocol, SecureWindowManagerDelegate
|
||||
|
||||
windowManager.delegate = self
|
||||
|
||||
MXLog.configure(logLevel: .debug)
|
||||
MXLog.configure(currentTarget: "uitests", filePrefix: nil, logLevel: .debug)
|
||||
|
||||
ServiceLocator.shared.register(userIndicatorController: UserIndicatorController())
|
||||
|
||||
|
@ -12,12 +12,11 @@ extension XCUIApplication {
|
||||
let getStartedButton = buttons[A11yIdentifiers.authenticationStartScreen.signIn]
|
||||
|
||||
XCTAssertTrue(getStartedButton.waitForExistence(timeout: 10.0))
|
||||
getStartedButton.tap()
|
||||
getStartedButton.tapCenter()
|
||||
|
||||
// Get started is network bound, wait for the change homeserver button for longer
|
||||
let changeHomeserverButton = buttons[A11yIdentifiers.serverConfirmationScreen.changeServer]
|
||||
XCTAssertTrue(changeHomeserverButton.waitForExistence(timeout: 30.0))
|
||||
changeHomeserverButton.tap()
|
||||
XCTAssertTrue(changeHomeserverButton.waitForExistence(timeout: 10.0))
|
||||
changeHomeserverButton.tapCenter()
|
||||
|
||||
let homeserverTextField = textFields[A11yIdentifiers.changeServerScreen.server]
|
||||
XCTAssertTrue(homeserverTextField.waitForExistence(timeout: 10.0))
|
||||
@ -26,7 +25,7 @@ extension XCUIApplication {
|
||||
|
||||
let confirmButton = buttons[A11yIdentifiers.changeServerScreen.continue]
|
||||
XCTAssertTrue(confirmButton.waitForExistence(timeout: 10.0))
|
||||
confirmButton.tap()
|
||||
confirmButton.tapCenter()
|
||||
|
||||
// Wait for server confirmation to finish
|
||||
let doesNotExistPredicate = NSPredicate(format: "exists == 0")
|
||||
@ -35,7 +34,7 @@ extension XCUIApplication {
|
||||
|
||||
let continueButton = buttons[A11yIdentifiers.serverConfirmationScreen.continue]
|
||||
XCTAssertTrue(continueButton.waitForExistence(timeout: 30.0))
|
||||
continueButton.tap()
|
||||
continueButton.tapCenter()
|
||||
|
||||
let usernameTextField = textFields[A11yIdentifiers.loginScreen.emailUsername]
|
||||
XCTAssertTrue(usernameTextField.waitForExistence(timeout: 10.0))
|
||||
@ -51,7 +50,7 @@ extension XCUIApplication {
|
||||
XCTAssertTrue(nextButton.waitForExistence(timeout: 10.0))
|
||||
XCTAssertTrue(nextButton.isEnabled)
|
||||
|
||||
nextButton.tap()
|
||||
nextButton.tapCenter()
|
||||
|
||||
// Wait for login to finish
|
||||
currentTestCase.expectation(for: doesNotExistPredicate, evaluatedWith: usernameTextField)
|
||||
@ -63,7 +62,7 @@ extension XCUIApplication {
|
||||
// Tapping the sheet button while animating upwards fails. Wait for it to settle
|
||||
sleep(1)
|
||||
|
||||
savePasswordButton.tap()
|
||||
savePasswordButton.tapCenter()
|
||||
}
|
||||
|
||||
// Wait for the home screen to become visible.
|
||||
@ -80,17 +79,17 @@ extension XCUIApplication {
|
||||
let profileButton = buttons[A11yIdentifiers.homeScreen.userAvatar]
|
||||
|
||||
// `Failed to scroll to visible (by AX action) Button` https://stackoverflow.com/a/33534187/730924
|
||||
profileButton.forceTap()
|
||||
profileButton.tapCenter()
|
||||
|
||||
// Logout
|
||||
let logoutButton = buttons[A11yIdentifiers.settingsScreen.logout]
|
||||
XCTAssertTrue(logoutButton.waitForExistence(timeout: 10.0))
|
||||
logoutButton.tap()
|
||||
logoutButton.tapCenter()
|
||||
|
||||
// Confirm logout
|
||||
let alertLogoutButton = alerts.firstMatch.buttons["Sign out"]
|
||||
XCTAssertTrue(alertLogoutButton.waitForExistence(timeout: 10.0))
|
||||
alertLogoutButton.tap()
|
||||
alertLogoutButton.tapCenter()
|
||||
|
||||
// Check that we're back on the login screen
|
||||
let getStartedButton = buttons[A11yIdentifiers.authenticationStartScreen.signIn]
|
||||
|
@ -37,13 +37,13 @@ class UserFlowTests: XCTestCase {
|
||||
// And open it
|
||||
let firstRoom = app.buttons.matching(NSPredicate(format: "identifier CONTAINS %@", Self.integrationTestsRoomName)).firstMatch
|
||||
XCTAssertTrue(firstRoom.waitForExistence(timeout: 10.0))
|
||||
firstRoom.tap()
|
||||
firstRoom.tapCenter()
|
||||
|
||||
sendMessages()
|
||||
|
||||
checkPhotoSharing()
|
||||
|
||||
checkDocumentSharing()
|
||||
// Intentionally disabled as they're super flakey on iOS 18 simulators
|
||||
// checkPhotoSharing()
|
||||
// checkDocumentSharing()
|
||||
|
||||
checkLocationSharing()
|
||||
|
||||
@ -57,7 +57,7 @@ class UserFlowTests: XCTestCase {
|
||||
// Cancel initial the room search
|
||||
let searchCancelButton = app.buttons["Cancel"].firstMatch
|
||||
XCTAssertTrue(searchCancelButton.waitForExistence(timeout: 10.0))
|
||||
searchCancelButton.forceTap()
|
||||
searchCancelButton.tapCenter()
|
||||
}
|
||||
|
||||
private func sendMessages() {
|
||||
@ -67,7 +67,7 @@ class UserFlowTests: XCTestCase {
|
||||
|
||||
var sendButton = app.buttons[A11yIdentifiers.roomScreen.sendButton].firstMatch
|
||||
XCTAssertTrue(sendButton.waitForExistence(timeout: 10.0))
|
||||
sendButton.tap()
|
||||
sendButton.tapCenter()
|
||||
|
||||
sleep(10) // Wait for the message to be sent
|
||||
|
||||
@ -81,12 +81,12 @@ class UserFlowTests: XCTestCase {
|
||||
|
||||
sendButton = app.buttons[A11yIdentifiers.roomScreen.sendButton].firstMatch
|
||||
XCTAssertTrue(sendButton.waitForExistence(timeout: 10.0))
|
||||
sendButton.tap()
|
||||
sendButton.tapCenter()
|
||||
|
||||
sleep(5) // Wait for the message to be sent
|
||||
|
||||
// Close the formatting options
|
||||
app.buttons[A11yIdentifiers.roomScreen.composerToolbar.closeFormattingOptions].tap()
|
||||
app.buttons[A11yIdentifiers.roomScreen.composerToolbar.closeFormattingOptions].tapCenter()
|
||||
}
|
||||
|
||||
private func checkPhotoSharing() {
|
||||
@ -98,7 +98,7 @@ class UserFlowTests: XCTestCase {
|
||||
// Tap on the second image. First one is always broken on simulators.
|
||||
let secondImage = app.scrollViews.images.element(boundBy: 1)
|
||||
XCTAssertTrue(secondImage.waitForExistence(timeout: 20.0)) // Photo library takes a bit to load
|
||||
secondImage.tap()
|
||||
secondImage.tapCenter()
|
||||
|
||||
// Wait for the image to be processed and the new screen to appear
|
||||
sleep(10)
|
||||
@ -129,7 +129,7 @@ class UserFlowTests: XCTestCase {
|
||||
// Handle map loading errors (missing credentials)
|
||||
let alertOkButton = app.alerts.firstMatch.buttons["OK"].firstMatch
|
||||
if alertOkButton.waitForExistence(timeout: 10.0) {
|
||||
alertOkButton.tap()
|
||||
alertOkButton.tapCenter()
|
||||
}
|
||||
|
||||
allowLocationPermissionOnce()
|
||||
@ -141,7 +141,7 @@ class UserFlowTests: XCTestCase {
|
||||
let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
|
||||
let notificationAlertAllowButton = springboard.buttons["Allow Once"].firstMatch
|
||||
if notificationAlertAllowButton.waitForExistence(timeout: 10.0) {
|
||||
notificationAlertAllowButton.tap()
|
||||
notificationAlertAllowButton.tapCenter()
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,7 +178,7 @@ class UserFlowTests: XCTestCase {
|
||||
// Open the room details
|
||||
let roomHeader = app.staticTexts[A11yIdentifiers.roomScreen.name]
|
||||
XCTAssertTrue(roomHeader.waitForExistence(timeout: 10.0))
|
||||
roomHeader.tap()
|
||||
roomHeader.tapCenter()
|
||||
|
||||
// Open the room member details
|
||||
tapOnButton(A11yIdentifiers.roomDetailsScreen.people)
|
||||
@ -186,7 +186,7 @@ class UserFlowTests: XCTestCase {
|
||||
// Open the first member's details. Loading members for big rooms can take a while.
|
||||
let firstRoomMember = app.scrollViews.buttons.firstMatch
|
||||
XCTAssertTrue(firstRoomMember.waitForExistence(timeout: 1000.0))
|
||||
firstRoomMember.tap()
|
||||
firstRoomMember.tapCenter()
|
||||
|
||||
// Go back to the room member details
|
||||
tapOnBackButton("People")
|
||||
@ -206,7 +206,7 @@ class UserFlowTests: XCTestCase {
|
||||
let profileButton = app.buttons[A11yIdentifiers.homeScreen.userAvatar]
|
||||
|
||||
// `Failed to scroll to visible (by AX action) Button` https://stackoverflow.com/a/33534187/730924
|
||||
profileButton.forceTap()
|
||||
profileButton.tapCenter()
|
||||
|
||||
// Open analytics
|
||||
tapOnButton(A11yIdentifiers.settingsScreen.analytics)
|
||||
@ -233,7 +233,7 @@ class UserFlowTests: XCTestCase {
|
||||
private func tapOnButton(_ identifier: String, waitForDisappearance: Bool = false) {
|
||||
let button = app.buttons[identifier]
|
||||
XCTAssertTrue(button.waitForExistence(timeout: 10.0))
|
||||
button.tap()
|
||||
button.tapCenter()
|
||||
|
||||
if waitForDisappearance {
|
||||
let doesNotExistPredicate = NSPredicate(format: "exists == 0")
|
||||
@ -245,7 +245,7 @@ class UserFlowTests: XCTestCase {
|
||||
private func tapOnMenu(_ identifier: String) {
|
||||
let button = app.buttons[identifier]
|
||||
XCTAssertTrue(button.waitForExistence(timeout: 10.0))
|
||||
button.forceTap()
|
||||
button.tapCenter()
|
||||
}
|
||||
|
||||
/// Taps on a back button that the system configured with a label but no identifier.
|
||||
@ -255,6 +255,6 @@ class UserFlowTests: XCTestCase {
|
||||
private func tapOnBackButton(_ label: String = "Back") {
|
||||
let button = app.buttons.matching(NSPredicate(format: "label == %@ && identifier == ''", label)).firstMatch
|
||||
XCTAssertTrue(button.waitForExistence(timeout: 10.0))
|
||||
button.tap()
|
||||
button.tapCenter()
|
||||
}
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ enum NSELogger {
|
||||
}
|
||||
isConfigured = true
|
||||
|
||||
MXLog.configure(target: "nse", logLevel: logLevel)
|
||||
MXLog.configure(currentTarget: "nse", filePrefix: "nse", logLevel: logLevel)
|
||||
}
|
||||
|
||||
static func logMemory(with tag: String) {
|
||||
|
@ -22,7 +22,7 @@ class LoggingTests: XCTestCase {
|
||||
let target = "tests"
|
||||
XCTAssertTrue(RustTracing.logFiles.isEmpty)
|
||||
|
||||
MXLog.configure(target: target, logLevel: .info)
|
||||
MXLog.configure(currentTarget: target, filePrefix: target, logLevel: .info)
|
||||
|
||||
// There is something weird with Rust logging where the file writing handle doesn't
|
||||
// notice that the file it is writing to was deleted, so we can't run these checks
|
||||
@ -168,7 +168,7 @@ class LoggingTests: XCTestCase {
|
||||
content: .init(body: "FileString", source: nil, thumbnailSource: nil, contentType: nil))
|
||||
|
||||
// When logging that value
|
||||
MXLog.configure(logLevel: .info)
|
||||
MXLog.configure(currentTarget: "tests", filePrefix: nil, logLevel: .info)
|
||||
|
||||
MXLog.info(textMessage)
|
||||
MXLog.info(noticeMessage)
|
||||
|
@ -10,14 +10,35 @@ import XCTest
|
||||
@testable import ElementX
|
||||
|
||||
class TracingConfigurationTests: XCTestCase {
|
||||
func testConfiguration() {
|
||||
let configuration = TracingConfiguration(logLevel: .trace, target: nil)
|
||||
func testConfiguration() { // swiftlint:disable line_length
|
||||
var filter = TracingConfiguration(logLevel: .error, currentTarget: "tests", filePrefix: nil).filter
|
||||
|
||||
let filterComponents = configuration.filter.components(separatedBy: ",")
|
||||
XCTAssertEqual(filterComponents.first, "info")
|
||||
XCTAssertTrue(filterComponents.contains("matrix_sdk_base::sliding_sync=trace"))
|
||||
XCTAssertTrue(filterComponents.contains("matrix_sdk::http_client=debug"))
|
||||
XCTAssertTrue(filterComponents.contains("matrix_sdk_crypto=debug"))
|
||||
XCTAssertTrue(filterComponents.contains("hyper=warn"))
|
||||
XCTAssertEqual(filter, "hyper=warn,matrix_sdk_ffi=info,matrix_sdk::client=trace,matrix_sdk_crypto=debug,matrix_sdk_crypto::olm::account=trace,matrix_sdk::oidc=trace,matrix_sdk::http_client=debug,matrix_sdk::sliding_sync=info,matrix_sdk_base::sliding_sync=info,matrix_sdk_ui::timeline=info,tests=error")
|
||||
|
||||
filter = TracingConfiguration(logLevel: .warn, currentTarget: "tests", filePrefix: nil).filter
|
||||
|
||||
XCTAssertEqual(filter, "hyper=warn,matrix_sdk_ffi=info,matrix_sdk::client=trace,matrix_sdk_crypto=debug,matrix_sdk_crypto::olm::account=trace,matrix_sdk::oidc=trace,matrix_sdk::http_client=debug,matrix_sdk::sliding_sync=info,matrix_sdk_base::sliding_sync=info,matrix_sdk_ui::timeline=info,tests=warn")
|
||||
|
||||
filter = TracingConfiguration(logLevel: .info, currentTarget: "tests", filePrefix: nil).filter
|
||||
|
||||
XCTAssertEqual(filter, "hyper=warn,matrix_sdk_ffi=info,matrix_sdk::client=trace,matrix_sdk_crypto=debug,matrix_sdk_crypto::olm::account=trace,matrix_sdk::oidc=trace,matrix_sdk::http_client=debug,matrix_sdk::sliding_sync=info,matrix_sdk_base::sliding_sync=info,matrix_sdk_ui::timeline=info,tests=info")
|
||||
|
||||
filter = TracingConfiguration(logLevel: .debug, currentTarget: "tests", filePrefix: nil).filter
|
||||
|
||||
XCTAssertEqual(filter, "hyper=warn,matrix_sdk_ffi=debug,matrix_sdk::client=trace,matrix_sdk_crypto=debug,matrix_sdk_crypto::olm::account=trace,matrix_sdk::oidc=trace,matrix_sdk::http_client=debug,matrix_sdk::sliding_sync=debug,matrix_sdk_base::sliding_sync=debug,matrix_sdk_ui::timeline=debug,tests=debug")
|
||||
|
||||
filter = TracingConfiguration(logLevel: .trace, currentTarget: "tests", filePrefix: nil).filter
|
||||
|
||||
XCTAssertEqual(filter, "hyper=warn,matrix_sdk_ffi=trace,matrix_sdk::client=trace,matrix_sdk_crypto=trace,matrix_sdk_crypto::olm::account=trace,matrix_sdk::oidc=trace,matrix_sdk::http_client=trace,matrix_sdk::sliding_sync=trace,matrix_sdk_base::sliding_sync=trace,matrix_sdk_ui::timeline=trace,tests=trace")
|
||||
} // swiftlint:enable line_length
|
||||
|
||||
func testLevelOrdering() {
|
||||
var logLevels: [TracingConfiguration.LogLevel] = [.info, .error, .trace, .debug, .warn]
|
||||
|
||||
XCTAssertEqual(logLevels.sorted(), [.error, .warn, .info, .debug, .trace])
|
||||
|
||||
logLevels = [.warn, .error, .debug, .trace, .info, .error]
|
||||
|
||||
XCTAssertEqual(logLevels.sorted(), [.error, .error, .warn, .info, .debug, .trace])
|
||||
}
|
||||
}
|
||||
|
@ -80,12 +80,15 @@ lane :alpha do
|
||||
end
|
||||
|
||||
lane :unit_tests do |options|
|
||||
reset_simulator = ENV.key?('CI')
|
||||
|
||||
run_tests(
|
||||
scheme: "UnitTests",
|
||||
destination: "platform=iOS Simulator,name=iPhone 16,OS=18.0",
|
||||
ensure_devices_found: true,
|
||||
result_bundle: true,
|
||||
number_of_retries: 3,
|
||||
reset_simulator: reset_simulator
|
||||
)
|
||||
|
||||
if !options[:skip_previews]
|
||||
@ -95,6 +98,7 @@ lane :unit_tests do |options|
|
||||
ensure_devices_found: true,
|
||||
result_bundle: true,
|
||||
number_of_retries: 3,
|
||||
reset_simulator: reset_simulator
|
||||
)
|
||||
end
|
||||
|
||||
@ -102,10 +106,6 @@ lane :unit_tests do |options|
|
||||
end
|
||||
|
||||
lane :ui_tests do |options|
|
||||
# Use a fresh simulator state to ensure hardware keyboard isn't attached.
|
||||
# Not necessary when running on GitHub.
|
||||
# reset_simulator_contents()
|
||||
|
||||
create_simulator_if_necessary(
|
||||
name: "iPhone 16",
|
||||
type: "com.apple.CoreSimulator.SimDeviceType.iPhone-16",
|
||||
@ -124,6 +124,8 @@ lane :ui_tests do |options|
|
||||
test_to_run = nil
|
||||
end
|
||||
|
||||
reset_simulator = ENV.key?('CI')
|
||||
|
||||
run_tests(
|
||||
scheme: "UITests",
|
||||
devices: ["iPhone 16", "iPad (10th generation)"],
|
||||
@ -132,6 +134,7 @@ lane :ui_tests do |options|
|
||||
result_bundle: true,
|
||||
only_testing: test_to_run,
|
||||
number_of_retries: 3,
|
||||
reset_simulator: reset_simulator
|
||||
)
|
||||
end
|
||||
|
||||
@ -145,12 +148,14 @@ lane :integration_tests do
|
||||
runtime: "com.apple.CoreSimulator.SimRuntime.iOS-18-0"
|
||||
)
|
||||
|
||||
reset_simulator = ENV.key?('CI')
|
||||
|
||||
run_tests(
|
||||
scheme: "IntegrationTests",
|
||||
destination: "platform=iOS Simulator,name=iPhone 16 Pro,OS=18.0",
|
||||
ensure_devices_found: true,
|
||||
result_bundle: true,
|
||||
reset_simulator: true
|
||||
reset_simulator: reset_simulator
|
||||
)
|
||||
end
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user