Source/WebCore/ChangeLog

 12016-10-13 Nan Wang <n_wang@apple.com>
 2
 3 AX: [Mac] better accessibility support for Summary elements
 4 https://bugs.webkit.org/show_bug.cgi?id=163367
 5 <rdar://problem/28745010>
 6
 7 Reviewed by NOBODY (OOPS!).
 8
 9 Exposed summary elements as AXButton and used the text node's content
 10 as AXTitle. Also exposed the details parent's expanded status on the summary
 11 element, so that users would see it as a collapsed/expanded button.
 12
 13 Changes are covered in the modified tests.
 14
 15 * accessibility/AccessibilityObject.cpp:
 16 (WebCore::AccessibilityObject::parentObjectUnignored):
 17 (WebCore::AccessibilityObject::scrollViewAncestor):
 18 (WebCore::AccessibilityObject::headingElementForNode):
 19 (WebCore::AccessibilityObject::matchedParent):
 20 (WebCore::AccessibilityObject::isDescendantOfObject):
 21 (WebCore::AccessibilityObject::isInsideARIALiveRegion):
 22 (WebCore::AccessibilityObject::isExpanded):
 23 (WebCore::AccessibilityObject::isARIAHidden):
 24 (WebCore::AccessibilityObject::focusableAncestor):
 25 (WebCore::AccessibilityObject::editableAncestor):
 26 * accessibility/AccessibilityObject.h:
 27 (WebCore::AccessibilityObject::isSummary):
 28 * accessibility/ios/WebAccessibilityObjectWrapperIOS.mm:
 29 (-[WebAccessibilityObjectWrapper _accessibilityListAncestor]):
 30 (-[WebAccessibilityObjectWrapper _accessibilityLandmarkAncestor]):
 31 (-[WebAccessibilityObjectWrapper _accessibilityTableAncestor]):
 32 (-[WebAccessibilityObjectWrapper _accessibilityFieldsetAncestor]):
 33 (-[WebAccessibilityObjectWrapper tableCellParent]):
 34 (-[WebAccessibilityObjectWrapper tableParent]):
 35 (-[WebAccessibilityObjectWrapper convertPointToScreenSpace:]):
 36 (-[WebAccessibilityObjectWrapper convertRectToScreenSpace:]):
 37 (-[WebAccessibilityObjectWrapper detailParentForSummaryObject:]):
 38 (-[WebAccessibilityObjectWrapper detailParentForObject:]):
 39 (matchedParent): Deleted.
 40 * accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
 41 (-[WebAccessibilityObjectWrapper additionalAccessibilityAttributeNames]):
 42 (createAccessibilityRoleMap):
 43 (-[WebAccessibilityObjectWrapper roleDescription]):
 44 (-[WebAccessibilityObjectWrapper accessibilityAttributeValue:]):
 45
1462016-10-12 Chris Dumez <cdumez@apple.com>
247
348 [Web IDL] Drop support for legacy [ConstructorConditional=*]
207279

Source/WebCore/accessibility/AccessibilityObject.cpp

@@int AccessibilityObject::blockquoteLevel
457457
458458AccessibilityObject* AccessibilityObject::parentObjectUnignored() const
459459{
460  AccessibilityObject* parent;
461  for (parent = parentObject(); parent && parent->accessibilityIsIgnored(); parent = parent->parentObject()) {
462  }
463 
464  return parent;
 460 return AccessibilityObject::matchedParent(const_cast<AccessibilityObject*>(this), false, [] (AccessibilityObject* object) {
 461 return !object->accessibilityIsIgnored();
 462 });
465463}
466464
467465AccessibilityObject* AccessibilityObject::previousSiblingUnignored(int limit) const

@@void AccessibilityObject::updateBackingS
16961694
16971695ScrollView* AccessibilityObject::scrollViewAncestor() const
16981696{
1699  for (const AccessibilityObject* scrollParent = this; scrollParent; scrollParent = scrollParent->parentObject()) {
1700  if (is<AccessibilityScrollView>(*scrollParent))
1701  return downcast<AccessibilityScrollView>(*scrollParent).scrollView();
1702  }
 1697 if (AccessibilityObject* scrollParent = AccessibilityObject::matchedParent(const_cast<AccessibilityObject*>(this), true, [] (AccessibilityObject* object) {
 1698 return is<AccessibilityScrollView>(*object);
 1699 }))
 1700 return downcast<AccessibilityScrollView>(*scrollParent).scrollView();
17031701
17041702 return nullptr;
17051703}

