Skip to content

Commit

Permalink
feat: replaced mocha with jest
Browse files Browse the repository at this point in the history
BREAKING CHANGE: whole interface is different, refer to README.
  • Loading branch information
oxala committed Sep 22, 2018
1 parent 3a3be90 commit 3e30509
Show file tree
Hide file tree
Showing 66 changed files with 735 additions and 1,953 deletions.
2 changes: 0 additions & 2 deletions .eslintignore

This file was deleted.

6 changes: 0 additions & 6 deletions .eslintrc.json

This file was deleted.

28 changes: 4 additions & 24 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,26 +1,6 @@
.DS_Store
/.idea
*.iml
/coverage
/work
/node_modules
*.configbean
/pids
/log
.cache
.beans
/static
*.marko.js
*.dust.js
*.log
.telemetry.json
/tmp
/reports
jshint.xml
jshint.html
mocha.xunit
*.marko.js
.coverage
yarn.lock
coverage
node_modules
yarn*
.vscode
.reports
marko-modules-mocking-map.json
11 changes: 0 additions & 11 deletions .istanbul.yml

This file was deleted.

23 changes: 0 additions & 23 deletions .marko-tester.js

This file was deleted.

37 changes: 11 additions & 26 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,29 +1,14 @@
language: node_js
node_js:
- "6.10.2"
- "8.11.2"
env:
- CXX=g++-4.8
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.8
cache:
directories:
- llvm-3.8.0
before_install:
-
if [ "${TRAVIS_OS_NAME}" = "linux" ]; then
if [ -z "$(ls -A llvm-$LLVM_VERSION)" ]; then
wget -O llvm-$LLVM_VERSION.tar.xz http://llvm.org/releases/$LLVM_VERSION/clang+llvm-$LLVM_VERSION-x86_64-linux-gnu-ubuntu-14.04.tar.xz;
mkdir llvm-$LLVM_VERSION;
xzcat llvm-$LLVM_VERSION.tar.xz | tar -xvf - --strip 1 -C llvm-$LLVM_VERSION;
fi;
llvm-$LLVM_VERSION/bin/llvm-config --version;
export LLVM_CONFIG="llvm-$LLVM_VERSION/bin/llvm-config";
fi
deploy:
on:
tags: true
branch: master
- NODE_ENV=test
before_script:
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
- chmod +x ./cc-test-reporter
- ./cc-test-reporter before-build
script:
- npm run lint
- npm run test -- --coverage
after_script:
- ./cc-test-reporter after-build -t lcov --exit-code $TRAVIS_TEST_RESULT
248 changes: 44 additions & 204 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,232 +1,72 @@
# marko-tester [![Build Status](https://travis-ci.org/oxala/marko-tester.svg?branch=master)](https://travis-ci.org/oxala/marko-tester)
[![Build Status](https://travis-ci.org/oxala/marko-tester.svg?branch=master)](https://travis-ci.org/oxala/marko-tester) [![Test Coverage](https://api.codeclimate.com/v1/badges/46c76b421392b0cdc6e1/test_coverage)](https://codeclimate.com/github/oxala/marko-tester/test_coverage)
# marko-tester
A utility that helps you test marko components within the JEST framework.

Test library to assist with testing marko 4 (and marko 4 legacy) UI components and more.

## Usage

### Start using marko-tester with:

```
yarn add marko-tester --dev
```

### CLI

Once you've installed marko-tester, you can start using the `markotester` alias with the path to your source folder. There are few arguments you can pass if needed:

- `--no-coverage` if you don't want to generate coverage report
- `--no-mocha` if you want to execute only linting
- `--no-lint` if you don't want lint checks
- `--lint-es5` if you want to lint code with es5 rules by default
- `--fix-lint` if you want to automatically fix your linting issues
- `--fix-fixtures` if you want to automatically replace failing fixtures with actual render result
- `--fix` combines `--fix-lint` and `--fix-fixtures` together

```
markotester source --no-coverage
markotester source --no-coverage --no-lint
markotester source --fix-lint
markotester source --fix-fixtures
```

`package.json` example:
## Requirements
Your project needs to have `jest@^23` and `marko@^4.5` installed.
Within your regular JEST configuration, you need to specify a transform for `*.marko` files:

```
"scripts": {
"lint": "yarn test --lint --no-mocha",
"test": "markotester src --no-lint --no-coverage",
"coverage": "yarn test --coverage"
...
"transform": {
...
"^.+\\.marko$": "<rootDir>/node_modules/marko-jest/preprocessor.js"
}
```

### File structure

```
app
|- source
| |- components
| | |- phone-frame
| | | +- test
| | | |- fixtures
| | | | |- default.html
| | | | |- default.json
| | | | |- empty.js
| | | | +- empty.html
| | | +- index.spec.js
| | |- component.js
| | +- index.marko
| +- pages
| | +- mobile-preview
| | |- test
| | | |- fixtures
| | | | |- default.html
| | | | +- default.json
| | | +- index.spec.js
| | |- index.js
| | +- index.marko
| +- services
| |- test
| | +- amazing-service.spec.js
| +- amazing-service.js
+- .marko-tester.js
```

### Configuration file

You can find an example configuration file in the root folder of `marko-tester` (default confirugation):
## Configuration
In the global JEST object, you can pass a `tester` configuration:

```
{
"components": [],
"taglibExcludeDirs": [],
"taglibExcludePackages": [],
"excludedAttributes": [],
"lassoPlugins": [],
"coverage": {
"reporters": [
"text-summary",
"html",
"json-summary"
],
"dest": ".reports",
"excludes": [
"**/*.marko.js"
]
"global": {
...
"tester": {
"fixturesDir": "inputs",
"shallow": false
}
};
}
```

* **components** - An array of patterns for files that should be loaded into jsdom page by lasso.
* **taglibExcludeDirs** - An array of paths relative to the root of your project folders that contain `marko.json`. This is used to isolate your tests so the nested components won't be renderer.
* **taglibExcludePackages** - An array of module names. This is used to isolate your tests so the nested components won't be renderer.
* **excludedAttributes** - An array of HTML attributes that can be different every test execution (e.g `data-widget` which marko dynamically changes based on package version).
* **lassoPlugins** - An array of lasso plugins to require and attach to lasso configuration during client test execution.
* **coverage.reporters** - An array of reporters for istanbul to use.
* **coverage.dest** - The target destination folder where reports will be written.
* **coverage.excludes** - An array of file patterns to exclude from istanbul reports.

### Automatic component/fixtures search and fixtures test
- fixturesDir - The folder name where you have fixtures to render the component with. _(Default: "fixtures")_

Marko-tester will try to automatically find your component renderer and/or fixtures to test. For the renderer, marko-tester will go up one level from your spec file and search for `index.marko` (or the file specified in `w-bind` for legacy components).
- shallow - You can turn off shallow rendering by passing `false` here. That way marko won't isolate any component test. _(Default: true)_

Fixtures will be automatically found if they are inside the `fixtures` folder on the same level as your spec file.

If fixtures and renderer would be found, and spec file exists for the component,fixture test would be automatically performed.
## Usage
`marko-tester` exposes a `getComponent` method for you to use. Pass a relative test file path to a marko component and you will receive a `render` method and `fixtures` method/object. By default, `getComponent` will run JEST SnapShot tests for the fixtures of the component.

### Render comparison based on specific input (fixtures test)
- `render` is a method that renders a component with a given input and mounts it to `document.body`. The mounted component instance is returned.

The rendering test works by giving your template the input to use for rendering and then comparing output with the specified HTML.
- `fixtures` is an object by default. It contains all the fixtures that are found within the fixture folder of this component. If a `withoutFixtures` option is passed to the `getComponent` method, `fixtures` will be a method that will run JEST SnapShot tests for your fixture. You will still be able to get fixture content by the filename: `fixtures[FixtureFileName]`.

The JSON file and HTML file comprising a test should follow the pattern below (check the `fixtures` folder in File Structure section):
### Example
You can find examples in the `tests` folder. The boilerplate looks like this:

```
{test-case}.html
{test-case}.json
{another-test-case}.html
{another-test-case}.js
```
const { getComponent } = require('marko-tester');
const { render } = getComponent('../index.marko');
### Component client-side testing
describe('When component is rendered', () => {
let component;
The client test works by instantiating a marko-widget and testing the functionality against it. For that browser environment is needed, for those purposes marko-tester uses jsdom to render the lasso-generated page and expose window object.

During client testing, `marko-tester` gives you a few methods to utilize:

* **describe.page** - Will create an empty page, giving you access to window and document objects. This method is available right after test case declaration.
* **describe.component** - Used to build the page with the component constructor in it. At this point, the `marko.component` attribute will be exposed to the mocha context giving you access to your widget's instance. This method is available right after test case declaration.

```
'use strict';
// First describe in spec files will be read by marko-tester to initialize test environment;
// By default the describe string will be the path to autodiscovered renderer or `index.js` in the directory above;
// If you specify a string for first describe, your text will be appended to the path of the directory above;
describe(({ expect, sinon, fixtures }) => {
// list of the params that are being returned in the callback:
// expect - chai's expect;
// sinon - library to spy and stub;
// fixtures - will give you a list of attached test fixtures to current component;
// mockRequire - exposes 'mock-require' npm module;
describe.component(({ marko, modRequire }) => {
// list of the params that are being returned in the callback:
// modRequire - a helper function to require modules on a browser level;
// marko - marko context that contains the component instance under `marko.component`;
let mockHello;
beforeEach(() => {
mockHello = 'world';
marko.component.hello = mockHello;
});
afterEach(() => {
delete marko.component.hello;
});
it('should have hello attribute', () => {
expect(marko.compomnent.hello).to.be.equal(mockHello);
});
beforeEach(() => {
component = render(fixtures.default);
});
});
```

By default, running `describe.component` will build the component using the `default` fixture (if there is one). If you wish to build the component using a different fixture, you can pass an option to do that before the callback:

```
describe.component({
fixture: {}
}, ({ marko }) => { ... });
```

### Few additional features

1. `describe.component` and `describe.page` commands are just patched describe functions. That's why the `only` and `skip` operators can be used with these commands (e.g `describe.component.only()`, `describe.page.skip()`).
2. If you want to mock require during client-side testing - you can do that using options for `testComponent` method. There as a key you can pass relative path to the necessary file that will be required. And the mock of that file as a value. Keep in mind that mocked require will only exist within this `buildComponent`.<br>
```
describe.component({
mock: {
require: {
'../dep': { hello: 'world' },
some_node_module: { world: 'hello' }
},
component: {
'nested-component': { world: 'hello' }
},
components: {
'hello-worlds': [{ worlds: 'hello' }]
}
},
}, ({ marko }) => { ... });
```
afterEach(() => {
component.destroy();
});
3. You can also use a different file layout if necessary. When your template has a top-level element of `tbody`, `tr`, or something else that expects a `table` element as a parent, you can add the `layout` parameter and set it to `table`. This will ensure JSDOM renders your component correctly.
```
describe.component({
fixture: fixtures.basic,
layout: 'table'
}, ({ marko }) => { ... });
...your assertions...
});
```

## Code style (linting)

Apart from testing, consistent styling is another important part of keeping high quality code. For that particular reason, `marko-tester` comes with an `eslint` and `stylelint` checks built-in. It will check the style of your code when you execute the `markotester` command.

It uses legacy (es5) **airbnb** configuration for ESLint and **standard** configuration for Stylelint (checkine both *less* and *css* files).

## References

* [Marko](http://markojs.com)
* [Mocha](https://mochajs.org)
* [Sinon](http://sinonjs.org/docs/)
* [Expect](http://chaijs.com/api/bdd/)
* [rewire](https://github.com/jhnns/rewire)
* [mock-require](https://github.com/boblauer/mock-require)
* [ESLint](http://eslint.org)
* [eslint-airbnb-config](https://github.com/airbnb/javascript/tree/es5-deprecated/es5)
* [eslint-config-ebay](https://github.com/darkwebdev/eslint-config-ebay)
* [Stylelint](https://github.com/stylelint/stylelint)
* [stylelint-config-standard](https://github.com/stylelint/stylelint-config-standard)
* [Istanbul](https://github.com/gotwarlost/istanbul)
* [jest](https://jestjs.io)

## Thanks
* [Dylan Piercey](https://github.com/DylanPiercey)
* [Abiyasa Suhardi](https://github.com/abiyasa)

## Licence
MIT
Loading

0 comments on commit 3e30509

Please sign in to comment.