Error when testing against Firebase Emulator 'Expected type 'Pa', but it was: a custom Fa object' - javascript

I'm currently attempting to execute the following test in Cypress.
before(async () => {
testEnv = await initializeTestEnvironment({
projectId: MY_PROJECT_ID,
firestore: {
host: "localhost",
port: 8080,
},
});
});
describe("Authorized user can write to collection", () => {
it("Can write to firestore doc", async () => {
console.log("testEnv", testEnv);
const alice = testEnv.authenticatedContext("alice", { role: "user" });
console.log("alice", alice);
const firestore = alice.firestore();
console.log("firestore", firestore);
const testA = await assertSucceeds(
setDoc(alice.firestore(), "/users/alice"),
{
foo: "bar",
}
);
console.log("testA", testA);
});
});
The test fails before the final console.log during the setDoc call. The error is
Expected type 'Pa', but it was: a custom Fa object
I believe I traced this custom Fa object to the _delegate property on the firestore variable, but I am unclear of how to proceed from here.
I make sure that the emulators are all running before running npx cypress open
I tried setting the firestore property via the hub and get the same result
I have also tried passing a 'rules' property to firestore as a string
Any help would be greatly appreciated!

Related

Transaction failure while testing firebase firestore

I am trying to write some tests for the cloud functions I have written, but I am facing a problem where a transaction never succeeds and ends up in an error:
9 FAILED_PRECONDITION: the stored version (1648901730789554) does not match the required base version (0)
Problematic code is the following:
await firebase.db().runTransaction((t) => {
return t.get(docRef).then((doc) => {
if (!doc.exists) {
console.log("no exist");
}
});
});
It is run several times (checked with debugger), and then the error messages is thrown...
And the firebase test env init:
export async function initialize() {
fb.initializeTestApp({
projectId: "my-test-project",
auth: { uid: "alice", email: "alice#example.com" }
});
const testEnv = await initializeTestEnvironment({
projectId: "demo-project-1234",
firestore: {
rules: fs.readFileSync("../firestore.rules", "utf8"), // Load rules from file
// host and port can be omitted if they can be discovered from the hub.
},
});
const alice = testEnv.authenticatedContext(uid);
const db = (alice.firestore() as unknown) as firestore.Firestore;
firebase.db = () => db;
return testEnv;
}
Am I doing something wrong?
Note: I currently have only one test that runs, nothing else. And firebase emulators are running, without any other app accessing it.
After some more research, I have figured out that I was mixing #firebase/testing and firebase-admin, and the matter should not be used for unit testing backend functions according to this post.
On a side note, it seems there already is a function to create a doc iff it does not exist:
docRef.create(...).then(() => log("ok")).catch(() => log("Not ok"))

"TypeError: Cannot read property 'Stream' of undefined" While connecting to Athena from React

I am trying to connect to AWS Athena and execute a query. I am using athena-express for this. When I try to query I am getting the following error.
Error: TypeError: Cannot read property 'Stream' of undefined
I have checked the IAM Role if it has permissions and even tried with Administrator Role. Still getting the same issue. Any help would be appreciated.
Please find the sample code below
const AthenaExpress = require("athena-express"),
aws = require("aws-sdk"),
awsCredentials = {
region: "us-east-2",
accessKeyId: "MYKEYHERE",
secretAccessKey: "MYSECRETHERE"
};
aws.config.update(awsCredentials);
const athenaExpressConfig = {
aws,
getStats: true
};
const athenaExpress = new AthenaExpress(athenaExpressConfig);
function Analytics() {
(async () => {
let query = {
sql: "select * from test limit 10",
db: "sampledb",
getStats: true
};
try {
let results = await athenaExpress.query(query);
console.log(results);
} catch (error) {
console.log(error);
}
})();
console.log("I am here")
return(
<div>
<h1>This is it</h1>
</div>
)
}
export default Analytics;
It looks like you're using sample code to test this functionality, however, have you also created the sampledb that you're referring to in your code?
There's not a lot of context or information in the question, but best guess would be that you're trying to query something, that is not there.
You should use pagination property here to resolve this problem:
let query = {
sql: "SELECT 1",
db: "databasename",
getStats: true ,
pagination: number
};
You can refer this link to know more about the pagination:
https://github.com/ghdna/athena-express#more-examples

How come I can't use environment variables like this?

