Skip to content

Commit

Permalink
fix(functions, emulator): add useEmulator, deprecate useFunctionsEmul…
Browse files Browse the repository at this point in the history
…ator

includes a lot of testing improvement in the area
  • Loading branch information
mikehardy committed Feb 9, 2022
1 parent 726f3bd commit 83b46e7
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 31 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/scripts/functions/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import * as functions from 'firebase-functions';
//
export const helloWorld = functions.https.onRequest((request, response) => {
functions.logger.info('Hello logs!', { structuredData: true });
response.send('Hello from Firebase!');
response.send('{ "data": "Hello from Firebase!" }');
});

export { testFunctionCustomRegion } from './testFunctionCustomRegion';
Expand Down
10 changes: 5 additions & 5 deletions packages/functions/__tests__/functions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ describe('Cloud Functions', function () {

describe('useFunctionsEmulator()', function () {
it('useFunctionsEmulator -> uses 10.0.2.2', function () {
functions().useFunctionsEmulator('http://localhost');
functions().useEmulator('localhost', 5001);

// @ts-ignore
expect(functions()._useFunctionsEmulatorOrigin).toBe('http://10.0.2.2');
expect(functions()._useFunctionsEmulatorHost).toBe('10.0.2.2');

functions().useFunctionsEmulator('http://127.0.0.1');
functions().useEmulator('127.0.0.1', 5001);

// @ts-ignore
expect(functions()._useFunctionsEmulatorOrigin).toBe('http://10.0.2.2');
expect(functions()._useFunctionsEmulatorHost).toBe('10.0.2.2');
});

it('prefers emulator to custom domain', function () {
Expand All @@ -30,7 +30,7 @@ describe('Cloud Functions', function () {
functions.useFunctionsEmulator('http://10.0.2.2');

// @ts-ignore
expect(functions._useFunctionsEmulatorOrigin).toBe('http://10.0.2.2');
expect(functions._useFunctionsEmulatorHost).toBe('10.0.2.2');
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public class UniversalFirebaseFunctionsModule extends UniversalFirebaseModule {
}

Task<Object> httpsCallable(
String appName, String region, String origin, String name, Object data, ReadableMap options) {
String appName, String region, String host, Integer port, String name, Object data, ReadableMap options) {
return Tasks.call(
getExecutor(),
() -> {
Expand All @@ -52,8 +52,8 @@ Task<Object> httpsCallable(
httpReference.setTimeout((long) options.getInt("timeout"), TimeUnit.SECONDS);
}

if (origin != null) {
functionsInstance.useFunctionsEmulator(origin);
if (host != null) {
functionsInstance.useEmulator(host, port);
}

return Tasks.await(httpReference.call(data)).getData();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,15 @@ public class ReactNativeFirebaseFunctionsModule extends ReactNativeFirebaseModul
public void httpsCallable(
String appName,
String region,
String origin,
String host,
Integer port,
String name,
ReadableMap wrapper,
ReadableMap options,
Promise promise) {
Task<Object> callMethodTask =
module.httpsCallable(
appName, region, origin, name, wrapper.toHashMap().get(DATA_KEY), options);
appName, region, host, port, name, wrapper.toHashMap().get(DATA_KEY), options);

// resolve
callMethodTask.addOnSuccessListener(
Expand Down
30 changes: 23 additions & 7 deletions packages/functions/e2e/functions.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,34 @@ describe('functions()', function () {
const response = await functionRunner();
response.data.should.equal('null');
});
});

it('useFunctionsEmulator', async function () {
const region = 'europe-west2';
const fnName = 'invertaseReactNativeFirebaseFunctionsEmulator';
describe('emulator', function () {
it('configures functions emulator via deprecated method with no port', async function () {
const region = 'us-central1';
const fnName = 'helloWorld';
const functions = firebase.app().functions(region);
functions.useFunctionsEmulator('http://localhost');
const response = await functions.httpsCallable(fnName)();
response.data.should.equal('Hello from Firebase!');
});

functions.useFunctionsEmulator('http://api.rnfirebase.io');

it('configures functions emulator via deprecated method with port', async function () {
const region = 'us-central1';
const fnName = 'helloWorld';
const functions = firebase.app().functions(region);
functions.useFunctionsEmulator('http://localhost:5001');
const response = await functions.httpsCallable(fnName)();
response.data.should.equal('Hello from Firebase!');
});

response.data.region.should.equal(region);
response.data.fnName.should.equal(fnName);
it('configures functions emulator', async function () {
const region = 'us-central1';
const fnName = 'helloWorld';
const functions = firebase.app().functions(region);
functions.useEmulator('localhost', 5001);
const response = await functions.httpsCallable(fnName)();
response.data.should.equal('Hello from Firebase!');
});
});

Expand Down
9 changes: 5 additions & 4 deletions packages/functions/ios/RNFBFunctions/RNFBFunctionsModule.m
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ @implementation RNFBFunctionsModule

RCT_EXPORT_METHOD(httpsCallable
: (FIRApp *)firebaseApp customUrlOrRegion
: (NSString *)customUrlOrRegion origin
: (NSString *)origin name
: (NSString *)customUrlOrRegion host
: (NSString *)host port
: (NSNumber *_Nonnull)port name
: (NSString *)name wrapper
: (NSDictionary *)wrapper options
: (NSDictionary *)options resolver
Expand All @@ -45,8 +46,8 @@ @implementation RNFBFunctionsModule
? [FIRFunctions functionsForApp:firebaseApp customDomain:customUrlOrRegion]
: [FIRFunctions functionsForApp:firebaseApp region:customUrlOrRegion];

if (origin != nil) {
[functions useFunctionsEmulatorOrigin:origin];
if (host != nil) {
[functions useEmulatorWithHost:host port:[port intValue]];
}

FIRHTTPSCallable *callable = [functions HTTPSCallableWithName:name];
Expand Down
24 changes: 24 additions & 0 deletions packages/functions/lib/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,9 +356,33 @@ export namespace FirebaseFunctionsTypes {
* If you want to use the emulator on a real android device, you will need to specify the actual host
* computer IP address.
*
* @deprecated prefer useEmulator instead
* @param origin url of the local emulator started via firebase tools "http://localhost:5001"
*/
useFunctionsEmulator(origin: string): void;

/**
* Changes this instance to point to a Cloud Functions emulator running locally.
*
* See https://firebase.google.com/docs/functions/local-emulator
*
* #### Example
*
* ```js
* if (__DEV__) {
* firebase.functions().useEmulator('localhost', 5001);
* }
* ```
*
* Note: on android, hosts 'localhost' and '127.0.0.1' are automatically remapped to '10.0.2.2' (the
* "host" computer IP address for android emulators) to make the standard development experience easy.
* If you want to use the emulator on a real android device, you will need to specify the actual host
* computer IP address.
*
* @param host hostname of the local emulator started via firebase tools, ex. "localhost"
* @param port port of the local emulator started via firebase tools, ex. 5001
*/
useEmulator(host: string, port: number): void;
}
}

Expand Down
34 changes: 25 additions & 9 deletions packages/functions/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ class FirebaseFunctionsModule extends FirebaseModule {
constructor(...args) {
super(...args);
this._customUrlOrRegion = this._customUrlOrRegion || 'us-central1';
this._useFunctionsEmulatorOrigin = null;
this._useFunctionsEmulatorHost = null;
this._useFunctionsEmulatorPort = -1;
}

httpsCallable(name, options = {}) {
Expand All @@ -70,7 +71,8 @@ class FirebaseFunctionsModule extends FirebaseModule {

return data => {
const nativePromise = this.native.httpsCallable(
this._useFunctionsEmulatorOrigin,
this._useFunctionsEmulatorHost,
this._useFunctionsEmulatorPort,
name,
{
data,
Expand All @@ -92,27 +94,41 @@ class FirebaseFunctionsModule extends FirebaseModule {
}

useFunctionsEmulator(origin) {
let _origin = origin;
[_, host, port] = /https?\:.*\/\/([^:]+):?(\d+)?/.exec(origin);
if (!port) {
port = 5001;
}
this.useEmulator(host, parseInt(port));
}

useEmulator(host, port) {
if (!isNumber(port)) {
throw new Error('useEmulator port parameter must be a number');
}

let _host = host;

const androidBypassEmulatorUrlRemap =
typeof this.firebaseJson.android_bypass_emulator_url_remap === 'boolean' &&
this.firebaseJson.android_bypass_emulator_url_remap;
if (!androidBypassEmulatorUrlRemap && isAndroid && _origin) {
if (_origin.startsWith('http://localhost')) {
_origin = _origin.replace('http://localhost', 'http://10.0.2.2');
if (!androidBypassEmulatorUrlRemap && isAndroid && _host) {
if (_host.startsWith('localhost')) {
_host = _host.replace('localhost', '10.0.2.2');
// eslint-disable-next-line no-console
console.log(
'Mapping functions host "localhost" to "10.0.2.2" for android emulators. Use real IP on real devices. You can bypass this behaviour with "android_bypass_emulator_url_remap" flag.',
);
}
if (_origin.startsWith('http://127.0.0.1')) {
_origin = _origin.replace('http://127.0.0.1', 'http://10.0.2.2');
if (_host.startsWith('127.0.0.1')) {
_host = _host.replace('127.0.0.1', '10.0.2.2');
// eslint-disable-next-line no-console
console.log(
'Mapping functions host "127.0.0.1" to "10.0.2.2" for android emulators. Use real IP on real devices. You can bypass this behaviour with "android_bypass_emulator_url_remap" flag.',
);
}
}
this._useFunctionsEmulatorOrigin = _origin || null;
this._useFunctionsEmulatorHost = _host || null;
this._useFunctionsEmulatorPort = port || -1;
}
}

Expand Down

0 comments on commit 83b46e7

Please sign in to comment.