@@AccessibilityObject* AccessibilityObject
17901788 return nullptr;
17911789
17921790 AccessibilityObject* axObject = renderObject->document().axObjectCache()->getOrCreate(renderObject);
1793  for (; axObject && axObject->roleValue() != HeadingRole; axObject = axObject->parentObject()) { }
17941791
1795  return axObject;
 1792 return AccessibilityObject::matchedParent(axObject, true, [] (AccessibilityObject* object) {
 1793 return object->roleValue() == HeadingRole;
 1794 });
 1795}
 1796
 1797AccessibilityObject* AccessibilityObject::matchedParent(AccessibilityObject* object, bool includeSelf, const std::function<bool(AccessibilityObject*)>& matches)
 1798{
 1799 AccessibilityObject* parent = includeSelf ? object : object->parentObject();
 1800 for (; parent; parent = parent->parentObject()) {
 1801 if (matches(parent))
 1802 return (parent);
 1803 }
 1804 return nullptr;
17961805}
17971806
17981807void AccessibilityObject::ariaTreeRows(AccessibilityChildrenVector& result)

@@bool AccessibilityObject::isDescendantOf
20342043{
20352044 if (!axObject || !axObject->hasChildren())
20362045 return false;
2037 
2038  for (const AccessibilityObject* parent = parentObject(); parent; parent = parent->parentObject()) {
2039  if (parent == axObject)
2040  return true;
2041  }
2042  return false;
 2046
 2047 return AccessibilityObject::matchedParent(const_cast<AccessibilityObject*>(this), false, [axObject] (AccessibilityObject* object) {
 2048 return object == axObject;
 2049 }) != nullptr;
20432050}
20442051
20452052bool AccessibilityObject::isAncestorOfObject(const AccessibilityObject* axObject) const

@@bool AccessibilityObject::isInsideARIALi
23072314 if (supportsARIALiveRegion())
23082315 return true;
23092316
2310  for (AccessibilityObject* axParent = parentObject(); axParent; axParent = axParent->parentObject()) {
2311  if (axParent->supportsARIALiveRegion())
2312  return true;
2313  }
2314 
2315  return false;
 2317 return AccessibilityObject::matchedParent(const_cast<AccessibilityObject*>(this), false, [] (AccessibilityObject* object) {
 2318 return object->supportsARIALiveRegion();
 2319 }) != nullptr;
23162320}
23172321
23182322bool AccessibilityObject::supportsARIAAttributes() const

@@bool AccessibilityObject::isExpanded() c
24782482 if (is<HTMLDetailsElement>(node()))
24792483 return downcast<HTMLDetailsElement>(node())->isOpen();
24802484
 2485 // Summary element should use its details parent's expanded status.
 2486 if (isSummary()) {
 2487 if (AccessibilityObject* parent = AccessibilityObject::matchedParent(const_cast<AccessibilityObject*>(this), false, [] (AccessibilityObject* object) {
 2488 return object->roleValue() == DetailsRole;
 2489 }))
 2490 return parent->isExpanded();
 2491 }
 2492
24812493 return false;
24822494}
24832495

@@bool AccessibilityObject::accessibilityI
29342946// http://www.w3.org/TR/wai-aria/terms#def_hidden
29352947bool AccessibilityObject::isARIAHidden() const
29362948{
2937  for (const AccessibilityObject* object = this; object; object = object->parentObject()) {
2938  if (equalLettersIgnoringASCIICase(object->getAttribute(aria_hiddenAttr), "true"))
2939  return true;
2940  }
2941  return false;
 2949 return AccessibilityObject::matchedParent(const_cast<AccessibilityObject*>(this), true, [] (AccessibilityObject* object) {
 2950 return equalLettersIgnoringASCIICase(object->getAttribute(aria_hiddenAttr), "true");
 2951 }) != nullptr;
29422952}
29432953
29442954// DOM component of hidden definition.

