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

Tests: Setup Jest as an alternative test runner #1382

Merged
merged 9 commits into from
Jul 6, 2017
Merged

Tests: Setup Jest as an alternative test runner #1382

merged 9 commits into from
Jul 6, 2017

Conversation

gziolo
Copy link
Member

@gziolo gziolo commented Jun 22, 2017

This is a proof of concept for Jest integration with Gutenberg.

Wondering why Jest? See: https://gziolo.pl/2017/06/17/picking-jest-over-mocha/.

Sidenotes: It doesn't need Webpack processing. It still uses Chai and Sinon to make it possible to run with both Mocha and Jest and perform comparisons on one branch. I had to disable one test suite, because I didn't find a quick way to make it pass. It can be done later if we ever decide we replace Mocha with Jest.

Regular test run

npm run test-unit

With slow tests:

RUN_SLOW_TESTS=1 npm run test-unit

Only one test file (element/test/index.js):

npm run test-unit element/test/index.js

Code coverage

npm run test-unit:coverage
screen shot 2017-06-23 at 12 51 28

Watch mode

npm run test-unit:watch

By default it executes test for modified files only. You can change it using UI for subsequent runs.

IDE integration

screen shot 2017-06-23 at 13 13 54

Performance

Jest is configured to omit Webpack processing step. It makes it faster even when executed with all caches disabled. Jest shines on subsequent runs when it's able to take advantage of its caching mechanism.

Mocha

Before: test npm run test-unit

334 passing (295ms)
96 pending

real 0m16.125s
user 0m16.797s
sys 0m0.895s

Jest without cache

test npm run test-unit -- --no-cache

Test Suites: 2 skipped, 28 passed, 28 of 30 total
Tests: 96 skipped, 334 passed, 430 total
Snapshots: 0 total
Time: 9.363s
Ran all test suites.

real 0m13.121s
user 1m11.006s
sys 0m3.656s

Jest

test npm run test-unit

Test Suites: 2 skipped, 28 passed, 28 of 30 total
Tests: 96 skipped, 334 passed, 430 total
Snapshots: 0 total
Time: 3.484s
Ran all test suites.

real 0m5.961s
user 0m30.956s
sys 0m2.355s

TODO

  • Fix build/test/full-content.js test.
  • Replace Chai and Sinon with Jest matchers and spies.
  • Enable Eslint rule jest/valid-expect.
  • Remove Mocha? :trollface:
  • Update testing docs

@gziolo gziolo added [Type] Automated Testing Testing infrastructure changes impacting the execution of end-to-end (E2E) and/or unit tests. [Type] Technical Prototype Offers a technical exploration into an idea as an example of what's possible [Status] In Progress Tracking issues with work in progress labels Jun 23, 2017
@gziolo gziolo self-assigned this Jun 23, 2017
@@ -86,7 +86,7 @@ function normalizeParsedBlocks( blocks ) {
} );
}

