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

Attempt to softly interrupt watch (#1599) #1709

Merged
merged 2 commits into from
Sep 29, 2016

Conversation

thymikee
Copy link
Collaborator

This is an attempt to solving #1599.

The PR features a new option: i for "softly" interrupting watch (forces tasks to fail without exiting the process, so you're able to run the tests again, e.g. with adjusted pattern or so).

screen shot 2016-09-15 at 21 11 36

The watchInterrupt flag is passed to runTest() through argv variable (not sure if that's the best idea though but hey, tried and worked as a proof of concept)

This is WIP, would definitely appreciate some help, as this is my first PR here.

@ghost ghost added the CLA Signed ✔️ label Sep 15, 2016
@codecov-io
Copy link

codecov-io commented Sep 15, 2016

Current coverage is 87.42% (diff: 100%)

Merging #1709 into master will not change coverage

@@             master      #1709   diff @@
==========================================
  Files            38         38          
  Lines          1217       1217          
  Methods           0          0          
  Messages          0          0          
  Branches          0          0          
==========================================
  Hits           1064       1064          
  Misses          153        153          
  Partials          0          0          

Powered by Codecov. Last update fd6b124...a593adf

@thymikee
Copy link
Collaborator Author

This is how the output looks after hitting interruption key.

screen shot 2016-09-16 at 00 15 01

Copy link
Member

@cpojer cpojer left a comment

Choose a reason for hiding this comment

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

This is an amazing implementation. I could have never thought of using argv for this, super original :D

Since we'd like to make sure this is solid and isn't going to trouble future generations, I recommend a slightly different approach:

Let's create a "WatchState" class in jest.js that has isInterrupted and setState. By default it's state is something like {interrupted: false}. We pass on the watch state into runTests and on every test result we ask watchState.isInterrupted() and then cancel just like you did in your initial diff.

I also think we might be able to simply kill workerfarm after each test result like if (watchState.isInterrupted()) { workerFarm.end(); } – that way you might not need to make the change in runTests.js.

Please make sure the new implementation works both when using jest -i --watch and jest --watch – the first one runs all the tests in the same process.

(Note: we are going to refactor the watch command into a separate module, for now just put everything into jest.js that needs to be there).

: this._createParallelTestRun(testPaths, onTestResult, onRunFailure);
? this._createInBandTestRun(testPaths, argv, onTestResult, onRunFailure)
:
this._createParallelTestRun(testPaths, argv, onTestResult, onRunFailure);
Copy link
Member

Choose a reason for hiding this comment

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

nit: this style isn't great. Let's rename onTestResult to onResult and onRunFailure to onFailure. That should be sufficiently descriptive and allow you to bring this back into 80 chars.

@@ -282,6 +287,7 @@ const runCLI = (
? chalk.dim(' \u203A Press ') + 'u' + chalk.dim(' to update failing snapshots.')
: null,
chalk.dim(' \u203A Press ') + 'p' + chalk.dim(' to filter by a filename regex pattern.'),
chalk.dim(' \u203A Press ') + 'i' + chalk.dim(' to interrupt watch mode.'),
Copy link
Member

Choose a reason for hiding this comment

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

can we call this c for cancel and say Press c to cancel current test run? I think that is clearer.

Ideally in the future we'll print this only when tests are actually running, but for now this is fine :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Sure, i works better for something like interactive I now think, but I had this interruption in mind. Updated to c and cancel as requested

@@ -347,6 +353,10 @@ const runCLI = (
pipe.write('\n');
writeCurrentPattern();
break;
case KEYS.I:
argv.watchInterrupt = true;
console.log('\n' + chalk.bold('Watch Interrupted...'));
Copy link
Member

@cpojer cpojer Sep 17, 2016

Choose a reason for hiding this comment

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

it should be pipe.write(chalk.bold('Test run interrupted')). Let's get rid of the ... here too.

@thymikee
Copy link
Collaborator Author

Yeah, passing the message through argv was kind of a hack, because this is a new environment for me and I wasn't sure how to pass the variable other way.

WatchState feels way better. With the last commit I've replaced argv with this class. The whole functionality works much faster. For parallel run the interruption is instant. For band run it needs to wait for the initiated singular test to end, which introduces a delay.

I guess I should write a test for WatchState class, shouldn't I?

BTW. This is the first time for me using flowtype and already loved it.

@thymikee
Copy link
Collaborator Author

Had a while so I've tweaked the messaging a bit. It's also visible while running tests.

While tests are running:
screen shot 2016-09-19 at 21 02 39
After c is pressed:
screen shot 2016-09-19 at 21 03 07
screen shot 2016-09-19 at 21 04 41

@ghost ghost added the CLA Signed ✔️ label Sep 19, 2016
Copy link
Member

@cpojer cpojer left a comment

Choose a reason for hiding this comment

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

This is great. I had a couple smaller comments and I'll probably need to experiment with the promises here a little bit myself, but it is almost ready to ship :)

@@ -30,6 +30,7 @@ const promisify = require('./lib/promisify');
const runTest = require('./runTest');
const snapshot = require('jest-snapshot');
const workerFarm = require('worker-farm');
const WatchState = require('./jest').WatchState;
Copy link
Member

Choose a reason for hiding this comment

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

hm, this circular dependency is not great. Can we put WatchState into a separate file next to TestRunner.js?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I was just about to ask about it earlier :D Fix'd with latest commit.

@@ -69,8 +69,11 @@ class DefaultReporter extends BaseReporter {
results.numRuntimeErrorTestSuites;
if (process.stdout.isTTY && remaining > 0) {
process.stderr.write(RUNNING_TEST_COLOR(
`Running ${pluralize('test suite', remaining)}...`,
`Running ${pluralize('test suite', remaining)}... `,
Copy link
Member

Choose a reason for hiding this comment

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

can we remove this again and add a space in front of the message on #75?

));
if (config.watch) {
process.stderr.write(RUNNING_TEST_COLOR('Press c to cancel '));
Copy link
Member

Choose a reason for hiding this comment

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

And we can get rid of the space at the end here. Let's do:

process.stderr.write(' ' + RUNNING_TEST_COLOR('Press ') + 'c' + RUNNING_TEST_COLOR('c to cancel'));

};

type WatchStateState = {
Copy link
Member

Choose a reason for hiding this comment

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

This kind of tells me we should find a new name for WatchState :D

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

TestWatcher maybe?

Copy link
Member

Choose a reason for hiding this comment

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

sure!

@thymikee
Copy link
Collaborator Author

Forgot to mention I've updated the TestWatcher with subscription API, so the interruption feels instant.

@cpojer
Copy link
Member

cpojer commented Sep 24, 2016

@thymikee would you mind rebasing your diff? We just merged the concurrent reporter so we made some changes in the same modules :(

@ghost ghost added the CLA Signed ✔️ label Sep 24, 2016
@thymikee
Copy link
Collaborator Author

@cpojer sure, give me a sec ;)

@thymikee
Copy link
Collaborator Author

@cpojer Rebased. I'd appreciate further testing of the feature. Some snapshots are not passing, but I'd rather like you to check if it's intentional.

@cpojer cpojer force-pushed the watch-interrupt branch 4 times, most recently from 06b14a0 to d7d5823 Compare September 28, 2016 08:42
@ghost ghost added the CLA Signed ✔️ label Sep 28, 2016
@cpojer
Copy link
Member

cpojer commented Sep 28, 2016

@thymikee I polished the implementation a little bit and I think it works pretty well now both in the concurrent and in-band mode. Would you mind giving it a try and letting me know what you think? I removed the "Press c to cancel a test run"-line so we aren't making the watcher messy, especially since cancel can only be used during a run. However, with the new concurrent reporter, printing a message during the run on how to abort also seems kind of odd. Do you have any suggestions on where to hint at that pressing "c" will cancel the run?

Also cc @gaearon because he requested this feature. Try it out!

@ghost ghost added the CLA Signed ✔️ label Sep 28, 2016
@thymikee
Copy link
Collaborator Author

thymikee commented Sep 28, 2016

@cpojer definitely appreciate the simpler EventEmitter-based solution and cleanup! (Guess I just wanted to play with subscription mechanism)

Letting user know about the possibility to cancel tests is indeed hard to fit into concurrent reporter. What about adjusting the message in Watch Usage section, to stick a little from the rest? E.g.

To cancel already running tests press c.

screen shot 2016-09-28 at 12 16 36

@ghost ghost added the CLA Signed ✔️ label Sep 28, 2016
@gaearon
Copy link
Contributor

gaearon commented Sep 28, 2016

Do we need a separate command? Can we make existing commands just keep working instead?

Basically all I wanted is to be able to p, type another pattern, press Enter, and have Jest acknowledge that during the test run. Same with o and a.

@cpojer
Copy link
Member

cpojer commented Sep 28, 2016

@gaearon you are saying that any existing command should cancel if a test run is active?

@ghost ghost added the CLA Signed ✔️ label Sep 28, 2016
@gaearon
Copy link
Contributor

gaearon commented Sep 28, 2016

I think that on confirmation (p confirms on <Enter>, a, o, and <Enter> itself confirm immediately) the existing command should cancel, clear the screen, and the new command should run.

@thymikee
Copy link
Collaborator Author

Wouldn't the console be too crowded if the user hits p, types a pattern and have all the tests running in the meantime, jumping around? I think better UX (for p command) would be to clear the screen immediately and then re-run tests with new pattern on <Enter>.

@cpojer
Copy link
Member

cpojer commented Sep 29, 2016

This is what it looks like now:

jest-interrupt

Took @gaearon's suggestion, even hitting "enter" during the run will abort. Let's see how people like it.

@cpojer cpojer merged commit 7a36a03 into jestjs:master Sep 29, 2016
mthmulders pushed a commit to mthmulders/jest that referenced this pull request Oct 10, 2016
* Attempt to softly interrupt watch

* Polish implementation.
@thymikee thymikee deleted the watch-interrupt branch February 19, 2017 16:29
tushardhole pushed a commit to tushardhole/jest that referenced this pull request Aug 21, 2017
* Attempt to softly interrupt watch

* Polish implementation.
@github-actions
Copy link

This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Please note this issue tracker is not a help forum. We recommend using StackOverflow or our discord channel for questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 13, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants