What's the best way to mock a nested function? - google-cloud-functions

consider a function
exports.projectNotifyLaunch = (admin, functions) => {
return functions.database.ref("/projects/{pid}").onCreate(snap => {
const { title } = snap.val();
const notification = {
title: `${title} just launched!`,
body: `We just heard about a new cryptocurrency project called ${title}`
};
return admin.messaging().sendToTopic("premium", { notification });
});
};
How should I mock deeply nested functions such as
functions.database.ref("/projects/{pid}").onCreate(snap => {});
or
admin.messaging().sendToTopic("premium", { notification });
in Jest? I want to fire off the snap=>{} callback and assert against the value of notification.
I was able to make this work
This works but it's quite verbose. I'm wondering if there is a better way, or a type of testing I'm not aware of with Jest.
describe("send notification to premium users on new project", () => {
// INPUTS
const snap = {
val: () => ({
title: "Test Title"
})
};
const functions = {
database: {
ref: () => ({
onCreate: callback => callback(snap)
})
}
};
// outputs
let topicStub = null;
let notificationStub = null;
const admin = {
messaging: () => ({
sendToTopic: (topic, notification) => {
topicStub = topic;
notificationStub = notification;
}
})
};
projectNotifyLaunch(admin, functions);
test("title is correct", () => {
expect(notificationStub.notification.title).toBe(
"Test Title just launched!"
);
});
test("topic is premium", () => {
expect(topicStub).toBe("premium");
});
});

Related

Component responsible to display all my transactions are not updating after submit

