This is a full-stack React template that uses Node/Express on the backend, and React/Redux/React Router on the front-end. It is still a work in progress, but is designed to make creating these apps quicker in the future.
- Clone and run
$ yarn
from project root - Set Appropriate environment variables in
server/.env
file (see.env.example
) - Run MongoDB on your local system see instructions here
- Run
$ yarn start:dev
from project root. This will run both the client and server in development mode.
Building the apps consists of transpiling the server and client code, and then
moving/copying files into a /dist
folder in the project root. This folder is
made so that it can be directly deployed to a hosting provider like Heroku, AWS,
Bluemix, etc. /client
and /server
each have their own package.json
with a
build command. The project root has a package.json
with a build command that
calls these two scripts, and then packages the files into the /dist
folder.
Run using $ yarn build
from project root.
- Repository: Full Stack React Boilerplate
- Main Developers: Austin
- Main Tools: React/Redux/React-Router
- Bootstrapped with: create-react-app
- Build: Webpack
- Styles:
├── config: configuration files (jest, webpack, etc)
│ └── jest
├── public: `static files`
│ ├── img
│ ├── js
│ └── vendor
├── scripts: `create-react-app generated scripts for builds/tests`
└── src: React code
├── actions: `redux action creators (async ones use redux-thunk)`
├── components
│ ├── layout: `Reused page-layout components (navbar, footer, etc)`
│ │ └── Header
│ ├── pages: `Top-level components rendered for React Router routes`
│ │ ├── About
│ │ └── Home
│ ├── TodoApp
│ ├── TodoFooter
│ └── TodoItem
├── reducers: `redux reducers`
└── scss: `Global scss files`
- Server: Node/Express
- Database: MongoDB @ mlab
- Bootstrapped with: Express Generator
- Build: Webpack
├── bin: `binary files (run app with this)`
├── controllers: `route controllers, all route-handling logic goes here`
├── models: `mongoose database models`
├── routers: `api route definitions`
├── middleware: `custom middleware for routes`
├── views: `view files for production app`
├── loaders: `custom webpack loaders`
├── app.js: `main express app, on '/' route`
├── api.js: `separate express app for your api, proxied to /api route of main app`
├── webpack.config.js: `server webpack build config`
{
name: {
type: String,
required: true
},
description: String,
completed: {
type: Boolean,
default: false,
required: true
}
}
{% api "getAllTodos", method="GET", url="/api/todos/" %}
Returns an array with all todos in the db
[
{
_id: 'fdjsfdsa098123890a`,
name: "Eat Vegetables",
completed: 'False'
},
{
_id: 'fdjsfdsa0981238902`,
name: "Buy Groceries",
completed: 'False'
}
]
{% endapi %}
{% api "addTodo", method="POST", url="/api/todos/" %}
Name | Type | Desc |
---|---|---|
name | String | Name of todo |
completed | Boolean | Is todo completed? (default: False) |
Returns db object with name, completed, and _id
{
_id: 'fdjsfdsa098123890a`,
name: "Eat Vegetables",
completed: 'False'
}
{% endapi %}
{% api "getTodo", method="GET", url="/api/todos/:id" %}
Name | Type | Desc |
---|---|---|
id | String | Object ID of todo |
Returns todo object corresponding to the id
{
_id: 'fdjsfdsa098123890a`,
name: "Eat Vegetables",
completed: 'False'
}
{% endapi %}
{% api "updateTodo", method="PUT", url="/api/comparisons/:id" %}
Update a todo in the db
Name | Type | Desc |
---|---|---|
id | String | Object ID of todo |
Name | Type | Desc |
---|---|---|
name | String | (optional) Name of todo |
completed | Boolean | (optional) Is todo completed? |
{
_id: 'fdjsfdsa098123890a`,
name: "Updated Todo",
completed: 'True'
}
{% endapi %}
{% api "deleteTodo", method="DELETE", url="/api/todos/:id" %}
Delete a Todo by id
Name | Type | Desc |
---|---|---|
id | String | Object ID of todo |
{
success: true,
deleted: {...}
}
{% endapi %}
{% api "toggleAll", method="POST", url="/api/todos/toggleAll" %}
Toggle all todoscompleted attribute to either
trueor
false`.
Name | Type | Desc |
---|---|---|
toggleTo | Boolean | Toggle to this |
{
success: true,
updated: {...}
}
{% endapi %}
{% api "clearCompleted", method="POST", url="/api/todos/clearCompleted" %}
Delete all completed todos
{
success: true,
deleted: {...}
}
{% endapi %}
We test our apps using Jest. Jest is great
for both front-end and back-end tests. To run the front-end/back-end tests,
change into /client
or server
respectively, and run $ yarn test
.
For unit testing the React App, we use Jest with Enzyme. Enzyme provides great utilities for testing React Components.
- Test File Location:
/client/src/folder/[moduleName].test.js
- Component tests go in the same folder as the component!
Integration tests are used to test different parts of the application working in unison. When making back-end integration tests, we are looking to make sure the proper controllers, mongoose models, etc get called when we make a request to a certain route.
Test File Location: /server/__tests__/name.integration.test.js
I have personally found that unit-testing many parts of the back-end is extremely cumbersome. You end up writing so many mocks/stubs for functions that work trivially. There are times where it makes sense to unit test the back-end (certainly for any pure functions, mongoose schema validation, etc), but it is often a lot easier and more beneficial to write integration tests.
If you are going to unit-test the back-end, here are some of my recommendations:
Controllers:
- When testing controllers, you will want to use a library to mock the mongoose
models being called. Libraries that do this are
jest-mongoose-mock
andmockgoose
.
Models:
- Testing model validation schemes is fairly easy, you can just create a new instance of the model & call instance.validate, and then check for errors.
- Testing instance methods is a little bit more involved. You will likely have to stub/mock parts of the Model. See this article for more details
Routes/Route Middleware:
- Libraries like supertest make it pretty easy to test your APIs. You will need to stub/mock your controllers to unit test these components.