diff --git a/.prettierrc b/.prettierrc index f23aea65a9..1a7bb6613e 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,5 +1,5 @@ { - "useTabs": true, + "useTabs": false, "tabWidth": 2, "printWidth": 140, "singleQuote": true, diff --git a/detox/src/android/espressoapi/DetoxAction.js b/detox/src/android/espressoapi/DetoxAction.js index 9908579576..98cebba86c 100644 --- a/detox/src/android/espressoapi/DetoxAction.js +++ b/detox/src/android/espressoapi/DetoxAction.js @@ -5,136 +5,136 @@ */ function sanitize_android_edge(edge) { - switch (edge) { - case 'left': - return 1; - case 'right': - return 2; - case 'top': - return 3; - case 'bottom': - return 4; - default: - throw new Error(`edge must be a 'left'/'right'/'top'/'bottom', got ${edge}`); - } + switch (edge) { + case 'left': + return 1; + case 'right': + return 2; + case 'top': + return 3; + case 'bottom': + return 4; + default: + throw new Error(`edge must be a 'left'/'right'/'top'/'bottom', got ${edge}`); + } } function sanitize_android_direction(direction) { - switch (direction) { - case 'left': - return 1; - case 'right': - return 2; - case 'up': - return 3; - case 'down': - return 4; - default: - throw new Error(`direction must be a 'left'/'right'/'up'/'down', got ${direction}`); - } + switch (direction) { + case 'left': + return 1; + case 'right': + return 2; + case 'up': + return 3; + case 'down': + return 4; + default: + throw new Error(`direction must be a 'left'/'right'/'up'/'down', got ${direction}`); + } } class DetoxAction { - static multiClick(times) { - if (typeof times !== 'number') throw new Error('times should be a number, but got ' + (times + (' (' + (typeof times + ')')))); - return { - target: { - type: 'Class', - value: 'com.wix.detox.espresso.DetoxAction' - }, - method: 'multiClick', - args: [ - { - type: 'Integer', - value: times - } - ] - }; - } + static multiClick(times) { + if (typeof times !== 'number') throw new Error('times should be a number, but got ' + (times + (' (' + (typeof times + ')')))); + return { + target: { + type: 'Class', + value: 'com.wix.detox.espresso.DetoxAction' + }, + method: 'multiClick', + args: [ + { + type: 'Integer', + value: times + } + ] + }; + } - static tapAtLocation(x, y) { - if (typeof x !== 'number') throw new Error('x should be a number, but got ' + (x + (' (' + (typeof x + ')')))); - if (typeof y !== 'number') throw new Error('y should be a number, but got ' + (y + (' (' + (typeof y + ')')))); - return { - target: { - type: 'Class', - value: 'com.wix.detox.espresso.DetoxAction' - }, - method: 'tapAtLocation', - args: [ - { - type: 'Integer', - value: x - }, - { - type: 'Integer', - value: y - } - ] - }; - } + static tapAtLocation(x, y) { + if (typeof x !== 'number') throw new Error('x should be a number, but got ' + (x + (' (' + (typeof x + ')')))); + if (typeof y !== 'number') throw new Error('y should be a number, but got ' + (y + (' (' + (typeof y + ')')))); + return { + target: { + type: 'Class', + value: 'com.wix.detox.espresso.DetoxAction' + }, + method: 'tapAtLocation', + args: [ + { + type: 'Integer', + value: x + }, + { + type: 'Integer', + value: y + } + ] + }; + } - static scrollToEdge(edge) { - if (typeof edge !== 'string') throw new Error('edge should be a string, but got ' + (edge + (' (' + (typeof edge + ')')))); - return { - target: { - type: 'Class', - value: 'com.wix.detox.espresso.DetoxAction' - }, - method: 'scrollToEdge', - args: [ - { - type: 'Integer', - value: sanitize_android_edge(edge) - } - ] - }; - } + static scrollToEdge(edge) { + if (typeof edge !== 'string') throw new Error('edge should be a string, but got ' + (edge + (' (' + (typeof edge + ')')))); + return { + target: { + type: 'Class', + value: 'com.wix.detox.espresso.DetoxAction' + }, + method: 'scrollToEdge', + args: [ + { + type: 'Integer', + value: sanitize_android_edge(edge) + } + ] + }; + } - static scrollInDirection(direction, amountInDP) { - if (typeof direction !== 'string') - throw new Error('direction should be a string, but got ' + (direction + (' (' + (typeof direction + ')')))); - if (typeof amountInDP !== 'number') - throw new Error('amountInDP should be a number, but got ' + (amountInDP + (' (' + (typeof amountInDP + ')')))); - return { - target: { - type: 'Class', - value: 'com.wix.detox.espresso.DetoxAction' - }, - method: 'scrollInDirection', - args: [ - { - type: 'Integer', - value: sanitize_android_direction(direction) - }, - { - type: 'Double', - value: amountInDP - } - ] - }; - } + static scrollInDirection(direction, amountInDP) { + if (typeof direction !== 'string') + throw new Error('direction should be a string, but got ' + (direction + (' (' + (typeof direction + ')')))); + if (typeof amountInDP !== 'number') + throw new Error('amountInDP should be a number, but got ' + (amountInDP + (' (' + (typeof amountInDP + ')')))); + return { + target: { + type: 'Class', + value: 'com.wix.detox.espresso.DetoxAction' + }, + method: 'scrollInDirection', + args: [ + { + type: 'Integer', + value: sanitize_android_direction(direction) + }, + { + type: 'Double', + value: amountInDP + } + ] + }; + } - static swipeInDirection(direction, fast) { - if (typeof direction !== 'string') - throw new Error('direction should be a string, but got ' + (direction + (' (' + (typeof direction + ')')))); - if (typeof fast !== 'boolean') throw new Error('fast should be a boolean, but got ' + (fast + (' (' + (typeof fast + ')')))); - return { - target: { - type: 'Class', - value: 'com.wix.detox.espresso.DetoxAction' - }, - method: 'swipeInDirection', - args: [ - { - type: 'Integer', - value: sanitize_android_direction(direction) - }, - { - type: 'boolean', - value: fast - } - ] - }; - } + static swipeInDirection(direction, fast) { + if (typeof direction !== 'string') + throw new Error('direction should be a string, but got ' + (direction + (' (' + (typeof direction + ')')))); + if (typeof fast !== 'boolean') throw new Error('fast should be a boolean, but got ' + (fast + (' (' + (typeof fast + ')')))); + return { + target: { + type: 'Class', + value: 'com.wix.detox.espresso.DetoxAction' + }, + method: 'swipeInDirection', + args: [ + { + type: 'Integer', + value: sanitize_android_direction(direction) + }, + { + type: 'boolean', + value: fast + } + ] + }; + } } module.exports = DetoxAction; diff --git a/detox/src/android/espressoapi/DetoxMatcher.js b/detox/src/android/espressoapi/DetoxMatcher.js index b9e45decbc..7096af731f 100644 --- a/detox/src/android/espressoapi/DetoxMatcher.js +++ b/detox/src/android/espressoapi/DetoxMatcher.js @@ -5,350 +5,350 @@ */ function sanitize_matcher(matcher) { - const originalMatcher = typeof matcher._call === 'function' ? matcher._call() : matcher._call; - return originalMatcher.type ? originalMatcher.value : originalMatcher; + const originalMatcher = typeof matcher._call === 'function' ? matcher._call() : matcher._call; + return originalMatcher.type ? originalMatcher.value : originalMatcher; } class DetoxMatcher { - static matcherForText(text) { - if (typeof text !== 'string') throw new Error('text should be a string, but got ' + (text + (' (' + (typeof text + ')')))); - return { - target: { - type: 'Class', - value: 'com.wix.detox.espresso.DetoxMatcher' - }, - method: 'matcherForText', - args: [text] - }; - } + static matcherForText(text) { + if (typeof text !== 'string') throw new Error('text should be a string, but got ' + (text + (' (' + (typeof text + ')')))); + return { + target: { + type: 'Class', + value: 'com.wix.detox.espresso.DetoxMatcher' + }, + method: 'matcherForText', + args: [text] + }; + } - static matcherForContentDescription(contentDescription) { - if (typeof contentDescription !== 'string') - throw new Error( - 'contentDescription should be a string, but got ' + (contentDescription + (' (' + (typeof contentDescription + ')'))) - ); - return { - target: { - type: 'Class', - value: 'com.wix.detox.espresso.DetoxMatcher' - }, - method: 'matcherForContentDescription', - args: [contentDescription] - }; - } + static matcherForContentDescription(contentDescription) { + if (typeof contentDescription !== 'string') + throw new Error( + 'contentDescription should be a string, but got ' + (contentDescription + (' (' + (typeof contentDescription + ')'))) + ); + return { + target: { + type: 'Class', + value: 'com.wix.detox.espresso.DetoxMatcher' + }, + method: 'matcherForContentDescription', + args: [contentDescription] + }; + } - static matcherForTestId(testId) { - if (typeof testId !== 'string') throw new Error('testId should be a string, but got ' + (testId + (' (' + (typeof testId + ')')))); - return { - target: { - type: 'Class', - value: 'com.wix.detox.espresso.DetoxMatcher' - }, - method: 'matcherForTestId', - args: [testId] - }; - } + static matcherForTestId(testId) { + if (typeof testId !== 'string') throw new Error('testId should be a string, but got ' + (testId + (' (' + (typeof testId + ')')))); + return { + target: { + type: 'Class', + value: 'com.wix.detox.espresso.DetoxMatcher' + }, + method: 'matcherForTestId', + args: [testId] + }; + } - static matcherForAnd(m1, m2) { - if (typeof m1 !== 'object' || typeof m1.constructor !== 'function' || m1.constructor.name.indexOf('Matcher') === -1) { - const isObject = typeof m1 === 'object'; - const additionalErrorInfo = isObject - ? typeof m1.constructor === 'object' - ? 'the constructor is no object' - : 'it has a wrong class name: "' + m1.constructor.name + '"' - : 'it is no object'; - throw new Error('m1 should be an instance of Matcher, got "' + m1 + '", it appears that ' + additionalErrorInfo); - } + static matcherForAnd(m1, m2) { + if (typeof m1 !== 'object' || typeof m1.constructor !== 'function' || m1.constructor.name.indexOf('Matcher') === -1) { + const isObject = typeof m1 === 'object'; + const additionalErrorInfo = isObject + ? typeof m1.constructor === 'object' + ? 'the constructor is no object' + : 'it has a wrong class name: "' + m1.constructor.name + '"' + : 'it is no object'; + throw new Error('m1 should be an instance of Matcher, got "' + m1 + '", it appears that ' + additionalErrorInfo); + } - if (typeof m2 !== 'object' || typeof m2.constructor !== 'function' || m2.constructor.name.indexOf('Matcher') === -1) { - const isObject = typeof m2 === 'object'; - const additionalErrorInfo = isObject - ? typeof m2.constructor === 'object' - ? 'the constructor is no object' - : 'it has a wrong class name: "' + m2.constructor.name + '"' - : 'it is no object'; - throw new Error('m2 should be an instance of Matcher, got "' + m2 + '", it appears that ' + additionalErrorInfo); - } + if (typeof m2 !== 'object' || typeof m2.constructor !== 'function' || m2.constructor.name.indexOf('Matcher') === -1) { + const isObject = typeof m2 === 'object'; + const additionalErrorInfo = isObject + ? typeof m2.constructor === 'object' + ? 'the constructor is no object' + : 'it has a wrong class name: "' + m2.constructor.name + '"' + : 'it is no object'; + throw new Error('m2 should be an instance of Matcher, got "' + m2 + '", it appears that ' + additionalErrorInfo); + } - return { - target: { - type: 'Class', - value: 'com.wix.detox.espresso.DetoxMatcher' - }, - method: 'matcherForAnd', - args: [ - { - type: 'Invocation', - value: sanitize_matcher(m1) - }, - { - type: 'Invocation', - value: sanitize_matcher(m2) - } - ] - }; - } + return { + target: { + type: 'Class', + value: 'com.wix.detox.espresso.DetoxMatcher' + }, + method: 'matcherForAnd', + args: [ + { + type: 'Invocation', + value: sanitize_matcher(m1) + }, + { + type: 'Invocation', + value: sanitize_matcher(m2) + } + ] + }; + } - static matcherForOr(m1, m2) { - if (typeof m1 !== 'object' || typeof m1.constructor !== 'function' || m1.constructor.name.indexOf('Matcher') === -1) { - const isObject = typeof m1 === 'object'; - const additionalErrorInfo = isObject - ? typeof m1.constructor === 'object' - ? 'the constructor is no object' - : 'it has a wrong class name: "' + m1.constructor.name + '"' - : 'it is no object'; - throw new Error('m1 should be an instance of Matcher, got "' + m1 + '", it appears that ' + additionalErrorInfo); - } + static matcherForOr(m1, m2) { + if (typeof m1 !== 'object' || typeof m1.constructor !== 'function' || m1.constructor.name.indexOf('Matcher') === -1) { + const isObject = typeof m1 === 'object'; + const additionalErrorInfo = isObject + ? typeof m1.constructor === 'object' + ? 'the constructor is no object' + : 'it has a wrong class name: "' + m1.constructor.name + '"' + : 'it is no object'; + throw new Error('m1 should be an instance of Matcher, got "' + m1 + '", it appears that ' + additionalErrorInfo); + } - if (typeof m2 !== 'object' || typeof m2.constructor !== 'function' || m2.constructor.name.indexOf('Matcher') === -1) { - const isObject = typeof m2 === 'object'; - const additionalErrorInfo = isObject - ? typeof m2.constructor === 'object' - ? 'the constructor is no object' - : 'it has a wrong class name: "' + m2.constructor.name + '"' - : 'it is no object'; - throw new Error('m2 should be an instance of Matcher, got "' + m2 + '", it appears that ' + additionalErrorInfo); - } + if (typeof m2 !== 'object' || typeof m2.constructor !== 'function' || m2.constructor.name.indexOf('Matcher') === -1) { + const isObject = typeof m2 === 'object'; + const additionalErrorInfo = isObject + ? typeof m2.constructor === 'object' + ? 'the constructor is no object' + : 'it has a wrong class name: "' + m2.constructor.name + '"' + : 'it is no object'; + throw new Error('m2 should be an instance of Matcher, got "' + m2 + '", it appears that ' + additionalErrorInfo); + } - return { - target: { - type: 'Class', - value: 'com.wix.detox.espresso.DetoxMatcher' - }, - method: 'matcherForOr', - args: [ - { - type: 'Invocation', - value: sanitize_matcher(m1) - }, - { - type: 'Invocation', - value: sanitize_matcher(m2) - } - ] - }; - } + return { + target: { + type: 'Class', + value: 'com.wix.detox.espresso.DetoxMatcher' + }, + method: 'matcherForOr', + args: [ + { + type: 'Invocation', + value: sanitize_matcher(m1) + }, + { + type: 'Invocation', + value: sanitize_matcher(m2) + } + ] + }; + } - static matcherForNot(m) { - if (typeof m !== 'object' || typeof m.constructor !== 'function' || m.constructor.name.indexOf('Matcher') === -1) { - const isObject = typeof m === 'object'; - const additionalErrorInfo = isObject - ? typeof m.constructor === 'object' - ? 'the constructor is no object' - : 'it has a wrong class name: "' + m.constructor.name + '"' - : 'it is no object'; - throw new Error('m should be an instance of Matcher, got "' + m + '", it appears that ' + additionalErrorInfo); - } + static matcherForNot(m) { + if (typeof m !== 'object' || typeof m.constructor !== 'function' || m.constructor.name.indexOf('Matcher') === -1) { + const isObject = typeof m === 'object'; + const additionalErrorInfo = isObject + ? typeof m.constructor === 'object' + ? 'the constructor is no object' + : 'it has a wrong class name: "' + m.constructor.name + '"' + : 'it is no object'; + throw new Error('m should be an instance of Matcher, got "' + m + '", it appears that ' + additionalErrorInfo); + } - return { - target: { - type: 'Class', - value: 'com.wix.detox.espresso.DetoxMatcher' - }, - method: 'matcherForNot', - args: [ - { - type: 'Invocation', - value: sanitize_matcher(m) - } - ] - }; - } + return { + target: { + type: 'Class', + value: 'com.wix.detox.espresso.DetoxMatcher' + }, + method: 'matcherForNot', + args: [ + { + type: 'Invocation', + value: sanitize_matcher(m) + } + ] + }; + } - static matcherWithAncestor(m, ancestorMatcher) { - if (typeof m !== 'object' || typeof m.constructor !== 'function' || m.constructor.name.indexOf('Matcher') === -1) { - const isObject = typeof m === 'object'; - const additionalErrorInfo = isObject - ? typeof m.constructor === 'object' - ? 'the constructor is no object' - : 'it has a wrong class name: "' + m.constructor.name + '"' - : 'it is no object'; - throw new Error('m should be an instance of Matcher, got "' + m + '", it appears that ' + additionalErrorInfo); - } + static matcherWithAncestor(m, ancestorMatcher) { + if (typeof m !== 'object' || typeof m.constructor !== 'function' || m.constructor.name.indexOf('Matcher') === -1) { + const isObject = typeof m === 'object'; + const additionalErrorInfo = isObject + ? typeof m.constructor === 'object' + ? 'the constructor is no object' + : 'it has a wrong class name: "' + m.constructor.name + '"' + : 'it is no object'; + throw new Error('m should be an instance of Matcher, got "' + m + '", it appears that ' + additionalErrorInfo); + } - if ( - typeof ancestorMatcher !== 'object' || - typeof ancestorMatcher.constructor !== 'function' || - ancestorMatcher.constructor.name.indexOf('Matcher') === -1 - ) { - const isObject = typeof ancestorMatcher === 'object'; - const additionalErrorInfo = isObject - ? typeof ancestorMatcher.constructor === 'object' - ? 'the constructor is no object' - : 'it has a wrong class name: "' + ancestorMatcher.constructor.name + '"' - : 'it is no object'; - throw new Error( - 'ancestorMatcher should be an instance of Matcher, got "' + ancestorMatcher + '", it appears that ' + additionalErrorInfo - ); - } + if ( + typeof ancestorMatcher !== 'object' || + typeof ancestorMatcher.constructor !== 'function' || + ancestorMatcher.constructor.name.indexOf('Matcher') === -1 + ) { + const isObject = typeof ancestorMatcher === 'object'; + const additionalErrorInfo = isObject + ? typeof ancestorMatcher.constructor === 'object' + ? 'the constructor is no object' + : 'it has a wrong class name: "' + ancestorMatcher.constructor.name + '"' + : 'it is no object'; + throw new Error( + 'ancestorMatcher should be an instance of Matcher, got "' + ancestorMatcher + '", it appears that ' + additionalErrorInfo + ); + } - return { - target: { - type: 'Class', - value: 'com.wix.detox.espresso.DetoxMatcher' - }, - method: 'matcherWithAncestor', - args: [ - { - type: 'Invocation', - value: sanitize_matcher(m) - }, - { - type: 'Invocation', - value: sanitize_matcher(ancestorMatcher) - } - ] - }; - } + return { + target: { + type: 'Class', + value: 'com.wix.detox.espresso.DetoxMatcher' + }, + method: 'matcherWithAncestor', + args: [ + { + type: 'Invocation', + value: sanitize_matcher(m) + }, + { + type: 'Invocation', + value: sanitize_matcher(ancestorMatcher) + } + ] + }; + } - static matcherWithDescendant(m, descendantMatcher) { - if (typeof m !== 'object' || typeof m.constructor !== 'function' || m.constructor.name.indexOf('Matcher') === -1) { - const isObject = typeof m === 'object'; - const additionalErrorInfo = isObject - ? typeof m.constructor === 'object' - ? 'the constructor is no object' - : 'it has a wrong class name: "' + m.constructor.name + '"' - : 'it is no object'; - throw new Error('m should be an instance of Matcher, got "' + m + '", it appears that ' + additionalErrorInfo); - } + static matcherWithDescendant(m, descendantMatcher) { + if (typeof m !== 'object' || typeof m.constructor !== 'function' || m.constructor.name.indexOf('Matcher') === -1) { + const isObject = typeof m === 'object'; + const additionalErrorInfo = isObject + ? typeof m.constructor === 'object' + ? 'the constructor is no object' + : 'it has a wrong class name: "' + m.constructor.name + '"' + : 'it is no object'; + throw new Error('m should be an instance of Matcher, got "' + m + '", it appears that ' + additionalErrorInfo); + } - if ( - typeof descendantMatcher !== 'object' || - typeof descendantMatcher.constructor !== 'function' || - descendantMatcher.constructor.name.indexOf('Matcher') === -1 - ) { - const isObject = typeof descendantMatcher === 'object'; - const additionalErrorInfo = isObject - ? typeof descendantMatcher.constructor === 'object' - ? 'the constructor is no object' - : 'it has a wrong class name: "' + descendantMatcher.constructor.name + '"' - : 'it is no object'; - throw new Error( - 'descendantMatcher should be an instance of Matcher, got "' + descendantMatcher + '", it appears that ' + additionalErrorInfo - ); - } + if ( + typeof descendantMatcher !== 'object' || + typeof descendantMatcher.constructor !== 'function' || + descendantMatcher.constructor.name.indexOf('Matcher') === -1 + ) { + const isObject = typeof descendantMatcher === 'object'; + const additionalErrorInfo = isObject + ? typeof descendantMatcher.constructor === 'object' + ? 'the constructor is no object' + : 'it has a wrong class name: "' + descendantMatcher.constructor.name + '"' + : 'it is no object'; + throw new Error( + 'descendantMatcher should be an instance of Matcher, got "' + descendantMatcher + '", it appears that ' + additionalErrorInfo + ); + } - return { - target: { - type: 'Class', - value: 'com.wix.detox.espresso.DetoxMatcher' - }, - method: 'matcherWithDescendant', - args: [ - { - type: 'Invocation', - value: sanitize_matcher(m) - }, - { - type: 'Invocation', - value: sanitize_matcher(descendantMatcher) - } - ] - }; - } + return { + target: { + type: 'Class', + value: 'com.wix.detox.espresso.DetoxMatcher' + }, + method: 'matcherWithDescendant', + args: [ + { + type: 'Invocation', + value: sanitize_matcher(m) + }, + { + type: 'Invocation', + value: sanitize_matcher(descendantMatcher) + } + ] + }; + } - static matcherForClass(className) { - if (typeof className !== 'string') - throw new Error('className should be a string, but got ' + (className + (' (' + (typeof className + ')')))); - return { - target: { - type: 'Class', - value: 'com.wix.detox.espresso.DetoxMatcher' - }, - method: 'matcherForClass', - args: [className] - }; - } + static matcherForClass(className) { + if (typeof className !== 'string') + throw new Error('className should be a string, but got ' + (className + (' (' + (typeof className + ')')))); + return { + target: { + type: 'Class', + value: 'com.wix.detox.espresso.DetoxMatcher' + }, + method: 'matcherForClass', + args: [className] + }; + } - static matcherForSufficientlyVisible() { - return { - target: { - type: 'Class', - value: 'com.wix.detox.espresso.DetoxMatcher' - }, - method: 'matcherForSufficientlyVisible', - args: [] - }; - } + static matcherForSufficientlyVisible() { + return { + target: { + type: 'Class', + value: 'com.wix.detox.espresso.DetoxMatcher' + }, + method: 'matcherForSufficientlyVisible', + args: [] + }; + } - static matcherForNotVisible() { - return { - target: { - type: 'Class', - value: 'com.wix.detox.espresso.DetoxMatcher' - }, - method: 'matcherForNotVisible', - args: [] - }; - } + static matcherForNotVisible() { + return { + target: { + type: 'Class', + value: 'com.wix.detox.espresso.DetoxMatcher' + }, + method: 'matcherForNotVisible', + args: [] + }; + } - static matcherForNotNull() { - return { - target: { - type: 'Class', - value: 'com.wix.detox.espresso.DetoxMatcher' - }, - method: 'matcherForNotNull', - args: [] - }; - } + static matcherForNotNull() { + return { + target: { + type: 'Class', + value: 'com.wix.detox.espresso.DetoxMatcher' + }, + method: 'matcherForNotNull', + args: [] + }; + } - static matcherForNull() { - return { - target: { - type: 'Class', - value: 'com.wix.detox.espresso.DetoxMatcher' - }, - method: 'matcherForNull', - args: [] - }; - } + static matcherForNull() { + return { + target: { + type: 'Class', + value: 'com.wix.detox.espresso.DetoxMatcher' + }, + method: 'matcherForNull', + args: [] + }; + } - static matcherForAtIndex(index, innerMatcher) { - if (typeof index !== 'number') throw new Error('index should be a number, but got ' + (index + (' (' + (typeof index + ')')))); + static matcherForAtIndex(index, innerMatcher) { + if (typeof index !== 'number') throw new Error('index should be a number, but got ' + (index + (' (' + (typeof index + ')')))); - if ( - typeof innerMatcher !== 'object' || - typeof innerMatcher.constructor !== 'function' || - innerMatcher.constructor.name.indexOf('Matcher') === -1 - ) { - const isObject = typeof innerMatcher === 'object'; - const additionalErrorInfo = isObject - ? typeof innerMatcher.constructor === 'object' - ? 'the constructor is no object' - : 'it has a wrong class name: "' + innerMatcher.constructor.name + '"' - : 'it is no object'; - throw new Error('innerMatcher should be an instance of Matcher, got "' + innerMatcher + '", it appears that ' + additionalErrorInfo); - } + if ( + typeof innerMatcher !== 'object' || + typeof innerMatcher.constructor !== 'function' || + innerMatcher.constructor.name.indexOf('Matcher') === -1 + ) { + const isObject = typeof innerMatcher === 'object'; + const additionalErrorInfo = isObject + ? typeof innerMatcher.constructor === 'object' + ? 'the constructor is no object' + : 'it has a wrong class name: "' + innerMatcher.constructor.name + '"' + : 'it is no object'; + throw new Error('innerMatcher should be an instance of Matcher, got "' + innerMatcher + '", it appears that ' + additionalErrorInfo); + } - return { - target: { - type: 'Class', - value: 'com.wix.detox.espresso.DetoxMatcher' - }, - method: 'matcherForAtIndex', - args: [ - { - type: 'Integer', - value: index - }, - { - type: 'Invocation', - value: sanitize_matcher(innerMatcher) - } - ] - }; - } + return { + target: { + type: 'Class', + value: 'com.wix.detox.espresso.DetoxMatcher' + }, + method: 'matcherForAtIndex', + args: [ + { + type: 'Integer', + value: index + }, + { + type: 'Invocation', + value: sanitize_matcher(innerMatcher) + } + ] + }; + } - static matcherForAnything() { - return { - target: { - type: 'Class', - value: 'com.wix.detox.espresso.DetoxMatcher' - }, - method: 'matcherForAnything', - args: [] - }; - } + static matcherForAnything() { + return { + target: { + type: 'Class', + value: 'com.wix.detox.espresso.DetoxMatcher' + }, + method: 'matcherForAnything', + args: [] + }; + } } module.exports = DetoxMatcher; diff --git a/detox/src/android/espressoapi/ViewActions.js b/detox/src/android/espressoapi/ViewActions.js index 094454ab39..d0a8435620 100644 --- a/detox/src/android/espressoapi/ViewActions.js +++ b/detox/src/android/espressoapi/ViewActions.js @@ -5,240 +5,240 @@ */ class ViewActions { - static clearGlobalAssertions() { - return { - target: { - type: 'Class', - value: 'android.support.test.espresso.action.ViewActions' - }, - method: 'clearGlobalAssertions', - args: [] - }; - } - - static clearText() { - return { - target: { - type: 'Class', - value: 'android.support.test.espresso.action.ViewActions' - }, - method: 'clearText', - args: [] - }; - } - - static click() { - return { - target: { - type: 'Class', - value: 'android.support.test.espresso.action.ViewActions' - }, - method: 'click', - args: [] - }; - } - - static swipeLeft() { - return { - target: { - type: 'Class', - value: 'android.support.test.espresso.action.ViewActions' - }, - method: 'swipeLeft', - args: [] - }; - } - - static swipeRight() { - return { - target: { - type: 'Class', - value: 'android.support.test.espresso.action.ViewActions' - }, - method: 'swipeRight', - args: [] - }; - } - - static swipeDown() { - return { - target: { - type: 'Class', - value: 'android.support.test.espresso.action.ViewActions' - }, - method: 'swipeDown', - args: [] - }; - } - - static swipeUp() { - return { - target: { - type: 'Class', - value: 'android.support.test.espresso.action.ViewActions' - }, - method: 'swipeUp', - args: [] - }; - } - - static closeSoftKeyboard() { - return { - target: { - type: 'Class', - value: 'android.support.test.espresso.action.ViewActions' - }, - method: 'closeSoftKeyboard', - args: [] - }; - } - - static pressImeActionButton() { - return { - target: { - type: 'Class', - value: 'android.support.test.espresso.action.ViewActions' - }, - method: 'pressImeActionButton', - args: [] - }; - } - - static pressBack() { - return { - target: { - type: 'Class', - value: 'android.support.test.espresso.action.ViewActions' - }, - method: 'pressBack', - args: [] - }; - } - - static pressMenuKey() { - return { - target: { - type: 'Class', - value: 'android.support.test.espresso.action.ViewActions' - }, - method: 'pressMenuKey', - args: [] - }; - } - - static pressKey(keyCode) { - if (typeof keyCode !== 'number') throw new Error('keyCode should be a number, but got ' + (keyCode + (' (' + (typeof keyCode + ')')))); - return { - target: { - type: 'Class', - value: 'android.support.test.espresso.action.ViewActions' - }, - method: 'pressKey', - args: [ - { - type: 'Integer', - value: keyCode - } - ] - }; - } - - static doubleClick() { - return { - target: { - type: 'Class', - value: 'android.support.test.espresso.action.ViewActions' - }, - method: 'doubleClick', - args: [] - }; - } - - static longClick() { - return { - target: { - type: 'Class', - value: 'android.support.test.espresso.action.ViewActions' - }, - method: 'longClick', - args: [] - }; - } - - static scrollTo() { - return { - target: { - type: 'Class', - value: 'android.support.test.espresso.action.ViewActions' - }, - method: 'scrollTo', - args: [] - }; - } - - static typeTextIntoFocusedView(stringToBeTyped) { - if (typeof stringToBeTyped !== 'string') - throw new Error('stringToBeTyped should be a string, but got ' + (stringToBeTyped + (' (' + (typeof stringToBeTyped + ')')))); - return { - target: { - type: 'Class', - value: 'android.support.test.espresso.action.ViewActions' - }, - method: 'typeTextIntoFocusedView', - args: [stringToBeTyped] - }; - } - - static typeText(stringToBeTyped) { - if (typeof stringToBeTyped !== 'string') - throw new Error('stringToBeTyped should be a string, but got ' + (stringToBeTyped + (' (' + (typeof stringToBeTyped + ')')))); - return { - target: { - type: 'Class', - value: 'android.support.test.espresso.action.ViewActions' - }, - method: 'typeText', - args: [stringToBeTyped] - }; - } - - static replaceText(stringToBeSet) { - if (typeof stringToBeSet !== 'string') - throw new Error('stringToBeSet should be a string, but got ' + (stringToBeSet + (' (' + (typeof stringToBeSet + ')')))); - return { - target: { - type: 'Class', - value: 'android.support.test.espresso.action.ViewActions' - }, - method: 'replaceText', - args: [stringToBeSet] - }; - } - - static openLinkWithText(linkText) { - if (typeof linkText !== 'string') - throw new Error('linkText should be a string, but got ' + (linkText + (' (' + (typeof linkText + ')')))); - return { - target: { - type: 'Class', - value: 'android.support.test.espresso.action.ViewActions' - }, - method: 'openLinkWithText', - args: [linkText] - }; - } - - static openLinkWithUri(uri) { - if (typeof uri !== 'string') throw new Error('uri should be a string, but got ' + (uri + (' (' + (typeof uri + ')')))); - return { - target: { - type: 'Class', - value: 'android.support.test.espresso.action.ViewActions' - }, - method: 'openLinkWithUri', - args: [uri] - }; - } + static clearGlobalAssertions() { + return { + target: { + type: 'Class', + value: 'android.support.test.espresso.action.ViewActions' + }, + method: 'clearGlobalAssertions', + args: [] + }; + } + + static clearText() { + return { + target: { + type: 'Class', + value: 'android.support.test.espresso.action.ViewActions' + }, + method: 'clearText', + args: [] + }; + } + + static click() { + return { + target: { + type: 'Class', + value: 'android.support.test.espresso.action.ViewActions' + }, + method: 'click', + args: [] + }; + } + + static swipeLeft() { + return { + target: { + type: 'Class', + value: 'android.support.test.espresso.action.ViewActions' + }, + method: 'swipeLeft', + args: [] + }; + } + + static swipeRight() { + return { + target: { + type: 'Class', + value: 'android.support.test.espresso.action.ViewActions' + }, + method: 'swipeRight', + args: [] + }; + } + + static swipeDown() { + return { + target: { + type: 'Class', + value: 'android.support.test.espresso.action.ViewActions' + }, + method: 'swipeDown', + args: [] + }; + } + + static swipeUp() { + return { + target: { + type: 'Class', + value: 'android.support.test.espresso.action.ViewActions' + }, + method: 'swipeUp', + args: [] + }; + } + + static closeSoftKeyboard() { + return { + target: { + type: 'Class', + value: 'android.support.test.espresso.action.ViewActions' + }, + method: 'closeSoftKeyboard', + args: [] + }; + } + + static pressImeActionButton() { + return { + target: { + type: 'Class', + value: 'android.support.test.espresso.action.ViewActions' + }, + method: 'pressImeActionButton', + args: [] + }; + } + + static pressBack() { + return { + target: { + type: 'Class', + value: 'android.support.test.espresso.action.ViewActions' + }, + method: 'pressBack', + args: [] + }; + } + + static pressMenuKey() { + return { + target: { + type: 'Class', + value: 'android.support.test.espresso.action.ViewActions' + }, + method: 'pressMenuKey', + args: [] + }; + } + + static pressKey(keyCode) { + if (typeof keyCode !== 'number') throw new Error('keyCode should be a number, but got ' + (keyCode + (' (' + (typeof keyCode + ')')))); + return { + target: { + type: 'Class', + value: 'android.support.test.espresso.action.ViewActions' + }, + method: 'pressKey', + args: [ + { + type: 'Integer', + value: keyCode + } + ] + }; + } + + static doubleClick() { + return { + target: { + type: 'Class', + value: 'android.support.test.espresso.action.ViewActions' + }, + method: 'doubleClick', + args: [] + }; + } + + static longClick() { + return { + target: { + type: 'Class', + value: 'android.support.test.espresso.action.ViewActions' + }, + method: 'longClick', + args: [] + }; + } + + static scrollTo() { + return { + target: { + type: 'Class', + value: 'android.support.test.espresso.action.ViewActions' + }, + method: 'scrollTo', + args: [] + }; + } + + static typeTextIntoFocusedView(stringToBeTyped) { + if (typeof stringToBeTyped !== 'string') + throw new Error('stringToBeTyped should be a string, but got ' + (stringToBeTyped + (' (' + (typeof stringToBeTyped + ')')))); + return { + target: { + type: 'Class', + value: 'android.support.test.espresso.action.ViewActions' + }, + method: 'typeTextIntoFocusedView', + args: [stringToBeTyped] + }; + } + + static typeText(stringToBeTyped) { + if (typeof stringToBeTyped !== 'string') + throw new Error('stringToBeTyped should be a string, but got ' + (stringToBeTyped + (' (' + (typeof stringToBeTyped + ')')))); + return { + target: { + type: 'Class', + value: 'android.support.test.espresso.action.ViewActions' + }, + method: 'typeText', + args: [stringToBeTyped] + }; + } + + static replaceText(stringToBeSet) { + if (typeof stringToBeSet !== 'string') + throw new Error('stringToBeSet should be a string, but got ' + (stringToBeSet + (' (' + (typeof stringToBeSet + ')')))); + return { + target: { + type: 'Class', + value: 'android.support.test.espresso.action.ViewActions' + }, + method: 'replaceText', + args: [stringToBeSet] + }; + } + + static openLinkWithText(linkText) { + if (typeof linkText !== 'string') + throw new Error('linkText should be a string, but got ' + (linkText + (' (' + (typeof linkText + ')')))); + return { + target: { + type: 'Class', + value: 'android.support.test.espresso.action.ViewActions' + }, + method: 'openLinkWithText', + args: [linkText] + }; + } + + static openLinkWithUri(uri) { + if (typeof uri !== 'string') throw new Error('uri should be a string, but got ' + (uri + (' (' + (typeof uri + ')')))); + return { + target: { + type: 'Class', + value: 'android.support.test.espresso.action.ViewActions' + }, + method: 'openLinkWithUri', + args: [uri] + }; + } } module.exports = ViewActions; diff --git a/detox/src/ios/earlgreyapi/GREYActions.js b/detox/src/ios/earlgreyapi/GREYActions.js index d33f934a24..9c0a47d016 100644 --- a/detox/src/ios/earlgreyapi/GREYActions.js +++ b/detox/src/ios/earlgreyapi/GREYActions.js @@ -5,124 +5,124 @@ */ function sanitize_greyDirection(action) { - switch (action) { - case 'left': - return 1; - case 'right': - return 2; - case 'up': - return 3; - case 'down': - return 4; - - default: - throw new Error(`GREYAction.GREYDirection must be a 'left'/'right'/'up'/'down', got ${action}`); - } + switch (action) { + case 'left': + return 1; + case 'right': + return 2; + case 'up': + return 3; + case 'down': + return 4; + + default: + throw new Error(`GREYAction.GREYDirection must be a 'left'/'right'/'up'/'down', got ${action}`); + } } function sanitize_greyContentEdge(action) { - switch (action) { - case 'left': - return 0; - case 'right': - return 1; - case 'top': - return 2; - case 'bottom': - return 3; - - default: - throw new Error(`GREYAction.GREYContentEdge must be a 'left'/'right'/'top'/'bottom', got ${action}`); - } + switch (action) { + case 'left': + return 0; + case 'right': + return 1; + case 'top': + return 2; + case 'bottom': + return 3; + + default: + throw new Error(`GREYAction.GREYContentEdge must be a 'left'/'right'/'top'/'bottom', got ${action}`); + } } class GREYActions { - /*@return A GREYAction that performs multiple taps of a specified @c count. + /*@return A GREYAction that performs multiple taps of a specified @c count. */ static actionForMultipleTapsWithCount(count) { - if (typeof count !== 'number') throw new Error('count should be a number, but got ' + (count + (' (' + (typeof count + ')')))); - return { - target: { - type: 'Class', - value: 'GREYActions' - }, - method: 'actionForMultipleTapsWithCount:', - args: [ - { - type: 'NSInteger', - value: count - } - ] - }; - } - - /*@return A GREYAction that performs multiple taps of a specified @c count at a specified + if (typeof count !== 'number') throw new Error('count should be a number, but got ' + (count + (' (' + (typeof count + ')')))); + return { + target: { + type: 'Class', + value: 'GREYActions' + }, + method: 'actionForMultipleTapsWithCount:', + args: [ + { + type: 'NSInteger', + value: count + } + ] + }; + } + + /*@return A GREYAction that performs multiple taps of a specified @c count at a specified @c point. */ static actionForMultipleTapsWithCountAtPoint( - count, - point - ) { - if (typeof count !== 'number') throw new Error('count should be a number, but got ' + (count + (' (' + (typeof count + ')')))); - if (typeof point !== 'object') throw new Error('point should be a object, but got ' + (point + (' (' + (typeof point + ')')))); - if (typeof point.x !== 'number') throw new Error('point.x should be a number, but got ' + (point.x + (' (' + (typeof point.x + ')')))); - if (typeof point.y !== 'number') throw new Error('point.y should be a number, but got ' + (point.y + (' (' + (typeof point.y + ')')))); - return { - target: { - type: 'Class', - value: 'GREYActions' - }, - method: 'actionForMultipleTapsWithCount:atPoint:', - args: [ - { - type: 'NSInteger', - value: count - }, - { - type: 'CGPoint', - value: point - } - ] - }; - } - - /*Returns an action that holds down finger for 1.0 second (@c kGREYLongPressDefaultDuration) to + count, + point + ) { + if (typeof count !== 'number') throw new Error('count should be a number, but got ' + (count + (' (' + (typeof count + ')')))); + if (typeof point !== 'object') throw new Error('point should be a object, but got ' + (point + (' (' + (typeof point + ')')))); + if (typeof point.x !== 'number') throw new Error('point.x should be a number, but got ' + (point.x + (' (' + (typeof point.x + ')')))); + if (typeof point.y !== 'number') throw new Error('point.y should be a number, but got ' + (point.y + (' (' + (typeof point.y + ')')))); + return { + target: { + type: 'Class', + value: 'GREYActions' + }, + method: 'actionForMultipleTapsWithCount:atPoint:', + args: [ + { + type: 'NSInteger', + value: count + }, + { + type: 'CGPoint', + value: point + } + ] + }; + } + + /*Returns an action that holds down finger for 1.0 second (@c kGREYLongPressDefaultDuration) to simulate a long press. @return A GREYAction that performs a long press on an element. */ static actionForLongPress() { - return { - target: { - type: 'Class', - value: 'GREYActions' - }, - method: 'actionForLongPress', - args: [] - }; - } - - /*Returns an action that holds down finger for specified @c duration to simulate a long press. + return { + target: { + type: 'Class', + value: 'GREYActions' + }, + method: 'actionForLongPress', + args: [] + }; + } + + /*Returns an action that holds down finger for specified @c duration to simulate a long press. @param duration The duration of the long press. @return A GREYAction that performs a long press on an element. */ static actionForLongPressWithDuration( - duration - ) { - if (typeof duration !== 'number') - throw new Error('duration should be a number, but got ' + (duration + (' (' + (typeof duration + ')')))); - return { - target: { - type: 'Class', - value: 'GREYActions' - }, - method: 'actionForLongPressWithDuration:', - args: [ - { - type: 'CGFloat', - value: duration - } - ] - }; - } - - /*Returns an action that holds down finger for specified @c duration at the specified @c point + duration + ) { + if (typeof duration !== 'number') + throw new Error('duration should be a number, but got ' + (duration + (' (' + (typeof duration + ')')))); + return { + target: { + type: 'Class', + value: 'GREYActions' + }, + method: 'actionForLongPressWithDuration:', + args: [ + { + type: 'CGFloat', + value: duration + } + ] + }; + } + + /*Returns an action that holds down finger for specified @c duration at the specified @c point (interpreted as being relative to the element) to simulate a long press. @param point The point that should be tapped. @@ -130,34 +130,34 @@ simulate a long press. @return A GREYAction that performs a long press on an element. */ static actionForLongPressAtPointDuration( - point, - duration - ) { - if (typeof point !== 'object') throw new Error('point should be a object, but got ' + (point + (' (' + (typeof point + ')')))); - if (typeof point.x !== 'number') throw new Error('point.x should be a number, but got ' + (point.x + (' (' + (typeof point.x + ')')))); - if (typeof point.y !== 'number') throw new Error('point.y should be a number, but got ' + (point.y + (' (' + (typeof point.y + ')')))); - if (typeof duration !== 'number') - throw new Error('duration should be a number, but got ' + (duration + (' (' + (typeof duration + ')')))); - return { - target: { - type: 'Class', - value: 'GREYActions' - }, - method: 'actionForLongPressAtPoint:duration:', - args: [ - { - type: 'CGPoint', - value: point - }, - { - type: 'CGFloat', - value: duration - } - ] - }; - } - - /*Returns an action that scrolls a @c UIScrollView by @c amount (in points) in the specified + point, + duration + ) { + if (typeof point !== 'object') throw new Error('point should be a object, but got ' + (point + (' (' + (typeof point + ')')))); + if (typeof point.x !== 'number') throw new Error('point.x should be a number, but got ' + (point.x + (' (' + (typeof point.x + ')')))); + if (typeof point.y !== 'number') throw new Error('point.y should be a number, but got ' + (point.y + (' (' + (typeof point.y + ')')))); + if (typeof duration !== 'number') + throw new Error('duration should be a number, but got ' + (duration + (' (' + (typeof duration + ')')))); + return { + target: { + type: 'Class', + value: 'GREYActions' + }, + method: 'actionForLongPressAtPoint:duration:', + args: [ + { + type: 'CGPoint', + value: point + }, + { + type: 'CGFloat', + value: duration + } + ] + }; + } + + /*Returns an action that scrolls a @c UIScrollView by @c amount (in points) in the specified @c direction. @param direction The direction of the swipe. @@ -165,32 +165,32 @@ simulate a long press. @return A GREYAction that scrolls a scroll view in a given @c direction for a given @c amount. */ static actionForScrollInDirectionAmount( - direction, - amount - ) { - if (!['left', 'right', 'up', 'down'].some((option) => option === direction)) - throw new Error('direction should be one of [left, right, up, down], but got ' + direction); - if (typeof amount !== 'number') throw new Error('amount should be a number, but got ' + (amount + (' (' + (typeof amount + ')')))); - return { - target: { - type: 'Class', - value: 'GREYActions' - }, - method: 'actionForScrollInDirection:amount:', - args: [ - { - type: 'NSInteger', - value: sanitize_greyDirection(direction) - }, - { - type: 'CGFloat', - value: amount - } - ] - }; - } - - /*Returns a scroll action that scrolls in a @c direction for an @c amount of points starting from + direction, + amount + ) { + if (!['left', 'right', 'up', 'down'].some((option) => option === direction)) + throw new Error('direction should be one of [left, right, up, down], but got ' + direction); + if (typeof amount !== 'number') throw new Error('amount should be a number, but got ' + (amount + (' (' + (typeof amount + ')')))); + return { + target: { + type: 'Class', + value: 'GREYActions' + }, + method: 'actionForScrollInDirection:amount:', + args: [ + { + type: 'NSInteger', + value: sanitize_greyDirection(direction) + }, + { + type: 'CGFloat', + value: amount + } + ] + }; + } + + /*Returns a scroll action that scrolls in a @c direction for an @c amount of points starting from the given start point specified as percentages. @c xOriginStartPercentage is the x start position as a percentage of the total width of the scrollable visible area, @c yOriginStartPercentage is the y start position as a percentage of the total height of the @@ -207,69 +207,69 @@ exclusive, of the total height of the scrollable visible area. @return A GREYAction that scrolls a scroll view in a given @c direction for a given @c amount starting from the given start points. */ static actionForScrollInDirectionAmountXOriginStartPercentageYOriginStartPercentage( - direction, - amount, - xOriginStartPercentage, - yOriginStartPercentage - ) { - if (!['left', 'right', 'up', 'down'].some((option) => option === direction)) - throw new Error('direction should be one of [left, right, up, down], but got ' + direction); - if (typeof amount !== 'number') throw new Error('amount should be a number, but got ' + (amount + (' (' + (typeof amount + ')')))); - if (typeof xOriginStartPercentage !== 'number') - throw new Error( - 'xOriginStartPercentage should be a number, but got ' + (xOriginStartPercentage + (' (' + (typeof xOriginStartPercentage + ')'))) - ); - if (typeof yOriginStartPercentage !== 'number') - throw new Error( - 'yOriginStartPercentage should be a number, but got ' + (yOriginStartPercentage + (' (' + (typeof yOriginStartPercentage + ')'))) - ); - return { - target: { - type: 'Class', - value: 'GREYActions' - }, - method: 'actionForScrollInDirection:amount:xOriginStartPercentage:yOriginStartPercentage:', - args: [ - { - type: 'NSInteger', - value: sanitize_greyDirection(direction) - }, - { - type: 'CGFloat', - value: amount - }, - { - type: 'CGFloat', - value: xOriginStartPercentage - }, - { - type: 'CGFloat', - value: yOriginStartPercentage - } - ] - }; - } - - /*@return A GREYAction that scrolls to the given content @c edge of a scroll view. + direction, + amount, + xOriginStartPercentage, + yOriginStartPercentage + ) { + if (!['left', 'right', 'up', 'down'].some((option) => option === direction)) + throw new Error('direction should be one of [left, right, up, down], but got ' + direction); + if (typeof amount !== 'number') throw new Error('amount should be a number, but got ' + (amount + (' (' + (typeof amount + ')')))); + if (typeof xOriginStartPercentage !== 'number') + throw new Error( + 'xOriginStartPercentage should be a number, but got ' + (xOriginStartPercentage + (' (' + (typeof xOriginStartPercentage + ')'))) + ); + if (typeof yOriginStartPercentage !== 'number') + throw new Error( + 'yOriginStartPercentage should be a number, but got ' + (yOriginStartPercentage + (' (' + (typeof yOriginStartPercentage + ')'))) + ); + return { + target: { + type: 'Class', + value: 'GREYActions' + }, + method: 'actionForScrollInDirection:amount:xOriginStartPercentage:yOriginStartPercentage:', + args: [ + { + type: 'NSInteger', + value: sanitize_greyDirection(direction) + }, + { + type: 'CGFloat', + value: amount + }, + { + type: 'CGFloat', + value: xOriginStartPercentage + }, + { + type: 'CGFloat', + value: yOriginStartPercentage + } + ] + }; + } + + /*@return A GREYAction that scrolls to the given content @c edge of a scroll view. */ static actionForScrollToContentEdge(edge) { - if (!['left', 'right', 'top', 'bottom'].some((option) => option === edge)) - throw new Error('edge should be one of [left, right, top, bottom], but got ' + edge); - return { - target: { - type: 'Class', - value: 'GREYActions' - }, - method: 'actionForScrollToContentEdge:', - args: [ - { - type: 'NSInteger', - value: sanitize_greyContentEdge(edge) - } - ] - }; - } - - /*A GREYAction that scrolls to the given content @c edge of a scroll view with the scroll action + if (!['left', 'right', 'top', 'bottom'].some((option) => option === edge)) + throw new Error('edge should be one of [left, right, top, bottom], but got ' + edge); + return { + target: { + type: 'Class', + value: 'GREYActions' + }, + method: 'actionForScrollToContentEdge:', + args: [ + { + type: 'NSInteger', + value: sanitize_greyContentEdge(edge) + } + ] + }; + } + + /*A GREYAction that scrolls to the given content @c edge of a scroll view with the scroll action starting from the given start point specified as percentages. @c xOriginStartPercentage is the x start position as a percentage of the total width of the scrollable visible area, @c yOriginStartPercentage is the y start position as a percentage of the total height of the @@ -285,96 +285,96 @@ exclusive, of the total height of the scrollable visible area. @return A GREYAction that scrolls to the given content @c edge of a scroll view with the scroll action starting from the given start point. */ static actionForScrollToContentEdgeXOriginStartPercentageYOriginStartPercentage( - edge, - xOriginStartPercentage, - yOriginStartPercentage - ) { - if (!['left', 'right', 'top', 'bottom'].some((option) => option === edge)) - throw new Error('edge should be one of [left, right, top, bottom], but got ' + edge); - if (typeof xOriginStartPercentage !== 'number') - throw new Error( - 'xOriginStartPercentage should be a number, but got ' + (xOriginStartPercentage + (' (' + (typeof xOriginStartPercentage + ')'))) - ); - if (typeof yOriginStartPercentage !== 'number') - throw new Error( - 'yOriginStartPercentage should be a number, but got ' + (yOriginStartPercentage + (' (' + (typeof yOriginStartPercentage + ')'))) - ); - return { - target: { - type: 'Class', - value: 'GREYActions' - }, - method: 'actionForScrollToContentEdge:xOriginStartPercentage:yOriginStartPercentage:', - args: [ - { - type: 'NSInteger', - value: sanitize_greyContentEdge(edge) - }, - { - type: 'CGFloat', - value: xOriginStartPercentage - }, - { - type: 'CGFloat', - value: yOriginStartPercentage - } - ] - }; - } - - /*Returns an action that fast swipes through the view. The start point of the swipe is chosen to + edge, + xOriginStartPercentage, + yOriginStartPercentage + ) { + if (!['left', 'right', 'top', 'bottom'].some((option) => option === edge)) + throw new Error('edge should be one of [left, right, top, bottom], but got ' + edge); + if (typeof xOriginStartPercentage !== 'number') + throw new Error( + 'xOriginStartPercentage should be a number, but got ' + (xOriginStartPercentage + (' (' + (typeof xOriginStartPercentage + ')'))) + ); + if (typeof yOriginStartPercentage !== 'number') + throw new Error( + 'yOriginStartPercentage should be a number, but got ' + (yOriginStartPercentage + (' (' + (typeof yOriginStartPercentage + ')'))) + ); + return { + target: { + type: 'Class', + value: 'GREYActions' + }, + method: 'actionForScrollToContentEdge:xOriginStartPercentage:yOriginStartPercentage:', + args: [ + { + type: 'NSInteger', + value: sanitize_greyContentEdge(edge) + }, + { + type: 'CGFloat', + value: xOriginStartPercentage + }, + { + type: 'CGFloat', + value: yOriginStartPercentage + } + ] + }; + } + + /*Returns an action that fast swipes through the view. The start point of the swipe is chosen to achieve the maximum the swipe possible to the other edge. @param direction The direction of the swipe. @return A GREYAction that performs a fast swipe in the given direction. */ static actionForSwipeFastInDirection( - direction - ) { - if (!['left', 'right', 'up', 'down'].some((option) => option === direction)) - throw new Error('direction should be one of [left, right, up, down], but got ' + direction); - return { - target: { - type: 'Class', - value: 'GREYActions' - }, - method: 'actionForSwipeFastInDirection:', - args: [ - { - type: 'NSInteger', - value: sanitize_greyDirection(direction) - } - ] - }; - } - - /*Returns an action that slow swipes through the view. The start point of the swipe is chosen to + direction + ) { + if (!['left', 'right', 'up', 'down'].some((option) => option === direction)) + throw new Error('direction should be one of [left, right, up, down], but got ' + direction); + return { + target: { + type: 'Class', + value: 'GREYActions' + }, + method: 'actionForSwipeFastInDirection:', + args: [ + { + type: 'NSInteger', + value: sanitize_greyDirection(direction) + } + ] + }; + } + + /*Returns an action that slow swipes through the view. The start point of the swipe is chosen to achieve maximum the swipe possible to the other edge. @param direction The direction of the swipe. @return A GREYAction that performs a slow swipe in the given direction. */ static actionForSwipeSlowInDirection( - direction - ) { - if (!['left', 'right', 'up', 'down'].some((option) => option === direction)) - throw new Error('direction should be one of [left, right, up, down], but got ' + direction); - return { - target: { - type: 'Class', - value: 'GREYActions' - }, - method: 'actionForSwipeSlowInDirection:', - args: [ - { - type: 'NSInteger', - value: sanitize_greyDirection(direction) - } - ] - }; - } - - /*Returns an action that swipes through the view quickly in the given @c direction from a specific + direction + ) { + if (!['left', 'right', 'up', 'down'].some((option) => option === direction)) + throw new Error('direction should be one of [left, right, up, down], but got ' + direction); + return { + target: { + type: 'Class', + value: 'GREYActions' + }, + method: 'actionForSwipeSlowInDirection:', + args: [ + { + type: 'NSInteger', + value: sanitize_greyDirection(direction) + } + ] + }; + } + + /*Returns an action that swipes through the view quickly in the given @c direction from a specific origin. @param direction The direction of the swipe. @@ -386,44 +386,44 @@ of the view. This must be between 0 and 1. @return A GREYAction that performs a fast swipe through a view in a specific direction from the specified point. */ static actionForSwipeFastInDirectionXOriginStartPercentageYOriginStartPercentage( - direction, - xOriginStartPercentage, - yOriginStartPercentage - ) { - if (!['left', 'right', 'up', 'down'].some((option) => option === direction)) - throw new Error('direction should be one of [left, right, up, down], but got ' + direction); - if (typeof xOriginStartPercentage !== 'number') - throw new Error( - 'xOriginStartPercentage should be a number, but got ' + (xOriginStartPercentage + (' (' + (typeof xOriginStartPercentage + ')'))) - ); - if (typeof yOriginStartPercentage !== 'number') - throw new Error( - 'yOriginStartPercentage should be a number, but got ' + (yOriginStartPercentage + (' (' + (typeof yOriginStartPercentage + ')'))) - ); - return { - target: { - type: 'Class', - value: 'GREYActions' - }, - method: 'actionForSwipeFastInDirection:xOriginStartPercentage:yOriginStartPercentage:', - args: [ - { - type: 'NSInteger', - value: sanitize_greyDirection(direction) - }, - { - type: 'CGFloat', - value: xOriginStartPercentage - }, - { - type: 'CGFloat', - value: yOriginStartPercentage - } - ] - }; - } - - /*Returns an action that swipes through the view quickly in the given @c direction from a + direction, + xOriginStartPercentage, + yOriginStartPercentage + ) { + if (!['left', 'right', 'up', 'down'].some((option) => option === direction)) + throw new Error('direction should be one of [left, right, up, down], but got ' + direction); + if (typeof xOriginStartPercentage !== 'number') + throw new Error( + 'xOriginStartPercentage should be a number, but got ' + (xOriginStartPercentage + (' (' + (typeof xOriginStartPercentage + ')'))) + ); + if (typeof yOriginStartPercentage !== 'number') + throw new Error( + 'yOriginStartPercentage should be a number, but got ' + (yOriginStartPercentage + (' (' + (typeof yOriginStartPercentage + ')'))) + ); + return { + target: { + type: 'Class', + value: 'GREYActions' + }, + method: 'actionForSwipeFastInDirection:xOriginStartPercentage:yOriginStartPercentage:', + args: [ + { + type: 'NSInteger', + value: sanitize_greyDirection(direction) + }, + { + type: 'CGFloat', + value: xOriginStartPercentage + }, + { + type: 'CGFloat', + value: yOriginStartPercentage + } + ] + }; + } + + /*Returns an action that swipes through the view quickly in the given @c direction from a specific origin. @param direction The direction of the swipe. @@ -435,44 +435,44 @@ of the view. This must be between 0 and 1. @return A GREYAction that performs a slow swipe through a view in a specific direction from the specified point. */ static actionForSwipeSlowInDirectionXOriginStartPercentageYOriginStartPercentage( - direction, - xOriginStartPercentage, - yOriginStartPercentage - ) { - if (!['left', 'right', 'up', 'down'].some((option) => option === direction)) - throw new Error('direction should be one of [left, right, up, down], but got ' + direction); - if (typeof xOriginStartPercentage !== 'number') - throw new Error( - 'xOriginStartPercentage should be a number, but got ' + (xOriginStartPercentage + (' (' + (typeof xOriginStartPercentage + ')'))) - ); - if (typeof yOriginStartPercentage !== 'number') - throw new Error( - 'yOriginStartPercentage should be a number, but got ' + (yOriginStartPercentage + (' (' + (typeof yOriginStartPercentage + ')'))) - ); - return { - target: { - type: 'Class', - value: 'GREYActions' - }, - method: 'actionForSwipeSlowInDirection:xOriginStartPercentage:yOriginStartPercentage:', - args: [ - { - type: 'NSInteger', - value: sanitize_greyDirection(direction) - }, - { - type: 'CGFloat', - value: xOriginStartPercentage - }, - { - type: 'CGFloat', - value: yOriginStartPercentage - } - ] - }; - } - - /*Returns an action that performs a multi-finger slow swipe through the view in the given + direction, + xOriginStartPercentage, + yOriginStartPercentage + ) { + if (!['left', 'right', 'up', 'down'].some((option) => option === direction)) + throw new Error('direction should be one of [left, right, up, down], but got ' + direction); + if (typeof xOriginStartPercentage !== 'number') + throw new Error( + 'xOriginStartPercentage should be a number, but got ' + (xOriginStartPercentage + (' (' + (typeof xOriginStartPercentage + ')'))) + ); + if (typeof yOriginStartPercentage !== 'number') + throw new Error( + 'yOriginStartPercentage should be a number, but got ' + (yOriginStartPercentage + (' (' + (typeof yOriginStartPercentage + ')'))) + ); + return { + target: { + type: 'Class', + value: 'GREYActions' + }, + method: 'actionForSwipeSlowInDirection:xOriginStartPercentage:yOriginStartPercentage:', + args: [ + { + type: 'NSInteger', + value: sanitize_greyDirection(direction) + }, + { + type: 'CGFloat', + value: xOriginStartPercentage + }, + { + type: 'CGFloat', + value: yOriginStartPercentage + } + ] + }; + } + + /*Returns an action that performs a multi-finger slow swipe through the view in the given @c direction. @param direction The direction of the swipe. @@ -481,33 +481,33 @@ the specified point. @return A GREYAction that performs a multi-finger slow swipe through a view in a specific direction from the specified point. */ static actionForMultiFingerSwipeSlowInDirectionNumberOfFingers( - direction, - numberOfFingers - ) { - if (!['left', 'right', 'up', 'down'].some((option) => option === direction)) - throw new Error('direction should be one of [left, right, up, down], but got ' + direction); - if (typeof numberOfFingers !== 'number') - throw new Error('numberOfFingers should be a number, but got ' + (numberOfFingers + (' (' + (typeof numberOfFingers + ')')))); - return { - target: { - type: 'Class', - value: 'GREYActions' - }, - method: 'actionForMultiFingerSwipeSlowInDirection:numberOfFingers:', - args: [ - { - type: 'NSInteger', - value: sanitize_greyDirection(direction) - }, - { - type: 'NSInteger', - value: numberOfFingers - } - ] - }; - } - - /*Returns an action that performs a multi-finger fast swipe through the view in the given + direction, + numberOfFingers + ) { + if (!['left', 'right', 'up', 'down'].some((option) => option === direction)) + throw new Error('direction should be one of [left, right, up, down], but got ' + direction); + if (typeof numberOfFingers !== 'number') + throw new Error('numberOfFingers should be a number, but got ' + (numberOfFingers + (' (' + (typeof numberOfFingers + ')')))); + return { + target: { + type: 'Class', + value: 'GREYActions' + }, + method: 'actionForMultiFingerSwipeSlowInDirection:numberOfFingers:', + args: [ + { + type: 'NSInteger', + value: sanitize_greyDirection(direction) + }, + { + type: 'NSInteger', + value: numberOfFingers + } + ] + }; + } + + /*Returns an action that performs a multi-finger fast swipe through the view in the given @c direction. @param direction The direction of the swipe. @@ -516,33 +516,33 @@ direction from the specified point. @return A GREYAction that performs a multi-finger fast swipe through a view in a specific direction from the specified point. */ static actionForMultiFingerSwipeFastInDirectionNumberOfFingers( - direction, - numberOfFingers - ) { - if (!['left', 'right', 'up', 'down'].some((option) => option === direction)) - throw new Error('direction should be one of [left, right, up, down], but got ' + direction); - if (typeof numberOfFingers !== 'number') - throw new Error('numberOfFingers should be a number, but got ' + (numberOfFingers + (' (' + (typeof numberOfFingers + ')')))); - return { - target: { - type: 'Class', - value: 'GREYActions' - }, - method: 'actionForMultiFingerSwipeFastInDirection:numberOfFingers:', - args: [ - { - type: 'NSInteger', - value: sanitize_greyDirection(direction) - }, - { - type: 'NSInteger', - value: numberOfFingers - } - ] - }; - } - - /*Returns an action that performs a multi-finger slow swipe through the view in the given + direction, + numberOfFingers + ) { + if (!['left', 'right', 'up', 'down'].some((option) => option === direction)) + throw new Error('direction should be one of [left, right, up, down], but got ' + direction); + if (typeof numberOfFingers !== 'number') + throw new Error('numberOfFingers should be a number, but got ' + (numberOfFingers + (' (' + (typeof numberOfFingers + ')')))); + return { + target: { + type: 'Class', + value: 'GREYActions' + }, + method: 'actionForMultiFingerSwipeFastInDirection:numberOfFingers:', + args: [ + { + type: 'NSInteger', + value: sanitize_greyDirection(direction) + }, + { + type: 'NSInteger', + value: numberOfFingers + } + ] + }; + } + + /*Returns an action that performs a multi-finger slow swipe through the view in the given @c direction. @param direction The direction of the swipe. @@ -551,51 +551,51 @@ direction from the specified point. @return A GREYAction that performs a multi-finger slow swipe through a view in a specific direction from the specified point. */ static actionForMultiFingerSwipeSlowInDirectionNumberOfFingersXOriginStartPercentageYOriginStartPercentage( - direction, - numberOfFingers, - xOriginStartPercentage, - yOriginStartPercentage - ) { - if (!['left', 'right', 'up', 'down'].some((option) => option === direction)) - throw new Error('direction should be one of [left, right, up, down], but got ' + direction); - if (typeof numberOfFingers !== 'number') - throw new Error('numberOfFingers should be a number, but got ' + (numberOfFingers + (' (' + (typeof numberOfFingers + ')')))); - if (typeof xOriginStartPercentage !== 'number') - throw new Error( - 'xOriginStartPercentage should be a number, but got ' + (xOriginStartPercentage + (' (' + (typeof xOriginStartPercentage + ')'))) - ); - if (typeof yOriginStartPercentage !== 'number') - throw new Error( - 'yOriginStartPercentage should be a number, but got ' + (yOriginStartPercentage + (' (' + (typeof yOriginStartPercentage + ')'))) - ); - return { - target: { - type: 'Class', - value: 'GREYActions' - }, - method: 'actionForMultiFingerSwipeSlowInDirection:numberOfFingers:xOriginStartPercentage:yOriginStartPercentage:', - args: [ - { - type: 'NSInteger', - value: sanitize_greyDirection(direction) - }, - { - type: 'NSInteger', - value: numberOfFingers - }, - { - type: 'CGFloat', - value: xOriginStartPercentage - }, - { - type: 'CGFloat', - value: yOriginStartPercentage - } - ] - }; - } - - /*Returns an action that performs a multi-finger fast swipe through the view in the given + direction, + numberOfFingers, + xOriginStartPercentage, + yOriginStartPercentage + ) { + if (!['left', 'right', 'up', 'down'].some((option) => option === direction)) + throw new Error('direction should be one of [left, right, up, down], but got ' + direction); + if (typeof numberOfFingers !== 'number') + throw new Error('numberOfFingers should be a number, but got ' + (numberOfFingers + (' (' + (typeof numberOfFingers + ')')))); + if (typeof xOriginStartPercentage !== 'number') + throw new Error( + 'xOriginStartPercentage should be a number, but got ' + (xOriginStartPercentage + (' (' + (typeof xOriginStartPercentage + ')'))) + ); + if (typeof yOriginStartPercentage !== 'number') + throw new Error( + 'yOriginStartPercentage should be a number, but got ' + (yOriginStartPercentage + (' (' + (typeof yOriginStartPercentage + ')'))) + ); + return { + target: { + type: 'Class', + value: 'GREYActions' + }, + method: 'actionForMultiFingerSwipeSlowInDirection:numberOfFingers:xOriginStartPercentage:yOriginStartPercentage:', + args: [ + { + type: 'NSInteger', + value: sanitize_greyDirection(direction) + }, + { + type: 'NSInteger', + value: numberOfFingers + }, + { + type: 'CGFloat', + value: xOriginStartPercentage + }, + { + type: 'CGFloat', + value: yOriginStartPercentage + } + ] + }; + } + + /*Returns an action that performs a multi-finger fast swipe through the view in the given @c direction. @param direction The direction of the swipe. @@ -604,65 +604,65 @@ direction from the specified point. @return A GREYAction that performs a multi-finger fast swipe through a view in a specific direction from the specified point. */ static actionForMultiFingerSwipeFastInDirectionNumberOfFingersXOriginStartPercentageYOriginStartPercentage( - direction, - numberOfFingers, - xOriginStartPercentage, - yOriginStartPercentage - ) { - if (!['left', 'right', 'up', 'down'].some((option) => option === direction)) - throw new Error('direction should be one of [left, right, up, down], but got ' + direction); - if (typeof numberOfFingers !== 'number') - throw new Error('numberOfFingers should be a number, but got ' + (numberOfFingers + (' (' + (typeof numberOfFingers + ')')))); - if (typeof xOriginStartPercentage !== 'number') - throw new Error( - 'xOriginStartPercentage should be a number, but got ' + (xOriginStartPercentage + (' (' + (typeof xOriginStartPercentage + ')'))) - ); - if (typeof yOriginStartPercentage !== 'number') - throw new Error( - 'yOriginStartPercentage should be a number, but got ' + (yOriginStartPercentage + (' (' + (typeof yOriginStartPercentage + ')'))) - ); - return { - target: { - type: 'Class', - value: 'GREYActions' - }, - method: 'actionForMultiFingerSwipeFastInDirection:numberOfFingers:xOriginStartPercentage:yOriginStartPercentage:', - args: [ - { - type: 'NSInteger', - value: sanitize_greyDirection(direction) - }, - { - type: 'NSInteger', - value: numberOfFingers - }, - { - type: 'CGFloat', - value: xOriginStartPercentage - }, - { - type: 'CGFloat', - value: yOriginStartPercentage - } - ] - }; - } - - /*Returns an action that taps on an element at the activation point of the element. + direction, + numberOfFingers, + xOriginStartPercentage, + yOriginStartPercentage + ) { + if (!['left', 'right', 'up', 'down'].some((option) => option === direction)) + throw new Error('direction should be one of [left, right, up, down], but got ' + direction); + if (typeof numberOfFingers !== 'number') + throw new Error('numberOfFingers should be a number, but got ' + (numberOfFingers + (' (' + (typeof numberOfFingers + ')')))); + if (typeof xOriginStartPercentage !== 'number') + throw new Error( + 'xOriginStartPercentage should be a number, but got ' + (xOriginStartPercentage + (' (' + (typeof xOriginStartPercentage + ')'))) + ); + if (typeof yOriginStartPercentage !== 'number') + throw new Error( + 'yOriginStartPercentage should be a number, but got ' + (yOriginStartPercentage + (' (' + (typeof yOriginStartPercentage + ')'))) + ); + return { + target: { + type: 'Class', + value: 'GREYActions' + }, + method: 'actionForMultiFingerSwipeFastInDirection:numberOfFingers:xOriginStartPercentage:yOriginStartPercentage:', + args: [ + { + type: 'NSInteger', + value: sanitize_greyDirection(direction) + }, + { + type: 'NSInteger', + value: numberOfFingers + }, + { + type: 'CGFloat', + value: xOriginStartPercentage + }, + { + type: 'CGFloat', + value: yOriginStartPercentage + } + ] + }; + } + + /*Returns an action that taps on an element at the activation point of the element. @return A GREYAction to tap on an element. */ static actionForTap() { - return { - target: { - type: 'Class', - value: 'GREYActions' - }, - method: 'actionForTap', - args: [] - }; - } - - /*Returns an action that taps on an element at the specified @c point. + return { + target: { + type: 'Class', + value: 'GREYActions' + }, + method: 'actionForTap', + args: [] + }; + } + + /*Returns an action that taps on an element at the specified @c point. @param point The point that should be tapped. It must be in the coordinate system of the element and it's position is relative to the origin of the element, as in @@ -670,27 +670,27 @@ element and it's position is relative to the origin of the element, as in @return A GREYAction to tap on an element at a specific point. */ static actionForTapAtPoint( - point - ) { - if (typeof point !== 'object') throw new Error('point should be a object, but got ' + (point + (' (' + (typeof point + ')')))); - if (typeof point.x !== 'number') throw new Error('point.x should be a number, but got ' + (point.x + (' (' + (typeof point.x + ')')))); - if (typeof point.y !== 'number') throw new Error('point.y should be a number, but got ' + (point.y + (' (' + (typeof point.y + ')')))); - return { - target: { - type: 'Class', - value: 'GREYActions' - }, - method: 'actionForTapAtPoint:', - args: [ - { - type: 'CGPoint', - value: point - } - ] - }; - } - - /*Returns an action that uses the iOS keyboard to input a string. + point + ) { + if (typeof point !== 'object') throw new Error('point should be a object, but got ' + (point + (' (' + (typeof point + ')')))); + if (typeof point.x !== 'number') throw new Error('point.x should be a number, but got ' + (point.x + (' (' + (typeof point.x + ')')))); + if (typeof point.y !== 'number') throw new Error('point.y should be a number, but got ' + (point.y + (' (' + (typeof point.y + ')')))); + return { + target: { + type: 'Class', + value: 'GREYActions' + }, + method: 'actionForTapAtPoint:', + args: [ + { + type: 'CGPoint', + value: point + } + ] + }; + } + + /*Returns an action that uses the iOS keyboard to input a string. @param text The text to be typed. For Objective-C, backspace is supported by using "\b" in the string and "\u{8}" in Swift strings. Return key is supported with "\n". @@ -699,90 +699,90 @@ For Example: @"Helpo\b\bloWorld" will type HelloWorld in Objective-C. @return A GREYAction to type a specific text string in a text field. */ static actionForTypeText( - text - ) { - if (typeof text !== 'string') throw new Error('text should be a string, but got ' + (text + (' (' + (typeof text + ')')))); - return { - target: { - type: 'Class', - value: 'GREYActions' - }, - method: 'actionForTypeText:', - args: [ - { - type: 'NSString', - value: text - } - ] - }; - } - - /*Returns an action that sets text on a UITextField or webview input directly. + text + ) { + if (typeof text !== 'string') throw new Error('text should be a string, but got ' + (text + (' (' + (typeof text + ')')))); + return { + target: { + type: 'Class', + value: 'GREYActions' + }, + method: 'actionForTypeText:', + args: [ + { + type: 'NSString', + value: text + } + ] + }; + } + + /*Returns an action that sets text on a UITextField or webview input directly. @param text The text to be typed. @return A GREYAction to type a specific text string in a text field. */ static actionForReplaceText( - text - ) { - if (typeof text !== 'string') throw new Error('text should be a string, but got ' + (text + (' (' + (typeof text + ')')))); - return { - target: { - type: 'Class', - value: 'GREYActions' - }, - method: 'actionForReplaceText:', - args: [ - { - type: 'NSString', - value: text - } - ] - }; - } - - /*@return A GREYAction that clears a text field by injecting back-spaces. + text + ) { + if (typeof text !== 'string') throw new Error('text should be a string, but got ' + (text + (' (' + (typeof text + ')')))); + return { + target: { + type: 'Class', + value: 'GREYActions' + }, + method: 'actionForReplaceText:', + args: [ + { + type: 'NSString', + value: text + } + ] + }; + } + + /*@return A GREYAction that clears a text field by injecting back-spaces. */ static actionForClearText() { - return { - target: { - type: 'Class', - value: 'GREYActions' - }, - method: 'actionForClearText', - args: [] - }; - } - - /*Returns an action that selects @c value on the given @c column of a UIPickerView. + return { + target: { + type: 'Class', + value: 'GREYActions' + }, + method: 'actionForClearText', + args: [] + }; + } + + /*Returns an action that selects @c value on the given @c column of a UIPickerView. @param column The UIPickerView column being set. @param value The value to set the UIPickerView. @return A GREYAction to set the value of a specified column of a UIPickerView. */ static actionForSetPickerColumnToValue( - column, - value - ) { - if (typeof column !== 'number') throw new Error('column should be a number, but got ' + (column + (' (' + (typeof column + ')')))); - if (typeof value !== 'string') throw new Error('value should be a string, but got ' + (value + (' (' + (typeof value + ')')))); - return { - target: { - type: 'Class', - value: 'GREYActions' - }, - method: 'actionForSetPickerColumn:toValue:', - args: [ - { - type: 'NSInteger', - value: column - }, - { - type: 'NSString', - value: value - } - ] - }; - } + column, + value + ) { + if (typeof column !== 'number') throw new Error('column should be a number, but got ' + (column + (' (' + (typeof column + ')')))); + if (typeof value !== 'string') throw new Error('value should be a string, but got ' + (value + (' (' + (typeof value + ')')))); + return { + target: { + type: 'Class', + value: 'GREYActions' + }, + method: 'actionForSetPickerColumn:toValue:', + args: [ + { + type: 'NSInteger', + value: column + }, + { + type: 'NSString', + value: value + } + ] + }; + } } module.exports = GREYActions; diff --git a/detox/src/ios/earlgreyapi/GREYCondition.js b/detox/src/ios/earlgreyapi/GREYCondition.js index c38e99a780..cc03662160 100644 --- a/detox/src/ios/earlgreyapi/GREYCondition.js +++ b/detox/src/ios/earlgreyapi/GREYCondition.js @@ -5,7 +5,7 @@ */ class GREYCondition { - /*Waits for the condition to be met until the specified @c seconds have elapsed. + /*Waits for the condition to be met until the specified @c seconds have elapsed. Will poll the condition as often as possible on the main thread while still giving a fair chance for other sources and handlers to be serviced. @@ -18,26 +18,26 @@ GREYCondition::waitWithTimeout:pollInterval: @return @c YES if the condition was met before the timeout, @c NO otherwise. */ static waitWithTimeout( - element, - seconds - ) { - if (typeof seconds !== 'number') throw new Error('seconds should be a number, but got ' + (seconds + (' (' + (typeof seconds + ')')))); - return { - target: { - type: 'Invocation', - value: element - }, - method: 'waitWithTimeout:', - args: [ - { - type: 'CGFloat', - value: seconds - } - ] - }; - } + element, + seconds + ) { + if (typeof seconds !== 'number') throw new Error('seconds should be a number, but got ' + (seconds + (' (' + (typeof seconds + ')')))); + return { + target: { + type: 'Invocation', + value: element + }, + method: 'waitWithTimeout:', + args: [ + { + type: 'CGFloat', + value: seconds + } + ] + }; + } - /*Waits for the condition to be met until the specified @c seconds have elapsed. Will poll the + /*Waits for the condition to be met until the specified @c seconds have elapsed. Will poll the condition immediately and then no more than once every @c interval seconds. Will attempt to poll the condition as close as possible to every @c interval seconds. @@ -48,31 +48,31 @@ the condition as close as possible to every @c interval seconds. @return @c YES if the condition was met before the timeout, @c NO otherwise. */ static waitWithTimeoutPollInterval( - element, - seconds, - interval - ) { - if (typeof seconds !== 'number') throw new Error('seconds should be a number, but got ' + (seconds + (' (' + (typeof seconds + ')')))); - if (typeof interval !== 'number') - throw new Error('interval should be a number, but got ' + (interval + (' (' + (typeof interval + ')')))); - return { - target: { - type: 'Invocation', - value: element - }, - method: 'waitWithTimeout:pollInterval:', - args: [ - { - type: 'CGFloat', - value: seconds - }, - { - type: 'CGFloat', - value: interval - } - ] - }; - } + element, + seconds, + interval + ) { + if (typeof seconds !== 'number') throw new Error('seconds should be a number, but got ' + (seconds + (' (' + (typeof seconds + ')')))); + if (typeof interval !== 'number') + throw new Error('interval should be a number, but got ' + (interval + (' (' + (typeof interval + ')')))); + return { + target: { + type: 'Invocation', + value: element + }, + method: 'waitWithTimeout:pollInterval:', + args: [ + { + type: 'CGFloat', + value: seconds + }, + { + type: 'CGFloat', + value: interval + } + ] + }; + } } module.exports = GREYCondition; diff --git a/detox/src/ios/earlgreyapi/GREYConditionDetox.js b/detox/src/ios/earlgreyapi/GREYConditionDetox.js index ac70ffc330..f523ba3e3c 100644 --- a/detox/src/ios/earlgreyapi/GREYConditionDetox.js +++ b/detox/src/ios/earlgreyapi/GREYConditionDetox.js @@ -5,41 +5,41 @@ */ function sanitize_greyElementInteraction(value) { - return { - type: 'Invocation', - value - }; + return { + type: 'Invocation', + value + }; } class GREYCondition { - static detoxConditionForElementMatched(interaction) { - if (typeof interaction !== 'object') { - throw new Error('interaction should be a GREYElementInteraction, but got ' + JSON.stringify(interaction)); - } + static detoxConditionForElementMatched(interaction) { + if (typeof interaction !== 'object') { + throw new Error('interaction should be a GREYElementInteraction, but got ' + JSON.stringify(interaction)); + } - return { - target: { - type: 'Class', - value: 'GREYCondition' - }, - method: 'detoxConditionForElementMatched:', - args: [sanitize_greyElementInteraction(interaction)] - }; - } + return { + target: { + type: 'Class', + value: 'GREYCondition' + }, + method: 'detoxConditionForElementMatched:', + args: [sanitize_greyElementInteraction(interaction)] + }; + } - static detoxConditionForNotElementMatched(interaction) { - if (typeof interaction !== 'object') { - throw new Error('interaction should be a GREYElementInteraction, but got ' + JSON.stringify(interaction)); - } + static detoxConditionForNotElementMatched(interaction) { + if (typeof interaction !== 'object') { + throw new Error('interaction should be a GREYElementInteraction, but got ' + JSON.stringify(interaction)); + } - return { - target: { - type: 'Class', - value: 'GREYCondition' - }, - method: 'detoxConditionForNotElementMatched:', - args: [sanitize_greyElementInteraction(interaction)] - }; - } + return { + target: { + type: 'Class', + value: 'GREYCondition' + }, + method: 'detoxConditionForNotElementMatched:', + args: [sanitize_greyElementInteraction(interaction)] + }; + } } module.exports = GREYCondition; diff --git a/detox/src/ios/earlgreyapi/GREYConfiguration.js b/detox/src/ios/earlgreyapi/GREYConfiguration.js index 2542fadfa7..273a4b9e3a 100644 --- a/detox/src/ios/earlgreyapi/GREYConfiguration.js +++ b/detox/src/ios/earlgreyapi/GREYConfiguration.js @@ -5,19 +5,19 @@ */ class GREYConfiguration { - /*@return The singleton GREYConfiguration instance. + /*@return The singleton GREYConfiguration instance. */ static sharedInstance() { - return { - target: { - type: 'Class', - value: 'GREYConfiguration' - }, - method: 'sharedInstance', - args: [] - }; - } - - /*If a user-configured value is associated with the given @c configKey, it is returned, + return { + target: { + type: 'Class', + value: 'GREYConfiguration' + }, + method: 'sharedInstance', + args: [] + }; + } + + /*If a user-configured value is associated with the given @c configKey, it is returned, otherwise the default value is returned. If a default value is not found, or an NSInvalidArgumentException is raised. @@ -27,27 +27,27 @@ NSInvalidArgumentException is raised. @return The value for the configuration stored associate with @c configKey. */ static valueForConfigKey( - element, - configKey - ) { - if (typeof configKey !== 'string') - throw new Error('configKey should be a string, but got ' + (configKey + (' (' + (typeof configKey + ')')))); - return { - target: { - type: 'Invocation', - value: element - }, - method: 'valueForConfigKey:', - args: [ - { - type: 'NSString', - value: configKey - } - ] - }; - } - - /*If a user-configured value is associated with the given @c configKey, it is returned, otherwise + element, + configKey + ) { + if (typeof configKey !== 'string') + throw new Error('configKey should be a string, but got ' + (configKey + (' (' + (typeof configKey + ')')))); + return { + target: { + type: 'Invocation', + value: element + }, + method: 'valueForConfigKey:', + args: [ + { + type: 'NSString', + value: configKey + } + ] + }; + } + + /*If a user-configured value is associated with the given @c configKey, it is returned, otherwise the default value is returned. If a default value is not found, NSInvalidArgumentException is raised. @@ -57,27 +57,27 @@ raised. @return The @c BOOL value for the configuration associated with @c configKey. */ static boolValueForConfigKey( - element, - configKey - ) { - if (typeof configKey !== 'string') - throw new Error('configKey should be a string, but got ' + (configKey + (' (' + (typeof configKey + ')')))); - return { - target: { - type: 'Invocation', - value: element - }, - method: 'boolValueForConfigKey:', - args: [ - { - type: 'NSString', - value: configKey - } - ] - }; - } - - /*If a user-configured value is associated with the given @c configKey, it is returned, otherwise + element, + configKey + ) { + if (typeof configKey !== 'string') + throw new Error('configKey should be a string, but got ' + (configKey + (' (' + (typeof configKey + ')')))); + return { + target: { + type: 'Invocation', + value: element + }, + method: 'boolValueForConfigKey:', + args: [ + { + type: 'NSString', + value: configKey + } + ] + }; + } + + /*If a user-configured value is associated with the given @c configKey, it is returned, otherwise the default value is returned. If a default value is not found, NSInvalidArgumentException is raised. @@ -87,27 +87,27 @@ raised. @return The integer value for the configuration associated with @c configKey. */ static integerValueForConfigKey( - element, - configKey - ) { - if (typeof configKey !== 'string') - throw new Error('configKey should be a string, but got ' + (configKey + (' (' + (typeof configKey + ')')))); - return { - target: { - type: 'Invocation', - value: element - }, - method: 'integerValueForConfigKey:', - args: [ - { - type: 'NSString', - value: configKey - } - ] - }; - } - - /*If a user-configured value is associated with the given @c configKey, it is returned, otherwise + element, + configKey + ) { + if (typeof configKey !== 'string') + throw new Error('configKey should be a string, but got ' + (configKey + (' (' + (typeof configKey + ')')))); + return { + target: { + type: 'Invocation', + value: element + }, + method: 'integerValueForConfigKey:', + args: [ + { + type: 'NSString', + value: configKey + } + ] + }; + } + + /*If a user-configured value is associated with the given @c configKey, it is returned, otherwise the default value is returned. If a default value is not found, NSInvalidArgumentException is raised. @@ -117,44 +117,44 @@ raised. @return The @c double value for the configuration associated with @c configKey. */ static doubleValueForConfigKey( - element, - configKey - ) { - if (typeof configKey !== 'string') - throw new Error('configKey should be a string, but got ' + (configKey + (' (' + (typeof configKey + ')')))); - return { - target: { - type: 'Invocation', - value: element - }, - method: 'doubleValueForConfigKey:', - args: [ - { - type: 'NSString', - value: configKey - } - ] - }; - } - - /*Resets all configurations to default values, removing all the configured values. + element, + configKey + ) { + if (typeof configKey !== 'string') + throw new Error('configKey should be a string, but got ' + (configKey + (' (' + (typeof configKey + ')')))); + return { + target: { + type: 'Invocation', + value: element + }, + method: 'doubleValueForConfigKey:', + args: [ + { + type: 'NSString', + value: configKey + } + ] + }; + } + + /*Resets all configurations to default values, removing all the configured values. @remark Any default values added by calling GREYConfiguration:setDefaultValue:forConfigKey: are not reset. */ static reset( - element - ) { - return { - target: { - type: 'Invocation', - value: element - }, - method: 'reset', - args: [] - }; - } - - /*Given a value and a key that identifies a configuration, set the value of the configuration. + element + ) { + return { + target: { + type: 'Invocation', + value: element + }, + method: 'reset', + args: [] + }; + } + + /*Given a value and a key that identifies a configuration, set the value of the configuration. Overwrites any previous value for the configuration. @remark To restore original values, call GREYConfiguration::reset. @@ -162,29 +162,29 @@ Overwrites any previous value for the configuration. @param value The configuration value to be set. Scalars should be wrapped in @c NSValue. @param configKey Key identifying an existing or new configuration. Must be a valid @c NSString. */ static setValueForConfigKey( - element, - value, - configKey - ) { - if (typeof configKey !== 'string') - throw new Error('configKey should be a string, but got ' + (configKey + (' (' + (typeof configKey + ')')))); - return { - target: { - type: 'Invocation', - value: element - }, - method: 'setValue:forConfigKey:', - args: [ - value, - { - type: 'NSString', - value: configKey - } - ] - }; - } - - /*Associates configuration identified by @c configKey with the provided @c value. + element, + value, + configKey + ) { + if (typeof configKey !== 'string') + throw new Error('configKey should be a string, but got ' + (configKey + (' (' + (typeof configKey + ')')))); + return { + target: { + type: 'Invocation', + value: element + }, + method: 'setValue:forConfigKey:', + args: [ + value, + { + type: 'NSString', + value: configKey + } + ] + }; + } + + /*Associates configuration identified by @c configKey with the provided @c value. @remark Default values persist even after resetting the configuration (using GREYConfiguration::reset) @@ -192,27 +192,27 @@ Overwrites any previous value for the configuration. @param value The configuration value to be set. Scalars should be wrapped in @c NSValue. @param configKey Key identifying an existing or new configuration. Must be a valid @c NSString. */ static setDefaultValueForConfigKey( - element, - value, - configKey - ) { - if (typeof configKey !== 'string') - throw new Error('configKey should be a string, but got ' + (configKey + (' (' + (typeof configKey + ')')))); - return { - target: { - type: 'Invocation', - value: element - }, - method: 'setDefaultValue:forConfigKey:', - args: [ - value, - { - type: 'NSString', - value: configKey - } - ] - }; - } + element, + value, + configKey + ) { + if (typeof configKey !== 'string') + throw new Error('configKey should be a string, but got ' + (configKey + (' (' + (typeof configKey + ')')))); + return { + target: { + type: 'Invocation', + value: element + }, + method: 'setDefaultValue:forConfigKey:', + args: [ + value, + { + type: 'NSString', + value: configKey + } + ] + }; + } } module.exports = GREYConfiguration; diff --git a/detox/src/ios/earlgreyapi/GREYConfigurationDetox.js b/detox/src/ios/earlgreyapi/GREYConfigurationDetox.js index e6dae5fb65..361ada8585 100644 --- a/detox/src/ios/earlgreyapi/GREYConfigurationDetox.js +++ b/detox/src/ios/earlgreyapi/GREYConfigurationDetox.js @@ -5,27 +5,27 @@ */ class GREYConfiguration { - static enableSynchronization(element) { - return { - target: { - type: 'Invocation', - value: element - }, - method: 'enableSynchronization', - args: [] - }; - } + static enableSynchronization(element) { + return { + target: { + type: 'Invocation', + value: element + }, + method: 'enableSynchronization', + args: [] + }; + } - static disableSynchronization(element) { - return { - target: { - type: 'Invocation', - value: element - }, - method: 'disableSynchronization', - args: [] - }; - } + static disableSynchronization(element) { + return { + target: { + type: 'Invocation', + value: element + }, + method: 'disableSynchronization', + args: [] + }; + } } module.exports = GREYConfiguration; diff --git a/detox/src/ios/earlgreyapi/GREYInteraction.js b/detox/src/ios/earlgreyapi/GREYInteraction.js index a6b3115c2d..9bdf2795b1 100644 --- a/detox/src/ios/earlgreyapi/GREYInteraction.js +++ b/detox/src/ios/earlgreyapi/GREYInteraction.js @@ -5,7 +5,7 @@ */ class GREYInteraction { - /*Indicates that the current interaction should be performed on a UI element contained inside + /*Indicates that the current interaction should be performed on a UI element contained inside another UI element that is uniquely matched by @c rootMatcher. @param rootMatcher Matcher used to select the container of the element the interaction @@ -13,30 +13,30 @@ will be performed on. @return The provided GREYInteraction instance, with an appropriate rootMatcher. */ static inRoot( - element, - rootMatcher - ) { - if ( - typeof rootMatcher !== 'object' || - rootMatcher.type !== 'Invocation' || - typeof rootMatcher.value !== 'object' || - typeof rootMatcher.value.target !== 'object' || - rootMatcher.value.target.value !== 'GREYMatchers' - ) { - throw new Error('rootMatcher should be a GREYMatcher, but got ' + JSON.stringify(rootMatcher)); - } - - return { - target: { - type: 'Invocation', - value: element - }, - method: 'inRoot:', - args: [rootMatcher] - }; - } - - /*Performs the @c action repeatedly on the the element matching the @c matcher until the element + element, + rootMatcher + ) { + if ( + typeof rootMatcher !== 'object' || + rootMatcher.type !== 'Invocation' || + typeof rootMatcher.value !== 'object' || + typeof rootMatcher.value.target !== 'object' || + rootMatcher.value.target.value !== 'GREYMatchers' + ) { + throw new Error('rootMatcher should be a GREYMatcher, but got ' + JSON.stringify(rootMatcher)); + } + + return { + target: { + type: 'Invocation', + value: element + }, + method: 'inRoot:', + args: [rootMatcher] + }; + } + + /*Performs the @c action repeatedly on the the element matching the @c matcher until the element to interact with (specified by GREYInteraction::selectElementWithMatcher:) is found or a timeout occurs. The search action is only performed when coupled with GREYInteraction::performAction:, GREYInteraction::assert:, or @@ -58,100 +58,100 @@ performAction:grey_tap()] // This should be separately called for the action. @return The provided GREYInteraction instance, with an appropriate action and matcher. */ static usingSearchActionOnElementWithMatcher( - element, - action, - matcher - ) { - if ( - typeof action !== 'object' || - action.type !== 'Invocation' || - typeof action.value !== 'object' || - typeof action.value.target !== 'object' || - action.value.target.value !== 'GREYActions' - ) { - throw new Error('action should be a GREYAction, but got ' + JSON.stringify(action)); - } - - if ( - typeof matcher !== 'object' || - matcher.type !== 'Invocation' || - typeof matcher.value !== 'object' || - typeof matcher.value.target !== 'object' || - matcher.value.target.value !== 'GREYMatchers' - ) { - throw new Error('matcher should be a GREYMatcher, but got ' + JSON.stringify(matcher)); - } - - return { - target: { - type: 'Invocation', - value: element - }, - method: 'usingSearchAction:onElementWithMatcher:', - args: [action, matcher] - }; - } - - /*Performs an @c action on the selected UI element. + element, + action, + matcher + ) { + if ( + typeof action !== 'object' || + action.type !== 'Invocation' || + typeof action.value !== 'object' || + typeof action.value.target !== 'object' || + action.value.target.value !== 'GREYActions' + ) { + throw new Error('action should be a GREYAction, but got ' + JSON.stringify(action)); + } + + if ( + typeof matcher !== 'object' || + matcher.type !== 'Invocation' || + typeof matcher.value !== 'object' || + typeof matcher.value.target !== 'object' || + matcher.value.target.value !== 'GREYMatchers' + ) { + throw new Error('matcher should be a GREYMatcher, but got ' + JSON.stringify(matcher)); + } + + return { + target: { + type: 'Invocation', + value: element + }, + method: 'usingSearchAction:onElementWithMatcher:', + args: [action, matcher] + }; + } + + /*Performs an @c action on the selected UI element. @param action The action to be performed on the @c element. @throws NSException if the action fails. @return The provided GREYInteraction instance with an appropriate action. */ static performAction( - element, - action - ) { - if ( - typeof action !== 'object' || - action.type !== 'Invocation' || - typeof action.value !== 'object' || - typeof action.value.target !== 'object' || - action.value.target.value !== 'GREYActions' - ) { - throw new Error('action should be a GREYAction, but got ' + JSON.stringify(action)); - } - - return { - target: { - type: 'Invocation', - value: element - }, - method: 'performAction:', - args: [action] - }; - } - - /*Performs an assertion that evaluates @c matcher on the selected UI element. + element, + action + ) { + if ( + typeof action !== 'object' || + action.type !== 'Invocation' || + typeof action.value !== 'object' || + typeof action.value.target !== 'object' || + action.value.target.value !== 'GREYActions' + ) { + throw new Error('action should be a GREYAction, but got ' + JSON.stringify(action)); + } + + return { + target: { + type: 'Invocation', + value: element + }, + method: 'performAction:', + args: [action] + }; + } + + /*Performs an assertion that evaluates @c matcher on the selected UI element. @param matcher The matcher to be evaluated on the @c element. @return The provided GREYInteraction instance with a matcher to be evaluated on an element. */ static assertWithMatcher( - element, - matcher - ) { - if ( - typeof matcher !== 'object' || - matcher.type !== 'Invocation' || - typeof matcher.value !== 'object' || - typeof matcher.value.target !== 'object' || - matcher.value.target.value !== 'GREYMatchers' - ) { - throw new Error('matcher should be a GREYMatcher, but got ' + JSON.stringify(matcher)); - } - - return { - target: { - type: 'Invocation', - value: element - }, - method: 'assertWithMatcher:', - args: [matcher] - }; - } - - /*In case of multiple matches, selects the element at the specified index. In case of the + element, + matcher + ) { + if ( + typeof matcher !== 'object' || + matcher.type !== 'Invocation' || + typeof matcher.value !== 'object' || + typeof matcher.value.target !== 'object' || + matcher.value.target.value !== 'GREYMatchers' + ) { + throw new Error('matcher should be a GREYMatcher, but got ' + JSON.stringify(matcher)); + } + + return { + target: { + type: 'Invocation', + value: element + }, + method: 'assertWithMatcher:', + args: [matcher] + }; + } + + /*In case of multiple matches, selects the element at the specified index. In case of the index being over the number of matched elements, it throws an exception. Please make sure that this is used after you've created the matcher. For example, in case three elements are matched, and you wish to match with the second one, then @c atIndex would be used in this @@ -168,24 +168,24 @@ to be selected. @return An interaction (assertion or an action) to be performed on the element at the specified index in the list of matched elements. */ static atIndex( - element, - index - ) { - if (typeof index !== 'number') throw new Error('index should be a number, but got ' + (index + (' (' + (typeof index + ')')))); - return { - target: { - type: 'Invocation', - value: element - }, - method: 'atIndex:', - args: [ - { - type: 'NSInteger', - value: index - } - ] - }; - } + element, + index + ) { + if (typeof index !== 'number') throw new Error('index should be a number, but got ' + (index + (' (' + (typeof index + ')')))); + return { + target: { + type: 'Invocation', + value: element + }, + method: 'atIndex:', + args: [ + { + type: 'NSInteger', + value: index + } + ] + }; + } } module.exports = GREYInteraction; diff --git a/detox/src/ios/earlgreyapi/GREYMatchers+Detox.js b/detox/src/ios/earlgreyapi/GREYMatchers+Detox.js index 8eb7fd85c1..f94048420b 100644 --- a/detox/src/ios/earlgreyapi/GREYMatchers+Detox.js +++ b/detox/src/ios/earlgreyapi/GREYMatchers+Detox.js @@ -5,213 +5,213 @@ */ class GREYMatchers { - static detoxMatcherForText(text) { - if (typeof text !== 'string') throw new Error('text should be a string, but got ' + (text + (' (' + (typeof text + ')')))); - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'detoxMatcherForText:', - args: [ - { - type: 'NSString', - value: text - } - ] - }; - } - - static detox_matcherForAccessibilityLabel(label) { - if (typeof label !== 'string') throw new Error('label should be a string, but got ' + (label + (' (' + (typeof label + ')')))); - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'detox_matcherForAccessibilityLabel:', - args: [ - { - type: 'NSString', - value: label - } - ] - }; - } - - static detoxMatcherForScrollChildOfMatcher(matcher) { - if ( - typeof matcher !== 'object' || - matcher.type !== 'Invocation' || - typeof matcher.value !== 'object' || - typeof matcher.value.target !== 'object' || - matcher.value.target.value !== 'GREYMatchers' - ) { - throw new Error('matcher should be a GREYMatcher, but got ' + JSON.stringify(matcher)); - } - - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'detoxMatcherForScrollChildOfMatcher:', - args: [matcher] - }; - } - - static detoxMatcherAvoidingProblematicReactNativeElements(matcher) { - if ( - typeof matcher !== 'object' || - matcher.type !== 'Invocation' || - typeof matcher.value !== 'object' || - typeof matcher.value.target !== 'object' || - matcher.value.target.value !== 'GREYMatchers' - ) { - throw new Error('matcher should be a GREYMatcher, but got ' + JSON.stringify(matcher)); - } - - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'detoxMatcherAvoidingProblematicReactNativeElements:', - args: [matcher] - }; - } - - static detoxMatcherForBothAnd(firstMatcher, secondMatcher) { - if ( - typeof firstMatcher !== 'object' || - firstMatcher.type !== 'Invocation' || - typeof firstMatcher.value !== 'object' || - typeof firstMatcher.value.target !== 'object' || - firstMatcher.value.target.value !== 'GREYMatchers' - ) { - throw new Error('firstMatcher should be a GREYMatcher, but got ' + JSON.stringify(firstMatcher)); - } - - if ( - typeof secondMatcher !== 'object' || - secondMatcher.type !== 'Invocation' || - typeof secondMatcher.value !== 'object' || - typeof secondMatcher.value.target !== 'object' || - secondMatcher.value.target.value !== 'GREYMatchers' - ) { - throw new Error('secondMatcher should be a GREYMatcher, but got ' + JSON.stringify(secondMatcher)); - } - - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'detoxMatcherForBoth:and:', - args: [firstMatcher, secondMatcher] - }; - } - - static detoxMatcherForBothAndAncestorMatcher(firstMatcher, ancestorMatcher) { - if ( - typeof firstMatcher !== 'object' || - firstMatcher.type !== 'Invocation' || - typeof firstMatcher.value !== 'object' || - typeof firstMatcher.value.target !== 'object' || - firstMatcher.value.target.value !== 'GREYMatchers' - ) { - throw new Error('firstMatcher should be a GREYMatcher, but got ' + JSON.stringify(firstMatcher)); - } - - if ( - typeof ancestorMatcher !== 'object' || - ancestorMatcher.type !== 'Invocation' || - typeof ancestorMatcher.value !== 'object' || - typeof ancestorMatcher.value.target !== 'object' || - ancestorMatcher.value.target.value !== 'GREYMatchers' - ) { - throw new Error('ancestorMatcher should be a GREYMatcher, but got ' + JSON.stringify(ancestorMatcher)); - } - - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'detoxMatcherForBoth:andAncestorMatcher:', - args: [firstMatcher, ancestorMatcher] - }; - } - - static detoxMatcherForBothAndDescendantMatcher(firstMatcher, descendantMatcher) { - if ( - typeof firstMatcher !== 'object' || - firstMatcher.type !== 'Invocation' || - typeof firstMatcher.value !== 'object' || - typeof firstMatcher.value.target !== 'object' || - firstMatcher.value.target.value !== 'GREYMatchers' - ) { - throw new Error('firstMatcher should be a GREYMatcher, but got ' + JSON.stringify(firstMatcher)); - } - - if ( - typeof descendantMatcher !== 'object' || - descendantMatcher.type !== 'Invocation' || - typeof descendantMatcher.value !== 'object' || - typeof descendantMatcher.value.target !== 'object' || - descendantMatcher.value.target.value !== 'GREYMatchers' - ) { - throw new Error('descendantMatcher should be a GREYMatcher, but got ' + JSON.stringify(descendantMatcher)); - } - - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'detoxMatcherForBoth:andDescendantMatcher:', - args: [firstMatcher, descendantMatcher] - }; - } - - static detoxMatcherForNot(matcher) { - if ( - typeof matcher !== 'object' || - matcher.type !== 'Invocation' || - typeof matcher.value !== 'object' || - typeof matcher.value.target !== 'object' || - matcher.value.target.value !== 'GREYMatchers' - ) { - throw new Error('matcher should be a GREYMatcher, but got ' + JSON.stringify(matcher)); - } - - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'detoxMatcherForNot:', - args: [matcher] - }; - } - - static detoxMatcherForClass(aClassName) { - if (typeof aClassName !== 'string') - throw new Error('aClassName should be a string, but got ' + (aClassName + (' (' + (typeof aClassName + ')')))); - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'detoxMatcherForClass:', - args: [ - { - type: 'NSString', - value: aClassName - } - ] - }; - } + static detoxMatcherForText(text) { + if (typeof text !== 'string') throw new Error('text should be a string, but got ' + (text + (' (' + (typeof text + ')')))); + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'detoxMatcherForText:', + args: [ + { + type: 'NSString', + value: text + } + ] + }; + } + + static detox_matcherForAccessibilityLabel(label) { + if (typeof label !== 'string') throw new Error('label should be a string, but got ' + (label + (' (' + (typeof label + ')')))); + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'detox_matcherForAccessibilityLabel:', + args: [ + { + type: 'NSString', + value: label + } + ] + }; + } + + static detoxMatcherForScrollChildOfMatcher(matcher) { + if ( + typeof matcher !== 'object' || + matcher.type !== 'Invocation' || + typeof matcher.value !== 'object' || + typeof matcher.value.target !== 'object' || + matcher.value.target.value !== 'GREYMatchers' + ) { + throw new Error('matcher should be a GREYMatcher, but got ' + JSON.stringify(matcher)); + } + + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'detoxMatcherForScrollChildOfMatcher:', + args: [matcher] + }; + } + + static detoxMatcherAvoidingProblematicReactNativeElements(matcher) { + if ( + typeof matcher !== 'object' || + matcher.type !== 'Invocation' || + typeof matcher.value !== 'object' || + typeof matcher.value.target !== 'object' || + matcher.value.target.value !== 'GREYMatchers' + ) { + throw new Error('matcher should be a GREYMatcher, but got ' + JSON.stringify(matcher)); + } + + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'detoxMatcherAvoidingProblematicReactNativeElements:', + args: [matcher] + }; + } + + static detoxMatcherForBothAnd(firstMatcher, secondMatcher) { + if ( + typeof firstMatcher !== 'object' || + firstMatcher.type !== 'Invocation' || + typeof firstMatcher.value !== 'object' || + typeof firstMatcher.value.target !== 'object' || + firstMatcher.value.target.value !== 'GREYMatchers' + ) { + throw new Error('firstMatcher should be a GREYMatcher, but got ' + JSON.stringify(firstMatcher)); + } + + if ( + typeof secondMatcher !== 'object' || + secondMatcher.type !== 'Invocation' || + typeof secondMatcher.value !== 'object' || + typeof secondMatcher.value.target !== 'object' || + secondMatcher.value.target.value !== 'GREYMatchers' + ) { + throw new Error('secondMatcher should be a GREYMatcher, but got ' + JSON.stringify(secondMatcher)); + } + + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'detoxMatcherForBoth:and:', + args: [firstMatcher, secondMatcher] + }; + } + + static detoxMatcherForBothAndAncestorMatcher(firstMatcher, ancestorMatcher) { + if ( + typeof firstMatcher !== 'object' || + firstMatcher.type !== 'Invocation' || + typeof firstMatcher.value !== 'object' || + typeof firstMatcher.value.target !== 'object' || + firstMatcher.value.target.value !== 'GREYMatchers' + ) { + throw new Error('firstMatcher should be a GREYMatcher, but got ' + JSON.stringify(firstMatcher)); + } + + if ( + typeof ancestorMatcher !== 'object' || + ancestorMatcher.type !== 'Invocation' || + typeof ancestorMatcher.value !== 'object' || + typeof ancestorMatcher.value.target !== 'object' || + ancestorMatcher.value.target.value !== 'GREYMatchers' + ) { + throw new Error('ancestorMatcher should be a GREYMatcher, but got ' + JSON.stringify(ancestorMatcher)); + } + + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'detoxMatcherForBoth:andAncestorMatcher:', + args: [firstMatcher, ancestorMatcher] + }; + } + + static detoxMatcherForBothAndDescendantMatcher(firstMatcher, descendantMatcher) { + if ( + typeof firstMatcher !== 'object' || + firstMatcher.type !== 'Invocation' || + typeof firstMatcher.value !== 'object' || + typeof firstMatcher.value.target !== 'object' || + firstMatcher.value.target.value !== 'GREYMatchers' + ) { + throw new Error('firstMatcher should be a GREYMatcher, but got ' + JSON.stringify(firstMatcher)); + } + + if ( + typeof descendantMatcher !== 'object' || + descendantMatcher.type !== 'Invocation' || + typeof descendantMatcher.value !== 'object' || + typeof descendantMatcher.value.target !== 'object' || + descendantMatcher.value.target.value !== 'GREYMatchers' + ) { + throw new Error('descendantMatcher should be a GREYMatcher, but got ' + JSON.stringify(descendantMatcher)); + } + + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'detoxMatcherForBoth:andDescendantMatcher:', + args: [firstMatcher, descendantMatcher] + }; + } + + static detoxMatcherForNot(matcher) { + if ( + typeof matcher !== 'object' || + matcher.type !== 'Invocation' || + typeof matcher.value !== 'object' || + typeof matcher.value.target !== 'object' || + matcher.value.target.value !== 'GREYMatchers' + ) { + throw new Error('matcher should be a GREYMatcher, but got ' + JSON.stringify(matcher)); + } + + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'detoxMatcherForNot:', + args: [matcher] + }; + } + + static detoxMatcherForClass(aClassName) { + if (typeof aClassName !== 'string') + throw new Error('aClassName should be a string, but got ' + (aClassName + (' (' + (typeof aClassName + ')')))); + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'detoxMatcherForClass:', + args: [ + { + type: 'NSString', + value: aClassName + } + ] + }; + } } module.exports = GREYMatchers; diff --git a/detox/src/ios/earlgreyapi/GREYMatchers.js b/detox/src/ios/earlgreyapi/GREYMatchers.js index d52af4b301..c51f3d191f 100644 --- a/detox/src/ios/earlgreyapi/GREYMatchers.js +++ b/detox/src/ios/earlgreyapi/GREYMatchers.js @@ -5,289 +5,289 @@ */ function sanitize_uiAccessibilityTraits(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` - ); - } - } - - return 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; } function sanitize_greyContentEdge(action) { - switch (action) { - case 'left': - return 0; - case 'right': - return 1; - case 'top': - return 2; - case 'bottom': - return 3; - - default: - throw new Error(`GREYAction.GREYContentEdge must be a 'left'/'right'/'top'/'bottom', got ${action}`); - } + switch (action) { + case 'left': + return 0; + case 'right': + return 1; + case 'top': + return 2; + case 'bottom': + return 3; + + default: + throw new Error(`GREYAction.GREYContentEdge must be a 'left'/'right'/'top'/'bottom', got ${action}`); + } } class GREYMatchers { - /*Matcher for application's key window. + /*Matcher for application's key window. @return A matcher for the application's key window. */ static matcherForKeyWindow() { - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForKeyWindow', - args: [] - }; - } - - /*Matcher for UI element with the provided accessibility @c label. + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForKeyWindow', + args: [] + }; + } + + /*Matcher for UI element with the provided accessibility @c label. @param label The accessibility label to be matched. @return A matcher for the accessibility label of an accessible element. */ static matcherForAccessibilityLabel( - label - ) { - if (typeof label !== 'string') throw new Error('label should be a string, but got ' + (label + (' (' + (typeof label + ')')))); - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForAccessibilityLabel:', - args: [ - { - type: 'NSString', - value: label - } - ] - }; - } - - /*Matcher for UI element with the provided accessibility ID @c accessibilityID. + label + ) { + if (typeof label !== 'string') throw new Error('label should be a string, but got ' + (label + (' (' + (typeof label + ')')))); + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForAccessibilityLabel:', + args: [ + { + type: 'NSString', + value: label + } + ] + }; + } + + /*Matcher for UI element with the provided accessibility ID @c accessibilityID. @param accessibilityID The accessibility ID to be matched. @return A matcher for the accessibility ID of an accessible element. */ static matcherForAccessibilityID( - accessibilityID - ) { - if (typeof accessibilityID !== 'string') - throw new Error('accessibilityID should be a string, but got ' + (accessibilityID + (' (' + (typeof accessibilityID + ')')))); - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForAccessibilityID:', - args: [ - { - type: 'NSString', - value: accessibilityID - } - ] - }; - } - - /*Matcher for UI element with the provided accessibility @c value. + accessibilityID + ) { + if (typeof accessibilityID !== 'string') + throw new Error('accessibilityID should be a string, but got ' + (accessibilityID + (' (' + (typeof accessibilityID + ')')))); + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForAccessibilityID:', + args: [ + { + type: 'NSString', + value: accessibilityID + } + ] + }; + } + + /*Matcher for UI element with the provided accessibility @c value. @param value The accessibility value to be matched. @return A matcher for the accessibility value of an accessible element. */ static matcherForAccessibilityValue( - value - ) { - if (typeof value !== 'string') throw new Error('value should be a string, but got ' + (value + (' (' + (typeof value + ')')))); - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForAccessibilityValue:', - args: [ - { - type: 'NSString', - value: value - } - ] - }; - } - - /*Matcher for UI element with the provided accessibility @c traits. + value + ) { + if (typeof value !== 'string') throw new Error('value should be a string, but got ' + (value + (' (' + (typeof value + ')')))); + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForAccessibilityValue:', + args: [ + { + type: 'NSString', + value: value + } + ] + }; + } + + /*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('traits 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. + traits + ) { + if (typeof traits !== 'object' || !traits instanceof Array) { + throw new Error('traits 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. @return A matcher for the accessibility hint of an accessible element. */ static matcherForAccessibilityHint( - hint - ) { - if (typeof hint !== 'string') throw new Error('hint should be a string, but got ' + (hint + (' (' + (typeof hint + ')')))); - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForAccessibilityHint:', - args: [ - { - type: 'NSString', - value: hint - } - ] - }; - } - - /*Matcher for UI element with accessiblity focus. + hint + ) { + if (typeof hint !== 'string') throw new Error('hint should be a string, but got ' + (hint + (' (' + (typeof hint + ')')))); + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForAccessibilityHint:', + args: [ + { + type: 'NSString', + value: hint + } + ] + }; + } + + /*Matcher for UI element with accessiblity focus. @return A matcher for the accessibility focus of an accessible element. */ static matcherForAccessibilityElementIsFocused() { - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForAccessibilityElementIsFocused', - args: [] - }; - } - - /*Matcher for UI elements of type UIButton, UILabel, UITextField or UITextView displaying the + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForAccessibilityElementIsFocused', + args: [] + }; + } + + /*Matcher for UI elements of type UIButton, UILabel, UITextField or UITextView displaying the provided @c inputText. @param text The text to be matched in the UI elements. @return A matcher to check for any UI elements with a text field containing the given text. */ static matcherForText( - text - ) { - if (typeof text !== 'string') throw new Error('text should be a string, but got ' + (text + (' (' + (typeof text + ')')))); - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForText:', - args: [ - { - type: 'NSString', - value: text - } - ] - }; - } - - /*Matcher for element that is the first responder. + text + ) { + if (typeof text !== 'string') throw new Error('text should be a string, but got ' + (text + (' (' + (typeof text + ')')))); + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForText:', + args: [ + { + type: 'NSString', + value: text + } + ] + }; + } + + /*Matcher for element that is the first responder. @return A matcher that verifies if a UI element is the first responder. */ static matcherForFirstResponder() { - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForFirstResponder', - args: [] - }; - } - - /*Matcher to check if system alert view is shown. + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForFirstResponder', + args: [] + }; + } + + /*Matcher to check if system alert view is shown. @return A matcher to check if a system alert view is being shown. */ static matcherForSystemAlertViewShown() { - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForSystemAlertViewShown', - args: [] - }; - } - - /*Matcher for UI element whose percent visible area (of its accessibility frame) exceeds the + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForSystemAlertViewShown', + args: [] + }; + } + + /*Matcher for UI element whose percent visible area (of its accessibility frame) exceeds the given @c percent. @param percent The percent visible area that the UI element being matched has to be visible. @@ -296,56 +296,56 @@ Allowed values for @c percent are [0,1] inclusive. @return A matcher that checks if a UI element has a visible area at least equal to a minimum value. */ static matcherForMinimumVisiblePercent( - percent - ) { - if (typeof percent !== 'number') throw new Error('percent should be a number, but got ' + (percent + (' (' + (typeof percent + ')')))); - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForMinimumVisiblePercent:', - args: [ - { - type: 'CGFloat', - value: percent - } - ] - }; - } - - /*Matcher for UI element that is sufficiently visible to the user. EarlGrey considers elements + percent + ) { + if (typeof percent !== 'number') throw new Error('percent should be a number, but got ' + (percent + (' (' + (typeof percent + ')')))); + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForMinimumVisiblePercent:', + args: [ + { + type: 'CGFloat', + value: percent + } + ] + }; + } + + /*Matcher for UI element that is sufficiently visible to the user. EarlGrey considers elements that are more than @c kElementSufficientlyVisiblePercentage (75 %) visible areawise to be sufficiently visible. @return A matcher intialized with a visibility percentage that confirms an element is sufficiently visible. */ static matcherForSufficientlyVisible() { - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForSufficientlyVisible', - args: [] - }; - } - - /*Matcher for UI element that is not visible to the user at all i.e. it has a zero visible area. + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForSufficientlyVisible', + args: [] + }; + } + + /*Matcher for UI element that is not visible to the user at all i.e. it has a zero visible area. @return A matcher for verifying if an element is not visible. */ static matcherForNotVisible() { - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForNotVisible', - args: [] - }; - } - - /*Matcher for UI element that matches EarlGrey's criteria for user interaction. Currently it must + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForNotVisible', + args: [] + }; + } + + /*Matcher for UI element that matches EarlGrey's criteria for user interaction. Currently it must satisfy at least the following criteria: 1) At least a few pixels of the element are visible to the user. 2) The element's accessibility activation point OR the center of the element's visible area @@ -353,31 +353,31 @@ is completely visible. @return A matcher that checks if a UI element is interactable. */ static matcherForInteractable() { - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForInteractable', - args: [] - }; - } - - /*Matcher to check if a UI element is accessible. + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForInteractable', + args: [] + }; + } + + /*Matcher to check if a UI element is accessible. @return A matcher that checks if a UI element is accessible. */ static matcherForAccessibilityElement() { - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForAccessibilityElement', - args: [] - }; - } - - /*Matcher for matching UIProgressView's values. Use greaterThan, greaterThanOrEqualTo, + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForAccessibilityElement', + args: [] + }; + } + + /*Matcher for matching UIProgressView's values. Use greaterThan, greaterThanOrEqualTo, lessThan etc to create @c comparisonMatcher. For example, to match the UIProgressView elements that have progress value greater than 50.2, use @code [GREYMatchers matcherForProgress:grey_greaterThan(@(50.2))] @endcode. In case if an @@ -387,140 +387,140 @@ unimplemented matcher is required, please implement it similar to @c grey_closeT @return A matcher for checking a UIProgessView's value. */ static matcherForProgress( - comparisonMatcher - ) { - if ( - typeof comparisonMatcher !== 'object' || - comparisonMatcher.type !== 'Invocation' || - typeof comparisonMatcher.value !== 'object' || - typeof comparisonMatcher.value.target !== 'object' || - comparisonMatcher.value.target.value !== 'GREYMatchers' - ) { - throw new Error('comparisonMatcher should be a GREYMatcher, but got ' + JSON.stringify(comparisonMatcher)); - } - - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForProgress:', - args: [comparisonMatcher] - }; - } - - /*Matcher that matches UI element based on the presence of an ancestor in its hierarchy. + comparisonMatcher + ) { + if ( + typeof comparisonMatcher !== 'object' || + comparisonMatcher.type !== 'Invocation' || + typeof comparisonMatcher.value !== 'object' || + typeof comparisonMatcher.value.target !== 'object' || + comparisonMatcher.value.target.value !== 'GREYMatchers' + ) { + throw new Error('comparisonMatcher should be a GREYMatcher, but got ' + JSON.stringify(comparisonMatcher)); + } + + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForProgress:', + args: [comparisonMatcher] + }; + } + + /*Matcher that matches UI element based on the presence of an ancestor in its hierarchy. The given matcher is used to match decendants. @param ancestorMatcher The ancestor UI element whose descendants are to be matched. @return A matcher to check if a UI element is the descendant of another. */ static matcherForAncestor( - ancestorMatcher - ) { - if ( - typeof ancestorMatcher !== 'object' || - ancestorMatcher.type !== 'Invocation' || - typeof ancestorMatcher.value !== 'object' || - typeof ancestorMatcher.value.target !== 'object' || - ancestorMatcher.value.target.value !== 'GREYMatchers' - ) { - throw new Error('ancestorMatcher should be a GREYMatcher, but got ' + JSON.stringify(ancestorMatcher)); - } - - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForAncestor:', - args: [ancestorMatcher] - }; - } - - /*Matcher that matches any UI element with a descendant matching the given matcher. + ancestorMatcher + ) { + if ( + typeof ancestorMatcher !== 'object' || + ancestorMatcher.type !== 'Invocation' || + typeof ancestorMatcher.value !== 'object' || + typeof ancestorMatcher.value.target !== 'object' || + ancestorMatcher.value.target.value !== 'GREYMatchers' + ) { + throw new Error('ancestorMatcher should be a GREYMatcher, but got ' + JSON.stringify(ancestorMatcher)); + } + + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForAncestor:', + args: [ancestorMatcher] + }; + } + + /*Matcher that matches any UI element with a descendant matching the given matcher. @param descendantMatcher A matcher being checked to be a descendant of the UI element being checked. @return A matcher to check if a the specified element is in a descendant of another UI element. */ static matcherForDescendant( - descendantMatcher - ) { - if ( - typeof descendantMatcher !== 'object' || - descendantMatcher.type !== 'Invocation' || - typeof descendantMatcher.value !== 'object' || - typeof descendantMatcher.value.target !== 'object' || - descendantMatcher.value.target.value !== 'GREYMatchers' - ) { - throw new Error('descendantMatcher should be a GREYMatcher, but got ' + JSON.stringify(descendantMatcher)); - } - - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForDescendant:', - args: [descendantMatcher] - }; - } - - /*Matcher that matches UIButton that has title label as @c text. + descendantMatcher + ) { + if ( + typeof descendantMatcher !== 'object' || + descendantMatcher.type !== 'Invocation' || + typeof descendantMatcher.value !== 'object' || + typeof descendantMatcher.value.target !== 'object' || + descendantMatcher.value.target.value !== 'GREYMatchers' + ) { + throw new Error('descendantMatcher should be a GREYMatcher, but got ' + JSON.stringify(descendantMatcher)); + } + + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForDescendant:', + args: [descendantMatcher] + }; + } + + /*Matcher that matches UIButton that has title label as @c text. @param title The title to be checked on the UIButtons being matched. @return A matcher to confirm UIButton titles. */ static matcherForButtonTitle( - title - ) { - if (typeof title !== 'string') throw new Error('title should be a string, but got ' + (title + (' (' + (typeof title + ')')))); - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForButtonTitle:', - args: [ - { - type: 'NSString', - value: title - } - ] - }; - } - - /*Matcher that matches UIScrollView that has contentOffset as @c offset. + title + ) { + if (typeof title !== 'string') throw new Error('title should be a string, but got ' + (title + (' (' + (typeof title + ')')))); + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForButtonTitle:', + args: [ + { + type: 'NSString', + value: title + } + ] + }; + } + + /*Matcher that matches UIScrollView that has contentOffset as @c offset. @param offset The content offset to be checked on the UIScrollView being matched. @return A matcher to confirm UIScrollView content offset. */ static matcherForScrollViewContentOffset( - offset - ) { - if (typeof offset !== 'object') throw new Error('offset should be a object, but got ' + (offset + (' (' + (typeof offset + ')')))); - if (typeof offset.x !== 'number') - throw new Error('offset.x should be a number, but got ' + (offset.x + (' (' + (typeof offset.x + ')')))); - if (typeof offset.y !== 'number') - throw new Error('offset.y should be a number, but got ' + (offset.y + (' (' + (typeof offset.y + ')')))); - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForScrollViewContentOffset:', - args: [ - { - type: 'CGPoint', - value: offset - } - ] - }; - } - - /*Matcher that matches a UISlider's value. + offset + ) { + if (typeof offset !== 'object') throw new Error('offset should be a object, but got ' + (offset + (' (' + (typeof offset + ')')))); + if (typeof offset.x !== 'number') + throw new Error('offset.x should be a number, but got ' + (offset.x + (' (' + (typeof offset.x + ')')))); + if (typeof offset.y !== 'number') + throw new Error('offset.y should be a number, but got ' + (offset.y + (' (' + (typeof offset.y + ')')))); + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForScrollViewContentOffset:', + args: [ + { + type: 'CGPoint', + value: offset + } + ] + }; + } + + /*Matcher that matches a UISlider's value. @param valueMatcher A matcher for the UISlider's value. You must provide a valid @c valueMatcher for the floating point value comparison. The @@ -533,144 +533,144 @@ is required, please implement it similar to @c grey_closeTo. @return A matcher for checking a UISlider's value. */ static matcherForSliderValueMatcher( - valueMatcher - ) { - if ( - typeof valueMatcher !== 'object' || - valueMatcher.type !== 'Invocation' || - typeof valueMatcher.value !== 'object' || - typeof valueMatcher.value.target !== 'object' || - valueMatcher.value.target.value !== 'GREYMatchers' - ) { - throw new Error('valueMatcher should be a GREYMatcher, but got ' + JSON.stringify(valueMatcher)); - } - - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForSliderValueMatcher:', - args: [valueMatcher] - }; - } - - /*Matcher that matches UIPickerView that has a column set to @c value. + valueMatcher + ) { + if ( + typeof valueMatcher !== 'object' || + valueMatcher.type !== 'Invocation' || + typeof valueMatcher.value !== 'object' || + typeof valueMatcher.value.target !== 'object' || + valueMatcher.value.target.value !== 'GREYMatchers' + ) { + throw new Error('valueMatcher should be a GREYMatcher, but got ' + JSON.stringify(valueMatcher)); + } + + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForSliderValueMatcher:', + args: [valueMatcher] + }; + } + + /*Matcher that matches UIPickerView that has a column set to @c value. @param column The column of the UIPickerView to be matched. @param value The value that should be set in the column of the UIPickerView. @return A matcher to check the value in a particular column of a UIPickerView. */ static matcherForPickerColumnSetToValue( - column, - value - ) { - if (typeof column !== 'number') throw new Error('column should be a number, but got ' + (column + (' (' + (typeof column + ')')))); - if (typeof value !== 'string') throw new Error('value should be a string, but got ' + (value + (' (' + (typeof value + ')')))); - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForPickerColumn:setToValue:', - args: [ - { - type: 'NSInteger', - value: column - }, - { - type: 'NSString', - value: value - } - ] - }; - } - - /*Matcher that verifies whether an element, that is a UIControl, is enabled. + column, + value + ) { + if (typeof column !== 'number') throw new Error('column should be a number, but got ' + (column + (' (' + (typeof column + ')')))); + if (typeof value !== 'string') throw new Error('value should be a string, but got ' + (value + (' (' + (typeof value + ')')))); + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForPickerColumn:setToValue:', + args: [ + { + type: 'NSInteger', + value: column + }, + { + type: 'NSString', + value: value + } + ] + }; + } + + /*Matcher that verifies whether an element, that is a UIControl, is enabled. @return A matcher for checking whether a UI element is an enabled UIControl. */ static matcherForEnabledElement() { - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForEnabledElement', - args: [] - }; - } - - /*Matcher that verifies whether an element, that is a UIControl, is selected. + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForEnabledElement', + args: [] + }; + } + + /*Matcher that verifies whether an element, that is a UIControl, is selected. @return A matcher for checking whether a UI element is a selected UIControl. */ static matcherForSelectedElement() { - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForSelectedElement', - args: [] - }; - } - - /*Matcher that verifies whether a view has its userInteractionEnabled property set to @c YES. + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForSelectedElement', + args: [] + }; + } + + /*Matcher that verifies whether a view has its userInteractionEnabled property set to @c YES. @return A matcher for checking whether a view' userInteractionEnabled property is set to @c YES. */ static matcherForUserInteractionEnabled() { - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForUserInteractionEnabled', - args: [] - }; - } - - /*Matcher primarily for asserting that the element is @c nil or not found. + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForUserInteractionEnabled', + args: [] + }; + } + + /*Matcher primarily for asserting that the element is @c nil or not found. @return A matcher to check if a specified element is @c nil or not found. */ static matcherForNil() { - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForNil', - args: [] - }; - } - - /*Matcher for asserting that the element exists in the UI hierarchy (i.e. not @c nil). + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForNil', + args: [] + }; + } + + /*Matcher for asserting that the element exists in the UI hierarchy (i.e. not @c nil). @return A matcher to check if a specified element is not @c nil. */ static matcherForNotNil() { - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForNotNil', - args: [] - }; - } - - /*A Matcher that matches against any object, including @c nils. + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForNotNil', + args: [] + }; + } + + /*A Matcher that matches against any object, including @c nils. @return A matcher that matches any object. */ static matcherForAnything() { - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForAnything', - args: [] - }; - } - - /*A Matcher that checks if a provided object is equal to the specified @c value. The equality is + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForAnything', + args: [] + }; + } + + /*A Matcher that checks if a provided object is equal to the specified @c value. The equality is determined by calling the @c isEqual: method of the object being examined. In case the @c value is @c nil, then the object itself is checked to be @c nil. @@ -679,19 +679,19 @@ passed in as boxed (object) values. @return A matcher that checks if an object is equal to the provided one. */ static matcherForEqualTo( - value - ) { - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForEqualTo:', - args: [value] - }; - } - - /*A Matcher that checks if a provided object is less than a specified @c value. The comparison + value + ) { + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForEqualTo:', + args: [value] + }; + } + + /*A Matcher that checks if a provided object is less than a specified @c value. The comparison is made by calling the @c compare: method of the object being examined. @param value The value to be compared, which should return @c NSOrderedDescending. Please @@ -699,19 +699,19 @@ ensure that scalar values are passed in as boxed (object) values. @return A matcher that checks an object is lesser than another provided @c value. */ static matcherForLessThan( - value - ) { - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForLessThan:', - args: [value] - }; - } - - /*A Matcher that checks if a provided object is greater than a specified @c value. The comparison + value + ) { + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForLessThan:', + args: [value] + }; + } + + /*A Matcher that checks if a provided object is greater than a specified @c value. The comparison is made by calling the @c compare: method of the object being examined. @param value The value to be compared, which should return @c NSOrderedAscending. Please @@ -719,66 +719,66 @@ ensure that scalar values are passed in as boxed (object) values. @return A matcher that checks an object is greater than another provided @c value. */ static matcherForGreaterThan( - value - ) { - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForGreaterThan:', - args: [value] - }; - } - - /*Matcher that matches a UIScrollView scrolled to content @c edge. + value + ) { + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForGreaterThan:', + args: [value] + }; + } + + /*Matcher that matches a UIScrollView scrolled to content @c edge. @param edge The content edge UIScrollView should be scrolled to. @return A matcher that matches a UIScrollView scrolled to content @c edge. */ static matcherForScrolledToContentEdge( - edge - ) { - if (!['left', 'right', 'top', 'bottom'].some((option) => option === edge)) - throw new Error('edge should be one of [left, right, top, bottom], but got ' + edge); - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForScrolledToContentEdge:', - args: [ - { - type: 'NSInteger', - value: sanitize_greyContentEdge(edge) - } - ] - }; - } - - /*Matcher that matches a UITextField's content. + edge + ) { + if (!['left', 'right', 'top', 'bottom'].some((option) => option === edge)) + throw new Error('edge should be one of [left, right, top, bottom], but got ' + edge); + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForScrolledToContentEdge:', + args: [ + { + type: 'NSInteger', + value: sanitize_greyContentEdge(edge) + } + ] + }; + } + + /*Matcher that matches a UITextField's content. @param value The text string contained inside the UITextField. @return A matcher that matches the value inside a UITextField. */ static matcherForTextFieldValue( - value - ) { - if (typeof value !== 'string') throw new Error('value should be a string, but got ' + (value + (' (' + (typeof value + ')')))); - return { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForTextFieldValue:', - args: [ - { - type: 'NSString', - value: value - } - ] - }; - } + value + ) { + if (typeof value !== 'string') throw new Error('value should be a string, but got ' + (value + (' (' + (typeof value + ')')))); + return { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForTextFieldValue:', + args: [ + { + type: 'NSString', + value: value + } + ] + }; + } } module.exports = GREYMatchers; diff --git a/generation/__tests__/android.js b/generation/__tests__/android.js index d87d335cea..44fbb519e8 100644 --- a/generation/__tests__/android.js +++ b/generation/__tests__/android.js @@ -3,99 +3,99 @@ const remove = require('remove'); const androidGenerator = require('../adapters/android'); describe('Android generation', () => { - let ExampleClass; - let exampleContent; - beforeAll(() => { - // Generate the code to test - fs.mkdirSync('./__tests__/generated-android'); - - const files = { - './fixtures/example.java': './__tests__/generated-android/example.js' - }; - - console.log('==> generating android files'); - androidGenerator(files); - - console.log('==> loading android files'); - // Load - ExampleClass = require('./generated-android/example.js'); - exampleContent = fs.readFileSync('./__tests__/generated-android/example.js', 'utf8'); - }); - - afterAll(() => { - // Clean up - remove.removeSync('./__tests__/generated-android'); - }); - - describe('methods', () => { - it('should expose the functions', () => { - expect(ExampleClass.multiClick).toBeInstanceOf(Function); - }); - - it('should generate type checks', () => { - expect(() => { - ExampleClass.multiClick('FOO'); - }).toThrowErrorMatchingSnapshot(); - }); - - it('should return adapter calls', () => { - const result = ExampleClass.multiClick(3); - expect(result.method).toBe('multiClick'); - expect(result.target.value).toBe('com.wix.detox.espresso.DetoxAction'); - expect(result.args[0].type).toBe('Integer'); - expect(result.args[0].value).toBe(3); - - expect(result).toMatchSnapshot(); - }); - - it('should add a sanitizer for the function with the correct name', () => { - const fn = ExampleClass.scrollInDirection; - - expect(() => { - fn(3, 42); - }).toThrowError(); - - expect(() => { - fn('down', 42); - }).not.toThrowError(); - - expect(fn('down', 42)).toMatchSnapshot(); - }); - }); - - describe('validation', () => { - describe('Matcher', () => { - it('should fail getting no object', () => { - expect(() => { - ExampleClass.matcherForAnd('I am a string', 'I am one too'); - }).toThrowErrorMatchingSnapshot(); - }); - - it('should fail with a wrong class', () => { - class AnotherClass {} - const x = new AnotherClass(); - - expect(() => { - ExampleClass.matcherForAnd(x, x); - }).toThrowErrorMatchingSnapshot(); - }); - - it("should succeed with the 'right' class", () => { - // stub for matcher class - class Matcher { - _call() { - return { - target: { type: 'Class', value: 'Detox.Matcher' }, - method: 'matchNicely' - }; - } - } - - const m = new Matcher(); - expect(() => { - ExampleClass.matcherForAnd(m, m); - }).not.toThrow(); - }); - }); - }); + let ExampleClass; + let exampleContent; + beforeAll(() => { + // Generate the code to test + fs.mkdirSync('./__tests__/generated-android'); + + const files = { + './fixtures/example.java': './__tests__/generated-android/example.js' + }; + + console.log('==> generating android files'); + androidGenerator(files); + + console.log('==> loading android files'); + // Load + ExampleClass = require('./generated-android/example.js'); + exampleContent = fs.readFileSync('./__tests__/generated-android/example.js', 'utf8'); + }); + + afterAll(() => { + // Clean up + remove.removeSync('./__tests__/generated-android'); + }); + + describe('methods', () => { + it('should expose the functions', () => { + expect(ExampleClass.multiClick).toBeInstanceOf(Function); + }); + + it('should generate type checks', () => { + expect(() => { + ExampleClass.multiClick('FOO'); + }).toThrowErrorMatchingSnapshot(); + }); + + it('should return adapter calls', () => { + const result = ExampleClass.multiClick(3); + expect(result.method).toBe('multiClick'); + expect(result.target.value).toBe('com.wix.detox.espresso.DetoxAction'); + expect(result.args[0].type).toBe('Integer'); + expect(result.args[0].value).toBe(3); + + expect(result).toMatchSnapshot(); + }); + + it('should add a sanitizer for the function with the correct name', () => { + const fn = ExampleClass.scrollInDirection; + + expect(() => { + fn(3, 42); + }).toThrowError(); + + expect(() => { + fn('down', 42); + }).not.toThrowError(); + + expect(fn('down', 42)).toMatchSnapshot(); + }); + }); + + describe('validation', () => { + describe('Matcher', () => { + it('should fail getting no object', () => { + expect(() => { + ExampleClass.matcherForAnd('I am a string', 'I am one too'); + }).toThrowErrorMatchingSnapshot(); + }); + + it('should fail with a wrong class', () => { + class AnotherClass {} + const x = new AnotherClass(); + + expect(() => { + ExampleClass.matcherForAnd(x, x); + }).toThrowErrorMatchingSnapshot(); + }); + + it("should succeed with the 'right' class", () => { + // stub for matcher class + class Matcher { + _call() { + return { + target: { type: 'Class', value: 'Detox.Matcher' }, + method: 'matchNicely' + }; + } + } + + const m = new Matcher(); + expect(() => { + ExampleClass.matcherForAnd(m, m); + }).not.toThrow(); + }); + }); + }); }); diff --git a/generation/__tests__/global-functions.js b/generation/__tests__/global-functions.js index edd6131aaa..30e25b870d 100644 --- a/generation/__tests__/global-functions.js +++ b/generation/__tests__/global-functions.js @@ -1,137 +1,137 @@ const globals = require('../core/global-functions'); describe('globals', () => { - describe('sanitize_android_direction', () => { - it('should return numbers for strings', () => { - expect(globals.sanitize_android_direction('left')).toBe(1); - expect(globals.sanitize_android_direction('right')).toBe(2); - expect(globals.sanitize_android_direction('up')).toBe(3); - expect(globals.sanitize_android_direction('down')).toBe(4); - }); - - it('should fail with unknown value', () => { - expect(() => { - globals.sanitize_android_direction('kittens'); - }).toThrowErrorMatchingSnapshot(); - }); - }); - - describe('sanitize_android_edge', () => { - it('should return numbers for strings', () => { - expect(globals.sanitize_android_edge('left')).toBe(1); - expect(globals.sanitize_android_edge('right')).toBe(2); - expect(globals.sanitize_android_edge('top')).toBe(3); - expect(globals.sanitize_android_edge('bottom')).toBe(4); - }); - - it('should fail with unknown value', () => { - expect(() => { - globals.sanitize_android_edge('kittens'); - }).toThrowErrorMatchingSnapshot(); - }); - }); - - describe('sanitize_greyDirection', () => { - it('should return numbers for strings', () => { - expect(globals.sanitize_greyDirection('left')).toBe(1); - expect(globals.sanitize_greyDirection('right')).toBe(2); - expect(globals.sanitize_greyDirection('up')).toBe(3); - expect(globals.sanitize_greyDirection('down')).toBe(4); - }); - - it('should fail with unknown value', () => { - expect(() => { - globals.sanitize_greyDirection('kittens'); - }).toThrowErrorMatchingSnapshot(); - }); - }); - - describe('sanitize_greyContentEdge', () => { - it('should return numbers for strings', () => { - expect(globals.sanitize_greyContentEdge('left')).toBe(0); - expect(globals.sanitize_greyContentEdge('right')).toBe(1); - expect(globals.sanitize_greyContentEdge('top')).toBe(2); - expect(globals.sanitize_greyContentEdge('bottom')).toBe(3); - }); - - it('should fail with unknown value', () => { - expect(() => { - globals.sanitize_greyContentEdge('kittens'); - }).toThrowErrorMatchingSnapshot(); - }); - }); - - describe('sanitize_uiAccessibilityTraits', () => { - it('should return numbers for traits', () => { - expect(globals.sanitize_uiAccessibilityTraits(['button'])).toBe(1); - - [ - 'button', - 'link', - 'header', - 'search', - 'image', - 'selected', - 'plays', - 'key', - 'text', - 'summary', - 'disabled', - 'frequentUpdates', - 'startsMedia', - 'adjustable', - 'allowsDirectInteraction', - 'pageTurn' - ].forEach((trait) => { - expect(typeof globals.sanitize_uiAccessibilityTraits([trait])).toBe('number'); - }); - }); - it('should combine the traits', () => { - expect(globals.sanitize_uiAccessibilityTraits(['summary', 'allowsDirectInteraction'])).toBe(16896); - }); - - it('should throw if unknown trait is accessed', () => { - expect(() => globals.sanitize_uiAccessibilityTraits(['unknown'])).toThrowErrorMatchingSnapshot(); - }); - }); - - const matcherInvocation = { - target: { type: 'Class', value: 'Detox.Matcher' }, - method: 'matchNicely' - }; - describe('sanitize_matcher', () => { - it("should return the object if it's no function", () => { - expect(globals.sanitize_matcher({ _call: matcherInvocation })).toEqual(matcherInvocation); - }); - - it("should return the ._call property if it's a function", () => { - const matcherLikeObj = { _call: () => matcherInvocation }; - expect(globals.sanitize_matcher(matcherLikeObj)).toEqual(matcherInvocation); - }); - - it("should unwrap the object if it's in an invocation", () => { - const invoke = { type: 'Invocation', value: matcherInvocation }; - const invokeCalled = { _call: invoke }; - const invokeThunk = { _call: () => invoke }; - - expect(globals.sanitize_matcher(invokeCalled)).toEqual(matcherInvocation); - expect(globals.sanitize_matcher(invokeThunk)).toEqual(matcherInvocation); - }); - - it('should not call on string', () => { - const matcherLikeObj = { - _call: 'I am a call' - }; - expect(globals.sanitize_matcher(matcherLikeObj)).toBe('I am a call'); - }); - }); - - describe('sanitize_greyElementInteraction', () => { - it('should wrap the argument in an invocation', () => { - expect(globals.sanitize_greyElementInteraction('Foo')).toEqual({ - type: 'Invocation', - value: 'Foo' - }); - }); - }); + describe('sanitize_android_direction', () => { + it('should return numbers for strings', () => { + expect(globals.sanitize_android_direction('left')).toBe(1); + expect(globals.sanitize_android_direction('right')).toBe(2); + expect(globals.sanitize_android_direction('up')).toBe(3); + expect(globals.sanitize_android_direction('down')).toBe(4); + }); + + it('should fail with unknown value', () => { + expect(() => { + globals.sanitize_android_direction('kittens'); + }).toThrowErrorMatchingSnapshot(); + }); + }); + + describe('sanitize_android_edge', () => { + it('should return numbers for strings', () => { + expect(globals.sanitize_android_edge('left')).toBe(1); + expect(globals.sanitize_android_edge('right')).toBe(2); + expect(globals.sanitize_android_edge('top')).toBe(3); + expect(globals.sanitize_android_edge('bottom')).toBe(4); + }); + + it('should fail with unknown value', () => { + expect(() => { + globals.sanitize_android_edge('kittens'); + }).toThrowErrorMatchingSnapshot(); + }); + }); + + describe('sanitize_greyDirection', () => { + it('should return numbers for strings', () => { + expect(globals.sanitize_greyDirection('left')).toBe(1); + expect(globals.sanitize_greyDirection('right')).toBe(2); + expect(globals.sanitize_greyDirection('up')).toBe(3); + expect(globals.sanitize_greyDirection('down')).toBe(4); + }); + + it('should fail with unknown value', () => { + expect(() => { + globals.sanitize_greyDirection('kittens'); + }).toThrowErrorMatchingSnapshot(); + }); + }); + + describe('sanitize_greyContentEdge', () => { + it('should return numbers for strings', () => { + expect(globals.sanitize_greyContentEdge('left')).toBe(0); + expect(globals.sanitize_greyContentEdge('right')).toBe(1); + expect(globals.sanitize_greyContentEdge('top')).toBe(2); + expect(globals.sanitize_greyContentEdge('bottom')).toBe(3); + }); + + it('should fail with unknown value', () => { + expect(() => { + globals.sanitize_greyContentEdge('kittens'); + }).toThrowErrorMatchingSnapshot(); + }); + }); + + describe('sanitize_uiAccessibilityTraits', () => { + it('should return numbers for traits', () => { + expect(globals.sanitize_uiAccessibilityTraits(['button'])).toBe(1); + + [ + 'button', + 'link', + 'header', + 'search', + 'image', + 'selected', + 'plays', + 'key', + 'text', + 'summary', + 'disabled', + 'frequentUpdates', + 'startsMedia', + 'adjustable', + 'allowsDirectInteraction', + 'pageTurn' + ].forEach((trait) => { + expect(typeof globals.sanitize_uiAccessibilityTraits([trait])).toBe('number'); + }); + }); + it('should combine the traits', () => { + expect(globals.sanitize_uiAccessibilityTraits(['summary', 'allowsDirectInteraction'])).toBe(16896); + }); + + it('should throw if unknown trait is accessed', () => { + expect(() => globals.sanitize_uiAccessibilityTraits(['unknown'])).toThrowErrorMatchingSnapshot(); + }); + }); + + const matcherInvocation = { + target: { type: 'Class', value: 'Detox.Matcher' }, + method: 'matchNicely' + }; + describe('sanitize_matcher', () => { + it("should return the object if it's no function", () => { + expect(globals.sanitize_matcher({ _call: matcherInvocation })).toEqual(matcherInvocation); + }); + + it("should return the ._call property if it's a function", () => { + const matcherLikeObj = { _call: () => matcherInvocation }; + expect(globals.sanitize_matcher(matcherLikeObj)).toEqual(matcherInvocation); + }); + + it("should unwrap the object if it's in an invocation", () => { + const invoke = { type: 'Invocation', value: matcherInvocation }; + const invokeCalled = { _call: invoke }; + const invokeThunk = { _call: () => invoke }; + + expect(globals.sanitize_matcher(invokeCalled)).toEqual(matcherInvocation); + expect(globals.sanitize_matcher(invokeThunk)).toEqual(matcherInvocation); + }); + + it('should not call on string', () => { + const matcherLikeObj = { + _call: 'I am a call' + }; + expect(globals.sanitize_matcher(matcherLikeObj)).toBe('I am a call'); + }); + }); + + describe('sanitize_greyElementInteraction', () => { + it('should wrap the argument in an invocation', () => { + expect(globals.sanitize_greyElementInteraction('Foo')).toEqual({ + type: 'Invocation', + value: 'Foo' + }); + }); + }); }); diff --git a/generation/__tests__/helpers.js b/generation/__tests__/helpers.js index 776484f5f0..da7fb544c3 100644 --- a/generation/__tests__/helpers.js +++ b/generation/__tests__/helpers.js @@ -1,13 +1,13 @@ const { methodNameToSnakeCase } = require('../helpers'); describe('helpers', () => { - describe('methodNameToSnakeCase', () => { - it('should not fail with empty string', () => { - expect(() => methodNameToSnakeCase('')).not.toThrow(); - }); + describe('methodNameToSnakeCase', () => { + it('should not fail with empty string', () => { + expect(() => methodNameToSnakeCase('')).not.toThrow(); + }); - it('should return the correct snake case method name', () => { - expect(methodNameToSnakeCase('actionForScrollInDirection:amount:xOriginStartPercentage:yOriginStartPercentage:')).toMatchSnapshot(); - }); - }); + it('should return the correct snake case method name', () => { + expect(methodNameToSnakeCase('actionForScrollInDirection:amount:xOriginStartPercentage:yOriginStartPercentage:')).toMatchSnapshot(); + }); + }); }); diff --git a/generation/__tests__/ios.js b/generation/__tests__/ios.js index 6e67d89405..edfa422264 100644 --- a/generation/__tests__/ios.js +++ b/generation/__tests__/ios.js @@ -3,322 +3,322 @@ const remove = require('remove'); const iosGenerator = require('../adapters/ios'); describe('iOS generation', () => { - let ExampleClass; - let exampleContent; - beforeAll(() => { - // Generate the code to test - fs.mkdirSync('./__tests__/generated-ios'); - - const files = { - './fixtures/example.h': './__tests__/generated-ios/example.js' - }; - - console.log('==> generating earl grey files'); - iosGenerator(files); - - console.log('==> loading earl grey files'); - // Load - ExampleClass = require('./generated-ios/example.js'); - exampleContent = fs.readFileSync('./__tests__/generated-ios/example.js', 'utf8'); - }); - - it('should export the class', () => { - expect(ExampleClass.actionForMultipleTapsWithCount).toBeInstanceOf(Function); - }); - - describe('Comments', () => { - it('should include single line comments', () => { - expect(exampleContent.indexOf('Single Line Comment here')).not.toBe(-1); - }); - - it('should include multi line comments', () => { - expect(exampleContent.indexOf('Multi Line Comment here\nAwesome')).not.toBe(-1); - }); - }); - - describe('Error handling', () => { - it('should throw error for wrong type', () => { - expect(() => { - ExampleClass.actionForMultipleTapsWithCount('foo'); - }).toThrowErrorMatchingSnapshot(); - - expect(() => { - ExampleClass.actionForMultipleTapsWithCount(42); - }).not.toThrow(); - - expect(() => { - ExampleClass.actionForMultipleTapsWithCountAtPoint(3, 4); - }).toThrowErrorMatchingSnapshot(); - - expect(() => { - ExampleClass.actionForMultipleTapsWithCountAtPoint(42, { x: 1, y: 2 }); - }).not.toThrow(); - }); - - it('should throw error for not in accepted range', () => { - expect(() => { - ExampleClass.actionForScrollInDirectionAmountXOriginStartPercentageYOriginStartPercentage('flipside', 3, 4, 5); - }).toThrowErrorMatchingSnapshot(); - - expect(() => { - ExampleClass.actionForScrollInDirectionAmountXOriginStartPercentageYOriginStartPercentage('down', 3, 4, 5); - }).not.toThrow(); - }); - - it('should thow error for CGPoint with wrong x and y values', () => { - expect(() => { - ExampleClass.actionForMultipleTapsWithCountAtPoint(3, { x: 3, y: 4 }); - }).not.toThrow(); - - expect(() => { - ExampleClass.actionForMultipleTapsWithCountAtPoint(3, { x: '3', y: 4 }); - }).toThrowErrorMatchingSnapshot(); - - expect(() => { - ExampleClass.actionForMultipleTapsWithCountAtPoint(3, { x: 3 }); - }).toThrowErrorMatchingSnapshot(); - }); - }); - - describe('Invocations', () => { - it('should return the invocation object for methods', () => { - const result = ExampleClass.actionForMultipleTapsWithCount(3); - - expect(result.target.type).toBe('Class'); - expect(result.target.value).toBe('GREYActions'); - - expect(result.method).toBe('actionForMultipleTapsWithCount:'); - - expect(result.args.length).toBe(1); - expect(result.args[0].type).toBe('NSInteger'); - expect(result.args[0].value).toBe(3); - expect(result).toMatchSnapshot(); - }); - - it('should return the invocation object for methods with objects as args', () => { - const result = ExampleClass.actionForMultipleTapsWithCountAtPoint(3, { - x: 3, - y: 4 - }); - - expect(result.target.type).toBe('Class'); - expect(result.target.value).toBe('GREYActions'); - - expect(result.method).toBe('actionForMultipleTapsWithCount:atPoint:'); - - expect(result.args.length).toBe(2); - expect(result.args[0].type).toBe('NSInteger'); - expect(result.args[0].value).toBe(3); - expect(result.args[1].type).toBe('CGPoint'); - expect(result.args[1].value).toEqual({ x: 3, y: 4 }); - expect(result).toMatchSnapshot(); - }); - - it('should return the invocation object for methods with strings', () => { - const result = ExampleClass.actionForTypeText('Foo'); - - expect(result.args[0].type).toBe('NSString'); - expect(result).toMatchSnapshot(); - }); - - it('should sanitize the directions', () => { - const result = ExampleClass.actionForScrollInDirectionAmountXOriginStartPercentageYOriginStartPercentage('down', 3, 4, 5); - - expect(result.args[0].type).toBe('NSInteger'); - expect(result.args[0].value).toBe(4); - expect(result).toMatchSnapshot(); - }); - - it('should sanitize the content edge', () => { - const result = ExampleClass.actionForScrollToContentEdge('bottom'); - - expect(result.args[0].type).toBe('NSInteger'); - expect(result.args[0].value).toBe(3); - }); - }); - - describe('filter functions with unknown arguments', () => { - it('should not have a function with one unkown type', () => { - expect(ExampleClass.actionWithUnknownType).not.toBeDefined(); - }); - - it('should not have a function with one kown and one unknown type', () => { - expect(ExampleClass.actionWithKnownAndUnknownType).not.toBeDefined(); - }); - }); - - describe('special case: id', () => { - it('should not wrap the args in type id, but pass them in as they are', () => { - const ancestorMatcher = { - type: 'Invocation', - value: { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForAccessibilityID:', - args: ['Grandson883'] - } - }; - const currentMatcher = { - type: 'Invocation', - value: { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForAccessibilityID:', - args: ['Grandfather883'] - } - }; - const result = ExampleClass.detoxMatcherForBothAndAncestorMatcher(currentMatcher, ancestorMatcher); - - expect(result).toEqual({ - target: { - type: 'Class', - value: 'GREYActions' - }, - method: 'detoxMatcherForBoth:andAncestorMatcher:', - args: [ - { - type: 'Invocation', - value: { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForAccessibilityID:', - args: ['Grandfather883'] - } - }, - { - type: 'Invocation', - value: { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForAccessibilityID:', - args: ['Grandson883'] - } - } - ] - }); - }); - - it('should fail with wrongly formatted matchers', () => { - expect(() => { - const ancestorMatcher = { - type: 'Invocation', - value: { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForAccessibilityID:', - args: ['Grandson883'] - } - }; - const currentAction = { - type: 'Invocation', - value: { - target: { - type: 'Class', - value: 'GREYAction' - }, - method: 'matcherForAccessibilityID:', - args: ['Grandfather883'] - } - }; - ExampleClass.detoxMatcherForBothAndAncestorMatcher(currentAction, ancestorMatcher); - }).toThrowErrorMatchingSnapshot(); - - expect(() => { - const ancestorAction = { - type: 'Invocation', - value: { - target: { - type: 'Class', - value: 'GREYAction' - }, - method: 'matcherForAccessibilityID:', - args: ['Grandson883'] - } - }; - const currentMatcher = { - type: 'Invocation', - value: { - target: { - type: 'Class', - value: 'GREYMatchers' - }, - method: 'matcherForAccessibilityID:', - args: ['Grandfather883'] - } - }; - ExampleClass.detoxMatcherForBothAndAncestorMatcher(currentMatcher, ancestorAction); - }).toThrowErrorMatchingSnapshot(); - - expect(() => { - const ancestorMatcher = { - type: 'Invocation', - value: { - target: { - type: 'Class', - value: 'GREYAction' - }, - method: 'matcherForAccessibilityID:', - args: ['Grandson883'] - } - }; - const currentMatcher = { - type: 'Invocation', - value: { - method: 'matcherForAccessibilityID:', - args: ['Grandfather883'] - } - }; - ExampleClass.detoxMatcherForBothAndAncestorMatcher(currentMatcher, ancestorMatcher); - }).toThrowErrorMatchingSnapshot(); - }); - }); - - describe('helper functions', () => { - it('should include them, if they are used', () => { - // GREYDirection is included, so sanitize_greyDirection should be there - expect(exampleContent.indexOf('function sanitize_greyDirection')).not.toBe(-1); - }); - - it('should not include them, if they are unused', () => { - // UIAccessibilityTraits is not included, so sanitize_uiAccessibilityTraits should not be there - expect(exampleContent.indexOf('function sanitize_uiAccessibilityTraits')).toBe(-1); - }); - }); - - describe('instance methods', () => { - it('should expose the instance methods as static ones', () => { - expect(ExampleClass.performAction).toBeInstanceOf(Function); - }); - - it('should have the first arg set as invocation', () => { - expect(ExampleClass.performAction('MyClass', 'Foo')).toEqual({ - target: { - type: 'Invocation', - value: 'MyClass' - }, - method: 'performAction:', - args: [ - { - type: 'NSString', - value: 'Foo' - } - ] - }); - }); - }); - - afterAll(() => { - // Clean up - remove.removeSync('./__tests__/generated-ios'); - }); + let ExampleClass; + let exampleContent; + beforeAll(() => { + // Generate the code to test + fs.mkdirSync('./__tests__/generated-ios'); + + const files = { + './fixtures/example.h': './__tests__/generated-ios/example.js' + }; + + console.log('==> generating earl grey files'); + iosGenerator(files); + + console.log('==> loading earl grey files'); + // Load + ExampleClass = require('./generated-ios/example.js'); + exampleContent = fs.readFileSync('./__tests__/generated-ios/example.js', 'utf8'); + }); + + it('should export the class', () => { + expect(ExampleClass.actionForMultipleTapsWithCount).toBeInstanceOf(Function); + }); + + describe('Comments', () => { + it('should include single line comments', () => { + expect(exampleContent.indexOf('Single Line Comment here')).not.toBe(-1); + }); + + it('should include multi line comments', () => { + expect(exampleContent.indexOf('Multi Line Comment here\nAwesome')).not.toBe(-1); + }); + }); + + describe('Error handling', () => { + it('should throw error for wrong type', () => { + expect(() => { + ExampleClass.actionForMultipleTapsWithCount('foo'); + }).toThrowErrorMatchingSnapshot(); + + expect(() => { + ExampleClass.actionForMultipleTapsWithCount(42); + }).not.toThrow(); + + expect(() => { + ExampleClass.actionForMultipleTapsWithCountAtPoint(3, 4); + }).toThrowErrorMatchingSnapshot(); + + expect(() => { + ExampleClass.actionForMultipleTapsWithCountAtPoint(42, { x: 1, y: 2 }); + }).not.toThrow(); + }); + + it('should throw error for not in accepted range', () => { + expect(() => { + ExampleClass.actionForScrollInDirectionAmountXOriginStartPercentageYOriginStartPercentage('flipside', 3, 4, 5); + }).toThrowErrorMatchingSnapshot(); + + expect(() => { + ExampleClass.actionForScrollInDirectionAmountXOriginStartPercentageYOriginStartPercentage('down', 3, 4, 5); + }).not.toThrow(); + }); + + it('should thow error for CGPoint with wrong x and y values', () => { + expect(() => { + ExampleClass.actionForMultipleTapsWithCountAtPoint(3, { x: 3, y: 4 }); + }).not.toThrow(); + + expect(() => { + ExampleClass.actionForMultipleTapsWithCountAtPoint(3, { x: '3', y: 4 }); + }).toThrowErrorMatchingSnapshot(); + + expect(() => { + ExampleClass.actionForMultipleTapsWithCountAtPoint(3, { x: 3 }); + }).toThrowErrorMatchingSnapshot(); + }); + }); + + describe('Invocations', () => { + it('should return the invocation object for methods', () => { + const result = ExampleClass.actionForMultipleTapsWithCount(3); + + expect(result.target.type).toBe('Class'); + expect(result.target.value).toBe('GREYActions'); + + expect(result.method).toBe('actionForMultipleTapsWithCount:'); + + expect(result.args.length).toBe(1); + expect(result.args[0].type).toBe('NSInteger'); + expect(result.args[0].value).toBe(3); + expect(result).toMatchSnapshot(); + }); + + it('should return the invocation object for methods with objects as args', () => { + const result = ExampleClass.actionForMultipleTapsWithCountAtPoint(3, { + x: 3, + y: 4 + }); + + expect(result.target.type).toBe('Class'); + expect(result.target.value).toBe('GREYActions'); + + expect(result.method).toBe('actionForMultipleTapsWithCount:atPoint:'); + + expect(result.args.length).toBe(2); + expect(result.args[0].type).toBe('NSInteger'); + expect(result.args[0].value).toBe(3); + expect(result.args[1].type).toBe('CGPoint'); + expect(result.args[1].value).toEqual({ x: 3, y: 4 }); + expect(result).toMatchSnapshot(); + }); + + it('should return the invocation object for methods with strings', () => { + const result = ExampleClass.actionForTypeText('Foo'); + + expect(result.args[0].type).toBe('NSString'); + expect(result).toMatchSnapshot(); + }); + + it('should sanitize the directions', () => { + const result = ExampleClass.actionForScrollInDirectionAmountXOriginStartPercentageYOriginStartPercentage('down', 3, 4, 5); + + expect(result.args[0].type).toBe('NSInteger'); + expect(result.args[0].value).toBe(4); + expect(result).toMatchSnapshot(); + }); + + it('should sanitize the content edge', () => { + const result = ExampleClass.actionForScrollToContentEdge('bottom'); + + expect(result.args[0].type).toBe('NSInteger'); + expect(result.args[0].value).toBe(3); + }); + }); + + describe('filter functions with unknown arguments', () => { + it('should not have a function with one unkown type', () => { + expect(ExampleClass.actionWithUnknownType).not.toBeDefined(); + }); + + it('should not have a function with one kown and one unknown type', () => { + expect(ExampleClass.actionWithKnownAndUnknownType).not.toBeDefined(); + }); + }); + + describe('special case: id', () => { + it('should not wrap the args in type id, but pass them in as they are', () => { + const ancestorMatcher = { + type: 'Invocation', + value: { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForAccessibilityID:', + args: ['Grandson883'] + } + }; + const currentMatcher = { + type: 'Invocation', + value: { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForAccessibilityID:', + args: ['Grandfather883'] + } + }; + const result = ExampleClass.detoxMatcherForBothAndAncestorMatcher(currentMatcher, ancestorMatcher); + + expect(result).toEqual({ + target: { + type: 'Class', + value: 'GREYActions' + }, + method: 'detoxMatcherForBoth:andAncestorMatcher:', + args: [ + { + type: 'Invocation', + value: { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForAccessibilityID:', + args: ['Grandfather883'] + } + }, + { + type: 'Invocation', + value: { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForAccessibilityID:', + args: ['Grandson883'] + } + } + ] + }); + }); + + it('should fail with wrongly formatted matchers', () => { + expect(() => { + const ancestorMatcher = { + type: 'Invocation', + value: { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForAccessibilityID:', + args: ['Grandson883'] + } + }; + const currentAction = { + type: 'Invocation', + value: { + target: { + type: 'Class', + value: 'GREYAction' + }, + method: 'matcherForAccessibilityID:', + args: ['Grandfather883'] + } + }; + ExampleClass.detoxMatcherForBothAndAncestorMatcher(currentAction, ancestorMatcher); + }).toThrowErrorMatchingSnapshot(); + + expect(() => { + const ancestorAction = { + type: 'Invocation', + value: { + target: { + type: 'Class', + value: 'GREYAction' + }, + method: 'matcherForAccessibilityID:', + args: ['Grandson883'] + } + }; + const currentMatcher = { + type: 'Invocation', + value: { + target: { + type: 'Class', + value: 'GREYMatchers' + }, + method: 'matcherForAccessibilityID:', + args: ['Grandfather883'] + } + }; + ExampleClass.detoxMatcherForBothAndAncestorMatcher(currentMatcher, ancestorAction); + }).toThrowErrorMatchingSnapshot(); + + expect(() => { + const ancestorMatcher = { + type: 'Invocation', + value: { + target: { + type: 'Class', + value: 'GREYAction' + }, + method: 'matcherForAccessibilityID:', + args: ['Grandson883'] + } + }; + const currentMatcher = { + type: 'Invocation', + value: { + method: 'matcherForAccessibilityID:', + args: ['Grandfather883'] + } + }; + ExampleClass.detoxMatcherForBothAndAncestorMatcher(currentMatcher, ancestorMatcher); + }).toThrowErrorMatchingSnapshot(); + }); + }); + + describe('helper functions', () => { + it('should include them, if they are used', () => { + // GREYDirection is included, so sanitize_greyDirection should be there + expect(exampleContent.indexOf('function sanitize_greyDirection')).not.toBe(-1); + }); + + it('should not include them, if they are unused', () => { + // UIAccessibilityTraits is not included, so sanitize_uiAccessibilityTraits should not be there + expect(exampleContent.indexOf('function sanitize_uiAccessibilityTraits')).toBe(-1); + }); + }); + + describe('instance methods', () => { + it('should expose the instance methods as static ones', () => { + expect(ExampleClass.performAction).toBeInstanceOf(Function); + }); + + it('should have the first arg set as invocation', () => { + expect(ExampleClass.performAction('MyClass', 'Foo')).toEqual({ + target: { + type: 'Invocation', + value: 'MyClass' + }, + method: 'performAction:', + args: [ + { + type: 'NSString', + value: 'Foo' + } + ] + }); + }); + }); + + afterAll(() => { + // Clean up + remove.removeSync('./__tests__/generated-ios'); + }); }); diff --git a/generation/adapters/android.js b/generation/adapters/android.js index 929f4ba0fb..2322a872e8 100644 --- a/generation/adapters/android.js +++ b/generation/adapters/android.js @@ -5,55 +5,55 @@ const { callGlobal } = require('../helpers'); const { isNumber, isString, isBoolean, isOfClass } = require('../core/type-checks'); const typeCheckInterfaces = { - Integer: isNumber, - Double: isNumber, - String: isString, - boolean: isBoolean, - 'Matcher': isOfClass('Matcher') + Integer: isNumber, + Double: isNumber, + String: isString, + boolean: isBoolean, + 'Matcher': isOfClass('Matcher') }; const contentSanitizersForFunction = { - scrollInDirection: { - argumentName: 'direction', - newType: 'String', - name: 'sanitize_android_direction', - value: callGlobal('sanitize_android_direction') - }, - swipeInDirection: { - argumentName: 'direction', - newType: 'String', - name: 'sanitize_android_direction', - value: callGlobal('sanitize_android_direction') - }, - scrollToEdge: { - argumentName: 'edge', - newType: 'String', - name: 'sanitize_android_edge', - value: callGlobal('sanitize_android_edge') - }, - 'Matcher': { - type: 'String', - name: 'sanitize_matcher', - value: callGlobal('sanitize_matcher') - } + scrollInDirection: { + argumentName: 'direction', + newType: 'String', + name: 'sanitize_android_direction', + value: callGlobal('sanitize_android_direction') + }, + swipeInDirection: { + argumentName: 'direction', + newType: 'String', + name: 'sanitize_android_direction', + value: callGlobal('sanitize_android_direction') + }, + scrollToEdge: { + argumentName: 'edge', + newType: 'String', + name: 'sanitize_android_edge', + value: callGlobal('sanitize_android_edge') + }, + 'Matcher': { + type: 'String', + name: 'sanitize_matcher', + value: callGlobal('sanitize_matcher') + } }; const contentSanitizersForType = { - 'Matcher': { - type: 'Invocation', - name: 'sanitize_matcher', - value: callGlobal('sanitize_matcher') - } + 'Matcher': { + type: 'Invocation', + name: 'sanitize_matcher', + value: callGlobal('sanitize_matcher') + } }; module.exports = generator({ - typeCheckInterfaces, - contentSanitizersForFunction, - contentSanitizersForType, - supportedTypes: ['Integer', 'int', 'double', 'Double', 'boolean', 'String', 'Matcher'], - renameTypesMap: { - int: 'Integer', // TODO: add test - double: 'Double' - }, - classValue: ({ package: pkg, name }) => `${pkg}.${name}` + typeCheckInterfaces, + contentSanitizersForFunction, + contentSanitizersForType, + supportedTypes: ['Integer', 'int', 'double', 'Double', 'boolean', 'String', 'Matcher'], + renameTypesMap: { + int: 'Integer', // TODO: add test + double: 'Double' + }, + classValue: ({ package: pkg, name }) => `${pkg}.${name}` }); diff --git a/generation/adapters/ios.js b/generation/adapters/ios.js index 30df668659..2e8bdf245e 100644 --- a/generation/adapters/ios.js +++ b/generation/adapters/ios.js @@ -1,87 +1,87 @@ const t = require('babel-types'); const generator = require('../core/generator'); const { - isNumber, - isString, - isBoolean, - isPoint, - isOneOf, - isGreyAction, - isGreyMatcher, - isGreyElementInteraction, - isArray, - isDefined + isNumber, + isString, + isBoolean, + isPoint, + isOneOf, + isGreyAction, + isGreyMatcher, + isGreyElementInteraction, + isArray, + isDefined } = require('../core/type-checks'); const { callGlobal } = require('../helpers'); const typeCheckInterfaces = { - NSInteger: isNumber, - CGFloat: isNumber, - CGPoint: isPoint, - CFTimeInterval: isNumber, - double: isNumber, - float: isNumber, - NSString: isString, - BOOL: isBoolean, - 'NSDate *': isNumber, - GREYDirection: isOneOf(['left', 'right', 'up', 'down']), - GREYContentEdge: isOneOf(['left', 'right', 'top', 'bottom']), - GREYPinchDirection: isOneOf(['outward', 'inward']), - 'id': isGreyAction, - 'id': isGreyMatcher, - 'GREYElementInteraction*': isGreyElementInteraction, - UIAccessibilityTraits: isArray, - id: isDefined + NSInteger: isNumber, + CGFloat: isNumber, + CGPoint: isPoint, + CFTimeInterval: isNumber, + double: isNumber, + float: isNumber, + NSString: isString, + BOOL: isBoolean, + 'NSDate *': isNumber, + GREYDirection: isOneOf(['left', 'right', 'up', 'down']), + GREYContentEdge: isOneOf(['left', 'right', 'top', 'bottom']), + GREYPinchDirection: isOneOf(['outward', 'inward']), + 'id': isGreyAction, + 'id': isGreyMatcher, + 'GREYElementInteraction*': isGreyElementInteraction, + UIAccessibilityTraits: isArray, + id: isDefined }; const contentSanitizersForType = { - GREYDirection: { - type: 'NSInteger', - name: 'sanitize_greyDirection', - value: callGlobal('sanitize_greyDirection') - }, - GREYContentEdge: { - type: 'NSInteger', - name: 'sanitize_greyContentEdge', - value: callGlobal('sanitize_greyContentEdge') - }, - UIAccessibilityTraits: { - type: 'NSInteger', - name: 'sanitize_uiAccessibilityTraits', - value: callGlobal('sanitize_uiAccessibilityTraits') - }, - 'GREYElementInteraction*': { - type: 'Invocation', - name: 'sanitize_greyElementInteraction', - value: callGlobal('sanitize_greyElementInteraction') - } + GREYDirection: { + type: 'NSInteger', + name: 'sanitize_greyDirection', + value: callGlobal('sanitize_greyDirection') + }, + GREYContentEdge: { + type: 'NSInteger', + name: 'sanitize_greyContentEdge', + value: callGlobal('sanitize_greyContentEdge') + }, + UIAccessibilityTraits: { + type: 'NSInteger', + name: 'sanitize_uiAccessibilityTraits', + value: callGlobal('sanitize_uiAccessibilityTraits') + }, + 'GREYElementInteraction*': { + type: 'Invocation', + name: 'sanitize_greyElementInteraction', + value: callGlobal('sanitize_greyElementInteraction') + } }; module.exports = generator({ - typeCheckInterfaces, - contentSanitizersForFunction: {}, - contentSanitizersForType, - supportedTypes: [ - 'CGFloat', - 'CGPoint', - 'GREYContentEdge', - 'GREYDirection', - 'GREYElementInteraction*', - 'NSInteger', - 'NSString *', - 'NSString', - 'NSUInteger', - 'id', - 'id', - 'CFTimeInterval', - 'UIAccessibilityTraits', - 'id' - ], - renameTypesMap: { - NSUInteger: 'NSInteger', - 'NSString *': 'NSString', - CFTimeInterval: 'CGFloat' - }, - classValue: ({ name }) => name, - blacklistedFunctionNames: ['init'] + typeCheckInterfaces, + contentSanitizersForFunction: {}, + contentSanitizersForType, + supportedTypes: [ + 'CGFloat', + 'CGPoint', + 'GREYContentEdge', + 'GREYDirection', + 'GREYElementInteraction*', + 'NSInteger', + 'NSString *', + 'NSString', + 'NSUInteger', + 'id', + 'id', + 'CFTimeInterval', + 'UIAccessibilityTraits', + 'id' + ], + renameTypesMap: { + NSUInteger: 'NSInteger', + 'NSString *': 'NSString', + CFTimeInterval: 'CGFloat' + }, + classValue: ({ name }) => name, + blacklistedFunctionNames: ['init'] }); diff --git a/generation/core/generator.js b/generation/core/generator.js index 14687ac4e9..9fe8c46f0f 100644 --- a/generation/core/generator.js +++ b/generation/core/generator.js @@ -8,246 +8,246 @@ const fs = require('fs'); const { methodNameToSnakeCase } = require('../helpers'); let globalFunctionUsage = {}; module.exports = function getGenerator({ - typeCheckInterfaces, - renameTypesMap, - supportedTypes, - classValue, - contentSanitizersForFunction, - contentSanitizersForType, - blacklistedFunctionNames = [] + typeCheckInterfaces, + renameTypesMap, + supportedTypes, + classValue, + contentSanitizersForFunction, + contentSanitizersForType, + blacklistedFunctionNames = [] }) { - /** - * the input provided by objective-c-parser looks like this: - * { - * "name": "BasicName", - * "methods": [ - * { - * "args": [], - * "comment": "This is the comment of basic method one", - * "name": "basicMethodOne", - * "returnType": "NSInteger" - * }, - * { - * "args": [ - * { - * "type": "NSInteger", - * "name": "argOne" - * }, - * { - * "type": "NSString", - * "name": "argTwo" - * } - * ], - * "comment": "This is the comment of basic method two.\nIt has multiple lines", - * "name": "basicMethodTwoWithArgOneAndArgTwo", - * "returnType": "NSString" - * } - * ] - * } - */ - function createClass(json) { - return t.classDeclaration( - t.identifier(json.name), - null, - t.classBody( - json.methods - .filter(filterMethodsWithUnsupportedParams) - .filter(filterMethodsWithBlacklistedName) - .map(createMethod.bind(null, json)) - ), - [] - ); - } - - function filterMethodsWithBlacklistedName({ name }) { - return !blacklistedFunctionNames.find((blacklisted) => name.indexOf(blacklisted) !== -1); - } - - function filterMethodsWithUnsupportedParams(method) { - return method.args.reduce((carry, methodArg) => { - if (methodArg === null) { - console.error(method); - } - return carry && supportedTypes.includes(methodArg.type); - }, true); - } - - function createExport(json) { - return t.expressionStatement( - t.assignmentExpression('=', t.memberExpression(t.identifier('module'), t.identifier('exports'), false), t.identifier(json.name)) - ); - } - - function createMethod(classJson, json) { - const args = json.args.map(({ name }) => t.identifier(name)); - - if (!json.static) { - args.unshift(t.identifier('element')); - } - - const m = t.classMethod( - 'method', - t.identifier(methodNameToSnakeCase(json.name)), - args, - t.blockStatement(createMethodBody(classJson, json)), - false, - true - ); - - if (json.comment) { - const comment = { - type: json.comment.indexOf('\n') === -1 ? 'LineComment' : 'BlockComment', - value: json.comment + '\n' - }; - - m.leadingComments = m.leadingComments || []; - m.leadingComments.push(comment); - } - return m; - } - - function sanitizeArgumentType(json) { - if (renameTypesMap[json.type]) { - return Object.assign({}, json, { - type: renameTypesMap[json.type] - }); - } - return json; - } - - function createMethodBody(classJson, json) { - const sanitizedJson = Object.assign({}, json, { - args: json.args.map((argJson) => sanitizeArgumentType(argJson)) - }); - - const allTypeChecks = createTypeChecks(sanitizedJson, sanitizedJson.name).reduce( - (carry, item) => (item instanceof Array ? [...carry, ...item] : [...carry, item]), - [] - ); - const typeChecks = allTypeChecks.filter((check) => typeof check === 'object'); - const returnStatement = createReturnStatement(classJson, sanitizedJson); - return [...typeChecks, returnStatement]; - } - - function createTypeChecks(json, functionName) { - const checks = json.args.map((arg) => createTypeCheck(arg, functionName)); - checks.filter((check) => Boolean(check)); - return checks; - } - - function addArgumentContentSanitizerCall(json, functionName) { - if (contentSanitizersForType[json.type]) { - globalFunctionUsage[contentSanitizersForType[json.type].name] = true; - return contentSanitizersForType[json.type].value(json.name); - } - - if (contentSanitizersForFunction[functionName] && contentSanitizersForFunction[functionName].argumentName === json.name) { - globalFunctionUsage[contentSanitizersForFunction[functionName].name] = true; - return contentSanitizersForFunction[functionName].value(json.name); - } - - return t.identifier(json.name); - } - - function addArgumentTypeSanitizer(json) { - if (contentSanitizersForType[json.type]) { - return contentSanitizersForType[json.type].type; - } - - return json.type; - } - - // These types need no wrapping with {type: ..., value: } - const plainArgumentTypes = ['id', 'id', 'id', 'GREYElementInteraction*', 'String']; - - function shouldBeWrapped({ type }) { - return !plainArgumentTypes.includes(type); - } - - function createReturnStatement(classJson, json) { - const args = json.args.map( - (arg) => - shouldBeWrapped(arg) - ? t.objectExpression([ - t.objectProperty(t.identifier('type'), t.stringLiteral(addArgumentTypeSanitizer(arg))), - t.objectProperty(t.identifier('value'), addArgumentContentSanitizerCall(arg, json.name)) - ]) - : addArgumentContentSanitizerCall(arg, json.name) - ); - - return t.returnStatement( - t.objectExpression([ - t.objectProperty( - t.identifier('target'), - t.objectExpression([ - t.objectProperty(t.identifier('type'), t.stringLiteral(json.static ? 'Class' : 'Invocation')), - t.objectProperty(t.identifier('value'), json.static ? t.stringLiteral(classValue(classJson)) : t.identifier('element')) - ]) - ), - t.objectProperty(t.identifier('method'), t.stringLiteral(json.name)), - t.objectProperty(t.identifier('args'), t.arrayExpression(args)) - ]) - ); - } - - function createTypeCheck(json, functionName) { - const optionalSanitizer = contentSanitizersForFunction[functionName]; - const type = optionalSanitizer && optionalSanitizer.argumentName === json.name ? optionalSanitizer.newType : json.type; - const typeCheckCreator = typeCheckInterfaces[type]; - const isListOfChecks = typeCheckCreator instanceof Array; - return isListOfChecks - ? typeCheckCreator.map((singleCheck) => singleCheck(json)) - : typeof typeCheckCreator === 'function' - ? typeCheckCreator(json) - : t.emptyStatement(); - } - - return function generator(files) { - Object.entries(files).forEach(([inputFile, outputFile]) => { - globalFunctionUsage = {}; - const input = fs.readFileSync(inputFile, 'utf8'); - const isObjectiveC = inputFile[inputFile.length - 1] === 'h'; - - const json = isObjectiveC ? objectiveCParser(input) : javaMethodParser(input); - - // set default name - if (!json.name) { - const pathFragments = outputFile.split('/'); - json.name = pathFragments[pathFragments.length - 1].replace('.js', ''); - } - const ast = t.program([createClass(json), createExport(json)]); - const output = generate(ast); - - const commentBefore = '/**\n\n\tThis code is generated.\n\tFor more information see generation/README.md.\n*/\n\n'; - - // Add global helper functions - const globalFunctionsStr = fs.readFileSync(__dirname + '/global-functions.js', 'utf8'); - const globalFunctionsSource = globalFunctionsStr.substr(0, globalFunctionsStr.indexOf('module.exports')); - - // Only include global functions that are actually used - const usedGlobalFunctions = Object.entries(globalFunctionUsage) - .filter(([key, value]) => value) - .map(([key]) => key); - const globalFunctions = usedGlobalFunctions - .map((name) => { - const start = globalFunctionsSource.indexOf(`function ${name}`); - const end = globalFunctionsSource.indexOf(`// END ${name}`); - return globalFunctionsSource.substr(start, end - start); - }) - .join('\n'); - - const code = [commentBefore, globalFunctions, output.code].join('\n'); - fs.writeFileSync(outputFile, code, 'utf8'); - - // Output methods that were not created due to missing argument support - const unsupportedMethods = json.methods.filter((x) => !filterMethodsWithUnsupportedParams(x)); - if (unsupportedMethods.length) { - console.log(`Could not generate the following methods for ${json.name}`); - unsupportedMethods.forEach((method) => { - const methodArgs = method.args.filter((methodArg) => !supportedTypes.includes(methodArg.type)).map((methodArg) => methodArg.type); - console.log(`\t ${method.name} misses ${methodArgs}`); - }); - } - }); - }; + /** + * the input provided by objective-c-parser looks like this: + * { + * "name": "BasicName", + * "methods": [ + * { + * "args": [], + * "comment": "This is the comment of basic method one", + * "name": "basicMethodOne", + * "returnType": "NSInteger" + * }, + * { + * "args": [ + * { + * "type": "NSInteger", + * "name": "argOne" + * }, + * { + * "type": "NSString", + * "name": "argTwo" + * } + * ], + * "comment": "This is the comment of basic method two.\nIt has multiple lines", + * "name": "basicMethodTwoWithArgOneAndArgTwo", + * "returnType": "NSString" + * } + * ] + * } + */ + function createClass(json) { + return t.classDeclaration( + t.identifier(json.name), + null, + t.classBody( + json.methods + .filter(filterMethodsWithUnsupportedParams) + .filter(filterMethodsWithBlacklistedName) + .map(createMethod.bind(null, json)) + ), + [] + ); + } + + function filterMethodsWithBlacklistedName({ name }) { + return !blacklistedFunctionNames.find((blacklisted) => name.indexOf(blacklisted) !== -1); + } + + function filterMethodsWithUnsupportedParams(method) { + return method.args.reduce((carry, methodArg) => { + if (methodArg === null) { + console.error(method); + } + return carry && supportedTypes.includes(methodArg.type); + }, true); + } + + function createExport(json) { + return t.expressionStatement( + t.assignmentExpression('=', t.memberExpression(t.identifier('module'), t.identifier('exports'), false), t.identifier(json.name)) + ); + } + + function createMethod(classJson, json) { + const args = json.args.map(({ name }) => t.identifier(name)); + + if (!json.static) { + args.unshift(t.identifier('element')); + } + + const m = t.classMethod( + 'method', + t.identifier(methodNameToSnakeCase(json.name)), + args, + t.blockStatement(createMethodBody(classJson, json)), + false, + true + ); + + if (json.comment) { + const comment = { + type: json.comment.indexOf('\n') === -1 ? 'LineComment' : 'BlockComment', + value: json.comment + '\n' + }; + + m.leadingComments = m.leadingComments || []; + m.leadingComments.push(comment); + } + return m; + } + + function sanitizeArgumentType(json) { + if (renameTypesMap[json.type]) { + return Object.assign({}, json, { + type: renameTypesMap[json.type] + }); + } + return json; + } + + function createMethodBody(classJson, json) { + const sanitizedJson = Object.assign({}, json, { + args: json.args.map((argJson) => sanitizeArgumentType(argJson)) + }); + + const allTypeChecks = createTypeChecks(sanitizedJson, sanitizedJson.name).reduce( + (carry, item) => (item instanceof Array ? [...carry, ...item] : [...carry, item]), + [] + ); + const typeChecks = allTypeChecks.filter((check) => typeof check === 'object'); + const returnStatement = createReturnStatement(classJson, sanitizedJson); + return [...typeChecks, returnStatement]; + } + + function createTypeChecks(json, functionName) { + const checks = json.args.map((arg) => createTypeCheck(arg, functionName)); + checks.filter((check) => Boolean(check)); + return checks; + } + + function addArgumentContentSanitizerCall(json, functionName) { + if (contentSanitizersForType[json.type]) { + globalFunctionUsage[contentSanitizersForType[json.type].name] = true; + return contentSanitizersForType[json.type].value(json.name); + } + + if (contentSanitizersForFunction[functionName] && contentSanitizersForFunction[functionName].argumentName === json.name) { + globalFunctionUsage[contentSanitizersForFunction[functionName].name] = true; + return contentSanitizersForFunction[functionName].value(json.name); + } + + return t.identifier(json.name); + } + + function addArgumentTypeSanitizer(json) { + if (contentSanitizersForType[json.type]) { + return contentSanitizersForType[json.type].type; + } + + return json.type; + } + + // These types need no wrapping with {type: ..., value: } + const plainArgumentTypes = ['id', 'id', 'id', 'GREYElementInteraction*', 'String']; + + function shouldBeWrapped({ type }) { + return !plainArgumentTypes.includes(type); + } + + function createReturnStatement(classJson, json) { + const args = json.args.map( + (arg) => + shouldBeWrapped(arg) + ? t.objectExpression([ + t.objectProperty(t.identifier('type'), t.stringLiteral(addArgumentTypeSanitizer(arg))), + t.objectProperty(t.identifier('value'), addArgumentContentSanitizerCall(arg, json.name)) + ]) + : addArgumentContentSanitizerCall(arg, json.name) + ); + + return t.returnStatement( + t.objectExpression([ + t.objectProperty( + t.identifier('target'), + t.objectExpression([ + t.objectProperty(t.identifier('type'), t.stringLiteral(json.static ? 'Class' : 'Invocation')), + t.objectProperty(t.identifier('value'), json.static ? t.stringLiteral(classValue(classJson)) : t.identifier('element')) + ]) + ), + t.objectProperty(t.identifier('method'), t.stringLiteral(json.name)), + t.objectProperty(t.identifier('args'), t.arrayExpression(args)) + ]) + ); + } + + function createTypeCheck(json, functionName) { + const optionalSanitizer = contentSanitizersForFunction[functionName]; + const type = optionalSanitizer && optionalSanitizer.argumentName === json.name ? optionalSanitizer.newType : json.type; + const typeCheckCreator = typeCheckInterfaces[type]; + const isListOfChecks = typeCheckCreator instanceof Array; + return isListOfChecks + ? typeCheckCreator.map((singleCheck) => singleCheck(json)) + : typeof typeCheckCreator === 'function' + ? typeCheckCreator(json) + : t.emptyStatement(); + } + + return function generator(files) { + Object.entries(files).forEach(([inputFile, outputFile]) => { + globalFunctionUsage = {}; + const input = fs.readFileSync(inputFile, 'utf8'); + const isObjectiveC = inputFile[inputFile.length - 1] === 'h'; + + const json = isObjectiveC ? objectiveCParser(input) : javaMethodParser(input); + + // set default name + if (!json.name) { + const pathFragments = outputFile.split('/'); + json.name = pathFragments[pathFragments.length - 1].replace('.js', ''); + } + const ast = t.program([createClass(json), createExport(json)]); + const output = generate(ast); + + const commentBefore = '/**\n\n\tThis code is generated.\n\tFor more information see generation/README.md.\n*/\n\n'; + + // Add global helper functions + const globalFunctionsStr = fs.readFileSync(__dirname + '/global-functions.js', 'utf8'); + const globalFunctionsSource = globalFunctionsStr.substr(0, globalFunctionsStr.indexOf('module.exports')); + + // Only include global functions that are actually used + const usedGlobalFunctions = Object.entries(globalFunctionUsage) + .filter(([key, value]) => value) + .map(([key]) => key); + const globalFunctions = usedGlobalFunctions + .map((name) => { + const start = globalFunctionsSource.indexOf(`function ${name}`); + const end = globalFunctionsSource.indexOf(`// END ${name}`); + return globalFunctionsSource.substr(start, end - start); + }) + .join('\n'); + + const code = [commentBefore, globalFunctions, output.code].join('\n'); + fs.writeFileSync(outputFile, code, 'utf8'); + + // Output methods that were not created due to missing argument support + const unsupportedMethods = json.methods.filter((x) => !filterMethodsWithUnsupportedParams(x)); + if (unsupportedMethods.length) { + console.log(`Could not generate the following methods for ${json.name}`); + unsupportedMethods.forEach((method) => { + const methodArgs = method.args.filter((methodArg) => !supportedTypes.includes(methodArg.type)).map((methodArg) => methodArg.type); + console.log(`\t ${method.name} misses ${methodArgs}`); + }); + } + }); + }; }; diff --git a/generation/core/global-functions.js b/generation/core/global-functions.js index 8ac4a2dc22..5ec9d775cd 100644 --- a/generation/core/global-functions.js +++ b/generation/core/global-functions.js @@ -3,147 +3,147 @@ // dynamically included while generating function sanitize_android_direction(direction) { - switch (direction) { - case 'left': - return 1; - case 'right': - return 2; - case 'up': - return 3; - case 'down': - return 4; - default: - throw new Error(`direction must be a 'left'/'right'/'up'/'down', got ${direction}`); - } + switch (direction) { + case 'left': + return 1; + case 'right': + return 2; + case 'up': + return 3; + case 'down': + return 4; + default: + throw new Error(`direction must be a 'left'/'right'/'up'/'down', got ${direction}`); + } } // END sanitize_android_direction function sanitize_android_edge(edge) { - switch (edge) { - case 'left': - return 1; - case 'right': - return 2; - case 'top': - return 3; - case 'bottom': - return 4; - default: - throw new Error(`edge must be a 'left'/'right'/'top'/'bottom', got ${edge}`); - } + switch (edge) { + case 'left': + return 1; + case 'right': + return 2; + case 'top': + return 3; + case 'bottom': + return 4; + default: + throw new Error(`edge must be a 'left'/'right'/'top'/'bottom', got ${edge}`); + } } // END sanitize_android_edge function sanitize_greyDirection(action) { - switch (action) { - case 'left': - return 1; - case 'right': - return 2; - case 'up': - return 3; - case 'down': - return 4; + switch (action) { + case 'left': + return 1; + case 'right': + return 2; + case 'up': + return 3; + case 'down': + return 4; - default: - throw new Error(`GREYAction.GREYDirection must be a 'left'/'right'/'up'/'down', got ${action}`); - } + default: + throw new Error(`GREYAction.GREYDirection must be a 'left'/'right'/'up'/'down', got ${action}`); + } } // END sanitize_greyDirection function sanitize_greyContentEdge(action) { - switch (action) { - case 'left': - return 0; - case 'right': - return 1; - case 'top': - return 2; - case 'bottom': - return 3; + switch (action) { + case 'left': + return 0; + case 'right': + return 1; + case 'top': + return 2; + case 'bottom': + return 3; - default: - throw new Error(`GREYAction.GREYContentEdge must be a 'left'/'right'/'top'/'bottom', got ${action}`); - } + default: + throw new Error(`GREYAction.GREYContentEdge must be a 'left'/'right'/'top'/'bottom', got ${action}`); + } } // END sanitize_greyContentEdge function sanitize_uiAccessibilityTraits(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` - ); - } - } + 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; + return traits; } // END sanitize_uiAccessibilityTraits function sanitize_matcher(matcher) { - const originalMatcher = typeof matcher._call === 'function' ? matcher._call() : matcher._call; - return originalMatcher.type ? originalMatcher.value : originalMatcher; + const originalMatcher = typeof matcher._call === 'function' ? matcher._call() : matcher._call; + return originalMatcher.type ? originalMatcher.value : originalMatcher; } // END sanitize_matcher function sanitize_greyElementInteraction(value) { - return { - type: 'Invocation', - value - }; + return { + type: 'Invocation', + value + }; } // END sanitize_greyElementInteraction module.exports = { - sanitize_greyDirection, - sanitize_greyContentEdge, - sanitize_uiAccessibilityTraits, - sanitize_android_direction, - sanitize_android_edge, - sanitize_matcher, - sanitize_greyElementInteraction + sanitize_greyDirection, + sanitize_greyContentEdge, + sanitize_uiAccessibilityTraits, + sanitize_android_direction, + sanitize_android_edge, + sanitize_matcher, + sanitize_greyElementInteraction }; diff --git a/generation/core/type-checks.js b/generation/core/type-checks.js index 414afc52db..162a5eadeb 100644 --- a/generation/core/type-checks.js +++ b/generation/core/type-checks.js @@ -6,13 +6,13 @@ const isNumber = generateTypeCheck('number'); const isString = generateTypeCheck('string'); const isBoolean = generateTypeCheck('boolean'); const isPoint = [ - generateTypeCheck('object'), - generateTypeCheck('number', { selector: 'x' }), - generateTypeCheck('number', { selector: 'y' }) + generateTypeCheck('object'), + generateTypeCheck('number', { selector: 'x' }), + generateTypeCheck('number', { selector: 'y' }) ]; const isOneOf = generateIsOneOfCheck; function isGreyMatcher({ name }) { - return template(` + return template(` if ( typeof ARG !== "object" || ARG.type !== "Invocation" || @@ -23,12 +23,12 @@ function isGreyMatcher({ name }) { throw new Error('${name} should be a GREYMatcher, but got ' + JSON.stringify(ARG)); } `)({ - ARG: t.identifier(name) - }); + ARG: t.identifier(name) + }); } function isGreyAction({ name }) { - return template(` + return template(` if ( typeof ARG !== "object" || ARG.type !== "Invocation" || @@ -39,12 +39,12 @@ function isGreyAction({ name }) { throw new Error('${name} should be a GREYAction, but got ' + JSON.stringify(ARG)); } `)({ - ARG: t.identifier(name) - }); + ARG: t.identifier(name) + }); } function isGreyElementInteraction({ name }) { - return template(` + return template(` if ( typeof ARG !== "object" ) { @@ -52,11 +52,11 @@ function isGreyElementInteraction({ name }) { throw new Error('${name} should be a GREYElementInteraction, but got ' + JSON.stringify(ARG)); } `)({ - ARG: t.identifier(name) - }); + ARG: t.identifier(name) + }); } function isArray({ name }) { - return template(` + return template(` if ( (typeof ARG !== 'object') || (!ARG instanceof Array) @@ -64,13 +64,13 @@ if ( throw new Error('${name} must be an array, got ' + typeof ARG); } `)({ - ARG: t.identifier(name) - }); + ARG: t.identifier(name) + }); } function isOfClass(className) { - return ({ name }) => - template(` + return ({ name }) => + template(` if ( typeof ARG !== 'object' || typeof ARG.constructor !== 'function' || @@ -82,31 +82,31 @@ function isOfClass(className) { throw new Error('${name} should be an instance of ${className}, got "' + ARG + '", it appears that ' + additionalErrorInfo); } `)({ - ARG: t.identifier(name) - }); + ARG: t.identifier(name) + }); } function isDefined() { - return ({ name }) => - template(` + return ({ name }) => + template(` if (!ARG) { throw new Error('${name} should be truthy, but it is "' + ARG + '"'); } `)({ - ARG: t.identifier(name) - }); + ARG: t.identifier(name) + }); } module.exports = { - isNumber, - isString, - isBoolean, - isPoint, - isOneOf, - isGreyAction, - isGreyMatcher, - isArray, - isOfClass, - isGreyElementInteraction, - isDefined + isNumber, + isString, + isBoolean, + isPoint, + isOneOf, + isGreyAction, + isGreyMatcher, + isArray, + isOfClass, + isGreyElementInteraction, + isDefined }; diff --git a/generation/helpers.js b/generation/helpers.js index 2431b30113..e0642c7e4e 100644 --- a/generation/helpers.js +++ b/generation/helpers.js @@ -1,21 +1,21 @@ const t = require('babel-types'); function capitalizeFirstLetter(string) { - return string.charAt(0).toUpperCase() + string.slice(1); + return string.charAt(0).toUpperCase() + string.slice(1); } function methodNameToSnakeCase(name) { - return name - .split(':') - .map((item, index) => (index === 0 ? item : capitalizeFirstLetter(item))) - .join(''); + return name + .split(':') + .map((item, index) => (index === 0 ? item : capitalizeFirstLetter(item))) + .join(''); } function callGlobal(sanitizerName) { - return (argIdentifier) => t.callExpression(t.identifier(sanitizerName), [t.identifier(argIdentifier)]); + return (argIdentifier) => t.callExpression(t.identifier(sanitizerName), [t.identifier(argIdentifier)]); } module.exports = { - methodNameToSnakeCase, - callGlobal + methodNameToSnakeCase, + callGlobal }; diff --git a/generation/index.js b/generation/index.js index b7af555fe9..ce38dadb25 100755 --- a/generation/index.js +++ b/generation/index.js @@ -4,34 +4,34 @@ const fs = require('fs'); const generateIOSAdapters = require('./adapters/ios'); const iosFiles = { - '../detox/ios/EarlGrey/EarlGrey/Action/GREYActions.h': '../detox/src/ios/earlgreyapi/GREYActions.js', - '../detox/ios/Detox/GREYMatchers+Detox.h': '../detox/src/ios/earlgreyapi/GREYMatchers+Detox.js', - '../detox/ios/EarlGrey/EarlGrey/Matcher/GREYMatchers.h': '../detox/src/ios/earlgreyapi/GREYMatchers.js', - '../detox/ios/EarlGrey/EarlGrey/Core/GREYInteraction.h': '../detox/src/ios/earlgreyapi/GREYInteraction.js', - '../detox/ios/Detox/GREYCondition+Detox.h': '../detox/src/ios/earlgreyapi/GREYConditionDetox.js', - '../detox/ios/EarlGrey/EarlGrey/Synchronization/GREYCondition.h': '../detox/src/ios/earlgreyapi/GREYCondition.js', - '../detox/ios/Detox/GREYConfiguration+Detox.h': '../detox/src/ios/earlgreyapi/GREYConfigurationDetox.js', - '../detox/ios/EarlGrey/EarlGrey/Common/GREYConfiguration.h': '../detox/src/ios/earlgreyapi/GREYConfiguration.js' + '../detox/ios/EarlGrey/EarlGrey/Action/GREYActions.h': '../detox/src/ios/earlgreyapi/GREYActions.js', + '../detox/ios/Detox/GREYMatchers+Detox.h': '../detox/src/ios/earlgreyapi/GREYMatchers+Detox.js', + '../detox/ios/EarlGrey/EarlGrey/Matcher/GREYMatchers.h': '../detox/src/ios/earlgreyapi/GREYMatchers.js', + '../detox/ios/EarlGrey/EarlGrey/Core/GREYInteraction.h': '../detox/src/ios/earlgreyapi/GREYInteraction.js', + '../detox/ios/Detox/GREYCondition+Detox.h': '../detox/src/ios/earlgreyapi/GREYConditionDetox.js', + '../detox/ios/EarlGrey/EarlGrey/Synchronization/GREYCondition.h': '../detox/src/ios/earlgreyapi/GREYCondition.js', + '../detox/ios/Detox/GREYConfiguration+Detox.h': '../detox/src/ios/earlgreyapi/GREYConfigurationDetox.js', + '../detox/ios/EarlGrey/EarlGrey/Common/GREYConfiguration.h': '../detox/src/ios/earlgreyapi/GREYConfiguration.js' }; generateIOSAdapters(iosFiles); const externalFilesToDownload = { - 'android.support.test.espresso.action.ViewActions': '../detox/src/android/espressoapi/ViewActions.js' + 'android.support.test.espresso.action.ViewActions': '../detox/src/android/espressoapi/ViewActions.js' }; const generateAndroidAdapters = require('./adapters/android'); const downloadEspressoFileByClass = require('./utils/downloadEspresso'); const downloadedAndroidFilesMap = Object.entries(externalFilesToDownload).reduce( - (obj, [fullyQualifiedClass, dest]) => ({ - ...obj, - [downloadEspressoFileByClass(fullyQualifiedClass)]: dest - }), - {} + (obj, [fullyQualifiedClass, dest]) => ({ + ...obj, + [downloadEspressoFileByClass(fullyQualifiedClass)]: dest + }), + {} ); const androidFiles = { - ...downloadedAndroidFilesMap, - '../detox/android/detox/src/main/java/com/wix/detox/espresso/DetoxAction.java': '../detox/src/android/espressoapi/DetoxAction.js', - '../detox/android/detox/src/main/java/com/wix/detox/espresso/DetoxMatcher.java': '../detox/src/android/espressoapi/DetoxMatcher.js' + ...downloadedAndroidFilesMap, + '../detox/android/detox/src/main/java/com/wix/detox/espresso/DetoxAction.java': '../detox/src/android/espressoapi/DetoxAction.js', + '../detox/android/detox/src/main/java/com/wix/detox/espresso/DetoxMatcher.java': '../detox/src/android/espressoapi/DetoxMatcher.js' }; generateAndroidAdapters(androidFiles); @@ -39,9 +39,9 @@ generateAndroidAdapters(androidFiles); const allFiles = [...Object.values(iosFiles), ...Object.values(androidFiles)]; allFiles.forEach((file) => { - const text = fs.readFileSync(file, 'utf8'); - prettier.resolveConfig(file).then((options) => { - const formatted = prettier.format(text, options); - fs.writeFileSync(file, formatted); - }); + const text = fs.readFileSync(file, 'utf8'); + prettier.resolveConfig(file).then((options) => { + const formatted = prettier.format(text, options); + fs.writeFileSync(file, formatted); + }); }); diff --git a/generation/utils/downloadEspresso.js b/generation/utils/downloadEspresso.js index 3c999907bf..08422d3d27 100644 --- a/generation/utils/downloadEspresso.js +++ b/generation/utils/downloadEspresso.js @@ -4,14 +4,14 @@ const downloadFileSync = require('download-file-sync'); const fs = require('fs'); module.exports = function downloadEspresso(fullyQualifiedClass) { - const tmpDir = os.tmpdir(); - const path = fullyQualifiedClass.replace(/\./g, '/'); - const fileContent = downloadFileSync( - `http://android.googlesource.com/platform/frameworks/testing/+/android-support-test/espresso/core/src/main/java/${path}.java?format=TEXT` - ); + const tmpDir = os.tmpdir(); + const path = fullyQualifiedClass.replace(/\./g, '/'); + const fileContent = downloadFileSync( + `http://android.googlesource.com/platform/frameworks/testing/+/android-support-test/espresso/core/src/main/java/${path}.java?format=TEXT` + ); - const result = Buffer.from(fileContent, 'base64').toString('ascii'); - const filePath = tmpDir + '/download.java'; - fs.writeFileSync(filePath, result); - return filePath; + const result = Buffer.from(fileContent, 'base64').toString('ascii'); + const filePath = tmpDir + '/download.java'; + fs.writeFileSync(filePath, result); + return filePath; };