从 js 到 objective C 的谓词

predicate from js to objective C

我有一个 .js 文件用于我的屏幕截图自动化 Instruments.app 我在其中查找具有以下谓词的单元格:

var classScheduleCell = classScheduleTableView.cells().firstWithPredicate("isEnabled == 1 && NONE staticTexts.value BEGINSWITH 'No classes'").withValueForKey(1, "isVisible");

我想将该谓词转换为 objective C UI 测试,因为我用于屏幕截图的 ruby 脚本现在使用 UI 测试而不是 Instruments .使用相同的谓词失败

XCUIElement *firstCell = [classScheduleTableView.cells elementMatchingPredicate:[NSPredicate predicateWithFormat:@"isEnabled == 1 && NONE staticTexts.value BEGINSWITH 'No classes'"]];

看来我可以使谓词的第一部分发生变化

isEnabled == 1

enabled == true

关于如何使另一部分工作的任何想法?

我认为 UI 测试无法实现您的确切谓词。

UI 测试与 UI 自动化

匹配谓词与 UI 测试 (UIT) 的行为与 UI 自动化 (UIA) 的行为略有不同。 UIA 可以更多地访问实际的 UI 工具包元素。 UIT 是一种更 black-box 的方法,只能通过可访问性 API 与元素交互。

NOT谓词

分解您的查询我假设第二部分试图找到标题为 'No classes' 的第一个 而不是 的单元格。首先,让我们匹配 staticTexts.

let predicate = NSPredicate(format: "NOT label BEGINSWITH 'No classes'")
let firstCell = app.staticTexts.elementMatchingPredicate(predicate)
XCTAssert(firstCell.exists)
firstCell.tap() // UI Testing Failure: Multiple matches found

如评论中所述,尝试点击 "first" 单元格会引发异常。这是因为以 "No classes".

开头的文本标签有多个匹配项

NONE谓词

使用 NSPredicate 的 NONE 运算符让我们走上了不同的道路。

let predicate = NSPredicate(format: "NONE label BEGINSWITH 'No classes'")
let firstCell = app.staticTexts.elementMatchingPredicate(predicate)
XCTAssert(firstCell.exists)// XCTAssertTrue failed: throwing "The left hand side for an ALL or ANY operator must be either an NSArray or an NSSet." - 

这种方法甚至找不到单元格。这是因为 elementMatchingPredicate() 期望预测为 return 单个实例,而不是数组或集合。我不知道如何使查询 select 成为第一个元素。一旦你得到 XCUIElement 就没有办法进一步限制它了。

不同的方法

也就是说,我建议您对测试采取稍微不同的方法。如果您的测试是确定性的,而且它们应该是,只需点击第一个已知单元格。这意味着您不必担心不明确的匹配器或链接谓词。

let firstCell = app.staticTexts["Biology"]
XCTAssert(firstCell.exists)
firstCell.tap()

我找到了一个解决方案,虽然不是最优雅的。我找不到使谓词像我在 UI Automation 中那样工作的方法,所以我使用了几个 for 循环来检查单元格标签的值。

NSPredicate *enabledCellsPredicate = [NSPredicate predicateWithFormat:@"enabled == true "];
XCUIElementQuery *enabledCellsQuery = [classScheduleTableView.cells matchingPredicate:enabledCellsPredicate];
int cellCount = enabledCellsQuery.count;
for (int i = 0; i < cellCount; i++) {
    XCUIElement *cellElement = [enabledCellsQuery elementBoundByIndex:i];
    XCUIElementQuery *cellStaticTextsQuery = cellElement.staticTexts;
    int textCount = cellStaticTextsQuery.count;
    BOOL foundNoClasses = NO;
    for (int j = 0; j < textCount; j++) {
        XCUIElement *textElement = [cellStaticTextsQuery elementBoundByIndex:j];
        if (textElement.value && [textElement.value rangeOfString:NSLocalizedString(@"No classes", nil) options:NSCaseInsensitiveSearch].location != NSNotFound) {
            foundNoClasses = YES;
            break;
        }
    }
    if (foundNoClasses == NO) {
        [cellElement tap];
        break;
    }
}

感谢@joe-masilotti 的帮助。