mirror of
https://github.com/hanzoai/firebase-js-sdk.git
synced 2026-09-24 16:59:10 +00:00
345 lines
9.4 KiB
TypeScript
345 lines
9.4 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2021 Google LLC
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
import {
|
|
initializeApp,
|
|
setLogLevel,
|
|
SDK_VERSION,
|
|
FirebaseApp,
|
|
deleteApp
|
|
} from 'firebase/app';
|
|
import {
|
|
Auth,
|
|
getAuth,
|
|
initializeAuth,
|
|
signInWithEmailAndPassword,
|
|
signOut
|
|
} from 'firebase/auth';
|
|
import {
|
|
initializeAppCheck,
|
|
AppCheck,
|
|
ReCaptchaV3Provider,
|
|
getToken
|
|
} from 'firebase/app-check';
|
|
import {
|
|
getAnalytics,
|
|
logEvent,
|
|
isSupported as analyticsIsSupported,
|
|
Analytics
|
|
} from 'firebase/analytics';
|
|
import {
|
|
getDatabase,
|
|
ref as dbRef,
|
|
onValue,
|
|
off,
|
|
update,
|
|
remove,
|
|
set,
|
|
Database
|
|
} from 'firebase/database';
|
|
import {
|
|
collection,
|
|
getFirestore,
|
|
doc,
|
|
setDoc,
|
|
updateDoc,
|
|
onSnapshot,
|
|
getDocs,
|
|
where,
|
|
query,
|
|
deleteDoc,
|
|
Firestore,
|
|
initializeFirestore
|
|
} from 'firebase/firestore';
|
|
import {
|
|
Functions,
|
|
getFunctions,
|
|
httpsCallable,
|
|
httpsCallableFromURL
|
|
} from 'firebase/functions';
|
|
import { getMessaging } from 'firebase/messaging';
|
|
import {
|
|
FirebasePerformance,
|
|
getPerformance,
|
|
trace as perfTrace
|
|
} from 'firebase/performance';
|
|
import {
|
|
getStorage,
|
|
FirebaseStorage,
|
|
ref as storageRef,
|
|
uploadString,
|
|
getDownloadURL,
|
|
StorageReference,
|
|
deleteObject
|
|
} from 'firebase/storage';
|
|
import {
|
|
getGenerativeModel,
|
|
getAI,
|
|
AI,
|
|
AgentPlatformBackend,
|
|
VertexAIBackend
|
|
} from 'firebase/ai';
|
|
import { getDataConnect, DataConnect } from 'firebase/data-connect';
|
|
// @ts-ignore
|
|
import { config, testAccount } from '../firebase-config';
|
|
import 'jest';
|
|
|
|
describe('MODULAR', () => {
|
|
let app: FirebaseApp;
|
|
beforeAll(() => {
|
|
console.log('FIREBASE VERSION', SDK_VERSION);
|
|
app = initializeApp(config);
|
|
setLogLevel('warn');
|
|
});
|
|
|
|
afterAll(() => {
|
|
signOut(getAuth(app));
|
|
deleteApp(app);
|
|
});
|
|
|
|
describe('AUTH', () => {
|
|
let auth: Auth;
|
|
it('initializeAuth()', () => {
|
|
auth = initializeAuth(app);
|
|
});
|
|
it('getAuth()', () => {
|
|
auth = getAuth(app);
|
|
});
|
|
it('signInWithEmailAndPassword()', async () => {
|
|
const cred = await signInWithEmailAndPassword(
|
|
auth,
|
|
testAccount.email,
|
|
testAccount.password
|
|
);
|
|
console.log('Logged in with test account', cred.user.email);
|
|
expect(cred.user.email).toBe(testAccount.email);
|
|
});
|
|
});
|
|
|
|
describe('APP CHECK', () => {
|
|
let appCheck: AppCheck;
|
|
it('init appCheck', () => {
|
|
// Test uses debug token, any string is fine here.
|
|
appCheck = initializeAppCheck(app, {
|
|
provider: new ReCaptchaV3Provider('fsad')
|
|
});
|
|
});
|
|
it('getToken()', async () => {
|
|
await getToken(appCheck);
|
|
});
|
|
});
|
|
|
|
describe('FUNCTIONS', () => {
|
|
let functions: Functions;
|
|
it('getFunctions()', () => {
|
|
functions = getFunctions(app);
|
|
});
|
|
it('httpsCallable()', async () => {
|
|
const callTest = httpsCallable<{ data: string }, { word: string }>(
|
|
functions,
|
|
'callTestv2'
|
|
);
|
|
const result = await callTest({ data: 'blah' });
|
|
expect(result.data.word).toBe('hellooo');
|
|
// This takes a while. Extend timeout past default (2000)
|
|
});
|
|
it('httpsCallableFromURL()', async () => {
|
|
const callTest = httpsCallableFromURL<{ data: string }, { word: string }>(
|
|
functions,
|
|
`https://us-central1-${app.options.projectId}.cloudfunctions.net/callTestv2`
|
|
);
|
|
const result = await callTest({ data: 'blah' });
|
|
expect(result.data.word).toBe('hellooo');
|
|
// This takes a while. Extend timeout past default (2000)
|
|
});
|
|
});
|
|
|
|
describe('STORAGE', () => {
|
|
let storage: FirebaseStorage;
|
|
let sRef: StorageReference;
|
|
let url: string;
|
|
it('getStorage()', () => {
|
|
storage = getStorage(app);
|
|
});
|
|
it('uploadString()', async () => {
|
|
sRef = storageRef(storage, '/test-exp.txt');
|
|
await uploadString(sRef, 'exp-efg');
|
|
});
|
|
it('getDownloadURL()', async () => {
|
|
url = await getDownloadURL(sRef);
|
|
expect(url).toMatch(/test-exp\.txt/);
|
|
});
|
|
it('fetch uploaded data', async () => {
|
|
const response = await fetch(url);
|
|
const data = await response.text();
|
|
expect(data).toBe('exp-efg');
|
|
await deleteObject(sRef);
|
|
});
|
|
});
|
|
|
|
describe('FIRESTORE', () => {
|
|
let firestore: Firestore;
|
|
it('initializeFirestore()', () => {
|
|
// fetch streams doesn't work in Jest.
|
|
// @ts-ignore I think the option is private so TS doesn't like it.
|
|
firestore = initializeFirestore(app, { useFetchStreams: false });
|
|
});
|
|
it('getFirestore()', () => {
|
|
firestore = getFirestore(app);
|
|
});
|
|
it('setDoc(), getDocs(), query(), where()', async () => {
|
|
firestore = getFirestore(app);
|
|
await setDoc(doc(firestore, 'testCollection/trueDoc'), {
|
|
testbool: true
|
|
});
|
|
// Reference doc a different way.
|
|
await setDoc(doc(collection(firestore, 'testCollection'), 'falseDoc'), {
|
|
testbool: false
|
|
});
|
|
const trueDocs = await getDocs(
|
|
query(
|
|
collection(firestore, 'testCollection'),
|
|
where('testbool', '==', true)
|
|
)
|
|
);
|
|
expect(trueDocs.docs.length).toBe(1);
|
|
await deleteDoc(doc(collection(firestore, 'testCollection'), 'trueDoc'));
|
|
|
|
await deleteDoc(doc(firestore, 'testCollection/falseDoc'));
|
|
});
|
|
it('onSnapshot() reflects CRUD operations', async () => {
|
|
firestore = getFirestore(app);
|
|
const testDocRef = doc(firestore, 'testCollection/testDoc');
|
|
let expectedData: any = {};
|
|
const unsub = onSnapshot(testDocRef, snap => {
|
|
if (snap.exists()) {
|
|
expect(snap.data()).toEqual(expectedData);
|
|
} else {
|
|
expect(expectedData).toBeNull;
|
|
}
|
|
});
|
|
expectedData = { word: 'hi', number: 14 };
|
|
await setDoc(testDocRef, { word: 'hi', number: 14 });
|
|
expectedData = { word: 'bye', number: 14, newProp: ['a'] };
|
|
await updateDoc(testDocRef, { word: 'bye', newProp: ['a'] });
|
|
expectedData = null;
|
|
await deleteDoc(testDocRef);
|
|
unsub();
|
|
});
|
|
});
|
|
|
|
describe('DATABASE', () => {
|
|
let db: Database;
|
|
it('getDatabase', () => {
|
|
db = getDatabase(app);
|
|
});
|
|
it('onValue() reflects CRUD operations', async () => {
|
|
const ref = dbRef(db, 'abc/def');
|
|
let expectedValue: any = {};
|
|
onValue(ref, snap => {
|
|
if (snap.exists()) {
|
|
expect(snap.val()).toEqual(expectedValue);
|
|
} else {
|
|
expect(expectedValue).toBeNull;
|
|
}
|
|
});
|
|
expectedValue = { text: 'string 123 xyz' };
|
|
await set(ref, { text: 'string 123 xyz' });
|
|
expectedValue.number = 987;
|
|
await update(ref, { number: 987 });
|
|
expectedValue = null;
|
|
await remove(ref);
|
|
off(ref);
|
|
});
|
|
});
|
|
|
|
describe('MESSAGING', () => {
|
|
it('getMessaging()', () => {
|
|
// @ts-ignore Stub missing browser APIs that FCM depends on
|
|
window.indexedDB = { open: () => Promise.resolve() };
|
|
// @ts-ignore Stub missing browser APIs that FCM depends on
|
|
navigator.serviceWorker = { addEventListener: () => {} };
|
|
getMessaging(app);
|
|
// @ts-ignore
|
|
delete window.indexedDB;
|
|
// @ts-ignore
|
|
delete navigator.serviceWorker;
|
|
});
|
|
});
|
|
|
|
describe('ANALYTICS', () => {
|
|
let analytics: Analytics;
|
|
it('analyticsIsSupported()', () => {
|
|
analyticsIsSupported();
|
|
});
|
|
it('getAnalytics()', () => {
|
|
const warn = jest.spyOn(console, 'warn').mockImplementationOnce(() => {});
|
|
analytics = getAnalytics(app);
|
|
expect(warn).toHaveBeenCalledWith(
|
|
expect.stringMatching('@firebase/analytics'),
|
|
expect.stringMatching(/IndexedDB unavailable/)
|
|
);
|
|
warn.mockRestore();
|
|
});
|
|
it("logEvent() doesn't error", () => {
|
|
logEvent(analytics, 'begin_checkout');
|
|
});
|
|
});
|
|
|
|
describe('PERFORMANCE', () => {
|
|
let performance: FirebasePerformance;
|
|
it('getPerformance()', () => {
|
|
performance = getPerformance(app);
|
|
});
|
|
it('trace()', () => {
|
|
const trace = perfTrace(performance, 'test');
|
|
trace.start();
|
|
trace.stop();
|
|
trace.putAttribute('testattr', 'perftestvalue');
|
|
expect(trace.getAttribute('testattr')).toBe('perftestvalue');
|
|
});
|
|
});
|
|
|
|
describe('AI', () => {
|
|
let ai: AI;
|
|
it('getAI with AgentPlatformBackend()', () => {
|
|
ai = getAI(app, { backend: new AgentPlatformBackend() });
|
|
});
|
|
it('getAI with VertexAIBackend()', () => {
|
|
expect(getAI(app, { backend: new VertexAIBackend() })).toBeDefined();
|
|
});
|
|
it('getGenerativeModel()', async () => {
|
|
const model = getGenerativeModel(ai, { model: 'gemini-3.5-flash' });
|
|
expect(model.model).toMatch(/gemini-3.5-flash$/);
|
|
});
|
|
});
|
|
|
|
describe('DATA CONNECT', () => {
|
|
let dataConnect: DataConnect;
|
|
it('getDataConnect()', () => {
|
|
dataConnect = getDataConnect(app, {
|
|
location: 'a-location',
|
|
connector: 'a-connector',
|
|
service: 'service'
|
|
});
|
|
});
|
|
it('dataConnect.getSettings()', () => {
|
|
expect(dataConnect.getSettings().location).toBe('a-location');
|
|
});
|
|
});
|
|
});
|