Custom matcher in Swift 5 / Xcode 11 / iOS 13 never sets element in GREYMatchesBlock to a UIView (EarlGrey 2.0)
- Dominant language
- Objective-C
- Stars
- 5.7k
- Forks
- 737
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 5
Description
Tested custom matcher in the example project, fails:
```
// EarlGreyExampleSwiftUITests.swift
func testCustomMatcher() {
let workaroundArray: NSArray = [grey_kindOfClass(UITableViewCell.self), grey_tableCell()]
let matcher = grey_allOf(workaroundArray as! [GREYMatcher])
EarlGrey.selectElement(with: matcher)
.perform(grey_doubleTap())
}
func grey_tableCell() -> GREYMatcher {
let matches: GREYMatchesBlock = { (element: Any?) -> Bool in
if let cell = element as? UITableViewCell { // fails
return true
} else {
print("goes here")
return false
}
}
// Create a description for the matcher.
let describe: GREYDescribeToBlock = { (description: Any) -> Void in
let greyDescription:GREYDescription = description as! GREYDescription
greyDescription.appendText("Table Cell")
}
// Create an EarlGrey custom matcher.
return GREYElementMatcherBlock.init(matchesBlock: matches, descriptionBlock: describe)
}
```
Error message:
```
cannot proceed
t = 3.54s Assertion Failure: EarlGreyExampleSwiftUITests.swift:78: Exception: com.google.earlgrey.ElementInteractionErrorDomain
Exception Name: com.google.earlgrey.ElementInteractionErrorDomain
Exception Reason: {
"User Info" : {
"NSLocalizedDescription" : "Interaction cannot continue because the desired element was not found."
},
"Error Info" : {
"Search API Info" : "",
"Action Name" : "Tap 2 times",
"Recovery Suggestion" : "Check if the element exists in the UI hierarchy printed below. If it exists, adjust the matcher so that it accurately matches element.",
"Element Matcher" : "(kindOfClass('UITableViewCell') && Table Cell)"
},
"Bundle ID" : "com.google.earlgrey.samples.EarlGrey",
"File Name" : "GREYElementInteraction.m",
"Stack Trace" : [
"0 AppFramework 0x000000010047dbce -[GREYElementInteraction matchElementsWithTimeout:syncBeforeMatch:completionBlock:] + 3198",
"1 AppFramework 0x000000010047fed1 -[GREYElementInteraction performAction:error:] + 1617",
"2 CoreFoundation 0x00007fff23e44c4c __invoking___ + 140",
"3 CoreFoundation 0x00007fff23e41e31 -[NSInvocation invoke] + 321",
"4 AppFramework 0x00000001004b2401 __38+[EDOInvocationRequest requestHandler]_block_invoke + 4433",
"5 AppFramework 0x00000001004aed4b -[EDOExecutor edo_handleMessage:] + 331",
"6 AppFramework 0x00000001004aebeb __37-[EDOExecutor handleRequest:context:]_block_invoke_2 + 43",
"7 libdispatch.dylib 0x00007fff51978951 _dispatch_call_block_and_release + 12",
"8 libdispatch.dylib 0x00007fff519798cb _dispatch_client_callout + 8",
"9 libdispatch.dylib 0x00007fff5197f60c _dispatch_lane_serial_drain + 707",
"10 libdispatch.dylib 0x00007fff51980044 _dispatch_lane_invoke + 388",
"11 libdispatch.dylib 0x00007fff5198a0c4 _dispatch_workloop_worker_thread + 626",
"12 libsystem_pthread.dylib 0x00007fff51b9ea3d _pthread_wqthread + 290",
"13 libsystem_pthread.dylib 0x00007fff51b9db77 start_wqthread + 15"
],
"Line" : "160",
"Error Code" : "0",
"App Screenshots" : {
"Screenshot At Failure" :
},
"Function Name" : "-[GREYElementInteraction matchElementsWithTimeout:syncBeforeMatch:completionBlock:]",
"Description" : "Interaction cannot continue because the desired element was not found.",
"Error Domain" : "com.google.earlgrey.ElementInteractionErrorDomain"
}
Exception Details: (kindOfClass('UITableViewCell') && Table Cell)
Bundle ID: com.google.EarlGreyExampleSwiftUITests.xctrunner
Stack Trace: (
0 EarlGreyExampleSwiftUITests 0x000000010546e96e -[GREYDefaultFailureHandler handleException:details:] + 2078
1 EarlGreyExampleSwiftUITests 0x000000010546eede +[GREYElementInteractionErrorHandler handleInteractionError:outError:] + 542
2 EarlGreyExampleSwiftUITests 0x000000010546f372 -[GREYElementInteractionProxy performAction:error:] + 498
3 EarlGreyExampleSwiftUITests 0x000000010546f14f -[GREYElementInteractionProxy performAction:] + 79
4 EarlGreyExampleSwiftUITests 0x0000000105464d3b $sSo15GREYInteractionP15EarlGreyExampleE7performyxSo10GREYAction_pF + 59
5 EarlGreyExampleSwiftUITests 0x0000000105466130 $s15EarlGreyExample0abC12SwiftUITestsC17testCustomMatcheryyF + 608
6 EarlGreyExampleSwiftUITests 0x000000010546637b $s15EarlGreyExample0abC12SwiftUITestsC17testCustomMatcheryyFTo + 43
7 CoreFoundation 0x00007fff23e44c4c __invoking___ + 140
8 CoreFoundation 0x00007fff23e41e31 -[NSInvocation invoke] + 321
9 EarlGreyExampleSwiftUITests 0x000000010547c168 -[GREYTestCaseInvocation invoke] + 104
10 XCTest 0x0000000103463037 __24-[XCTestCase invokeTest]_block_invoke_2 + 52
11 XCTest 0x0000000103462fe3 __24-[XCTestCase invokeTest]_block_invoke.206 + 320
12 XCTest 0x00000001034bddc2 +[XCTestCase(Failures) performFailableBlock:testCase:testCaseRun:shouldInterruptTest:] + 69
13 XCTest 0x00000001034bdcd4 -[XCTestCase(Failures) _performTurningExceptionsIntoFailuresInterruptAfterHandling:block:] + 115
14 XCTest 0x00000001034629f6 -[XCTestCase invokeTest] + 1183
15 EarlGreyExampleSwiftUITests 0x00000001054844f0 -[XCTestCase(GREYTest) grey_invokeTest] + 992
16 XCTest 0x0000000103464329 __26-[XCTestCase performTest:]_block_invoke_2 + 43
17 XCTest 0x00000001034bddc2 +[XCTestCase(Failures) performFailableBlock:testCase:testCaseRun:shouldInterruptTest:] + 69
18 XCTest 0x00000001034bdcd4 -[XCTestCase(Failures) _performTurningExceptionsIntoFailuresInterruptAfterHandling:block:] + 115
19 XCTest 0x0000000103464260 __26-[XCTestCase performTest:]_block_invoke.359 + 86
20 XCTest 0x00000001034d0a0d +[XCTContext runInContextForTestCase:block:] + 211
21 XCTest 0x0000000103463b14 -[XCTestCase performTest:] + 566
22 XCTest 0x00000001034aa38e -[XCTest runTest] + 57
23 XCTest 0x000000010345dd50 __27-[XCTestSuite performTest:]_block_invoke + 354
24 XCTest 0x000000010345d4a2 __59-[XCTestSuite _performProtectedSectionForTest:testSection:]_block_invoke + 24
25 XCTest 0x00000001034d0a0d +[XCTContext runInContextForTestCase:block:] + 211
26 XCTest 0x000000010345d459 -[XCTestSuite _performProtectedSectionForTest:testSection:] + 148
27 XCTest 0x000000010345d7be -[XCTestSuite performTest:] + 348
28 XCTest 0x00000001034aa38e -[XCTest runTest] + 57
29 XCTest 0x000000010345dd50 __27-[XCTestSuite performTest:]_block_invoke + 354
30 XCTest 0x000000010345d4a2 __59-[XCTestSuite _performProtectedSectionForTest:testSection:]_block_invoke + 24
31 XCTest 0x00000001034d0a0d +[XCTContext runInContextForTestCase:block:] + 211
32 XCTest 0x000000010345d459 -[XCTestSuite _performProtectedSectionForTest:testSection:] + 148
33 XCTest 0x000000010345d7be -[XCTestSuite performTest:] + 348
34 XCTest 0x00000001034aa38e -[XCTest runTest] + 57
35 XCTest 0x000000010345dd50 __27-[XCTestSuite performTest:]_block_invoke + 354
36 XCTest 0x000000010345d4a2 __59-[XCTestSuite _performProtectedSectionForTest:testSection:]_block_invoke + 24
37 XCTest 0x00000001034d0a0d +[XCTContext runInContextForTestCase:block:] + 211
38 XCTest 0x000000010345d459 -[XCTestSuite _performProtectedSectionForTest:testSection:] + 148
39 XCTest 0x000000010345d7be -[XCTestSuite performTest:] + 348
40 XCTest 0x00000001034aa38e -[XCTest runTest] + 57
41 XCTest 0x00000001034dff14 __44-[XCTTestRunSession runTestsAndReturnError:]_block_invoke + 171
42 XCTest 0x00000001034e0001 __44-[XCTTestRunSession runTestsAndReturnError:]_block_invoke.100 + 96
43 XCTest 0x0000000103478746 -[XCTestObservationCenter _observeTestExecutionForBlock:] + 682
44 XCTest 0x00000001034dfc9f -[XCTTestRunSession runTestsAndReturnError:] + 615
45 XCTest 0x0000000103441744 -[XCTestDriver runTestsAndReturnError:] + 456
46 XCTest 0x00000001034cc64c _XCTestMain + 2496
47 EarlGreyExampleSwiftUITests-Runner 0x000000010324ee1a -[_XCTRunnerAppDelegate applicationWillResignActive:] + 0
48 EarlGreyExampleSwiftUITests-Runner 0x000000010324ed18 _XCTRunnerRunTests + 0
49 CoreFoundation 0x00007fff23da1a9c __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
50 CoreFoundation 0x00007fff23da1193 __CFRunLoopDoBlocks + 195
51 CoreFoundation 0x00007fff23d9bf83 __CFRunLoopRun + 995
52 CoreFoundation 0x00007fff23d9b884 CFRunLoopRunSpecific + 404
53 GraphicsServices 0x00007fff38b5ac1a GSEventRunModal + 139
54 UIKitCore 0x00007fff48c19220 UIApplicationMain + 1605
55 EarlGreyExampleSwiftUITests-Runner 0x000000010324efd5 main + 183
56 libdyld.dylib 0x00007fff519b910d start + 1
)
Screenshots: {
"Screenshot At Failure" :
}
UI Hierarchy (ordered by window level, front to back):
Legend: {
"[Window 1]" : "Frontmost Window",
"[AX]" : "Accessibility",
"[UIE]" : "User Interaction Enabled"
}
========== Window 1 ==========
|--
| |--
| |--
**** No Animating Views Found. ****
========== Window 2 ==========
|--
| |--
| | |--
| | | |--
| | | | |--<_UIScrollViewScrollIndicator:0x7faa27b090c0; isAccessible=N; AX.label='Horizontal scroll bar, 1 page'; AX.value='0%'; AX.frame={{31.333333333333332, 863}, {288, 30}}; AX.activationPoint={175.33333333333334, 891.5}; AX.traits='UIAccessibilityTraitAdjustable'; AX.focused='N'; frame={{24.333333333333343, 710}, {282, 3}}; opaque; alpha=0>
| | | | | |--
| | | | |--<_UIScrollViewScrollIndicator:0x7faa2780a510; isAccessible=N; AX.label='Vertical scroll bar, 6 pages'; AX.value='0%'; AX.frame={{297, 180}, {30, 716}}; AX.activationPoint={325.5, 242.33333333333334}; AX.traits='UIAccessibilityTraitAdjustable'; AX.focused='N'; frame={{314, 3}, {3, 118.66666666666667}}; opaque; alpha=0>
| | | | | |--
| | | | |--
| | | | | |--<_UITableViewCellSeparatorView:0x7faa2561e340; isAccessible=N; AX.frame={{26, 223.66666666666666}, {304, 0.33333333333334281}}; AX.activationPoint={178, 223.83333333333331}; AX.traits='UIAccessibilityTraitNone'; AX.focused='N'; frame={{16, 43.666666666666664}, {304, 0.33333333333333331}}; opaque; alpha=1>
| | | | | |--
| | | | | | |--
| | | | |--
| | | | | |--<_UITableViewCellSeparatorView:0x7faa27b2d650; isAccessible=N; AX.frame={{26, 267.66666666666663}, {304, 0.33333333333331439}}; AX.activationPoint={178, 267.83333333333326}; AX.traits='UIAccessibilityTraitNone'; AX.focused='N'; frame={{16, 43.666666666666664}, {304, 0.33333333333333331}}; opaque; alpha=1>
| | | | | |--
| | | | | | |--
| | | | |--
| | | | | |--<_UITableViewCellSeparatorView:0x7faa27b2e070; isAccessible=N; AX.frame={{26, 311.66666666666663}, {304, 0.33333333333331439}}; AX.activationPoint={178, 311.83333333333326}; AX.traits='UIAccessibilityTraitNone'; AX.focused='N'; frame={{16, 43.666666666666664}, {304, 0.33333333333333331}}; opaque; alpha=1>
| | | | | |--
| | | | | | |--
| | | | |--
| | | | | |--<_UITableViewCellSeparatorView:0x7faa27b2a210; isAccessible=N; AX.frame={{26, 355.66666666666663}, {304, 0.33333333333331439}}; AX.activationPoint={178, 355.83333333333326}; AX.traits='UIAccessibilityTraitNone'; AX.focused='N'; frame={{16, 43.666666666666664}, {304, 0.33333333333333331}}; opaque; alpha=1>
| | | | | |--
| | | | | | |--
| | | | |--
| | | | | |--<_UITableViewCellSeparatorView:0x7faa27b28620; isAccessible=N; AX.frame={{26, 399.66666666666663}, {304, 0.33333333333331439}}; AX.activationPoint={178, 399.83333333333326}; AX.traits='UIAccessibilityTraitNone'; AX.focused='N'; frame={{16, 43.666666666666664}, {304, 0.33333333333333331}}; opaque; alpha=1>
| | | | | |--
| | | | | | |--
| | | | |--
| | | | | |--<_UITableViewCellSeparatorView:0x7faa27b2f8f0; isAccessible=N; AX.frame={{26, 443.66666666666669}, {304, 0.33333333333331439}}; AX.activationPoint={178, 443.83333333333337}; AX.traits='UIAccessibilityTraitNone'; AX.focused='N'; frame={{16, 43.666666666666664}, {304, 0.33333333333333331}}; opaque; alpha=1>
| | | | | |--
| | | | | | |--
| | | | |--
| | | | | |--<_UITableViewCellSeparatorView:0x7faa27b305b0; isAccessible=N; AX.frame={{26, 487.66666666666669}, {304, 0.33333333333331439}}; AX.activationPoint={178, 487.83333333333337}; AX.traits='UIAccessibilityTraitNone'; AX.focused='N'; frame={{16, 43.666666666666664}, {304, 0.33333333333333331}}; opaque; alpha=1>
| | | | | |--
| | | | | | |--
| | | | |--
| | | | | |--<_UITableViewCellSeparatorView:0x7faa27b31270; isAccessible=N; AX.frame={{26, 531.66666666666674}, {304, 0.33333333333337123}}; AX.activationPoint={178, 531.83333333333348}; AX.traits='UIAccessibilityTraitNone'; AX.focused='N'; frame={{16, 43.666666666666664}, {304, 0.33333333333333331}}; opaque; alpha=1>
| | | | | |--
| | | | | | |--
| | | | |--
| | | | | |--<_UITableViewCellSeparatorView:0x7faa27b31f30; isAccessible=N; AX.frame={{26, 575.66666666666674}, {304, 0.33333333333337123}}; AX.activationPoint={178, 575.83333333333348}; AX.traits='UIAccessibilityTraitNone'; AX.focused='N'; frame={{16, 43.666666666666664}, {304, 0.33333333333333331}}; opaque; alpha=1>
| | | | | |--
| | | | | | |--
| | | | |--
| | | | | |--<_UITableViewCellSeparatorView:0x7faa27b32df0; isAccessible=N; AX.frame={{26, 619.66666666666674}, {304, 0.33333333333337123}}; AX.activationPoint={178, 619.83333333333348}; AX.traits='UIAccessibilityTraitNone'; AX.focused='N'; frame={{16, 43.666666666666664}, {304, 0.33333333333333331}}; opaque; alpha=1>
| | | | | |--
| | | | | | |--
| | | | |--
| | | | | |--<_UITableViewCellSeparatorView:0x7faa27b33ab0; isAccessible=N; AX.frame={{26, 663.66666666666674}, {304, 0.33333333333337123}}; AX.activationPoint={178, 663.83333333333348}; AX.traits='UIAccessibilityTraitNone'; AX.focused='N'; frame={{16, 43.666666666666664}, {304, 0.33333333333333331}}; opaque; alpha=1>
| | | | | |--
| | | | | | |--
| | | | |--
| | | | | |--<_UITableViewCellSeparatorView:0x7faa27b34770; isAccessible=N; AX.frame={{26, 707.66666666666663}, {304, 0.33333333333337123}}; AX.activationPoint={178, 707.83333333333326}; AX.traits='UIAccessibilityTraitNone'; AX.focused='N'; frame={{16, 43.666666666666664}, {304, 0.33333333333333331}}; opaque; alpha=1>
| | | | | |--
| | | | | | |--
| | | | |--
| | | | | |--<_UITableViewCellSeparatorView:0x7faa27b35430; isAccessible=N; AX.frame={{26, 751.66666666666663}, {304, 0.33333333333337123}}; AX.activationPoint={178, 751.83333333333326}; AX.traits='UIAccessibilityTraitNone'; AX.focused='N'; frame={{16, 43.666666666666664}, {304, 0.33333333333333331}}; opaque; alpha=1>
| | | | | |--
| | | | | | |--
| | | | |--
| | | | | |--<_UITableViewCellSeparatorView:0x7faa27b36220; isAccessible=N; AX.frame={{26, 795.66666666666663}, {304, 0.33333333333337123}}; AX.activationPoint={178, 795.83333333333326}; AX.traits='UIAccessibilityTraitNone'; AX.focused='N'; frame={{16, 43.666666666666664}, {304, 0.33333333333333331}}; opaque; alpha=1>
| | | | | |--
| | | | | | |--
| | | | |--
| | | | | |--<_UITableViewCellSeparatorView:0x7faa27b37120; isAccessible=N; AX.frame={{26, 839.66666666666663}, {304, 0.33333333333337123}}; AX.activationPoint={178, 839.83333333333326}; AX.traits='UIAccessibilityTraitNone'; AX.focused='N'; frame={{16, 43.666666666666664}, {304, 0.33333333333333331}}; opaque; alpha=1>
| | | | | |--
| | | | | | |--
| | | | |--
| | | | | |--<_UITableViewCellSeparatorView:0x7faa27b37de0; isAccessible=N; AX.frame={{26, 883.66666666666663}, {304, 0.33333333333337123}}; AX.activationPoint={178, 883.83333333333326}; AX.traits='UIAccessibilityTraitNone'; AX.focused='N'; frame={{16, 43.666666666666664}, {304, 0.33333333333333331}}; opaque; alpha=1>
| | | | | |--
| | | | | | |--
| | | | |--
| | | | | |--<_UITableViewCellSeparatorView:0x7faa27b38aa0; isAccessible=N; AX.frame={{26, 927.66666666666663}, {304, 0.33333333333337123}}; AX.activationPoint={178, 927.83333333333326}; AX.traits='UIAccessibilityTraitNone'; AX.focused='N'; frame={{16, 43.666666666666664}, {304, 0.33333333333333331}}; opaque; alpha=1>
| | | | | |--
| | | | | | |--
| | | |--
| | | | |--
| | | |--
| | | | |--
| | | |--
| | | | |--
| | | | | |--
| | | |--<_UILayoutGuide:0x7faa2780a140; isAccessible=N; AX.frame={{0, 862}, {0, 34}}; AX.activationPoint={0, 879}; AX.traits='UIAccessibilityTraitNone'; AX.focused='N'; frame={{0, 862}, {0, 34}}; opaque; hidden; alpha=1>
| | | |--<_UILayoutGuide:0x7faa27809db0; isAccessible=N; AX.frame={{0, 0}, {0, 44}}; AX.activationPoint={0, 22}; AX.traits='UIAccessibilityTraitNone'; AX.focused='N'; frame={{0, 0}, {0, 44}}; opaque; hidden; alpha=1>
```
_Originally posted by @whoyawn in https://github.com/google/EarlGrey/issues/1281#issuecomment-617482793_
Contributor guide
Research direction
Start with EarlGreyExampleSwiftUITests.swift and reproduce testCustomMatcher using the GREYMatchesBlock shown. Inspect the failed interaction reported from GREYElementInteraction.m and the printed UI hierarchy; done means the custom matcher recognizes the intended UITableViewCell and the double-tap interaction succeeds.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- ios, objective-c, swift
- Domain
- mobile, testing-qa
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100