From 3ef41c7383c696e274e686aa9dd828443978b838 Mon Sep 17 00:00:00 2001 From: Daniel Schmidt Date: Wed, 18 Oct 2017 20:23:36 +0200 Subject: [PATCH] move traits matcher to generated code --- detox/src/ios/earlgreyapi/GREYActions.js | 27 ++++++++++ .../src/ios/earlgreyapi/GREYMatchers+Detox.js | 27 ++++++++++ detox/src/ios/earlgreyapi/GREYMatchers.js | 51 +++++++++++++++++++ detox/src/ios/matchers.js | 25 +-------- detox/test/e2e/b-matchers.js | 1 + generation/earl-grey/global-functions.js | 27 ++++++++++ generation/earl-grey/index.js | 21 +++++++- 7 files changed, 153 insertions(+), 26 deletions(-) diff --git a/detox/src/ios/earlgreyapi/GREYActions.js b/detox/src/ios/earlgreyapi/GREYActions.js index 2ea832c6bd..35b737f03b 100644 --- a/detox/src/ios/earlgreyapi/GREYActions.js +++ b/detox/src/ios/earlgreyapi/GREYActions.js @@ -39,6 +39,33 @@ function sanitize_greyContentEdge(action) { } } +function sanitize_uiAccessibilityTraits(traits) { + let traits = 0; + for (let i = 0; i < value.length; i++) { + switch (value[i]) { + case 'button': traits |= 1; break; + case 'link': traits |= 2; break; + case 'header': traits |= 4; break; + case 'search': traits |= 8; break; + case 'image': traits |= 16; break; + case 'selected': traits |= 32; break; + case 'plays': traits |= 64; break; + case 'key': traits |= 128; break; + case 'text': traits |= 256; break; + case 'summary': traits |= 512; break; + case 'disabled': traits |= 1024; break; + case 'frequentUpdates': traits |= 2048; break; + case 'startsMedia': traits |= 4096; break; + case 'adjustable': traits |= 8192; break; + case 'allowsDirectInteraction': traits |= 16384; break; + case 'pageTurn': traits |= 32768; break; + default: throw new Error(`Unknown trait '${value[i]}', see list in https://facebook.github.io/react-native/docs/accessibility.html#accessibilitytraits-ios`); + } + } + + return traits; +} + class GREYActions { diff --git a/detox/src/ios/earlgreyapi/GREYMatchers+Detox.js b/detox/src/ios/earlgreyapi/GREYMatchers+Detox.js index 7ccec743fc..b0cced4e73 100644 --- a/detox/src/ios/earlgreyapi/GREYMatchers+Detox.js +++ b/detox/src/ios/earlgreyapi/GREYMatchers+Detox.js @@ -39,6 +39,33 @@ function sanitize_greyContentEdge(action) { } } +function sanitize_uiAccessibilityTraits(traits) { + let traits = 0; + for (let i = 0; i < value.length; i++) { + switch (value[i]) { + case 'button': traits |= 1; break; + case 'link': traits |= 2; break; + case 'header': traits |= 4; break; + case 'search': traits |= 8; break; + case 'image': traits |= 16; break; + case 'selected': traits |= 32; break; + case 'plays': traits |= 64; break; + case 'key': traits |= 128; break; + case 'text': traits |= 256; break; + case 'summary': traits |= 512; break; + case 'disabled': traits |= 1024; break; + case 'frequentUpdates': traits |= 2048; break; + case 'startsMedia': traits |= 4096; break; + case 'adjustable': traits |= 8192; break; + case 'allowsDirectInteraction': traits |= 16384; break; + case 'pageTurn': traits |= 32768; break; + default: throw new Error(`Unknown trait '${value[i]}', see list in https://facebook.github.io/react-native/docs/accessibility.html#accessibilitytraits-ios`); + } + } + + return traits; +} + class GREYMatchers { diff --git a/detox/src/ios/earlgreyapi/GREYMatchers.js b/detox/src/ios/earlgreyapi/GREYMatchers.js index 17dbebb7ef..3059b6c8d2 100644 --- a/detox/src/ios/earlgreyapi/GREYMatchers.js +++ b/detox/src/ios/earlgreyapi/GREYMatchers.js @@ -39,6 +39,33 @@ function sanitize_greyContentEdge(action) { } } +function sanitize_uiAccessibilityTraits(traits) { + let traits = 0; + for (let i = 0; i < value.length; i++) { + switch (value[i]) { + case 'button': traits |= 1; break; + case 'link': traits |= 2; break; + case 'header': traits |= 4; break; + case 'search': traits |= 8; break; + case 'image': traits |= 16; break; + case 'selected': traits |= 32; break; + case 'plays': traits |= 64; break; + case 'key': traits |= 128; break; + case 'text': traits |= 256; break; + case 'summary': traits |= 512; break; + case 'disabled': traits |= 1024; break; + case 'frequentUpdates': traits |= 2048; break; + case 'startsMedia': traits |= 4096; break; + case 'adjustable': traits |= 8192; break; + case 'allowsDirectInteraction': traits |= 16384; break; + case 'pageTurn': traits |= 32768; break; + default: throw new Error(`Unknown trait '${value[i]}', see list in https://facebook.github.io/react-native/docs/accessibility.html#accessibilitytraits-ios`); + } + } + + return traits; +} + class GREYMatchers { @@ -116,6 +143,30 @@ class GREYMatchers { }; } + /*Matcher for UI element with the provided accessibility @c traits. + +@param traits The accessibility traits to be matched. + +@return A matcher for the accessibility traits of an accessible element. + +*/static matcherForAccessibilityTraits(traits) { + if (typeof traits !== 'object' || !traits instanceof Array) { + throw new Error('TraitsMatcher ctor argument must be an array, got ' + typeof traits); + } + + return { + target: { + type: "Class", + value: "GREYMatchers" + }, + method: "matcherForAccessibilityTraits:", + args: [{ + type: "NSInteger", + value: sanitize_uiAccessibilityTraits(traits) + }] + }; + } + /*Matcher for UI element with the provided accessiblity @c hint. @param hint The accessibility hint to be matched. diff --git a/detox/src/ios/matchers.js b/detox/src/ios/matchers.js index a0be4da18f..aefc203176 100644 --- a/detox/src/ios/matchers.js +++ b/detox/src/ios/matchers.js @@ -59,30 +59,7 @@ class TypeMatcher extends Matcher { class TraitsMatcher extends Matcher { constructor(value) { super(); - if ((typeof value !== 'object') || (!value instanceof Array)) throw new Error(`TraitsMatcher ctor argument must be an array, got ${typeof value}`); - let traits = 0; - for (let i = 0; i < value.length; i++) { - switch (value[i]) { - case 'button': traits |= 1; break; - case 'link': traits |= 2; break; - case 'header': traits |= 4; break; - case 'search': traits |= 8; break; - case 'image': traits |= 16; break; - case 'selected': traits |= 32; break; - case 'plays': traits |= 64; break; - case 'key': traits |= 128; break; - case 'text': traits |= 256; break; - case 'summary': traits |= 512; break; - case 'disabled': traits |= 1024; break; - case 'frequentUpdates': traits |= 2048; break; - case 'startsMedia': traits |= 4096; break; - case 'adjustable': traits |= 8192; break; - case 'allowsDirectInteraction': traits |= 16384; break; - case 'pageTurn': traits |= 32768; break; - default: throw new Error(`Unknown trait '${value[i]}', see list in https://facebook.github.io/react-native/docs/accessibility.html#accessibilitytraits-ios`); - } - } - this._call = invoke.call(invoke.IOS.Class('GREYMatchers'), 'matcherForAccessibilityTraits:', invoke.IOS.NSInteger(traits)); + this._call = invoke.callDirectly(GreyMatchers.matcherForAccessibilityTraits(value)); } } diff --git a/detox/test/e2e/b-matchers.js b/detox/test/e2e/b-matchers.js index 81aef3fa4d..b169bae3c4 100644 --- a/detox/test/e2e/b-matchers.js +++ b/detox/test/e2e/b-matchers.js @@ -57,6 +57,7 @@ describe('Matchers', () => { await expect(element(by.id('UniqueId345').and(by.text('ID')))).toExist(); await expect(element(by.id('UniqueId345').and(by.text('RandomJunk')))).toNotExist(); await expect(element(by.id('UniqueId345').and(by.label('RandomJunk')))).toNotExist(); + await expect(element(by.id('UniqueId345').and(by.traits(['button'])))).toNotExist(); }); // waiting to upgrade EarlGrey version in order to test this (not supported in our current one) diff --git a/generation/earl-grey/global-functions.js b/generation/earl-grey/global-functions.js index 5720d3ec1f..ae3ac8bbd9 100644 --- a/generation/earl-grey/global-functions.js +++ b/generation/earl-grey/global-functions.js @@ -32,6 +32,33 @@ function sanitize_greyContentEdge(action) { } } +function sanitize_uiAccessibilityTraits(traits) { + let traits = 0; + for (let i = 0; i < value.length; i++) { + switch (value[i]) { + case 'button': traits |= 1; break; + case 'link': traits |= 2; break; + case 'header': traits |= 4; break; + case 'search': traits |= 8; break; + case 'image': traits |= 16; break; + case 'selected': traits |= 32; break; + case 'plays': traits |= 64; break; + case 'key': traits |= 128; break; + case 'text': traits |= 256; break; + case 'summary': traits |= 512; break; + case 'disabled': traits |= 1024; break; + case 'frequentUpdates': traits |= 2048; break; + case 'startsMedia': traits |= 4096; break; + case 'adjustable': traits |= 8192; break; + case 'allowsDirectInteraction': traits |= 16384; break; + case 'pageTurn': traits |= 32768; break; + default: throw new Error(`Unknown trait '${value[i]}', see list in https://facebook.github.io/react-native/docs/accessibility.html#accessibilitytraits-ios`); + } + } + + return traits; +} + module.exports = { sanitize_greyDirection, diff --git a/generation/earl-grey/index.js b/generation/earl-grey/index.js index 0f27be9e96..8c55c71296 100644 --- a/generation/earl-grey/index.js +++ b/generation/earl-grey/index.js @@ -32,7 +32,18 @@ const isGreyMatcher = ({ name }) => template(` } `)({ ARG: t.identifier(name) - }) + }); +const isArray = ({ name }) => template(` +if ( + (typeof ARG !== 'object') || + (!ARG instanceof Array) +) { + throw new Error('TraitsMatcher ctor argument must be an array, got ' + typeof ARG); + } +`)({ + ARG: t.identifier(name) + }); + // Constants const SUPPORTED_TYPES = [ @@ -44,7 +55,8 @@ const SUPPORTED_TYPES = [ "NSString *", "NSString", "NSUInteger", - "id" + "id", + "UIAccessibilityTraits" ]; /** @@ -170,6 +182,10 @@ const supportedContentSanitizersMap = { GREYContentEdge: { type: "NSInteger", value: callGlobal("sanitize_greyContentEdge") + }, + UIAccessibilityTraits: { + type: "NSInteger", + value: callGlobal("sanitize_uiAccessibilityTraits") } }; function addArgumentContentSanitizerCall(json) { @@ -236,6 +252,7 @@ function createTypeCheck(json) { GREYContentEdge: isOneOf(["left", "right", "top", "bottom"]), GREYPinchDirection: isOneOf(["outward", "inward"]), "id": isGreyMatcher, + UIAccessibilityTraits: isArray, }; const typeCheckCreator = typeInterfaces[json.type];