从 js 到目标 C 的谓词

Posted

技术标签:

【中文标题】从 js 到目标 C 的谓词【英文标题】:predicate from js to objective C 【发布时间】:2015-10-26 15:44:53 【问题描述】:

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

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

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

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

看起来我可以改变谓词的第一部分

isEnabled == 1

enabled == true

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

【问题讨论】:

如果将谓词一分为二,您可能会指出 (&& case) 的哪一部分不起作用?我不使用XCUIElement,但是staticTexts.text我不知道staticTexts是什么? 如果我把它分成两部分,我可以让第一部分工作改变 isEnabled == 1 为 enabled == true。 staticTexts.value 是使用 Instruments.app 在 .js 中查找标签值的谓词 【参考方案1】:

我找到了一个解决方案,虽然不是最优雅的。我找不到让谓词像我在 UI 自动化中那样工作的方法,所以我使用了几个 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 的帮助。

【讨论】:

【参考方案2】:

我不相信 UI 测试可以实现您的确切谓词。

UI 测试与 UI 自动化

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

NOT谓词

分解您的查询我假设第二部分试图找到第一个单元格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

如评论中所述,尝试点击“第一个”单元格会引发异常。这是因为以“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() 期望预测返回单个实例,而不是数组或集合。我不知道如何使查询选择第一个元素。一旦你得到XCUIElement,就没有办法进一步限制它了。

不同的方法

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

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

【讨论】:

问题是我需要找到第一个没有“No classes”文本的启用单元格。单元格内容是动态的并且经常变化。我会用你的第一个谓词再试一次,但使用matchingPredicate 而不是elementMatchingPredicate ,所以如果我得到一个XCUIElementQuery,我就可以用elementBoundByIndex 得到第一个元素。我会告诉你这是否有效

以上是关于从 js 到目标 C 的谓词的主要内容,如果未能解决你的问题,请参考以下文章

更新声明:[Amazon](500310) 无效操作:目标表必须是等值连接谓词的一部分;

NSPredicate:比较没有时间的日期(目标 C)

在 Redshift 更新查询中使用左外连接导致错误:目标表必须是等连接谓词的一部分

将变形目标从 Blender 导出到 Three.js

如何在 ios 中将变量从 javascript 传递到目标 C 和目标 C 到 Javascript

js 合并多个对象 Object.assign