Skip to content

Latest commit

 

History

History
399 lines (269 loc) · 17.6 KB

CONTRIBUTING.md

File metadata and controls

399 lines (269 loc) · 17.6 KB

Contributing

We, the maintainers, love pull requests from everyone, but often find we must say "no" despite how reasonable the proposal may seem.

For this reason, we ask that you open an issue to discuss proposed changes prior to submitting a pull request for the implementation. This helps us to provide direction as to implementation details, which branch to base your changes on, and so on.

Sensu is and always will be open source, and we continue to highly value community contribution.

Table of Contents

Expand

Getting Started

Process

  1. Open an issue to describe your proposed improvement or feature.
  2. Fork https://github.com/sensu/web
  3. Clone the fork.
  4. Ensure your system is ready for development; see prereqs below.
  5. Create your feature branch (git checkout -b my-new-feature)
  6. Commit your changes with a DCO Signed-off-by statement (git commit --signoff)
  7. Push your feature branch (git push origin my-new-feature)
  8. Create a Pull Request as appropriate based on the issue discussion

Prerequisites

  1. Git
  2. Node: install version 8.0 or greater; brew install node on macOS
  3. Yarn: brew install yarn on macOS
  4. A fork of the repo (for any contributions)

Installation

  1. git clone https://github.com/sensu/web.git
  2. cd web
  3. yarn install dependencies

Running Locally

  1. Ensure that you have a local instance of the backend running.
  2. yarn build && yarn start to start the development server.
  3. A browser window should open with the web application. If not, open http://localhost:3000 in your browser of choice.

Testing Changes

  1. If possible, test any visual changes in all latest versions of common browsers, on both desktop and mobile.
  2. Run yarn quality.

Editors

This project implements prettier and eslint to keep code consistent and functional. There are a number of plugins available for your favourite editor of choice that can automatically fix your code and point out problems.

Atom

VIM

VSCode

Contribution welcome.

Available Browser Extensions

React Developer Tools

Adds React debugging tools to the Chrome Developer Tools.

Available on the Chrome Extension Gallery.

Relay DevTools

Allow you to inspect data in the store of your Relay apps, and how that data changes over time in response to GraphQL queries, and client mutations.

Available on the Chrome Extension Gallery.

Redux DevTools

The extension provides power-ups for your Redux development workflow.

Available on the Chrome Extension Gallery.

Available Scripts

In the project directory, you can run:

yarn start

Runs the app in the development mode.
Open http://localhost:3000 to view it in the browser.

The page will reload if you make edits.
You will also see any lint errors in the console.

yarn test

Launches the test runner in the interactive watch mode.
See the section about tests for more information.

yarn run build

Builds the app for production to the build folder.
It correctly bundles React in production mode and optimizes the build for the best performance.

The build is minified and the filenames include the hashes.
Your app is ready to be deployed!

See the section about deployment for more information.

DCO

To make a good faith effort to ensure the criteria of the MIT License are met, Sensu Inc. requires the Developer Certificate of Origin (DCO) process to be followed.

The DCO is an attestation attached to every contribution made by every developer. In the commit message of the contribution, the developer simply adds a Signed-off-by statement and thereby agrees to the DCO, which you can find below or at http://developercertificate.org/.

Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
    have the right to submit it under the open source license
    indicated in the file; or

(b) The contribution is based upon previous work that, to the best
    of my knowledge, is covered under an appropriate open source
    license and I have the right under that license to submit that
    work with modifications, whether created in whole or in part
    by me, under the same open source license (unless I am
    permitted to submit under a different license), as
    indicated in the file; or

(c) The contribution was provided directly to me by some other
    person who certified (a), (b) or (c) and I have not modified
    it.

(d) I understand and agree that this project and the contribution
    are public and that a record of the contribution (including all
    personal information I submit with it, including my sign-off) is
    maintained indefinitely and may be redistributed consistent with
    this project or the open source license(s) involved.

