This is my first time writing unit tests - please be nice.
I am trying to write unit tests for two functions. one function is to GET a number from the api, and the other is to POST data.
I am not sure how to do this. I know, I want to use the intern "expect" call and fetch-mock but the rest I want to do in react / javascript. I made a mock response with some data.
My questions are:
How can I use fetch-mock to compare my expected output with what my function is outputting
How does my mock response data relate to fetch-mock?
Again, I have not done this before and i am having a hard time understanding the resources available online (have been researching this for 8+ hours) so i am looking for another opinion
I haven't used fetch-mock before, and there are many ways to go about something like this, but the general process for mocking is to setup the mock, do what you need to do, and tear it down in an after or afterEach. How you actually go about checking whether your GET request worked depends on how you go about making the request in the first place.
A test for a mock request might look something like this. The assumption here is that you have a request method that makes a request and returns a Promise (what you'd get if you did return fetch('some_url')).
import * as fetchMock from 'fetch-mock';
const { describe, it, afterEach } = intern.getPlugin('interface.bdd');
const { expect } = intern.getPlugin('chai');
describe('my suite', () => {
afterEach(() => {
fetchMock.restore();
});
it('should do something', () => {
fetchMock.get('*', { hello: 'world' });
return thingThatDoesAGetRequest.then(response => {
expect(response).to.equal({ hello: 'world' });
});
})
});
Another option would be to wait for the mock request to complete rather than looking at a function return value:
it('should do something', test => {
// Create a promise that will resolve when a request is made
const promise = new Promise(resolve => {
fetchMock.get('*', () => {
resolve();
return { hello: 'world' }
});
});
// Do whatever should be making a call
thingThatDoesAGetRequest();
// Wait for the request promise to resolve, then see if whatever
// you expect to happen has happened
return promise.then(() => {
expect(something).to.equal({ hello: 'world' });
});
})
Related
I want to have different values returned for the same mock in each Test.
I am using mockReturnValueOnce for returning different values in each call of a test.
But for further test when I use mockImplementationOnce it still returns mockReturnValue.
const mock = require('module-to-mock');
jest.mock('module-to-mock');
describe('tests', () => {
it('test #1', async () => {
mock.foo = jest
.fn()
.mockReturnValueOnce(1) // First call
.mockReturnValueOnce(2) // Seconds call
.mockReturnValue("default"); // Rest of the calls
// execute test
});
it('test #2', async () => {
mock.foo.mockImplementationOnce(() => 3);
// It is not working I am getting "default"
// execute test
});
});
I did try resetting the mock using mock.foo.mockReset(), but it did not help. I did add it at the end of each test, once the test is executed. I also try by adding at the beginning of each test.
I have common mock implementation for all the functions in module-to-mock in a separate file.
I just want to remove/reset the mock done in the test #1 and move to the original mock done in a separate file.
I have an Angular service with a method that makes a call to a method in an httpService that returns an observable.
Once that method returns success, a series of parallel calls are made to the same method of the httpService but with different params to save some images.
I am trying to unit test that the calls are made in the right order and with the right params.
When I try to use spies and .toHaveBeenCalled() I only get the 1st call recognised by Jasmine.
I am assuming it has something to do with timing but I am lost and can't find any examples of this use case. Any guidance will be appreciated.
Edit: the code works 100%, my issue is just how to write unit tests for the sequence calls.
// Service
// HttpS is a custom service that makes HTTP requests
constructor(private httpS: HttpS) {
}
save(params: {images: any[]}): Observable<any> {
return this.saveEntry(params);
}
private saveEntry(params: {images: any[]}): Observable<any> {
return this.httpS.put('url', {something: 'something'}).pipe(
// once this request is successful, make parallel requests
concatMap(() => {
const reqs = [];
params.images.forEach(image => {
reqs.push(this.saveImage({ image }));
});
return forkJoin(reqs);
})
);
}
private saveImage(data: {image: any}): Observable<any> {
return this.httpS.put('url',{imgData: data.image});
}
// Test
describe('save', () => {
it('should make a PUT request with something, then on success multiple parallel PUT requests with imgData', () => {
spyOn(httpService, 'put').and.callFake(() => cold('-a|', { a: {} }));
service.save(data).pipe(take(1)).subscribe();
// The mock data I'm passing has 3 images so it results in 1 call first, then 3 in parallel, 1 for each image, but this test says it has been called just once.
expect(httpS.put).toHaveBeenCalledTimes(4);
// Trying .toHaveBeenCalledWith() but obviously that fails too
})
})
I think it has to do with subscribe running at a later point in time than your assertions (due to asynchronous nature).
Try this:
describe('save', () => {
it('should make a PUT request with something, then on success multiple parallel PUT requests with imgData', (done) => { // add done to tell Jasmine when you're done with unit test
spyOn(httpService, 'put').and.callFake(() => cold('-a|', { a: {} }));
service.save(data).pipe(take(1)).subscribe(response => {
expect(httpS.put).toHaveBeenCalledTimes(4); // make assertion once the response comes back
done(); // call done to let Jasmine know you're done with the test
});
})
})
I'm new to Angular and I'm still trying to figure out how things work for it. I'm currently having trouble testing a Component that depends on a Service that returns a Promise. The function I'm testing is structured like the following:
success: boolean;
borrowBook() {
this.bookService.borrow(this.selectedBook.id)
.then(() => {
this.success = true;
})
.catch((error: BorrowingError) => {
this.success = false;
});
}
Now, I'm not really sure if something like the code above is considered idiomatic, but that's how I wrote the code. In my unit test, I mocked the bookService using jasmine.createSpyObj function, and defined the stub as follows:
mockBookService.borrow.and.returnValue(Promise.resolve(testResult));
However, my test fails saying that component.success is undefined when I expected it to be truthy. My test is programmed as follows:
it('test', async(() => {
mockBookService.borrow.and.returnValue(Promise.resolve(testResult));
//setup pre-conditions here...
component.borrowBook(();
expect(component.success).toBeTruthy();
}));
My impression is that the expectations are being checked even before the Promise is handled accordingly.
I chanced upon this article about testing asynchronous code in Angular, which stated that the flushMicrotasks function can be used to run all the async components before checking expectations. This is only provided through the fake zone created through the fakeAsync, so in my code I used that instead of just async.
it('test', fakeAsync(() => { //used fakeAsync instead
mockBookService.borrow.and.returnValue(Promise.resolve(testResult));
//setup pre-conditions here...
component.borrowBook(();
flushMicrotasks(); //added this before checking expectations
expect(component.success).toBeTruthy();
}));
I call this function, console log is called but done() is not called:
import {Database} from "../../code/server/Database";
import 'mocha'
const expect = require('chai').expect
describe('Database save', function() {
it('should save without error', function(done) {
Database.saveSessionData(1, 2, 3, function(err, docs) {
expect(err).to.equal(null)
expect(docs.sessionOpenTime).to.equal(1)
expect(docs.sessionCloseTime).to.equal(2)
expect(docs.sessionLength).to.equal(3)
console.log(2222)
done()
})
})
})
Here is the result, 'Running tests' continues spinning on forever:
But if I change the 'Database' code into this, it works as expected:
setTimeout(function () {
console.log('lol')
done()
}, 1000)
What am I missing here?
Mocha test hangs since you have an opened database connection.
There are two options to solve this problem:
If you do not need a real database connection in your tests:
you can use sinon.stub() (https://www.npmjs.com/package/sinon) to return a predetermined response for async methods you use in your tests or sinon.spy() to make sure a stubbed method called exact number of times.
Here's a good article I just found to illustrate how to use sinon.js: https://semaphoreci.com/community/tutorials/best-practices-for-spies-stubs-and-mocks-in-sinon-js.
you can implement a dependency injection container to be able to replace your implementation of Database class to a Database class that does not perform I/O operations.
Although dependency injection implementations may vary depending on requirements some simple implementations are also available:
https://blog.risingstack.com/dependency-injection-in-node-js/
If you need to perform a real connection in your tests:
Consider adding an after hook to your mocha tests:
let's say mongodb is used as a database (it does not matter, but it would
be an actual working example)
const mongoose = require('mongoose');
const expect = require('chai').expect;
mongoose.connect('mongodb://localhost/test');
after(() => {
mongoose.connection.close();
});
describe('db connection', () => {
it('should make a test', () => {
expect(1).to.equal(1);
});
});
I'm using chai and chai-as-promised to test some asynchronous JS code.
I just want to check that a function returning a promise will eventually return an Array and wrote the 2 following tests:
A:
it('should return an array', () => {
foo.bar().should.eventually.to.be.a('array')
})
B:
it('should return an array', (done) => {
foo.bar().should.eventually.to.be.a('array').notify(done)
})
Both are passing OK, but only the B option actually runs the full code included in my bar() function (ie displaying the console.log() message from the code below). Am I doing something wrong? Why is that so?
bar() {
return myPromise()
.then((result) => {
console.log('Doing stuff')
return result.body.Data
})
.catch((e) => {
console.err(e)
})
}
What test library do you use? Mocha, Intern or other?
For Mocha and Intern, you must return the promise from your test method:
it('should return an array', () => {
return foo.bar().should.eventually.to.be.a('array');
})
Testing a promise means that you’re testing asynchronous code. Notify and done callback sets up a timer and waits for the promise chain to finish up executing.
The second approach is the correct one since you may need to test chained promises.
Take a look at this tutorial which got me into asynchronous unit testing.