Skip to content

Commit bf92962

Browse files
committed
fix(functions): correct httpsCallable timeout units on macOS/web
1 parent 4e0b2ee commit bf92962

4 files changed

Lines changed: 143 additions & 2 deletions

File tree

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { afterAll, beforeAll, beforeEach, describe, expect, it, jest } from '@jest/globals';
2+
3+
jest.mock('@react-native-firebase/app/dist/module/common', () => {
4+
const actualCommon = jest.requireActual(
5+
'@react-native-firebase/app/dist/module/common',
6+
) as Record<string, unknown>;
7+
return {
8+
...actualCommon,
9+
isOther: false,
10+
isAndroid: true,
11+
};
12+
});
13+
14+
import { firebase } from '../lib';
15+
16+
function timeoutFromNativeCall(nativeMock: jest.Mock): number {
17+
const call = nativeMock.mock.calls[0] as unknown[] | undefined;
18+
expect(call).toBeDefined();
19+
const options = call?.[4] as { timeout?: number } | undefined;
20+
expect(options?.timeout).toBeDefined();
21+
return options?.timeout as number;
22+
}
23+
24+
describe('httpsCallable timeout units on native platforms', function () {
25+
let httpsCallableNative: jest.Mock;
26+
27+
beforeAll(function () {
28+
// @ts-ignore test-only global
29+
globalThis.RNFB_SILENCE_MODULAR_DEPRECATION_WARNINGS = true;
30+
});
31+
32+
afterAll(function () {
33+
// @ts-ignore test-only global
34+
globalThis.RNFB_SILENCE_MODULAR_DEPRECATION_WARNINGS = false;
35+
});
36+
37+
beforeEach(function () {
38+
httpsCallableNative = jest
39+
.fn<(...args: unknown[]) => Promise<{ data: null }>>()
40+
.mockResolvedValue({ data: null });
41+
42+
const functions = firebase.app().functions();
43+
// @ts-ignore test-only internal cache
44+
functions._nativeModule = {
45+
httpsCallable: (
46+
_host: unknown,
47+
_port: unknown,
48+
_name: unknown,
49+
_wrapper: unknown,
50+
options: { timeout?: number },
51+
) => httpsCallableNative(_host, _port, _name, _wrapper, options),
52+
};
53+
});
54+
55+
it('converts milliseconds to seconds for httpsCallable (Android/iOS)', async function () {
56+
const runner = firebase.app().functions().httpsCallable('example', { timeout: 30000 });
57+
await runner();
58+
59+
expect(httpsCallableNative).toHaveBeenCalledTimes(1);
60+
expect(timeoutFromNativeCall(httpsCallableNative)).toBe(30);
61+
});
62+
});
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { afterAll, beforeAll, beforeEach, describe, expect, it, jest } from '@jest/globals';
2+
3+
jest.mock('@react-native-firebase/app/dist/module/common', () => {
4+
const actualCommon = jest.requireActual(
5+
'@react-native-firebase/app/dist/module/common',
6+
) as Record<string, unknown>;
7+
return {
8+
...actualCommon,
9+
isOther: true,
10+
isAndroid: false,
11+
};
12+
});
13+
14+
import { firebase } from '../lib';
15+
16+
function timeoutFromNativeCall(nativeMock: jest.Mock): number {
17+
const call = nativeMock.mock.calls[0] as unknown[] | undefined;
18+
expect(call).toBeDefined();
19+
const options = call?.[4] as { timeout?: number } | undefined;
20+
expect(options?.timeout).toBeDefined();
21+
return options?.timeout as number;
22+
}
23+
24+
describe('httpsCallable timeout units on other platforms', function () {
25+
let httpsCallableNative: jest.Mock;
26+
27+
beforeAll(function () {
28+
// @ts-ignore test-only global
29+
globalThis.RNFB_SILENCE_MODULAR_DEPRECATION_WARNINGS = true;
30+
});
31+
32+
afterAll(function () {
33+
// @ts-ignore test-only global
34+
globalThis.RNFB_SILENCE_MODULAR_DEPRECATION_WARNINGS = false;
35+
});
36+
37+
beforeEach(function () {
38+
httpsCallableNative = jest
39+
.fn<(...args: unknown[]) => Promise<{ data: null }>>()
40+
.mockResolvedValue({ data: null });
41+
42+
const functions = firebase.app().functions();
43+
// @ts-ignore test-only internal cache
44+
functions._nativeModule = {
45+
httpsCallable: (
46+
_host: unknown,
47+
_port: unknown,
48+
_name: unknown,
49+
_wrapper: unknown,
50+
options: { timeout?: number },
51+
) => httpsCallableNative(_host, _port, _name, _wrapper, options),
52+
};
53+
});
54+
55+
it('keeps milliseconds for httpsCallable (web/macos)', async function () {
56+
const runner = firebase.app().functions().httpsCallable('example', { timeout: 30000 });
57+
await runner();
58+
59+
expect(httpsCallableNative).toHaveBeenCalledTimes(1);
60+
expect(timeoutFromNativeCall(httpsCallableNative)).toBe(30000);
61+
});
62+
});

packages/functions/e2e/functions.e2e.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,18 @@ describe('functions() modular', function () {
511511
const response = await httpsCallable(functions, fnName)();
512512
response.data.should.equal('Hello from Firebase!');
513513
});
514+
515+
it('HttpsCallableOptions.timeout honors millisecond values on web/macos', async function () {
516+
if (!Platform.other) {
517+
return this.skip();
518+
}
519+
const { getApp } = modular;
520+
const { getFunctions, httpsCallable, connectFunctionsEmulator } = functionsModular;
521+
const functions = getFunctions(getApp(), 'us-central1');
522+
connectFunctionsEmulator(functions, 'localhost', 5001);
523+
const response = await httpsCallable(functions, 'helloWorldV2', { timeout: 10000 })();
524+
response.data.should.equal('Hello from Firebase!');
525+
});
514526
});
515527

516528
describe('httpsCallableFromUrl()', function () {

packages/functions/lib/namespaced.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,10 @@ class FirebaseFunctionsModule extends FirebaseModule {
280280
httpsCallable(name: string, options: HttpsCallableOptions = {}) {
281281
if (options.timeout) {
282282
if (isNumber(options.timeout)) {
283-
options.timeout = options.timeout / 1000;
283+
// Native Android/iOS expect seconds; Firebase JS (web/macos) expects milliseconds.
284+
if (!isOther) {
285+
options.timeout = options.timeout / 1000;
286+
}
284287
} else {
285288
throw new Error('HttpsCallableOptions.timeout expected a Number in milliseconds');
286289
}
@@ -337,7 +340,9 @@ class FirebaseFunctionsModule extends FirebaseModule {
337340
httpsCallableFromUrl(url: string, options: HttpsCallableOptions = {}) {
338341
if (options.timeout) {
339342
if (isNumber(options.timeout)) {
340-
options.timeout = options.timeout / 1000;
343+
if (!isOther) {
344+
options.timeout = options.timeout / 1000;
345+
}
341346
} else {
342347
throw new Error('HttpsCallableOptions.timeout expected a Number in milliseconds');
343348
}

0 commit comments

Comments
 (0)