I have set up a monorepo for my project using lerna, and the website package is written using Next.
I have another package called omega=lib which acts as a library, and contains models/schemas for my mongo database. It also has a function that connects to it.
In my website, I am trying to fetch some data from the Channel schema (which exists in omega-lib), and the code for that looks like this:
Channel.ts
import { Schema, model, Document } from "mongoose";
import dbConnect from "../utils/dbConnect";
export interface IChannel extends Document {
name: string
logging_enabled: boolean
}
const ChannelSchema = new Schema({
name: { type: String, index: { unique: true } },
logging_enabled: Boolean
});
const Channel = model<IChannel>('Channel', ChannelSchema);
export const getChannel = async (username: string) => {
await dbConnect();
return Channel.findOne({ name: username });
}
export default Channel;
I am trying to use this code in one of my pages, using getServerSideProps:
export const getServerSideProps = async (context: GetServerSidePropsContext<ParsedUrlQuery>) => {
console.log("DB", process.env.MONGO_DB_URI);
const userInfo: User = await getUser(context);
const moderators: User[] = await getModerators(context);
const channelInfo = await getChannel(userInfo.login);
console.log("CHANNEL INFO", channelInfo);
return {
props: {
userInfo,
moderators,
channelInfo
}
}
}
IT IS WORTH NOTING, THAT ON LINE 2, THIS VALUE GETS LOGGED TO THE CONSOLE CORRECTLY!
Here's where the problem starts, when this code rus, I get this error:
MongooseError: The uri parameter to openUri() must be a string, got "undefined". Make sure the first parameter to mongoose.connect() or mongoose.createConnection() is a string.
This is coming from when the dbConnect() function is called. Here is the code for that:
import mongoose from 'mongoose';
const dbConnect = (uri?: string) => {
if (mongoose.connection.readyState >= 1) {
return;
}
return mongoose.connect(process.env.MONGO_DB_URI ?? uri, {
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false,
})
}
export default dbConnect;
I do not see how MONGO_DB_URI can be null, it is defined in my next.config.js:
module.exports = {
env: {
PRIVATE_KEY: "xxx",
CLIENT_ID: "xxx",
MONGO_DB_URI: "mongodb://localhost:27017/omegalogs",
REDIRECT_URI: "http://localhost:3000/login",
SCOPES: "user:read:email,moderation:read",
WEBSOCKET_PORT: 9393
},
};
And it is worth noting, that the correct value gets printed in the example code above, however it is undefined when being used in dbConnect().
This dbConnect() function is defined in a the omega-lib package, but is used as a dependency. I don't think this is the problem, because it works fine in another project that has the same MONGO_DB_URI defined in the environment file.
This only works if I actually pass the MONGO_DB_URI environment variable through as a parameter to dbConnect(), which is why it is an optional string.
Can anyone tell me why the dbConnect() function is not picking up the environment variable? It should be doing this server side, so I don't see why it wouldn't.
you already try to create a .env file and store the variables there for the process can see? you can install dotenv with:
npm i dotenv
//add dotenv to your index file
require('dotenv').config()
//this will in you .env file in the root of the project
PRIVATE_KEY: "xxx",
CLIENT_ID: "xxx",
MONGO_DB_URI: "mongodb://localhost:27017/omegalogs",
REDIRECT_URI: "http://localhost:3000/login",
SCOPES: "user:read:email,moderation:read",
WEBSOCKET_PORT: 9393
//now you can use in the same way
process.env.MONGO_DB_URI
is a easy way to do in my opinion

TypeError in "path" when running Firebase Functions Test

