0

I have a UITableView used to show search results. As I type, I’m calling Tableview.reloadData(). Visually, everything works. As I begin typing, I show up to 5 matches and as I go below that, the list will show fewer items correctly. Here are the how the cells are created and number of rows reported.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "placeCell") as! PlaceCell
    if shouldShowSearchResults {
        let place = filteredPlaces[indexPath.row]
        cell.dataSource = place
    } else {
        let place = allPlaces[indexPath.row]
        cell.dataSource = place
    }
    cell.delegate = self
    return cell
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if shouldShowSearchResults {
        vlog?.debug("Number of FILTERED rows in PlacesTableView: \(filteredPlaces.count)")
        return filteredPlaces.count
    } else {
        vlog?.debug("Number of unfiltered rows in PlacesTableView: \(allPlaces.count)")
        return allPlaces.count
    }
}

Since the PlaceCell is a custom class, here are some details of it:

// I've omitted labels, etc.
class PlaceCell: UITableViewCell {

    var dataSource : PlaceView? {
        didSet {
            if let ds = dataSource {
                self.isAccessibilityElement = true
                self.accessibilityLabel = ds.getAccessibilityLabel()

            } else {
                self.isAccessibilityElement = true
                self.accessibilityLabel = nil
            }
        }
    }
    weak var delegate : PlaceCellDelegate? = nil

    override func prepareForReuse() {
        self.isAccessibilityElement = false
        self.accessibilityLabel = nil
        super.prepareForReuse()
    }
}

I began noticing a problem when UI Tests using Google's Earl Grey began failing due to multiple cells with the same Accessibility Label. Visually, I didn't understand why this was failing since there was only one cell visible that matched.

Upon inspect the views using Reveal, it seems that, as the count of cells drops below what was the maximum of 5, the old cells are still in the TableView, but hidden. So there is a hidden cell that used to be displaying the same data as is displayed by a different cell.

Any idea why this would be happening? This has worked for a number of months and I'm not sure what's changed.

markand
  • 2,829
  • 1
  • 16
  • 16
  • You need to show relevant code; `cellForRowAt`, `numberOfCells` - How you are accessing cells in the test. Preferable create an [MCVE] that reproduces the problem – Paulw11 Jan 03 '19 at 00:05
  • Paul - I've added some of the code. A few points. – markand Jan 03 '19 at 00:41
  • Tried to modify the comment, but took too long...(continued) First, the cells are always showing correctly, and the debug logs show that, for example, numberOfCells is returning the correct count. Also, prepareForReuse is being called properly for all cells that are reused, but for the ones that remain hidden, it's not called. As for your question as to how I'm accessing the cells in the test, I'm not. I'm typing in a search box which is calling `reloadData()`. – markand Jan 03 '19 at 00:48
  • But you said that a test is failing; you must have test script that you are using. It may well be an issue with Earl Grey. Anything that crawls the view hierarchy is at risk of having issues if Apple changes what happens under the hood. You said yourself that Reveal shows that the cells are there. If Apple simply makes them hidden and it gives the right visual output, then they can do that. – Paulw11 Jan 03 '19 at 00:54
  • Understood. This is also happening without Earl Grey. If I run the app and simply type in the search bar, when the count of items drops down below where it was (i.e. 5, which is the max), and I inspect the view using Reveal, I see the hidden cells. Where the Earl Grey test fails is simply trying to select the row and tap on it: `EarlGrey.selectElement(with: grey_accessibilityLabel("Whole Foods Market, East Mayo Boulevard, Phoenix").perform(grey_tap())` – markand Jan 03 '19 at 00:59
  • Yes, I understand that it isn't *caused* by Earl Grey, simply that because Earl Grey is inspecting the view hierarchy (which is risky) your test is failing. – Paulw11 Jan 03 '19 at 01:10
  • You probably need something like `visibleSendButtonMatcher = grey_allOf(grey_accessibilityLabel(@"Send"), grey_sufficientlyVisible(), nil);` – Paulw11 Jan 03 '19 at 01:16
  • Well the core of the issue is why would a UITableView not get rid of cells that it's not using, because again, it's happening outside of Earl Grey. I also tried not doing a reloadData but either reloading or removing cells and the removed cells show the same behavior. I'm going to try getting rid of my custom cell and see if that does anything. – markand Jan 03 '19 at 02:46
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/186080/discussion-between-paulw11-and-markand). – Paulw11 Jan 03 '19 at 04:37

1 Answers1

1

It is always perilous when you traverse the view hierarchy; things can change, and perhaps that is what has happened here.

Regardless, you can make your test more robust by only selecting the visible item with the required label by using grey_sufficientlyVisible

Something like:

grey_allOf(grey_accessibilityLabel("Whole Foods Market, East Mayo Boulevard, Phoenix"), grey_sufficientlyVisible(), nil)
Paulw11
  • 108,386
  • 14
  • 159
  • 186