I'm having a hard time doing some test on while loop using jest. This is the code I want to test but don't know how to do it.
const SHA256 = require('crypto-js/sha256')
class Block {
constructor(index, timestamp, data, prevHash = "") {
this.index = index
this.timestamp = timestamp
this.data = data
this.prevHash = prevHash
this.hash = this.calculateHash()
this.nonce = 0
}
calculateHash() {
return SHA256(this.index + this.prevHash + this.timestamp + JSON.stringify(this.data) + this.nonce).toString()
}
mineBlock(difficulty) {
while(this.hash.substring(0, difficulty) !== Array(difficulty + 1).join('0')) {
this.nonce++
this.hash = this.calculateHash()
}
}
}
module.exports = Block
This is what I've done so far
const Block = require('../block')
const BlockClass = new Block()
describe('Block Class', () => {
it('constructor', () => {
const obj = new Block(1, 2, 3, 4, 0)
expect(obj.index).toBe(1)
expect(obj.timestamp).toBe(2)
expect(obj.data).toBe(3)
expect(obj.prevHash).toBe(4)
expect(obj.nonce).toBe(0)
})
})
describe('hash', () => {
it('should be string', () => {
expect(typeof BlockClass.calculateHash()).toBe('string')
})
})
I'm pretty new with jest and unit testing and I find it really nice skills to have.
You can do something like this.
const Block = require('../block')
describe('mineBlock', () => {
let block = new Block()
it('should do <something>', () => {
block.mineBlock(5)
expect(block.nonce).toBe('<something>')
expect(block.hash).toBe('<something>')
})
})
Please replace <something> with real values you want.
Related
I have a lambda which calls an interface. Am trying to mock the functions imported from the interface. In each test case, I have to mock different values. When I run all the test cases, the first mocked value does not get cleared and it is carried over to all Test cases
interface.js
const oracledb=require("oracledb");
module.exports = class dbLayer{
execSql= async (sqlQuery) => {
var result;
var binds={};
result = await oracledb.execute(sqlQuery,binds);
return result
}
}
lambda.js
const qryInterface = require(./interface)
var db;
const handler = async (event, context) => {
var sql= event.query
db = new qryInterface();
var dbResponse = await db.execSql(sql)
return dbResponse
}
test.js
const index = require(./lambda)
const dbMock = require(./interface)
jest.mock(./interface);
var mockResponse1 = {
rows: [
{
col1 : 123
}
]
}
var mockResponse2 = {
rows: [
{
col1 : 456
}
]
}
const firstQryResponse = async () => {
return new Promise((resolve, reject) => {
resolve(mockResponse1);
});
};
const secondQryResponse = async () => {
return new Promise((resolve, reject) => {
resolve(mockResponse2);
});
};
describe("1st test suite", () => {
beforeEach(() => {
dbMock.mockReset();
jest.restoreAllMocks();
});
it("Test 1", asycn () => {
var event={}
event.sql=`SELECT col1 FROM TBL_A WHERE col2 = 'A'`
dbMock.mockImplementation(() => {
return {
execSql:firstQryResponse
}
});
var response = await index.handler(event)
expect(response).toEqual(mockResponse1 )
});
it("Test 2", asycn () => {
var event={}
event.sql=`SELECT col1 FROM TBL_A WHERE col2 = 'B'`
dbMock.mockImplementation(() => {
return {
execSql:secondQryResponse
}
});
var response = await index.handler(event)
expect(response).toEqual(mockResponse2 )
});
});
Test 1 mocks the value set in firstQryResponse and Test 2 mocks secondQryResponse. But what happens is the value mocked for execSql is Not getting reset in Test 2 .i.e. firstQryResponse gets carried over to Test 2.
Because of this, 2nd test fails. If i run them individually, it runs fine. I did try mockReset(), but it does not help as well.
Appreciate any help on this
Thanks
Sadiq
I tried comparing data from each table from my data base but i failed
I'm not too familiar with react, I'm still working on it, I'm trying to compare the data from recommendation and customization and if they are the same I display them.
const getRecommendation = () => {
Axios.get("http://localhost:5000/recommendations").then((response) => {
setRecomList(response.data);
});
};
const getCostumization = () => {
Axios.get("http://localhost:5000/customizations").then((response) => {
setCustomList(response.data);
});
};
const getRecById = async (id) => {
Axios.get(`http://localhost:5000/recommendations/${id}`).then((res) => {
setRecById(
recById.filter((val) => {
return val._id === id;
})
);
});
};
useEffect(() => {
{
recommendation.map((rec, i) => {
customization.map((cus, j) => {
if (
rec.type === cus.type &&
rec.violonBody === cus.violonBody &&
rec.violonStick === cus.violonStick &&
rec.violonChincrest === cus.violonChincrest
) {
getCostumization();
}
});
});
}
});
Thank you!
You can use like below
const compare = (obj1, obj2) => {
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) return false;
return keys1.every((key) => obj1[key] === obj2[key]);
};
console.log(compare({ a: 1, b: 2 }, { a: 1, b: 2}));
console.log(compare({ a: 1, b: 2 }, { a: 1, b: 2, c:3 }));
Comparing objects & array is not an easy task to do by ourselves since it involves doing deep comparison.
One of the popular and convenient way is to use the _.isEqual from the lodash library.
You could use it like this:
var object = { 'a': 1 };
var other = { 'a': 1 };
_.isEqual(object, other);
// => true
object === other;
// => false
Could you do something like this? This should return an array of objects that are found in both arrays:
function compareArrays(arr1, arr2) {
const same = [];
for (const i = 0; i < arr1.length; i++) {
for (const j = 0; j < arr2.length; j++) {
if (arr1[i].name === arr2[j].name) {
same.push(arr1[i]);
}
}
}
return same;
}
So using your example it would look like this:
const getRecommendation = () => {
Axios.get("http://localhost:5000/recommendations").then((response) => {
setRecomList(response.data);
});
};
const getCostumization = () => {
Axios.get("http://localhost:5000/customizations").then((response) => {
setCustomList(response.data);
});
};
const getRecById = async (id) => {
Axios.get(`http://localhost:5000/recommendations/${id}`).then((res) => {
setRecById(
recById.filter((val) => {
return val._id === id;
})
);
});
};
useEffect(() => {
const equalPairArray = compareArrays(recommendation, customization)
if(equalPairArray.length > 0){
getCostumization();
}
});
Is there a way to easily compare 2 ast's on babel?
Consider a program like this as the source file:
// example.ts
import { foo } from "bar";
describe("Some test", () => {
let moduleFixture: any;
beforeAll(async () => {
moduleFixture = await foo.createTestingModule({}).compile();
});
afterAll(async () => {
await foo.tearDown();
});
});
And consider the following babel program
const babelParser = require("#babel/parser");
const { default: traverse } = require("#babel/traverse");
const { readFileSync } = require("fs");
const recast = require("recast");
const { default: template } = require("#babel/template");
const source = readFileSync(`./example.ts`, "utf-8");
const buildBeforeAll = template(
` beforeAll(async () => {
moduleFixture = await foo.createTestingModule({}).compile();
}); `,
{
plugins: ["typescript"],
}
);
const beforeAllAst = buildBeforeAll();
const ast = babelParser.parse(source, {
allowImportExportEverywhere: true,
plugins: ["typescript"],
});
traverse(ast, {
enter(path) {
const isBeforeAll = path.isIdentifier({ name: "beforeAll" });
if (isBeforeAll) {
// Somehow compare is beforeAllASt === path
console.log(`found an appropriate beforeall`);
path.replaceWithSourceString(`beforeEach`);
}
},
});
console.log(recast.print(ast).code);
What would be the best way to compare beforeAllAst with a traversed node?
The simplest way to made such modifications will be using 🐊Putout code transformer, I'm working on.
Here is how it looks like:
const source = `
beforeAll(async () => {
moduleFixture = await foo.createTestingModule({}).compile();
});
`;
module.exports.replace = () => ({
[source]: (vars, path) => {
path.node.callee.name = 'beforeEach'
return path;
},
});
This plugin searches for exact mach of beforeAll function call. It uses #putout/compare which can be used directly in your code:
const {compare} = require('#putout/compare');
traverse(ast, {
enter(path) {
const isBeforeAll = path.isIdentifier({ name: "beforeAll" });
if (compare(path, beforeAllAst)) {
// Somehow compare is beforeAllASt === path
console.log(`found an appropriate beforeall`);
path.replaceWithSourceString(`beforeEach`);
}
},
});
#putout/compare compares AST-node with given string or other AST-node
disclaimer: this is part of a course I am taking and a practice task. I am having quite hard time wrapping my head around the test chapter of a course I am taking. Given the following class, I have to write test to it but I see the error else path not taken on my return results; line. Which else is it talking about?
import DB from './DB';
import ErrorLogger from './ErrorLogger'; // ===> if path not taken here
class ChapterSevenJest {
constructor() {
if (!ChapterSevenJest.instance) {
ChapterSevenJest.instance = this;
}
return ChapterSevenJest.instance;
}
_db = new DB();
getData = async (gradeId, teamId) => {
let results = [];
try {
results = await this._db.getData(gradeId, teamId);
} catch (error) {
ErrorLogger.register(
error
);
}
return results; // else path not taken here
};
}
const JestPractice = new ChapterSevenJest();
export default JestPractice;
the test:
import DB from './DB';
import ErrorLogger from './ErrorLogger';
import JestPractice from './JestPractice';
describe('service', () => {
const gradeId = 11;
const teamId = 1;
let spyLogs;
beforeEach(() => {
spyLogs = jest.spyOn(ErrorLogger, 'register');
spyLogs.mockReturnValue(true);
});
afterEach(() => {
spyLogs.mockReset();
});
it('should return data ot a grade and team', async () => {
const spyDB = jest.spyOn(
DB.prototype,
'getData'
);
const stat = [
{
"score" : 100,
"rank": 2
}
]
spyDB.mockResolvedValue(stat);
const results = await JestPractice.getData(
gradeId,
teamId
);
expect(spyDB).toHaveBeenCalledWith(gradeId, teamId);
expect(results).toHaveLength(1);
expect(results[0].score).toStrictEqual(100);
expect(results[0].rank).toStrictEqual(2);
});
it('should return empty on error', async () => {
const spyDB = jest.spyOn(
DB.prototype,
'getData'
);
spyDB.mockRejectedValue('error');
const results = await JestPractice.getData(
gradeId,
teamId
);
expect(spyDB).toHaveBeenCalledWith(gradeId, teamId);
expect(results).toHaveLength(0);
expect(spyLogs).toHaveBeenCalledWith(
"error"
);
});
});
There is only 1 if statement which is
if (!ChapterSevenJest.instance) {
ChapterSevenJest.instance = this;
}
You need to have a test where ChapterSevenJest.instance is truthy so that the if block doesn't execute.
How can I restore or implement mock in one test? I have a function:
const parser = (data)=>{
const now = moment().format('DD-MM-YYYY');
//more implementation
const parsedDate = moment(dateFromData).format('DD-MM-YYYY')
return {
date: isDateFromDataExists ? now : parsedDate
}
}
And now I would like to test my function. When isDateFromDataExists is true I would like to return current year (which should be mocked), but when isDateFromDataExists is false I would like to return parsedDate.
When I mocked globally
jest.mock('moment', () => () => ({format: () => '01-01-2020'}));
I can't "unlock" in one test.
How can I do this with Jest?
====EDIT====
This is my code.
const myParser = (single) => {
const obj = {};
const now = moment().format("DD-MM-YYYY");
obj.availableFrom = get(single, 'FreeFrom', '') !== '' ? moment(get(single, 'FreeFrom'), 'YYYY-MM-DD').format("DD-MM-YYYY") : now;
return obj;
}
This is my tests
test('Return correct json when FreeFrom is empty', async () => {
const xmlData = fs.readFileSync(path.join(__dirname, './testData/1.xml'), 'utf8');
var jsonObj = parser.parse(xmlData, options, true);
const result = require('./testData/1.json');
expect(myParser(jsonObj)).toEqual(result);
});
test('Return correct json when FreeFrom is available', async () => {
const xmlData = fs.readFileSync(path.join(__dirname, './testData/2.xml'), 'utf8');
var jsonObj = parser.parse(xmlData, options, true);
const result = require('./testData/2.json');
expect(myParser(jsonObj)).toEqual(result);
});
I have to cover two test cases.
When FreeFrom is not empty string then convert value with moment. Then format to my format.
When FreeFrom is empty string then use current date with moment. Then format to my format.
In case 2. I would like to mock current date to make tests independent of system date.
As suggested in the comments check related question
Here's how you could implement it
let dateFromData = null;
let isDateFromDataExists = null;
const parser = (data) => {
const now = moment().format('DD-MM-YYYY');
const parsedDate = moment(dateFromData, 'DD-MM-YYYY').format('DD-MM-YYYY')
return {
date: isDateFromDataExists ? now : parsedDate
}
}
const {
core: {
beforeEach,
describe,
it,
expect,
run
},
} = window.jestLite;
describe("parser", () => {
beforeEach(() => {
const currentTimestamp = moment().valueOf();
moment.now = jestLite.core.jest.fn().mockReturnValue(currentTimestamp);
});
it("return current date when isDateFromDataExists is true", () => {
isDateFromDataExists = true;
const currentDate = moment().format('DD-MM-YYYY');
expect(parser().date).toBe(currentDate);
});
it("return parsed date when isDateFromDataExists is false", () => {
isDateFromDataExists = false;
dateFromData = "02-01-2003";
expect(parser().date).toBe(dateFromData);
});
});
run().then(result => {
console.log(result);
})
<script src="https://unpkg.com/jest-lite#1.0.0-alpha.4/dist/core.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.19.1/moment.min.js"></script>