# Testing

## Karma setup for Typescript

Webpacker does not setup `Karma` by default, so you've to manually install it along with its dependencies as per your need. Following things marked as optional can be used to fancify the test results (Recommended).

```js
// package.json
"scripts": {
  "test": "NODE_ENV=test karma start"
},
"dependencies": {
  "typescript": "^2.5.2",
  "ts-loader": "^2.3.7"
},
"devDependencies": {
  "karma": "^1.7.1",
  "karma-webpack": "^2.0.4",
  "karma-chrome-launcher": "^2.2.0",
  "karma-jquery": "^0.2.2",
  "karma-jasmine": "^1.1.0",
  "karma-jasmine-jquery": "^0.1.1",
  "jasmine-core": "^2.8.0",
  [optional] "karma-coverage": "^1.1.1",
  [optional] "karma-coverage-istanbul-reporter": "^1.3.0",
  [optional] "karma-spec-reporter": "0.0.31",
  [optional] "istanbul-instrumenter-loader": "^3.0.0",
}
```

It is beneficial to use the same webpack configuration file (generated by webpacker) in Karma configuration to avoid redundancy. Following line tells Karma not to write transpiled source files onto filesystem while testing to avoid `Error: EACCES: permission denied, mkdir '/_karma_webpack_' ` error. Then inject a new rule a.k.a. loader in the existing ones (needed only if you have installed `istanbul-instrumenter-loader`) to generate a coverage report under `/coverage` directory.

```js
// config/webpack/test.js
const environment = require('./environment')
environment.plugins.get('Manifest').opts.writeToFileEmit = process.env.NODE_ENV !== 'test'
environment.loaders.append('istanbul-instrumenter', {
  test: /\.ts$/,
  enforce: "post",
  loader: "istanbul-instrumenter-loader",
  query: {
    esModules: true
  },
  exclude: ["node_modules", /\.test\.ts$/]
}) /* optional */
module.exports = environment.toWebpackConfig()
```

Finally, update `karma.conf.js` to read the same `test.js` file mentioned above. Rest of the things are mandatory (few marked as optional wherever appropriate).

```js
// karma.conf.js
const webpackConfig = require('./config/webpack/test.js')
module.exports = function(config) {
  config.set({
    basePath: "",
    frameworks: ["jquery-3.2.1", "jasmine-jquery", "jasmine"],
    plugins: [
      "karma-jquery",
      "karma-jasmine-jquery",
      "karma-jasmine",
      "karma-webpack",
      "karma-chrome-launcher",
      "karma-coverage-istanbul-reporter" /* optional */,
      "karma-spec-reporter" /* optional */
    ],
    files: [ "/* add spec files */" ],
    exclude: [],
    webpack: webpackConfig,
    preprocessors: {"/* add spec files */" : ["webpack"]},
    mime: { "text/x-typescript": ["ts"] },
    reporters: ["progress", "coverage-istanbul" /* optional */],
    coverageIstanbulReporter: {
      reports: [ 'html', 'lcovonly', 'text-summary' ],
      fixWebpackSourcePaths: true
    } /* optional */,
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ["Chrome"],
    singleRun: true
  });
};
```

## Lazy compilation

Webpacker lazily compiles assets in test env so you can write your tests without any extra
setup and everything will just work out of the box.

Here is a sample system test case with hello_react example component:

```js
// Example React component

import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'

const Hello = props => (
  <div>Hello David</div>
)

document.addEventListener('DOMContentLoaded', () => {
  ReactDOM.render(
    <Hello />,
    document.body.appendChild(document.createElement('div')),
  )
})
```

```erb
<%# views/pages/home.html.erb %>

<%= javascript_pack_tag "hello_react" %>
```

```rb
# Tests example React component
require "application_system_test_case"
class HomesTest < ApplicationSystemTestCase
  test "can see the hello message" do
    visit root_url
    assert_selector "h5", text: "Hello! David"
  end
end
```

## Capybara setup for Rails
Make sure you configure Rails to serve static files from the public directory in the test environment.

```rb
# config/environments/test.rb
# Configure public file server for tests with Cache-Control for performance.
config.public_file_server.enabled = true
```
