I want to mock stripe apis but unable to figure out how to do it. I'm creating the session using below code-
const stripe = require('stripe')('key');
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'],
line_items: [
{
price_data: {
currency: 'usd',
product_data: {
name: 'abs',
images: ['url'],
},
unit_amount: 100,
},
quantity: 1,
},
],
mode: 'payment',
success_url: `${YOUR_DOMAIN}?success=true&session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${YOUR_DOMAIN}?back=true&order_id=${req.clientReferenceId}`,
metadata: req.metadata,
client_reference_id: req.clientReferenceId,
customer_email: req.customerEmail,
billing_address_collection: 'required',
});
I cannot import stripe in test file as it will require API key. How to do this?
PS- I tried by following this - Jest to mock Stripe but it is not working for me.
stripe exported as a function, when you want to mock it you can use jest.doMock helper.
Imagine that you have an index.js like this:
const stripe = require('stripe')('key'); // You use require('stripe') as a function
exports.CreateSession = async (req) => {
const session = await stripe.checkout.sessions.create({
// information to create session
});
return session;
}
Then, testing file will be like this:
describe('Create session', () => {
beforeEach(() => {
jest.resetModules(); // importance line
});
it('creates the session', async () => {
const req = {
unitAmount: 100,
imageUrl: '',
metadata: {
userId: '1'
}
};
jest.doMock('stripe', () => {
// instead of mocking return an object, let’s return a function
return jest.fn(() => ({ // when the function be called, it return an object like this
checkout: {
sessions: {
create: jest.fn(() => Promise.resolve({
sessionId: '123' // sessionId instead of id , right?
})),
},
},
}));
});
const { CreateSession } = require('./index'); // import function what you need to test
const resp = await CreateSession(req); // execute with a parameter
expect(resp.sessionId).toBe('123');
});
});
You need to create the stripe mock before use it:
jest.mock("stripe", ()=> ({
checkout: {
sessions: {
create: jest.fn(()=> Promise.resolve()) //--> resolve data you are expecting
}
}
}));
Also you can use the Manual Mocks
__mocks__/stripe.js
const stripe = {
checkout: {
sessions: {
create: jest.fn(()=> Promise.resolve()) //--> resolve data you are expecting
}
}
};
export default stripe;
Related
i am writing test functions in nestjs and i am new to this task.
I mostly had problems with typeorm. but my current problem is that I do not call the paginate function in the PaginateLib class inside the function I wrote in the service. I tested the userList function directly before, but it gave paginate undefined error. Now I used mock and paginate function in test. it still gives undefined error.
Here's my admin.service code
public async userList(page, limit): Promise<any> {
const opt = {
relations: ['userInfo'],
};
const userData = await this.paginateLib.paginate(
getRepository(Users),
opt,
page,
limit,
);
return userData;
}
Here's Paginate function code in PaginateLib class. I'm cutting this short as I don't think it's very necessary.
export class PaginateLib {
async paginate(repo, opt, page, limit) {
try {
page = Number(page);
limit = Number(limit);
const items = (Number(page) - 1) * Number(limit);
const [data, count] = await repo.findAndCount({
...opt,
skip: Number(items),
take: Number(limit),
});
if (count <= items) {
return [];
}
and here's my test code
class PaginateMock {
paginate(repo: any, opt: any, page: number, limit: number) {
return [];
}
}
describe('AdminService', () => {
let service: AdminService;
let connection: Connection;
let module: TestingModule;
let services: PaginateLib;
beforeAll(async () => {
const ApiServiceProvider = {
provide: PaginateLib,
useClass: PaginateMock,
},
module = await Test.createTestingModule({
imports: [
TypeOrmModule.forRoot({
type: '****',
host: '****',
port: ****,
username: '****',
password: '****',
database: '****',
entities: [__dirname + '/../../**/*.entity.ts'],
synchronize: true,
}),
],
providers: [
AdminService,
ApiServiceProvider,
],
}).compile();
service = module.get<AdminService>(AdminService);
services = module.get<PaginateLib>(PaginateLib);
});
// afterAll(async () => {
// await module.close();
// });
describe('User Info', () => {
it('should be get user list', async () => {
const paginateSpy = jest.spyOn(services, 'paginate');
expect(paginateSpy).toHaveBeenCalled();
expect(true).toBe(service.userList(1, 1));
});
});
});
I tried different things many times. but the error I get is undefined. what should I do? Is there anyone have an idea?thank you
Try this:
describe('User Info', () => {
it('should be get user list', async () => {
const paginateSpy = jest.spyOn(services, 'paginate');
const userData = await service.userList(1, 1);
expect(paginateSpy).toHaveBeenCalled();
expect(userData).toBe(); // Don't know what userData actually looks like. So this is up to you
});
});
I am working in a test module for my application which uses Sequelize to make queries to a database. I am trying to mock this module and I found this answer which was oriented to typescript: How to mock Sequelize with Jest?
I am doing my test in javascript and I find the mocked function isn't working. So I would like to find an alternative to call the function member of a mocked module inside a test block and perform an implementation of it. I'm not sure if it is a good practice, but I didn't find another way to test the procedure, so I require to reimplement the member definition, however when I run the test, it appears as the reimplementation wasn't performed.
The function I was intended to test is in file sql-api.js
const initDB = async function () {
await connect()
await synchronizePatients()
};
const sequelize = new Sequelize(config.db.database, config.db.username, config.db.password, {
host: config.db.host,
dialect: 'postgres'
});
const connect = async function () {
try {
return await sequelize.authenticate();
} catch (error) {
console.error('Unable to connect to the database:', error);
return error;
}
}
const synchronizePatients = async function () {
console.log("Synchronize patients")
return await Patients.sync({ alter: true })
}
const Patients = sequelize.define('patients', {
uuid: {
primaryKey: true,
allowNull: false,
type: DataTypes.UUID,
defaultValue: Sequelize.UUIDV4 // Or Sequelize.UUIDV1
},
id: {
type: DataTypes.INTEGER,
},
nombres: {
type: DataTypes.STRING,
allowNull: false
},
apellidos: {
type: DataTypes.STRING,
allowNull: false
}, {
// Other model options go here
timestamps: true,
});
Then I have a mock module in __mock__ folder, named sequelized.js
'use strict';
const sequelize = jest.createMockFromModule('sequelize');
const mSequelize = {
authenticate: jest.fn(),
define: jest.fn()
};
const actualSequelize = jest.requireActual('sequelize');
sequelize.Sequelize = jest.fn(() => mSequelize);
sequelize.DataTypes = actualSequelize.DataTypes;
module.exports= sequelize;
Then in my test code in __tests__ folder:
const sqlapi = require("../sql-api");
const { Sequelize, Op } = require('sequelize');
const config = require("../config.json")
const mPatients = { sync: jest.fn() };
const mUsers = {
sync: jest.fn(),
findOne: jest.fn(),
create: jest.fn()
};
jest.mock("sequelize");
const mSequelizeContext = new Sequelize();
describe("Testing setup DB", () => {
afterAll(() => {
jest.resetAllMocks();
});
test("It should connect correctly", async () => {
mSequelizeContext.define.mockImplementation((modelName) => {
switch (modelName) {
case 'patients':
return mPatients;
case 'users':
return mUsers;
}
})
await sqlapi.initDB();
expect(Sequelize).toBeCalledWith(config.db.database, config.db.username, config.db.password, {
host: config.db.host,
dialect: 'postgres'
});
expect(mSequelizeContext.authenticate).toBeCalled();
})
})
However, when I try to run the code, I have the following error:
TypeError: Cannot read property 'sync' of undefined
374 | const synchronizePatients = async function () {
375 | console.log("Synchronize patients")
> 376 | return await Patients.sync({ alter: true })
| ^
377 | }
As the function define wasn't reimplemented in mSequelizeContext.define.mockImplementation(...). I don't know why it doesn't work. In the example I referred first, to call the mocked function they use a mocked(mSequelizeContext.define), however, that mocked function is part of another library ts-jest/utils oriented to typescript. I was wondering that in Javascript it isn't needed.
I also noticed that replacing the implementation in the mock folder by:
const mSequelize = {
authenticate: jest.fn(),
define: jest.fn().mockImplementation((modelName) => {
switch (modelName) {
case 'patients':
return mPatients;
case 'users':
return mUsers;
}
})
};
And here it works, but by the other way, reimplementing inside the test procedure, it doesn't.
Please, if you could orient me in this implementation.
I am trying to develop an application using NestJs as the backend framework. Currently I am writing some integration tests for the controllers.
This is my first project using typescript, I usually use Java/Spring but I wanted to learn and give nestJs a try.
I use different guards to access rest endpoints. In this case I have an AuthGuard and RolesGuard
To make the rest endpoint work I just add something like this in the TestingModuleBuilder:
.overrideGuard(AuthGuard())
.useValue({ canActivate: () => true })
The point is, is it possible to define or override this guards for each test to check that the request should fail if no guard or not allowed guard is defined?
My code for the test is the following one:
describe('AuthController integration tests', () => {
let userRepository: Repository<User>
let roleRepository: Repository<Role>
let app: INestApplication
beforeAll(async () => {
const module = await Test.createTestingModule({
imports: [
AuthModule,
TypeOrmModule.forRoot(typeOrmConfigTest),
PassportModule.register({ defaultStrategy: 'jwt' }),
JwtModule.register({
secret: jwtConfig.secret,
signOptions: {
expiresIn: jwtConfig.expiresIn
}
})
]
})
.overrideGuard(AuthGuard())
.useValue({ canActivate: () => true })
.overrideGuard(RolesGuard)
.useValue({ canActivate: () => true })
.compile()
app = module.createNestApplication()
await app.init()
userRepository = module.get('UserRepository')
roleRepository = module.get('RoleRepository')
const initializeDb = async () => {
const roles = roleRepository.create([
{ name: RoleName.ADMIN },
{ name: RoleName.TEACHER },
{ name: RoleName.STUDENT }
])
await roleRepository.save(roles)
}
await initializeDb()
})
afterAll(async () => {
await roleRepository.query(`DELETE FROM roles;`)
await app.close()
})
afterEach(async () => {
await userRepository.query(`DELETE FROM users;`)
})
describe('users/roles (GET)', () => {
it('should retrieve all available roles', async () => {
const { body } = await request(app.getHttpServer())
.get('/users/roles')
.set('accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200)
expect(body).toEqual(
expect.arrayContaining([
{
id: expect.any(String),
name: RoleName.STUDENT
},
{
id: expect.any(String),
name: RoleName.TEACHER
},
{
id: expect.any(String),
name: RoleName.ADMIN
}
])
)
})
})
It's not immediately possibly with the current implementation, but if you save the guard mock as a jest mock it should be possible. Something like this
describe('Controller Integration Testing', () => {
let app: INestApplication;
const canActivate = jest.fn(() => true);
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
})
.overrideGuard(TestGuard)
.useValue({ canActivate })
.compile();
app = moduleFixture.createNestApplication();
await app.init();
});
it('/ (GET)', () => {
return request(app.getHttpServer())
.get('/')
.expect(200)
.expect('Hello World!');
});
it('/ (GET) Fail guard', () => {
canActivate.mockReturnValueOnce(false);
return request(app.getHttpServer())
.get('/')
.expect(403);
});
});
I'm mocking the #elastic/elasticsearch library and I want to test that the search method is called with the right arguments but I'm having issues accessing search from my tests.
In my ES mock I just export an object that includes a Client prop that returns another object that has the search prop. This is the way search is accessed from the library
const { Client } = require('#elastic/elasticsearch')
const client = new Client(...)
client.search(...)
__mocks__/#elastic/elasticsearch
module.exports = {
Client: jest.fn().mockImplementation(() => {
return {
search: (obj, cb) => {
return cb(
'',
{
statusCode: 200,
body: {
hits: {
hits: [
{
_source: esIndexes[obj.index]
}
]
}
}
}
)
}
}
})
}
__tests__/getAddresses.test.js
const { getAddresses } = require('../src/multiAddressLookup/utils/getAddresses')
const { Client } = require('#elastic/elasticsearch')
beforeEach(() => {
process.env.ES_CLUSTER_INDEX = 'foo'
process.env.ui = '*'
})
describe('multiAddressLookup', () => {
test('Should return the correct premises data with only the relevant "forecasted_outages"', async () => {
const event = {
foo: 'bar'
}
const esQueryResponse = {
"body": "\"foo\":\"bar\"",
"headers": {"Access-Control-Allow-Origin": '*'},
"statusCode": 200
}
await expect(getAddresses(event)).resolves.toEqual(esQueryResponse)
expect(Client().search).toHaveBeenCalled() // This fails with 0 calls registered
})
})
I'm not sure of any exact documentation for this scenario but I got the idea while looking through the Jest: The 4 ways to create an ES6 Mock Class - Automatic mock portion of the Jest documentation.
First, the search method in the ES mock, __mocks__/#elastic/elasticsearch, needs to be converted into a jest mock function, jest.fn(). Doing this gives us access to properties and values that jest mocks provide.
__mocks__/#elastic/elasticsearch.js converted
module.exports = {
Client: jest.fn().mockImplementation(() => {
return {
search: jest.fn((obj, cb) => {
return cb(
'',
{
statusCode: 200,
body: {
hits: {
hits: [
{
_source: esIndexes[obj.index]
}
]
}
}
}
)
})
}
})
}
Second, in our tests we need to follow the path from the Client mock class until we find out methods. The syntax is MockClass.mock.results[0].value.mockFunction.
Example Test
const { Client } = require('#elastic/elasticsearch') // This is located in the "__mocks__" folder in the root of your project
const { getAddresses } = require('../../src/getAddresses') // This is the file we wrote and what we are unit testing
describe('getAddresses', () => {
it('Should call the ES Search method', async () => {
const event = { ... }
const expected = { ... }
await expect(getAddresses(event)).resolves.toEqual(expected) // pass
expect(Client.mock.results[0].value.search).toHaveBeenCalled() // pass
})
})
I've been using Knex successfully to connect to a backend database. But I want to be able to unit test my code. Is there a way to mock the database connection?
I've tried using proxyquire but I can't seem to get it to work.
The problem seems to be with the way Knex is initialized.
var knex = require('knex')({
client: 'mysql',
connection: {}
});
I setup knex to be mocked in my unit test.
myService = proxyquire('../app/myService', {
'knex': knexProxy
});
My service includes knex.
var knex = require('knex').knex,
When my service runs a query, it fails.
var sql = knex("table_name");
sql.insert(rowToInsert, "auto_increment_id");
sql.then(function (insertId) {
resolve();
}, function (err) {
reject(err);
});
For some reason I just can't seem to capture the request before it attempts the connection.
I've also, tried to create a custom Knex Client, but that hasn't worked yet either.
Using jest:
Create the file /__mocks__/knex.js in your app root:
module.exports = () => ({
select: jest.fn().mockReturnThis(),
from: jest.fn().mockReturnThis(),
where: jest.fn().mockReturnThis(),
first: jest.fn().mockReturnThis(),
then: jest.fn(function (done) {
done(null)
})
})
Pass the desired return value to done
I have been using in-memory Sqlite3 databases for automated testing with great success. It's not true unit testing however it does run much faster than MySQL or PostgreSQL. I have posted more details about this solution on a different question.
I used jest to mock knex but I had to define an object that contains the method that I used.
not the most elegant solution but is working
let knexMock = () => {
const fn = () => {
return {
returning: function() {
return {
insert: jest.fn().mockImplementation(() => [123123])
}
},
insert: jest.fn()
}
}
fn.raw = jest.fn()
return fn
}
knex.mockImplementation(knexMock)
I'm using jest and you can do something like this:
jest.mock('knex', () => {
const fn = () => {
return {
select: jest.fn().mockReturnThis(),
from: jest.fn().mockReturnThis(),
where: jest.fn().mockReturnThis(),
first: jest.fn().mockReturnThis(),
insert: jest.fn().mockReturnThis(),
raw: jest.fn().mockReturnThis(),
then: jest.fn(function (done) {
done(null)
})
}
}
return fn
})
I've written this tiny lib called knex-mock-client which does exactly this, it allows you to setup your db "connection" with a mockClient which will track your calls & help you with responses.
For example:
// my-cool-controller.ts
import { db } from '../common/db-setup';
export async function addUser(user: User): Promise<{ id }> {
const [insertId] = await db.insert(user).into('users');
return { id: insertId };
}
// my-cool-controller.spec.ts
import { expect } from '#jest/globals';
import knex, { Knex } from 'knex';
import { getTracker, MockClient } from 'knex-mock-client';
import faker from 'faker';
jest.mock('../common/db-setup', () => {
return knex({ client: MockClient });
});
describe('my-cool-controller tests', () => {
let tracker: Tracker;
beforeAll(() => {
tracker = getTracker();
});
afterEach(() => {
tracker.reset();
});
it('should add new user', async () => {
const insertId = faker.datatype.number();
tracker.on.insert('users').response([insertId]);
const newUser = { name: 'foo bar', email: 'test#test.com' };
const data = await addUser(newUser);
expect(data.id).toEqual(insertId);
const insertHistory = tracker.history.insert;
expect(insertHistory).toHaveLength(1);
expect(insertHistory[0].method).toEqual('insert');
expect(insertHistory[0].bindings).toEqual([newUser.name, newUser.email]);
});
});
This works for me, hope it helps someone:
//db.ts
import knex from 'knex';
const db = knex({
client: 'pg',
connection: {},
pool: { min: 0, max: 1 }
});
export default db('someTableName');
//myFunction.ts
//somewhere inside a function
const data = await db
// 👇 Knex query builders are mutable so when re-using them .clone() is necessary.
.clone()
.where({ pk: 'someId', sk: 'someId2' })
.select('data')
.orderBy('inserted_at', 'desc')
.first()
//myFunction.test.ts
describe("myFunction", () => {
beforeEach(() => {
jest.spyOn(db, "clone").mockImplementation(() => db);
jest.spyOn(db, "select");
jest.spyOn(db, "where");
jest.spyOn(db, "orderBy");
});
afterEach(() => {
jest.clearAllMocks();
});
it("should work as expected", async () => {
jest.spyOn(db, "first").mockResolvedValueOnce("desiredReturnValue");
await myFunction();
expect(db.where).toHaveBeenCalledWith({
pk: "someId",
sk: "someId2",
});
expect(db.select).toHaveBeenCalledWith("data");
expect(db.orderBy).toHaveBeenCalledWith("inserted_at", "desc");
expect(db.first).toHaveBeenCalledTimes(1);
});
});