Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic testing setup #39

Closed
9 tasks done
arcticicestudio opened this issue Nov 21, 2018 · 0 comments
Closed
9 tasks done

Basic testing setup #39

arcticicestudio opened this issue Nov 21, 2018 · 0 comments

Comments

@arcticicestudio
Copy link
Contributor

arcticicestudio commented Nov 21, 2018

Related epics: #38

To start writing tests the basic testing environment must be set up. As also mentioned in #38, Nord Docs requires some special changes when it comes to the testing setup because of Gatsby. Apart from that the setup is the same like in most projects and is also documented in the official Jest docs.

The scope of this issue is to get started to write unit tests. Of course, Gatsby provides a extensive documentation and great guides for this setup which will be implemented for Nord Docs.

Jest

The first step is to get Jest up and running which is quite easy since it works out-of-the-box™ after installing the main package jest.
This step is documented in the sections “Setting up your environment” of the Gatsby guide and the Jest docs about how to get started.

The main configuration file jest.config.js will be placed in the project root and initially contains the following options:

  • coverageDirectory - The path to the directory where all coverage reports will be placed. It'll be set to the main build directory within the reports sub-directory.
  • collectCoverageFrom - To ensure only relevant files are included in the coverage stats this array will set paths to find sources to measure the coverage from.
  • globals - This will include the __PATH_PREFIX__ variable which is usually set by Gatsby, and which some components need.
  • moduleNameMapper - A map from regular expressions to module names that allow to stub out resources, like images or styles with a single module while also allows to set up resolve aliases which will reflect the same setup like the ones configured for Webpack in Webpack configuration #31.
  • modulePaths - This will include paths to additional locations to search when resolving modules which is useful to define test specific utils which can then be imported like a aliased module.
  • setupFiles - This also includes setup scripts that'll be run to configure and set up tests (executed before setupTestFrameworkScriptFile) and will initial include a shim mock for the ___loader function used by Gatsby.
  • setupTestFrameworkScriptFile - The setup file that'll be run to configure or set up the testing framework before each test. It'll import and run the cleanup function of react-testing-library and jest-dom's custom matchers to extend the expect global.
  • testPathIgnorePatterns - Paths for files that'll be ignored when matching test files have been found.
  • transform - Contains regex matcher for files that will be transpiled with Babel first before run them with Jest. See the “Use Jest with Babel” section below for details.
  • transformIgnorePatterns - This is required since Gastby includes un-transpiled ES6 code and by default Jest doesn’t try to transform code inside node_modules, therefore the gatsby-browser-entry.js isn't transpiled before running Jest so the gatsby module must be excluded.

Use Jest with Babel

To write tests using the latest ECMAScript syntax and proposals, Babel must be in place and set up to transpile the sources before passing them to Jest to run them.
This step is documented in the sections “Creating a configuration file for Jest” of the Gatsby guide about the preprocess file and the Jest docs about using babel.

The main Babel configuration file babel-config.js will be placed in the base test folder within the project root. It'll initially use the babel-preset-gatsby preset package which includes all necessary Babel plugins to write tests for Gatsby based projects. This includes all plugins mentioned in the Jest Babel setup guide and additionally adds useful syntax proposal plugins that are also used in the project sources like e.g. babel-plugin-proposal-class-properties and babel-plugin-proposal-optional-chaining.
The the custom transformer will be exported using babel-jest's createTransformer function which takes the created Babel config object as parameter.

react-testing-library provides a function to get elements by an test ID using the data-testid property (attribute) that can be added to any React component's JSX so it can be easily queried in tests. Note that this should only be done when there is no other way which is documented in the guiding principles!
Since this property is only relevant for test purposes it should and will be removed for production builds using the babel-plugin-react-remove-properties package that'll be included in Gatsby's Babel configuration and loaded when in production mode.

react-testing-library and jest-dom

