Error while testing delete method in NodeJs with Mocha - javascript

I'm developing a billboard app to learn new technologies and i'm currently having problems trying to test the DELETE method of the API using Mocha.
I've been trying different approaches for it, but i couldn't find a solution yet. I'm using NodeJs and Hapi for the back-end server
const mongoose = require('mongoose')
const chai = require('chai')
const hapiServer = require('../../../index')
const expect = require('chai').expect
const should = chai.should()
chai.use(require('chai-http'))
before(async () => {
const server = await hapiServer()
global.url = 'http://localhost:3000'
})
after(async () => {
await mongoose.connection.close()
//await mongoose.connection.db.dropCollection()
})
const id = new mongoose.Types.ObjectId('5cd8a0eefc06344accd62a76')
describe('Movies API', () => {
it('Should DELETE a single movie', async () => {
const response = await chai.request(global.url)
.delete('/api/movies/' + '5cd8a0eefc06344accd62a77')
response.should.have.status(202)
})
})
Here's the index.js
const Hapi = require('#hapi/hapi')
const Inert = require('#hapi/inert')
const Vision = require('#hapi/vision')
const HapiSwagger = require('hapi-swagger')
const mongoose = require('mongoose')
const mongo = require('./config/mongo')
const Pack = require('./package')
const start = async () => {
const server = await new Hapi.Server({
host: 'localhost',
port: 3000,
})
// MongoDB Connection
try{
await mongoose
.connect(mongo.configuration.getUri(process.env.NODE_ENV), {useNewUrlParser: true})
console.log('MongoDB Connected...')
} catch(err) {
console.log(err)
}
const swaggerOptions = {
info: {
title: 'Billboard API Documentation',
version: Pack.version,
},
}
await server.register([
Inert,
Vision,
{
plugin: HapiSwagger,
options: swaggerOptions
}
]);
try {
await server.start()
console.log('Server running at:', server.info.uri)
} catch(err) {
console.log(err)
}
// Register Plugins
const moviesRoutes = require('./plugins/movies/routes')
server.route(moviesRoutes)
}
start()
module.exports = start
So, the the rest of the api tests are similar and they work excelent. But when i try to test this method i get this response:
error: Error: cannot DELETE /api/movies/5cd8a0eefc06344accd62a77 (404)
at Response.toError (C:\Users\lucas\billboard-backend\node_modules\superagent\lib\node\response.js:94:15)
at ResponseBase._setStatusProperties (C:\Users\lucas\billboard-backend\node_modules\superagent\lib\response-base.js:123:16)
at new Response (C:\Users\lucas\billboard-backend\node_modules\superagent\lib\node\response.js:41:8)
at Test.Request._emitResponse (C:\Users\lucas\billboard-backend\node_modules\superagent\lib\node\index.js:752:20)
at C:\Users\lucas\billboard-backend\node_modules\superagent\lib\node\index.js:916:38
at IncomingMessage.<anonymous> (C:\Users\lucas\billboard-backend\node_modules\superagent\lib\node\parsers\json.js:19:7)
at IncomingMessage.emit (events.js:201:15)
at endReadableNT (_stream_readable.js:1130:12)
at processTicksAndRejections (internal/process/task_queues.js:84:9) {
status: 404,
text: '{"statusCode":404,"error":"Not Found","message":"Not Found"}',
method: 'DELETE',
path: '/api/movies/5cd8a0eefc06344accd62a77'
Any ideas of why is this happening?

You need to add a route like this in your routes file assuming you're using controllers
const express = require('express')
const router = express.Router()
const movieController = require('../controllers/movie.controller')
router.delete('/api/movies/:movieId', movieController.deleteMovie)
module.exports = router

Related

App deployed on Heroku but api calls are now failing (Failed to load resource: net::ERR_CONNECTION_REFUSED, TypeError: Failed to fetch)

My app is successfully deployed on Heroku- it works when I have VSCode open and do npm run start manually, however when I close VSCode it is no longer able to successfully call any APIs on the backend and the console shows me a bunch of errors like the one in the title.
my console (ONLY happens when I close VSCode):
my code in the backend:
const PORT = 8000
const express = require('express')
const cors = require('cors')
const {TwitterApi} = require('twitter-api-v2')
const axios = require('axios')
const cheerio = require('cheerio')
require('dotenv').config()
const snoowrap = require('snoowrap')
const linkPreviewGenerator = require('link-preview-generator')
const spotify = require('spotify-web-api-node')
const fetch = require('node-fetch')
var request = require('request')
const app = express()
app.use(cors())
app.get('/', async (req, res) => {
const client = new TwitterApi(process.env.twt_bearer_token)
const trendsInternational = await client.v1.trendsByPlace(1);
const trendList = []
for (const {trends} of trendsInternational) {
for (const trend of trends) {
trendList.push({
name: trend.name,
url: trend.url
})
}
}
res.json(trendList)
})
app.get('/reddit', async (req, res) => {
const r = new snoowrap({
userAgent: process.env.user_agent,
clientId: process.env.client_id,
clientSecret: process.env.client_secret,
refreshToken: process.env.refresh_token
})
topPosts = []
;(await r.getHot()).forEach(post => {
topPosts.push({
title: post.title,
url: post.url
})
})
res.json(topPosts);
})
app.get('/news', async (req, res) => {
const news_url = 'https://www.theguardian.com/international'
axios(news_url)
.then(response => {
const html = response.data;
const $ = cheerio.load(html);
const articles = [];
const values = new Set();
$('.fc-item__title', html).each(function () { //<-- cannot be a function expression
const title = $(this).text().trim();
const url = $(this).find('a').attr('href');
if (!values.has(url)) {
values.add(url);
articles.push({
title,
url
});
}
})
res.json(articles)
}).catch(err => console.log(err))
})
app.listen(PORT, () => console.log(`Server is running on port ${PORT}`))```
Heroku runs on its own port, try setting port like this
const PORT = Number(process.env["PORT"]) || 8000

How to register pg-promise with hapi

I try to register pg-promise as hapi plugin.
However, the following error occurred.
TypeError: Cannot read properties of undefined (reading 'name')
at internals.Server.register (/home/kim.js/pgpromise/node_modules/#hapi/hapi/lib/server.js:456:42)
at init (/home/kim.js/pgpromise/hapi-pgTest.js:22:16)
My code is as follows and I also attach a reference site.
Hapi Tutorial - Getting Started
Hapi Tutorial - Plugins
'use strict';
const promise = require('bluebird');
const Hapi = require('#hapi/hapi');
const Pg = require('pg-promise')();
const postgreSql = {
host: '127.0.0.1',
port: 5432,
user: 'someone',
password: 'my_password',
database: 'my_db',
table_schema: 'public',
};
const init = async () => {
const server = Hapi.server({
port: 3000,
host: '192.168.9.23'
});
await server.register([{ // ERROR is Here !!
plugin: Pg,
options: {
promiseLib: promise
}
}]);
server.route({
method: 'GET',
path: '/',
handler: async (request, h) => {
let sql = 'SELECT FROM my_table limit 1';
let result = await pgp.one(sql).catch(error => { console.log(sql); });
return result;
}
});
const pgp = Pg(postgreSql);
await server.start();
console.log('Server running on %s', server.info.uri);
};
process.on('unhandledRejection', (err) => {
console.log(err);
process.exit(1);
});
init();
English is not my first language, so please understand if the sentence is weird.
In my project, I used a plug-in called hapi-pg-promise before, but Hang occurred with hapi v20.
My mistake was that I try register the module, not the plugin.
So I referred to hapi plugin doc and modified my code by referring to hapi-pg-promise source code.
Make My hapi-pg-promise
'use strict';
/* this is original source
const Hoek = require('hoek');
const PgPromise = require('pg-promise');
*/
const Hoek = require('#hapi/hoek');
const PgPromise = require('pg-promise')();
const pkg = require('./package.json');
const DEFAULTS = {
init: {},
cn: undefined
};
module.exports = {
pkg,
register: async function (server, options) {
const opts = Hoek.applyToDefaults(DEFAULTS, options);
const pgp = require('pg-promise')(opts.init);
const db = pgp(opts.cn);
server.ext('onPreHandler', (request, h) => {
request.db = db;
return h.continue;
});
server.expose('db', db);
server.events.on('stop', pgp.end);
}
};
After that, I registered the plugin and it worked :)
/* NOT this
const Pg = require('pg-promise')();
*/
const Pg = require('./myPlugins/my-hapi-pg-promise');

Prevent Apify from shutting down my express server

I have an express server with a POST endpoint that starts a crawler. When the crawler finishes it shuts down the whole server. Am I doing something wrong? How can I prevent it from happening?
The project looks something like this:
// server.js
const express = require('express')
const bodyParser = require('body-parser')
const startSearch = require('./crawler.js')
const app = express()
app.use(bodyParser.json())
app.post('/crawl', async (req, res) => {
const { foo, bar } = req.body
startSearch({ foo, bar })
res.end()
})
app.listen(PORT, () => console.log(`listening on port ${PORT}`))
// crawler.js
const Apify = require('apify')
const startSearch = ({ foo, bar }) => {
Apify.main(async () => {
const sources = [{
url: 'https://path_to_website.com',
userData: { foo, bar }
}]
const requestList = await Apify.openRequestList(null, sources)
const crawler = new Apify.PuppeteerCrawler({
requestList,
handlePageFunction: async ({ request, page }) => {
// do things using puppeteer
}
}
})
await crawler.run()
})
}
Just avoid using Apify.main(). For details, see How to use Apify on Google Cloud Functions
(I thought I'm sending the answer, but it seems it was just a comment)

Web3 web3.eth.sendSignedTransaction Invalid params

Im very new to ethereum i have set up a private network using the pantheon client. i have successfully deployed a contract to the network and all interactions with the contract work when using through remix.
I am trying to set up a relay where a transaction is signed client side, sent to a nodeJs server and then the server proxies the transaction to the contract. however when i pass the signed transaction to sendSignedTransaction() i get the error Invalid params, to me this is very vague and i am unsure what i'm doing wrong / what the invalid params are. (any advice on how to debug this?)
UPDATE
using web3 v1.2.0
Error
Error: Returned error: Invalid params
at Object.ErrorResponse (/Users/ghost/node_modules/web3-core-helpers/src/errors.js:29:16)
at Object.<anonymous> (/Users/ghost/node_modules/web3-core-requestmanager/src/index.js:140:36)
at /Users/ghost/node_modules/web3-providers-ws/src/index.js:121:44
at Array.forEach (<anonymous>)
at W3CWebSocket.WebsocketProvider.connection.onmessage (/Users/ghost/node_modules/web3-providers-ws/src/index.js:98:36)
at W3CWebSocket._dispatchEvent [as dispatchEvent] (/Users/ghost/node_modules/yaeti/lib/EventTarget.js:107:17)
at W3CWebSocket.onMessage (/Users/ghost/node_modules/websocket/lib/W3CWebSocket.js:234:14)
at WebSocketConnection.<anonymous> (/Users/ghost/node_modules/websocket/lib/W3CWebSocket.js:205:19)
at WebSocketConnection.emit (events.js:188:13)
at WebSocketConnection.processFrame (/Users/ghost/node_modules/websocket/lib/WebSocketConnection.js:552:26)
at /Users/ghost/node_modules/websocket/lib/WebSocketConnection.js:321:40
at process.internalTickCallback (internal/process/next_tick.js:70:11)
Contract
pragma solidity ^0.5.1;
import "./Ownable.sol";
contract Entry is Ownable {
mapping (address => string) hash;
function addEntry(string memory _hash) public {
hash[msg.sender] = _hash;
}
function getHash() public view returns(string memory){
return hash[msg.sender];
}
}
Relay Server
const Web3 = require('web3');
const express = require('express')
const app = express()
const port = 3003
const bodyParser = require('body-parser');
const cors = require('cors')
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json())
app.use(cors())
var web3 = new Web3(Web3.givenProvider || "ws://localhost:7002");
app.post('/transaction/send', async (req, res) => {
const {tx, data} = req.body;
web3.eth.sendSignedTransaction(tx, function (err, transactionHash) {
if(err) console.log(err);
console.log(transactionHash);
});
})
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
Front end
import React from 'react';
import './App.css';
import Web3 from 'web3';
import request from 'request-promise';
const Tx = require('ethereumjs-tx').Transaction;
const web3 = new Web3("http://localhost:8545");
const privKey = '[My Priv key here]';
const contractADDRESS = "0x4261d524bc701da4ac49339e5f8b299977045ea5";
const addressFrom = '0x627306090abaB3A6e1400e9345bC60c78a8BEf57';
const contractABI = [{"constant":false,"inputs":[{"name":"_hash","type":"string"}],"name":"addEntry","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getHash","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"}];
function App() {
async function sendTx(){
const data = await extraData();
web3.eth.getTransactionCount(addressFrom).then(txCount => {
const txData = {
nonce: web3.utils.toHex(txCount),
gasLimit: web3.utils.toHex(25000),
gasPrice: web3.utils.toHex(10e9),
to: contractADDRESS,
from: addressFrom,
data: data
}
sendSigned(txData, function(err, result) {
if (err) return console.log('error', err)
console.log('sent', result)
})
})
}
async function sendSigned(txData, cb) {
const privateKey = new Buffer(privKey, 'hex')
const transaction = new Tx(txData)
transaction.sign(privateKey)
const serializedTx = transaction.serialize().toString('hex')
const response = request({
method: 'POST',
uri: 'http://127.0.0.1:3003/transaction/send',
body: {
tx: serializedTx,
data: 'somehashhh'
},
json: true,
});
}
async function extraData() {
const contractInstance = new web3.eth.Contract(contractABI, contractADDRESS);
return await contractInstance.methods.addEntry('somehashhh').encodeABI();
}
return (
<div className="App">
<header className="App-header">
<div onClick={() => sendTx()}>Submit transaction</div>
</header>
</div>
);
}
export default App;
This is the txData sent from front end
{
data: "0x17ce42bd0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000a736f6d6568617368686800000000000000000000000000000000000000000000"
from: "0x627306090abaB3A6e1400e9345bC60c78a8BEf57"
gasLimit: "0x61a8"
gasPrice: "0x2540be400"
nonce: "0x0"
to: "0x4261d524bc701da4ac49339e5f8b299977045ea5"
}
After a lot of trail and error an 0 suggestions on stack overflow working, i have got the transaction signing working!. In the end i came away from using ethereumjs-tx (which for some reason is recommended by a lot of people) and used just pure Web3.
Front end client
async function sendTx(){
const { address: from } = web3.eth.accounts.privateKeyToAccount(PRIVATE_KEY)
const contract = new web3.eth.Contract(CONTRACT_ABI, CONTRACT_ADDRESS)
const query = await contract.methods.updateCount();
const signed = await web3.eth.accounts.signTransaction({
to: CONTRACT_ADDRESS,
from,
value: '0',
data: query.encodeABI(),
gasPrice: web3.utils.toWei('20', 'gwei'),
gas: Math.round((await query.estimateGas({ from })) * 1.5),
nonce: await web3.eth.getTransactionCount(from, 'pending')
}, PRIVATE_KEY)
const response = await request({
method: 'POST', json: true,
uri: 'http://127.0.0.1:3003/transaction/send',
body: {
tx: signed.rawTransaction,
data: 'some data'
}
});
console.log(response);
}
Relay Server
const Web3 = require('web3');
const express = require('express')
const app = express()
const port = 3003
const bodyParser = require('body-parser');
const cors = require('cors')
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json())
app.use(cors())
var web3 = new Web3(Web3.givenProvider || "ws://localhost:7002");
app.post('/transaction/send', async (req, res) => {
const {tx, data} = req.body;
web3.eth.sendSignedTransaction(tx)
.on('transactionHash', (txHash) => res.json({txHash}))
.on('error', console.log)
})
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
hopefully this can help someone else
đź‘Ť

Unit Testing Controllers use Jest, NodeJS

I want to check a case that certain routes are calling the correct controller use Jest specific (mock or spy).
It is case specific for unit testing. Somebody can help me how to check it use jest. I don't need verify kind of
expect (status code or res object) i need to check if controller have been called.
Thanks!
For instance:
// todoController.js
function todoController (req, res) {
res.send('Hello i am todo controller')
}
// index.spec.js
const express = require('express');
const request = require('request-promise');
const todoController = require('./todoController');
jest.mock('./todoController');
const app = express();
app.get('/todo', todoController)
test('If certain routes are calling the correct controller , controller should to have been called times one.', async() => {
await request({url: 'http://127.0.0.1/todo'})
expect(todoController).toHaveBeenCalledTimes(1);
})
Actually if you search, there are many references out there.
In the following, I share a few ways that I know.
One of the big conceptual leaps to testing Express applications with mocked request/response is understanding how to mock a chained
API eg. res.status(200).json({ foo: 'bar' }).
First you can make some kind of interceptor, this is achieved by returning the res instance from each of its methods:
// util/interceptor.js
module.exports = {
mockRequest: () => {
const req = {}
req.body = jest.fn().mockReturnValue(req)
req.params = jest.fn().mockReturnValue(req)
return req
},
mockResponse: () => {
const res = {}
res.send = jest.fn().mockReturnValue(res)
res.status = jest.fn().mockReturnValue(res)
res.json = jest.fn().mockReturnValue(res)
return res
},
// mockNext: () => jest.fn()
}
The Express user-land API is based around middleware. AN middleware that takes a request (usually called req), a response (usually called res ) and a next (call next middleware) as parameters.
And then you have controller like this :
// todoController.js
function todoController (req, res) {
if (!req.params.id) {
return res.status(404).json({ message: 'Not Found' });
}
res.send('Hello i am todo controller')
}
They are consumed by being “mounted” on an Express application (app) instance (in app.js):
// app.js
const express = require('express');
const app = express();
const todoController = require('./todoController');
app.get('/todo', todoController);
Using the mockRequest and mockResponse we’ve defined before, then we’ll asume that res.send() is called with the right payload ({ data }).
So on your test file :
// todo.spec.js
const { mockRequest, mockResponse } = require('util/interceptor')
const controller = require('todoController.js')
describe("Check method \'todoController\' ", () => {
test('should 200 and return correct value', async () => {
let req = mockRequest();
req.params.id = 1;
const res = mockResponse();
await controller.todoController(req, res);
expect(res.send).toHaveBeenCalledTimes(1)
expect(res.send.mock.calls.length).toBe(1);
expect(res.send).toHaveBeenCalledWith('Hello i am todo controller');
});
test('should 404 and return correct value', async () => {
let req = mockRequest();
req.params.id = null;
const res = mockResponse();
await controller.todoController(req, res);
expect(res.status).toHaveBeenCalledWith(404);
expect(res.json).toHaveBeenCalledWith({ message: 'Not Found' });
});
});
This is only 1 approach to testing Express handlers and middleware. The alternative is to fire up the Express server.

Categories