# frontend-collaborator

This repository for the Collaborators application in Workstation.

## Setup

Install the version of Node.js specified in [.nvmrc](.nvmrc). A good way to do this is using [nvm](https://github.com/nvm-sh/nvm), which lets you install different versions simulatenously and switch between them.

Copy the template [`.env.shadow`](.env.shadow) to `.env` and edit it to set the `GRASS_TOKEN` variable to a token you have obtained.

Install the dependencies:

```sh
yarn
```

## Development

Start the dev server:

```sh
yarn start
```

Then open [`http://localhost:8080`](http://localhost:8080) in your browser.

Run the tests:

```sh
yarn test
```

To see all available tasks:

```sh
yarn run
```

## Generating types

To generate or update TypeScript definitions for GraphQL variables and responses based on the latest queries and schema fetched from the server:

```sh
yarn generate:types
```

## Component directory structure

Components should usually kept in their own file, except in cases where it makes sense to define a simple wrapper component alongside a main component.

Page components and components only used in a single page should be placed in a directory under `src/pages/`. Components used in multiple pages should be placed in a directory under `src/components/`.

For example given a PersonPage component, a PersonInfo component only used in PersonPage, and a ConfirmModal component used in several pages this structure should be used:

```
└── src
    ├── components
    │   └── confirm-modal
    │       ├── __tests__
    │       │   └── confirm-modal.spec.ts
    │       ├── confirm-modal.scss
    │       └── confirm-modal.tsx
    └── pages
        └── person-page
            ├── __tests__
            │   ├── person-info.spec.ts
            │   └── person-page.spec.ts
            ├── person-info.scss
            ├── person-info.tsx
            ├── person-page.scss
            └── person-page.tsx
```

## Testing

Tests should follow the [Testing Library guiding principals](https://testing-library.com/docs/guiding-principles):

> The more your tests resemble the way your software is used, the more confidence they can give you.

In practice for us that means tests should usually simulate user journeys through the app. They should trigger behaviour as a user would, by firing events, and make assertions based on the DOM. They should use components hooked up to Redux and Apollo contexts so that end-to-end functionality can be tested, rather than implementation details such as `dispatch` calls.

This also means that where functionality is implemented by composing a number of different components together we should prioritise testing those components together, rather than in isolation, especially if those components are only used in a single place.

There are currently a lot of tests for older components that do not use this approach, but all new tests should follow it, and older ones should be rewritten when an appropriate opportunity arises.

### Examples

```js
/*
 * ❌ Bad
 */

const props = { dispatch: jest.fn() };

// Using unconnected component makes it difficult to test rerendering caused by Redux store changes
const component = renderComponent({ Component: MyComponent, props });

// Only waits for a single tick of the event loop - is brittle and doesn't reflect real behaviour
await waitFor(() => {});

// Doesn't communicate intent of test and can result in false positives which are a pain to update in the future
expect(component).toMatchSnapshot();

fireEvent.click(component.getByText('Click me'));

// Tests implementation detail which doesn't reflect user experience
expect(props.dispatch).toHaveBeenCalledWith(myAction());

/*
 * ✅ Good
 */

renderComponent({ Component: ConnectedMyComponent });

await waitForElementToBeRemoved(screen.getByText('Loading'));

expect(screen.getByText('Something loaded asynchronously')).toBeInTheDocument();

fireEvent.click(screen.getByText('Click me'));

expect(screen.getByText('Something that shows after button is clicked')).toBeInTheDocument();
```

### Resources

- [Testing Library docs](https://testing-library.com/docs/)
- [Apollo testing docs](https://www.apollographql.com/docs/react/development-testing/testing/)
- [Kent C. Dodds testing blog posts](https://kentcdodds.com/blog/?q=testing)