The following is an example DCO Signed-off-by statement.

 Author: Sean Porter <sean@sensu.io>

 Committer: Greg Poirier <greg@sensu.io>

   Let's name it WizardFormat.

   Calling it the Sensu Metric Format was a mistake.

   Signed-off-by: Sean Porter <sean@sensu.io>
   Signed-off-by: Grep Poirier <greg@sensu.io>

Git makes this easy with git commit --signoff!

The DCO text can either be manually added to your commit body, or you can add either -s or --signoff to your usual git commit commands. If you forget to add the sign-off you can also amend a previous commit with the sign-off by running git commit --amend -s. If you've pushed your changes to Github already you'll need to force push your branch after this with git push -f.

Tests

Notarize uses Jest as its test runner. Jest is a Node-based runner. This means that the tests always run in a Node environment and not in a real browser. This lets us enable fast iteration speed and prevent flakiness.

While Jest provides browser globals such as window thanks to jsdom, they are only approximations of the real browser behavior. Jest is intended to be used for unit tests of your logic and your components rather than the DOM quirks.

Filename Conventions

Jest will look for test files with any of the following popular naming conventions:

  • Files with .js suffix in __tests__ folders.
  • Files with .test.js suffix.
  • Files with .spec.js suffix.

The .test.js / .spec.js files (or the __tests__ folders) can be located at any depth under the src top level folder.

We recommend to put the test files (or __tests__ folders) next to the code they are testing so that relative imports appear shorter. For example, if App.test.js and App.js are in the same folder, the test just needs to import App from './App' instead of a long relative path. Colocation also helps find tests more quickly in larger projects.

Command Line Interface

When you run yarn test, Jest will launch in the watch mode. Every time you save a file, it will re-run the tests, just like yarn start recompiles the code.

The watcher includes an interactive command-line interface with the ability to run all tests, or focus on a search pattern. It is designed this way so that you can keep it open and enjoy fast re-runs. You can learn the commands from the “Watch Usage” note that the watcher prints after every run:

Jest watch mode

Writing Tests

To create tests, add it() (or test()) blocks with the name of the test and its code. You may optionally wrap them in describe() blocks for logical grouping but this is neither required nor recommended.

Jest provides a built-in expect() global function for making assertions. A basic test could look like this:

import sum from "./sum";

it("sums numbers", () => {
  expect(sum(1, 2)).toEqual(3);
  expect(sum(2, 2)).toEqual(4);
});

All expect() matchers supported by Jest are extensively documented here.
You can also use jest.fn() and expect(fn).toBeCalled() to create “spies” or mock functions.

Testing Components

There is a broad spectrum of component testing techniques. They range from a “smoke test” verifying that a component renders without throwing, to shallow rendering and testing some of the output, to full rendering and testing component lifecycle and state changes.

Different projects choose different testing tradeoffs based on how often components change, and how much logic they contain. If you haven’t decided on a testing strategy yet, we recommend that you start with creating simple smoke tests for your components:

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";

it("renders without crashing", () => {
  const div = document.createElement("div");
  ReactDOM.render(<App />, div);
});

This test mounts a component and makes sure that it didn’t throw during rendering. Tests like this provide a lot value with very little effort so they are great as a starting point, and this is the test you will find in src/App.test.js.

When you encounter bugs caused by changing components, you will gain a deeper insight into which parts of them are worth testing in your application. This might be a good time to introduce more specific tests asserting specific expected output or behavior.

If you’d like to test components in isolation from the child components they render, we recommend using shallow() rendering API from Enzyme.

You can write a smoke test with it too:

import React from "react";
import { shallow } from "enzyme";
import App from "./App";

it("renders without crashing", () => {
  shallow(<App />);
});

Unlike the previous smoke test using ReactDOM.render(), this test only renders <App> and doesn’t go deeper. For example, even if <App> itself renders a <Button> that throws, this test will pass. Shallow rendering is great for isolated unit tests, but you may still want to create some full rendering tests to ensure the components integrate correctly. Enzyme supports full rendering with mount(), and you can also use it for testing state changes and component lifecycle.

