So I'm trying to do some basic API testing with Jest by importing a function from handler.ts but Jest crawls through the handler ts imports and gives me linter errors for a file that handler importest from my libs folder when all I want to do is check if the result of that function equals what I want it to equal.
Here's my test file test/handler.test.ts:
import { getInbox } from './../handler'
import * as myMongo from '../../../libs/mongo';
import { Db } from 'mongodb';
const productionDbPromise: Promise<Db> = myMongo.getProductionDb();
test("Case page 1, limit 5", async ()=>{
const page = 1;
const limit = 5;
const event = {
queryStringParameters: {
page: page,
limit: limit
}
};
const productionDb = await productionDbPromise;
const seekerCollection = productionDb.collection('seekers');
const totalDocs = await seekerCollection.countDocuments({ lastMessageDate: { $ne: null } });
const code = 200;
const status = 'OK';
const res: any = await getInbox(event);
expect(res.code).toEqual(code);
expect(res.status).toEqual(status);
expect(res.json().totalDocs).toEqual(totalDocs);
expect(res.json().seekers.length).toEqual(limit);
});
And here's the error:
Test suite failed to run
TypeError: twilio is not a function
6 | export const client = twilio(accountSid, authToken);
7 | export const messagingServiceSid = process.env.TWILIO_SERVICE_ID;
> 8 |
| ^
at Object.<anonymous> (../../libs/twilio.ts:8:18)
at Object.<anonymous> (../../libs/message.ts:7:18)
at Object.<anonymous> (handler.ts:14:19)
at Object.<anonymous> (__test__/handler.test.ts:4:19)
Test Suites: 1 failed, 1 total
Tests: 0 total
Snapshots: 0 total
Time: 12.086 s
npm ERR! Test failed. See above for more details.
Any idea how to get it to ignore this? (which by the way the function I'm testing does not even use any exports from that libs file, and the twilio object is correctly imported on the first line of that file)
It's not Jest's responsibility to run a linter, also it doesn't crawl through any modules that weren't explicitly imported.
This is not linter but runtime error, and it cannot be suppressed or discarded. The problem is exactly what it says:
TypeError: twilio is not a function
Call stack gives a good idea where it comes from:
at Object.<anonymous> (../../libs/twilio.ts:8:18)
at Object.<anonymous> (../../libs/message.ts:7:18)
at Object.<anonymous> (handler.ts:14:19)
at Object.<anonymous> (__test__/handler.test.ts:4:19)
handler.ts depends on message.ts, and message.ts depends on twilio.ts, where the error happens. If twilio is not supposed to be available in tests, either it or one of these modules need to be mocked.
Related
Can anyone help here. I couldn't run my test file. Below is the error & test file.
jest.useFakeTimers();
import { orderController } from '../controllers/orderController';
import { orderService } from '../service/orderService';
const res: any = {
send(object: any) {
return object;
}
};
describe("Methods in orderController", () => {
test("checking an API", async () => {
const patientDetailsMock = await jest.spyOn(orderService, 'getPatientDetails');
//const req = {}
//await orderController.createOrder(req, res);
expect(patientDetailsMock).toHaveBeenCalled();
//console.log("hello..inside test",patientDetailsMock)
//expect(patientDetailsMock).toBeTruthy();
});
});
>chandanasriharimummaneni#PTRL671:~/Desktop/demo/JestTesting/node-orders$ npm test
> node-orders#0.0.1 test /home/chandanasriharimummaneni/Desktop/demo/JestTesting/node-orders
> jest
FAIL src/test/orderController.test.ts
Methods in orderController
✕ checking an API (3ms)
● Methods in orderController › checking an API
expect(jest.fn()).toHaveBeenCalled()
Expected number of calls: >= 1
Received number of calls: 0
21 | //const req = {}
22 | //await orderController.createOrder(req, res);
> 23 | expect(patientDetailsMock).toHaveBeenCalled();
| ^
24 | //console.log("hello..inside test",patientDetailsMock)
25 | //expect(patientDetailsMock).toBeTruthy();
26 |
at Object.<anonymous> (src/test/orderController.test.ts:23:36)
console.warn node_modules/mongoose/lib/helpers/printJestWarning.js:4
Mongoose: looks like you're trying to test a Mongoose app with Jest's default jsdom test environment. Please make sure you read Mongoose's docs on configuring Jest to test Node.js apps: http://mongoosejs.com/docs/jest.html
console.info node_modules/common-component/lpl/utils/logger/logger.js:184
{ uniqId: '', req: '', jsonObject: '', description: '', arguments: '' } [
'AWS-MIS-Config',
'{"provider":"amazon","keyId":"AKIAT5D3HEZTLAOGKVPG","key":"ZrPLIGmGXWh/nPh0euj+042m+yUUJUzUYvwPMoRR","region":"us-east-1"}'
]
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 1.994s, estimated 2s
Ran all test suites.
Jest did not exit one second after the test run has completed.
This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with `--detectOpenHandles` to troubleshoot this issue.
What are ways to mock db and methods using mongoose ORM?
Is there any way to mock db connection with object reference ? Also help me to to clear the issue. I have changed jsdom test environment.
I'm writing unit tests with Jest trying to test a module which uses FS.
The module file:
import fs from 'fs';
import logger from './logger.utils';
export const getNumberOfFiles = async (targetDir: string): Promise<number> => {
// get number of folders
logger.info(`getNumberOfFiles from ${targetDir}/${fileName}`);
const numberOfFiles = await fs.readdirSync(targetDir);
return numberOfFiles.length;
};
Test file
import fs from 'fs';
import { getNumberOfFiles } from '../../src/utils/fs.utils';
jest.mock('fs');
describe('fs.utils', () => {
describe('getNumberOfFiles', () => {
it('Should return number', async () => {
fs.readdirSync = jest.fn();
const readdirSyncMock = fs.readdirSync = jest.fn();
readdirSyncMock.mockResolvedValue([1, 2, 3]);
const result = await getNumberOfFiles('targetDir');
expect(result).toEqual(3);
expect(readdirSyncMock.mock.calls.length).toEqual(1);
});
});
});
When I run the test file, I get the following error:
Config file ..../config/runtime.json cannot be read. Error code is: undefined. Error message is: Cannot read property 'replace' of undefined
1 | const cheggLogger = require('#chegg/logger');
2 | import loggingContext from './loggingContext';
> 3 | import config from 'config';
| ^
4 | import os from 'os';
5 | import constants from '../../config/constants';
6 |
at Config.Object.<anonymous>.util.parseFile (node_modules/config/lib/config.js:789:13)
at Config.Object.<anonymous>.util.loadFileConfigs (node_modules/config/lib/config.js:666:26)
at new Config (node_modules/config/lib/config.js:116:27)
at Object.<anonymous> (node_modules/config/lib/config.js:1459:31)
at Object.<anonymous> (src/utils/logger.utils.ts:3:1)
Content of logger.utils.ts
const internalLogger = require('internalLogger');
import loggingContext from './loggingContext';
import config from 'config';
import os from 'os';
import constants from '../../config/constants';
const logger = internalLogger.createLogger({
level: config.get(constants.LOG_LEVEL)
});
export default logger;
I assume that config is using FS, and once I mock the module, it fails.
How can I resolve this? Please advise
I'm guessing the problem comes from config also using the fs api but you are now mock entire module fs which makes all methods should be mocked before using.
But I have an idea for you by using jest.doMock which you can provide a factory for each test and just mock only method we need. Here is a draft idea:
describe('fs.utils', () => {
describe('getNumberOfFiles', () => {
it('Should return number', async () => {
jest.doMock('fs', () => ({
// Keep other methods still working so `config` or others can use
// so make sure we don't break anything
...jest.requireActual('fs'),
readdirSync: jest.fn(pathUrl => {
// Mock for our test path since `config` also uses this method :(
return pathUrl === 'targetDir' ? Promise.resolve([1, 2, 3]) : jest.requireActual('fs').readdirSync(pathUrl)
})
}));
// One of the thing we should change is to switch `require` here
// to make sure the mock is happened before we actually require the code
// we can also use `import` here but requires us do a bit more thing
// so I keep thing simple by using `require`
const {getNumberOfFiles} = require('../../src/utils/fs.utils');
const result = await getNumberOfFiles('targetDir');
expect(result).toEqual(3);
// you might stop assert this as well
// expect(readdirSyncMock.mock.calls.length).toEqual(1);
});
});
});
Just also want to check, if you created a config file as described here: https://www.npmjs.com/package/config#quick-start
When i run my project in terminal like this
node index.js
I get a reference error: config not defined
/home/ether/Documents/nodesendeth/index.js:6
const {asset, base, spread, allocation} = config;
^
ReferenceError: config is not defined
at tick (/home/ether/Documents/nodesendeth/index.js:6:47)
at run (/home/ether/Documents/nodesendeth/index.js:49:3)
at Object.<anonymous> (/home/ether/Documents/nodesendeth/index.js:52:1)
at Module._compile (internal/modules/cjs/loader.js:1151:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1171:10)
at Module.load (internal/modules/cjs/loader.js:1000:32)
at Function.Module._load (internal/modules/cjs/loader.js:899:14)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
at internal/main/run_main_module.js:17:47
in my code i have assigned the config constant like this:
require('dotenv').config;
const ccxt = require('ccxt');
const axios = require('axios');
const tick = async => {
const {asset, base, spread, allocation} = config;
const market = `${asset}/${base}`;
const orders = binanceClient.fetchOpenOrders(market);
orders.forEach(async order => {
await binanceClient.cancelOrder(order.id);
});
const results = Promise.all([
axios.get('https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd'),
axios.get('https://api.coingecko.com/api/v3/simple/price?ids=tether&vs_currencies=usd')
]);
const marketPrice = results[0].data.bitcoin.usd / results[1].data.tether.usd;
const sellPrice = marketPrice * (1 + spread);
const buyPrice = marketPrice * (1 - spread);
const balances = binanceClient.fetchBalance();
const assetBalance = balances.free[asset];
const baseBalance = balances.free[base];
const sellVolume = assetBalance * allocation;
const buyVolume = (baseBalance * allocation) / marketPrice;
binanceClient.createLimitSellOrder(market, sellVolume, sellPrice);
binanceClient.createLimitBuyOrder(market, sellVolume, buyPrice);
console.log(`
New tick for ${market}...
Created limit sell order for ${sellVolume}#${sellPrice}
Create limit buy order for ${buyVolume}#${buyPrice}`)
}
const run = () => {
const config = {
asset: 'BTC',
base: 'USDT',
allocation: 0.1,
spread: 0.2,
tickInterval: 2000
};
const binanceClient = new ccxt.binance({
apiKey: process.env.API_ENV,
secret: process.env.API_SECRET,
});
tick(config, binanceClient);
setInterval(tick, config.tickInterval, config, binanceClient);
}
run()
I also got await errors saying that i need to run them in an sync function which I do.
i have removed the await keyword now but the app should run with the await kewyword because those functions are async.
Why am i getting those errors when i have a config variable aswell as an async function?
I assume that something with my async function doesnt work because it neither recognises the config constant nor the async/await calls
config is undefined in your code.
You likely meant to declare it on this line, as follows:
const config = require('dotenv').config();
...but this is only half of your problem because, furthermore, the object returned by .config() puts all the variables in a parsed property.
So for example, if your .env looked like this:
apple=red
ball=blue
...and you just logged config, you'd see this:
{ parsed: { apple: 'red', ball: 'blue' } }
Then you could write:
const {apple, ball} = require('dotenv').config().parsed;
console.log(apple, ball);
And this would write:
red blue
In your specific case, if you are expecting asset, base, spread, and allocation to be environment variables in your .env file, then you could potentially change the line to say:
const {asset, base, spread, allocation} = config.parsed;
I am trying to learn how to make a discord bot and pull data from this API called Ergast (http://ergast.com/mrd). I found this npm (https://github.com/estevE11/f1-stats) which uses NodeJS implementation to get a historical record of F1 data from Ergast API. Sorry for the bad wording I am still trying to learn the lingo.
I followed what was stated in the npm documentation for installing it and tried using the example to get data from the API. However when I run the code in index.js I get the error "TypeError: "x" is not a function". When I go into the node_modules "f1-stats" folder and run the code from main.js I do get the correct result.
index.js:
const client = new Discord.Client(); //This will be our client
const { prefix, token } = require('./config.json');//const PREFIX = '!';
const f1s = require('f1-stats');
//module.exports.f1s = f1s; //Still causes the TypeError
f1s("2008 drivers", (res) => {
console.log(res);
});
The error message I get in index.js:
f1s("2008 drivers", (res) => {
^
TypeError: f1s is not a function
at Object.<anonymous> (C:\Users\RyanPC\Documents\DiscordBot\index.js:8:1)
at Module._compile (internal/modules/cjs/loader.js:776:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:787:10)
node_modules/f1-stats/main.js:
const f1s = require("./f1-stats"); // "./" is used because module is located in the same folder as the Node.js file
f1s("2008 drivers", (res) => {
console.log(res);
});
when I run it in node_modules/f1-stats/main.js:
{ MRData:
{ xmlns: 'http://ergast.com/mrd/1.4',
series: 'f1',
url: 'http://ergast.com/api/f1/2008/drivers.json',
limit: '30',
offset: '0',
total: '22',
DriverTable: { season: '2008', Drivers: [Array] } } }
Because f1-stats doesn't export anything so when you import it. It is empty. The correct file you need to import is f1-stats/f1-stats.
const f1s = require('f1-stats/f1-stats');
try importing f1s properly , you are getting error because you have not imported the function properly , in other words...check what is being exported from what are you trying to import....hope it solves the problem.
I am trying to setup Unit Testing for Firebase cloud functions. I was following these links:
https://firebase.google.com/docs/functions/unit-testing
https://github.com/firebase/functions-samples/blob/4663b4ddfae3ed8f8a110156d60e71f028680ee7/quickstarts/uppercase/functions/test/test.online.js
I am trying to make the sample code run. Code is as follows:
const chai = require('chai');
const sinon = require('sinon');
const admin = require('firebase-admin');
const projectConfig = {
databaseURL : 'https://gr-automation-5e65c.firebaseio.com',
storageBucket : 'gr-automation-5e65c.appspot.com',
projectId : 'gr-automation-5e65c',
};
const test = require('firebase-functions-test')(projectConfig, '../gr-automation-5e65c-firebase-adminsdk-jkdtf-849f3d0f65.json');
test.mockConfig( /* removed for Clarity */ );
const assert = chai.assert;
describe('Cloud Functions', () => {
let myFunctions;
adminInitStub = sinon.stub(admin, 'initializeApp');
admin.initializeApp();
//console.log(test);
before(() => {
myFunctions = require('../lib/index.js');
//console.log(myFunctions);
//console.log(admin);
});
after(() => {
test.cleanup();
admin.database().ref('messages').remove();
});
describe('makeUpperCase', () => {
it('should upper case input and write it to /uppercase', () => {
const snap = test.database.makeDataSnapshot('input', 'messages/11111/original');
const wrapped = test.wrap(myFunctions.makeUppercase);
return wrapped(snap).then(() => {
return admin.database().ref('messages/11111/uppercase').once('value').then((createdSnap) => {
assert.equal(createdSnap.val(), 'INPUT');
});
});
})
});
});
When I run the test, I get the following error:
Cloud Functions
makeUpperCase
Uppercasing undefined input
1) should upper case input and write it to /uppercase
2) "after all" hook
0 passing (364ms)
2 failing
1) Cloud Functions
makeUpperCase
should upper case input and write it to /uppercase:
Error: Please supply a Firebase app in the constructor for DataSnapshot in order to use the .ref method.
at DataSnapshot.get ref [as ref] (node_modules/firebase-functions/lib/providers/database.js:186:19)
at Function.exports.makeUppercase.functions.database.ref.onCreate [as run] (lib/index.js:135:21)
at wrapped (node_modules/firebase-functions-test/lib/main.js:53:30)
at Context.it (test/index.test.js:46:13)
2) Cloud Functions
"after all" hook:
Error: The default Firebase app does not exist. Make sure you call initializeApp() before using any of the Firebase services.
at FirebaseAppError.FirebaseError [as constructor] (node_modules/firebase-admin/lib/utils/error.js:39:28)
at FirebaseAppError.PrefixedFirebaseError [as constructor] (node_modules/firebase-admin/lib/utils/error.js:85:28)
at new FirebaseAppError (node_modules/firebase-admin/lib/utils/error.js:119:28)
at FirebaseNamespaceInternals.app (node_modules/firebase-admin/lib/firebase-namespace.js:105:19)
at FirebaseNamespace.app (node_modules/firebase-admin/lib/firebase-namespace.js:372:30)
at FirebaseNamespace.ensureApp (node_modules/firebase-admin/lib/firebase-namespace.js:388:24)
at FirebaseNamespace.fn (node_modules/firebase-admin/lib/firebase-namespace.js:283:30)
at Context.after (test/index.test.js:31:15)
Any hint on what am I doing wrong?
test.data.makeDataSnapshot has an optional third parameter which is a Firebase app (see https://firebase.google.com/docs/reference/functions/test/test.database#.makeDataSnapshot). However, since you initialized the firebase-functions-test with your project config values, you normally do not need to supply it.
However you have this line:
adminInitStub = sinon.stub(admin, 'initializeApp');
This is causing the next line to initialize a fake app, since initializeApp method was stubbed out to not do anything
This is causing the 2 failures, to fix, remove:
adminInitStub = sinon.stub(admin, 'initializeApp');