Jest run a single test to get Authentication token before running all tests specified across multiple.test.ts files - jestjs

I am using Jest to automate the testing of a specific API that involves multiple endpoints. The way I have structured my framework is that I have a specific request spec class and test.ts file (i.e. test suite) for each of the endpoints. The calls to these endpoints are authenticated with a token. So in each of the .test.ts test suite files I am using the below beforeAll hook to get the token that is used in each of my tests within the test suite.
beforeAll(async () => {
pricesRequest = new PricesRequestSpec();
tokenRequest = new TokenRequestSpec();
token = await tokenRequest.postTokenRequest();
});
This is fine in that I am only retrieving and using 1 token for all tests in a test suite rather than for each test, however as I have 6 endpoints with the tests for each of these in 6 separate .test.ts files I am making 6 requests for a new token when I really only need to make 1. Is there a way to run the request to retrieve the token before executing any of the testsuites so that I can make just 1 call for get token rather than multiple i.e. using some globalConfig. I know I could get around this by having all tests in the single test.ts testSuite file but for readability purposes I want to keep these in separate folders.
Much appreciated.

I worked out how to do this. I created a script globalSetup.ts in which I make the call to get the token and set this as an env variable..
export default async () => {
let tokenRequest = new TokenRequestSpec();
const token = await tokenRequest.postTokenRequest();
process.env.bearerToken = token;
}
I point to this file in my jest.config.ts for the param...
globalSetup: './jestGlobalSetup.ts'
I can then access this environment varaibles within all my test scripts e.g.
it('returns status 200 and expected response', async () => {
const response = await pricesRequest.getPricesRequest(process.env.bearerToken, queryParams);
pricesRequest.validateSuccessfulResponse(response);
})

Related

NestJS + Jest: how to receive external http requests within integration test?

Goal
In my setup I have two applications. Application A (from a third party ) receives user input, processes it and then sends the processed data via POST to Application B (my nestjs server). I want to run an integration test, where I want to validate internal variables of Application B against User input. For this I want to define the tests within B which do the following steps:
send predefined user input to A
receive a POST from A
do some processing
validate the processing
Defining the tests within B should give the possibility to examine code coverage for the integration tests. I can't do this if I write another application which tests from external.
Problem
I didn't find any way how to receive external http requests within jest tests. My approach would be to create a module with a controller and then listen to the port. For example like this
describe('Integration Test', () => {
beforeAll(async () => {
const testingModule: TestingModule = await Test.createTestingModule(
{
imports: [HttpModule],
providers: [IntegrationTestService],
controllers: [IntegrationTestController],
},
).compile();
await testingModule.listen(3000);
// here I define my tests
});
}
But TestingModule doesn't provide the function "listen". I also didn't get it working using a predefined normal module that is created via NestFactory.create(IntegrationTestModule).
Any suggestion is appreciated!
To run the test server on a port, you need to call testingModule.createNestApplication() like it shows in the docs under e2e tests. Adding this to the end of your beforeAll() will allow you to receive the http requests
const app = testingModule.createNestApplicaiton();
await app.listen(3000);

Node.JS: Refreshing the nodemailer-mock after each test in Jest

I am building a Node JS application using Express.js framework. My application is sending email using the nodemailer package, https://nodemailer.com/about/. I am writing test using supertest and Jest. I am using nodemailer-mock package, https://www.npmjs.com/package/nodemailer-mock to mock my application.
I can mock the logic for sending email for Jest as mentioned in the nodemailer-mock documentation. The only issue is that it is not resetting the data/ count after each test. For example, I have two tests and both are sending emails and when I do the following assertion, it is failing.
const sentEmails = mock.getSentMail();
// there should be one
expect(sentEmails.length).toBe(1);
It is failing because an email was sent in the previous test. How can I reset it?
Assuming your mock variable is set (or even imported) at the module level, this should cover it:
afterEach(() => {
mock.reset();
});
Keep in mind that this method also seems to reset anything else you have configured on the mock (success response, fail response, etc.), so you may need to perform that setup each time too. That would be a good fit for a beforeEach block.

Isolated jest integration tests using DB transaction

in our project we have integration tests written with Jest which first setup data in DB, run test logic and then do the teardown.
Because these tests can run in parallel we have to create setup with unique values (eg. emails have to be unique) for each test so it works with unique keys in the DB.
Our idea is to mock DB layer and create a new transaction for every test before it starts and later rollback it so we do not have to worry about unique test setup and teardown.
I was able to mock our DB layer (currently we use knex) using following code but I do not know how to create a transaction at the beginning of the test, save it to some "test scope variable" and then access it and rollback it.
jest.mock('db.service', () => {
const originalModule = jest.requireActual('db.service');
return {
...originalModule,
db: jest.fn(() => {
// this db() function is called every time when we work with DB and returns knex instance
// maybe something like originalModule.db().transacting(tx);
return originalModule.db();
}),
};
});
Does anybody please have an idea how to do it?

How can I create a default item in my database with Jest so that I could test my API CRUD operations?

I have a complete API build with express that can handle all CRUD operations. My api handles the creation of Services. I'm using an a MYSQL database with my API which contains one table called service. Now I want to be able to insert a mock/default service object so that I could run that same service object in all my tests, and delete it at the end so that I don't fill the my service table with redundant data. And I want that service object to be put through my almost all my tests except my Post request. How can I accomplish this with Jest?
Here's what I have so far in my service.test.js file
How can I create the service object before all my tests and delete it after all my tests and keep it as a global variable to my file?
Jest provides beforeAll and afterAll for your problem/situation
beforeAll - Function will run before all the tests.
afterAll - Function will run after all the tests
Code Structure:
...
beforeAll((done) => {
//Insert your mock data on database
});
afterAll((done) => {
//Delete your mock data from database
});
test('', async() => {
//Your test with database mock data
});
....
Reference : Setup and Teardown -> One-Time Setup

nodejs tests randomly fail on CircleCI

We are building an application using nodejs and writing asynchronous tests for it using Jest. There is a problem we have been facing for a while now in regards to tests; sometimes tests fail on CircleCI while other times they pass. And yes, we are using async/await method to wait for the data to be fetched first before doing an assertion. Here is a snippet from the tests file:
it('should return the expected number of trips', async () => {
const postResp = await request(app)
.post('/api/v1/requests')
.set('authorization', token)
.send(mockRequest);
const createdRequestId = postResp.body.request.id;
const getResp = await request(app)
.get(`/api/v1/requests/${createdRequestId}`)
.set('authorization', token);
expect(getResp.body.requestData.trips).toHaveLength(2);
});
And this is the error that was thrown by CircleCI in regards to this block of test:
TypeError: Cannot read property 'trips' of undefined
There has to be more than this error. i.e some failed requests or the content of the response that you are getting back from the server.
What you might want to do is to log the content of getResp or getResp.body first. then check if the request you are making is returning the right results in circle ci.
You can login via ssh to circle ci so that you can debug by following this step layed out here. https://circleci.com/docs/2.0/ssh-access-jobs/ depending on if you are using circle ci 1 or two.
Only then can you know the cause of the error

Resources