React-Native app doesn't work if i use await - javascript

This is the first time I'm using react-native to develop an Android app.
I'm trying to use async/await when I retrieve some data from firestore, but when I add the word await the app crashes and it won't start anymore.
I use react-native-firebase library as you can see in my package.json file.
This is the part of my component that doesn't work:
componentDidMount() {
this.getAccountFromFirestore(this.props.user);
}
getAccountFromFirestore = async user => {
const accounts = await firebase
.firestore()
.collection('accounts')
.get();
this.setState({ loading: false });
};
This is my package.json, if it's usefull
{
"name": "myapp",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"test": "jest",
"ios": "react-native run-ios",
"android": "react-native run-android"
},
"dependencies": {
"native-base": "^2.8.1",
"react": "16.6.1",
"react-native": "0.57.6",
"react-native-firebase": "^5.1.1",
"react-native-navigation": "^1.1.493",
"react-native-vector-icons": "^6.1.0",
"react-redux": "^5.1.1",
"redux": "^4.0.1"
},
"devDependencies": {
"babel-jest": "23.6.0",
"jest": "23.6.0",
"metro-react-native-babel-preset": "0.49.2",
"react-test-renderer": "16.6.1"
},
"jest": {
"preset": "react-native"
}
}

You can implement with Promise like :
firebase
.firestore()
.collection('accounts')
.get()
.then(accounts => {
console.log ('Use accounts variable as per your requirement,'accounts)
})
.catch(error => {console.error(error)})

I don't know whether it's your React Native or if you're using Node 6. But for what I know, async/await is only supported on Node 8 or above. So, your best bet is still using Promises with this problem. For example:
componentDidMount() {
this.getAccountFromFirestore(this.props.user);
}
getAccountFromFirestore = user => {
firebase
.firestore()
.collection('accounts')
.get()
.then(accounts => {
let data = accounts.docs.map(account => account.data());
console.log(data);
this.setState({ loading: false });
})
.catch(err => console.log(err));
};
Also when using async/await, don't forget the try-catch blocks:
componentDidMount() {
this.getAccountFromFirestore(this.props.user);
}
getAccountFromFirestore = async user => {
try {
const accounts = await firebase
.firestore()
.collection('accounts')
.get();
const data = accounts.docs.map(a => a.data());
console.log(data);
this.setState({ loading: false });
} catch (err) {
console.error(err);
}
};

Option a) keep using promises
Option b) Migrate that RN, if you can use async/await your code is prob too old to go in the stores anyway.
Option c) Babel...

Related

Firebase 'collection' is not exported from 'firebase/firestore'

