I am trying to load files into an array and then run tests on them. This is my code:
let files: string[] = []
describe.only("Name of the group", () => {
beforeAll(() => {
files = ["a", "b"]
})
test.each(files)("runs", f => {
console.log(f)
})
})
However, I get
Error: .each called with an empty Array of table data.
What am I doing wrong?
Thanks!
test.each expects a table value as input. which means an array of arrays. But that is fixed automatically so don't worry about it.
But the call order is important here! Notice that the tests are defined before they are actually run. So, beforeAll will run after the tests were defined. This means the files array won't be defined while the tests are being registered.
In order to fix this, you need to make sure the files array is populated before the tests are read and registered
So something like this:
const files: string[][] = [ ['test1'],['test2'] ];
describe('Something Something', () => {
describe('Name of the group', () => {
test.each(files)('runs %s', (f) => {});
});
});
Related
I'm quite new with jest testing and I'm having trouble to understand how Jest deals with the functions I'm trying to test. Here's my problem:
I'm trying to test the following, quite simple function, which will receive a bookId and will find the object within an array that containa such id. All is vanilla js, no react.
function catchSelectedBook(bookId) {
const objectSearchAsString = localStorage.getItem('objecttransfer');
const booksObject = JSON.parse(objectSearchAsString);
const currentBook = booksObject.filter((book) => book.id === bookId);
return currentBook;
}
The unit test Jest code is the following:
describe('Given a function that is given as argument the id', () => {
test('When invoked, it finds the book that matches such id', () => {
const returnMokObject = {
kind: 'books#volumes',
totalItems: 1080,
items: [
{
kind: 'books#volume',
id: 'HN1dzQEACAAJ',
}],
};
mockLocalstorageJest();
const answer = catchSelectedBook('HN1dzQEACAAJ');
expect(answer.id).toBe('HN1dzQEACAAJ');
});
});
The function mockLocalstorageJest sends to the local storage an object so that it can be get when the function catchSelectedBook is tested
I export my function like this:
module.exports = {
catchSelectedBook,mockLocalstorageJest,
};
And I import the function into the test file like this:
const { catchSelectedBook, mockLocalstorageJest} = require('./book-details.js');
Whenever I run the test, I got the following error message:
enter image description here
Does that mean that Jest doesn't have the array method "filter" defined?
Thanks!
I think that this instruction is returning null
const objectSearchAsString = localStorage.getItem('objecttransfer');
JSON.parse(null) returns null so bookObject is also null.
I believe that your problem is that you are not setting up the local storage correctly in mockLocalstorageJest().
Trying to unit test my controller, but when I do so I'm getting the following error.
I'm open to answers with a different way of testing my controller.
Error:
TypeError: expected sinon object
const test = require('sinon-test');
describe('index (get all)', function() {
beforeEach(function() {
res = {
json: sinon.spy(),
status: sinon.stub().returns({ end: sinon.spy() })
};
expectedResult = [{}, {}, {}];
});
it(
'should return array of vehicles or empty array',
test(() => {
this.stub(Vehicle, 'find').yields(null, expectedResult);
Controller.index(req, res);
sinon.assert.calledWith(Vehicle.find, {});
sinon.assert.calledWith(res.json, sinon.match.array);
})
);
});
First of all, when asking a StackOverflow question, it makes sense to post a fully runnable example and stating all dependencies. Basically, I used more than an hour trying to test this out because both were missing.
This is the fully expanded example, just with dummy implementations of your two main objects.
var sinon = require("sinon");
var sinonTest = require("sinon-test");
var test = sinonTest(sinon);
const Vehicle = {
find() {}
};
const Controller = {
index() {}
};
describe("index (get all)", function() {
let expectedResult, res, req;
beforeEach(function() {
res = {
json: sinon.spy(),
status: sinon.stub().returns({ end: sinon.spy() })
};
expectedResult = [{}, {}, {}];
});
it(
"should return array of vehicles or empty array",
test(function() {
this.stub(Vehicle, "find").yields(null, expectedResult);
Controller.index(req, res);
sinon.assert.calledWith(Vehicle.find, {});
sinon.assert.calledWith(res.json, sinon.match.array);
})
);
});
Now, to your question, which was why you were getting an error. The first thing to test is: does the bug appear when I update to the latest versions of the dependencies of the test? The answer is, no, it does not appear. So basically, this is about you using the sinon-test version 2.0, which had a compatibility bug with Sinon 3. This is from the changelog:
2.1.0 / 2017-08-07
==================
Fix compatibility with Sinon 3 (#77)
2.0.0 / 2017-06-22
==================
* Simplify configuration API (#74)
So, given that has been fixed, and the example below is being used, the test is fully runnable:
mocha mytest.js
index (get all)
1) should return array of vehicles or empty array
0 passing (6ms)
1 failing
1) index (get all)
should return array of vehicles or empty array:
AssertError: expected find to be called with arguments
The error here is of course not really an error, but simply a byproduct of me not having the full implementation of your controller and vehicle classes.
I'm trying to test my Promise with chai. My promise returns an array of objects like this:
[
{id: 1, Location: 'some where'},
{id: 2, Location: 'over the rainbow'},
]
I keep getting this error but my test still passes:
UnhandledPromiseRejectionWarning: AssertionError: expected [ Array(7) ] to have deep property 'Location'
My code:
describe('Function myPromise', () => {
it(`should returns object with property Location`, () => {
expect(myPromise(myParams)).to.eventually.have.deep.property('Location');
});
});
I've also tried:
to.eventually.have.deep.property.include('Location');
to.eventually.have.property('Location');
to.eventually.be.an('array').and.have.property('Location');
return expect(myPromise(myParams)).to.eventually.have('Location');
have.deep.property is applicable for checking object but seems like you checked the array.
Let me illustrate with a simple example
const fixtures = [
{id: 1, Location: 'some where'},
{id: 2, Location: 'over the rainbow'},
];
// I tested the first element
expect(fixtures[0]).to.have.deep.property('Location'); // passed
If you want to check every single element, you probably need a loop.
Updates
To use loop to check every element, the first thing to do is to grab the fixtures from the promise function. In this way, I'm using async/await but you can use promise too.
describe("Function myPromise", () => {
it(`should returns object with property Location`, async () => {
const fixtures = await myPromise(myParams); // get the fixtures first
// looping and check each element
fixtures.forEach(fixture =>
expect(fixture).to.have.deep.property("Location"); // no need to use `eventually.have.deep`
);
});
});
Hope it helps
I've figured out how to avoid that error. It's simpler and more straightforward than I thought:
describe('Function myPromise', () => {
it(`should returns object with property Location`, () => {
myPromise(myParams)
.then((results) => {
expect(results).to.be.an('array');
results.forEach((result) => {
expect(result).to.have.property('Location');
});
});
});
});
You can try using Joi (or chai-joi in your case) to make schema validation very easy. I would definitely try this if you're going to be having many tests with object schema validation.
Well a promise is handled asynchronously. I believe you are missing the .then() method in which will return the promise(rejected or fulfilled).
describe('Function myPromise', () => {
it(`should returns object with property Location`, () => {
expect(myPromise(myParams).then(data => data).to.eventually.have.deep.property('Location');
});
});
This is a follow up question to this question.
I have a function called assertTruthy for Jest. assertTruthy(msg, fn, args), expects a message, a function and arguments and should pass if the thing that is returned when the function is invoked with the arguments is truthy and fail if its not.
I want to extend it to also support Jest's only and skip.
Here is what I wrote:
assertTruthy.skip = ({
message = '',
fn = undefined,
args,
} = {}) => {
it.skip(message, () => {
expect(fn(args)).toBeTruthy();
});
};
assertTruthy.only = ({
message = '',
fn = undefined,
args,
} = {}) => {
it.only(message, () => {
expect(fn(args)).toBeTruthy();
});
};
How would I test these functions?
Here is what I tried, which works, but I'm not sure if this is correct.
describe('skip()', () => {
test('it skips the function', () => {
it.skip = jest.fn();
assertTruthy.skip({
message: 'something',
fn: () => true,
args: undefined,
});
expect(it.skip).toHaveBeenCalledTimes(1);
});
});
This looks like a fair enough test that your assertTruthy skip and only call Jest's it skip and only methods.
You might want to assert that it also calls them with the arguments you expect using toHaveBeenCalledWith.
Can you please elaborate more, what you want to achieve and I did't get it properly why you want to extend jest skip and only methods to achieve the same thing that you are already testing.
But if you only want to test if a function not been invoked/executed with toHaveBeenCalledTimes() based on the arguments to be truthy/falsy then you are doing it right.
I need to test function in my ts-module.
module-to-test.ts
import { config } from './app-config';
export const isSomethingWhatINeedSelector = createSelector(
firstDependencySelector,
secondDependencySelector,
(first, second) => config.key && (first || !second)
);
But I don't want to write many test for this case, and I want to try to use
describe.each([[],[],[]]) functionality to reduce number of code lines.
And I need to change config.key on each iteration of describe.each.
When I do at the beginning of the test-file something like this:
jest.mock('./app-config', () => ({
config: {
key : false,
},
}));
it works for the whole file and all the tests. I want to make mock inside "test/it" functions to change value of key dynamically.
Now I have that code, that doesn't work as expected
describe.each([
[
'should be ....',
true, false
],
[
'should be ....',
false, true
],
/* and etc. ... [], [], [] ... only for questnion here is two params*/
])('Functionality of ...', (
testTitle = '',
mockStatusOfConfigKey,
expected,
) => {
const state = ... /* initial */
beforeEach(() => {
jest.resetModules();
/*....configuring the state*/
});
it(testTitle, () => {
jest.mock('./app-config', () => ({ /*...or doMock(), that don't works*/
config: {
key : mockStatusOfConfigKey,
},
}));
expect(isSomethingWhatINeedSelector(state)).toBe(expected);
});
});
Any ideas how to make mocks dynamically changable inside test functions?
config.key is just true/false
Two important concepts from Exploring ES6 (which are also applicable to TypeScript Modules):
In ES6, imports are live read-only views on exported values
and
while you can’t change the values of imports, you can change the objects that they are referring to.
app-config exports config which is an object.
config can't be assigned to something else, but the object it refers to can be changed.
Any code that imports config gets a live view of the object and will automatically see any modifications to the object:
import { config } from './app-config';
...
it(testTitle, () => {
config.key = mockStatusOfConfigKey; // modify the config object
expect(isSomethingWhatINeedSelector(state)).toBe(expected); // SUCCESS
});
});