I'm going around in circles trying to get a data driven test in Jest working. Although tests run async I was expecting the describes to run synchronously so the data would be set up before the main test runs. I also tried a beforeAll but this has the same problem. Is there a way to do this?
describe("My tests"), () => {
let testData = Array<MyDataStructure> = [];
describe("prepare test data", () => {
getData.then((data) => {
testData = data;
});
});
describe("run tests", () => {
test.each(testData)("this fails as testData is empty array", row: MyDataStructure) => console.log(row);
});
});
});
Wait until getData is done then execute the test cases.
beforeAll for getting data once for all tests.
beforeEach for re-fetch data for each test:
describe("My tests", () => {
let testData: Array<MyDataStructure> = [];
beforeAll(async () => { // async function
testData = await getData(); // wait until getData is done
});
describe("run tests", () => {
test.each(testData)("this fails as testData is empty array", (row: MyDataStructure) => console.log(row));
});
});
Related
I am trying to define my mocha tests in json and then parse them and run my tests. However, I find that I am having difficulty running the tests in the callback functions
function addTwoNumbers(a,b){
return a+b;
}
function testAddNumbers(){
describe("testing the addition of 2 numbers",() => {
it('should return the addition',(done) => {
addTwoNumbers(2,2).should.be.equal(4)
done()
})
})
}
//Obtain all the test jsons
glob(__dirname +'/../**/*.doc.json', {} , (err,fileNames) => {
fileNames.forEach(fileName => {
let file = fs.readFileSync(fileName)
let tests = JSON.parse(file)
tests.forEach(test => {
testAddNumbers()
})
})
})
Which returns:
Backend listening on port 3000
0 passing (1ms)
Moving testAddNumbers() outside the glob block works, so I am not too sure of the problem. Eg:
function addTwoNumbers(a,b){
return a+b;
}
function testAddNumbers(){
describe("testing the addition of 2 numbers",() => {
it('should return the addition',(done) => {
addTwoNumbers(2,2).should.be.equal(4)
done()
})
})
}
//Obtain all the test jsons
glob(__dirname +'/../**/*.doc.json', {} , (err,fileNames) => {
fileNames.forEach(fileName => {
let file = fs.readFileSync(fileName)
let tests = JSON.parse(file)
tests.forEach(test => {
})
})
})
testAddNumbers()
returns
Backend listening on port 3000
testing the addition of 2 numbers
√ should return the addition
1 passing (238ms)
Thanks for the help!
I have fixed it in a way that I find rather disgraceful, but if you can do better do enlighten me
Problem:
Mocha was exiting when it reached the end of the file
Solution:
Loop and wait till file has completed running. This must be done within a mocha test or mocha will blatantly ignore you as if you were its mom
describe('Wait for dynamically added tests to complete', function () {
this.timeout(999999999)
it('Waiting...', function (done) {
completed = (function wait() {
// console.log(completed)
// console.log('boomdiyadah')
if (!completed) {
setTimeout(wait, 1000)
} else {
done()
}
})();
})
})
Probably this could be implemented with promises but my life needs to move forward
I am having problems loading filenames into jest.each asynchronously.
My code:
let files: string[][]
function getFilesWorking() {
files = [["test1"], ["test2"]]
}
async function getFilesAsync() {
files = await Promise.resolve([["test1"], ["test2"]])
}
beforeAll(() => {
console.log("before")
})
describe.only("Name of the group", () => {
getFilesAsync()
test.each(files)("runs", f => {})
})
beforeAll is executed before each test but NOT before initialization of test.each, so I end up with undefined.
How can I load files before using test.each?
You can pass an async callback to beforeAll and await getFilesAsync within it
beforeAll(async () => {
await getFilesAsync();
})
As of Jest 28.1.3 and prior, this is not possible. There is an open issue documenting this behavior.
The best thing you can do for now is put your tests in a regular it() test and do a deep value comparison:
it('tests an array of cases', async () => {
const data = await getSomeAsyncData()
const expectedData = [ ... ]
expect(data).toEqual(expectedData)
})
You can use beforeEach to set up code that will run prior to tests for any given scope, https://jestjs.io/docs/setup-teardown:
beforeEach(() => {
console.log('before every test');
});
describe.only(('Name of the group') => {
beforeEach(() => {
console.log('before tests in this describe block');
})
})
Jest is only going to run the tests in your describe.only block. If you want to use beforeEach in other blocks and run those tests as well, change describe.only to describe.
(Edit: I know this is a year late, I'm just trying to look for a similar problem/solution set and thought I could answer this.)
I am using jest for unit testing in my node express application,please excuse , because i am new to all this
in my abc.test.js
const s3Helper = require('../../../../../lib/s3_helper');
beforeEach(async () => {
s3Helper.uploadBufferToS3 = jest.fn(() => true);
});
describe('test1', () => {
it('test1', async () => {
expect(s3Helper.uploadBufferToS3)
.toHaveBeenCalled();
});
});
describe('test2', () => {
it('test2', async () => {
expect(s3Helper.uploadBufferToS3)
.toHaveBeenCalled();
});
});
so when i run this test file in test1 it returns that test is passed, however in test2 it returns expected >=1 returned 0.
since i am mocking it beforeEach i expect it should return 1 for each describe block
I am trying use beforeEach and afterEach for test.each, seems these set up and tear down are not called, here is my sample code
let mydata;
describe('test each feature of jest %re', () => {
beforeAll( () => {
return mydata = [1,2,5,7] ;
});
dataArr = [1,2];
it.each(dataArr)
('%i', async(data) => {
expect(data).toBe(1);
});
});
I'm getting error
● test each feature of jest %re › encountered a declaration exception
I'd like to run my Jest tests concurrently, but I'm having issues with one scenario:
I'm testing the results on an endpoint, and I want to test multiple things about it. So in my beforeAll function, I make the request and store the response, and then I test the response in multiple tests. This works fine synchronously, but when I make the tests concurrent, it no longer lets you pass a variable into the test, so it's a no go. Alternatively, I can put the request in the test itself and then expect many things about the response, but then I don't have the granularity to see what went wrong if something fails.
Is there any solution for this scenario?
This works:
let data;
beforeAll(async () => {
data = await getDataFromRequest();
}
it('value1 should be truthy', () => {
expect(data.value1).toBeTruthy();
}
it('value2 should be truthy', () => {
expect(data.value2).toBeTruthy();
}
This also works:
it.concurrent('data should have correct values', async () => {
const data = await getDataFromRequest();
expect(data.value1).toBeTruthy();
expect(data.value2).toBeTruthy();
}
But what I want is:
let data;
beforeAll(async () => {
data = await getDataFromRequest();
}
it.concurrent('value1 should be truthy', () => {
expect(data.value1).toBeTruthy();
}
it.concurrent('value2 should be truthy', () => {
expect(data.value2).toBeTruthy();
}
Seems worth pointing out, that there is also a discussion about this in a jest issue: https://github.com/facebook/jest/issues/4281
Gist of it: It doesn't work that way and isn't planned. Possible workaround:
const dataPromise = getSomeDataPromise();
test.concurrent('one', async () => {
const data = await dataPromise;
});
test.concurrent('two', async () => {
const data = await dataPromise;
});
Was having same issue when doing browser testing with Playwright where one test suite only requires one instance of browser. Had to wrap it with a Promise with setInterval. In your case it should be like below:
let data;
beforeAll(async () => {
data = await getDataFromRequest();
}
test.concurrent('value1 should be truthy', async () => {
await waitForData();
expect(data.value1).toBeTruthy();
}
test.concurrent('value2 should be truthy', async () => {
await waitForData();
expect(data.value2).toBeTruthy();
}
/**
* #param {number} interval - the interval to check data availability
* #param {number} timeout - the overall timeout value
* #return Promise of your data OR reject if timeout.
*/
function waitForData(interval = 500, timeout = 5000){
let acc = 0; // time accumulation
return new Promise((resolve, reject) => {
const i = setInterval(() => {
acc += interval;
if (data) {
clearInterval(i);
resolve(data);
}
if (acc > timeout) {
clearInterval(i);
reject();
}
}, interval);
});
}
So you just need to assign the proper check interval and timeout which should be long enough for your data asycn call to come back.