describe( 'full post content fixture', () => {
describe.skip( 'full post content fixture', () => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still need to find a way to make this test suite pass.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gziolo This suite can probably be rewritten to use Jest snapshots. What is the current issue with it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of them fail, but I didn't even try to fix them. I just wanted to validate if Gutenberg can work with Jest without any changes in test files.

I started my parental leave this week so I might not have time to debug it in the upcoming days or weeks, but I'm happy to help with reviews using my mobile :)

// We need a high timeout here to accomodate Travis CI
this.timeout( 10000 );
// We need a high timeout for Mocha here to accomodate Travis CI
if ( this.timeout ) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jest doesn't provide such method.

if ( ! process.env.RUN_SLOW_TESTS ) {
return;
}
const maybeDescribe = process.env.RUN_SLOW_TESTS ? describe : describe.skip;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can't have test suite without any tests so it complains without skipping.

"**/utils/**/*.js"
],
"coveragePathIgnorePatterns": [
"<rootDir>/components/clipboard-button/index.js",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage errors on those 3 files. I didn't try to understand why.

Copy link
Member Author

@gziolo gziolo Jul 6, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It fails because nyc or istanbul doesn't like param destructuring in function definition that uses a default value ... Example:

function Notice( { status, content, onRemove = noop } ) { ... }

I think it needs to be fixed somewhere else. I can investigate it further later.


module.exports = {
process( src ) {
// Description of PEG.js options: https://github.com/pegjs/pegjs#javascript-api
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I followed pegjs-loader from Webpack and it looks like it works properly :)

@@ -0,0 +1,21 @@
require( 'core-js/modules/es7.object.values' );
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is tricky part. I had to add it explicitly here. babel-jest should do it instead, but apparently there is something happening that breaks it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be a code comment.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, will add in another PR.

global.before = global.beforeAll;
global.context = global.describe;

global.wp = {
Copy link
Member Author

@gziolo gziolo Jun 23, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need it to support wp.element.* syntax. I should probably add comment in code, too :)

@@ -438,12 +438,6 @@ describe( 'FormTokenField', function() {
expect( textInputNode.prop( 'value' ) ).to.equal( ' quux' );
} );

it( 'should skip empty tokens at the beginning of a paste', function() {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is copy and paste from the test above.

@youknowriad
Copy link
Contributor

Copying my comments for our slack discussion here:

Before introducing a new testing framework to Core, we need to consider the different options and Jest is a great test runner (maybe the best right now) 🙂

One of the issues we currently have with our mocha setup is that we build the tests using webpack (pegs-loader, sass-loader, wp global variables are all handled by webpack) before running them, this has some costs. We can’t run a single test without building the entire suite which is not very performant.

This PR solves this issue 🎉 but the solution has some downsides: we need to “recreate” (or find a hack) the webpack loaders one by one. Also, this makes our test code and built code slightly different.

I personally think the niceties that come with Jest surpass the downsides: Performance, coverage, snapshots.

It would be great to have others' opinion.

@ntwb
Copy link
Member

ntwb commented Jul 2, 2017

Found this an interesting read, results were not what I expected:

https://medium.com/dailyjs/javascript-test-runners-benchmark-3a78d4117b4

p.s. I do like watch, cache, snapshots features of Jest FWIW

@gziolo
Copy link
Member Author

gziolo commented Jul 2, 2017

Found this an interesting read, results were not what I expected

I saw that the other day, too. This benchmark is very interesting but I noticed that Jest is executed with default configuration, which means it needs to setup a fresh jsdom instance for every test suite. You can pick node test env instead which should drastically speed up things and will align with what Mocha and Jasmine offer out of the box. Jest's default setup is optimized for code that is run in the browser.

I asked post's author to add Jest setup that uses node as test env. I'm looking forward to see how it would impact results.

@gziolo
Copy link
Member Author

gziolo commented Jul 3, 2017

@ntwb I got confirmation form benchmark's author that Jest is 30% faster with test env set to node. See https://medium.com/@vitaliypotapov/thanks-for-suggestion-jest-is-really-30-faster-with-env-node-option-the-chart-4309ba8aba81. It still slower in this particular case though.

@gziolo gziolo force-pushed the try/jest branch 2 times, most recently from 0c3fde7 to e118d4d Compare July 6, 2017 06:00
@gziolo
Copy link
Member Author

gziolo commented Jul 6, 2017

Fixed build/test/full-content.js test which was the only blocker. It turned out I missed to include blocks import in the setup phase.

If we are fine with using Jest I'm more than happy to remove Mocha and update all references in documentation.

.gitignore Outdated
gutenberg.pot
.idea
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IDE specific entries in .gitignore should not be in the repo, users should manage these locally in ~/.gitignore_global

See also https://core.trac.wordpress.org/ticket/34345

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for tip, this was bothering me since forever :)

package.json Outdated
@@ -59,12 +59,14 @@
"enzyme": "^2.8.2",
"eslint": "^3.17.1",
"eslint-config-wordpress": "^1.1.0",
"eslint-plugin-jest": "20.0.3",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should include a ~ for updating via minor semantic version releases.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

package.json Outdated
"eslint-plugin-jsx-a11y": "^4.0.0",
"eslint-plugin-react": "^6.10.3",
"expose-loader": "^0.7.3",
"extract-text-webpack-plugin": "^2.1.0",
"gettext-parser": "^1.2.2",
"glob": "^7.1.1",
"jest": "20.0.4",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should include a ~ for updating via minor semantic version releases.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see ^ is used in other places, shouldn't it be used here, too?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should use ^ to include all non-blocking updates, I guess it's also the default when using npm install --save

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be ~, linters and for the most part rules will inherit the same semantic behaviour from the linter, in this case ESLint and by proxy it's shared plugins and shared configs:

Via ESLint Semantic Version Policy:
"According to our policy, any minor update may report more errors than the previous release (ex: from a bug fix). As such, we recommend using the tilde (~) in package.json e.g. "eslint": "~3.1.0" to guarantee the results of your builds."

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't follow:

  • How this relates to Jest specifically
  • Why this means we can't use ^

I think this is best left for a separate PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

@youknowriad
Copy link
Contributor

Let's remove mocha in this PR, we don't want to maintain two runners IMO.

@gziolo
Copy link
Member Author

gziolo commented Jul 6, 2017

I removed Mocha and updated most of its references.

There are two cleanup tasks left which can be done in the follow up PR if you agree:

  • Replace Chai and Sinon with Jest matchers and spies.
  • Enable Eslint rule jest/valid-expect and remove mocha Eslint env.

"mocha": true
},
"mocha": true,
"jest/globals": true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't include before and after, which means we still need mocha: true? I'm a bit surprised by that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know. I will fix it with jest-codemods soon.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done with #1788.

@nylen
Copy link
Member

nylen commented Jul 6, 2017

Not having to wait for webpack builds to run the tests is a huge improvement. Let's try it.

@nylen nylen merged commit 1406fe8 into master Jul 6, 2017
@nylen nylen deleted the try/jest branch July 6, 2017 22:27
@gziolo
Copy link
Member Author

gziolo commented Jul 7, 2017

Full API migration from Mocha to Jest is ready to review #1788.

youknowriad pushed a commit that referenced this pull request Jan 17, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Status] In Progress Tracking issues with work in progress [Type] Automated Testing Testing infrastructure changes impacting the execution of end-to-end (E2E) and/or unit tests. [Type] Technical Prototype Offers a technical exploration into an idea as an example of what's possible
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants