This template aims to accelerate the start of a react project using Create React App, it already provides basic quality settings and project standardizations.
- React declarative component-centric UI
- React router dom for manager routing
- Testing library for testing web pages by querying and interacting with DOM nodes
- Jest for matchers and mocks in unit tests
-
Setting environment variables
Create
.env
file with all settings the application will need to run.
There is a.env.example
file in the root of project's directory which you can use as a model for that. -
Install dependencies
Get all dependencies installed by running
$ npm install # or $ yarn
-
Setting up the project
$ yarn prepare-husky
-
Start developing
$ yarn start
Project should be running at http://localhost:3000
-
Start production mode
$ yarn build $ global add serve $ serve -s build
Project should be running at http://localhost:3000
-
Setting environment variables
Create
.env
file with all settings the application will need to run.
There is a.env.example
file in the root of project's directory which you can use as a model for that. -
Start developing and building
$ docker-compose -f docker-compose.dev.yml up -d --build
Project should be running at http://localhost:3000
-
Start production mode (locally)
$ docker-compose up -d --build
Project should be running at http://localhost:3001
-
This project was created using Create React App.
-
Naming standards
# branch feat/description # commit feat: description
To standardize our commits we use Conventional Commits a specification for adding human and machine readable meaning to commit messages.
-
Linter
# find problems $ yarn lint # find and fix problems automatically $ yarn lint:fix
-
Unit tests
# run all unit tests $ yarn test # run all the tests and watch for changes in related files $ yarn test:watch # run tests only on changed files $ yarn test:staged # run all unit tests generates the coverage report in the coverage folder # in the project root $ yarn test:coverage # run all unit tests generates the coverage report in the coverage folder # in the project root and watch changes in related files $ yarn test:watch:coverage
-
Hooks
This project has these hooks:
pre-commit
: perform static code analysis with eslintcommit-msg
: validates the commit message according to the convention adopted by the projectpre-push
: perform unit testing of project components and integration tests
-
For best practices to structure files please read this document
-
To learn a little more about how we write the types of our entities, see the documentation for our type package
-
To create a component or utility, it must first be determined its type, in order to select a directory in which to create the corresponding files:
- It would be created within the app in case they are app's own features
- It would be created inside commons in case of multi-domain general-purpose utilities.
- It would be created inside components in case the component is used in multiple domains.
- It would be created within domains if it centralizes the logical and visual representation according to the domain
- Each domain would have thair own route file that specifies the route where it belongs
- In case of a necessity of creating a subdomain directory, a new directory would be created called pages and it would group all pages of a domain.
- It would be created inside the subdirectories of domains/components in case the component will only be used in the views of a specific domain.
- If a page needs to use a component, this component would be created inside domains/MyDomain/components as well.
- If a page needs to be divided to decrease its complexity, this division would be created in domains/MyDomain/pages/MyPage/widgets directory.
- It would be created within the domains/hooks subdirectories if the hook was only used within a specific domain
- It would be created inside hooks in case the hook is used in multiple domains.
├─ 📁 app ├─ 📁 commons ├─ 📁 components └─ 📁 domains └─ 📁 Auth ├─ 📁 components ├─ 📁 pages | └─ 📁 Login | └─ 📁 widgets └─ 📁 hooks
-
The directory should have the same name as the component. The component file should have the name of the component in Pascal Case format and the extension
.tsx
.├─ 📁 Login │ └─ 📄 Login.tsx
-
Every directory should contain a 📄 index.ts which serves as an entry point for the module, component, utils and/or hooks.
├─ 📁 Login │ ├─ 📄 index.ts │ └─ 📄 Login.tsx
-
Every component, utils and/or hooks should come with a test. The test must have the same name as the file being tested and the extension must be
.spec.tsx
├─ 📁 Login │ ├─ 📄 index.ts │ ├─ 📄 Login.tsx │ └─ 📄 login.spec.tsx
-
The types for the component will be written in
.ts
file using the same component name in camel case format and thetypes
prefix.├─ 📁 Login │ ├─ 📄 index.ts │ ├─ 📄 Login.tsx │ ├─ 📄 login.spec.tsx │ ├─ 📄 login.styled.scss │ └─ 📄 login.types.ts
-
The Definitions for the component as
constants
will be written to a.ts
file using the same component name in camel case format and the prefixdefinitions
.├─ 📁 Login │ ├─ 📄 index.ts │ ├─ 📄 Login.tsx │ ├─ 📄 login.definitions.ts │ ├─ 📄 login.spec.tsx │ ├─ 📄 login.styled.scss │ └─ 📄 login.types.ts
-
If a subcomponents contains subcomponents (widgets), they should have their own module subdirectory inside the same components directory.
├─ 📁 Login │ ├─ 📁 widgets │ │ ├─ 📁 Form │ │ │ ├─ 📄 index.ts │ │ │ ├─ 📄 form.styled.scss │ │ │ ├─ 📄 Form.tsx │ │ │ └─ 📄 form.spec.tsx | | |─ 📁 FormsSubcomponent │ │ │ ├─ 📄 index.ts │ │ │ ├─ 📄 FormsSubcomponent.styled.scss │ │ │ ├─ 📄 FormsSubcomponent.tsx │ │ │ └─ 📄 FormsSubcomponent.spec.tsx │ │ └─ 📄 index.ts │ ├─ 📄 index.ts │ ├─ 📄 login.styled.scss │ ├─ 📄 Login.tsx │ └─ 📄 login.spec.tsx
- In the case of hooks, their names should start by the prefix use and use Camel Case format and have the extension
.ts
or.tsx
. They should be contained in a directory with the same name, along with an index file and its corresponding test.spec.ts
or.spec.tx
.
├─ 📁 Login │ ├─ 📁 hooks │ │ ├─ 📁 useCount │ │ │ ├─ 📄 index.ts │ │ │ ├─ 📄 useCount.ts │ │ │ └─ 📄 useCount.spec.ts │ │ └─ 📄 index.ts │ ├─ 📄 index.ts │ ├─ 📄 login.styled.scss │ ├─ 📄 Login.tsx │ └─ 📄 login.spec.tsx
- In the case of hooks, their names should start by the prefix use and use Camel Case format and have the extension
-
The component should have the same name as the file using Pascal Case format. It should be declared in a Arrow Function, always typying the expected answer and making the default export at the end of the file.
// Login.tsx import React from 'react'; const Login: React.FC = () => <div>...</div>; export default Login;
-
If the component has props, they will be imported from the corresponding
.definitions.ts
file adding initial prefix corresponding to their type. Example interfaceILogin
, typeTLogin
, enumELogin
.// Login.tsx import React from 'react'; import { ILogin } from './login.types'; const Login: React.FC<ILogin> = ({ title, description }: ILogin) => ( <div> <h1>{title}</h1> <p>{description}</p> </div> ); export default Login;
-
The index file will be responsible for exporting everything needed form the module. Especially, the component's default.
// index.ts export { default } from './Login';
-
For testing best practices, please read this document.
-
To create a test is necessary to import from the testing library both the render and the screen.
import { render, screen } from '@testing-library/react';
-
The component to be tested should also be imported.
import { render, screen } from '@testing-library/react'; import Login from './Login';
-
The heading of the tests must be written following the order Given-When-Then Documentation
- Given represents a precondition
- When an action
- Then a result or consequence of the action (user acceptance criteria).
- And a result or consequence of other consequence (user acceptance criteria).
- But a result which should not be possibly observable
import { render, screen } from "@testing-library/react"; import ComponentExample from "./ComponentExample"; describe("GIVEN a ComponentExample", () => { describe("WHEN rendered", () => { it("THEN should display the correct text", () => { ... }); }); });
-
In this first instance, we will verify the right rendering of the component by checking the text in each of the elements.
import { render, screen } from '@testing-library/react'; import Login from './Login'; describe('GIVEN a Login', () => { describe('WHEN rendered', () => { it('THEN should display the correct text', () => { render(<Login title="title" description="description" />); expect(screen.getByText(/title/i)).toBeInTheDocument(); expect(screen.getByText(/description/i)).toBeInTheDocument(); }); }); });