onUpdate function in firebase is not retrieving before state - node.js

I'm using onUpdate function to retrieve a before state, but before and after are returning the same value:
exports.subscriptionDowngradeHandler = async (change, context) => {
const before = change.before.data().product;
console.log("product before: ", before);
const after = change.after.data().product;
console.log("product after: ", after);
await change.after.ref.set({
before: before.id,
after: after.id
}, { merge: true });
}
Value before.data().product is expected to be the other id, but instead is the actual one as after.data().product
EDIT
index.js is just calling subscriptionDowngradeHandler as a handler for the function:
const authModule = require("./auth");
const admin = require("firebase-admin");
const creditsModule = require("./credits");
const functions = require("firebase-functions");
const subscriptionsModule = require("./subscriptions");
admin.initializeApp();
exports.subscriptionDowngrade =
functions.firestore
.document("/customers/{userId}/subscriptions/{pushId}")
.onUpdate(subscriptionsModule.subscriptionDowngradeHandler);
exports.subspriptionPeriodEnd = functions.firestore
.document("/customers/{userId}/subscriptions/{pushId}")
.onWrite(subscriptionsModule.subscriptionPeriodEndHandler);
subscriptions.js is as follows:
const admin = require("firebase-admin");
exports.subscriptionPeriodEndHandler = async (change, context) => {
const periodEndBefore = change.before.data().current_period_end;
const periodEndAfter = change.after.data().current_period_end;
console.log(periodEndBefore);
console.log(periodEndAfter);
}
exports.subscriptionDowngradeHandler = async (change, context) => {
const before = change.before.data().product;
const after = change.after.data().product;
await change.after.ref.set({
before: before.id,
after: after.id
}, { merge: true });
}
In both functions before and after shows exactly the same data.

Related

Jest return mocked value when S3.getObject function is called