@@void AccessibilityObject::setPreventKeyb
30353045
30363046AccessibilityObject* AccessibilityObject::focusableAncestor()
30373047{
3038  AccessibilityObject* potentialFocusableAncestor = this;
3039  while (potentialFocusableAncestor) {
3040  if (potentialFocusableAncestor->canSetFocusAttribute())
3041  return potentialFocusableAncestor;
3042  potentialFocusableAncestor = potentialFocusableAncestor->parentObject();
3043  }
3044 
3045  return nullptr;
 3048 return AccessibilityObject::matchedParent(const_cast<AccessibilityObject*>(this), true, [] (AccessibilityObject* object) {
 3049 return object->canSetFocusAttribute();
 3050 });
30463051}
30473052
30483053AccessibilityObject* AccessibilityObject::editableAncestor()
30493054{
3050  AccessibilityObject* potentialEditableAncestor = this;
3051  while (potentialEditableAncestor) {
3052  if (potentialEditableAncestor->isTextControl())
3053  return potentialEditableAncestor;
3054  potentialEditableAncestor = potentialEditableAncestor->parentObject();
3055  }
3056 
3057  return nullptr;
 3055 return AccessibilityObject::matchedParent(const_cast<AccessibilityObject*>(this), true, [] (AccessibilityObject* object) {
 3056 return object->isTextControl();
 3057 });
30583058}
30593059
30603060AccessibilityObject* AccessibilityObject::highestEditableAncestor()
207268

Source/WebCore/accessibility/AccessibilityObject.h

@@public:
561561 bool isSubscriptStyleGroup() const;
562562 bool isSuperscriptStyleGroup() const;
563563 bool isFigure() const;
 564 bool isSummary() const { return roleValue() == SummaryRole; }
564565
565566 virtual bool isChecked() const { return false; }
566567 virtual bool isEnabled() const { return false; }

@@public:
10621063 AccessibilityObject* editableAncestor();
10631064 AccessibilityObject* highestEditableAncestor();
10641065
 1066 static AccessibilityObject* matchedParent(AccessibilityObject*, bool includeSelf, const std::function<bool(AccessibilityObject*)>&);
 1067
10651068protected:
10661069 AXID m_id;
10671070 AccessibilityChildrenVector m_children;
207268

Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm

@@static AccessibilityObjectWrapper* Acces
131131 return wrapper;
132132}
133133
134 template<typename MatchFunction>
135 static AccessibilityObject* matchedParent(AccessibilityObject* object, bool includeSelf, const MatchFunction& matches)
136 {
137  if (!object)
138  return nullptr;
139 
140  AccessibilityObject* parent = includeSelf ? object : object->parentObject();
141  for (; parent; parent = parent->parentObject()) {
142  if (matches(parent))
143  return parent;
144  }
145 
146  return nullptr;
147 }
148 
149 
150134#pragma mark Accessibility Text Marker
151135
152136@interface WebAccessibilityTextMarker : NSObject

@@- (AccessibilityObjectWrapper*)_accessib
554538 return role == ListRole || role == ListBoxRole;
555539 };
556540
557  if (AccessibilityObject* parent = matchedParent(m_object, false, matchFunc))
 541 if (AccessibilityObject* parent = AccessibilityObject::matchedParent(m_object, false, matchFunc))
558542 return parent->wrapper();
559543 return nil;
560544}
561545
562546- (AccessibilityObjectWrapper*)_accessibilityLandmarkAncestor
563547{
564  auto matchFunc = [self] (AccessibilityObject* object) {
 548 if (AccessibilityObject* parent = AccessibilityObject::matchedParent(m_object, false, [self] (AccessibilityObject* object) {
565549 return [self _accessibilityIsLandmarkRole:object->roleValue()];
566  };
567 
568  if (AccessibilityObject* parent = matchedParent(m_object, false, matchFunc))
 550 }))
569551 return parent->wrapper();
570552 return nil;
571553}
572554
573555- (AccessibilityObjectWrapper*)_accessibilityTableAncestor
574556{
575  auto matchFunc = [] (AccessibilityObject* object) {
576  return object->roleValue() == TableRole || object->roleValue() == GridRole;
577  };
578557
579  if (AccessibilityObject* parent = matchedParent(m_object, false, matchFunc))
 558 if (AccessibilityObject* parent = AccessibilityObject::matchedParent(m_object, false, [] (AccessibilityObject* object) {
 559 return object->roleValue() == TableRole || object->roleValue() == GridRole;
 560 }))
580561 return parent->wrapper();
581562 return nil;
582563}
583564
584565- (AccessibilityObjectWrapper*)_accessibilityFieldsetAncestor
585566{
586  auto matchFunc = [] (AccessibilityObject* object) {
 567 if (AccessibilityObject* parent = AccessibilityObject::matchedParent(m_object, false, [] (AccessibilityObject* object) {
587568 return object->isFieldset();
588  };
589 
590  if (AccessibilityObject* parent = matchedParent(m_object, false, matchFunc))
 569 }))
591570 return parent->wrapper();
592571 return nil;
593572}

