setMethods is deprecated and will be removed in future releases - vue.js

I am using the function setMethods, it is still working, however I received the above message on the console. I am wondering what should be the new approach?.
It is being used to spy on a method and then see if it was called with the mocked parameters, here is the code:
const spyGenerateCalendar = jest.spyOn(wrapper.vm, 'generateCalendar');
const spyAxiosRequest = jest.spyOn(axios, 'get');
// setting methods for spying
wrapper.setMethods({generateCalendar: spyGenerateCalendar});
wrapper.vm.generateCalendar();
// Expecting calls
expect(spyGenerateCalendar).toHaveBeenCalled();
expect(spyAxiosRequest).toBeCalledWith(axiosRequestURL, axiosRequestParams);

It is unneeded. I am already spying on the method "generateCalendar" on the line:
const spyGenerateCalendar = jest.spyOn(wrapper.vm, 'generateCalendar');
So If the line wrapper.setMethods({generateCalendar: spyGenerateCalendar}); is removed. The result will be the same, so expect(spyGenerateCalendar).toHaveBeenCalled(); will be true

Related

Jest spyOn vs mock - both defined and undefined errors

Just upgraded to jsdom-fourteen in my jest configuration. It's working wonderfully, but a single test is failing.
test('Do the thing', () => {
window.location.assign = jest.fn();
});
I inherited this code. It looks like a simple enough jest mock. It complains that it cannot assign the read-only property assign and that makes sense, I assume this is jsdom functionality that was added.
However... I can't do a jest.spyOn either, which seems to be what is suggested. I've not used spyOn before.
jest.spyOn(window.location.assign);
But this gives me an undefined property error:
Cannot spy the undefined property because it is not a function; undefined given instead
The line before this, I added a log just to check. It is definitely a function:
console.log(window.location.assign);
=> [Function: assign]
I'm not sure how these two errors can even coexist - both defined and undefined?
Due to how JavaScript works, it would be impossible to write spyOn function the way that allowed it to work like spyOn(window.location.assign). Inside spyOn, it's possible to retrieve window.location.assign function that was provided as an argument but not window.location object and assign method name to do window.location.assign = jest.fn().
The signature of spyOn is:
jest.spyOn(object, methodName)
It should be:
jest.spyOn(window.location, 'assign');
This may be unworkable as well because window.location.assign is read-only in later JSDOM versions, which is used by Jest to emulate DOM in Node.js. The error confirms that this is the issue.
It may be possible to mock read-only property manually:
const origAssign = Object.getOwnPropertyDescriptor(window.location, 'assign');
beforeEach(() => {
Object.defineProperty(window.location, 'assign', { value: jest.fn() })
});
afterEach(() => {
Object.defineProperty(window.location, 'assign', origAssign)
});
This wouldn't work with real DOM because built-ins may be read-only and non-configurable. This is the issue in Chrome. For testability reasons it may be beneficial to use location.href instead of location.assign.
Eventually worked through some things and found this:
delete global.window.location;
window.location = { assign : jest.fn()};
As it appears later iterations of jsdom lock the location object down further and further until it's completely not modifiable, #Estus' answer will only work in lower versions of jsdom/jest.

How to correctly utilise redux-saga putResolve

I'm trying to sequence my API calls so that I can call an endpoint, wait for it to succeed, then select the required value out of the state.
I'm very new to redux-saga and am finding it difficult to understand how to achieve this!
What I've tried:
So we try and block whilst we perform an API call:
const resp = yield putResolve(assistantActions.fetchSustainability());
Later in the code we select the updated value out of the state:
const assistant = yield select(getAssistant);
The action that is called looks like:
export const fetchSustainability = () => ({ type: FETCH_SUSTAINABILITY });
In the saga we:
yield takeEvery(FETCH_SUSTAINABILITY, fetchSustainability);
Then the function returns a promise:
function fetchSustainability() {
return axios.get(`${url}/sustainability`);
}
I'm not sure that I've set this up any where near right as I've made lots of changes trying to get it working!
The select statement executes immediately and as the call isn't blocked the state isn't updated correctly.
Is my approach correct? If not is someone able to provide a simple working example on how to achieve a blocking call.
So the second parameter to takeEvery needs to be a generator function;
within that you can call your fetchSustainability
function* generator() {
yield call(fetchSustainability); // calls the actual function
}
// in the saga
yield takeEvery(FETCH_SUSTAINABILITY, generator);
your action fetchSustainability should return a Promise.
Here's an example to highlight the difference between put and putResolve.
https://codesandbox.io/s/redux-saga-example-x77jb
The example uses thunkMiddleware

How can Sinon spies register a Vue component method as called when it is called as an event's callback?