I'm trying to import "collection" on my project, but I got this error only on "collection". I followed the firebase docs about query, but I've no idea how to solve it.
React:
import { query, where, getDocs, collection } from "firebase/firestore";
const [username, setUsername] = useState("")
const [utente, setUtente] = useState(null)
const [err, setErr] = useState(false)
const handleSearch = async () =>{
const q = query(collection(db, "users"), where("displayName", "==", username)
);
const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
});};
const handleKey = e=>{
e.code === "Enter" && handleSearch();
};
Package.json:
{
"name": "whatsapp-clone",
"version": "0.1.0",
"private": true,
"dependencies": {
"#emotion/react": "^11.10.4",
"#emotion/styled": "^11.10.4",
"#material-ui/core": "^4.11.4",
"#material-ui/icons": "^4.11.2",
"#mui/material": "^5.10.5",
"compressorjs": "^1.0.7",
"emoji-picker-react": "^3.6.2",
"firebase": "^8.6.3",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-firebase-hooks": "^3.0.4",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.3",
"react-scrollable-feed": "^1.3.1",
"uuid": "^8.3.2"
},
Thank you very much in advance
You are using Firebase 8.6.3 but the modular syntax was introduced starting from v9.0.0. Upgrading to latest version should fix the issue:
npm i firebase#latest
You can alternatively use the Namespaced syntax with the current version but I'll recommend upgrading and using the new one.

Firebase functions crashes while accessing firestore

Could you please find an error in following code?
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
exports.GetShort = functions.https.onRequest((request, response) => {
response.header("Access-Control-Allow-Origin", "*");
longURL = request.query.long
functions.logger.info("url is - " ,longURL)
SaveToDB(longURL)
})
function SaveToDB(link){
functions.logger.info("here")
admin.firestore().collection("url").where("urlNames","array_contains",link).get().then(
function(querySnapshot){
functions.logger.info("snap, " ,querySnapshot)
querySnapshot.forEach(function(doc) {
functions.logger.info("things : " ,doc.id, " => ", doc.data())
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
});
}
) .catch(function(error) {
functions.logger.info("Error getting documents: ", error);
});
}
After hitting above function, firebase-functions logs displays logs till "here". After that it crashes without any more logs/stacktrace.
below is the contents of packages.json from functions directory.
{
"name": "functions",
"description": "Cloud Functions for Firebase",
"scripts": {
"lint": "eslint .",
"serve": "firebase emulators:start --only functions",
"shell": "firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"engines": {
"node": "14"
},
"main": "index.js",
"dependencies": {
"firebase-admin": "^9.8.0",
"firebase-functions": "^3.14.1"
},
"devDependencies": {
"eslint": "^7.6.0",
"eslint-config-google": "^0.14.0",
"firebase-functions-test": "^0.2.0"
},
"private": true
}
I would kindly suggest you watch the 3 videos about "JavaScript Promises" from the Firebase video series to see how to manage the life cycle of a Cloud Function and the way to deal with calls to asynchronous methods.
In particular, for an HTTPS Cloud Function, you need to end it with send(), redirect(), or end().
So your code could be adapted as follows:
exports.GetShort = functions.https.onRequest((request, response) => {
response.header("Access-Control-Allow-Origin", "*");
const longURL = request.query.long;
functions.logger.info("url is - ", longURL)
SaveToDB(longURL)
.then(() => {
response.status(200).send('Saved to DB');
})
.catch(error => {
// See video series
response.status(500).send(error);
})
})
function SaveToDB(link) {
functions.logger.info("here")
return admin.firestore().collection("url").where("urlNames", "array_contains", link).get()
.then(querySnapshot => {
functions.logger.info("snap, ", querySnapshot)
querySnapshot.forEach(function (doc) {
functions.logger.info("things : ", doc.id, " => ", doc.data())
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
// => Here, depending on your real functional requirements, you may need to use Promise.all()
});
return null;
}
).catch(function (error) {
functions.logger.info("Error getting documents: ", error);
// Throw an error
});
}
Well, I found the problem. Sometimes silly things make most of the noise around.
Instead of "array-contains", I wrote "array_contains".

TypeError: querySnapshot.forEach is not a function - Firebase Cloud Functions

I have a data structure made this way:
Posts(collection)
UserId(document)
Posts(collection)
postDoc (document)
And I'm setting a cloud function to change all Posts(subcollection) documents upon a certain event, and in order to do so I'm using collectionGroup queries:
This is how I set it up:
exports.changeIsVisibleFieldAfterDay = functions.pubsub
.schedule("every 2 minutes").onRun((context) => {
const querySnapshot = db.collectionGroup("Posts")
.where("isVisible", "==", true).get();
querySnapshot.forEach((doc) => {
console.log(doc.data());
});
});
In the Firebase Log I receive the following error:
TypeError: querySnapshot.forEach is not a function
Searching online I found out that there may be a problem with Firebase SDK version but mine is uptodate, I attach the package.json file here:
{
"name": "functions",
"description": "Cloud Functions for Firebase",
"scripts": {
"lint": "eslint .",
"serve": "firebase emulators:start --only functions",
"shell": "firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"engines": {
"node": "12"
},
"main": "index.js",
"dependencies": {
"firebase-admin": "^9.2.0",
"firebase-functions": "^3.11.0"
},
"devDependencies": {
"eslint": "^7.6.0",
"eslint-config-google": "^0.14.0",
"firebase-functions-test": "^0.2.0"
},
"private": true
}
The get() method is asynchronous, so you either need to use then() to get the querySnapshot when the Promise returned by get() is fulfilled, or use async/await. More details on how to deal with asynchronous calls in this SO answer.
With then()
const functions = require('firebase-functions');
// The Firebase Admin SDK to access Firestore.
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
exports.changeIsVisibleFieldAfterDay = functions.pubsub
.schedule("every 2 minutes").onRun((context) => {
return db.collectionGroup("Posts").where("isVisible", "==", true).get()
.then(querySnapshot => {
querySnapshot.forEach((doc) => {
console.log(doc.data());
});
return null;
})
});
With async/await
const functions = require('firebase-functions');
// The Firebase Admin SDK to access Firestore.
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
exports.changeIsVisibleFieldAfterDay = functions.pubsub
.schedule("every 2 minutes").onRun(async (context) => {
const querySnapshot = await db.collectionGroup("Posts").where("isVisible", "==", true).get();
querySnapshot.forEach((doc) => {
console.log(doc.data());
});
return null;
});
Note the return null; at the end. See this doc item for more details on this key point.
Note also that if you want to update several docs within the forEach() loop, you will need to use Promise.all(). Many SO answers cover this case.

I am trying to run my test script using mocha but there is an error of "Reference Error: beforeEach is not defined"

Mocha test Suite gives a reference error and it says "beforeEach is not defined"
I am trying to run my test script for my todo app in node.js using mocha. But there is a reference error and it says "beforeEach is not defined"
const {app} = require('./../server');
const {Todo} = require('./../models/todo');
beforeEach((done) => {
Todo.remove({}).then(() => done());
});
describe('POST /todos', () => {
it('should create a new todo', (done) => {
var text = 'Test todo text';
request(app)
.post('/todos')
.send({text})
.expect(200)
.expect((res) => {
expect(res.body.text).toBe(text);
})
.end((err, res) => {
if (err) {
return done(err);
}
Todo.find().then((todos) => {
expect(todos.length).toBe(1);
expect(todos[0].text).toBe(text);
done();
}).catch((e) => done(e));
});
});
it('should not create todo with invalid body data', (done) => {
request(app)
.post('/todos')
.send({})
.expect(400)
.end((err, res) => {
if (err) {
return done(err);
}
Todo.find().then((todos) => {
expect(todos.length).toBe(0);
done();
}).catch((e) => done(e));
});
});
});
Also, I have included all the necessary packages for my package.json file.
My Package.json file is given below
{
"name": "todo-api",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "mocha server/**/*.test.js",
"test-watch": "nodemon --exec 'npm test' "
},
"author": "",
"license": "ISC",
"dependencies": {
"bluebird": "^3.5.3",
"body-parser": "^1.15.2",
"express": "^4.14.0",
"mongodb": "^2.2.5",
"mongoose": "^4.5.9"
},
"devDependencies": {
"expect": "^1.20.2",
"mocha": "^3.0.2",
"nodemon": "^1.10.2",
"supertest": "^2.0.0"
}
}
It looks to me like you are trying to clear out your data in your MongoDB database before each new test of your todo app. So you want to find your collection of todo and drop everything in there before your next test, if so
beforeEach(() => {
mongoose.connection.collections.todo
});
With the above you are directly referencing the collection of todo sitting inside your database and you call the drop() function on your collection of todo.
beforeEach(() => {
mongoose.connection.collections.todo.drop();
});
Please let me know if I am correct in fulfilling your requirement. Keep in mind this is an asynchronous operation, so you need to ensure you pause the entire testing environment until the operation is complete, but you already know this, because you have already attempted to implement the done callback.
Also, drop() will accept a callback function like so:
beforeEach((done) => {
mongoose.connection.collections.todo.drop(() => {});
});
The function will only be executed once you are done with the collection. So you also have to pass the done() callback after defining it like so:
beforeEach((done) => {
mongoose.connection.collections.todo.drop(() => {
done();
});
});
Also, when you run a Mocha test, you do npm run test.
I've just tried to replicate your issue with the test with simple repository using your package.json file. My test file
const expect = require('expect');
beforeEach((done) => {
done();
});
describe('just a test', function() {
it('test', function() {
expect(true).toBe(true);
})
});
Then, when running npm t, the test was executed successfully.
Perhaps there is a misconfiguration in your project.