@@- (NSString *)accessibilityLabel
10411020- (AccessibilityTableCell*)tableCellParent
10421021{
10431022 // Find if this element is in a table cell.
1044  auto matchFunc = [] (AccessibilityObject* object) {
 1023 if (AccessibilityObject* parent = AccessibilityObject::matchedParent(m_object, true, [] (AccessibilityObject* object) {
10451024 return object->isTableCell();
1046  };
1047 
1048  if (AccessibilityObject* parent = matchedParent(m_object, true, matchFunc))
 1025 }))
10491026 return static_cast<AccessibilityTableCell*>(parent);
10501027 return nil;
10511028}

@@- (AccessibilityTableCell*)tableCellPare
10531030- (AccessibilityTable*)tableParent
10541031{
10551032 // Find if the parent table for the table cell.
1056  auto matchFunc = [] (AccessibilityObject* object) {
 1033 if (AccessibilityObject* parent = AccessibilityObject::matchedParent(m_object, true, [] (AccessibilityObject* object) {
10571034 return is<AccessibilityTable>(*object) && downcast<AccessibilityTable>(*object).isExposableThroughAccessibility();
1058  };
1059 
1060  if (AccessibilityObject* parent = matchedParent(m_object, true, matchFunc))
 1035 }))
10611036 return static_cast<AccessibilityTable*>(parent);
10621037 return nil;
10631038}

