Pircate / EachNavigationBar

A custom navigation bar for each view controller.
MIT License
591 stars 70 forks source link

Help needed: BackItem broken for UITests #35

Open luke-riu opened 3 years ago

luke-riu commented 3 years ago

Since bringing this (fantastic) library in, my UI test has failed when trying to press the back button in the navigation bar. Do you know if there is a trick to getting it tappable at all? I used to have app.navigationBars.buttons.element(boundBy: 0).tap(), but that is now failing with

Failed to synthesize event: Failed to scroll to visible (by AX action) Button, label: 'Back', error: Error kAXErrorCannotComplete performing AXAction 2003 on element AX element pid: 15737, elementOrHash.elementID: 105553178871296.256. (Underlying Error: Error kAXErrorCannotComplete performing AXAction 2003 on element AX element pid: 15737, elementOrHash.elementID: 105553178871296.256)

Any help appreciated. Thanks a lot Luke

Pircate commented 3 years ago

Which version are you using?

luke-riu commented 3 years ago

My podlock file shows 1.15.0

Pircate commented 3 years ago

Can I have a look at your code?

luke-riu commented 3 years ago

Sure. Ignore the custom Colour., Fonts. and Image.. These are SwiftGen structs for UIColor, UIFont and UIImage

In my UINavigationController subclass, I have

private func setupNavigationBar() {
    self.navigation.configuration.isEnabled = true
    self.navigation.configuration.titleTextAttributes = [
      .foregroundColor: Colour.text
    ]
    self.navigation.configuration.barTintColor = Colour.layer1
    self.navigation.configuration.isTranslucent = false
    self.navigation.configuration.isHidden = true
    self.navigation.configuration.backItem = UINavigationController
      .Configuration
      .BackItem(style: .image(Image.back),
                tintColor: Colour.text)

  }

The homepage has

private fund setupNavigationBar() {
    self.navigation.bar.isHidden = false

    self.navigation.bar.prefersLargeTitles = false
    self.navigation.item.largeTitleDisplayMode = .never
    self.navigation.bar.additionalHeight = 20

    // acts as a bit of a skirt to keep the label off the bottom of the nav bar
    let navFooter = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 18))
    navFooter.backgroundColor = Colour.layer1
    self.navigation.bar.additionalView = navFooter

     // title
    let label = UILabel(frame: .zero)
    label.text = "Explore"
    label.font = Fonts.h2
    self.navigation.item.leftBarButtonItem = UIBarButtonItem(customView: label)

     // search button
    let imageview = UIImageView()
    imageview.image = Image.search.withRenderingMode(.alwaysTemplate)
    imageview.tintColor = Colour.text

    let searchButton = UIButton(type: .custom)
    searchButton.addTarget(buttonTarget, action: buttonSelector, for: .touchUpInside)
    searchButton.addSubview(imageview)
    searchButton.accessibilityIdentifier = "nav_button"

   // snapkit constraints
    imageview.snp.makeConstraints { (make) in
      make.width.height.equalTo(24)
      make.left.right.equalToSuperview()
      make.top.bottom.equalToSuperview().inset(10)
    }

    self.navigation.item.rightBarButtonItem = UIBarButtonItem(customView: searchButton)
}

Before the next view controller is pushed, I call

trendingViewController.navigationItem.title = "Trending"

then in viewDidLoad(animated:) on that view controller, I call

    self.navigation.bar.prefersLargeTitles = true
    self.navigation.item.largeTitleDisplayMode = .always

Then, my UI tests goes something like this

    let app = XCUIApplication()
    // tap cell to get into view controller
    // test element exists
    app.navigationBars.buttons.element(boundBy: 0).tap() // <-- fails

Thanks

Pircate commented 3 years ago
navigation.bar.backBarButtonItem = .init(style: .image(image))

Try using it in trendingViewController

luke-riu commented 3 years ago

Sadly not made any difference. Putting a breakpoint in my test, when I type into the console

po app.navigationBars.buttons

I get the following output

Find: Target Application 'com.my.app'
  Output: {
    Application, pid: 18209, label: 'App'
  }
  ↪︎Find: Descendants matching type NavigationBar
    Output: {
      NavigationBar, {{0.0, 47.0}, {428.0, 96.0}}, identifier: 'Trending'
      NavigationBar, {{0.0, 47.0}, {428.0, 96.0}}, identifier: 'Trending'
    }
    ↪︎Find: Descendants matching type Button
      Output: {
        Button, {{0.0, 47.0}, {55.7, 44.0}}, label: 'Back'
        Button, {{12.0, 47.0}, {36.0, 44.0}}
      }

I'm sure you'll know better than me, but I think it a bit weird there are two buttons, one which says "Back". Either way, when doing either po app.navigationBars.buttons.element(boundBy: 0).isHittable is false for both 0 and 1. I'm not sure if that's helpful.