Files

360 lines
10 KiB
JavaScript

/**
* @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 } from 'firebase/app';
import { getAuth, signInWithEmailAndPassword, signOut } from 'firebase/auth';
import {
getAnalytics,
isSupported as analyticsIsSupported,
logEvent
} from 'firebase/analytics';
import { initializeAppCheck, CustomProvider } from 'firebase/app-check';
import {
getFunctions,
httpsCallable,
httpsCallableFromURL
} from 'firebase/functions';
import {
getStorage,
ref,
uploadString,
getDownloadURL,
deleteObject
} from 'firebase/storage';
import {
getFirestore,
collection,
setDoc,
doc,
updateDoc,
deleteDoc,
getDocs,
query,
where,
onSnapshot
} from 'firebase/firestore';
import { getMessaging, getToken } from 'firebase/messaging';
import { getPerformance, trace as perfTrace } from 'firebase/performance';
import {
getDatabase,
ref as dbRef,
set,
update,
remove,
onValue,
off
} from 'firebase/database';
import { getGenerativeModel, getAI, AgentPlatformBackend } from 'firebase/ai';
import { getDataConnect, DataConnect } from 'firebase/data-connect';
/**
* The config file should look like:
*
* // A config for a project
* export const config = {
* apiKey: ************,
* authDomain: ************,
* databaseURL: ************,
* projectId: ************,
* storageBucket: ************,
* messagingSenderId: ************,
* appId: ************,
* measurementId: ************
* };
*
* // A user account with read/write privileges in that project
* // for storage, database, firestore
* export const testAccount = {
* email: ************,
* password: ************
* }
*/
import { config, testAccount } from '../firebase-config';
/**
* Quick sample app to debug and explore basic Firebase API usage/problems.
*
* In order for app check to work, add the app check debug token to
* build/index.html and uncomment the line.
*/
/**
* Auth smoke test.
*
* Login with email and password. Account must exist. Should set up
* test project rules to only allow read/writes from this account
* (and other test accounts), to properly test rules.
*
* Logout after all tests are done.
*/
async function authLogin(app) {
const auth = getAuth(app);
const cred = await signInWithEmailAndPassword(
auth,
testAccount.email,
testAccount.password
);
console.log('[AUTH] Logged in with test account', cred.user.email);
return cred;
}
async function authLogout(app) {
console.log('[AUTH] Logging out user');
return signOut(getAuth(app));
}
/**
* Functions smoke test.
*
* Call a deployed function.
* This cloud function must be deployed in this project first. See
* e2e/smoke-tests/README.md for more info.
*/
async function callFunctions(app) {
console.log('[FUNCTIONS] start');
const functions = getFunctions(app);
let callTest = httpsCallable(functions, 'callTestv2');
try {
const result = await callTest({ data: 'blah' });
console.log('[FUNCTIONS] result (by name):', result.data);
} catch (e) {
if (e.message.includes('Unauthenticated')) {
console.warn(
'Functions blocked by App Check. ' +
'Activate app check with a live sitekey to allow Functions calls'
);
} else {
throw e;
}
}
callTest = httpsCallableFromURL(
functions,
`https://us-central1-${app.options.projectId}.cloudfunctions.net/callTestv2`
);
try {
const result = await callTest({ data: 'blah' });
console.log('[FUNCTIONS] result (by URL):', result.data);
} catch (e) {
if (e.message.includes('Unauthenticated')) {
console.warn(
'Functions blocked by App Check. ' +
'Activate app check with a live sitekey to allow Functions calls'
);
} else {
throw e;
}
}
}
/**
* Storage smoke test.
* Create, read, delete.
*/
async function callStorage(app) {
console.log('[STORAGE] start');
const storage = getStorage(app);
const storageRef = ref(storage, '/test.txt');
await uploadString(storageRef, 'efg');
await new Promise(resolve => setTimeout(resolve, 1000));
const url = await getDownloadURL(storageRef);
console.log('[STORAGE] download url', url);
const response = await fetch(url);
const data = await response.text();
console.log("[STORAGE] Returned data (should be 'efg'):", data);
await deleteObject(storageRef);
}
/**
* Firestore smoke test.
* Create 2 docs, test query filter.
* Create, update, delete a doc with `onSnapshot` monitoring changes.
*/
async function callFirestore(app) {
console.log('[FIRESTORE] start');
const firestore = getFirestore(app);
setDoc(doc(collection(firestore, 'testCollection'), 'trueDoc'), {
testbool: true
});
setDoc(doc(collection(firestore, 'testCollection'), 'falseDoc'), {
testbool: false
});
const trueDocs = await getDocs(
query(
collection(firestore, 'testCollection'),
where('testbool', '==', true)
)
);
trueDocs.docs.forEach(doc =>
console.log('[FIRESTORE] Filter test, expect one doc', doc.data())
);
await deleteDoc(doc(collection(firestore, 'testCollection'), 'trueDoc'));
await deleteDoc(doc(firestore, 'testCollection/falseDoc'));
const testDocRef = doc(firestore, 'testCollection/testDoc');
console.log('[FIRESTORE] Doc creation and updating');
onSnapshot(testDocRef, snap => {
if (snap.exists) {
console.log('[FIRESTORE] SNAPSHOT:', snap.data());
} else {
console.log("[FIRESTORE] Snapshot doesn't exist");
}
});
console.log('[FIRESTORE] creating (expect to see snapshot data)');
await setDoc(testDocRef, { word: 'hi', number: 14 });
console.log('[FIRESTORE] updating (expect to see snapshot data change)');
await updateDoc(testDocRef, { word: 'bye', newProp: ['a'] });
console.log("[FIRESTORE] deleting (expect to see snapshot doesn't exist)");
await deleteDoc(testDocRef);
}
/**
* Database smoke test.
* Create, update, delete a doc with `on` monitoring changes.
*/
async function callDatabase(app) {
console.log('[DATABASE] start');
const db = getDatabase(app);
const ref = dbRef(db, 'abc/def');
onValue(ref, snap => {
if (snap.exists()) {
console.log(`[DATABASE] value: ${JSON.stringify(snap.val())}`);
} else {
console.log("[DATABASE] Snapshot doesn't exist");
}
});
console.log('[DATABASE] creating (expect to see snapshot data)');
await set(ref, { text: 'string 123 xyz' });
console.log('[DATABASE] updating (expect to see snapshot data change)');
await update(ref, { number: 987 });
console.log("[DATABASE] deleting (expect to see snapshot doesn't exist)");
await remove(ref);
off(ref);
}
/**
* Messaging smoke test.
* Call getToken(), it may be blocked if user does not click "Allow" for
* notification permissions, or has blocked it on this same host in the past.
*/
async function callMessaging(app) {
console.log('[MESSAGING] start');
const messaging = getMessaging(app);
try {
const token = await getToken(messaging);
console.log(`[MESSAGING] Got token: ${token}`);
} catch (e) {
if (e.message.includes('messaging/permission-blocked')) {
console.log('[MESSAGING] Permission blocked (expected on localhost)');
} else {
throw e;
}
}
}
/**
* Analytics smoke test.
* Just make sure some functions can be called without obvious errors.
*/
function callAnalytics(app) {
console.log('[ANALYTICS] start');
analyticsIsSupported();
const analytics = getAnalytics(app);
logEvent(analytics, 'begin_checkout');
console.log('[ANALYTICS] logged event');
}
/**
* App Check smoke test.
* Just make sure some functions can be called without obvious errors.
*/
function callAppCheck(app) {
console.log('[APP CHECK] start');
initializeAppCheck(app, {
provider: new CustomProvider({
getToken: () => Promise.resolve({ token: 'abcd' })
})
});
console.log('[APP CHECK] initialized');
}
/**
* Performance smoke test.
* Just make sure some functions can be called without obvious errors.
*/
function callPerformance(app) {
console.log('[PERFORMANCE] start');
const performance = getPerformance(app);
const trace = perfTrace(performance, 'test');
trace.start();
trace.stop();
trace.putAttribute('testattr', 'perftestvalue');
console.log(
"[PERFORMANCE] trace (should be 'perftestvalue')",
trace.getAttribute('testattr')
);
}
/**
* AI smoke test.
* Just make sure some functions can be called without obvious errors.
*/
async function callAI(app) {
console.log('[AI] start');
const ai = getAI(app, { backend: new AgentPlatformBackend() });
const model = getGenerativeModel(ai, { model: 'gemini-3.5-flash' });
const result = await model.countTokens('abcdefg');
console.log(`[AI] counted tokens: ${result.totalTokens}`);
}
/**
* DataConnect smoke test.
* Just make sure some functions can be called without obvious errors.
*/
function callDataConnect(app) {
console.log('[DATACONNECT] start');
getDataConnect(app, {
location: 'a-location',
connector: 'a-connector',
service: 'service'
});
console.log('[DATACONNECT] initialized');
}
/**
* Run smoke tests for all products.
* Comment out any products you want to ignore.
*/
async function main() {
console.log('FIREBASE VERSION', SDK_VERSION);
const app = initializeApp(config);
setLogLevel('warn');
callAppCheck(app);
await authLogin(app);
await callStorage(app);
await callFirestore(app);
await callDatabase(app);
await callMessaging(app);
callAnalytics(app);
callPerformance(app);
await callFunctions(app);
await callAI(app);
callDataConnect(app);
await authLogout(app);
console.log('DONE');
}
main();