How to set data in parametrized test inside before hook - mocha.js

I have the code bellow. when I run the code I get the data is undefined. I do need the before hook because I use async code and describe does not support async. I this case the before hook is not being ran and the execution goes directly to the test loop. Is there any way I can fix this problem by seeding my data inside the before hook prior to the test loop execution or making the describe function to execute async code ?
describe("some function", () => {
var users
data;
before(async () => {
users = await getAllUsers();
data = [
//seeding data
]
});
data.forEach(({fName, lName}) => {
it(`${fName}`, async function () {
//test execution
})
})
})

Related

how to generate it() tests after waiting on an asynchronous response

I want to generate it() tests in a loop, but the data required to drive the loop needs to be retrieved asynchronously first. I've tried solving the problem using before() but it won't work.
The code below retrieves and displays the parameters in the loop correctly but... the it() tests don't get executed.
It's as if mocha ignores it() that appear AFTER waiting on a promise.
describe('Generated tests', async () => {
const testParams = await <asynchronous call here>
testParams.forEach(testParam=> {
console.log(testParam)
it(`Generated test for ${testParam}, () => myTestFunc(testParam))
})
})
Solved this by placing await before describe:
describe('All Tests', async () => {
it('Level1 Test', () => <test code here> )
const testParams = await <async call here>
describe('Generated tests', () => {
testParams.forEach(testParam=> it(`Test ${testParam}`, ()=>testFunc(testParam))
})
})

How can I spyOn `useMutation` so that I can see what the values are being passed?

Rather than create a massive E2E test, I want to verify what the useMutation is receiving from the component. There is a lot of business logic before my component "posts" and I want to test that the GraphQL mutation function is receiving the shape of data.
Manually mocking the query doesn't provide value in this case, as it skips the business logic I want to keep track of. There is no value right now to let the query return full data & response, as my component will unmount and URL will change after successful data is returned.
So ideally, we just stop the test when the useMutation hook is called.
I am hoping to do something like:
const mutationSpy = jest.spyOn(graphQL, 'useMutation');
...
expect(mutationSpy).toHaveBeenCalledWith(myDataShape);
The best way to track whether a mutation has been called is to use the MockedProvider from #apollo/react-testing (react-native) or #apollo/client (react) to supply a callback function to your mock response that changes a variable in the test scope so that it may be checked once the test has been run. Something like this.
Here is the documentation:
https://www.apollographql.com/docs/react/development-testing/testing/#testing-mutation-components
test.js
let createMutationCalled = false
const mocks = [
{
request,
result: () => {
createMutationCalled = true
return { data }
}
}
];
describe('test', () => {
test('should call createTicket mutation', async () => {
const { getByTestId } = render(
<MockedProvider mocks={mocks}>
<SelfReportPage />
</MockedProvider>
)
let input = getByTestId('sr-description')
let submit = getByTestId('sr-submit')
fireEvent.changeText(input, 'Test text.')
fireEvent.press(submit)
await new Promise(r => setTimeout(r, 0));
expect(createMutationCalled).toBe(true)
})
})

Testing an Async function using Jest / Enzyme

Trying run a test case for the following:
async getParents() {
const { user, services, FirmId } = this.props;
let types = await Models.getAccounts({ user, services, firmId: FirmId });
let temp = types.map((type) => {
if(this.state.Parent_UID && this.state.Parent_UID.value === type.Account_UID) {
this.setState({Parent_UID: {label: type.AccountName, value: type.Account_UID}})
}
return {
label: type.AccountName,
value: type.Account_UID,
}
})
this.setState({ParentOptions: temp});
}
here is what i have so far for my test:
beforeEach(() => wrapper = mount(<MemoryRouter keyLength={0}><AccountForm {...baseProps} /></MemoryRouter>));
it('Test getParents function ',async() => {
wrapper.setProps({
user:{},
services:[],
FirmId:{},
})
wrapper.find('AccountForm').setState({
SourceOptions:[[]],
Parent_UID: [{
label:[],
value:[],
}],
});
wrapper.update();
await
expect(wrapper.find('AccountForm').instance().getParents()).toBeDefined()
});
If i try to make this ToEqual() it expects a promise and not anobject, what else could I add into this test to work properly.
Goal: Make sure the functions gets called correctly. The test is passing at the moment and has a slight increase on test coverage.
Using Jest and Enzyme for React Js
you can put the await before the async method, like:
await wrapper.find('AccountForm').instance().getParents()
and compare if the state was changed.
In another way, if can mock your API request, because this is a test, then you do not need the correct API, but know if the function calls the API correctly and if the return handling is correct.
And, you cand spy the function like:
const spy = jest.spyOn(wrapper.find('AccountForm').instance(), 'getParents');
and campare if the function was called if they are triggered by some action:
expect(spy).toBeCalled()

Do jest tests wait for previous async tests to resolve?

I have read that jest tests in the same tests file execute sequentially. I have also read that when writing tests that involve callbacks a done parameter should be used.
But when using promises using the async/await syntax that I am using in my code below, can I count on the tests to but run and resolve in sequential order?
import Client from '../Client';
import { Project } from '../Client/types/client-response';
let client: Client;
beforeAll(async () => {
jest.setTimeout(10000);
client = new Client({ host: 'ws://127.0.0.1', port: 8080 , logger: () => {}});
await client.connect();
})
describe('Create, save and open project', () => {
let project: Project;
let filename: string;
beforeAll(async () => {
// Close project
let project = await client.getActiveProject();
if (project) {
let success = await client.projectClose(project.id, true);
expect(success).toBe(true);
}
})
test('createProject', async () => {
project = await client.createProject();
expect(project.id).toBeTruthy();
});
test('projectSave', async () => {
filename = await client.projectSave(project.id, 'jesttest.otii', true);
expect(filename.endsWith('jesttest.otii')).toBe(true);
});
test('projectClose', async () => {
let success = await client.projectClose(project.id);
expect(success).toBe(true);
});
test('projectOpen', async () => {
project = await client.openProject(filename);
expect(filename.endsWith('jesttest.otii')).toBe(true);
});
})
afterAll(async () => {
await client.disconnect();
})
From the docs:
...by default Jest runs all the tests serially in the order they were encountered in the collection phase, waiting for each to finish and be tidied up before moving on.
So while Jest may run test files in parallel, by default it runs the tests within a file serially.
That behavior can be verified by the following test:
describe('test order', () => {
let count;
beforeAll(() => {
count = 0;
})
test('1', async () => {
await new Promise((resolve) => {
setTimeout(() => {
count++;
expect(count).toBe(1); // SUCCESS
resolve();
}, 1000);
});
});
test('2', async () => {
await new Promise((resolve) => {
setTimeout(() => {
count++;
expect(count).toBe(2); // SUCCESS
resolve();
}, 500);
});
});
test('3', () => {
count++;
expect(count).toBe(3); // SUCCESS
});
});
For sure it depends on test runnner configured. Say for Jasmine2 it seems impossible to run tests concurrently:
Because of the single-threadedness of javascript, it isn't really possible to run your tests in parallel in a single browser window
But looking into docs' config section:
--maxConcurrency=
Prevents Jest from executing more than the specified amount of tests at the same time. Only affects tests that use test.concurrent.
--maxWorkers=|
Alias: -w. Specifies the maximum number of workers the worker-pool will spawn for running tests. This defaults to the number of the cores available on your machine. It may be useful to adjust this in resource limited environments like CIs but the default should be adequate for most use-cases.
For environments with variable CPUs available, you can use percentage based configuration: --maxWorkers=50%
Also looking at description for jest-runner-concurrent:
Jest's default runner uses a new child_process (also known as a worker) for each test file. Although the max number of workers is configurable, running a lot of them is slow and consumes tons of memory and CPU.
So it looks like you can configure amount of test files running in parallel(maxWorkers) as well as concurrent test cases in scope of single worker(maxConcurrency). If you use jest as test runner. And this affects only test.concurrent() tests.
For some reason I was unable to find anything on test.concurrent() at their main docs site.
Anyway you can check against your environment by yourselves:
describe('checking concurrent execution', () => {
let a = 5;
it('deferred change', (done) => {
setTimeout(() => {
a = 11;
expect(a).toEqual(11);
done();
}, 1000);
});
it('fails if running in concurrency', () => {
expect(a).toEqual(11);
});
})
Sure, above I used Jasmine's syntax(describe, it) so you may need to replace that with other calls.

How to test redux-thunk middleware async functions?

I'm trying to test my asyn thunk middleware function using mocha, chai and sinon (my first time!).
Please consider my files:
ayncActionCreators.js
export const fetchCurrentUser = () => {
return (dispatch) => {
setTimeout(dispatch, 100);
}
};
ayncActionCreators.spec.js
//...
it('Should work', () => {
const dispatch = sinon.spy();
const action = fetchCurrentUser();
action(dispatch);
expect(dispatch.called).to.be.true;
});
I did not yet implement the fetchCurrentUser function - just assumed it will take some "server" time and then it will call 'dispatch()'.
The spec fails, due to the async flow. If I add a setTimeout of 101 ms before the expect - it passes.
My code will use some DB API that returns promise, so the async function will eventually look like:
//...
return (dispatch) => {
return dbAPI.fetchUser().then(dispatch(....));
}
So I tried to require dbAPI and create a sinon.stub().returns(Promise.resolve()) inside the test and it didn't work as well (I thought that since the stub returns a resolved promise - the async function will act like a synchronous function).
Any ideas how should I test async functions like that?
Thank,
Amit.
Don't mock dispatch with sinon, write your own and call Mocha's done() in that when it's done.
it('Should work', (done) => {
const dispatch = () => {
// Do your tests here
done();
};
const action = fetchCurrentUser();
action(dispatch)
// Also allow quick failures if your promise fails
.catch(done);
})
If you're just wanting to ensure that the dispatch is called, then mocha will time out. The catch on the returned promise from your async action creator allows errors to be shown in the right place and for the test to fail rather than time out.
Well, I think I've found a solution:
Assuming my async function looks like this:
//...
return (dispatch) => {
return dbAPI.fetchUser().then(dispatch(....));
}
Then I can write the spec as follows:
it('Should work', () => {
dbAPI.fetchUser = sinon.stub().returns(Promise.resolve({username: 'John'}));
const dispatch = sinon.spy();
const action = fetchCurrentUser();
action(dispatch).then(() => {
expect(dispatch.called).to.be.true;
});
});
I don't know if this is a workaround or not, but it works. I would appreciate your opinions of a better way of doing this...
Thanks,
Amit.

Resources