@@- (CGPoint)convertPointToScreenSpace:(Fl
14261401 }
14271402 else {
14281403 // Find the appropriate scroll view to use to convert the contents to the window.
1429  auto matchFunc = [] (AccessibilityObject* object) {
1430  return is<AccessibilityScrollView>(*object);
1431  };
1432 
14331404 ScrollView* scrollView = nullptr;
1434  AccessibilityObject* parent = matchedParent(m_object, false, matchFunc);
 1405 AccessibilityObject* parent = AccessibilityObject::matchedParent(m_object, false, [] (AccessibilityObject* object) {
 1406 return is<AccessibilityScrollView>(*object);
 1407 });
14351408 if (parent)
14361409 scrollView = downcast<AccessibilityScrollView>(*parent).scrollView();
14371410

@@- (CGRect)convertRectToScreenSpace:(IntR
14801453
14811454 } else {
14821455 // Find the appropriate scroll view to use to convert the contents to the window.
1483  auto matchFunc = [] (AccessibilityObject* object) {
1484  return is<AccessibilityScrollView>(*object);
1485  };
1486 
14871456 ScrollView* scrollView = nullptr;
1488  AccessibilityObject* parent = matchedParent(m_object, false, matchFunc);
 1457 AccessibilityObject* parent = AccessibilityObject::matchedParent(m_object, false, [] (AccessibilityObject* object) {
 1458 return is<AccessibilityScrollView>(*object);
 1459 });
14891460 if (parent)
14901461 scrollView = downcast<AccessibilityScrollView>(*parent).scrollView();
14911462

@@- (AccessibilityObject*)detailParentForS
18551826{
18561827 // Use this to check if an object is the child of a summary object.
18571828 // And return the summary's parent, which is the expandable details object.
1858  auto matchFunc = [] (AccessibilityObject* object) {
 1829 if (AccessibilityObject* summary = AccessibilityObject::matchedParent(object, true, [] (AccessibilityObject* object) {
18591830 return object->hasTagName(summaryTag);
1860  };
1861 
1862  if (AccessibilityObject* summary = matchedParent(object, true, matchFunc))
 1831 }))
18631832 return summary->parentObject();
18641833 return nil;
18651834}

@@- (AccessibilityObject*)detailParentForS
18671836- (AccessibilityObject*)detailParentForObject:(AccessibilityObject*)object
18681837{
18691838 // Use this to check if an object is inside a details object.
1870  auto matchFunc = [] (AccessibilityObject* object) {
 1839 if (AccessibilityObject* details = AccessibilityObject::matchedParent(object, true, [] (AccessibilityObject* object) {
18711840 return object->hasTagName(detailsTag);
1872  };
1873 
1874  if (AccessibilityObject* details = matchedParent(object, true, matchFunc))
 1841 }))
18751842 return details;
18761843 return nil;
18771844}
207268

Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm

@@- (NSArray*)additionalAccessibilityAttri
14101410 if (m_object->isToggleButton())
14111411 [additional addObject:NSAccessibilityValueAttribute];
14121412
1413  if (m_object->supportsExpanded())
 1413 if (m_object->supportsExpanded() || m_object->isSummary())
14141414 [additional addObject:NSAccessibilityExpandedAttribute];
14151415
14161416 if (m_object->isScrollbar()

@@static const AccessibilityRoleMap& creat
22072207 { RubyRunRole, NSAccessibilityGroupRole },
22082208 { RubyTextRole, NSAccessibilityGroupRole },
22092209 { DetailsRole, NSAccessibilityGroupRole },
2210  { SummaryRole, NSAccessibilityGroupRole },
 2210 { SummaryRole, NSAccessibilityButtonRole },
22112211 { SVGTextPathRole, NSAccessibilityGroupRole },
22122212 { SVGTextRole, NSAccessibilityGroupRole },
22132213 { SVGTSpanRole, NSAccessibilityGroupRole },

@@- (NSString*)roleDescription
24942494 return AXDetailsText();
24952495 case FooterRole:
24962496 return AXFooterRoleDescriptionText();
2497  case SummaryRole:
2498  return AXSummaryText();
24992497 case VideoRole:
25002498 return localizedMediaControlElementString("VideoElement");
25012499 default:

@@- (NSString*)roleDescription
25352533 if (m_object->isTabItem())
25362534 return NSAccessibilityRoleDescription(@"AXTab", nil);
25372535
 2536 if (m_object->isSummary())
 2537 return AXSummaryText();
 2538
25382539 // We should try the system default role description for all other roles.
25392540 // If we get the same string back, then as a last resort, return unknown.
25402541 NSString* defaultRoleDescription = NSAccessibilityRoleDescription(axRole, [self subrole]);

@@- (id)accessibilityAttributeValue:(NSStr
27572758 if (m_object->isMeter())
27582759 return [NSString string];
27592760
 2761 // Summary element should use its text node as AXTitle.
 2762 if (m_object->isSummary())
 2763 return m_object->textUnderElement();
 2764
27602765 return [self baseAccessibilityTitle];
27612766 }
27622767
207268

LayoutTests/ChangeLog

 12016-10-13 Nan Wang <n_wang@apple.com>
 2
 3 AX: [Mac] better accessibility support for Summary elements
 4 https://bugs.webkit.org/show_bug.cgi?id=163367
 5 <rdar://problem/28745010>
 6
 7 Reviewed by NOBODY (OOPS!).
 8
 9 * accessibility/mac/details-summary-expected.txt:
 10 * accessibility/mac/details-summary-role-description-expected.txt:
 11 * accessibility/mac/details-summary-role-description.html:
 12 * accessibility/mac/details-summary.html:
 13
1142016-10-12 Joseph Pecoraro <pecoraro@apple.com>
215
316 Web Inspector: step-into `console.log(o)` should not step through inspector javascript
207268

LayoutTests/accessibility/mac/details-summary-expected.txt

@@On success, you will see a series of "PA
1010PASS details1.role is 'AXRole: AXGroup'
1111PASS details1.subrole is 'AXSubrole: AXDetails'
1212PASS details1.isExpanded is true
13 PASS details1.childAtIndex(0).role is 'AXRole: AXGroup'
14 PASS details1.childAtIndex(0).subrole is 'AXSubrole: AXSummary'
 13PASS summary1.role is 'AXRole: AXButton'
 14PASS summary1.subrole is 'AXSubrole: AXSummary'
 15PASS summary1.title is 'AXTitle: Some open info'
1516PASS details1.isAttributeSettable('AXExpanded') is true
1617PASS details1.isExpanded is false
 18PASS summary1.isExpanded is false
1719PASS details1.isExpanded is false
 20PASS summary1.isExpanded is false
1821PASS details1.isExpanded is true
 22PASS summary1.isExpanded is true
1923PASS details1.isExpanded is true
 24PASS summary1.isExpanded is true
2025PASS details2.subrole is 'AXSubrole: AXDetails'
2126PASS details2.isExpanded is false
2227Received AXExpandedChanged notification
207268

LayoutTests/accessibility/mac/details-summary-role-description-expected.txt

@@This tests that summary and detail eleme
66On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
77
88
9 PASS summary.role is 'AXRole: AXGroup'
 9PASS summary.role is 'AXRole: AXButton'
1010PASS details.role is 'AXRole: AXGroup'
1111PASS summary.subrole is 'AXSubrole: AXSummary'
1212PASS details.subrole is 'AXSubrole: AXDetails'
207268

LayoutTests/accessibility/mac/details-summary-role-description.html

1919 var summary = accessibilityController.accessibleElementById("summary");
2020 var details = accessibilityController.accessibleElementById("details");
2121
22  shouldBe("summary.role", "'AXRole: AXGroup'");
 22 shouldBe("summary.role", "'AXRole: AXButton'");
2323 shouldBe("details.role", "'AXRole: AXGroup'");
2424 shouldBe("summary.subrole", "'AXSubrole: AXSummary'");
2525 shouldBe("details.subrole", "'AXSubrole: AXDetails'");
207268

LayoutTests/accessibility/mac/details-summary.html

66<body id="body">
77
88<details open id="details1">
9  <summary>Some open info</summary>
 9 <summary id="summary1">Some open info</summary>
1010 <p>Details about the open topic.</p>
1111</details>
1212

3939 });
4040
4141 var details1 = accessibilityController.accessibleElementById("details1");
 42 var summary1 = accessibilityController.accessibleElementById("summary1");
4243 shouldBe("details1.role", "'AXRole: AXGroup'");
4344 shouldBe("details1.subrole", "'AXSubrole: AXDetails'");
4445 shouldBeTrue("details1.isExpanded");
45  shouldBe("details1.childAtIndex(0).role", "'AXRole: AXGroup'");
46  shouldBe("details1.childAtIndex(0).subrole", "'AXSubrole: AXSummary'");
 46 shouldBe("summary1.role", "'AXRole: AXButton'");
 47 shouldBe("summary1.subrole", "'AXSubrole: AXSummary'");
 48 shouldBe("summary1.title", "'AXTitle: Some open info'");
4749 shouldBeTrue("details1.isAttributeSettable('AXExpanded')");
4850
4951 // Toggle the expanded state.
5052 details1.setBoolAttributeValue("AXExpanded", false);
5153 details1 = accessibilityController.accessibleElementById("details1");
 54 summary1 = accessibilityController.accessibleElementById("summary1");
5255 shouldBeFalse("details1.isExpanded");
 56 shouldBeFalse("summary1.isExpanded");
5357
5458 // Give it the same value to make sure we don't expand.
5559 details1.setBoolAttributeValue("AXExpanded", false);
5660 details1 = accessibilityController.accessibleElementById("details1");
 61 summary1 = accessibilityController.accessibleElementById("summary1");
5762 shouldBeFalse("details1.isExpanded");
 63 shouldBeFalse("summary1.isExpanded");
5864
5965 // Set to expand again.
6066 details1.setBoolAttributeValue("AXExpanded", true);
6167 details1 = accessibilityController.accessibleElementById("details1");
 68 summary1 = accessibilityController.accessibleElementById("summary1");
6269 shouldBeTrue("details1.isExpanded");
 70 shouldBeTrue("summary1.isExpanded");
6371
6472 // And duplicate the true state to make sure it doesn't toggle off.
6573 details1.setBoolAttributeValue("AXExpanded", true);
6674 details1 = accessibilityController.accessibleElementById("details1");
 75 summary1 = accessibilityController.accessibleElementById("summary1");
6776 shouldBeTrue("details1.isExpanded");
 77 shouldBeTrue("summary1.isExpanded");
6878
6979 var details2 = accessibilityController.accessibleElementById("details2");
7080 shouldBe("details2.subrole", "'AXSubrole: AXDetails'");
207268