From 83fa11d98abb456240c866f5e6a180eb8b709cec Mon Sep 17 00:00:00 2001 From: Daniel Schmidt Date: Wed, 11 Jul 2018 09:04:13 +0200 Subject: [PATCH 1/3] remove weak type-guards --- .../src/android/espressoapi/DetoxAssertion.js | 8 ++++---- detox/src/android/espressoapi/DetoxMatcher.js | 20 +++++++++---------- detox/src/android/espressoapi/ViewActions.js | 2 +- .../__tests__/__snapshots__/android.js.snap | 4 ---- generation/__tests__/android.js | 17 ++++++++++++---- generation/core/type-checks.js | 2 +- 6 files changed, 29 insertions(+), 24 deletions(-) diff --git a/detox/src/android/espressoapi/DetoxAssertion.js b/detox/src/android/espressoapi/DetoxAssertion.js index 189461ff6d..1eaf7c056c 100644 --- a/detox/src/android/espressoapi/DetoxAssertion.js +++ b/detox/src/android/espressoapi/DetoxAssertion.js @@ -14,7 +14,7 @@ class DetoxAssertion { 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); + console.error('m should be an instance of Matcher, got "' + m + '", it appears that ' + additionalErrorInfo); } return { @@ -65,7 +65,7 @@ class DetoxAssertion { 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); + console.error('m should be an instance of Matcher, got "' + m + '", it appears that ' + additionalErrorInfo); } if (typeof timeoutSeconds !== "number") throw new Error("timeoutSeconds should be a number, but got " + (timeoutSeconds + (" (" + (typeof timeoutSeconds + ")")))); @@ -92,13 +92,13 @@ class DetoxAssertion { 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); + console.error('m should be an instance of Matcher, got "' + m + '", it appears that ' + additionalErrorInfo); } if (typeof searchMatcher !== 'object' || typeof searchMatcher.constructor !== 'function' || searchMatcher.constructor.name.indexOf('Matcher') === -1) { const isObject = typeof searchMatcher === 'object'; const additionalErrorInfo = isObject ? typeof searchMatcher.constructor === 'object' ? 'the constructor is no object' : 'it has a wrong class name: "' + searchMatcher.constructor.name + '"' : 'it is no object'; - throw new Error('searchMatcher should be an instance of Matcher, got "' + searchMatcher + '", it appears that ' + additionalErrorInfo); + console.error('searchMatcher should be an instance of Matcher, got "' + searchMatcher + '", it appears that ' + additionalErrorInfo); } return { diff --git a/detox/src/android/espressoapi/DetoxMatcher.js b/detox/src/android/espressoapi/DetoxMatcher.js index 918f5a8a6b..3422301c96 100644 --- a/detox/src/android/espressoapi/DetoxMatcher.js +++ b/detox/src/android/espressoapi/DetoxMatcher.js @@ -50,13 +50,13 @@ class DetoxMatcher { 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); + console.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); + console.error('m2 should be an instance of Matcher, got "' + m2 + '", it appears that ' + additionalErrorInfo); } return { @@ -79,13 +79,13 @@ class DetoxMatcher { 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); + console.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); + console.error('m2 should be an instance of Matcher, got "' + m2 + '", it appears that ' + additionalErrorInfo); } return { @@ -108,7 +108,7 @@ class DetoxMatcher { 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); + console.error('m should be an instance of Matcher, got "' + m + '", it appears that ' + additionalErrorInfo); } return { @@ -128,13 +128,13 @@ class DetoxMatcher { 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); + console.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); + console.error('ancestorMatcher should be an instance of Matcher, got "' + ancestorMatcher + '", it appears that ' + additionalErrorInfo); } return { @@ -157,13 +157,13 @@ class DetoxMatcher { 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); + console.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); + console.error('descendantMatcher should be an instance of Matcher, got "' + descendantMatcher + '", it appears that ' + additionalErrorInfo); } return { @@ -244,7 +244,7 @@ class DetoxMatcher { 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); + console.error('innerMatcher should be an instance of Matcher, got "' + innerMatcher + '", it appears that ' + additionalErrorInfo); } return { diff --git a/detox/src/android/espressoapi/ViewActions.js b/detox/src/android/espressoapi/ViewActions.js index 81a1bfdacc..b6e23ffb11 100644 --- a/detox/src/android/espressoapi/ViewActions.js +++ b/detox/src/android/espressoapi/ViewActions.js @@ -271,7 +271,7 @@ class ViewActions { if (typeof desiredStateMatcher !== 'object' || typeof desiredStateMatcher.constructor !== 'function' || desiredStateMatcher.constructor.name.indexOf('Matcher') === -1) { const isObject = typeof desiredStateMatcher === 'object'; const additionalErrorInfo = isObject ? typeof desiredStateMatcher.constructor === 'object' ? 'the constructor is no object' : 'it has a wrong class name: "' + desiredStateMatcher.constructor.name + '"' : 'it is no object'; - throw new Error('desiredStateMatcher should be an instance of Matcher, got "' + desiredStateMatcher + '", it appears that ' + additionalErrorInfo); + console.error('desiredStateMatcher should be an instance of Matcher, got "' + desiredStateMatcher + '", it appears that ' + additionalErrorInfo); } if (typeof maxAttempts !== "number") throw new Error("maxAttempts should be a number, but got " + (maxAttempts + (" (" + (typeof maxAttempts + ")")))); diff --git a/generation/__tests__/__snapshots__/android.js.snap b/generation/__tests__/__snapshots__/android.js.snap index a3e3aa9439..6ff5be163f 100644 --- a/generation/__tests__/__snapshots__/android.js.snap +++ b/generation/__tests__/__snapshots__/android.js.snap @@ -37,7 +37,3 @@ Object { }, } `; - -exports[`Android generation validation Matcher should fail getting no object 1`] = `"m1 should be an instance of Matcher, got \\"I am a string\\", it appears that it is no object"`; - -exports[`Android generation validation Matcher should fail with a wrong class 1`] = `"m1 should be an instance of Matcher, got \\"[object Object]\\", it appears that it has a wrong class name: \\"AnotherClass\\""`; diff --git a/generation/__tests__/android.js b/generation/__tests__/android.js index 44fbb519e8..d8ba6f8b9a 100644 --- a/generation/__tests__/android.js +++ b/generation/__tests__/android.js @@ -65,19 +65,28 @@ describe('Android generation', () => { describe('validation', () => { describe('Matcher', () => { - it('should fail getting no object', () => { + it('should log that it gets no object', () => { + const spy = jest.spyOn(console, "error"); expect(() => { ExampleClass.matcherForAnd('I am a string', 'I am one too'); - }).toThrowErrorMatchingSnapshot(); + }).not.toThrow(); + + + expect(spy).toHaveBeenCalled(); + spy.mockRestore(); }); - it('should fail with a wrong class', () => { + it('should log with a wrong class', () => { + const spy = jest.spyOn(console, "error"); class AnotherClass {} const x = new AnotherClass(); expect(() => { ExampleClass.matcherForAnd(x, x); - }).toThrowErrorMatchingSnapshot(); + }).not.toThrow(); + + expect(spy).toHaveBeenCalled(); + spy.mockRestore(); }); it("should succeed with the 'right' class", () => { diff --git a/generation/core/type-checks.js b/generation/core/type-checks.js index 162a5eadeb..34d17eb978 100644 --- a/generation/core/type-checks.js +++ b/generation/core/type-checks.js @@ -79,7 +79,7 @@ function isOfClass(className) { const isObject = typeof ARG === 'object'; const additionalErrorInfo = isObject ? (typeof ARG.constructor === 'object' ? 'the constructor is no object' : 'it has a wrong class name: "' + ARG.constructor.name +'"') : 'it is no object'; - throw new Error('${name} should be an instance of ${className}, got "' + ARG + '", it appears that ' + additionalErrorInfo); + console.error('${name} should be an instance of ${className}, got "' + ARG + '", it appears that ' + additionalErrorInfo); } `)({ ARG: t.identifier(name) From ba457e06975af75c859867337f5926a5657b949b Mon Sep 17 00:00:00 2001 From: Daniel Schmidt Date: Wed, 11 Jul 2018 09:04:54 +0200 Subject: [PATCH 2/3] make sure we dont unwrap the call if it is already unwrapped --- detox/src/android/espressoapi/DetoxAssertion.js | 4 ++++ detox/src/android/espressoapi/DetoxMatcher.js | 4 ++++ detox/src/android/espressoapi/ViewActions.js | 4 ++++ generation/__tests__/global-functions.js | 5 +++++ generation/core/global-functions.js | 4 ++++ 5 files changed, 21 insertions(+) diff --git a/detox/src/android/espressoapi/DetoxAssertion.js b/detox/src/android/espressoapi/DetoxAssertion.js index 1eaf7c056c..87b70ec160 100644 --- a/detox/src/android/espressoapi/DetoxAssertion.js +++ b/detox/src/android/espressoapi/DetoxAssertion.js @@ -6,6 +6,10 @@ function sanitize_matcher(matcher) { + if (!matcher._call) { + return matcher; + } + const originalMatcher = typeof matcher._call === 'function' ? matcher._call() : matcher._call; return originalMatcher.type ? originalMatcher.value : originalMatcher; } diff --git a/detox/src/android/espressoapi/DetoxMatcher.js b/detox/src/android/espressoapi/DetoxMatcher.js index 3422301c96..933834f5ca 100644 --- a/detox/src/android/espressoapi/DetoxMatcher.js +++ b/detox/src/android/espressoapi/DetoxMatcher.js @@ -6,6 +6,10 @@ function sanitize_matcher(matcher) { + if (!matcher._call) { + return matcher; + } + const originalMatcher = typeof matcher._call === 'function' ? matcher._call() : matcher._call; return originalMatcher.type ? originalMatcher.value : originalMatcher; } diff --git a/detox/src/android/espressoapi/ViewActions.js b/detox/src/android/espressoapi/ViewActions.js index b6e23ffb11..02d2c91794 100644 --- a/detox/src/android/espressoapi/ViewActions.js +++ b/detox/src/android/espressoapi/ViewActions.js @@ -6,6 +6,10 @@ function sanitize_matcher(matcher) { + if (!matcher._call) { + return matcher; + } + const originalMatcher = typeof matcher._call === 'function' ? matcher._call() : matcher._call; return originalMatcher.type ? originalMatcher.value : originalMatcher; } diff --git a/generation/__tests__/global-functions.js b/generation/__tests__/global-functions.js index 30e25b870d..785a64939f 100644 --- a/generation/__tests__/global-functions.js +++ b/generation/__tests__/global-functions.js @@ -124,6 +124,11 @@ describe('globals', () => { }; expect(globals.sanitize_matcher(matcherLikeObj)).toBe('I am a call'); }); + + it('should not get _call property if it is not present', () => { + const unwrappedMatcher = "I am a call"; + expect(globals.sanitize_matcher(unwrappedMatcher)).toBe('I am a call'); + }) }); describe('sanitize_greyElementInteraction', () => { diff --git a/generation/core/global-functions.js b/generation/core/global-functions.js index ffec773c90..1d670ee486 100644 --- a/generation/core/global-functions.js +++ b/generation/core/global-functions.js @@ -127,6 +127,10 @@ function sanitize_uiAccessibilityTraits(value) { } // END sanitize_uiAccessibilityTraits function sanitize_matcher(matcher) { + if (!matcher._call) { + return matcher; + } + const originalMatcher = typeof matcher._call === 'function' ? matcher._call() : matcher._call; return originalMatcher.type ? originalMatcher.value : originalMatcher; } // END sanitize_matcher From b89e24ffd1205cc7f41634ff77ea3757867c8cea Mon Sep 17 00:00:00 2001 From: Daniel Schmidt Date: Wed, 11 Jul 2018 09:05:04 +0200 Subject: [PATCH 3/3] add extra test --- detox/src/invoke/Invoke.test.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/detox/src/invoke/Invoke.test.js b/detox/src/invoke/Invoke.test.js index 789136140e..d4cf7bee8d 100644 --- a/detox/src/invoke/Invoke.test.js +++ b/detox/src/invoke/Invoke.test.js @@ -6,6 +6,14 @@ describe('call', () => { target: { type: 'Invocation', value: 'fn' }, method: 'method', args: [] - }) + }); + }); + + it('handles arguments as thunk', () => { + expect(call('fn', 'method', 'no-thunk', () => 'a-thunk')()).toEqual({ + target: 'fn', + method: 'method', + args: ['no-thunk', { type: 'Invocation', value: 'a-thunk' }] + }); }); });