Like documented in #38, Nord Docs will use the awesome react-testing-library by Kent C. Dodds to render React components and test them with a bunch of useful DOM utils. Nord Docs testing principle is based on the concept of the author to not test implementation details for UIs but see your app/website only from the sight of the user.

The setup documentation provides instruction for best practices on how to configure the library for a optimal and easy developer workflow. This includes a global configuration that'll be added and loaded via Jest's setupTestFrameworkScriptFile option and will be placed within the test base directory named setup.js.
Initially it'll import the react-testing-library/cleanup-after-each script which will automatially execute afterEach(cleanup) for each test which prevents unnecessary boilerplate per test file and possible problems when the function is not called accidentally. It'll also import jest-dom/extend-expect to automatically extend the expect global with jest-dom's custom matchers.

Shims

Like documented in Gatsby's official testing setup guide there are some configurations that are specific to Gatsby projects. One is the global ___loader function used by Gatsby which must be mocked using Jest's fn() mocking function. The ___loader.js file will be created in a folder called __shims__ within the base test directory.

Mocks

With Webpack, there are many loaders available to load any kind of file type, e.g. CSS or Sass/Less for styles and images/videos of many types. Jest doesn't know how to handle these when these are imported within source files that are normally processed by Webpack so it'll throw errors during the import.
A Jest mock is a dummy module that is used instead of the real module inside tests. It is good when there are something that you can’t or don’t want to test. Almost everything can be mocked and the examples are assets rather than code. For stylesheets, there is a package called identity-obj-proxy which is also already configured for this project. For all other assets a manual mock will be created called file.js that'll be created in a new __mocks__ folder within the base test directory.
To configure Jest to use these mocks the matching regex for the files will be added to the moduleNameMapper option.

ESLint

Since Jest makes use of the globally provided functions, ESLint's environment must be configured to know that Jest is used in the project. This can easily be done by adding the jest: true property to the env option in the .eslintrc.js config file.

NPM scripts

To allow to run all tests with various options there will be some new NPM scripts:

  • test - Run all tests with Jest.
  • test:cov - Run all tests with coverage reports.
  • test:watch - Run all tests in Jest's watch mode.

Tasks

@arcticicestudio arcticicestudio added this to the 0.1.0 milestone Nov 21, 2018
@arcticicestudio arcticicestudio self-assigned this Nov 21, 2018
arcticicestudio added a commit that referenced this issue Nov 24, 2018
This commit implements the main configuration file of Jest. It follows
the "Setting up your environment" (1) guide of Gatsby and the Jest docs
about how to get started (2). The file is placed in the project root and
initially contains the following options:

- `coverageDirectory` - The directory where Jest should output its
  coverage files.
- `collectCoverageFrom` - To ensure only relevant files are included in
  the coverage stats this array of glob patterns matches files for which
  coverage information should be collected.
- `globals` - A set of global variables that need to be available in all
  test environments. The `__PATH_PREFIX__` variable is specific to
  Gatsby based projects which is necessary for some components.
- `moduleNameMapper` - A map from regular expressions to module names
  that allow to stub out resources, like images or styles with a single
  module. It is also used to set up "resolve aliases" that reflect the
  same setup like the ones configured for Gatsby's Webpack
  configuration.
- `modulePaths` - An array with paths to additional locations to search
  when resolving modules. This is useful to define test specific utils
  which can then be imported like an aliased module.
- `setupFiles` - The paths to modules that run some code to configure or
  set up the testing environment before each test. The `___loader` shim
  is a global function used by internal Gatsby APIs. Note that this is
  executed BEFORE the `setupTestFrameworkScriptFile` option!
- `setupTestFrameworkScriptFile` - The path to the module that runs to
  configure or set up the testing framework before each test. Note that
  this is executed AFTER the `setupFiles` option!
- `testPathIgnorePatterns` - An array of regexp pattern strings that are
  matched against all test paths before executing the test. If the test
  path matches any of the patterns, it will be skipped.
