From 1aa2e032f9f42fdeba5bccff816ca44860339782 Mon Sep 17 00:00:00 2001 From: Salakar Date: Sat, 24 Mar 2018 05:53:49 +0000 Subject: [PATCH] wip --- tests-new/README.md | 12 + tests-new/android/app/google-services.json | 97 +++++--- tests-new/app.js | 2 +- tests-new/bridge/env/node/index.js | 49 ++-- tests-new/bridge/env/node/vm.js | 86 ++++++- tests-new/bridge/env/node/ws.js | 2 +- tests-new/bridge/env/rn.js | 10 + tests-new/e2e/auth/auth.js | 241 +++++++++++++++++++ tests-new/e2e/bridge.spec.js | 62 ++--- tests-new/e2e/example.spec.js | 60 ----- tests-new/e2e/firestore/transactions.e2e.js | 78 ++++++ tests-new/e2e/mocha.opts | 1 + tests-new/package-lock.json | 250 ++++++++++++++++++++ tests-new/package.json | 5 + 14 files changed, 789 insertions(+), 166 deletions(-) create mode 100644 tests-new/e2e/auth/auth.js delete mode 100755 tests-new/e2e/example.spec.js create mode 100644 tests-new/e2e/firestore/transactions.e2e.js diff --git a/tests-new/README.md b/tests-new/README.md index b7421b50..c487929e 100755 --- a/tests-new/README.md +++ b/tests-new/README.md @@ -81,3 +81,15 @@ CPU/ABI: null (null) Path: /Users/mike/.android/avd/Actually_THIS_one.avd Error: Failed to parse properties from /Users/mike/.android/avd/Actually_THIS_one.avd/config.ini + +#### Running specific tests + +Add a `--grep` to e2e/mocha.opts file, e.g. `--grep auth` for all tests that have auth in the file path or tests descriptions. + +#### Running Node debugger + +Add `--inspect` to e2e/mocha.opts file + +To open node debugger tools on chrome navigate to chrome://inspect/#devices and click the `Open dedicated DevTools for Node` link. + +Add the default connection of `localhost:9229` if you haven't already - then the debugger will automatically connect everytime you start tests with inspect flag. diff --git a/tests-new/android/app/google-services.json b/tests-new/android/app/google-services.json index 5181bffd..4828b6f8 100644 --- a/tests-new/android/app/google-services.json +++ b/tests-new/android/app/google-services.json @@ -1,38 +1,43 @@ { "project_info": { - "project_number": "17067372085", - "firebase_url": "https://rnfirebase-5579a.firebaseio.com", - "project_id": "rnfirebase", - "storage_bucket": "rnfirebase.appspot.com" + "project_number": "305229645282", + "firebase_url": "https://rnfirebase-b9ad4.firebaseio.com", + "project_id": "rnfirebase-b9ad4", + "storage_bucket": "rnfirebase-b9ad4.appspot.com" }, "client": [ { "client_info": { - "mobilesdk_app_id": "1:17067372085:android:efe37851d57e1d05", + "mobilesdk_app_id": "1:305229645282:android:efe37851d57e1d05", "android_client_info": { "package_name": "com.reactnativefirebasedemo" } }, "oauth_client": [ { - "client_id": "17067372085-ltes2e70ehnlp4s5bl7uljuqvjul2l9s.apps.googleusercontent.com", + "client_id": "305229645282-5fgq5kq024eqpvji5o0i7jq7q7bnnpl9.apps.googleusercontent.com", "client_type": 1, "android_info": { "package_name": "com.reactnativefirebasedemo", - "certificate_hash": "34d770365973b7580e04dab50692506aff7bd32f" + "certificate_hash": "1f92c8aab0a091a3aaccfa144bf402bb97273494" } }, { - "client_id": "17067372085-n572o9802h9jbv9oo60h53117pk9333k.apps.googleusercontent.com", + "client_id": "305229645282-cvp6v0iogjjuuvi5g2dcb3lrr9n884a3.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "com.reactnativefirebasedemo", + "certificate_hash": "859f2afac694e21d26ca67e750c9875107c2e755" + } + }, + { + "client_id": "305229645282-j8ij0jev9ut24odmlk9i215pas808ugn.apps.googleusercontent.com", "client_type": 3 } ], "api_key": [ { - "current_key": "AIzaSyB-z0ytgXRRiClvslJl0tp-KbhDub9o6AM" - }, - { - "current_key": "AIzaSyAJw8mR1fPcEYC9ouZbkCStJufcCQrhmjQ" + "current_key": "AIzaSyCzbBYFyX8d6VdSu7T4s10IWYbPc-dguwM" } ], "services": { @@ -43,15 +48,15 @@ "status": 2, "other_platform_oauth_client": [ { - "client_id": "17067372085-n572o9802h9jbv9oo60h53117pk9333k.apps.googleusercontent.com", - "client_type": 3 - }, - { - "client_id": "17067372085-siujfe334vool17t2mtrmjrsgl81nhd9.apps.googleusercontent.com", + "client_id": "305229645282-t29pn6o2t7se1f7rvrfsll4r0pvd6fb6.apps.googleusercontent.com", "client_type": 2, "ios_info": { "bundle_id": "com.invertase.RNFirebaseTests" } + }, + { + "client_id": "305229645282-j8ij0jev9ut24odmlk9i215pas808ugn.apps.googleusercontent.com", + "client_type": 3 } ] }, @@ -62,31 +67,28 @@ }, { "client_info": { - "mobilesdk_app_id": "1:17067372085:android:af36d4d29a83e04c", + "mobilesdk_app_id": "1:305229645282:android:c9de0f8cb930daf5", "android_client_info": { - "package_name": "com.testing" + "package_name": "com.reactnativefirebaseexamples" } }, "oauth_client": [ { - "client_id": "17067372085-066pi4ln798odtdrifoktb3mea9dtipt.apps.googleusercontent.com", + "client_id": "305229645282-hu7tr12kgn5lfhq82l51b1sh66aaue5f.apps.googleusercontent.com", "client_type": 1, "android_info": { - "package_name": "com.testing", - "certificate_hash": "34d770365973b7580e04dab50692506aff7bd32f" + "package_name": "com.reactnativefirebaseexamples", + "certificate_hash": "1f92c8aab0a091a3aaccfa144bf402bb97273494" } }, { - "client_id": "17067372085-n572o9802h9jbv9oo60h53117pk9333k.apps.googleusercontent.com", + "client_id": "305229645282-j8ij0jev9ut24odmlk9i215pas808ugn.apps.googleusercontent.com", "client_type": 3 } ], "api_key": [ { - "current_key": "AIzaSyB-z0ytgXRRiClvslJl0tp-KbhDub9o6AM" - }, - { - "current_key": "AIzaSyAJw8mR1fPcEYC9ouZbkCStJufcCQrhmjQ" + "current_key": "AIzaSyCzbBYFyX8d6VdSu7T4s10IWYbPc-dguwM" } ], "services": { @@ -97,15 +99,15 @@ "status": 2, "other_platform_oauth_client": [ { - "client_id": "17067372085-n572o9802h9jbv9oo60h53117pk9333k.apps.googleusercontent.com", - "client_type": 3 - }, - { - "client_id": "17067372085-siujfe334vool17t2mtrmjrsgl81nhd9.apps.googleusercontent.com", + "client_id": "305229645282-t29pn6o2t7se1f7rvrfsll4r0pvd6fb6.apps.googleusercontent.com", "client_type": 2, "ios_info": { "bundle_id": "com.invertase.RNFirebaseTests" } + }, + { + "client_id": "305229645282-j8ij0jev9ut24odmlk9i215pas808ugn.apps.googleusercontent.com", + "client_type": 3 } ] }, @@ -113,6 +115,37 @@ "status": 2 } } + }, + { + "client_info": { + "mobilesdk_app_id": "1:305229645282:android:af36d4d29a83e04c", + "android_client_info": { + "package_name": "com.testing" + } + }, + "oauth_client": [ + { + "client_id": "305229645282-j8ij0jev9ut24odmlk9i215pas808ugn.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyCzbBYFyX8d6VdSu7T4s10IWYbPc-dguwM" + } + ], + "services": { + "analytics_service": { + "status": 1 + }, + "appinvite_service": { + "status": 1, + "other_platform_oauth_client": [] + }, + "ads_service": { + "status": 2 + } + } } ], "configuration_version": "1" diff --git a/tests-new/app.js b/tests-new/app.js index 80af3871..224c6eb7 100755 --- a/tests-new/app.js +++ b/tests-new/app.js @@ -23,7 +23,7 @@ class Root extends Component { render() { return ( - React Native Firebase Test App + React Native Firebase Test App ); } diff --git a/tests-new/bridge/env/node/index.js b/tests-new/bridge/env/node/index.js index 8a506d01..31905726 100644 --- a/tests-new/bridge/env/node/index.js +++ b/tests-new/bridge/env/node/index.js @@ -2,13 +2,13 @@ const detox = require('detox'); const vm = require('./vm'); const ws = require('./ws'); +// TODO each reload/relaunch should capture __coverage__ + const detoxOriginalInit = detox.init.bind(detox); const detoxOriginalCleanup = detox.cleanup.bind(detox); -let detoxOriginalReloadReactNative = null; let bridgeReady = false; process.on('rn-ready', () => { - // console.log('READY', true); bridgeReady = true; }); @@ -19,37 +19,38 @@ function onceBridgeReady() { }); } +function shimDevice() { + // reloadReactNative + const detoxOriginalReloadReactNative = device.reloadReactNative.bind(device); + device.reloadReactNative = async () => { + bridgeReady = false; + global.bridge.reload(); + return onceBridgeReady(); + }; + + // launchApp + const detoxOriginalLaunchApp = device.launchApp.bind(device); + device.launchApp = async (...args) => { + bridgeReady = false; + await detoxOriginalLaunchApp(...args); + return onceBridgeReady(); + }; + + // todo other device methods +} + detox.init = async (...args) => { bridgeReady = false; - console.log('detox.init.start'); - return detoxOriginalInit(...args).then(() => { - console.log('detox.init.complete'); - - detoxOriginalReloadReactNative = device.reloadReactNative.bind(device); - device.reloadReactNative = async () => { - console.log('reloadReactNative.start'); - bridgeReady = false; - // return device.launchApp({ newInstance: true }).then(() => { - global.bridge.reload(); - - return onceBridgeReady(); - }; - + shimDevice(); return onceBridgeReady(); }); }; -detox.cleanup = async (...args) => { - console.log('detox.cleanup'); - - return detoxOriginalCleanup(...args).then(() => { - console.log('detox.cleanup.end'); - +detox.cleanup = async (...args) => + detoxOriginalCleanup(...args).then(() => { ws.close(); - process.exit(); }); -}; global.bridge = { _ws: null, diff --git a/tests-new/bridge/env/node/vm.js b/tests-new/bridge/env/node/vm.js index 6185bc08..da4a33d3 100644 --- a/tests-new/bridge/env/node/vm.js +++ b/tests-new/bridge/env/node/vm.js @@ -25,11 +25,12 @@ function sendResult(replyID, result) { } /** - * + * TODO * @param message */ -function sendError(message) { - console.error(message); +function sendError(error) { + console.log('error'); + throw error; } /** @@ -67,13 +68,80 @@ function getScript(src, callback) { }); } +function consoleShim() { + return { + ...console, + log(...args) { + if ( + args[0] && + typeof args[0] === 'string' && + args[0].startsWith('Running application "') + ) { + return; + } + + if ( + args[0] && + typeof args[0] === 'string' && + args[0].startsWith('Deprecated') + ) { + return; + } + console.log(...args); + }, + warn(...args) { + if ( + args[0] && + typeof args[0] === 'string' && + args[0].startsWith('Running application "') + ) { + return; + } + + if ( + args[0] && + typeof args[0] === 'string' && + args[0].startsWith('Deprecated') + ) { + return; + } + console.log(...args); + }, + }; +} + process.on('ws-message', request => { // console.log(request.method); switch (request.method) { case 'prepareJSRuntime': + if (currentContext) { + try { + for (const name in currentContext.__fbBatchedBridge) { + currentContext.__fbBatchedBridge[name] = undefined; + delete currentContext.__fbBatchedBridge[name]; + } + + for (const name in currentContext.__fbGenNativeModule) { + currentContext.__fbGenNativeModule[name] = undefined; + delete currentContext.__fbGenNativeModule[name]; + } + + for (const name in currentContext.__fbBatchedBridgeConfig) { + currentContext.__fbBatchedBridgeConfig[name] = undefined; + delete currentContext.__fbBatchedBridgeConfig[name]; + } + + for (const name in currentContext) { + currentContext[name] = undefined; + delete currentContext[name]; + } + } catch (e) { + console.error(e); + } + } currentContext = undefined; currentContext = createContext({ - console, + console: consoleShim(), __bridgeNode: { ready() { process.emit('rn-ready'); @@ -128,7 +196,7 @@ process.on('ws-message', request => { try { script.runInContext(currentContext, TEMP_BUNDLE_PATH); } catch (e) { - sendError(`Failed to exec script: ${e.message}`); + sendError(e); } sendResult(request.id); }); @@ -148,9 +216,11 @@ process.on('ws-message', request => { ); } } catch (e) { - sendError( - `Failed while making a call ${request.method}:::${e.message}` - ); + if (request.method !== '$disconnected') { + sendError( + `Failed while making a call ${request.method}:::${e.message}` + ); + } } finally { sendResult(request.id, JSON.stringify(returnValue)); } diff --git a/tests-new/bridge/env/node/ws.js b/tests-new/bridge/env/node/ws.js index 0d4c4684..daf9745d 100644 --- a/tests-new/bridge/env/node/ws.js +++ b/tests-new/bridge/env/node/ws.js @@ -6,7 +6,7 @@ const ws = new WebSocket( ); ws.onmessage = message => process.emit('ws-message', JSON.parse(message.data)); -ws.onopen = () => console.log('WS open'); +// ws.onopen = () => console.log('WS open'); ws.onclose = event => (!event.wasClean ? console.log('WS close', event) : ''); module.exports = ws; diff --git a/tests-new/bridge/env/rn.js b/tests-new/bridge/env/rn.js index 39763587..87baab0e 100644 --- a/tests-new/bridge/env/rn.js +++ b/tests-new/bridge/env/rn.js @@ -1,6 +1,10 @@ import reactNative, { Platform, NativeModules } from 'react-native'; import RNRestart from 'react-native-restart'; // Import package from node modules +require('sinon'); +require('should-sinon'); +require('should'); + const bridgeNode = global.__bridgeNode; // https://github.com/ptmt/react-native-macos/blob/master/React/Modules/RCTDevSettings.mm @@ -26,3 +30,9 @@ export default { } }, }; + +// keep alive +setInterval(() => { + // I don't do anything lol + // BUT i am needed - otherwise RN's batch bridge starts to hang in detox... ??? +}, 50); diff --git a/tests-new/e2e/auth/auth.js b/tests-new/e2e/auth/auth.js new file mode 100644 index 00000000..447ee416 --- /dev/null +++ b/tests-new/e2e/auth/auth.js @@ -0,0 +1,241 @@ +const sinon = require('sinon'); +require('should-sinon'); +const should = require('should'); + +const randomString = (length, chars) => { + let mask = ''; + if (chars.indexOf('a') > -1) mask += 'abcdefghijklmnopqrstuvwxyz'; + if (chars.indexOf('A') > -1) mask += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + if (chars.indexOf('#') > -1) mask += '0123456789'; + if (chars.indexOf('!') > -1) mask += '~`!@#$%^&*()_+-={}[]:";\'<>?,./|\\'; + let result = ''; + for (let i = length; i > 0; --i) { + result += mask[Math.round(Math.random() * (mask.length - 1))]; + } + return result; +}; + +describe('.auth()', () => { + beforeEach(async () => { + await device.reloadReactNative(); + }); + + describe('.signInAnonymously()', () => { + it('it should sign in anonymously', () => { + const successCb = currentUser => { + debugger; + currentUser.should.be.an.Object(); + currentUser.uid.should.be.a.String(); + currentUser.toJSON().should.be.an.Object(); + should.equal(currentUser.toJSON().email, null); + currentUser.isAnonymous.should.equal(true); + currentUser.providerId.should.equal('firebase'); + + currentUser.should.equal(bridge.module.auth().currentUser); + + return bridge.module.auth().signOut(); + }; + + return bridge.module + .auth() + .signInAnonymously() + .then(successCb); + }); + }); + + describe('.signInAnonymouslyAndRetrieveData()', () => { + it('it should sign in anonymously', () => { + const successCb = currentUserCredential => { + const currentUser = currentUserCredential.user; + currentUser.should.be.an.Object(); + currentUser.uid.should.be.a.String(); + currentUser.toJSON().should.be.an.Object(); + should.equal(currentUser.toJSON().email, null); + currentUser.isAnonymous.should.equal(true); + currentUser.providerId.should.equal('firebase'); + currentUser.should.equal(bridge.module.auth().currentUser); + + const { additionalUserInfo } = currentUserCredential; + additionalUserInfo.should.be.an.Object(); + + return bridge.module.auth().signOut(); + }; + + return bridge.module + .auth() + .signInAnonymouslyAndRetrieveData() + .then(successCb); + }); + }); + + describe('.signInWithEmailAndPassword()', () => { + it('it should login with email and password', () => { + const email = 'test@test.com'; + const pass = 'test1234'; + + const successCb = currentUser => { + currentUser.should.be.an.Object(); + currentUser.uid.should.be.a.String(); + currentUser.toJSON().should.be.an.Object(); + currentUser.toJSON().email.should.eql('test@test.com'); + currentUser.isAnonymous.should.equal(false); + currentUser.providerId.should.equal('firebase'); + currentUser.should.equal(bridge.module.auth().currentUser); + + return bridge.module.auth().signOut(); + }; + + return bridge.module + .auth() + .signInWithEmailAndPassword(email, pass) + .then(successCb); + }); + + it('it should error on login if user is disabled', () => { + const email = 'disabled@account.com'; + const pass = 'test1234'; + + const successCb = () => Promise.reject(new Error('Did not error.')); + + const failureCb = error => { + error.code.should.equal('auth/user-disabled'); + error.message.should.equal( + 'The user account has been disabled by an administrator.' + ); + return Promise.resolve(); + }; + + return bridge.module + .auth() + .signInWithEmailAndPassword(email, pass) + .then(successCb) + .catch(failureCb); + }); + + it('it should error on login if password incorrect', () => { + const email = 'test@test.com'; + const pass = 'test1234666'; + + const successCb = () => Promise.reject(new Error('Did not error.')); + + const failureCb = error => { + error.code.should.equal('auth/wrong-password'); + error.message.should.equal( + 'The password is invalid or the user does not have a password.' + ); + return Promise.resolve(); + }; + + return bridge.module + .auth() + .signInWithEmailAndPassword(email, pass) + .then(successCb) + .catch(failureCb); + }); + + it('it should error on login if user not found', () => { + const email = 'randomSomeone@fourOhFour.com'; + const pass = 'test1234'; + + const successCb = () => Promise.reject(new Error('Did not error.')); + + const failureCb = error => { + error.code.should.equal('auth/user-not-found'); + error.message.should.equal( + 'There is no user record corresponding to this identifier. The user may have been deleted.' + ); + return Promise.resolve(); + }; + + return bridge.module + .auth() + .signInWithEmailAndPassword(email, pass) + .then(successCb) + .catch(failureCb); + }); + }); + + describe('.onAuthStateChanged()', () => { + it('calls callback with the current user and when auth state changes', async () => { + await bridge.module.auth().signInAnonymouslyAndRetrieveData(); + + // Test + const callback = sinon.spy(); + + let unsubscribe; + await new Promise(resolve => { + unsubscribe = bridge.module.auth().onAuthStateChanged(user => { + callback(user); + resolve(); + }); + }); + + callback.should.be.calledWith(bridge.module.auth().currentUser); + callback.should.be.calledOnce(); + + // Sign out + + await bridge.module.auth().signOut(); + + await new Promise(resolve => { + setTimeout(() => resolve(), 100); + }); + + // Assertions + + callback.should.be.calledWith(null); + callback.should.be.calledTwice(); + + // Tear down + + unsubscribe(); + }); + + it('stops listening when unsubscribe called', async () => { + await bridge.module.auth().signInAnonymouslyAndRetrieveData(); + + // Test + const callback = sinon.spy(); + + let unsubscribe; + await new Promise(resolve => { + unsubscribe = bridge.module.auth().onAuthStateChanged(user => { + callback(user); + resolve(); + }); + }); + + callback.should.be.calledWith(bridge.module.auth().currentUser); + callback.should.be.calledOnce(); + + // Sign out + + await bridge.module.auth().signOut(); + + await new Promise(resolve => { + setTimeout(() => resolve(), 100); + }); + + // Assertions + + // callback.should.be.calledWith(null); + callback.should.be.calledTwice(); + + // Unsubscribe + + unsubscribe(); + + // Sign back in + + await bridge.module.auth().signInAnonymouslyAndRetrieveData(); + + // Assertions + + callback.should.be.calledTwice(); + + // Tear down + + await bridge.module.auth().signOut(); + }); + }); +}); diff --git a/tests-new/e2e/bridge.spec.js b/tests-new/e2e/bridge.spec.js index 98aaa7a8..e9b007f9 100755 --- a/tests-new/e2e/bridge.spec.js +++ b/tests-new/e2e/bridge.spec.js @@ -1,60 +1,42 @@ -// describe('Example', () => { -// beforeEach(async () => { -// await device.reloadReactNative(); -// }); -// -// it('should have welcome screen', async () => { -// await expect(element(by.id('welcome'))).toBeVisible(); -// }); -// -// it('should show hello screen after tap', async () => { -// await element(by.id('hello_button')).tap(); -// await expect(element(by.text('Hello!!!'))).toBeVisible(); -// }); -// -// it('should show world screen after tap', async () => { -// await element(by.id('world_button')).tap(); -// await expect(element(by.text('World!!!'))).toBeVisible(); -// }); -// }); +const should = require('should'); -describe('should work inside node', () => { +describe('bridge', () => { beforeEach(async () => { await device.reloadReactNative(); }); - it('should provide bridge global', () => { - const firebase = bridge.module; - - + it('should provide -> global.bridge', () => { + should(bridge).not.be.undefined(); return Promise.resolve(); }); - it('should require 2', () => { - const firebase = bridge.module; - // const { Platform } = bridge.rnModule; - // should.equal(firebase.auth.nativeModuleExists, true); + it('should provide -> global.bridge.module', () => { + should(bridge.module).not.be.undefined(); return Promise.resolve(); }); - it('should require 3', () => { - const firebase = bridge.module; - // const { Platform } = bridge.rnModule; - // should.equal(firebase.auth.nativeModuleExists, true); + it('should provide -> global.bridge.rn', () => { + should(bridge.rn).not.be.undefined(); + should(bridge.rn.Platform.OS).be.a.String(); + should(bridge.rn.Platform.OS).equal(device.getPlatform()); return Promise.resolve(); }); - it('should require 4', () => { - const firebase = bridge.module; - // const { Platform } = bridge.rnModule; - // should.equal(firebase.auth.nativeModuleExists, true); + it('should provide -> global.reload and allow reloadReactNative usage', async () => { + should(bridge.reload).be.a.Function(); + // and check it works without breaking anything + await device.reloadReactNative(); + should(bridge.reload).be.a.Function(); return Promise.resolve(); }); - it('should require 5', () => { - const firebase = bridge.module; - // const { Platform } = bridge.rnModule; - // should.equal(firebase.auth.nativeModuleExists, true); + it('should allow detox to launchApp without breaking remote debug', async () => { + await device.launchApp({ newInstance: true }); + should(bridge.module).not.be.undefined(); + should(bridge.reload).be.a.Function(); + should(bridge.rn).not.be.undefined(); + should(bridge.rn.Platform.OS).be.a.String(); + should(bridge.rn.Platform.OS).equal(device.getPlatform()); return Promise.resolve(); }); }); diff --git a/tests-new/e2e/example.spec.js b/tests-new/e2e/example.spec.js deleted file mode 100755 index 5b4e6e74..00000000 --- a/tests-new/e2e/example.spec.js +++ /dev/null @@ -1,60 +0,0 @@ -// describe('Example', () => { -// beforeEach(async () => { -// await device.reloadReactNative(); -// }); -// -// it('should have welcome screen', async () => { -// await expect(element(by.id('welcome'))).toBeVisible(); -// }); -// -// it('should show hello screen after tap', async () => { -// await element(by.id('hello_button')).tap(); -// await expect(element(by.text('Hello!!!'))).toBeVisible(); -// }); -// -// it('should show world screen after tap', async () => { -// await element(by.id('world_button')).tap(); -// await expect(element(by.text('World!!!'))).toBeVisible(); -// }); -// }); - -describe('should work inside node', () => { - beforeEach(async () => { - await device.reloadReactNative(); - }); - - it('should require', () => { - const firebase = bridge.module; - - - return Promise.resolve(); - }); - - it('should require 2', () => { - const firebase = bridge.module; - // const { Platform } = bridge.rnModule; - // should.equal(firebase.auth.nativeModuleExists, true); - return Promise.resolve(); - }); - - it('should require 3', () => { - const firebase = bridge.module; - // const { Platform } = bridge.rnModule; - // should.equal(firebase.auth.nativeModuleExists, true); - return Promise.resolve(); - }); - - it('should require 4', () => { - const firebase = bridge.module; - // const { Platform } = bridge.rnModule; - // should.equal(firebase.auth.nativeModuleExists, true); - return Promise.resolve(); - }); - - it('should require 5', () => { - const firebase = bridge.module; - // const { Platform } = bridge.rnModule; - // should.equal(firebase.auth.nativeModuleExists, true); - return Promise.resolve(); - }); -}); diff --git a/tests-new/e2e/firestore/transactions.e2e.js b/tests-new/e2e/firestore/transactions.e2e.js new file mode 100644 index 00000000..f6d716b1 --- /dev/null +++ b/tests-new/e2e/firestore/transactions.e2e.js @@ -0,0 +1,78 @@ +const should = require('should'); + +describe('firestore.runTransaction', () => { + beforeEach(async () => { + await device.reloadReactNative(); + }); + + it('should set, update and delete transactionally and allow a return value', async () => { + const firebase = bridge.module; + let deleteMe = false; + const firestore = firebase.firestore(); + + const docRef = firestore + .collection('transactions') + .doc(Date.now().toString()); + + const updateFunction = async transaction => { + const doc = await transaction.get(docRef); + if (doc.exists && deleteMe) { + transaction.delete(docRef); + return 'bye'; + } + + if (!doc.exists) { + transaction.set(docRef, { value: 1 }); + return 1; + } + + const newValue = doc.data().value + 1; + + if (newValue > 2) { + return Promise.reject(new Error('Value should not be greater than 2!')); + } + + transaction.update(docRef, { + value: newValue, + somethingElse: 'update', + }); + + return newValue; + }; + + // set tests + const val1 = await firestore.runTransaction(updateFunction); + should.equal(val1, 1); + const doc1 = await docRef.get(); + doc1.data().value.should.equal(1); + should.equal(doc1.data().somethingElse, undefined); + + // update + const val2 = await firestore.runTransaction(updateFunction); + should.equal(val2, 2); + const doc2 = await docRef.get(); + doc2.data().value.should.equal(2); + doc2.data().somethingElse.should.equal('update'); + + // rejecting / cancelling transaction + let didReject = false; + try { + await firestore.runTransaction(updateFunction); + } catch (e) { + didReject = true; + } + should.equal(didReject, true); + const doc3 = await docRef.get(); + doc3.data().value.should.equal(2); + doc3.data().somethingElse.should.equal('update'); + + // delete + deleteMe = true; + const val4 = await firestore.runTransaction(updateFunction); + should.equal(val4, 'bye'); + const doc4 = await docRef.get(); + should.equal(doc4.exists, false); + + return Promise.resolve('Test Completed'); + }); +}); diff --git a/tests-new/e2e/mocha.opts b/tests-new/e2e/mocha.opts index 131492bb..2fead4e1 100755 --- a/tests-new/e2e/mocha.opts +++ b/tests-new/e2e/mocha.opts @@ -1,4 +1,5 @@ --recursive --timeout 120000 +--slow 1200 --bail --require ./bridge/env/node diff --git a/tests-new/package-lock.json b/tests-new/package-lock.json index b3fc04c7..a8b2ecd2 100644 --- a/tests-new/package-lock.json +++ b/tests-new/package-lock.json @@ -4,6 +4,14 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@sinonjs/formatio": { + "version": "2.0.0", + "resolved": "http://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", + "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==", + "requires": { + "samsam": "1.3.0" + } + }, "absolute-path": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/absolute-path/-/absolute-path-0.0.0.tgz", @@ -960,6 +968,15 @@ "babel-runtime": "6.26.0" } }, + "babel-plugin-transform-es2015-duplicate-keys": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", + "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, "babel-plugin-transform-es2015-for-of": { "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", @@ -1054,6 +1071,14 @@ "babel-runtime": "6.26.0" } }, + "babel-plugin-transform-es2015-typeof-symbol": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", + "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", + "requires": { + "babel-runtime": "6.26.0" + } + }, "babel-plugin-transform-es2015-unicode-regex": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", @@ -1185,6 +1210,82 @@ } } }, + "babel-preset-es2015": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.6.0.tgz", + "integrity": "sha1-iLM+WP7JTG695Y3GXs5dFODsJWg=", + "requires": { + "babel-plugin-check-es2015-constants": "6.22.0", + "babel-plugin-transform-es2015-arrow-functions": "6.22.0", + "babel-plugin-transform-es2015-block-scoped-functions": "6.22.0", + "babel-plugin-transform-es2015-block-scoping": "6.26.0", + "babel-plugin-transform-es2015-classes": "6.24.1", + "babel-plugin-transform-es2015-computed-properties": "6.24.1", + "babel-plugin-transform-es2015-destructuring": "6.23.0", + "babel-plugin-transform-es2015-duplicate-keys": "6.24.1", + "babel-plugin-transform-es2015-for-of": "6.23.0", + "babel-plugin-transform-es2015-function-name": "6.24.1", + "babel-plugin-transform-es2015-literals": "6.22.0", + "babel-plugin-transform-es2015-modules-commonjs": "6.26.0", + "babel-plugin-transform-es2015-object-super": "6.24.1", + "babel-plugin-transform-es2015-parameters": "6.24.1", + "babel-plugin-transform-es2015-shorthand-properties": "6.24.1", + "babel-plugin-transform-es2015-spread": "6.22.0", + "babel-plugin-transform-es2015-sticky-regex": "6.24.1", + "babel-plugin-transform-es2015-template-literals": "6.22.0", + "babel-plugin-transform-es2015-typeof-symbol": "6.23.0", + "babel-plugin-transform-es2015-unicode-regex": "6.24.1", + "babel-plugin-transform-regenerator": "6.26.0" + } + }, + "babel-preset-es2015-mod": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/babel-preset-es2015-mod/-/babel-preset-es2015-mod-6.6.0.tgz", + "integrity": "sha1-4QW2LrfBABCQq4YiUpiQTPkMHo4=", + "requires": { + "babel-plugin-transform-es2015-modules-commonjs": "6.7.7", + "babel-plugin-transform-regenerator": "6.6.5", + "babel-preset-es2015": "6.6.0", + "modify-babel-preset": "2.0.2" + }, + "dependencies": { + "babel-plugin-transform-es2015-modules-commonjs": { + "version": "6.7.7", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.7.7.tgz", + "integrity": "sha1-+lyiAWYXxNcSEj2M/BV4f8qoPzM=", + "requires": { + "babel-plugin-transform-strict-mode": "6.24.1", + "babel-runtime": "5.8.38", + "babel-template": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-regenerator": { + "version": "6.6.5", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.6.5.tgz", + "integrity": "sha1-B5qYK9VuIjXjHuOxetVK66iY1Oc=", + "requires": { + "babel-core": "6.26.0", + "babel-plugin-syntax-async-functions": "6.13.0", + "babel-plugin-transform-es2015-block-scoping": "6.26.0", + "babel-plugin-transform-es2015-for-of": "6.23.0", + "babel-runtime": "5.8.38", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "private": "0.1.8" + } + }, + "babel-runtime": { + "version": "5.8.38", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.38.tgz", + "integrity": "sha1-HAsC62MxL18If/IEUIJ7QlydTBk=", + "requires": { + "core-js": "1.2.7" + } + } + } + }, "babel-preset-es2015-node": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/babel-preset-es2015-node/-/babel-preset-es2015-node-6.1.1.tgz", @@ -1201,6 +1302,15 @@ "semver": "5.5.0" } }, + "babel-preset-es3": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-es3/-/babel-preset-es3-1.0.1.tgz", + "integrity": "sha1-4I3ZUKFnDauLUKvOqpuT09mszR4=", + "requires": { + "babel-plugin-transform-es3-member-expression-literals": "6.22.0", + "babel-plugin-transform-es3-property-literals": "6.22.0" + } + }, "babel-preset-fbjs": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/babel-preset-fbjs/-/babel-preset-fbjs-2.1.4.tgz", @@ -5099,6 +5209,11 @@ "integrity": "sha1-OGchPo3Xm/Ho8jAMDPwe+xgsDfE=", "dev": true }, + "just-extend": { + "version": "1.1.27", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-1.1.27.tgz", + "integrity": "sha512-mJVp13Ix6gFo3SBAy9U/kL+oeZqzlYYYLQBwXVBlVzIsZwBqGREnOro24oC/8s8aox+rJhtZ2DiQof++IrkA+g==" + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -5216,6 +5331,11 @@ "lodash._root": "3.0.1" } }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + }, "lodash.isarguments": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", @@ -5286,6 +5406,11 @@ "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=" }, + "lolex": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.3.2.tgz", + "integrity": "sha512-A5pN2tkFj7H0dGIAM6MFvHKMJcPnjZsOMvR7ujCjfgW5TbV6H9vb1PgxLtHvjqNZTHsUolz+6/WEO0N1xNx2ng==" + }, "loose-envify": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", @@ -5725,6 +5850,14 @@ } } }, + "modify-babel-preset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/modify-babel-preset/-/modify-babel-preset-2.0.2.tgz", + "integrity": "sha1-v6UJZp/kn0IiwM4XG6RO0OgVUec=", + "requires": { + "require-relative": "0.8.7" + } + }, "morgan": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.6.1.tgz", @@ -5838,6 +5971,18 @@ "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", "dev": true }, + "nise": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/nise/-/nise-1.3.2.tgz", + "integrity": "sha512-KPKb+wvETBiwb4eTwtR/OsA2+iijXP+VnlSFYJo3EHjm2yjek1NWxHOUQat3i7xNLm1Bm18UA5j5Wor0yO2GtA==", + "requires": { + "@sinonjs/formatio": "2.0.0", + "just-extend": "1.1.27", + "lolex": "2.3.2", + "path-to-regexp": "1.7.0", + "text-encoding": "0.6.4" + } + }, "node-fetch": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", @@ -6245,6 +6390,14 @@ "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", "dev": true }, + "path-to-regexp": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", + "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", + "requires": { + "isarray": "0.0.1" + } + }, "path-type": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", @@ -6901,6 +7054,11 @@ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" }, + "require-relative": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz", + "integrity": "sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=" + }, "require-uncached": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", @@ -7008,6 +7166,11 @@ "ret": "0.1.15" } }, + "samsam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz", + "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==" + }, "sane": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/sane/-/sane-2.5.0.tgz", @@ -7464,6 +7627,59 @@ "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==" }, + "should": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/should/-/should-13.2.1.tgz", + "integrity": "sha512-l+/NwEMO+DcstsHEwPHRHzC9j4UOE3VQwJGcMWSsD/vqpqHbnQ+1iSHy64Ihmmjx1uiRPD9pFadTSc3MJtXAgw==", + "requires": { + "should-equal": "2.0.0", + "should-format": "3.0.3", + "should-type": "1.4.0", + "should-type-adaptors": "1.1.0", + "should-util": "1.0.0" + } + }, + "should-equal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", + "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", + "requires": { + "should-type": "1.4.0" + } + }, + "should-format": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", + "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", + "requires": { + "should-type": "1.4.0", + "should-type-adaptors": "1.1.0" + } + }, + "should-sinon": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/should-sinon/-/should-sinon-0.0.6.tgz", + "integrity": "sha512-ScBOH5uW5QVFaONmUnIXANSR6z5B8IKzEmBP3HE5sPOCDuZ88oTMdUdnKoCVQdLcCIrRrhRLPS5YT+7H40a04g==" + }, + "should-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", + "integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=" + }, + "should-type-adaptors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz", + "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", + "requires": { + "should-type": "1.4.0", + "should-util": "1.0.0" + } + }, + "should-util": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.0.tgz", + "integrity": "sha1-yYzaN0qmsZDfi6h8mInCtNtiAGM=" + }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", @@ -7501,6 +7717,30 @@ } } }, + "sinon": { + "version": "4.4.8", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-4.4.8.tgz", + "integrity": "sha512-EWZf/D5BN/BbDFPmwY2abw6wgELVmk361self+lcwEmVw0WWUxURp2S/YoDB2WG/xurFVzKQglMARweYRWM6Hw==", + "requires": { + "@sinonjs/formatio": "2.0.0", + "diff": "3.3.1", + "lodash.get": "4.4.2", + "lolex": "2.3.2", + "nise": "1.3.2", + "supports-color": "5.3.0", + "type-detect": "4.0.8" + }, + "dependencies": { + "supports-color": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", + "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", + "requires": { + "has-flag": "3.0.0" + } + } + } + }, "slash": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", @@ -8289,6 +8529,11 @@ } } }, + "text-encoding": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", + "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=" + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -8445,6 +8690,11 @@ "prelude-ls": "1.1.2" } }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" + }, "type-is": { "version": "1.6.16", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", diff --git a/tests-new/package.json b/tests-new/package.json index 0db469f8..f06c6fc5 100755 --- a/tests-new/package.json +++ b/tests-new/package.json @@ -13,11 +13,16 @@ "ios:pod:install": "cd ios && rm -rf ReactNativeFirebaseDemo.xcworkspace && pod install && cd .." }, "dependencies": { + "babel-preset-es2015-mod": "^6.6.0", + "babel-preset-es3": "^1.0.1", "detox": "^7.2.0", "mocha": "^4.0.1", "react": "^16.2.0", "react-native": "^0.52.3", "react-native-restart": "0.0.6", + "should": "^13.2.1", + "should-sinon": "0.0.6", + "sinon": "^4.4.8", "ws": "^5.1.0" }, "devDependencies": {