Skip to content

Commit 8b01d5e

Browse files
authoredFeb 3, 2025··
chore(app-check): deprecation warning for v8 API ahead of future major release (#8198)
1 parent decaeca commit 8b01d5e

File tree

5 files changed

+236
-42
lines changed

5 files changed

+236
-42
lines changed
 

‎packages/app-check/__tests__/appcheck.test.ts

+119-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
1-
import { describe, expect, it } from '@jest/globals';
1+
import { jest, beforeEach, describe, expect, it } from '@jest/globals';
2+
// @ts-ignore test
3+
import FirebaseModule from '../../app/lib/internal/FirebaseModule';
4+
5+
import {
6+
createCheckV9Deprecation,
7+
CheckV9DeprecationFunction,
8+
} from '../../app/lib/common/unitTestUtils';
29

310
import {
411
firebase,
512
initializeAppCheck,
613
getToken,
714
getLimitedUseToken,
8-
addTokenListener,
915
setTokenAutoRefreshEnabled,
16+
onTokenChanged,
17+
CustomProvider,
1018
} from '../lib';
1119

1220
describe('appCheck()', function () {
@@ -47,12 +55,117 @@ describe('appCheck()', function () {
4755
expect(getLimitedUseToken).toBeDefined();
4856
});
4957

50-
it('`addTokenListener` function is properly exposed to end user', function () {
51-
expect(addTokenListener).toBeDefined();
52-
});
53-
5458
it('`setTokenAutoRefreshEnabled` function is properly exposed to end user', function () {
5559
expect(setTokenAutoRefreshEnabled).toBeDefined();
5660
});
61+
62+
it('`CustomProvider` function is properly exposed to end user', function () {
63+
expect(CustomProvider).toBeDefined();
64+
});
65+
});
66+
67+
describe('test `console.warn` is called for RNFB v8 API & not called for v9 API', function () {
68+
let appCheckRefV9Deprecation: CheckV9DeprecationFunction;
69+
let staticsRefV9Deprecation: CheckV9DeprecationFunction;
70+
71+
beforeEach(function () {
72+
appCheckRefV9Deprecation = createCheckV9Deprecation(['appCheck']);
73+
staticsRefV9Deprecation = createCheckV9Deprecation(['appCheck', 'statics']);
74+
75+
// @ts-ignore test
76+
jest.spyOn(FirebaseModule.prototype, 'native', 'get').mockImplementation(() => {
77+
return new Proxy(
78+
{},
79+
{
80+
get: () =>
81+
jest.fn().mockResolvedValue({
82+
source: 'cache',
83+
changes: [],
84+
documents: [],
85+
metadata: {},
86+
path: 'foo',
87+
} as never),
88+
},
89+
);
90+
});
91+
});
92+
93+
describe('AppCheck', function () {
94+
it('appCheck.activate()', function () {
95+
const app = firebase.app();
96+
const appCheck = firebase.appCheck();
97+
appCheckRefV9Deprecation(
98+
() =>
99+
initializeAppCheck(app, {
100+
provider: {
101+
providerOptions: {
102+
android: {
103+
provider: 'playIntegrity',
104+
},
105+
},
106+
},
107+
isTokenAutoRefreshEnabled: true,
108+
}),
109+
() => appCheck.activate('string'),
110+
'activate',
111+
);
112+
});
113+
114+
it('appCheck.setTokenAutoRefreshEnabled()', function () {
115+
const appCheck = firebase.appCheck();
116+
appCheckRefV9Deprecation(
117+
() => setTokenAutoRefreshEnabled(appCheck, true),
118+
() => appCheck.setTokenAutoRefreshEnabled(true),
119+
'setTokenAutoRefreshEnabled',
120+
);
121+
});
122+
123+
it('appCheck.getToken()', function () {
124+
const appCheck = firebase.appCheck();
125+
appCheckRefV9Deprecation(
126+
() => getToken(appCheck, true),
127+
() => appCheck.getToken(true),
128+
'getToken',
129+
);
130+
});
131+
132+
it('appCheck.getLimitedUseToken()', function () {
133+
const appCheck = firebase.appCheck();
134+
appCheckRefV9Deprecation(
135+
() => getLimitedUseToken(appCheck),
136+
() => appCheck.getLimitedUseToken(),
137+
'getLimitedUseToken',
138+
);
139+
});
140+
141+
it('appCheck.onTokenChanged()', function () {
142+
const appCheck = firebase.appCheck();
143+
appCheckRefV9Deprecation(
144+
() =>
145+
onTokenChanged(
146+
appCheck,
147+
() => {},
148+
() => {},
149+
() => {},
150+
),
151+
() =>
152+
appCheck.onTokenChanged(
153+
() => {},
154+
() => {},
155+
() => {},
156+
),
157+
'onTokenChanged',
158+
);
159+
});
160+
161+
it('CustomProvider', function () {
162+
const appCheck = firebase.appCheck;
163+
staticsRefV9Deprecation(
164+
() => CustomProvider,
165+
() => appCheck.CustomProvider,
166+
'CustomProvider',
167+
);
168+
});
169+
});
57170
});
58171
});

