Is there a way to spy on a Promise constructor? - jasmine

I have this function
public pick(config?: FilePickerConfig): Promise<FilePickerResult> {
return new Promise<FilePickerResult>(resolve => {
this.pickWithCallbacks(resolve, resolve, config);
});
}
I want to test if the call to this.pickWithCallbacks has as first and second parameter the resolve parameter of the function.
Is there a way to do this in jest or jasmine? I have tried to spy on window, 'Promise' but it does not work.
Edit: It is not a depulicate of Spying on a constructor using Jasmine because that is what I have tried and did not work.
I have tried this:
const dummyResolve = () => { };
const promiseSpy = spyOn(window, 'Promise').and.callFake((dummyResolve)=>{});
const pickWithCallbacksSpy = spyOn(sut, 'pickWithCallbacks');
sut.pick();
expect(pickWithCallbacksSpy).toHaveBeenCalledWith(dummyResolve, dummyResolve, undefined);

So finally I just left the Promise do his thing and I captured the resolve callback
test('on success should call pickWithCallbacks with the resolve function of a promise', (done) => {
const cordovaExecSpy = spyOn(sut, 'pickWithCallbacks');
const dummyReturn = {};
sut.pick().then(obtained => {
expect(obtained).toBe(dummyReturn);
done();
});
const capturedOnSucess = cordovaExecSpy.calls.mostRecent().args[0];
capturedOnSucess(dummyReturn);
});
test('on Error should call pickWithCallbacks with the resolve function of a promise', (done) => {
const cordovaExecSpy = spyOn(sut, 'pickWithCallbacks');
const dummyReturn = {};
sut.pick().then(obtained => {
expect(obtained).toBe(dummyReturn);
done();
});
const capturedOnError = cordovaExecSpy.calls.mostRecent().args[1];
capturedOnError(dummyReturn);
});

Related

how do I unit test this function which handles observables

I have created this function because for all the requests my application sends out using http.post, this is how different parts handle the response. So rather than duplicating the code, I thought to create a function. But I am unable to figure out how to unit test this function.
private editAnswerSubject: Subject<Result>;
subscribeToReturnedObservable(observable:Observable<any>, subject:Subject<Result>) {
observable.subscribe((res) => {
const ev = <HttpEvent<any>>(res);
if (ev.type === HttpEventType.Response) {
const isResponseStructureOK: boolean = this.helper.validateServerResponseStructure(ev.body);
if (isResponseStructureOK) {
const response: ServerResponseAPI = ev.body;
subject.next(new Result(response.result, response['additional-info']));
} else {
subject.next(new Result(messages.error, messages.invalidStructureOfResponse));
}
}
},
(error: ServerResponseAPI) => {
const errorMessage: string = this.helper.userFriendlyErrorMessage(error);
subject.next(new Result(messages.error, errorMessage));
},
() => { // observable complete
});
}
editAnswer(answer: Answer): any {
const observable = this.bs.editAnswer(answer)
this.subscribeToReturnedObservable(observable,this.editAnswerSubject);
}
The test I have written so far is
describe('subscribeToReturnedObservable tests:', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [QuestionManagementService, HelperService, WebToBackendInterfaceService, AuthService, HttpClient, HttpHandler]
});
});
fit('should call send next value for the subject is the response from the server is ok', () => {
const questionService:QuestionManagementService = TestBed.get(QuestionManagementService);
const body = {"result":"success", "additional-info":"some additional info"};
const receivedHttpEvent = new HttpResponse({body:body});
let observable = new Observable();
spyOn(observable,'subscribe').and.returnValue(receivedHttpEvent);
spyOn(questionService['editQuestionSubject'],'next');
questionService.subscribeToReturnedObservable(observable,questionService['editQuestionSubject']);
observable.subscribe();
expect(questionService['editQuestionSubject'].next).toHaveBeenCalled();
});
});
But it get error Expected spy next to have been called.
I did this (hoping that it is the right way). The scope of testing is to check that the Subject's next is called correctly. So create an Observable using of and let the code flow from there.
fit('should call send next value for the subject is the response from the server is ok', () => {
const questionService:QuestionManagementService = TestBed.get(QuestionManagementService);
const helperService:HelperService = TestBed.get(HelperService);
const body = {"result":"success", "additional-info":"some additional info"};
const receivedHttpEvent = new HttpResponse({body:body});
const expectedResult = new Result('success', 'some additional info');
spyOn(helperService,'validateServerResponseStructure').and.returnValue(true);
let observable = of(receivedHttpEvent);
spyOn(questionService['editQuestionSubject'],'next');
questionService.subscribeToReturnedObservable(observable,questionService['editQuestionSubject']);
expect(questionService['editQuestionSubject'].next).toHaveBeenCalledWith(expectedResult);
});

Selector for React-Redux

