From cd841c9e54d5cc1164365a497f6aa44b2ce25407 Mon Sep 17 00:00:00 2001 From: Mike Hardy Date: Sat, 17 Jan 2026 13:15:35 -0500 Subject: [PATCH 1/2] fix(app): tolerate missing `userInfo` in NativeError previously a missing NativeError.userInfo would crash the constructor of NativeFirebaseError as it was expected to be defined with this change we will tolerate a completely missing userInfo property --- packages/app/__tests__/app.test.ts | 17 +++++++++++++++++ .../app/lib/internal/NativeFirebaseError.ts | 14 +++++++------- packages/app/lib/types/internal.ts | 2 +- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/packages/app/__tests__/app.test.ts b/packages/app/__tests__/app.test.ts index 9ece480b19..f95dcfa709 100644 --- a/packages/app/__tests__/app.test.ts +++ b/packages/app/__tests__/app.test.ts @@ -10,6 +10,7 @@ import firebase, { setLogLevel, } from '../lib'; import { Logger } from '../lib/internal/logger'; +import { NativeFirebaseError } from '../lib/internal'; describe('App', function () { describe('modular', function () { @@ -121,4 +122,20 @@ describe('App', function () { ); }); }); + + describe('`NativeFirebaseError` can cope with missing properties', function () { + it('missing `userInfo.code` does not error', function () { + const testNativeError = { + userInfo: undefined, + }; + const testNativeFirebaseError = new NativeFirebaseError( + // @ts-ignore - using malformed object to test handling of malformed objects + testNativeError, + new Error().stack!, + 'testNamespace', + ); + expect(testNativeFirebaseError.namespace).toBe('testNamespace'); + expect(testNativeFirebaseError.code).toBe('testNamespace/unknown'); + }); + }); }); diff --git a/packages/app/lib/internal/NativeFirebaseError.ts b/packages/app/lib/internal/NativeFirebaseError.ts index 66a9b1c4ee..dbf0d63816 100644 --- a/packages/app/lib/internal/NativeFirebaseError.ts +++ b/packages/app/lib/internal/NativeFirebaseError.ts @@ -34,7 +34,7 @@ export default class NativeFirebaseError extends Error { ): NativeFirebaseError { return new NativeFirebaseError( { userInfo: errorEvent }, - stack || new Error().stack!, + stack ?? new Error().stack!, namespace, ); } @@ -50,12 +50,12 @@ export default class NativeFirebaseError extends Error { Object.defineProperty(this, 'code', { enumerable: false, - value: `${this.namespace}/${userInfo.code || 'unknown'}`, + value: `${this.namespace}/${userInfo?.code ?? 'unknown'}`, }); Object.defineProperty(this, 'message', { enumerable: false, - value: `[${this.code}] ${userInfo.message || nativeError.message}`, + value: `[${this.code}] ${userInfo?.message ?? nativeError.message}`, }); Object.defineProperty(this, 'jsStack', { @@ -71,23 +71,23 @@ export default class NativeFirebaseError extends Error { // Needed for MFA processing of errors on web Object.defineProperty(this, 'customData', { enumerable: false, - value: nativeError.customData || null, + value: nativeError.customData ?? null, }); // Needed for MFA processing of errors on web Object.defineProperty(this, 'operationType', { enumerable: false, - value: nativeError.operationType || null, + value: nativeError.operationType ?? null, }); Object.defineProperty(this, 'nativeErrorCode', { enumerable: false, - value: userInfo.nativeErrorCode || null, + value: userInfo?.nativeErrorCode ?? null, }); Object.defineProperty(this, 'nativeErrorMessage', { enumerable: false, - value: userInfo.nativeErrorMessage || null, + value: userInfo?.nativeErrorMessage ?? null, }); this.stack = NativeFirebaseError.getStackWithMessage( diff --git a/packages/app/lib/types/internal.ts b/packages/app/lib/types/internal.ts index c1999aadcc..c26f6ab0ab 100644 --- a/packages/app/lib/types/internal.ts +++ b/packages/app/lib/types/internal.ts @@ -96,7 +96,7 @@ export interface NativeErrorUserInfo { } export interface NativeError { - userInfo: NativeErrorUserInfo; + userInfo?: NativeErrorUserInfo; message?: string; customData?: any; operationType?: string; From 83f75983ee2d5ccc625645b6b55ab2de112c8316 Mon Sep 17 00:00:00 2001 From: Mike Hardy Date: Sat, 17 Jan 2026 13:17:08 -0500 Subject: [PATCH 2/2] test(functions): avoid deprecated methods in modular tests --- packages/functions/__tests__/functions.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/functions/__tests__/functions.test.ts b/packages/functions/__tests__/functions.test.ts index c382a3b752..f96d56bafe 100644 --- a/packages/functions/__tests__/functions.test.ts +++ b/packages/functions/__tests__/functions.test.ts @@ -117,7 +117,7 @@ describe('Cloud Functions', function () { }); it('`FunctionsModule` type is properly exposed to end user', function () { - const functionsInstance: Functions = (firebase.app() as unknown as FirebaseApp).functions(); + const functionsInstance: Functions = getFunctions(); expect(functionsInstance).toBeDefined(); expect(functionsInstance.httpsCallable).toBeDefined(); expect(functionsInstance.httpsCallableFromUrl).toBeDefined(); @@ -126,12 +126,12 @@ describe('Cloud Functions', function () { }); it('`Functions` type is properly exposed to end user', function () { - const functionsInstance: Functions = (firebase.app() as unknown as FirebaseApp).functions(); + const functionsInstance: Functions = getFunctions(); expect(functionsInstance).toBeDefined(); }); it('`FirebaseApp` type is properly exposed to end user', function () { - const app = firebase.app() as unknown as FirebaseApp; + const app = getApp(); expect(app).toBeDefined(); expect(app.functions).toBeDefined(); });