‎packages/app-check/lib/modular/index.d.ts

+43-9
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
import { FirebaseApp } from '@firebase/app-types';
1+
import { ReactNativeFirebase } from '@react-native-firebase/app';
22
import { FirebaseAppCheckTypes } from '..';
33

4+
import FirebaseApp = ReactNativeFirebase.FirebaseApp;
45
import AppCheck = FirebaseAppCheckTypes.Module;
56
import AppCheckOptions = FirebaseAppCheckTypes.AppCheckOptions;
67
import AppCheckTokenResult = FirebaseAppCheckTypes.AppCheckTokenResult;
78
import PartialObserver = FirebaseAppCheckTypes.PartialObserver;
89
import Unsubscribe = FirebaseAppCheckTypes.Unsubscribe;
10+
import AppCheckProvider = FirebaseAppCheckTypes.AppCheckProvider;
11+
import CustomProviderOptions = FirebaseAppCheckTypes.CustomProviderOptions;
912

1013
/**
1114
* Activate App Check for the given app. Can be called only once per app.
@@ -39,19 +42,42 @@ export function getToken(
3942
export function getLimitedUseToken(appCheckInstance: AppCheck): Promise<AppCheckTokenResult>;
4043

4144
/**
42-
* Registers a listener to changes in the token state.
43-
* There can be more than one listener registered at the same time for one or more App Check instances.
44-
* The listeners call back on the UI thread whenever the current
45-
* token associated with this App Check instance changes.
46-
* @param appCheckInstance - AppCheck
47-
* @param listener - PartialObserver<AppCheckTokenResult>
48-
* @returns {Unsubscribe}
45+
* Registers a listener to changes in the token state. There can be more
46+
* than one listener registered at the same time for one or more
47+
* App Check instances. The listeners call back on the UI thread whenever
48+
* the current token associated with this App Check instance changes.
49+
*
50+
* @returns A function that unsubscribes this listener.
4951
*/
50-
export function addTokenListener(
52+
export function onTokenChanged(
5153
appCheckInstance: AppCheck,
5254
listener: PartialObserver<AppCheckTokenResult>,
5355
): Unsubscribe;
5456

57+
/**
58+
* Registers a listener to changes in the token state. There can be more
59+
* than one listener registered at the same time for one or more
60+
* App Check instances. The listeners call back on the UI thread whenever
61+
* the current token associated with this App Check instance changes.
62+
*
63+
* Token listeners do not exist in the native SDK for iOS, no token change events will be emitted on that platform.
64+
* This is not yet implemented on Android, no token change events will be emitted until implemented.
65+
*
66+
* NOTE: Although an `onError` callback can be provided, it will
67+
* never be called, Android sdk code doesn't provide handling for onError function
68+
*
69+
* NOTE: Although an `onCompletion` callback can be provided, it will
70+
* never be called because the token stream is never-ending.
71+
*
72+
* @returns A function that unsubscribes this listener.
73+
*/
74+
export function onTokenChanged(
75+
appCheckInstance: AppCheck,
76+
onNext: (tokenResult: AppCheckListenerResult) => void,
77+
onError?: (error: Error) => void,
78+
onCompletion?: () => void,
79+
): () => void;
80+
5581
/**
5682
* Set whether App Check will automatically refresh tokens as needed.
5783
* @param appCheckInstance - AppCheck
@@ -61,3 +87,11 @@ export function setTokenAutoRefreshEnabled(
6187
appCheckInstance: AppCheck,
6288
isAutoRefreshEnabled: boolean,
6389
): void;
90+
91+
/**
92+
* Custom provider class.
93+
* @public
94+
*/
95+
export class CustomProvider implements AppCheckProvider {
96+
constructor(customProviderOptions: CustomProviderOptions);
97+
}

‎packages/app-check/lib/modular/index.js

+37-19
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
*/
1818

1919
import { firebase } from '..';
20+
import { MODULAR_DEPRECATION_ARG } from '../../../app/lib/common';
21+
import CustomProvider from '../ReactNativeFirebaseAppCheckProvider';
2022

2123
/**
2224
* @typedef {import('@firebase/app').FirebaseApp} FirebaseApp
@@ -35,11 +37,12 @@ import { firebase } from '..';
3537
*/
3638
export async function initializeAppCheck(app, options) {
3739
if (app) {
38-
await firebase.app(app.name).appCheck().initializeAppCheck(options);
40+
const appCheck = firebase.app(app.name).appCheck();
41+
await appCheck.initializeAppCheck.call(appCheck, options, MODULAR_DEPRECATION_ARG);
3942
return { app: firebase.app(app.name) };
4043
}
41-
42-
await firebase.app().appCheck().initializeAppCheck(options);
44+
const appCheck = firebase.app().appCheck();
45+
await appCheck.initializeAppCheck.call(appCheck, options, MODULAR_DEPRECATION_ARG);
4346
return { app: firebase.app() };
4447
}
4548

@@ -51,7 +54,8 @@ export async function initializeAppCheck(app, options) {
5154
* @returns {Promise<AppCheckTokenResult>}
5255
*/
5356
export function getToken(appCheckInstance, forceRefresh) {
54-
return appCheckInstance.app.appCheck().getToken(forceRefresh);
57+
const appCheck = appCheckInstance.app.appCheck();
58+
return appCheck.getToken.call(appCheck, forceRefresh, MODULAR_DEPRECATION_ARG);
5559
}
5660

5761
/**
@@ -61,29 +65,43 @@ export function getToken(appCheckInstance, forceRefresh) {
6165
* @returns {Promise<AppCheckTokenResult>}
6266
*/
6367
export function getLimitedUseToken(appCheckInstance) {
64-
return appCheckInstance.app.appCheck().getLimitedUseToken();
68+
const appCheck = appCheckInstance.app.appCheck();
69+
return appCheck.getLimitedUseToken.call(appCheck, MODULAR_DEPRECATION_ARG);
6570
}
6671

6772
/**
68-
* Registers a listener to changes in the token state.
69-
* There can be more than one listener registered at the same time for one or more App Check instances.
70-
* The listeners call back on the UI thread whenever the current
71-
* token associated with this App Check instance changes.
73+
* Set whether App Check will automatically refresh tokens as needed.
7274
* @param {AppCheck} appCheckInstance - The App Check instance.
73-
* @param {PartialObserver<AppCheckTokenResult>} listener - The listener to register.
74-
* @returns {Unsubscribe}
75+
* @param {boolean} isAutoRefreshEnabled - Whether to enable auto-refresh.
7576
*/
76-
export function addTokenListener(appCheckInstance, listener) {
77-
// Not implemented on React Native
78-
// See packages/app-check/lib/index.js:127
79-
throw new Error('addTokenListener is not implemented on React Native');
77+
export function setTokenAutoRefreshEnabled(appCheckInstance, isAutoRefreshEnabled) {
78+
const appCheck = appCheckInstance.app.appCheck();
79+
return appCheck.setTokenAutoRefreshEnabled.call(
80+
appCheck,
81+
isAutoRefreshEnabled,
82+
MODULAR_DEPRECATION_ARG,
83+
);
8084
}
8185

8286
/**
83-
* Set whether App Check will automatically refresh tokens as needed.
87+
* Registers a listener to changes in the token state. There can be more
88+
* than one listener registered at the same time for one or more
89+
* App Check instances. The listeners call back on the UI thread whenever
90+
* the current token associated with this App Check instance changes.
91+
*
8492
* @param {AppCheck} appCheckInstance - The App Check instance.
85-
* @param {boolean} isAutoRefreshEnabled - Whether to enable auto-refresh.
93+
* @param {PartialObserver<AppCheckTokenResult>} listener - The listener to register.
94+
* @returns {Unsubscribe}
8695
*/
87-
export function setTokenAutoRefreshEnabled(appCheckInstance, isAutoRefreshEnabled) {
88-
return appCheckInstance.app.appCheck().setTokenAutoRefreshEnabled(isAutoRefreshEnabled);
96+
export function onTokenChanged(appCheckInstance, onNextOrObserver, onError, onCompletion) {
97+
const appCheck = appCheckInstance.app.appCheck();
98+
return appCheck.onTokenChanged.call(
99+
appCheck,
100+
onNextOrObserver,
101+
onError,
102+
onCompletion,
103+
MODULAR_DEPRECATION_ARG,
104+
);
89105
}
106+
107+
export { CustomProvider };

‎packages/app/lib/common/index.js

+20-4
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,18 @@ export function tryJSONStringify(data) {
107107
const NO_REPLACEMENT = true;
108108

109109
const mapOfDeprecationReplacements = {
110+
appCheck: {
111+
default: {
112+
activate: 'initializeAppCheck()',
113+
setTokenAutoRefreshEnabled: 'setTokenAutoRefreshEnabled()',
114+
getToken: 'getToken()',
115+
getLimitedUseToken: 'getLimitedUseToken()',
116+
onTokenChanged: 'onTokenChanged()',
117+
},
118+
statics: {
119+
CustomProvider: 'CustomProvider',
120+
},
121+
},
110122
crashlytics: {
111123
default: {
112124
checkForUnsentReports: 'checkForUnsentReports()',
@@ -247,8 +259,8 @@ export function createMessage(
247259
}
248260

249261
function getNamespace(target) {
250-
if (target.GeoPoint) {
251-
// target is statics object. GeoPoint is a static class on Firestore
262+
if (target.GeoPoint || target.CustomProvider) {
263+
// target is statics object. GeoPoint - Firestore, CustomProvider - AppCheck
252264
return 'firestore';
253265
}
254266
if (target._config && target._config.namespace) {
@@ -263,8 +275,8 @@ function getNamespace(target) {
263275
}
264276

265277
function getInstanceName(target) {
266-
if (target.GeoPoint) {
267-
// target is statics object. GeoPoint is a static class on Firestore
278+
if (target.GeoPoint || target.CustomProvider) {
279+
// target is statics object. GeoPoint - Firestore, CustomProvider - AppCheck
268280
return 'statics';
269281
}
270282
if (target._config) {
@@ -309,6 +321,10 @@ export function createDeprecationProxy(instance) {
309321
) {
310322
deprecationConsoleWarning('firestore', prop, 'statics', false);
311323
}
324+
if (prop === 'CustomProvider') {
325+
deprecationConsoleWarning('appCheck', prop, 'statics', false);
326+
}
327+
312328
if (prop !== 'setLogLevel') {
313329
// we want to capture setLogLevel function call which we do below
314330
return Reflect.get(target, prop, receiver);

‎packages/app/lib/common/unitTestUtils.ts

+17-4
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ export type CheckV9DeprecationFunction = (
1919
modularFunction: () => void,
2020
nonModularFunction: () => void,
2121
methodNameKey: string,
22-
uniqueMessage: string = '',
22+
uniqueMessage?: string | null,
23+
ignoreFirebaseAppDeprecationWarning?: boolean,
2324
) => void;
2425

2526
export const createCheckV9Deprecation = (moduleNames: string[]): CheckV9DeprecationFunction => {
@@ -28,14 +29,26 @@ export const createCheckV9Deprecation = (moduleNames: string[]): CheckV9Deprecat
2829
nonModularFunction: () => void,
2930
methodNameKey: string,
3031
uniqueMessage: string?,
32+
checkFirebaseAppDeprecationWarning: boolean = false,
3133
) => {
3234
const moduleName = moduleNames[0]; // firestore, database, etc
3335
const instanceName = moduleNames[1] || 'default'; // default, FirestoreCollectionReference, etc
34-
const consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
35-
// Do not call `mockRestore()` as it removes the spy
36+
const consoleWarnSpy = jest.spyOn(console, 'warn');
3637
consoleWarnSpy.mockReset();
38+
39+
consoleWarnSpy.mockImplementation(warnMessage => {
40+
const firebaseAppDeprecationMessage = warnMessage.includes('Please use `getApp()` instead.');
41+
if (checkFirebaseAppDeprecationWarning) {
42+
throw new Error(`Console warn was called unexpectedly with: ${warnMessage}`);
43+
} else {
44+
if (!firebaseAppDeprecationMessage) {
45+
// we want to ignore all firebase app deprecation warnings (e.g. "Please use `getApp()` instead.") unless actually testing for it which we do above
46+
throw new Error(`Console warn was called unexpectedly with: ${warnMessage}`);
47+
}
48+
}
49+
});
50+
// Do not call `mockRestore()` unless removing the spy
3751
modularFunction();
38-
expect(consoleWarnSpy).not.toHaveBeenCalled();
3952
consoleWarnSpy.mockReset();
4053
consoleWarnSpy.mockRestore();
4154
const consoleWarnSpy2 = jest.spyOn(console, 'warn').mockImplementation(warnMessage => {

0 commit comments

Comments
 (0)
Please sign in to comment.