I'm using redux toolkit with react and have a basic setup because I'm building a simple expense tracker, so I have two operations: get all transactions and add a new transaction. That's it.
My problem: When I create a new transaction the component responsible for displaying my data does not update and I can only see the changes after refreshing the page.
Below you can see my transactionSlice file:
const initialState = {
transactions: [],
loading: false,
error: null,
}
export const getTransactions = createAsyncThunk(
"transactions/getTransactions",
async () => {
const res = await axios.get('http://localhost:8000/transactions')
return res.data
}
)
export const addTransaction = createAsyncThunk(
"transaction/addTransaction",
async(data) => {
const res = await axios.post('http://localhost:8000/transactions', data);
return res.data
}
)
const transactionsSlice = createSlice({
name: 'transactions',
initialState,
reducers: {},
extraReducers: {
[getTransactions.pending]: (state) => {
state.loading = true;
},
[getTransactions.fulfilled]: (state, {payload}) => {
console.log(payload);
state.loading = false;
state.transactions = payload;
state.error = ''
},
[getTransactions.rejected]: (state) => {
state.loading = false;
state.error = state.error.message;
},
[addTransaction.pending]: (state) => {
state.loading = true;
},
[addTransaction.fulfilled]: (state) => {
state.loading = false;
},
[addTransaction.rejected]: (state) => {
state.loading = false;
state.error = state.error.message;
}
}
});
and here is the code from the component where I'm displaying all transactions
const { transactions, loading } = useSelector(selectAllTransactions);
const dispatch = useDispatch();
useEffect(() => {
dispatch(getTransactions());
}, [dispatch]);
but when I make a post request my state with all transactions doesn't update immediately. I can only see the changes if I update the page and I'm doing it manually. I'm wondering why is this happening if I have useEffect watching for changes?
AddTransaction.js file :
const [transactionName, setTransactionName] = useState('');
const [amount, setAmount] = useState('');
const dispatch = useDispatch();
const handleSubmit = (e) => {
e.preventDefault();
const data = {
transactionName,
amount
}
if(transactionName && amount){
dispatch(addTransaction(data));
dispatch(getTransactions());
setTransactionName('')
setAmount('');
}
}
I've tried to google it but it seems my doubt is so silly that I can't even find an answer for that.
Here is my server file:
app.post('/transactions',(req, res) => {
const {transactionName, amount} = req.body;
const query = `INSERT INTO transactions (title, amount)
VALUES ("${transactionName}", "${amount}")`
db.query(query, (err, result) => {
if(err){
console.log(err)
}
res.send(result)
})
});
Am I missing something? Could someone explain to me why the component responsible to display all transactions are not updating after submit, please?
Try executing getTransactions once addTransaction(data) is finished, not at the same time:
const handleSubmit = (e) => {
e.preventDefault();
const data = {
transactionName,
amount
}
if(transactionName && amount){
dispatch(addTransaction(data))
.then(() => {
dispatch(getTransactions())
setTransactionName('')
setAmount('')
}
}
}

why is the state of my contract not changing

I am creating a study project in solidity, its a basic smart contract.
I have the following smart contract:
contract SmartContract {
uint256 public contractProperty = 10;
function changeProperty(int256 newVal) external {
contractProperty = uint256(newVal);
}
}
I am running the following test:
const SmartContract = artifacts.require("SmartContract");
contract('SmartContract', function(accounts) {
var testInstance;
it('returns correctly', () => {
return SmartContract.deployed().then((instance) => {
testInstance = instance;
})
.then(() => {
testInstance.changeProperty(10000);
})
.then(() => {
return testInstance.contractProperty();
})
.then((val) => {
assert.equal(val.toString(), '10000'.toString());
});
});
});
I get an error that expected 10 to equal to 10000 meaning that the contract property doesn't change.
What am I doing wrong? Why does the state of my smart contract not change?
(Am using truffle and ganache with solidity ^0.8)
const SmartContract = artifacts.require('./SmartContract.sol');
require('chai').use(require('chai-as-promised')).should();
contract('SmartContract', function (accounts) {
var testInstance;
it('returns correctly', () => {
return SmartContract.deployed()
.then((instance) => {
testInstance = instance;
})
.then(() => {
return testInstance.changeProperty(10000); // return is required
})
.then(() => {
return testInstance.contractProperty(); // return is required
})
.then((val) => {
assert.equal(val.toString(), '10000'.toString());
});
});
});
without {, ..., }, we don't need require return
contract('SmartContract', function (accounts) {
var testInstance;
it('returns correctly', () => {
return SmartContract.deployed()
.then((instance) => {
testInstance = instance;
})
.then(() => testInstance.changeProperty(10000))
.then(() => testInstance.contractProperty())
.then((val) => {
assert.equal(val.toString(), '10000'.toString());
});
});
});

why promise.resolve lost value inside of async function?

I know when we use promise in JavaScript, we usally use two ways like below.
var f1 = () => {
return new Promise( (resolve, reject) => {
resolve(10);
})
}
var f2 = () => {
return Promise.resolve(10)
}
f1().then( data => { console.log(data) }) // 10
f2().then( data => { console.log(data) }) // 10
But if i use async function inside of promise, Promise.resolve lost the value like below.
const fs = require('fs')
var f1 = () => {
return new Promise( (resolve, reject) => {
fs.readFile('data.txt', (err, data) => {
resolve(data);
})
})
}
var f2 = () => {
return Promise.resolve()
.then(() => {
fs.readFile('data.txt', (err, data) => {
//return data --> undefined
//Promise.resolve(data) --> undefined
return Promise.resolve() --> undefined
})
})
}
f1().then( data => { console.log('1,',data) })
f2().then( data => { console.log('2,',data) })
I think that i use wrong way about Promise.resolve,,, OR Promise.resolve not support async function... someone tell me why Promose.resolve fail..
If you have a value that you immediately want to resolve a promise with, you can use Promise.resolve().
If you get the value asynchronously in a callback, you must use the new Promise constructor with the resolve/reject callbacks, there is no way around it.

TypeError: Cannot read property 'splice' of undefined

I've created a fixture file to handle my JSON datas used to write tests.
Before each test, I want my data to be filled with seed data.
After each test, I want my data to be empty
Courses.json :
[
{
"id": 1,
"title": "Ma course"
}
]
CoursesFixture.js :
const { courseList } = require('./courses')
mockData = [
{
"id": 1,
"title": "Ma course"
}
]
module.exports = {
up: () => {
courseList.splice(0)
courseList.push.apply(courseList, mockData)
},
down: () => {
courseList.splice(0)
}
}
CoursesTest.js :
const request = require("supertest")
require('chai').should()
const bodyParser = require("body-parser")
const app = require('./../../app')
app.use(bodyParser.json())
const listeDeCourses = require("../fixtures/courses")
const listeDeCoursesFixture = require("../fixtures/coursesFixture")
describe('Courses', () =>{
beforeEach(() => { listeDeCoursesFixture.up() })
afterEach(() => { listeDeCoursesFixture.down() })
describe('Delete course list', ()=>{
it("Should delete a list of course", ()=>{
return request(app).get('/course')
.then((res) => {
res.body.should.have.lengthOf(1)
request(app).delete('/course').send({"id":"1"})
.then((res) => {
res.body.should.have.lengthOf(0)
})
}).catch((err) =>{
throw new Error(err);
})
})
})
describe('Create course list', () =>{
it("Should create a list of courses", () =>{
return request(app).post('/course').send({"id":3,"title":"Première course"}).then((res) => {
res.status.should.be.eq(200)
const listCourses = res.body
const lastCourse = res.body[1]
listCourses.should.be.a('array')
lastCourse.id.should.be.eq(3)
lastCourse.title.should.be.eq("Première course")
listCourses[listCourses.length - 1].should.be.eq(lastCourse)
}).catch((err) => {
throw new Error(err)
})
})
})
describe('Get course list', ()=>{
it("Should get a list of all courses", ()=>{
return request(app).get('/course')
.then((res) => {
res.body.should.have.lengthOf(1)
}).catch((err) =>{
console.log(err)
throw new Error(err);
})
})
})
})
My problem is that when I launch my test I have an error :
TypeError: Cannot read property 'splice' of undefined
I think the problem is in CoursesFixture.js and surely a syntax error somewhere but I can't find where it is.
const { courseList } = require('./courses') should be const courseList = require('./courses')?

firebase set failed first argument contains undefined in property

When I create an event, I do this:
export const eventCreate = ({ title, time, location }) => {
const newPostKey = firebase.database().ref('/events').push().key;
const update = {};
const postDetails = {
eventId: newPostKey,
title,
...
goingNumber: 1,
...
};
update[`/events/${newPostKey}`] = postDetails;
return (dispatch) => {
firebase.database().ref()
.update(update)
.then(() => {
dispatch({ type: EVENT_CREATE });
})
.then(() => newPostKey);
};
};
in the database:
later when I try to update the goingNumber:
export const eventSave = ({ goingNumber, eventId }) => {
return (dispatch) => {
firebase.database().ref(`/events/${eventId}`)
.set({ goingNumber })
.then(() => {
dispatch({ type: EVENT_SAVE_SUCCESS });
});
};
};
I get this error saying:
You're not passing in a value for goingNumber. My guess is that you're looking for
firebase.database().ref(`/events/${eventId}`)
.child('goingNumber').set(goingNumber )