This page provides insights into how to set up the project in your development environment
including what dependencies need to be installed, the steps to build and run the application,
and even some setup of additional tools that will assist you during development.

- **Author**: Alex Wilkes <[adw4236@rit.edu](mailto:adw4236@rit.edu)>

# Initial setup
Required programs:
- [Node.JS](https://nodejs.org/en/download/)
- [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)

Initial setup steps
1. Clone the repo
2. run `npm install` from the top-level directory
    - This runs npm install on the sub-directories `client` and `server` 
3. At this point if you are unfamilliar with the project, you should familiarize yourself with
   the [project structure](https://github.com/FiTRSkills/ForkInTheCode/wiki/Project-Structure)

## Client Setup

The client side can be ran independently of the server side so long as you specify
a valid API server.

The client side application requires some environment variables to run, you can set up
these in any way you wish, however the easiest is through the use of a `.env` file.
A `.env` file (literally a text file just called `.env`) can be created in the `/client`
folder containing the following variables. The format of the file is `KEY=VALUE` on each
line. The following example can be used as a template for the file.

```
# The URL to the API server, this can be one running locally, or elsewhere
REACT_APP_SERVER_URL=http://localhost:9000
```

## Server Setup

In a development environment, the server will only run the API server rather than serving
up the client side frontend.  This allows you to specify different ports for the two servers
and run them both on your machine without needing to worry about setting up subdomains.

In a production environment, specifically when the environment variable `NODE_ENV` is set to
`production`, the app will run with subdomains enabled.  See the section below about optional
host file configuration if you wish to test the app in production mode.

The server side application requires some environment variables to run, you can set up
these in any way you wish, however the easiest is through the use of a `.env` file.
A `.env` file (literally a text file just called `.env`) can be created in the `/server`
folder containing the following variables. The format of the file is `KEY=VALUE` on each
line. The following example can be used as a template for the file.

```
# The connection string pointing to a running database. This can be locally hosted or elsewhere
DB_CONN=mongodb://localhost:27017/data
# The username to the database
DB_USER=admin
# The password to the database
DB_PW=password
# The port the server will run on, defaults to 9000
# PORT=9000
# The domain to allow CORS through, this should match the domain used to access the app, you can
# safely ignore this if you aren't setting up a production environment since it defaults to localhost
# DOMAIN=fitr.com
```

#### Optional host file configuration
If you wish to emulate the production server on your own machine (see
[Running the Application](#Running-the-Application)) you will need to also add a domain
in your systems host file.  Find the file listed below and append the following lines to
the end of the file.

- Windows: `C:\Windows\System32\drivers\etc\hosts`
- Unix: `/etc/hosts`

```
127.0.0.1 fitrskillsdev.com
127.0.0.1 api.fitrskillsdev.com
```

After doing this, ensure you update the frontend API url environment variable to point to
`http://api.fitrskillsdev.com/`

# Running the Application
The application can be either be ran as two independent pieces (ideal for development) or
built and ran as one unified server with subdomains (ideal for production).

## Client Standalone
The client side is simply a default create-react-app project which comes with several
developer friendly tools.

To run the client side server, cd into the `/client` folder and run `npm start` which
is an alias for `react-scripts start`.

Once the application is running, it will automatically reload when the code has been changed.

## Server Standalone
The server is an express http server and running it will start the API server.

to run the server, cd into the `/server` folder and run `npm start`.

## Production Client & Server
In order to emulate the production environment, the client and server must be built and then
ran.  The following command should be ran at the top-level, they will invoke the proper
commands in the client and server projects.  If you wish to see what exactly happens here,
reference the top-level `package.json` file.

Before proceeding, ensure you have configured your host file according to the directions in
setting up the server.

1. `npm install` if you have yet to do so.
2. `npm run build` after any code changes.
3. `npm run start`
    - Note: This command will automatically set the NODE_ENV variable.

Alternatively you can just run `npm run rebuildAndStart`.

# Additional Environment Setup
There are some additional tools that should be setup in your development environment for
various reasons although they don't explicitly impact the code running.

## Prettier
Prettier is a tool that will re-write your code in one standard format.  This makes it
easy to ensure that all developers are following the same style guidelines.  Prettier is
installed as a top-level dependency, however it can alternatively be installed globally
using `npm install -g prettier` to have easy access to the command line tools.

All pull requests should run Prettier on all files changed in that request.  Because of
this, it is a good idea to configure your IDE to automatically run prettier when you save
a file. Some instructions on how to set up your IDE to do this can be found below:

- [JetBrains (WebStorm/IntelliJ)](https://plugins.jetbrains.com/plugin/10456-prettier)

## Local Database
If you are doing heavy database activity during development, you should setup a local
database instead of using one on the cloud.

1. Download and install [MongoDB Community](https://www.mongodb.com/try/download/community)
2. The database should automatically run as a service, but if you configured it differently,
   run the database now.
3. Run the mongo shell
    1. Open a command prompt
    2. cd to `<MongoDB install directory>/Server/<version>/bin`
    3. run the command `mongo` (Note, if you are not using the default port, you will have
       to specify which one, see the documentation linked below)
4. Run: `use data` (You can replace data here with anything, just make sure to update it in
   your DB_CONN environment variable as well).
5. Run: `db.createUser({user: "admin", pwd: "password", roles: []})` (Again, you can change
   the username and password, just make sure the environment variables reflect it).
6. Set the environment variables for the server side project
    - DB_CONN (Likely: `mongodb://localhost:27017/data`)
    - DB_USER
    - DB_PW
7. You should now be able to run the server connected to your local database.
8. Optionally you can populate some dummy data into this database with the populate.js script.
   Just run the command `npm run populate` and the same database that is configured by the
   server will be populated with some basic data.

For more information on MongoDB shell commands, see the
[MongoDB documentation](https://docs.mongodb.com/manual/mongo/)

You can also use [MongoDB Compass](https://www.mongodb.com/try/download/compass) as
a graphical interface for exploring the database.

## Using a Backend Debug Console
There are plenty of techniques to testing the application during development including
[Postman](https://www.postman.com/downloads/) to hit an API endpoint, or just going through
the UI to make the requests.

Another way to test the backend during development is by using the chrome dev tools.
If you are familiar with the devtools, you know you can type in javascript directly into
the console and execute it.  Node.JS allows you to use this same functionality
for the backend.

1. Start the server with `node --inspect src/bin/www` instead of the normal `npm start`.
2. In chrome, navigate to the url `chrome://inspect/#devices`
3. The server should show up in the "Remote Target" section, click on `inspect` to open the session.
4. Navigate to the `Sources` tab and click on the plus button under file system.  Navigate
   to your saved project and open up the `server` folder.

This session allows you to execute code exactly like it would be if it was ran from a
source file.  The following are some commands that can be used to interact with the server.

```
// Lets you import a document (or any module for that matter) and use it as you would in code
const Document = require("./src/models/<file>");

// An example of how you would create a new document (database entry) in code and save it.
let document = new Document();
// await is very important on any asynchronous methods (most of them)
await document.save();

// Get a document already in the database
let document = await Document.findById("<id>");

// Edit values of that document
document.key = "newValue";
await document.save();
```

The documents are based on the [mongoose API](https://mongoosejs.com/docs/documents.html) which
you should be familiar with if you are working on the backend although as mentioned, this
is not just restricted to model tier testing.

You can also use this to debug the code by navigating to the sources tab and opening files
there.

# Running tests
There are four total types of automated tests that exist in our application.

- Model Tier Unit Tests
- API Integration Tests
- Frontend UI Tests
- End-To-End Tests

See [UI Testing](https://github.com/FiTRSkills/ForkInTheCode/wiki/UI-Testing)
and [Server Testing](https://github.com/FiTRSkills/ForkInTheCode/wiki/Server-Testing)
for information on the philosophies of writing tests.

## Cypress Tests
The frontend and end-to-end tests can both be ran using [Cypress](https://www.cypress.io/)
which is a javascript framework for testing web applications with javascript.

**NOTE**: The end-to-end tests were in early stages at the end of our project and are mostly
just a proof of concept, more will have to be implemented.

### Cypress Config
the `cypress.json` is the file that contains all configurations needed to run cypress tests.
This file must be committed to the repository to provide cypress configurations for CI, but
can otherwise be changed to support your local testing environment.  If you do make changes
to this file, ensure you don't accidentally commit them.

Cypress cannot pull its environment variables from the `.env` file, so they must be placed in
this configuration.  All environment variables to run the frontend and backend must be present.
The end-to-end tests will make use of the database environment variables to access and pre-populate
the database with data needed for tests.

### Running Cypress
The command `npm run test` can be executed in the `/client` folder to launch cypress.  Note that
for Cypress to open, `npm install` must be ran in this directory specifically, the top level will
only install the cypress library and not the executable binaries for the application.
  
## Jest Tests
The integration and unit tests are both implemented using Jest on the backend.

### Jest Config
The `jest.config.js` file contains all necessary configurations as well as descriptive comments
for what each one does.  This file should be used to configure coverage reports and some other
features.

The `jest-mongodb-config.js` file contains configurations for the in memory mongoDB that is ran
during the jest tests.

### Running Jest
From the `/server` folder, you can run the command `npm run test` to run all tests.

Alternatively you can specify individual files to be ran through the commands `npx jext <file>`.

The coverage results will automatically be generated and both be shown as output to the command
executed as well as html files in the `/server/coverage` directory for a more detailed view.

# Generating Documentation
Currently, we have a system in place to automatically generate API documentation, although it
has not been used much.

## API Documentation
The command `npm run doc` can be used and uses [JsDoc](https://jsdoc.app/) to generate
documentation.  This can be extended to also generate documentation for other tiers if
needed.