Why is my Mocha/Chai test giving a false positive?

As a pre-cursor to this question, I am a novice at Node, JS, Mocha and Chai!
I have a set of tests which I run using npm run start, in which 'start' defines a script within my Package.json file:
"devDependencies": {
"chai": "^3.5.0",
"chai-as-promised": "^7.1.1",
"cli-color": "^1.1.0",
"concurrently": "^3.1.0",
"mocha": "^5.2.0"
},
"dependencies": {
"body-parser": "^1.16.1",
"cors": "^2.8.1",
"express": "^4.14.0",
"moment": "^2.18.1",
"superagent": "^3.3.2"
}
Here is my test:
const expect = require('chai').expect;
const screenshotFolder = 'puppeteer/test/screenshots';
module.exports = async(page) => {
const frame = page.frames().find(frame => frame.name() === 'iframe');
const allChoicesButton = await frame.$('.statement a.all-choices');
await allChoicesButton.click({});
const saveYourChoicesButton = await frame.$('.button.permissions-block__submit');
await saveYourChoicesButton.click({});
try {
const confirmationMessageText = await frame.$eval('.submission-response__copy > p', e => e.textContent);
describe('User can choose all', function() {
it('Click choose all and display a confirmation message', function(done) {
expect(confirmationMessageText).to.equal('Thank you. Your choices have been updatedx.').
notify(done)
});
});
} catch (err) {
await page.screenshot({
path: screenshotFolder + '/confirmationMessageText.png',
fullPage: true
});
}
};
I have purposefully added an 'x' to 'updatedx' so it fails....only it passes. So, I'm sure this has been asked 100 times but I'm unclear as to why it is passing and also why the screenshot is printed, given that an error is not thrown.
Thanks in advance.
I've realised the error now, swapped frame.$eval with frame.$ and this has resolved the issue.

Categories

Resources