Contributing Guidelines

Table of Contents

Project Structure

Contributing

Requirements

  • docker>=17.0.0

  • docker-compose>=1.17.0

  • node>=10.0.0

Set-up dev environment

#. If not yet done, clone project locally

#. If not yet done, install node dependencies

#. Start application

You can now access application in dev mode at http://localhost

Start developing

  1. Create a new branch

Requirements

  • New branch MUST be started from development (which is our dev branch)

  • Feature branch MUST be named feature/[a-zA-Z0-9\-]+

  • Bug fix branch MUST be named fix/[a-zA-Z0-9\-]+

  • Branch referring to an open issue MUST be named (fix|feature)/<issue-ID>

  1. Develop on new branch being careful to write test for every change you proceed to

  2. Push branch

Pushing will trigger a CI pipeline (see section CI/CD)

  1. Create a pull request

Install new dependencies

Command above can sometime error with EACCES code, this means that docker wrote some files (usually cache) in your local node_modules folder. To solve it you can change right access of the folder by running command

Release a new version

  1. Create a release branch release/x.x.x

  2. Bump to version x.x.x

    • package.json: change version to x.x.x

    • CHANGELOG.md: ensure release section x.x.x documentation is exhaustive and set release date

  3. Commit with message bump version to x.x.x

  1. Tag version

  1. Bump to version increment(x.x.x)-dev

    • package.json: change version to increment(x.x.x)-dev

    • CHANGLOG.md: create empty increment(x.x.x)-dev section with unreleased status

  2. Push branch and tags

  1. Proceed to merge request release/x.x.x -> master

Tests

Commands

Run test

Display more DOM lines when a test fails

Run coverage

Practices

Test framework

