I'm trying to write a test script using automation in xcode 4.5.
I have a UICollectionView
and I want to click on some cell not currently visible.
Per documentation, I should expect cells
to return all cells in the collection view, and visibleCells
to return only the currently visible ones.
Instead what I'm seeing is that cells returns only the currently visible cells, and calling visibleCells stops the script on 'undefined' is not a function (evaluating 'collection.visibleCells()')
var target = UIATarget.localTarget();
var collection = target.frontMostApp().mainWindow().collectionViews()[0];
UIALogger.logMessage("Looking in collection: " + collection);
UIALogger.logMessage("Cells: " + collection.cells() + " length " + collection.cells().length);
UIALogger.logMessage("Visible cells: " + collection.visibleCells());
The code above returns the right UICollectionView
, second log line prints:
Cells: [object UIAElementArray] length 12
although I have 100 items in the collection view, and third log line crashes script.
Is this a documentation/UIACollectionView bug?
Any ideas how can I tell the automation to scroll until it sees a cell with the name "My cell"?
I've tried using someCell.scrollToVisible
, but I need to have the cell to do that, and I don't since I can't get it from cells.
EDIT:
As suggested by Jonathan I've implemented a scroll-till-found function.
it's a bit implementation specific, so you'll probably need to tweak isCellWithName
.
I'm also looking to add a break in case we didn't find the needed cell in the while loop, if anyone has ideas, feel free to edit this.
function isCellWithName(cell, name) {
return (cell.staticTexts()[0].name() == name);
}
function getCellWithName(array, name) {
for (var i = 0; i < array.length; i++) {
if (isCellWithName(array[i], name)) {
return array[i];
}
}
return false;
}
function scrollToName(collection, name) {
var found = getCellWithName(collection.cells(), name);
while (found === false) {
collection.dragInsideWithOptions({startOffset:{x:0.2, y:0.99}, endOffset:{x:0.2, y:0},duration:1.0});
found = getCellWithName(collection.cells(), name);
}
return found;
}
The documentation is apparently incorrect. There is no visibleCells()
method on UIACollectionView
. I figured this out by looping over all the collection view elements properties and printing out their names:
var target = UIATarget.localTarget();
var window = target.frontMostApp().mainWindow();
var collectionView = window.collectionViews()[0];
for (var i in collectionView) {
UIALogger.logMessage(i);
}
Table view elements, on the other hand, do list all the cells with the cells()
method. I'm wondering if they choose not to do this because of the much more complicated nature of collection views. It could be very expensive to actually fetch all the collection view cells, build their representations and frames, and return the elements if you had a lot of them. That's what UI Automation does when it asks table views for all the cells. They have to all be instantiated and calculated in order to get the element representations.
But, to answer your larger question, how to scroll to a specific cell. Can you consistently scroll it into view with a swipe gesture? It's not the most convenient way to do it and we're "spoiled" by the ability to scroll to non-visible elements with table views. But from a user behavior testing standpoint, swiping a certain amount is what the user would have to do anyway. Could the test be structured to reflect this and would it address your need?
I couldn't get the the @marmor dragInsideWithOptions()
bit to work in a generic fashion. Instead, I'm using the collectionView's value() function to get an index of the current page vs. last page, as in "page 3 of 11". Then I use collectionView's scrollUp() and scrollDown() methods to walk through the pages until we find what we're after. I wrote an extension for TuneUp's uiautomation-ext.js that seem to do the trick, and more:
function animationDelay() {
UIATarget.localTarget().delay(.2);
}
extend(UIACollectionView.prototype, {
/**
* Apple's bug in UIACollectionView.cells() -- only returns *visible* cells
*/
pageCount: function() {
var pageStatus = this.value();
var words = pageStatus.split(" ");
var lastPage = words[3];
return lastPage;
},
currentPage: function() {
var pageStatus = this.value();
var words = pageStatus.split(" ");
var currentPage = words[1];
//var lastPage = words[3];
return currentPage;
},
scrollToTop: function() {
var current = this.currentPage();
while (current != 1) {
this.scrollUp();
animationDelay();
current = this.currentPage();
}
},
scrollToBottom: function() {
var current = this.currentPage();
var lastPage = this.pageCount();
while (current != lastPage) {
this.scrollDown();
animationDelay();
current = this.currentPage();
}
},
cellCount: function() {
this.scrollToTop();
var current = this.currentPage();
var lastPage = this.pageCount();
var cellCount = this.cells().length;
while (current != lastPage) {
this.scrollDown();
animationDelay();
current = this.currentPage();
cellCount += this.cells().length;
}
return cellCount;
},
currentPageCellNamed: function(name) {
var array = this.cells();
for (var i = 0; i < array.length; i++) {
var cell = array[i];
if (cell.name() == name) {
return cell;
}
}
return false;
},
cellNamed: function(name) {
// for performance, look on the current page first
var foundCell = this.currentPageCellNamed(name);
if (foundCell != false) {
return foundCell;
}
if (this.currentPage() != 1) {
// scroll up and check out the first page before we iterate
this.scrollToTop();
foundCell = this.currentPageCellNamed(name);
if (foundCell != false) {
return foundCell;
}
}
var current = this.currentPage();
var lastPage = this.pageCount();
while (current != lastPage) {
this.scrollDown();
animationDelay();
current = this.currentPage();
foundCell = this.currentPageCellNamed(name);
if (foundCell != false) {
return foundCell;
}
}
return false;
},
/**
* Asserts that this collection view has a cell with the name (accessibility identifier)
* matching the given +name+ argument.
*/
assertCellNamed: function(name) {
assertNotNull(this.cellNamed(name), "No collection cell found named '" + name + "'");
}
});
来源:https://stackoverflow.com/questions/13789905/uiacollectionview-cells-vs-visiblecells