How do you test NodeJS to see if a middleware was used? - javascript

Forgive me if this is something you shouldn't do, but I've looked around to see what is possible.
I want to verify that my express app has a middleware called/used for the app.
import express from 'express';
import cors from 'cors';
const app = express();
app.use(cors()); // <----- I WANT TO TEST THIS
app.get('/', (_req, res) => res.send({ hello: 'world' });
app.listen(5000, () => console.log(`Listening on port 5000`));
export default app;
Potential jest test
import app from './index.ts';
// This is a poor attempt to try and get this to work
test('test if CORS is implemented', () => {
const mockCors = jest.mock('cors');
const myApp = app;
expect(mockCors).toHaveBeenCalledTimes(1);
});
If anyone has the solution and if I should not be doing this, what is the reason behind it?

My guess is that you don't actually care that cors is called. Your client won't say to you "I want the cors middleware to be called". All the client should care about is the service that is provided, not how it's implemented. Your tests should do the same. If you decide one day to use another module for CORS, your tests shouldn't need to change, why would they?
My (personal) preferred approach is exactly that. Testing that given some input, my programs gives me the output I desire. Everything inside the program can be changed, as long as the behavior does not change. That will give you peace of mind when refactoring.
Also, for testing an Express app, you don't need a server, you just need the app. Actually starting the server can add complexity to your tests, since they might be hanging if you forget to close the server after them.
So in this example, the very first thing I would do is move everything you have in index.ts into a file called app.ts, and remove this line:
app.listen(5000, () => console.log(`Listening on port 5000`));
And in index.ts, only have this:
import app from './app.ts';
// Start the server
app.listen(5000, () => console.log(`Listening on port 5000`));
Then, I would use Supertest along with Jest, to make requests to that app:
npm i -D supertest
And then, in your test file, test what matters to the client:
import request from 'supertest';
import app from './app.js'; // Just import the app, not the server
describe("myApp", () => {
it('should implement CORS', async() => {
const { headers } = await request(app).get('/');
expect(headers['access-control-allow-origin']).toEqual('*');
});
});

Related

Why Doesn't the Fetch API Call My API Endpoint I Created in Express?

I am wondering why the Fetch API in javascript isn't call the endpoint I created in express. When I start my server and go to the '/characters' endpoint, it returns correctly formatted JSON.
Here is my express index.js
const app = express();
const PORT = 3000;
const charactersRoute = require('./routes/characters');
//Characters Route
app.use('/characters', charactersRoute)
app.listen(PORT, function(err) {
if(err) console.log(err);
console.log(`Server is listening on port ${PORT}`)
})
Here is my Characters Route
const express = require('express'); // Web Framework
const https = require('https');
const router = express.Router();
const PORT = 3000;
// app.listen(PORT, function(err) {
// if(err) console.log(err);
// console.log(`Server is listening on port ${PORT}`)
// })
const api = 'https://www.breakingbadapi.com/api/characters/?limit=20';
router.get("/", function(req, res) {
https.get(api, (response) => {
console.log(response.statusCode);
response.on('data', (d) => {
const data = JSON.parse(d);
res.send(data);
})
// res.send("Running")
})
})
module.exports = router;
Here is my Characters.jsx file where I'm using Fetch
import React, {useEffect, useState} from 'react';
import Card from '#mui/material/Card';
import axios from 'axios';
export default function Character() {
const [data, setData] = useState();
useEffect(() => {
fetch('/characters')
.then(res => res.json())
.then(data => setData(data))
// console.log(data);
}, []);
}
When I run my front end and check the response I receive, it returns my index.html.
If I fetch the API URL itself, then it correctly returns the JSON in my frontend. But When I try to fetch the API endpoint I created in express, I don't get any data. Any suggestions?
You did not set the endpoint for the fetch function. It doesn't know what API '/characters' is. It is similar to saying the house number but not telling the street, you don't know where to go. So you need to pass the absolute path to fetch to request data from the server, because the server is a different 'entity', it's not the same with your front-end. Therefore, you need to provide the full API URL. Or, if using axios, since I see you imported it above, you must set axios.defaults.baseURL = <API_URL>, (or provide the full URL in the request itself just like in fetch) and then make the request with the help of axios, not fetch.
Therefore your React code will look a little something like this:
import React, {useEffect, useState} from 'react';
import Card from '#mui/material/Card';
import axios from 'axios';
axios.defaults.baseURL = 'http://localhost:3000';
export default function Character() {
const [data, setData] = useState();
useEffect(() => {
const getData = async () => {
try {
const {data} = await axios.get('/characters');
setData(data);
} catch (err) {
console.error(err);
}
};
getData();
}, []);
}
But I suggest you create a different file with all the axios requests and there you set the baseUrl - that's a better practice.
I think is that you are not using cors in your app.
const cors = require('cors');
const app = express();
app.use(cors());
app.use(express.json());
Try this, I hope it helps you!
Error pattern
This kind of error occurs when we send a request from the client-side to the server-side using a relative URL (/characters in this case). But the frontend app and the backend app run on 2 different ports.
Reason
When we use relative URLs, the URL will be concatenated with the current host (the frontend host, not the backend). Usually, we receive a 404 error because the resource doesn't exist.
Example
Backend Express app running on port 5000. React app running on port 3000 for development. In React app, if we send a request to /users, then the full URL is http://localhost:3000/users. The request goes to the React app, not the backend server. And we don't receive the desired output.
Action
You should use an absolute URL, something like: http://localhost:5000/users to send the request to your backend app. Consider saving the host part (http://localhost:5000) in a global variable in order to use it in multiple places in your frontend code. When you have different environments for the backend (DEV/STAGING/PRODUCTION), you can change the backend host in only 1 place.

Using module.exports= router but still getting Router.use() requires a middleware function but got a Object

I looked all over the internet and all I could find was:
"Make sure you add module.exports = router" at the end of your router file.
My router file is as follows:
let router = express.Router();
const staticOptions = {
root: path.join(__dirname, "./../../assets")
};
// a bunch of router.get() functions
module.exports = router;
// auth/google
I then go ahead and import it into my server.ts file as follows:
import * as googleAuthRouter from "./api/AccountLinking/googleAuth";
...
app.use("/auth/google", googleAuthRouter);
but I'm still getting the following error:
TypeError: Router.use() requires a middleware function but got a Object
I only have one route im importing into the server.js file. I barely just started this project. Everywhere I look online says: "you just need to do module.exports = router and it'll fix it." In this case it doesn't. What am i doing wrong?
Typescript is driving me crazy and seriously hindering my development efforts. I'm fairly close to giving up and going back to plain JS
Change import to require:
const googleAuthRouter = require('./api/AccountLinking/googleAuth');
app.use("/auth/google", googleAuthRouter);

How to create a basic client to use GraphQL subscriptions via websockets

I'm trying to create a basic chat-like app just for the sake of learning a few things.
I have set up a basic graphql server to handle connecting a user, and let them add a message. Now I'm trying to add some mechanism so that every user can see each others' messages added in real time. I'm new to GraphQL but it would seem subscriptions are what I should use.
Here's my server index.ts:
import { createServer } from 'http';
import jwt from 'jsonwebtoken';
import mongoose from 'mongoose';
import resolvers from 'modules/resolvers';
import typeDefs from 'modules/type-defs';
import { ApolloServer } from 'apollo-server-express';
import cookieParser from 'cookie-parser';
import express from 'express';
import cors from 'cors';
const PORT = 4000;
const getUser = (token: string) => {
// ...
};
const server = new ApolloServer({
context: ({ req, res }) => {
const token = req.cookies.jwt;
const currentUser = getUser(token);
return { currentUser, req, res };
},
resolvers,
subscriptions: {
onConnect: async (connectionParams, webSocket, context) => {
console.log(`Subscription client connected using Apollo server's built-in SubscriptionServer.`)
},
onDisconnect: async (webSocket, context) => {
console.log(`Subscription client disconnected.`)
},
},
typeDefs,
});
const app = express();
const httpServer = createServer(app);
app.use(cors({ credentials: true, origin: 'http://localhost:3000' }));
app.use(cookieParser());
server.applyMiddleware({ app, cors: false });
server.installSubscriptionHandlers(httpServer);
httpServer.listen(PORT, () => {
console.log(`Server ready at http://localhost:${PORT}${server.graphqlPath}`);
console.log(`Subscriptions ready at ws://localhost:${PORT}${server.subscriptionsPath}`);
});
mongoose.connect('mongodb://127.0.0.1:27017/irc', {
useCreateIndex: true,
useNewUrlParser: true,
useUnifiedTopology: true,
});
What I'm trying to do is set up something as simple as possible on the client side (javascript/react) without having to rely on a lib like apollo-client.
I managed to use simple fetch calls to send queries/mutations and was expecting to be able to use subscriptions in a "simple" way too. Apollo-client seems over complicated for what I'm trying to do and I'd like to understand how it actually works - but every tutorial on subscriptions seem to use this lib...
I don't really understand what my server is actually doing regarding subscriptions, and I thought I'd configured it to listen to websockets connections but I'm not so sure anymore.
I tried sending a basic message just to see what would happen:
const ws = new WebSocket('ws://localhost:4000/graphql');$
ws.onopen = event => {
ws.send('Lorem ipsum dolor sit amet.');
};
... but even though my chrome's network tab seems to indicate that everything went fine, my server does not seem to care about my message since nothing gets logged.
Could someone please explain if it's possible to use basic web sockets to use apollo-server's subscriptions? And how?
Thanks
Apollo Server and Apollo Client both use subscriptions-transport-ws under the hood to handle subscriptions. subscriptions-transport-ws uses WebSocket as a transport for exchanging messages between the server and the client. These messages have a specific format used by the library -- in order to use only WebSocket on the client-side, you'd have to send the same sort of messages.
You could inspect the source code to determine what sort of messages are being sent and when. The better option, though, would be to create an instance of SubscriptionClient and utilize its methods. Since usage of the library isn't particularly well documented, you'd have to stumble your way through but it should be possible.
If you're new to GraphQL, though, you should stick with Apollo Client since it's documentation is fairly good (see here) and subscriptions can be pretty complicated to set up, especially once you add authentication.

Understanding various parameters passed in export default

I was going through an article on web when I stumbled upon the following code snippet.
I this author have used babel to use ES6 syntax in node and have configured our app in two parts
App.js
Server.js
Inside our Server.js he have done something like this
import express from 'express';
import cors from 'cors';
const app = express();
function setPort(port = 5000) {
app.set('port', parseInt(port, 10));
}
function listen() {
const port = app.get('port') || 5000;
app.listen(port, () => {
console.log(`The server is running and listening at http://localhost:${port}`);
});
}
app.use(cors({
origin: '*', // Be sure to switch to your production domain
optionsSuccessStatus: 200
}));
// Endpoint to check if the API is running
app.get('/api/status', (req, res) => {
res.send({ status: 'ok' });
});
export default {
getApp: () => app,
setPort,
listen
};
Here this statement doesn't make sense to me
export default {
getApp: () => app,
setPort,
listen
};
And then in app.js, He have done this
import server from './server';
server.listen();
export default server;
Question: Can someone please explain me in stretch what is happening here? Like why is our getApp: () => app written like this and why setPort and listen written normally?
Ps: I know what does export default mean
The author is exporting an object with three properties as the default export.
Property 1: getApp -
This property has a value which is a function that returns the app variable from the server.js file, which is just the express instance. In other words, it is a method which returns the express app.
Property 2: setPort -
This property has a value equal to the setPort function defined in the server.js file
Property 3: listen -
This property has a value equal to the listen function defined in the server.js file
So when the author calls server.listen() in the app.js file, he/she is just calling the listen function which he/she has imported from the server.js file. Not exactly sure why they've chosen to set the app this way...
Well, put simply it's an inline function definition utilising ES6 arrow functions syntax which returns the internal app instance.
It's no different to:
getApp: function() {
return app;
}
The reason it's declared inline is because you don't actually have a function definition anywhere else in the module. If you added the function beforehand then it could be exported the same way as listen / setPort

React server side rendering renders incorrect content

I'm working on a react web app using React, Redux, and React Router, with server side rendering (using express)
The problem I'm facing is a bit hard to explain. I will try to explain it in the following steps.
You first enter the app from a URL like http://www.example.com/articles/1234. The express server will send down the correct content which includes the correct page source and the DOM(from chrome Element panel) as the initial load.
Then let's navigate to a different page like http://www.example.com/articles/5678 (navigating is not causing page refresh since it's a single page app, it only reaches out to the server for SSR content when you do a refresh with your browser or entering a page from a URL in browser address bar) everything works fine so far.
Refresh the page in the browser (You're now on page http://www.example.com/articles/5678) with cmd + r or F5. Again, the server will send down the content. But this time the content that you're receiving is a bit different. The page content in the browser is correct as well as DOM from chrome Elements panel. However, the page source is not correct, it's still the old page source that you got from step 1.
I have tried to log out the content when refreshing the page. The content that the server sent down in step 3 is not the correct content (It's the previous page) but somehow the browser can still see the right content.
And if I refresh the page once more after step 3 then I will get both the correct content and correct page source...
I'm also using Facebook open graph debugger. The debugger is telling me that it follows a redirect to step 3. And the redirect URL it followed is the previous page URL. I know this not quite right, but not sure where I'm doing it wrong...
Here are my express server settings
Thanks for the help!
server.js
require('babel-register');
const express = require('express');
const React = require('react');
const ReactDOMServer = require('react-dom/server');
const ReactRouter = require('react-router');
const ReactRedux = require('react-redux');
const Store = require('./src/store/configureStore').default;
const routes = require('./src/routes').default;
const compression = require('compression');
const morgan = require('morgan');
const store = Store();
const match = ReactRouter.match;
const RouterContext = ReactRouter.RouterContext;
const Provider = ReactRedux.Provider;
const port = process.env.PORT || 5050;
const ReactHelmet = require('react-helmet');
const Helmet = ReactHelmet.Helmet;
const app = express();
app.use('/dist', express.static('./dist'));
app.set('view engine', 'ejs');
app.use(compression());
app.use(morgan('combined'));
app.use((req, res) => {
// prettier-ignore
match(
{ routes, location: req.url },
(error, redirectLocation, renderProps) => {
if (error) {
res.status(500).send(error.message);
} else if (redirectLocation) {
res.redirect(302, redirectLocation.pathname + redirectLocation.search);
} else if (renderProps) {
console.log(renderProps);
const body = ReactDOMServer.renderToString(
React.createElement(
Provider,
{ store },
React.createElement(RouterContext, renderProps)
)
);
const meta = Helmet.renderStatic().meta.toString();
res.status(200).render('index', {body, meta});
} else {
res.status(404).send('Not found');
}
}
);
});
console.log('listening on port ' + port); // eslint-disable-line
app.listen(port);
I have eventually resolved the issue.
The main problem was that I placed my async data fetching calls in the componentWillMount lifecycle method instead of componentDidMount.
And I didn't properly handle async data fetching in my App.
I'm now using the approach mentioned in this article to deal with my async data fetching issue.
Basically, I'm doing the following:
On the client side: Create a static method fetchData in components.
On the server side: Use React Router to grab the right component and use the fetchData method to fetch the data needed for that component.
After these promises have been resolved, get the current state from Redux store and render the HTML and send it down to the client.
Inject the state to the client side Redux store and render the page.

Categories