从 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) 无效操作:目标表必须是等值连接谓词的一部分;
在 Redshift 更新查询中使用左外连接导致错误:目标表必须是等连接谓词的一部分