How to write useMutation hook with onCompleted as a parameter? - apollo

I need to write dedicated hook useMutation with onCompleted and parameter onMutationCompleted.
In file it uses like:
const [data] = useClearWorkerMutation({ onCompleted: onMutationCompleted });
I don't know how to put onCompleted in this hook correctly.
export function useClearWorkerMutation() {
return useMutation<ClearWorkerMutationData, ClearWorkerMutationInput>(
CLEAR_WORKER_MUTATION,
{
onCompleted: (data) =>
},
},
);
}

Per the docs the function signature for useMutation is:
function useMutation<TData = any, TVariables = OperationVariables>(
mutation: DocumentNode,
options?: MutationHookOptions<TData, TVariables>,
): MutationTuple<TData, TVariables> {}
If the only option is onCompleted and you have some query then you would have:
useMutation(YOUR_MUTATION,{onCompleted: (data) => {…your function…})
It looks as if you're doing this correctly. Are you getting errors? Is your onCompleted function not getting executed? What's not working?

Related

How to jest.spyOn mock implementation only for the first call then use default implementation?

I would like to use jest.spyOn to mock the implementation of a method only for the first call. On 2nd 3rd ...nth call want to call it's actual previous implementation.
I tried the below in ts and it is not working:
import handler from '../src/handler';
import * as cRedis from '../src/redis';
jest.spyOn(cRedis, 'rGetAsync');
describe('handle cart quantity validation', () => {
test('test 1 blabla', async () => {
(cRedis.rGetAsync as jest.Mock).mockImplementationOnce(
() =>
new Promise(resolve =>
setTimeout(() => {
resolve('{}');
}, 1000),
),
);
const response = await handler();
});
});
the handler function calls the method rGetAsync of cRedis two times.
just for illustrative example:
handler.ts
import { rGetAsync } from './redis';
export default function () {
const a = await rGetAsync('a');
const b = await rGetAsync('b');
console.log(a, b);
}
My problem is that the mockedImplementation is used in both calls!
So mockImplementationOnce is not really mocking it once.
I expect that for first call to use the mock implementation and second one the real one.
How can I achieve this with jest?
I have used your code and the following test:
import * as cRedis from '../redis';
import handler from '../handler';
describe('handle cart quantity validation', () => {
it('test 1 blabla', async () => {
const spy = jest.spyOn(cRedis, 'rGetAsync');
spy.mockResolvedValueOnce('Not Original')
await handler();
});
});
My redis looks like this:
export const rGetAsync = async () => Promise.resolve('Original implementation');
And my output is:
console.log
Not Original Original implementation
So it works properly.
You can check my post about clear/reset/restore of spies and mocks.

Testing Redux arrow function Action Creators

I have an arrow function in my React-Redux application that dispatches just an action without a payload, which will wipe (Reset) a part of my Redux store. There's no HTTP (or Promises) involved.
export const resetSearch = () => dispatch => {
dispatch({
type: RESET_SEARCH
});
};
I want to test that it returns the correct Action type:
import * as actions from '../actions/actionCreators';
import * as types from '../actions/actionTypes';
describe('actions', () => {
it('should create an action to reset part of the store', () => {
const expectedAction = {
type: types.RESET_SEARCH
};
expect(actions.resetSearch()).toEqual(expectedAction);
});
});
The test is not passing because I need to return an Object but, instead, I send this anonimous arrow function. Here is the Jest output
Expected value to equal: {"type": "RESET_SEARCH"}
Received: [Function anonymous]
How should the test be?
All help will be apreaciated!
Thanks
Can you plese try below code snippet, It should do:
const expectedAction = {
type: types.RESET_SEARCH
};
let retnFunc = actions.resetSearch();
retnFunc((receivedAction)=>{
expect(receivedAction).toEqual(expectedAction);
});
Here resetSearch returns a function which gets called with the action object so just imitated the same.
Let me know if you need any more help!

Test async middleware in redux with thunk

I have a middleware that waits for a ARTICLE_REQUEST action, performs a fetch and dispatches either an ARTICLE_SUCCESS or an ARTICLE_FAILURE action when fetch is done. Like so
import { articleApiUrl, articleApiKey } from '../../environment.json';
import { ARTICLE_REQUEST, ARTICLE_SUCCESS, ARTICLE_FAILURE } from '../actions/article';
export default store => next => action => {
// Prepare variables for fetch()
const articleApiListUrl = `${articleApiUrl}list`;
const headers = new Headers({ 'Content-Type': 'application/json', 'x-api-key': articleApiKey });
const body = JSON.stringify({ ids: [action.articleId] });
const method = 'POST';
// Quit when action is not to be handled by this middleware
if (action.type !== ARTICLE_REQUEST) {
return next(action)
}
// Pass on current action
next(action);
// Call fetch, dispatch followup actions and return Promise
return fetch(articleApiListUrl, { headers, method, body })
.then(response => response.json());
.then(response => {
if (response.error) {
next({ type: ARTICLE_FAILURE, error: response.error });
} else {
next({ type: ARTICLE_SUCCESS, article: response.articles[0] });
}
});
}
I really wonder how to test this async code. I want to see if the follow-up actions will be dispatched properly and maybe if the fetch call gets invoked with the proper URL and params. Can anyone help me out?
PS: I am using thunk although I am not absolutely sure of its function as I just followed another code example
You can mock the fetch() function like so:
window.fetch = function () {
return Promise.resolve({
json: function () {
return Prommise.resolve({ … your mock data object here … })
}
})
}
Or you wrap the entire middleware in a Function like so:
function middlewareCreator (fetch) {
return store => next => action => { … }
}
and then create the middleware with the actual fetch method as parameter, so you can exchange it for tests or production.

TDD: Sinon 2.x and trying to test a sync method that uses async

So I've run into another snag, which I'm fighting with... I have a method that is a sync call, and within this method it calls a promise, async, method.
in my app I have the following:
export class App {
constructor(menuService) {
_menuService = menuService;
this.message = "init";
}
configureRouter(config, router) {
console.log('calling configureRouter');
_menuService.getById(1).then(menuItem => {
console.log('within then');
console.log(`configureRouter ${JSON.stringify(menuItem, null, 2)}`);
const collection = menuItem.links.map(convertToRouteCollection);
console.log(`collection ${JSON.stringify(collection, null, 2)}`);
//I think there is an issue with asyn to synch for the test
config.map(collection);
}).catch(err => {
console.error(err);
});
console.log('calling configureRouter assign router');
this.router = router;
}
}
The test I've tried the following within mocha
...
it('should update router config', function () {
const expectedData = {
name: "main menu",
links: [{
url: '/one/two',
name: 'link name',
title: 'link title'
}]
};
const configMapStub = sinon.stub();
const config = {
map: configMapStub
};
const routerMock = sinon.stub();
let app = null;
const actualRouter = null;
let menuService = null;
setTimeout(() => {
menuService = {
getById: sinon.stub().returns(Promise.resolve(expectedData).delay(1))
};
app = new App(menuService);
app.configureRouter(config, routerMock);
}, 10);
clock.tick(30);
expect(app.router).to.equal(routerMock);
expect(menuService.getById.calledWith(1)).to.equal(true);
//console.log(configMapStub.args);
expect(configMapStub.called).to.equal(true);
const linkItem = expectedData.links[0];
const actual = [{
route: ['', 'welcome'],
name: linkItem.name,
moduleId: linkItem.name,
nav: true,
title: linkItem.title
}];
console.log(`actual ${JSON.stringify(actual, null, 2)}`);
expect(config.map.calledWith(actual)).to.equal(true);
});
...
No matter what, I get configMockStub to always get false, while I am getting the menuService.getById.calledWith(1).to.equal(true) to equal true.
The test above was an attempt to try and get 'time' to pass. I've tried it without and have equally failed.
I'm really striking out on ideas on how to test this. Maybe I have the code wrong to reference a promise inside this method.
The only thing I can say I don't have any choice over the configureRouter method. Any guidance is appreciated.
Thanks!
Kelly
Short answer:
I recently discovered I was trying to make configureRouter method be a synchronous call (making it use async await keywords). What I found out was Aurelia does allow that method to be promised. Because of this, the test in question is no longer an issue.
Longer answer:
The other part of this is that I had a slew of babel issues lining up between babelling for mocha, and then babelling for wallaby.js. For some reason these two were not playing well together.
in the test above, another thing was to also change the following:
it('should update router config', function () {
to
it('should update router config', async function () {
I feel like there was another step, but at this time I cannot recall. In either case, knowing that I could use a promise made my world much easier for Aurelia.

Backbone Views - Mocha - Targeting events in collection.fetch success callback function

When testing a marionette compositeviewm in the onBeforeShow function, I am performing a collection.fetch with a success callback. However within the callback I then go on to clone my collection and attach events to it.
Now my issue is when testing this view, how would I target the various events/function calls I have set in the success callback of collection.fetch?
Is it possible or is it a case of not simply not being able to and code refactoring should take place?
If I set a sinon spy on checkEmptyState and then add a model to my collection created for the tests, the spy is not triggered, which makes sense as I have stubbed the fetch method for the collection in the beforeEach function in order to prevent any api calls. Which would be the best approach/set-up to enable testing the code within the success callback, if possible?
For example:
onBeforeShow: function () {
var that = this;
this.fetch = this.collection.fetch({
success: function (collection, response, options) {
if (!response.length ) {
that.addEmptyPostsMessage();
}
that.stopListening(that.collection);
//Change collection property and re-apply events
that.collection = that.collection.clone(that.options.filterAttr, that.options.isFiltered);
that._initialEvents();
that.collection.reset(that.collection.filterItems(that.collection.models, that.options.filterAttr), {reset: true});
that.listenTo(that.collection, 'update', that.checkEmptyState);
},
reset: false,
remove: false
});
}
For my test set-up:
beforeEach(function () {
this.server = sinon.fakeServer.create();
this.server.autoRespond = true;
this.collectionFetchStub = sinon.stub(My.Collection.Items.prototype, 'fetch', function () {
return: {
success: function () {console.log("this is never called!")}
}
});
My success callback in my stub is never reached.
You could make sure that you fetch stub executes it's success callback. Something like
var collection = [...],
response = 'ok';
this.collectionFetchStub = sinon.stub(My.Collection.Items.prototype, 'fetch', function (options) {
options.success(collection, response);
};
Or when using a sinon fakeserver instead of using autoRespond you should try
server.respondWith([200, { 'Content-Type': 'text/html', 'Content-Length': 2 }, collection_json_as_string]);
Make sure that the response is valid json.