How to test Cloud Functions with Firestore? - firebase

I'm trying to test cloud functions function.
But, in testing(npm run test) I got this error.
Why did I get this error? how to fix it?
TypeError: Path must be a string. Received undefined
at assertPath (path.js:7:11)
at Object.join (path.js:1218:7)
at database (node_modules/firebase-functions/lib/providers/firestore.js:36:45)
at Object.document (node_modules/firebase-functions/lib/providers/firestore.js:44:12)
at Object.<anonymous> (src/index.ts:6:21)
at Object.loadTypeScript (node_modules/espower-typescript/index.js:23:17)
at require (internal/module.js:20:19)
at Context.before (test/initialize-pair.ts:19:23)
This is my index.ts.
It is working as a real cloud functions function.
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp(functions.config().firebase);
export const aFunc = functions.firestore.document('/users/{uid}').onUpdate(() => { console.log('called')});
thanks

It looks like you're running npm run test without understanding what your particular test script is supposed to actually do. There isn't an npm script provided by the Firebase CLI for testing functions automatically.
If you want to do unit testing of your functions, read the advice in the documentation here.
If you want to use the local emulator to manually simulate events to your function, read the documentation here.

Related

when performing testing, I have `Bucket name not specified or invalid` error after initialize the app in Cloud Function

I know there are a lot of similar thread discussing similar issue, but I still don't find any solution because maybe my case is slightly different.
so I have this error when performing testing using Mocha in Firebase emulator
Error: Bucket name not specified or invalid. Specify a valid bucket
name via the storageBucket option when initializing the app, or
specify the bucket name explicitly when calling the getBucket()
method.
import * as admin from "firebase-admin";
export const app = admin.initializeApp();
const storage = app.storage();
const defaultBucket = storage.bucket(); // it seem error is in here
I am using cloud function, so I assume initializeApp() with empty argument is fine according to the documentation in here. but I have that error when run the test in emulator
my mocha test script is like this
export FIRESTORE_EMULATOR_HOST="localhost:8080" && export FIREBASE_AUTH_EMULATOR_HOST="localhost:9099" && mocha -r ts-node/register src/tests/cloud_function_tests --recursive --extension .test.ts --timeout 60000 --exit
and it seems that error only appears when I perform the testing, if I run those code above using emulator (without mocha testing), that error will never occured
I am using
Node 14
firebase-admin: 9.6.0
firebase-functions: 3.13.2
firebase tools: 9.10.0

How can I deploy a single Firebase Cloud Function in a group and a region?

I have created a group of Firebase Cloud Functions (v2) that are deployed in a region (europe-west1).
#index.ts
import * as apiV2 from './v2';
export const v2 = apiV2;
#v2.ts
export const addTextMessage = functions.region('europe-west1').onCall(
...
)
I want only to deploy the addTextMessage function.
I tried:
firebase deploy --only functions:v2-addTextMessage
# or
firebase deploy --only "functions:v2-addTextMessage(europe-west1)"
However the function is not deployed:
✔ functions: functions folder uploaded successfully
i functions: current functions in project: v2-addTextMessage(europe-west1)
⚠ functions: the following filters were specified but do not match any functions in the project: v2-addTextMessage(europe-west1)
What command should I use?
Try to replace the "-" by ".".
You should use :
firebase deploy --only functions:groupName.functionName
In your case :
firebase deploy --only functions:v2.addTextMessage
It's true that the CLI terminal log is misleading because if you've exceeded your deployment quota and the CLI detects that the name of your function is for instance v2-addTextMessage(europe-west-1), it will print a message suggesting you to use the command firebase deploy --only functions:v2-addTextMessage to deploy this function only, which doesn't work.
See the full Firebase CLI documentation here
You are using the correct command, however, you have not exported the addTextMessage function to your index.ts file, without that the deployment cannot find the funtion to deploy. You can export it by adding the following code to your index.ts:
export const v2-addTextMessage = apiV2.addTextMessage
Also, you cannot use the functions parameter and the function name as a String. So your command on this case would have to be:
firebase deploy --only functions:v2-addTextMessage
For Specifying region on deployment, as you already added to your code on the edited version of the question, you cannot do it on the FirebaseCLI command, thanks to #Doug Stevenson for pointing that out on the comment section.
Ideally, as you can see on this video, you would have to specify that in your cloud function code, before deployment by adding the following:
exports.v2-addTextMessage = functions
.region('europe-west1')
.storage.object().onFinalize((object) => { });

Firebase-tools is not uploading newly created functions to Firebase