To use selector, I tried to follow this URL reference: https://blog.isquaredsoftware.com/2017/12/idiomatic-redux-using-reselect-selectors/
One of the example is :
const selectSomeData = state => state.someData;
const selectFilteredSortedTransformedData = createSelector(
selectSomeData,
(someData) => {
const filteredData = expensiveFiltering(someData);
const sortedData = expensiveSorting(filteredData);
const transformedData = expensiveTransformation(sortedData);
return transformedData;
}
)
const mapState = (state) => {
const transformedData = selectFilteredSortedTransformedData(state);
return {
data: transformedData
};
}
Question: Within mapState we are calling selectFilteredSortedTransformedData and we are also passing State as parameter. However, the function itself is not taking any parameter, how does it work?
const selectFilteredSortedTransformedData = createSelector(
did you add mapState function in redux connect function ?? something like this.
export default connect(mapState)(Component)

How to use sinon to mock a series of knex call

Given a myknex.js:
export default { return require('knex')({client:'mysql',connection:{//conn}})}
and I want to write a unit test for the following function:
async function get({ userId }) {
return await myknex('users')
.where({ id: userId })
.returning('*');
}
The unit test looks like:
const sinon = require('sinon');
const sandbox = sinon.createSandbox();
const { myknex } = require('./myknex');
it('no record', async () => {
sandbox
.stub(myknex('users'), 'executeQuery').resolves([]);
const result = await myrepo.get({ userId: 1 });
const expectedResult = [];
expect(result).to.deep.equal(expectedResult);
});
I got an error message about:
TypeError: Cannot stub non-existent own property executeQuery
How can I mock the chained myknex calls?
Since you have myknex.js export a function of knex, we need to use proxyquire to mock this in test file.
const chai = require('chai');
const expect = chai.expect;
const sinon = require('sinon');
const proxyquire = require('proxyquire'); // include proxyquire
const expectedResult = [];
const knexQuery = {
where: sinon.stub().returnsThis(), // because we want to call `returning` afterwards
returning: sinon.stub().resolves(expectedResult) // resolve it as promise
}
const myknexStub = sinon.stub().returns(knexQuery);
const myrepo = proxyquire('./src', { './myknex': myknexStub }); // your source file and stub myknex here
describe(('Test My Module'), () => {
it('no record', async () => {
const result = await myrepo.get({ userId: 1 });
// many options to unit test the function
expect(myknexStub.calledWith('users')).to.be.ok;
expect(knexQuery.where.calledWith({ id: 1 })).to.be.ok;
expect(knexQuery.returning.calledWith('*')).to.be.ok;
expect(knexQuery.returning.calledAfter(knexQuery.where)).to.be.ok;
expect(result).to.deep.equal(expectedResult);
});
});
Hope it helps

Testing if method with Promise was called (Jest)

I have an initializer method calling another method that returns a promise, like:
initStuffAfterLoad() {
const _this = this;
const theInterval = window.setInterval(function() {
if (thing) {
window.clearInterval(theInterval);
_this.getBanana()
.then(response => {
_this.getApple(response, _this);
});
}
}, 100);
}
and am needing to test whether getBanana was called (jest/sinon). So far I have:
test('init function calls getBanana', () => {
let thing = true
const getBananaSpy = sinon.spy();
sinon.stub(TheClass.prototype, 'getBanana').callsFake(getBananaSpy).resolves();
jest.useFakeTimers();
TheClass.prototype.initStuffAfterLoad();
jest.runOnlylPendingTimers();
expect(getBananaSpy.called).toBeTruthy();
TheClass.prototype.getBanana.restore();
});
However it still receives false at the assertion. I figure I'm not handling the Promise part correctly - what is the best practice way to do this?
I am not familiar with sinon, but here is a way to achieve your need with pure jest (even better it also checks that getApple is called when getBanana reseolves :))
jest.useFakeTimers()
const _this = {
getBanana: () => {},
getApple: () => {}
}
const initStuffAfterLoad = () => {
const theInterval = window.setInterval(function() {
window.clearInterval(theInterval);
_this.getBanana().then(response => {
_this.getApple(response, _this)
});
}, 100);
}
test('', () => {
let result
_this.getBanana = jest.fn(() => {
result = new Promise( resolve => { resolve() } )
return result
})
_this.getApple = jest.fn()
initStuffAfterLoad()
jest.runAllTimers()
expect(_this.getBanana.mock.calls.length).toBe(1)
return result.then(() => {
expect(_this.getApple.mock.calls.length).toBe(1)
})
})
code tested :)
PASS test\temp.test.js √ (25ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 2.489s

chai-as-promised should.eventually.equal not passing

I am trying to write a minimum working example of chai-as-promised in order to understand how it is working when testing functions that return a promise.
I have the following function:
simple.test = async (input) => {
return input;
};
and the following test function:
chai.use(sinonChai);
chai.use(chaiAsPromised);
const { expect } = chai;
const should = chai.should();
describe('#Test', () => {
it('test', () => {
expect(simple.test(1)).should.eventually.equal(1);
});
});
However, testing this results in the test not passing, but in a very long error, which is pasted here: https://pastebin.com/fppecStx
Question: Is there something wrong about the code, or what seems to be the problem here?
First: Your mixing expect and should. If you want to use should for assertion, you don't need expect.
Second: To tell mocha that a test is async you have to either call done, return a Promise or use async/await.
const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
const sinonChai = require('sinon-chai');
const should = chai.should();
chai.use(sinonChai);
chai.use(chaiAsPromised);
// Function to test
const simple = {
test: async (input) => {
return input;
}
}
// Test
describe('#Test', () => {
it('test', () => {
return simple.test(1).should.eventually.equal(1);
});
});

Resources