- `transform` - To write tests using the latest ECMAScript syntax and
  proposals, Babel must be in place and set up to transpile the sources
  before they are processed by Jest to run them. This mapping from
  regular expressions to paths of transformers will transpile matching
  files with the specified Babel config. See the Jest documentation (3)
  about how to use Jest with Babel for more details.
- `transformIgnorePatterns` - This is an important and required option
  for Gatsby based projects since Gastby includes un-transpiled ES6 code
  and by default Jest doesn't try to transform code inside
  `node_modules`, therefore the` gatsby-browser-entry.js` file isn't
  transpiled before running Jest so the `gatsby` module must be
  excluded. The array of regexp pattern strings that are matched against
  all source file paths before transformation. If the test path matches
  any of the patterns, it will not be transformed.

References:
  (1) https://www.gatsbyjs.org/docs/unit-testing/#setting-up-your-environment
  (2) https://jestjs.io/docs/en/getting-started
  (3) https://jestjs.io/docs/en/getting-started#using-babel

GH-39
arcticicestudio added a commit that referenced this issue Nov 24, 2018
To write tests using the latest ECMAScript syntax and proposals,
Babel (1) must be in place and set up to transpile the sources before
passing them to Jest to run them.
This step is documented in the sections "Creating a configuration file
for Jest" (2) of the Gatsby guide about the preprocess file and the Jest
docs about "Using Babel" (3).

The file is placed in the base `test` folder within the project root.
It initially uses the `babel-preset-gatsby` (4) preset package which
includes all necessary Babel plugins to write tests for Gatsby based
projects. This includes all plugins mentioned in the Jest Babel setup
guide and additionally adds useful syntax proposal plugins that are also
used in the project sources like e.g.
`babel-plugin-proposal-class-properties` (5) and
`babel-plugin-proposal-optional-chaining` (6).
The the custom transformer is exported using babel-jest's
`createTransformer` function (7) which takes the created Babel config
object as parameter.

References:
  (1) https://babeljs.io
  (2) https://www.gatsbyjs.org/docs/unit-testing/#2-creating-a-configuration-file-for-jest
  (3) https://jestjs.io/docs/en/getting-started#using-babel
  (4) https://www.npmjs.com/package/babel-preset-gatsby
  (5) https://babeljs.io/docs/en/babel-plugin-proposal-class-properties
  (6) https://babeljs.io/docs/en/babel-plugin-proposal-optional-chaining
  (7) https://jestjs.io/docs/en/tutorial-react#custom-transformers

GH-39
arcticicestudio added a commit that referenced this issue Nov 24, 2018
`react-testing-library` provides a function to get elements by an test
ID using the `data-testid` property (attribute) that can be added to any
React component's JSX so it can be easily queried in tests. Note that
this only be done when there is no other way which is documented in the
guiding principles (1)!
Since this property is ONLY relevant for test purposes, this commit
configures the babel-plugin-react-remove-properties (2) to remove the
property from production builds. The plugin is added in Gatsby's
Babel configuration and loaded when in production mode.

References:
  (1) https://github.com/kentcdodds/react-testing-library#guiding-principles
  (2) https://github.com/oliviertassinari/babel-plugin-react-remove-properties

GH-39
arcticicestudio added a commit that referenced this issue Nov 24, 2018
The setup documentation (1) provides instruction for best practices on
how to configure the library for a optimal and easy developer workflow.
This includes a global configuration that has been placed within the
`test` base directory named `setup.js` and will be loaded via Jest's
`setupTestFrameworkScriptFile` option .
Initially it imports the `react-testing-library/cleanup-after-each`
script which will automatically execute `afterEach(cleanup)` for each
test which prevents unnecessary boilerplate per test file and possible
problems when the function is not called accidentally. It also imports
`jest-dom/extend-expect` to automatically extend the `expect` global
with jest-dom's custom matchers (2).