I'm totally new to Jest and typescript. my 2nd test case to be honest.
I want in my jest test - when s3.getObject is called in the actual class, it should return the mocked value.
my handler code:
var aws = require("aws-sdk");
var s3 = new aws.S3({apiVersion: '2006-03-01'});
exports.handler = async function (event, context, callback) {
const bucket = 'event.s3.bucket.name';
const filename = 'fileName';
const inputBucketParams = {
Bucket: bucket,
Key: filename,
};
let result;
try {
**//I want the result to be the mocked value in my test case.**
result = await s3.getObject(inputBucketParams).promise();
const fileContent = getFileContents(result.Body.toString("utf-8"));
my test case:
import {getFileContent} from "../../utils/FileContent";
import anything = jasmine.anything;
const lambdaHandler = require('../lambda/myLambda');
const AWSMock = require('aws-sdk-mock');
const AWS = require("aws-sdk");
describe('Test getS3Object', () => {
beforeEach(() => AWSMock.setSDKInstance(AWS));
})
let s3Object = {
"bucket": {
},
"object": {
}
};
let event = {Records: [
{
s3: s3Object --> from above.
}
]
}
var aws = require("aws-sdk");
var s3 = new aws.S3({apiVersion: '2006-03-01'});
describe('my handler test', async function () {
const s3GetObject = AWSMock.mock('S3', 'getObject', getFileContent('fileName.csv'));
const s3mock = jest.fn();
const getObjectMock = jest.fn(() => getFileContent('fileName.csv'));
const params = {
Bucket: 'bucketName',
Key: 'filename'
}
var returnValue = s3mock.mockReturnValue({
Body: getFileContent('fileName.csv')
});
test('s3 getObject response mock', async () => {
//jest.spyOn(s3, "getObject")
const getObjectMockValue = s3.spyOn('S3', 'getObject').mockReturnValue({
Body: getFileContent('fileName.csv')
})
// my handler is called from this, and when it get to s3.getObject, it fails.
const handlerResponse = await lambdaHandler.handler(event, anything(), anything());
});
});
I want in my jest test - when s3.getObject is called in the actual class, it should return the mocked value.

Firebase function testes with local emulators, Firestore collection snapshot persists of claiming being emtpy

Trying to test "locally" a firebase function with
firebase emulators:start --inspect-functions on http:// 127 .0.0.1:5000.
When debugging it step by step, the snapshot doesn't exist...but it's not. What I can possibly do wrong ?
const BotDetector = require("device-detector-js/dist/parsers/bot");
const fs = require("fs");
const DEBUG_BOT = true;
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
const db = admin.firestore();
// Main firebase function called on firebase.json rewrites rules
exports.dynamicMetaTagsUpdate = functions.https.onRequest(async (request, response) => {
let html = fs.readFileSync("../web/index.html", "utf8");
const botDetector = new BotDetector();
const userAgent = request.headers["user-agent"].toString();
const bot = botDetector.parse(userAgent);
if (bot || DEBUG_BOT) {
try {
const { postID } = request.query;
const postUrl = 'http://localhost:5000/blog/post?postID=' + postID;
const docRef = db.collection("posts").doc(postID);
const postData = docRef.get().then((snapshot) => {
if (snapshot.exists()) {
const object = {
postUrl: postUrl,```

Promisify is not a function

I am working on lex and I am trying to store user data in DynamoDB while using NodeJS
Here is my code:
'use strict';
const uuidV1 = require('uuid/v1');
const AWS = require('aws-sdk');
const promisify = require('es6-promisify');
const dynamo = new AWS.DynamoDB.DocumentClient();
module.exports.saveBookingToDatabase = function(Arrival_city, Departure_city, Flight_type, Phone_number){
console.log('saveBookingToDatabase');
const item = {};
item.bookingId = uuidV1();
item.arrivalCity = Arrival_city;
item.departureCity = Departure_city;
item.classType = Flight_type;
item.phone = Phone_number;
const params = {
TableName: 'airstallion',
Item: item
};
const putAsync = promisify(dynamo.put, dynamo);
return putAsync(params).then(() => {
console.log(`Saving ticket ${JSON.stringify(item)}`);
return item;
})
.catch(error => {
Promise.reject(error);
});
}
When i run the program is returning the following error
Since aws-sdk library supports promise, its not necessary to use es6-promisify library. Using node.js async/await we shall achieve the same use case.
'use strict';
const uuidV1 = require('uuid/v1');
const AWS = require('aws-sdk');
const dynamo = new AWS.DynamoDB.DocumentClient();
module.exports.saveBookingToDatabase = async function(Arrival_city, Departure_city, Flight_type, Phone_number){
console.log('saveBookingToDatabase');
const item = {};
item.bookingId = uuidV1();
item.arrivalCity = Arrival_city;
item.departureCity = Departure_city;
item.classType = Flight_type;
item.phone = Phone_number;
const params = {
TableName: 'airstallion',
Item: item
};
try {
let result = await dynamo.put(params)
console.log(`Saving ticket ${JSON.stringify(item)}`);
return item;
} catch(e) {
throw (e)
}
}

firebase functions datasnapshot is not working

I am trying to run the next code in firebase functions, and it gives an error of not recognizing datasnapshot. what can cause it?
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.updateVotes = functions.database.ref('travels/{travelId}/locations/{locationId}/voting/users')
.onUpdate((userVotes, context) => {
var travelId = context.params.travelId;
var locationId = context.params.locationId
var sumVotes = 0;
userVotes.forEach((userVote) => {
sumVotes += userVote.val().userVote;
})
// var votes = userVotes.val();
// for (var vote in votes) {
// if (votes.hasOwnProperty(vote)) {
// sumVotes += votes[vote].userVote;
// }
// }
return admin.database()
.ref('travels/' + travelId + '/locations/' + locationId + '/voting')
.update({ votes: sumVotes })
})
The error is:
TypeError: userVotes.forEach is not a function at exports.updateVotes.functions.database.ref.onUpdate
onUpdate doesn't return a DataSnapshot it returns a Change object.
You need to select the after or before property - do you want the information before the write, or after the write (Usually it's after - this is the new data in Firebase).
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.updateVotes = functions.database.ref('travels/{travelId}/locations/{locationId}/voting/users')
.onUpdate((change, context) => {
var travelId = context.params.travelId;
var locationId = context.params.locationId
var sumVotes = 0;
var userVotes = change.after;
userVotes.forEach((userVote) => {
sumVotes += userVote.val().userVote;
})
return admin.database()
.ref('travels/' + travelId + '/locations/' + locationId + '/voting')
.update({ votes: sumVotes })
})

Stripe and Firestore

I am trying to get Stripe server code working using Firestore. I found example server code that uses Firebase RTDB and am having trouble converting this code to use Firestore.
Original Firebase Function code using Real Time Database:
const functions = require('firebase-functions')
const admin = require('firebase-admin')
admin.initializeApp(functions.config().firebase);
const stripe = require('stripe')(functions.config().stripe.testkey)
exports.stripeCharge = functions.database
.ref('/payments/{userId}/{paymentId}')
.onWrite(event => {
const payment = event.data.val();
const userId = event.params.userId;
const paymentId = event.params.paymentId;
// checks if payment exists or if it has already been charged
if (!payment || payment.charge) return;
return admin.database()
.ref(`/users/${userId}`)
.once('value')
.then(snapshot => {
return snapshot.val();
})
.then(customer => {
const amount = payment.amount;
const idempotency_key = paymentId; // prevent duplicate charges
const source = payment.token.id;
const currency = 'usd';
const charge = {amount, currency, source};
return stripe.charges.create(charge, { idempotency_key });
})
.then(charge => {
admin.database()
.ref(`/payments/${userId}/${paymentId}/charge`)
.set(charge)
})
});
My attempt to convert this to using Firestore:
const functions = require('firebase-functions')
const admin = require('firebase-admin')
admin.initializeApp(functions.config().firebase)
const stripe = require('stripe')(functions.config().stripe.testkey)
exports.stripeCharge = functions.firestore
.document('/users/{userId}/payments/{paymentId}')
.onWrite(event => {
const payment = event.data
const userId = event.params.userId
const paymentId = event.params.paymentId
// checks if payment exists or if it has already been charged
if (!payment || payment.charge) return
return admin.firestore
.document(`/users/${userId}`)
.get()
.then(snapshot => {
return snapshot
})
.then(customer => {
const amount = payment.amount;
const idempotency_key = paymentId // prevent duplicate charges
const source = payment.token.id
const currency = 'usd'
const description = 'irl Map Fine Print'
const charge = {amount, currency, source}
return stripe.charges.create(charge, { idempotency_key })
})
.then(charge => {
admin.firestore
.fieldValue(`/users/${userId}/payments/${paymentId}/charge`)
.set(charge)
})
})
My version fails with error saying that admin.firestore.document is not a function.
This updated code will work for you! There were several issues with your code: Missing parentheses... incorrect use of fieldValue (though I am not sure how to use this correctly)... 'document' should be 'doc'
But this works:
const functions = require('firebase-functions')
const admin = require('firebase-admin')
admin.initializeApp(functions.config().firebase)
const stripe = require('stripe')(functions.config().stripe.token)
exports.stripeCharge = functions.firestore
.document('/users/{userId}/payments/{paymentId}')
.onWrite(event => {
const payment = event.data.data()
const userId = event.params.userId
const paymentId = event.params.paymentId
// checks if payment exists or if it has already been charged
if (!payment || payment.charge) return
return admin.firestore()
.doc(`/users/${userId}`)
.get()
.then(snapshot => {
return snapshot
})
.then(customer => {
const amount = payment.price * 100 // amount must be in cents
const idempotency_key = paymentId // prevent duplicate charges
const source = payment.token.id
const currency = 'usd'
const description = 'irl Map Fine Print'
const charge = {amount, currency, source}
return stripe.charges.create(charge, { idempotency_key })
})
.then(charge => {
admin.firestore()
.doc(`/users/${userId}/payments/${paymentId}`)
.set({
charge: charge
}, { merge: true })
})
})

Resources