- Notifications
You must be signed in to change notification settings - Fork0
Brbb/fancy
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
A simple MERN implementation of a login flow.
A.env
file is required in the/backend
folder
DB_URL=mongodb://<user>:<password>@<server>:<port>/fancydbAPI_PORT=3001TOKEN_SECRET=<anysecret>TEST_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImZyYW5jZXNjb0BlbWFpbC5jb20iLCJqdGkiOiI4YmU2ZjJhMzg2NDk2YWRkOTRhNTgyZjk0OWY4MjEzOCIsImlhdCI6MTU0NTM3ODI0NSwiZXhwIjoxNTQ1NDIxNDQ1fQ.oq18-oCfloQNzL-9acnRb_m1HB4W4pKu3nRGUCZEvI0LISTENING_TO_UNHANDLED_REJECTION=false
Install backend modules:
cd backend && npm init
Install frontend modules:
cd frontend && npm init
To quickly setup and run the app with frontend and backend concurrenlty, from the project root directory execute:
npm start
will execute the command specified in the start script inpackage.json
concurrently \"cd backend && npm start\" \"cd frontend && npm start\"
From the/backend
folder with an instance or nodemon:
npm start
From the/frontend
folder:
npm start
Thesingle units using unit tests. These units have been isolated using mocks to exclude database calls and split the behavior in the smallest micro-behaviors possible. Matching unit test files are in the same folder of the tested module/class/unit.
After the test it's possible to check the coverage in/backend/coverage/lcov-report/index.html
Note: some parts have been ignored because the test is either insignificant or trivial (eg.server.js
requiresapp.js
andmongoose
, but I trust the require module to do its job).Other parts like theRoutes
or thelocalStorage
have been partially tested either because it's implicit in theexpect
or because we trust the language (for examplelocalStorage.setItem
shouldn't fail).
Some "big bang style" integration tests for the main functionalities without trying all the possible combinations of the composing segments.Some "functional test" all the way to the database for the backend and some "integration/functional test" from the button click to the mock of theaxios
call.
This because the amount of time required is well beyond my availability.
These tests have the file name matching*.int.test.js
or are stored in the__test__
folder.
Black-box tests are shown with supertest on the backend and snapshots on the frontend.
Random actions to cover the main functionalities manually.
ESLint is configured to check syntax in a pretest. In order to have the code fixed, run from the/backend
folder:
npm run pretest -- --fix
and if everything goes well:
npm test
This will run the unit tests (file.test.js
near each file) and the integration tests in the__test__
folder.
From the/frontend
folder execute npm test. Thereact-script test
command is configured to work with Jest and Enzyme.
Backend and frontend have been separated in subfolders to allow a future possible division in multiple repositories.
Express API server with MongoDB as storage.
The flow of an API call is:
API → Router → Handler → Controller → Model
The handler collects the request and prepares the parameters for the controller in order to make this concerned only about logic and Model. This also helps with testability and modularity.
It could be possible to move the code in the route files, but this becomes slightly unreadable and requires exports of all the methods used to allow testing. Each request is wrapped in a handle to catchUnhandledRejection
and prevent Express to crash.
Form the/routes/auth.js
file:
consthandler=require("./handlers/auth.handler");constexpress=require("express");constrouter=express.Router();consthandle=require("../helpers/promiseHelper").handle;router.post("/login",handle(handler.login));
then in the/routes/handlers/auth.handler.js
:
module.exports{login:async(req,res)=>{if(!req.body)returnres.status(400).send({err:"Request needs body"});const{ email, password}=req.body;if(!email||!password)returnres.status(400).send({err:"Body needs email and password properties"});letresult=awaitctrl.login(email,password);if(result.err)returnres.status(400).send(result);returnres.send(result);}}
and the/controllers/auth.js
:
login:async(email,password)=>{varuser=awaitauth.verifyUserPassword(email,password);if(user){lettoken=auth.getToken(user.email);return{token:token,userId:user._id};}return{err:"Wrong username/password combination"};},
The structure includes thesrc
folder and the following subfolders:
- components → The components divided by concern + UI Elements
- routes
- services → API clients for auth, language and users
- other config and application files
At startup,src/index.js
will render<App />
, which contains the Routes and matching paths to the components.