I am working on an Angular project and I am writing Firebase functions that I would like to deploy to Firebase. As I write more functions for Firebase and try to deploy them to Firebase using firebase deploy --only functions, only existing functions get deployed. More specifically, I have 16 functions that I would like to deploy to Firebase but only the same 12 get deployed.
So far, I have done the following to try to fix the problem:
I made sure that I am on the latest firebase-tools (6.7.0)
I have tried specifying the newly written functions I would like to deploy using firebase deploy --only functions:<NEW FUNCTION NAME HERE>
Remove all export functions from the functions/src/index.ts file and upload a blank index.ts. Even when using a blank index.ts file, the same functions still get deployed to Firebase.
I know there can be up to a 30-second delay when uploading functions to Firebase, so I have even waited for an entire night before trying to upload new functions.
I have started from complete scratch using firebase init to recreate the whole functions directory and it still keeps uploading the same functions.
I upgraded from the free Firebase plan to the Spark plan.
The following code is the main index.ts file which is located in functions/src/index.ts.
import * as functions from 'firebase-functions';
import { firestore } from 'firebase-admin';
import * as moment from 'moment';
import { request } from 'https';
// Local Functions Imports
import * as Permissions from './permissions';
import * as Groups from './groups';
import * as Shifts from './shifts';
import * as Roles from './roles';
import * as Session from './sessions';
import * as Users from './users';
import * as Slack from './slack';
import * as ScheduleChanges from './schedule-changes';
import * as Email from './email';
// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
/* -------- USER MANAGEMENT -------------- */
export const createUser = Users.createUser;
export const addUserToDefaultJoinGroups = Users.addUserToDefaultJoinGroups;
export const deleteUser = Users.deleteUser;
/* -------- SESSION MANAGEMENT -------------- */
export const addSessionID = Session.addSessionID;
/* -------- ROLE MANAGEMENT -------------- */
export const addRoleID = Roles.addRoleID;
export const removeAllShiftsAssociatedWithRole = Roles.removeAllShiftsAssociatedWithRole;
/* -------- SHIFT MANAGEMENT -------------- */
export const addShiftID = Shifts.addShiftID;
export const hourly_job = Shifts.hourly_job;
export const changeShiftStatsTest = Shifts.changeShiftStatsTest;
/* -------- GROUPS MANAGEMENT -------------- */
export const addGroupID = Groups.addGroupID;
export const addGroupIDNewTestFunction = Groups.addGroupIDNewTestFunction;
/* -------- PERMISSIONS MANAGEMENT -------------- */
export const addPermissionID = Permissions.addPermissionID;
/* -------- Emailing -------------- */
export const sendWelcomeEmailToNewUser = Email.sendWelcomeEmailToNewUser;
export const sendWelcomeEmailToNewUser2 = Email.sendWelcomeEmailToNewUser2;
/* -------- SLACK MESSAGING MANAGEMENT -------------- */
export const sendWelcomingMessage = Slack.sendWelcomingMessage;
/* -------- SCHEDULE CHANGES MANAGEMENT -------------- */
export const addScheduleChangeID = ScheduleChanges.addScheduleChangeID;
As seen in the code above, there are 16 functions that should be deployed to Firebase. However, only 12 get deployed. The following code snippet is from functions/src/groups/index.ts. In this file, the addGroupID is an existing function which continually gets deployed to Firebase. On the other hand, addGroupIDNewTestFunction is a new function that isn't getting deployed to Firebase even though they are in the same file and being referenced the same way.
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin'
export const addGroupID = functions.firestore
.document("organizations/{organizationID}/groups/{groupID}")
.onCreate(async (snap, context) => {
console.log("Adding group id");
await admin.firestore()
.doc(`organizations/${context.params.organizationID}/groups/${context.params.groupID}`).update({
'groupID': context.params.groupID
})
})
export const addGroupIDNewTestFunction = functions.firestore
.document("organizations/{organizationID}/groups2/{groupID}")
.onCreate(async (snap, context) => {
console.log("Adding group id");
await admin.firestore()
.doc(`organizations/${context.params.organizationID}/groups/${context.params.groupID}`).update({
'groupID': context.params.groupID
})
})
As mentioned previously, I have specified 16 functions in the main index.ts file that should get deployed to Firebase functions. However, only the existing 12 functions are getting deployed. The following code snippet is the output firebase gives me when I run firebase deploy --only functions inside the Angular project.
firebase deploy --only functions
=== Deploying to 'university-scheduling'...
i deploying functions
Running command: npm --prefix "$RESOURCE_DIR" run lint
> functions# lint /Users/brandon/Dropbox/Bearforce_Scheduling/bearforce-website/functions
> tslint --project tsconfig.json
no-unused-variable is deprecated. Since TypeScript 2.9. Please use the built-in compiler checks instead.
Could not find implementations for the following rules specified in the configuration:
use-input-property-decorator
use-output-property-decorator
use-host-property-decorator
Try upgrading TSLint and/or ensuring that you have all necessary custom rules installed.
If TSLint was recently upgraded, you may have old rules configured which need to be cleaned up.
WARNING: /Users/brandon/Dropbox/Bearforce_Scheduling/bearforce-website/functions/src/email/index.ts:2:13 - 'admin' is declared but its value is never read.
WARNING: /Users/brandon/Dropbox/Bearforce_Scheduling/bearforce-website/functions/src/index.ts:2:1 - All imports on this line are unused.
WARNING: /Users/brandon/Dropbox/Bearforce_Scheduling/bearforce-website/functions/src/index.ts:3:13 - 'moment' is declared but its value is never read.
WARNING: /Users/brandon/Dropbox/Bearforce_Scheduling/bearforce-website/functions/src/index.ts:4:1 - All imports on this line are unused.
WARNING: /Users/brandon/Dropbox/Bearforce_Scheduling/bearforce-website/functions/src/slack/index.ts:2:13 - 'admin' is declared but its value is never read.
WARNING: /Users/brandon/Dropbox/Bearforce_Scheduling/bearforce-website/functions/src/slack/index.ts:6:7 - 'request' is declared but its value is never read.
WARNING: /Users/brandon/Dropbox/Bearforce_Scheduling/bearforce-website/functions/src/slack/index.ts:7:7 - 'options' is declared but its value is never read.
WARNING: /Users/brandon/Dropbox/Bearforce_Scheduling/bearforce-website/functions/src/users/index.ts:3:1 - All imports on this line are unused.
WARNING: /Users/brandon/Dropbox/Bearforce_Scheduling/bearforce-website/functions/src/users/index.ts:43:11 - 'groups' is declared but itsvalue is never read.
WARNING: /Users/brandon/Dropbox/Bearforce_Scheduling/bearforce-website/functions/src/users/index.ts:65:11 - 'uid' is declared but its value is never read.
Running command: npm --prefix "$RESOURCE_DIR" run build
> functions# build /Users/brandon/Dropbox/Bearforce_Scheduling/bearforce-website/functions
> tsc
✔ functions: Finished running predeploy script.
i functions: ensuring necessary APIs are enabled...
✔ functions: all necessary APIs are enabled
i functions: preparing functions directory for uploading...
i functions: packaged functions (106.24 KB) for uploading
✔ functions: functions folder uploaded successfully
⚠ appEngineLocation us-central1
i functions: updating Node.js 6 function createUser(us-central1)...
i functions: updating Node.js 6 function deleteUser(us-central1)...
i functions: updating Node.js 6 function addSessionID(us-central1)...
i functions: updating Node.js 6 function addRoleID(us-central1)...
i functions: updating Node.js 6 function removeAllShiftsAssociatedWithRole(us-central1)...
i functions: updating Node.js 6 function addShiftID(us-central1)...
i functions: updating Node.js 6 function hourly_job(us-central1)...
i functions: updating Node.js 6 function changeShiftStatsTest(us-central1)...
i functions: updating Node.js 6 function addGroupID(us-central1)...
i functions: updating Node.js 6 function addPermissionID(us-central1)...
i functions: updating Node.js 6 function sendWelcomingMessage(us-central1)...
i functions: updating Node.js 6 function addScheduleChangeID(us-central1)...
✔ scheduler: all necessary APIs are enabled
✔ functions[addPermissionID(us-central1)]: Successful update operation.
✔ functions[createUser(us-central1)]: Successful update operation.
✔ functions[addShiftID(us-central1)]: Successful update operation.
✔ functions[changeShiftStatsTest(us-central1)]: Successful update operation.
✔ functions[sendWelcomingMessage(us-central1)]: Successful update operation.
✔ functions[hourly_job(us-central1)]: Successful update operation.
✔ functions[addSessionID(us-central1)]: Successful update operation.
✔ functions[deleteUser(us-central1)]: Successful update operation.
✔ functions[addGroupID(us-central1)]: Successful update operation.
✔ functions[removeAllShiftsAssociatedWithRole(us-central1)]: Successful update operation.
✔ functions[addScheduleChangeID(us-central1)]: Successful update operation.
✔ functions[addRoleID(us-central1)]: Successful update operation.
✔ Deploy complete!
Please note that it can take up to 30 seconds for your updated functions to propagate.
You should check the directory which is compiled js files.
The default is functions/lib/.
If you import like ../../foo.ts anywhere at functions/src or functions/src/tests, etc then the compiled js file is functions/lib/{any}/foo.js.
The deploy target files are functions/lib/*.js only. So, functions/lib/{any}/foo.js is ignored.
You should change directory or files structure.
If the reason is test files then you should meke tsconfig.json for deploy and exclude them.
I wanted to give you guys an update on the solution to the problem I described above. In one of my index.ts files, I had the following require statement, var mailgun = require('mailgun-js'). Whenever I replaced this the require statement with import * as mailgun from 'mailgun-js', all the functions were deployed properly.
The most confusing part about this whole issue was that I only received success messages even when things weren't working properly. I do thank you guys for the speedy support and all of your suggestions!!
I had the exact same problem and the solution was Editing functions/src/index.ts instead of functions/lib/index.js
In my case it's index.ts because of I selected that option when initialized the project with "firebase init", your case depends on it, can be index.js too, but always on /src and not in /lib.
I think that the /lib folder if for the compiled file.
When deploying functions the compiler converts the src/.ts files into "lib/src/.js" files.
Somehow I had some files hanging around from previous deployments in the "lib/*js" space. Sure enough these files were getting deployed but the files containing the new function I had created were located in "lib/src/*js. No new changes were being passed up into cloud functions.
and so I went into package.json and changed
"main": "lib/index.js",
to read
"main": "lib/src/index.js",
And to cleanup I deleted all .js files from "lib/
I was back in business.

Deploying firebase cloud function in typescript

I'm trying to deploy the very first cloud function.
It works perfectly fine, but when I try to deploy it in terminal, it sets out warning saying that "functions is declared but it's value is never read".
Is this some common starting mistake, as I am new to this subject? Thank you.
I tried both imports , deploy erros remains same
// const functions = require('firebase-functions');
import * as functions from 'firebase-functions'
Errors message
index.ts file code here
Your code doesn't declare any Cloud Functions yet, so eslint warns you that you're importing functions but not using it.
The message will disappear when you declare a Cloud Function in your index.js/index.ts. For example, the documentation on getting started contains this example:
exports.addMessage = functions.https.onRequest((req, res) => {
const original = req.query.text;
return admin.database().ref('/messages').push({original: original}).then((snapshot) => {
return res.redirect(303, snapshot.ref.toString());
});
});
As you can see, this code uses functions in its first line. So if you add this (or any other Cloud Functions declaration) to your code, you're using functions and eslint will no longer warn you about it not being used.
The error will disappear when you finally use "functions" in a cloud function.
nevermind, you are better off using
const functions = require('firebase-functions');
when importing firebase-functions in your index.js
========
EDIT : ======
Make sure that you have correctly installed those dependencies, by running those npm commands in the right folder:
npm install firebase-functions#latest firebase-admin#latest --save
npm install -g firebase-tools
Probably solved, but for me I was expecting ~/functions/index.ts to be the file building but the firebase cli added ~/functions/src/index.ts and THAT was the file.

functions: Error from emulator. Error occurred while parsing your function triggers

I'm testing firebase functions locally in my existing project in typescript. When i run following command, i always get typeerror even though i can upload it to firebase project. the error always occured after typescript compile to js
firebase serve --only functions
TypeError: Cannot read property 'username' of undefined
at Object. (C:\Users\phone\Desktop\VMS\mynewvm_functions\functions\lib\email\index.js:8:52)
at Module._compile (module.js:635:30)
at Object.Module._extensions..js (module.js:646:10)
at Module.load (module.js:554:32)
at tryModuleLoad (module.js:497:12)
at Function.Module._load (module.js:489:3)
at Module.require (module.js:579:17)
at require (internal/module.js:11:18)
at Object. (C:\Users\phone\Desktop\VMS\mynewvm_functions\functions\lib\index.js:19:15)
at Module._compile (module.js:635:30)
import * as functions from 'firebase-functions';
import * as nodemailer from 'nodemailer';
const accountname = functions.config().emailaccount.username;
const accountpassword = functions.config().emailaccount.password;
/* smtp configuration */
I already set emailaccount in my project, below is my code.
firebase functions:config:set emailaccount.username="email#domain.com"
emailaccount.password="mypassword"
Please note that it is working fine when uploaded to firebase functions but it's not when serving locally. what can i do to make it work locally?
Finally, I just replace all my credentials with actual values instead of getting from firebase config. And I cd to functions folder and type 'npm start'. it look like when i run 'firebase serve --only functions', it doesn't apply with recent changes so give me the same error until I type 'npm start' which will run tsc and firebase shell, stop it (ctrl+c) then type 'firebase serve --only functions' again. Fyi, I created my current firebase functions project using firebase cli and typescript.
firebase cli - 3.18.4
firebase functions - ^1.0.1
firebase admin - 5.12.0
#google-cloud/storage - 1.6
After testing for long period of time, I decided to put username, password and tokens directly in my functions for local testing although I don't really like this idea and I change back to functions.config().. when i deploy to firebase. Thanks for #Frank for answers
There is no built-in config parameter called emailaccount, so it seems you defined it yourself.
The local environment does not automatically contain these variables. You will actually have to define them in a file called runtimeconfig.json. An easy way to do that is shown here:
cd functions
firebase functions:config:get > .runtimeconfig.json

Resources