References:
  (1) https://github.com/kentcdodds/react-testing-library#setup
  (2) https://github.com/gnapse/jest-dom#custom-matchers

GH-39
arcticicestudio added a commit that referenced this issue Nov 24, 2018
>> Shims

Like documented in Gatsby's official testing setup guide (1) there are
some configurations that are specific to Gatsby projects. One is the
global `___loader` function used by Gatsby which this is mocked in this
commit using Jest's `fn()` mocking function. The `___loader.js` file
is placed in a folder called `__shims__` within the base `test`
directory.

>> Mocks

With Webpack, there are many loaders available to load any kind of file
type (2), e.g. CSS or Sass/Less for styles and images/videos of many
types. Jest doesn't know how to handle these when these are imported
within source files that are normally processed by Webpack so it'll
throw errors during the import.
A Jest mock (3) is a dummy module that is used instead of the real
module inside tests. It is good when there are something that you can't
or don't want to test. Almost everything can be mocked and the examples
are assets rather than code. For stylesheets, there is a package called
`identity-obj-proxy` (4) which is also already configured for this
project. For all other assets a manual mock has been created in a new
`__mocks__` folder within the base `test` directory.
To configure Jest to use these mocks the matching regex for the files
have been added to the `moduleNameMapper` option.

References:
  (1) https://www.gatsbyjs.org/docs/unit-testing/#setting-up-your-environment
  (2) https://webpack.js.org/loaders
  (3) https://jestjs.io/docs/en/manual-mocks
  (4) https://www.npmjs.com/package/identity-obj-proxy

GH-39
arcticicestudio added a commit that referenced this issue Nov 24, 2018
Since Jest makes use of the globally provided functions, ESLint's
environment must be configured to know that Jest is used in the project.

GH-39
arcticicestudio added a commit that referenced this issue Nov 24, 2018
This commit adds new NPM scripts to allow to run all tests with various
options:

- `test` - Run all tests with Jest.
- `test:cov` - Run all tests with coverage reports (1).
- `test:watch` - Run all tests in Jest's "watch mode" (2).

References:
  (1) https://jestjs.io/docs/en/cli#coverage
  (2) https://jestjs.io/docs/en/cli#watch

GH-39
arcticicestudio added a commit that referenced this issue Nov 24, 2018
This commit implements the first snapshot tests for all existing
components. The snapshots approach has been chosen by purpose because
all components are in initial implementation state and actually only
render a React `<Fragment>`.

It also fixes the resulting problems with `propType` violations for the
`Landing` (index/root) page which renders the `Root` component without
passing children. This has been fixed by using a `React.Fragment`.

GH-39
arcticicestudio added a commit that referenced this issue Nov 24, 2018
@arcticicestudio arcticicestudio removed their assignment Nov 27, 2018
arcticicestudio added a commit that referenced this issue Dec 13, 2018
This commit integrates jest-styled-components (1), a set of utilities
for testing "Styled Components" (2) with Jest () that improves the
napshot testing experience and provides a brand new matcher to make
expectations on the style rules.
This is the officially recommended library styled-components for Jest
integration (3).

Instead of storing the generated class names in snapshots it allows to
track the actual CSS rules and attributes for better comparison what
changed and if the change is even really related to the affected
component.

> Configuration

To enable this features the package is simply imported in the test
framework setup file defined in Jest's `setupTestFrameworkScriptFile`
field (GH-39).

> Custom Style Matcher

The custom `toHaveStyleRule` matcher (4) is useful to test if a given
rule is applied to a component. It will be added to the extended global
`except` object when the main package file is being imported.

References:
  (1) https://github.com/styled-components/jest-styled-components
  (2) https://www.styled-components.com
  (3) https://jestjs.io
  (4) https://github.com/styled-components/jest-styled-components#tohavestylerule

Associated epics: GH-38
Associated issues: GH-39
GH-76
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant