Skip to content

Commit

Permalink
updates and transfer to another computer
Browse files Browse the repository at this point in the history
  • Loading branch information
perennialAutodidact committed Nov 9, 2024
1 parent 4c6b355 commit 5196e06
Show file tree
Hide file tree
Showing 182 changed files with 5,700 additions and 17,733 deletions.
121 changes: 101 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,19 @@ This project uses Nx to manage a monorepo containing a backend server created wi
- Install and/or switch to Node 18.17.1.
- Run `git clone https://github.com/perennialAutodidact/memory-snap.git`
- Run `cd memory-snap`
- Run `yarn install` in the root directory, Nx will take care of installing dependencies for each package in the `packages` directory. If Yarn is not installed globally for Node 18.17.1, then install it using `npm install -g yarn`.
- Run `yarn install` in the root directory, TurboRepo will take care of installing dependencies for each package in the `apps` directory. If Yarn is not installed globally for Node 18.17.1, then install it using `npm install -g yarn`.
- Create a [Pexels](https://pexels.com) account and find the API key for the account
- Create the file `packages/backend/.env.local` and add the Pexel's API key to it: `PEXELS_API_KEY=<API_KEY>` where `<API_KEY>` is the API key string
- Create the file `packages/frontend/.env.local` and add: `REACT_APP_API_URL=http://localhost:8080`
- Create the file `.env.local` in the root directory and add: `API_PORT=http://localhost:8080` and `CLIENT_PORT=http://localhost:3000`
- Create the file `apps/backend/.env.local` and add to it:

```
PEXELS_API_KEY=<API_KEY> # <API_KEY>` is the Pexel's API key string
PORT = 8080
```
- Create the file `apps/frontend/.env.local` and add:
```
REACT_APP_API_URL=http://localhost:8080
```

- Run `yarn start` to start the local dev server

## Styling
Expand All @@ -23,33 +31,52 @@ be loaded **before** Bootstrap is imported into the project in
`src/styles/index.scss`.

## Testing
Tests are written in Jest with React Testing Library. There is a helper
function named `setupTests` in `src/helpers/tests` which will render
components
wrapped in the necessary context providers. This function should be
used
instead of React Test Library's `render` function for rendering components
within tests.
Tests are written in Jest with React Testing Library.

### Commands
`yarn test` - Start the test suite in watch mode

`yarn ci` - Run the test suite once.

### Testing helpers
There is a helper function named `setupTests` in `src/utils/tests` which will
render components wrapped in the necessary context providers. This function
should be used instead of React Test Library's `render` function for rendering
components within tests.

The `setupTests` function accepts the following arguments:
<details>
<summary>
Expand arguments
</summary>

`Component`: **React.ReactNode** - The component to be rendered in the test
`options`: **object** - values used to render the Component in a particular state
- `props`: **object** - props for the Component
- `state`: **object** - the current state of the application (currently this is the value that will be provided to `GameContext`)
- `route`: **string** - url of route to be rendered (e.g. "/users/10")
- `props`: **object** - props for the Component

- `state`: **object** - the current state of the application (currently this is the value that will be provided to `GameContext`)

- `route`: **string** - url of route to be rendered (e.g. "/users/10")

Ideally, tests should be written for every single component and every single
user action **before** writing the code to fix the test. Mock as little as
possible to maximize test confidence.
</details>


### Linting
#### Command
`yarn lint` - Run linting and style linting

Run `yarn test` to start the test suite in watch mode.
The custom dependency `apps/eslint-config` manages the ESLint configs for both
`apps/frontend` and `apps/backend`.

## ImmerJS

Since React utilizes top-down, immutable state, it's best practice
to always return a new state object from the reducer to avoid stale state
within the app and to ensure that components update when state values change.
Using traditional spread operator syntax is effective, but gets very messy when
Since React utilizes top-down, immutable state, it's best practice to always
return a new state object from the reducer to avoid stale state within the app
and to ensure that components update when state values change. Using
traditional spread operator syntax is effective, but gets very messy when
updating deeply nested state values, because each layer of the state object
needs to be duplicated as the deeply nested value is accessed.

Expand All @@ -58,7 +85,9 @@ to allow immutable state updates to be written in a mutable syntax. The
`produce` function from Immer creates a `draft` of a given object, applies
mutable change to it and then returns a new object with the desired changes.

For example:
<details>
<summary>Example</summary>

```javascript
// traditional reducer syntax, using spread syntax
const reducer = (state, action) => {
Expand Down Expand Up @@ -107,6 +136,55 @@ value is required from the `produce` function*.

See the [ImmerJs Docs](https://immerjs.github.io/immer/produce/) for more
information about the `produce` function.
</details>
## Recurring development errors and their solutions

### Error
`Please include a state object` while running tests on a component.

<details>
<summary>Example</summary>

```sh
● ScoreBoard component › renders active player

please include a state object

3 | export const photosReducer = (state, action) => {
4 | if (!state) {
> 5 | throw new Error('please include a state object');
| ^
6 | } else if (!action || (action && !action.type)) {
7 | throw new Error('please include an action object with "type" property');
8 | }

at photosReducer (src/contexts/PhotosContext/reducer/photosReducer.js:5:11)
at updateReducer (../../node_modules/react-dom/cjs/react-dom.development.js:15845:22)
at Object.useReducer (../../node_modules/react-dom/cjs/react-dom.development.js:17079:16)
at useReducer (../../node_modules/react/cjs/react.development.js:1626:21)
at useFetchedPhotos (src/hooks/useFetchedPhotos/useFetchedPhotos.jsx:8:39)
at PhotosProvider (src/components/Providers/PhotosProvider/PhotosProvider.jsx:18:53)
at renderWithHooks (../../node_modules/react-dom/cjs/react-dom.development.js:15486:18)
at updateFunctionComponent (../../node_modules/react-dom/cjs/react-dom.development.js:19617:20)
at beginWork (../../node_modules/react-dom/cjs/react-dom.development.js:21640:16)
at beginWork$1 (../../node_modules/react-dom/cjs/react-dom.development.js:27465:14)
at performUnitOfWork (../../node_modules/react-dom/cjs/react-dom.development.js:26599:12)
at workLoopSync (../../node_modules/react-dom/cjs/react-dom.development.js:26505:5)
at renderRootSync (../../node_modules/react-dom/cjs/react-dom.development.js:26473:7)
at recoverFromConcurrentError (../../node_modules/react-dom/cjs/react-dom.development.js:25889:20)
at performConcurrentWorkOnRoot (../../node_modules/react-dom/cjs/react-dom.development.js:25789:22)
at flushActQueue (../../node_modules/react/cjs/react.development.js:2667:24)
at act (../../node_modules/react/cjs/react.development.js:2582:11)
at ../../node_modules/@testing-library/react/dist/act-compat.js:47:25
at renderRoot (../../node_modules/@testing-library/react/dist/pure.js:180:26)
at render (../../node_modules/@testing-library/react/dist/pure.js:271:10)
at setupTests (src/utils/tests.jsx:22:9)
at Object.<anonymous> (src/components/Game/ScoreBoard/ScoreBoard.test.jsx:21:19)
```
</details>
### Solution
Include
## Contributing
Expand All @@ -120,6 +198,8 @@ branches that will be linked to the issue for which they're created. Branches
created in this way will follow the aforementioned branch name formatting. See
the images below.
<details>
<summary>Expand</summary>
![image](design/readmeImages/contributing_create_branch.png)
![image](design/readmeImages/contributing_create_branch_2.png)
Expand All @@ -128,3 +208,4 @@ All new branches should be created using the `dev` branch as a base. Click
![image](design/readmeImages/contributing_create_branch_3.png)
![image](design/readmeImages/contributing_create_branch_4.png)
</details>
8 changes: 8 additions & 0 deletions apps/backend/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
root: true,
extends: ['@memory-snap/eslint-config/backend'],
parser: '@babel/eslint-parser',
parserOptions: {
project: true,
},
};
37 changes: 0 additions & 37 deletions apps/backend/.eslintrc.json

This file was deleted.

1 change: 0 additions & 1 deletion apps/backend/__mocks__/handlers.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { rest } from 'msw';
import { mockPhotos } from './mockPhotos';

export const handlers = [
rest.get('/photos', (req, res, ctx) => {
Expand Down
2 changes: 1 addition & 1 deletion apps/backend/app.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('app', () => {
.then((response) => {
expect(response.body).toEqual({ photos: mockPhotos });
})
.catch((error) => console.log({ error }));
.catch((error) => console.error({ error }));
});

it('returns error on fail', async () => {
Expand Down
4 changes: 2 additions & 2 deletions apps/backend/controllers/express/photosController.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { createClient } from 'pexels';

const getPhotos = async (req, res) => {
try {
const { query, perPage: per_page } = req.query;
const { imageSearchQuery, perPage: per_page } = req.query;
const pexelsClient = createClient(process.env.PEXELS_API_KEY);
const response = await pexelsClient.photos.search({
query,
query: imageSearchQuery,
per_page,
orientation: 'square',
});
Expand Down
6 changes: 2 additions & 4 deletions apps/backend/jest.config.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
const config = async () => ({
module.exports = {
setupFilesAfterEnv: ['<rootDir>/__test__/jest.setup.js'],
transformIgnorePatterns: ['/node_modules/', '/node_modules/(?!pexels)'],
verbose: true,
moduleDirectories: ['node_modules', '.'],
transform: {
'\\.jsx?$': 'babel-jest',
},
});

export default config;
};
4 changes: 2 additions & 2 deletions apps/backend/jsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
"module": "ESNext",
"target": "es6",
"baseUrl": "./",
// "types": ["node"]
"types": ["node"],
"paths": {
"controllers": ["./controllers"],
"controllers": ["./controllers"]
}
},
"exclude": ["node_modules"]
Expand Down
3 changes: 1 addition & 2 deletions apps/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
},
"scripts": {
"ci": "cross-env ci=true yarn test",
"lint": "npx eslint",
"lint": "npx eslint . --fix",
"serve": "cross-env NODE_ENV=production node app.js",
"start": "cross-env NODE_ENV=development nodemon app.js",
"test": "cross-env NODE_ENV=test yarn jest"
Expand All @@ -33,7 +33,6 @@
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-unused-imports": "^3.0.0",
"jest": "^29.6.4",
"msw": "^1.2.5",
"nodemon": "^3.0.1",
"prettier": "^3.0.3",
"prettier-eslint-cli": "^7.1.0",
Expand Down
Loading

0 comments on commit 5196e06

Please sign in to comment.