You can read the Enzyme documentation for more testing techniques. Enzyme documentation uses Chai and Sinon for assertions but you don’t have to use them because Jest provides built-in expect() and jest.fn() for spies.

Here is an example from Enzyme documentation that asserts specific output, rewritten to use Jest matchers:

import React from "react";
import { shallow } from "enzyme";
import App from "./App";

it("renders welcome message", () => {
  const wrapper = shallow(<App />);
  const welcome = <h2>Welcome to React</h2>;
  // expect(wrapper.contains(welcome)).to.equal(true);
  expect(wrapper.contains(welcome)).toEqual(true);
});

All Jest matchers are extensively documented here.

Additionally, you might find jest-enzyme helpful to simplify your tests with readable matchers. The above contains code can be written simpler with jest-enzyme.

expect(wrapper).toContainReact(welcome);

Initializing Test Environment

If your changes use a browser API that you need to mock in your tests or if you just need a global setup before running your tests, add a src/setupTests.js to your project. It will be automatically executed before running your tests.

For example:

src/setupTests.js

const localStorageMock = {
  getItem: jest.fn(),
  setItem: jest.fn(),
  clear: jest.fn(),
};
global.localStorage = localStorageMock;

Focusing and Excluding Tests

You can replace it() with xit() to temporarily exclude a test from being executed.
Similarly, fit() lets you focus on a specific test without running any other tests.

Troubleshooting

yarn start doesn’t detect changes

When you save a file while yarn start is running, the browser should refresh with the updated code.
If this doesn’t happen, try one of the following workarounds:

  • If your project is in a Dropbox folder, try moving it out.
  • If the watcher doesn’t see a file called index.js and you’re referencing it by the folder name, you need to restart the watcher due to a Webpack bug.
  • Some editors like Vim and IntelliJ have a “safe write” feature that currently breaks the watcher. You will need to disable it. Follow the instructions in “Adjusting Your Text Editor”.
  • If your project path contains parentheses, try moving the project to a path without them. This is caused by a Webpack watcher bug.
  • On Linux and macOS, you might need to tweak system settings to allow more watchers.
  • If the project runs inside a virtual machine such as (a Vagrant provisioned) VirtualBox, create an .env file in your project directory if it doesn’t exist, and add CHOKIDAR_USEPOLLING=true to it. This ensures that the next time you run yarn start, the watcher uses the polling mode, as necessary inside a VM.

If none of these solutions help please leave a comment in this thread.

yarn test hangs on macOS Sierra

If you run yarn test and the console gets stuck after printing react-scripts test --env=jsdom to the console there might be a problem with your Watchman installation as described in facebookincubator/create-react-app#713.

We recommend deleting node_modules in your project and running yarn install (or yarn if you use it) first. If it doesn't help, you can try one of the numerous workarounds mentioned in these issues:

It is reported that installing Watchman 4.7.0 or newer fixes the issue. If you use Homebrew, you can run these commands to update it:

watchman shutdown-server
brew update
brew reinstall watchman

You can find other installation methods on the Watchman documentation page.

If this still doesn’t help, try running launchctl unload -F ~/Library/LaunchAgents/com.github.facebook.watchman.plist.

There are also reports that uninstalling Watchman fixes the issue. So if nothing else helps, remove it from your system and try again.

yarn run build exits too early

It is reported that yarn run build can fail on machines with limited memory and no swap space, which is common in cloud environments. Even with small projects this command can increase RAM usage in your system by hundreds of megabytes, so if you have less than 1 GB of available memory your build is likely to fail with the following message:

The build failed because the process exited too early. This probably means the system ran out of memory or someone called kill -9 on the process.

If you are completely sure that you didn't terminate the process, consider adding some swap space to the machine you’re building on, or build the project locally.

yarn run build fails on Heroku

This may be a problem with case sensitive filenames. Please refer to this section.