Post

Replies

Boosts

Views

Activity

How to correctly resolve URL bookmarks for use in Simulator UI tests?
To make UI testing easier and faster, I usually create URL bookmarks during normal app usage in the Simulator so that they can be instantly resolved on app launch during UI tests. For example, one of my apps allows browsing selected folders and stores bookmarks so they can be quickly opened again on following app launches, and instead of selecting the test folder each time at the beginning of the UI test, I select it once during normal app usage so that it's available immediately during the UI test. This usually works fine, but every now and then the UI tests fail because the tested app isn't able to resolve the stored bookmark. I don't know why this happens, but usually opening and closing the app again in the Simulator and re-running the UI tests solves the issue. The problem now is that I've just tried to setup some new UI tests for Apple Vision Pro Simulator and I'm never able to resolve bookmarks. So I created a sample project that reproduces the issue, and curiously enough the bookmarks don't even resolve when using an iPad Simulator (which usually works fine with my regular UI tests). What am I doing wrong? This can be reproduced with a default iOS project, embedding the default storyboard view controller in a navigation view controller, and this code: import UIKit class ViewController: UIViewController, UIDocumentPickerDelegate { override func viewDidLoad() { navigationItem.rightBarButtonItem = UIBarButtonItem(systemItem: .add, primaryAction: UIAction(handler: { _ in let picker = UIDocumentPickerViewController(forOpeningContentTypes: [.folder]) picker.delegate = self self.present(picker, animated: true) })) if let bookmark = UserDefaults.standard.data(forKey: "bookmark") { readBookmark(bookmark) } } func readBookmark(_ bookmark: Data) { do { let label = UILabel(frame: CGRect(x: 100, y: 100, width: 600, height: 100)) label.numberOfLines = 0 var stale = false let url = try URL(resolvingBookmarkData: bookmark, bookmarkDataIsStale: &stale) if !url.startAccessingSecurityScopedResource() { fatalError() } label.text = url.path view.addSubview(label) } catch { fatalError(error.localizedDescription) } } func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { do { let url = urls[0] if !url.startAccessingSecurityScopedResource() { fatalError() } let bookmark = try url.bookmarkData() UserDefaults.standard.set(bookmark, forKey: "bookmark") readBookmark(bookmark) } catch { fatalError(error.localizedDescription) } } } And a default UI test, which always crashes because of the fatalError() in the catch clause of readBookmark(_:): final class problemUITests: XCTestCase { @MainActor func testExample() throws { let app = XCUIApplication() app.launch() } }
0
0
411
Oct ’24
Xcode UI test always fails to tap close button in font picker navigation bar
I'm trying to close the UIFontPickerViewController in a UI test by tapping the close button in the navigation bar. In a default iOS app, I embed the default storyboard view controller in a navigation view controller, then in code I open the font picker like this: class ViewController: UIViewController, UIFontPickerViewControllerDelegate { override func viewDidAppear(_ animated: Bool) { let picker = UIFontPickerViewController(configuration: .init()) picker.delegate = self self.present(picker, animated: true) } func fontPickerViewControllerDidPickFont(_ viewController: UIFontPickerViewController) { } } And the UI test looks like this: final class problemUITests: XCTestCase { @MainActor func testExample() throws { let app = XCUIApplication() app.launch() sleep(2) let button = app.navigationBars.element(boundBy: 1).buttons.element(boundBy: 0) print(button.debugDescription) XCTAssert(button.waitForExistence(timeout: 2)) button.tap() } } When running the UI test, the XCTAssert always fails and the button.tap() also fails with an error message Failed to tap "chiudi" Button: No matches found for Element at index 1 from input {( NavigationBar )} "chiudi" means "close" in Italian, my macOS system language. It sounds to me like I correctly get the close button, but the messages Xcode prints make no sense to me. It's particularly confusing given that the output of the print statement shows that the button is there, but somehow fails to be tapped: Attributes: Button, 0x104f44660, {{701.0, 320.0}, {43.0, 44.0}}, label: 'chiudi' Element subtree: →Button, 0x104f44660, {{701.0, 320.0}, {43.0, 44.0}}, label: 'chiudi' Image, 0x104f44780, {{709.0, 327.5}, {30.0, 30.0}}, identifier: 'UICloseButtonBackground' Path to element: →Application, 0x104f35940, pid: 29803, label: 'problem' ↳Window (Main), 0x104f376a0, {{0.0, 0.0}, {1032.0, 1376.0}} ↳Other, 0x104f42e10, {{0.0, 0.0}, {1032.0, 1376.0}} ↳Other, 0x104f43100, {{0.0, 0.0}, {1032.0, 1376.0}} ↳Other, 0x104f43220, {{0.0, 0.0}, {1032.0, 1376.0}} ↳Other, 0x104f43340, {{0.0, 0.0}, {1032.0, 1376.0}} ↳Other, 0x104f43460, {{0.0, 0.0}, {1032.0, 1376.0}} ↳Other, 0x104f43580, {{0.0, 0.0}, {1032.0, 1376.0}} ↳Other, 0x104f436a0, {{0.0, 0.0}, {1032.0, 1376.0}} ↳Other, 0x104f437c0, {{0.0, 0.0}, {1032.0, 1376.0}} ↳Other, 0x104f438e0, {{0.0, 0.0}, {1032.0, 1376.0}} ↳Other, 0x104f43a00, {{0.0, 0.0}, {1032.0, 1376.0}} ↳Other, 0x104f43b20, {{0.0, 0.0}, {1032.0, 1376.0}} ↳Other, 0x104f43c40, {{276.0, 314.0}, {480.0, 748.0}} ↳Other, 0x104f43e80, {{276.0, 314.0}, {480.0, 748.0}} ↳Other, 0x104f43fa0, {{276.0, 314.0}, {480.0, 748.0}} ↳Other, 0x104f440c0, {{276.0, 314.0}, {480.0, 748.0}} ↳Other, 0x104f441e0, {{276.0, 314.0}, {480.0, 748.0}} ↳Other, 0x104f44300, {{276.0, 314.0}, {480.0, 748.0}} ↳NavigationBar, 0x104f44420, {{276.0, 314.0}, {480.0, 108.0}}, identifier: 'Scegli font' ↳Button, 0x104f44660, {{701.0, 320.0}, {43.0, 44.0}}, label: 'chiudi' Query chain: →Find: Target Application 'org.desairem.problem' Output: { Application, 0x104f781b0, pid: 29803, label: 'problem' } ↪︎Find: Descendants matching type NavigationBar Output: { NavigationBar, 0x10607c0d0, {{0.0, 24.0}, {1032.0, 50.0}}, identifier: 'UIFontPickerView' NavigationBar, 0x10607dab0, {{276.0, 314.0}, {480.0, 108.0}}, identifier: 'Scegli font' } ↪︎Find: Element at index 1 Output: { NavigationBar, 0x1064693a0, {{276.0, 314.0}, {480.0, 108.0}}, identifier: 'Scegli font' } ↪︎Find: Descendants matching type Button Output: { Button, 0x104f714a0, {{701.0, 320.0}, {43.0, 44.0}}, label: 'chiudi' Button, 0x104f71800, {{711.0, 378.0}, {17.0, 22.0}}, identifier: 'Dictate', label: 'Avvia dettatura' } ↪︎Find: Element at index 0 Output: { Button, 0x104f5d5e0, {{701.0, 320.0}, {43.0, 44.0}}, label: 'chiudi' }
0
0
418
Oct ’24
SKLabelNode keeps jumping back and forth when displaying different numbers with equal number of digits
I'm trying to display a right-aligned timecode in my game. I had expected that digits would all have the same width, but this doesn't seem to be the case in SpriteKit, even though it seems to be the case in AppKit. In SpriteKit, with the default font there is a noticeable difference in width between the digit 1 and the rest (1 is thinner), so whenever displaying a number with the least significant digit 1 all preceding digits shift slightly to the right. This happens even when setting a NSAttributedString with a font that has a fixedAdvance attribute. class GameScene: SKScene { override func didMove(to view: SKView) { let label = SKLabelNode(text: "") view.scene!.addChild(label) // label.horizontalAlignmentMode = .left label.horizontalAlignmentMode = .right var i = 11 Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { _ in label.text = "\(i)" // let font = NSFont(descriptor: NSFontDescriptor(fontAttributes: [.name: "HelveticaNeue-UltraLight", .fixedAdvance: 20]), size: 30)! // let paragraphStyle = NSMutableParagraphStyle() // paragraphStyle.alignment = .right // label.attributedText = NSAttributedString(string: "\(i)", attributes: [.font: font, .foregroundColor: SKColor.labelColor, .paragraphStyle: paragraphStyle]) i += 5 } } } With AppKit, when using SpriteKit's default font HelveticaNeue-UltraLight, this issue doesn't exist, regardless whether I set the fixedAdvance font attribute. class ViewController: NSViewController { override func viewDidLoad() { super.viewDidLoad() let font = NSFont(descriptor: NSFontDescriptor(fontAttributes: [.name: "HelveticaNeue-UltraLight"]), size: 30)! // let font = NSFont(descriptor: NSFontDescriptor(fontAttributes: [.name: "HelveticaNeue-Light", .fixedAdvance: 20]), size: 30)! let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.alignment = .right let textField = NSTextField(labelWithString: "") textField.font = font textField.alignment = .right // textField.alignment = .left textField.frame = CGRect(x: 100, y: 100, width: 100, height: 100) view.addSubview(textField) var i = 11 Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { _ in textField.stringValue = "\(i)" // textField.attributedStringValue = NSAttributedString(string: "\(i)", attributes: [.font: font, .paragraphStyle: paragraphStyle]) i += 5 } } } Is there a solution to this problem? I filed FB15553700.
0
0
618
Oct ’24
Modal UINavigationController shown programmatically has no navigation buttons
When I create a modal segue to a navigation controller in a storyboard, the navigation bar buttons appear correctly. But when trying to recreate this programmatically, no buttons appear: import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let button = UIButton(type: .infoLight, primaryAction: UIAction(handler: { _ in self.present(UINavigationController(rootViewController: ModalViewController()), animated: true) })) button.frame.origin = CGPoint(x: 100, y: 100) view.addSubview(button) } } class ModalViewController: UIViewController { override func loadView() { let button = UIBarButtonItem(title: "button") button.primaryAction = UIAction(handler: { action in }) button.style = .done navigationItem.title = "title" navigationItem.rightBarButtonItem = button view = UITableView() } } What am I doing wrong?
Topic: UI Frameworks SubTopic: UIKit Tags:
2
0
488
Oct ’24
NSAttributedString.enumerateAttribute(_:in) crashes with custom attribute in macOS Sequoia
The following code crashes on macOS 15 Sequoia: import Foundation let key = NSAttributedString.Key("org.example.key") let value = Value() let string = NSMutableAttributedString() string.append(NSAttributedString(string: "a", attributes: [:])) string.append(NSAttributedString(string: "b", attributes: [key: value])) string.append(NSAttributedString(string: "c", attributes: [:])) string.enumerateAttribute(key, in: NSRange(location: 0, length: string.length)) { value, range, stop in print(range) } class Value: Equatable, Hashable { static func == (lhs: Value, rhs: Value) -> Bool { return lhs === rhs } func hash(into hasher: inout Hasher) { hasher.combine(ObjectIdentifier(self)) } } The error is EXC_BAD_ACCESS (code=1, address=0x0) I wanted to run it on my external macOS 14 partition to confirm that it didn't crash before updating to macOS 15, but for some reason macOS will just restart and boot again into macOS 15. So I tried with macOS 13, which I was allowed to start for some reason, and I was able to confirm that the code doesn't crash. Is this a known issue, and is there a workaround? Removing the two lines that add the letters a and c, or just declaring class Value without conformance to Equatable, Hashable, interestingly, solves the issue.
5
0
641
Oct ’24
Xcode UI test cannot tap menu button in form
Apparently UI tests are unable to tap menu buttons but can tap regular buttons inside forms. Earlier today I was able to see in the Simulator that the UI test tries to tap the button by tapping the center of the containing form row, which works for regular buttons, but not for menu buttons. In fact, when trying in the SwiftUI preview in Xcode it seems that menu buttons have to be tapped exactly on top of them, while regular buttons can be tapped anywhere in the form row. (Now I’m not able to see touches performed by the UI test anymore in the Simulator for an unknown reason, even though I have “Show single touches” enabled in the Simulator settings.) How can I open a menu button in a UI test? The UI code: struct ContentView: View { @State private var label1 = "Menu 1" @State private var label2 = "Menu 2" var body: some View { NavigationStack { Form { LabeledContent("Menu 1") { Button(label1) { label1 = "Menu 1 tapped" } .accessibilityIdentifier("menu1") } LabeledContent("Menu 2") { Menu(label2) { Button("Button") { } .accessibilityIdentifier("button") } .accessibilityIdentifier("menu2") } } } } } #Preview { ContentView() } And the test: final class problemUITests: XCTestCase { func testExample() throws { // UI tests must launch the application that they test. let app = XCUIApplication() app.launch() app.collectionViews.element(boundBy: 0).buttons["menu1"].tap() app.collectionViews.element(boundBy: 0).buttons["menu2"].tap() app.collectionViews.element(boundBy: 0).buttons["button"].tap() } }
2
0
694
Oct ’24
New iPhone 6.9" screenshots with App Store Connect API
The App Store Connect API documentation still doesn't list the new 6.9" iPhone display type: https://developer.apple.com/documentation/appstoreconnectapi/screenshotdisplaytype I already opened a similar topic about the new iPad Pro 13" screenshot type in May (4 months ago), but nobody replied and that screenshot type is still not listed in the specification. I also created a bug report in Feedback Assistant back then, without any reply. Why does it take so long to update the API specification?
0
0
968
Sep ’24
SKTexture initialized with system UIImage has slightly wrong aspect ratio and ignores system symbol color
On macOS, system symbols displays in a SKTexture as expected, with the correct color and aspect ratio. But on iOS they are always displayed in black, and sometimes with slightly wrong aspect ratio. Is there a solution to this problem? import SpriteKit #if os(macOS) import AppKit #else import UIKit #endif class GameScene: SKScene { override func didMove(to view: SKView) { let systemImage = "square.and.arrow.up" let width = 400.0 #if os(macOS) let image = NSImage(systemSymbolName: systemImage, accessibilityDescription: nil)!.withSymbolConfiguration(.init(hierarchicalColor: .white))! let scale = NSScreen.main!.backingScaleFactor image.size = CGSize(width: width * scale, height: width / image.size.width * image.size.height * scale) #else let image = UIImage(systemName: systemImage)!.applyingSymbolConfiguration(.init(pointSize: width))!.applyingSymbolConfiguration(.init(hierarchicalColor: .white))! #endif let texture = SKTexture(image: image) print(image.size, texture.size(), image.size.width / image.size.height) let size = CGSize(width: width, height: width / image.size.width * image.size.height) addChild(SKSpriteNode(texture: texture, size: size)) } }
8
0
1.2k
Sep ’24
Xcode downloaded client crash report at libsecinit_appsandbox.c
Among the newest crash reports downloaded by Xcode for my App Store app there is one that contains a single thread, crashed at libsecinit_appsandbox.c, without any trace of my app name. What could possibly cause such a crash? Is this something related with app signing? The app has been on the App Store for a long time and this never happened to me. Thread 0 Crashed: 0 libsystem_secinit.dylib 0x00000001941dcfcc _libsecinit_appsandbox.cold.12 + 60 (libsecinit_appsandbox.c:454) 1 libsystem_secinit.dylib 0x00000001941dbf94 _libsecinit_appsandbox + 1764 (libsecinit_appsandbox.c:454) 2 libsystem_trace.dylib 0x00000001872be598 _os_activity_initiate_impl + 64 (activity.c:131) 3 libsystem_secinit.dylib 0x00000001941db85c _libsecinit_initializer + 80 (libsecinit_initializer.c:17) 4 libSystem.B.dylib 0x00000001941f2664 libSystem_initializer + 280 (init.c:338) 5 dyld 0x00000001871fe608 invocation function for block in dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const::$_0::operator()() const + 168 (Loader.cpp:2198) 6 dyld 0x000000018723cd6c invocation function for block in dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const + 340 (MachOAnalyzer.cpp:2481) 7 dyld 0x0000000187230400 invocation function for block in dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const + 496 (MachOFile.cpp:1669) 8 dyld 0x00000001871df2fc dyld3::MachOFile::forEachLoadCommand(Diagnostics&, void (load_command const*, bool&) block_pointer) const + 300 (MachOFile.cpp:1185) 9 dyld 0x000000018722f394 dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const + 192 (MachOFile.cpp:1628) 10 dyld 0x000000018723c880 dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const + 516 (MachOAnalyzer.cpp:2448) 11 dyld 0x00000001871fa53c dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const + 564 (Loader.cpp:2189) 12 dyld 0x00000001872042d4 dyld4::PrebuiltLoader::runInitializers(dyld4::RuntimeState&) const + 44 (PrebuiltLoader.cpp:818) 13 dyld 0x000000018721dcc0 dyld4::APIs::runAllInitializersForMain() + 84 (DyldAPIs.cpp:3889) 14 dyld 0x00000001871e4010 dyld4::prepare(dyld4::APIs&, dyld3::MachOAnalyzer const*) + 3156 (dyldMain.cpp:891) 15 dyld 0x00000001871e2ef4 start + 1868 (dyldMain.cpp:1265) Crash report
Topic: Code Signing SubTopic: General
2
0
589
Sep ’24
Forcing right to left text direction in Xcode UI test prevents sliders from moving
I'm using the following code to launch a UI test that forces a specific app language and moves a slider. I noticed that when forcing right to left text direction (for Arabic or Hebrew), during the UI test the slider doesn't move. The app content: struct ContentView: View { @State private var slider = 0.0 var body: some View { Slider(value: $slider, in: 0.0...1.0) } } The UI test: final class problemUITests: XCTestCase { func testExample() throws { let app = XCUIApplication() let locale = Locale(identifier: "ar") app.launchArguments += ["-AppleLanguages", "(ar)", "-AppleLocale", "ar"] if locale.language.characterDirection == .rightToLeft { app.launchArguments += ["-NSForceRightToLeftWritingDirection", "YES", "-AppleTextDirection", "YES"] } app.launch() app.sliders.element.adjust(toNormalizedSliderPosition: 0.3) } } Am I missing something or is there a workaround?
0
1
475
Jul ’24
Simulate hardware keyboard button press in Xcode UI test for iPad
XCUIElement has two methods named typeKey(_:modifierFlags:): the first one takes a String as an argument, the second one a XCUIKeyboardKey, which has constants like .downArrow. Now, even if the documentation says that both methods are "Available in macOS and in iPadOS 15 and later", when compiling the UI tests for iOS, the following line app.typeKey(.downArrow, modifierFlags: []) produces a compiler error Type 'String' has no member 'downArrow' Am I missing something or is there a workaround?
0
0
456
Jul ’24
Sample projects of NEFilterProvider use IPC but the documentation says that it blocks IPC
The sample project Filtering Network Traffic uses IPC (NSXPCConnection etc.) to send data from the network extension to the app, but the documentation for NEFilterProvider says The sandbox prevents the Filter Data Provider extension from moving network content outside of its address space by blocking all network access, IPC, and disk write operations. Since my network extension forwards all network traffic to the app so that the user can see it, I was wondering when the app isn’t running and the user shuts down the machine, if the network extension could write the flows it wasn’t able to forward to the app to disk, so that it could read them on the next successful connection to the app. Then almost by accident I read again the documentation and according to the quoted passage a network extension cannot write to disk, but it also cannot use IPC. Is NSXPCConnection not considered IPC, or could the statement that it cannot write to disk be false as well?
3
0
514
Jul ’24