We use Jestarrow-up-right test framework (directly packed into create-react-apparrow-up-right

We use React testing libraryarrow-up-right to test components

Requirements

  • Tests MUST be written in a **/__tests__ folder located in the same directory as the element tested

  • Tests file for <filename>.js MUST be named <filename>.test.js

Folder structure

Testing guidelines

Here are some useful reading to help you write tests:

  • https://kentcdodds.com/blog/how-to-know-what-to-test

  • https://kentcdodds.com/blog/common-mistakes-with-react-testing-library

  • Anything displayed here: https://kentcdodds.com/testing/

Test example

Code linting

Framework

We use ESLint (packed in create-react-apparrow-up-right)

This project use a combination of husky, lint-staged, prettier to format code automatically including .js,.jsx, .json and .css (c.f create-react-app documentationarrow-up-right.

Some pre-commit hooks are set-up so whenever you make a commit, prettier will format the changed files automatically.

Requirements

  • Code MUST respect linting rules defined in .eslintrc

Commit Linting

Framework

We use commitlintarrow-up-right

The Conventional Commits specificationarrow-up-right is a lightweight convention on top of commit messages. It provides an easy set of rules for creating an explicit commit history; which makes it easier to write automated tools on top of. This convention dovetails with SemVer, by describing the features, fixes, and breaking changes made in commit messages.

The commit message should be structured as follows:

Types of commit:

  • feat: Add a new feature to the codebase (MINOR in semantic versioning).

  • fix: Fix a bug (equivalent to a PATCH in Semantic Versioning).

  • docs: Documentation changes.

  • style: Code style change (semicolon, indentation...).

  • refactor: Refactor code without changing public API.

  • perf: Update code performances.

  • test: Add test to an existing feature.

  • ci: Update continuous integration processes

  • chore: Update something without impacting the user (ex: bump a dependency in package.json).

Requirements

  1. Commits MUST be prefixed with a type, which consists of a noun, feat, fix, etc., followed by the OPTIONAL scope, OPTIONAL !, and REQUIRED terminal colon and space.

  2. The type feat MUST be used when a commit adds a new feature to your application or library.

  3. The type fix MUST be used when a commit represents a bug fix for your application.

  4. A scope MAY be provided after a type. A scope MUST consist of a noun describing a section of the codebase surrounded by parenthesis, e.g., fix(parser):

  5. A description MUST immediately follow the colon and space after the type/scope prefix. The description is a short summary of the code changes, e.g., fix: array parsing issue when multiple spaces were contained in string.

  6. A longer commit body MAY be provided after the short description, providing additional contextual information about the code changes. The body MUST begin one blank line after the description.

  7. A commit body is free-form and MAY consist of any number of newline separated paragraphs.

  8. One or more footers MAY be provided one blank line after the body. Each footer MUST consist of a word token, followed by either a :<space> or <space># separator, followed by a string value (this is inspired by the git trailer conventionarrow-up-right).

  9. A footer’s token MUST use - in place of whitespace characters, e.g., Acked-by (this helps differentiate the footer section from a multi-paragraph body). An exception is made for BREAKING CHANGE, which MAY also be used as a token.

  10. A footer’s value MAY contain spaces and newlines, and parsing MUST terminate when the next valid footer token/separator pair is observed.

  11. Breaking changes MUST be indicated in the type/scope prefix of a commit, or as an entry in the footer.

  12. If included as a footer, a breaking change MUST consist of the uppercase text BREAKING CHANGE, followed by a colon, space, and description, e.g., BREAKING CHANGE: environment variables now take precedence over config files.

  13. If included in the type/scope prefix, breaking changes MUST be indicated by a ! immediately before the :. If ! is used, BREAKING CHANGE: MAY be omitted from the footer section, and the commit description SHALL be used to describe the breaking change.

  14. Types other than feat and fix MAY be used in your commit messages, e.g., docs: updated ref docs.

  15. The units of information that make up Conventional Commits MUST NOT be treated as case sensitive by implementors, with the exception of BREAKING CHANGE which MUST be uppercase.

  16. BREAKING-CHANGE MUST be synonymous with BREAKING CHANGE, when used as a token in a footer

Files organization & file naming convention

We make active usage of redux, if not familiar with redux we recommend going through redux documentationarrow-up-right before going through this section.

Requirements

  • Actions MUST go into a into src/redux/actions

  • Reducers MUST go into a into src/redux/reducers

  • Enhancers MUST go into a into src/redux/enhancers

Folder structure

Reducers

We highly recommend you reading more about structuring reducerarrow-up-right

Requirements

  • State structure (or state shape) MUST be defined in terms of domain data & app status, it MUST NOT be defined after your UI component tree

  • Root reducer (feeded to createStore()) MUST combine together specialized reducers:

    • data reducers, handling the data application needs to show, use, or modify (typically information retrieved from some APIs)

    • status reducers, handling information related to application's behavior (such as "there is a request in progress")

    • ui reducer, handling how the UI is currently displayed (such as "Sidebar is open")

  • Global state shape MUST reflect src/redux/reducers/ folder structure. Keys in global state MUST be the same as file names src/redux/reducers/

  • Specialized reducer files MUST implement a reducer function exported as default

Folder structure

Corresponding state shape would be

Example

Actions

Actions are payloads of information that send data from your application to your store. They are the only source of information for the store. You send them to the store using store.dispatch().

Requirements

  • Actions MUST be grouped by piece of state they cover (e.g. UI actions are defined into src/redux/actions/ui.js)

  • Each action type MUST be declared as a constant

  • Each action SHOULD come with an action creator function

  • Action types & creator functions MUST be implemented in the same file

  • Actions MUST be serializable (if you think in passing a function into an action for handling by reducers, it means that you actually need a redux middleware)

  • Actions MUST follow Flux-Standard-Actionarrow-up-right(https://github.com/redux-utilities/flux-standard-action#actions) format

    • MUST be a plain JavaScript object

    • MUST have a type property

    • MAY have an error property

    • MAY have an payload property

    • MAY have an meta property

    • MUST NOT include property other than type, error, payload and meta

  • There SHOULD NOT be a 1-to-1 link between actions and reducers. Typically an action could be reduced by multiple reducers

Folder structure

Example

Enhancers and middlewares

Store enhancers are higher-order function that composes a store creator to return a new, enhanced store creator. In our case, we mainly use enhancer to add redux middlewares allowing to hook custom behaviors when dispatching actions.

We highly recommend you reading more about middlewares in reduxarrow-up-right

Requirements

  • Middlewares MUST go into src/redux/enhancers/middlewares

Folder structure

Components go into src/components

Requirements

  • All components MUST go into src/components

  • Components MUST have a unique name

Module specific components go into src/components/

Requirements

  • Component files MUST go into a into a folder named after the component in src/components/

  • Component code MUST be split into as many atomic sub components as necessary

  • Component MUST follow naming pattern path-based-component-naming, which consists in naming the component accordingly to its relative path from src/components/

Examples of those components are

  • Skeleton elements such as AppBar, Sidebar

  • View panels such as Home

  • Layout elements such as Layout

Folder structure and file naming

Component naming

Main component

Sub component

Generic atomic reusable components go into src/components/UI

Requirements

  • Generic UI components MUST NOT held business logic specific to the application (they actually could be stored on some external npm library)

  • MUST follow naming pattern path-based-component-naming, which consists in naming the component accordingly to its relative path from src/components/UI

Examples of those components are: Button, Input, Checkbox, Select, Modal, etc…

Folder structure and file naming

Containers go into src/containers

Requirements

  • Container MUST go into src/containers

  • Container MUST follow same relative path from src/containers as the component it wraps from src/components

  • Container MUST have same name as the component it wraps

Folder structure

Custom hooks go into src/hooks

Requirements

  • Custom hook MUST go into src/hooks

  • Custom hook's name MUST start with use (for example: useTimer)

Folder structure

Component & Container separation pattern

We respect a separation between presentational components & containers.

Motivation for the pattern

  • Better separation of concerns makes app understandable and better UI writing components this way.

  • Better reusability. Same presentational component can be used with completely different state sources, and turn those into separate container components that can be further reused.

  • Presentational components are essentially app’s “palette”. It is possible to put them on a single page and let designers tweak all their variations without touching the app’s logic. It is possible to run screenshot regression tests on that page.

  • This forces to extract “layout components” such as Sidebar, AppBar, etc. and use this.props.children instead of duplicating the same markup and layout in several container components.

You can read more about it herearrow-up-right

Components (or presentational components) are concerned with how things look

Requirements

  • SHOULD implement some DOM markup and styles of their own

  • MAY contain both presentational components and containers

  • SHOULD allow containment via this.props.children.

  • SHOULD NOT have their own state (when they do, it MUST be UI state and MUST NOT be data)

  • SHOULD be written as functional components unless they need state, lifecycle hooks, or performance optimizations

  • MUST receive data and callbacks exclusively via props.

  • MUST NOT have dependencies with the rest of the app, such as redux actions or stores

  • MUST NOT specify how the data is loaded or mutated (API calls MUST NOT be defined in a component)

  • MUST NOT define any route

Implement a component

Set imports

Requirements

  • MAY import components from UI libraries typically Material-UI

  • MAY import components and containers from the rest of the application

  • SHOULD NOT import any resources related to Redux, except compose() that is sometime convenient to connect multiple material-ui wrappers (withStyles(), withTheme()...)

  • SHOULD NOT have any dependencies in the rest of the application, except components or containers

  • MUST be organized in 3 ordered sections: 1. low-level React imports / 2. Material-UI imports / 3. intra-application imports

Example

Define styles

Requirements

  • MUST be a function taking theme as argument and returning an object

Example

Code component

Requirements

  • SHOULD be a function taking a props object as an argument (except lifecycle, UI state or some optimization are required)

  • MUST respect component naming convention (see below)

  • MUST be agnostic of the rest of the application, this MUST include every variable namings. Think it as it should be able to exist on its own

  • MUST be documented with PropTypes

Example

Connect styles and export

Requirements

  • MAY inject styles information using withStyle(), makeStyle(), _withTheme(), withWidth()

  • There MUST be one unique export

Example

Basic: only withStyle()

Advanced: using compose() from redux

Containers are concerned with how things work

Requirements

  • MAY contain both presentational components and containers

  • SHOULD NOT define DOM markup of their own (except for some wrapping divs)

  • MUST NOT have styles

  • MAY provide the data and behavior to presentational or other container components.

  • MAY organise components/containers using routes

  • MAY implement redux related elements mapStateToProp(), mapDispatchToProps(), mergeProps() and connect it to presentational component using connect()

  • MAY implement API calls or other side effects

  • MAY be stateful, as they tend to serve as data sources

Implement a container

Set imports

Requirements

  • MAY import elements from state management libraries elements (redux, react-redux)

  • MAY import elements from src/redux such as actions or selectors

  • MAY import elements from routing library

  • MAY import Material-UI utilities such as isWidthUp()

Example

Code container

Requirements

  • SHOULD NOT define DOM markup of their own (except for some wrapping divs)

  • MAY define route

  • MAY implement hooks on React lifecycle

  • MUST respect

Example

Lifecycle container

Routing container

Implement mapStateToProps(state, [ownProps]), mapDispatchToProps(dispatch, [ownProps]), mergeProps(stateProps, dispatchProps, ownProps)

Requirements

  • MAY implement mapStateToProps(state, [ownProps])

  • MAY implement mapDispatchToProps(dispatch, [ownProps]). If it is only required to map action creators it MUST be an object

  • MAY implement mergeProps(stateProps, dispatchProps, ownProps)

  • Aggregating props MUST NOT be performed within container, ownProps and mergeProps() allow to accomplish it properly out of the component (c.f. https://github.com/reduxjs/react-redux/blob/master/docs/api.md)

Example

Connect container & export

Requirements

  • MAY connect redux information to a comp

  • MUST be one unique export

Example

Others

Error handling: Refer to to this articlearrow-up-right for handling async errors using our built ErrorFallback.js file.

Material-UI

Theme

Material UI themearrow-up-right is declared in ./src/themes/theme.js

CSS classes

To apply styling on specific components and not in the full app, use Material-UI overridesarrow-up-right

UI width

To make UI fully responsive, you can use Material-UI breakpointsarrow-up-right

Audit application

Conventions

RFC keywords

  1. MUST This word, or the terms "REQUIRED" or "SHALL", mean that the definition is an absolute requirement of the specification.

  2. MUST NOT This phrase, or the phrase "SHALL NOT", mean that the definition is an absolute prohibition of the specification.

  3. SHOULD This word, or the adjective "RECOMMENDED", mean that there may exist valid reasons in particular circumstances to ignore a particular item, but the full implications must be understood and carefully weighed before choosing a different course.

  4. SHOULD NOT This phrase, or the phrase "NOT RECOMMENDED" mean that there may exist valid reasons in particular circumstances when the particular behavior is acceptable or even useful, but the full implications should be understood and the case carefully weighed before implementing any behaviour described with this label.

  5. MAY This word, or the adjective "OPTIONAL", mean that an item is truly optional. One vendor may choose to include the item because a particular marketplace requires it or because the vendor feels that it enhances the product while another vendor may omit the same item. An implementation which does not include a particular option MUST be prepared to interoperate with another implementation which does include the option, though perhaps with reduced functionality. In the same vein an implementation which does include a particular option MUST be prepared to interoperate with another implementation which does not include the option (except, of course, for the feature the option provides.)

Last updated

Was this helpful?