I'm writing a test for a google cloud function which'll write some information to a firestore database. The test uses firebase-functions-test and jest. The function I'm writing works successfully when I deploy it but when I try to run the test I get:
TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received type object
at GrpcClient.loadProto (node_modules/google-gax/src/grpc.ts:182:23)
at new FirestoreClient (node_modules/#google-cloud/firestore/build/src/v1/firestore_client.js:113:32)
at ClientPool.Firestore._clientPool.pool_1.ClientPool [as clientFactory] (node_modules/#google-cloud/firestore/build/src/index.js:319:26)
at ClientPool.acquire (node_modules/#google-cloud/firestore/build/src/pool.js:81:35)
at ClientPool.run (node_modules/#google-cloud/firestore/build/src/pool.js:155:29)
at Firestore.request (node_modules/#google-cloud/firestore/build/src/index.js:885:33)
at WriteBatch.commit_ (node_modules/#google-cloud/firestore/build/src/write-batch.js:450:14)
My function:
const admin = require('firebase-admin');
const functions = require('firebase-functions');
const db = admin.firestore();
const saveCheckup = functions.pubsub.topic('save-test').onPublish((message) => {
const {url, ...dataToSave} = message.attributes;
let current = db.collection('current').doc(url);
current.set(dataToSave, {merge: true})
return true;
});
module.exports = saveCheckup;
My test:
import * as admin from 'firebase-admin';
const testEnv = require('firebase-functions-test')(
{
databaseURL: "https://my-project.firebaseio.com",
projectId: 'my-project',
storageBucket: 'my-project.appspot.com'
}, "./my-project-firebase-adminsdk.json"
);
describe('saveCheckup', () => {
let adminStub, saveCheckup;
beforeAll(() => {
adminStub = jest.spyOn(admin, "initializeApp");
saveCheckup = require('../functions/save_checkup');
});
afterAll(() => {
adminStub.mockRestore();
testEnv.cleanup();
admin.database().ref("current").remove();
});
it("should save the user", async () => {
const wrapped = testEnv.wrap(saveCheckup);
await wrapped({attributes: {
date: "test date",
url: "testurl",
status: "200"
}});
const record = await admin.database().ref('/current/testurl').once('value');
expect(record.val()).toHaveProperty("status", "200");
})
});
Update: We were not able to solve this problem and ended up just writing offline tests for firestore instead.
The error output you posted shows that the error is within the Google Firebase node module files.
It even shows the line and character location:
at new FirestoreClient (node_modules/.../v1/firestore_client.js:113:32)
// Error location here ^
If you are trying to deploy locally please read this: https://firebase.google.com/docs/hosting/deploying
and follow the directions according to your situation.
Add a "jest.config.js" into the root directory keep the following code into the file
module.exports = {
testPathIgnorePatterns: ['lib/', 'node_modules/'],
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
testEnvironment: 'node'
};

How to fix firebase database initialised multiple times due to React SSR initialised database and cloud function firebase initialised database?

I have updated the question as found the root cause of the issue.
As I have hosted my React SSR app which uses firebase database in the client serving by one of the cloud function named app throwing an error of Error: FIREBASE FATAL ERROR: Database initialized multiple times. Please make sure the format of the database URL matches with each database() call.. When I comment out one by one and deploy, works perfectly. But when I deploy together doesn't work. How do I separate these two keeping both at the same repo?
ORIGINAL Question: Why firebase cloud function throwing an error of 'The default Firebase app does not exist.'?
So I am trying out firebase function for the first time. admin.messaging() throwing me the following error. Help me figure out why?
If I look at the console I get results till console.log('deviceToken', deviceToken);
so whats wrong in const messageDone = await admin.messaging().sendToDevice(deviceToken, payload);?
const functions = require('firebase-functions');
const admin = require('firebase-admin');
exports.updateUnreadCount = functions.database.ref('/chats/{chatId}/{messageId}')
.onCreate(async(snap, context) => {
const appOptions = JSON.parse(process.env.FIREBASE_CONFIG);
appOptions.databaseAuthVariableOverride = context.auth;
const adminApp = admin.initializeApp(appOptions, 'app');
const { message, senderId, receiverUid } = snap.val();
console.log(message, senderId, receiverUid);
console.log('------------------------');
const deleteApp = () => adminApp.delete().catch(() => null);
try {
const db = adminApp.database();
const reciverUserRef = await db.ref(`users/${receiverUid}/contacts/${senderId}/`);
console.log('reciverUserRef', reciverUserRef);
const deviceTokenSnapshot = await reciverUserRef.child('deviceToken').once('value');
const deviceToken = await deviceTokenSnapshot.val();
console.log('deviceToken', deviceToken);
const payload = {
notification: {
title: 'Test Notification Title',
body: message,
sound: 'default',
badge: '1'
}
};
const messageDone = await admin.messaging().sendToDevice(deviceToken, payload);
console.log('Successfully sent message: ', JSON.stringify(messageDone));
return deleteApp().then(() => res);
} catch (err) {
console.log('error', err);
return deleteApp().then(() => Promise.reject(err));
}
});
Update1: According to this https://firebase.google.com/docs/cloud-messaging/send-message#send_to_a_topic, admin.messaging().sendToDevice(deviceToken, payload) APIs are only available in the Admin Node.js SDK?
So switched to
const payload = {
data: {
title: 'Test Notification Title',
body: message,
sound: 'default',
badge: '1'
},
token: deviceToken
};
const messageDone = await admin.messaging().send(payload);
Which is not working either. Getting an error Error: The default Firebase app does not exist. Make sure you call initializeApp() before using any of the Firebase services. Any lead will be helpful.
EDIT: Finally got the function working.
My index.js is exporting to functions, follwoing
exports.app = functions.https.onRequest(app); //React SSR
exports.updateChat = functions.database.ref('/chats/{chatId}/{messageId}').onCreate(updateChat);
exports.app is a react ssr function, which I am using to host my site. This uses database too. and throwing error of multiple database instance.
When I comment out one by one and deploy, works perfectly. But when I deploy together doesn't work. How do I separate these two keeping both at the same repo? Any suggestions, please?
You can initialise db outside export function.
const admin = require('firebase-admin');
const adminApp = admin.initializeApp(appOptions, 'app')
//continue code
Update:
const admin = require('firebase-admin');
const adminApp = admin.initializeApp(options);
async function initialize(options, apps = 'app') {
try {
const defaultApp = adminApp.name
if(defaultApp) {
const adminApp1 = admin.initializeApp(apps);
}else {
const adminApp1 = admin.initializeApp(options, apps);
}
}catch(err) {
console.error(err);
}
}
Modify this snippet as per your need and try it out
It abstracts initialize of app in another function. Just call this function at appropriate place in your code.

Categories

Resources