I have a method called testfn in my vue component that gets called whenever event testevt fires. This method contains a call to console.log that clearly shows the method is being called.
When running a test with vue-test-utils, if I create a Sinon spy for the method and call the method directly, the spy correctly detects that the method was called:
const wrapper = mount(MyComponent, {});
var spy = sinon.spy(wrapper.vm, 'testfn');
wrapper.vm.testfn();
expect(spy.called).to.be.true; //(uses the Chai assertion library)
This does not throw an error.
However, if I create the same spy, but instead of calling the method directly, I emit the event that calls my method, the method gets called (I can see this because the method contains a call to console.log) but the spy does not register that the method was called. Thus, the following gives an error:
const wrapper = mount(MyComponent, {});
var spy = sinon.spy(wrapper.vm, 'testfn');
wrapper.vm.$emit('testevt');
expect(spy.called).to.be.true; //(uses the Chai assertion library)
What seems to be happening is that testfn itself is not called, but rather, a clone of it is called. Regardless, how can I use a sinon spy to detect whether testfn, or a clone of it, gets called after I emit the testevt event?
I was trying spying like that today with no success so I switched to:
const spy = sinon.spy()
const wrapper = shallowMount(MyComponent, {localVue, methods: {clicked: spy}})
wrapper.get('button').trigger('click')
expect(spy).to.have.been.calledOnce
Hopefully someone can find an actual answer - but until then this works.

RN with Firestore unable to wait for Promise to resolve

I have a simple call to Firestore to write a doc and then wait for the doc to finish writing before changing state of the parent. However, the parent state is being changed too fast, resulting in reading fields that I think have not yet been written/propagated. I tried adding a delay with setTimeout and it seems ignored. How can I make sure the state change is absolutely only called after the Firestore doc is written completely?
The code:
updateDBEntry(stateObj) {
var that = this;
var docRef = firebase.firestore().collection('sessions').doc(this.state.userID);
docRef.get().then((doc) => {
if (!doc.exists) {
const timestamp = firebase.firestore.FieldValue.serverTimestamp();
var duration = (stateObj.seshDuration) ? stateObj.seshDuration : 1;
docRef.set({
seshName: stateObj.seshName,
seshStreet: stateObj.seshStreet,
seshZipcode: stateObj.seshZipcode,
seshDuration: duration,
seshDesc: stateObj.seshDesc,
seshTime: timestamp,
}).then(() => {
var handleToUpdate = that.props.handleToUpdate;
setTimeout(() => {
handleToUpdate(1); //this changes the parent's state
}, 10000);
});
}
});
}
I'm not sure exactly the problem you're running into here, mostly because you've only shown this one function, and not how you're using it in the rest of your app. But I can tell you three things for sure:
When the promise from set() resolves successfully, you can be certain the document is written.
get() and set() are asynchronous, and so is then(). They all return promises the represent async work.
Item 2 means that your entire function updateDBEntry() is also asynchronous and returns immediately, before any of the work is complete.
Because this entire function is async, when it returns, the document will not have been created yet. Instead, maybe this function should return that resolves only after all the work is complete, so that the caller can also use it set up some code to execute after the work is done.

When does a strongloop promise execute the database call?

I was refactoring someone elses code.
let promiseObj = Application.models.Widget.findById(connection.childId)
if (connection.child != 'Widget') {
typeES = "media"
promiseObj = Application.models.Media.findById(connection.childId)
}
promiseObj.then((obj) => {
let ownerId = obj.ownerId
let promiseUser = Application.models.MyUser.findById(ownerId)
})
The question is, does the server get called when
"let promiseObj = Application.models.Widget.findById(connection.childId)" is declared.
Or does the server get called when the .then is declared as the promise have a way to be fulfilled.
This is loopback with ES6.
Thanks guys/girls :D
Does the server get called when let promiseObj = Application.models.Widget.findById(connection.childId) is declared.
Yes, the server request is made as soon as the findById method is called.
Or does the server get called when the .then is declared as the promise have a way to be fulfilled.
then is just a method that is called, there is no declaration here. And it doesn't "give the promise a way to be fulfilled" - the promise will always resolve when the request finishes (fulfill in case of success and reject in case of an error), regardless whether there are any callbacks or not.
If you install a callback via then, it will be called when the promise is fulfilled.
So yes, I'm pretty certain that you should refactor this code:
let promiseObj;
if (connection.child != 'Widget') {
promiseObj = Application.models.Widget.findById(connection.childId);
} else {
typeES = "media"
promiseObj = Application.models.Media.findById(connection.childId)
}
let promiseUser = promiseObj.then((obj) => {
return Application.models.MyUser.findById(obj.ownerId);
});
As Erazihel is explaining, the declaration does not fire the resolve, it is called when you call .then()
I made a simple example in order to visualize the effect, there you will check that the time of the resolve matches the time where you call .then(), not on declaration.
p1.then(
// Then calls the resolve so the execution time 'resolve' matches .then
function(val) {
var timeMeAgain = new Date().toLocaleString();
log.insertAdjacentHTML('beforeend', val.thisPromiseCount +
') Promise done, then is called here (<small>Async call finished, .then called at: '+timeMeAgain+', promise executed at": '+val.timeCalledAt+' </small>)<br/>');
})
Check the example code here
*Code is based in the MDN example. Check documentation here
EDIT
About the resolve method, as the MDN documentation explains:
The method returns a Promise object that is resolved with the given value.
If the value is a thenable (i.e. has a "then" method), the returned
promise will "follow" that thenable, adopting its eventual state;
otherwise the returned promise will be fulfilled with the value.
Meaning that the response object will be returned when the Database or endpoint returns the information, not on declaration of the promise.