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

Fix .only() behaviour when running with watch option, fixes #2429 #2544

Merged
merged 3 commits into from
Sep 29, 2017

Conversation

ddneat
Copy link
Contributor

@ddneat ddneat commented Oct 16, 2016

Since version 3.0.0 the watch option does not work as expected in combination with .only().

@fediev already described in detail #2429 the misbehaviour.

@boneskull
Copy link
Contributor

boneskull commented Nov 1, 2016

@davidspinat thanks. can you please sign the CLA?

@ddneat
Copy link
Contributor Author

ddneat commented Nov 2, 2016

@boneskull of course 👍

@ddneat
Copy link
Contributor Author

ddneat commented Nov 23, 2016

@boneskull may I help you with something else? :)

@boneskull
Copy link
Contributor

@davidspinat Sorry, bandwidth problems.

This may not be feasible, but can you provide an integration test? If you're having trouble, I can dig deeper and suggest something.

Failing that, maybe you see if you can't re-create the problem via other means...

@boneskull boneskull added status: waiting for author waiting on response from OP - more information needed and removed needs-cla labels Nov 24, 2016
@ddneat
Copy link
Contributor Author

ddneat commented Jan 2, 2017

@boneskull Sorry haven't managed to provide an integration test. However I would suggest the following:

In https://github.com/mochajs/mocha/blob/master/test/integration/helpers.js#L64 we might extend the signature of runMocha with the an argument called times e.g.:

runMocha: function (fixturePath, args, fn, times) ...

Further we would need to modify invokeMocha to rerun the tests with different arguments/files... Nevertheless I'm not sure if it's worth the effort. Seems quite overwhelming and confusing to me.

What's your opinion?

@jzaefferer
Copy link

For the record, I had the same issue as reported in #2429 and just tested this branch locally, it works and fixes issue. Not the same as automated tests, but considering the two changes relatively trivial, maybe its good enough.

@ddneat
Copy link
Contributor Author

ddneat commented Feb 3, 2017

@boneskull how should we proceed here? :)

@threepears
Copy link

threepears commented Jun 20, 2017

@boneskull : just curious if this is being, or has been, integrated yet. My team has been watching this page for months, waiting to update our Mocha version until this issue is fixed, as we found the problem with ".only()" to break behavior we had relied on. This ticket is still listed as open, but if you've integrated this into a recent version, please let us know. Thank you!

@juank11memphis
Copy link

Is this bug getting fixed any time soon?
Thanks!

@ddneat
Copy link
Contributor Author

ddneat commented Jul 24, 2017

Is there any chance this PR will be merged? How might we add a test which covers this fix? I guess everyone would love to see this merged. Please leave some feedback.

Greetings

@boneskull boneskull added status: needs review a maintainer should (re-)review this pull request semver-minor implementation requires increase of "minor" version number; "features" semver-patch implementation requires increase of "patch" version number; "bug fixes" and removed status: waiting for author waiting on response from OP - more information needed semver-minor implementation requires increase of "minor" version number; "features" labels Aug 1, 2017
@boneskull
Copy link
Contributor

@davidspinat Can you please revert the change to the root mocha.js? This file is generated (manually, currently) when we release.

@boneskull
Copy link
Contributor

A proper harness for testing watch-related behavior would be necessary if we were to make enhancements in this subsystem (or re-implement it).

The risk here is that the change involves code that's run regardless of whether --watch is invoked. If someone (like @jzaefferer?) has been running against this branch for awhile, it'd help to know that it's not causing problems elsewhere.

@@ -795,7 +795,7 @@ Runner.prototype.run = function (fn) {
var rootSuite = this.suite;

// If there is an `only` filter
if (this.hasOnly) {
if (hasOnly(rootSuite)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Okay, so it looks like with the addition of --forbid-only, this may need some changes.

Runner#hasOnly is set if e.g. a describe.only() is encountered (see lib/interfaces/common.js).

The --forbid-only functionality will check this value. At the point that it's checked, the Runner may or may not have a suite property. This means there's likely some weird interactions between --forbid-only and --watch.

A solution may be to set Runner#hasOnly to true if the result of hasOnly() is true. hasOnly() may also want to check the value of Runner#hasOnly. When the Runner's end event is handled, it may also need to reset Runner#hasOnly to false.

I haven't fiddled with this too much, but this is the matrix we're trying to assert is OK:

  1. describe.only()
  2. it.only()
  3. --watch
  4. --forbid-only

For example, run a --watch with --forbid-only, then add a describe.only(), save, then remove it again & save. What happens?

Copy link
Contributor

Choose a reason for hiding this comment

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

(careful with nested suites here; hasOnly() looks like it only inspects the innards of any given suite, and not if that suite was itself marked as an "only" suite; that information is stored in the aforemention suite's parent! 😄)

Copy link
Contributor

Choose a reason for hiding this comment

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

Worth noting that #2874 also touches hasOnly-using code in addition to the --forbid-only code already merged doing so.

(I plan on a more detailed review later this week.)

Copy link
Contributor

@ScottFreeCode ScottFreeCode Sep 29, 2017

Choose a reason for hiding this comment

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

This should be merged correctly now, I think.

Copy link
Contributor

@boneskull boneskull left a comment

Choose a reason for hiding this comment

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

will need further experimentation and/or tests

@@ -795,7 +795,7 @@ Runner.prototype.run = function (fn) {
var rootSuite = this.suite;

// If there is an `only` filter
if (this.hasOnly) {
if (hasOnly(rootSuite)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

(careful with nested suites here; hasOnly() looks like it only inspects the innards of any given suite, and not if that suite was itself marked as an "only" suite; that information is stored in the aforemention suite's parent! 😄)

@jzaefferer
Copy link

The risk here is that the change involves code that's run regardless of whether --watch is invoked. If someone (like @jzaefferer?) has been running against this branch for awhile, it'd help to know that it's not causing problems elsewhere.

I can't say how long I was running this branch locally, might've been a few weeks though. I never noticed any regressions.

Looks like this will requires further changes now - let me know if I can help testing the result.

Copy link
Contributor

@ScottFreeCode ScottFreeCode left a comment

Choose a reason for hiding this comment

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

(TL;DR? Recommendations at the bottom.)

on design and concerns

(careful with nested suites here; hasOnly() looks like it only inspects the innards of any given suite, and not if that suite was itself marked as an "only" suite; that information is stored in the aforemention suite's parent! 😄)

As long as it's used only on:

  • the root suite
  • inside the filterOnly function

...it should be fine. (And I believe that's the case here.) If we're really paranoid, we could make the existing hasOnly function only accessible to two other functions: filterOnly and a runner-level hasOnly function that calls this existing hasOnly against the root suite, the new runner-level hasOnly function being what we would use here and in the forbidding-related code (see also second section). Alternatively, again if we're really paranoid, maybe we could update the hasOnly function to also check suite.parent._onlySuites.indexOf(suite) >= 0 or something like that? But as long as stuff's tested I don't think either of those is a necessity (see more on that in the rest of this section).

A proper harness for testing watch-related behavior would be necessary if we were to make enhancements in this subsystem (or re-implement it).

If someone had come up with one by now I'd be all for using it, and it would be great to come up with one so we can start in on trying to deal with other watch-related behavior, but for this particular fix I'm not convinced it's worth holding up on something that hard to figure out -- given that the hasOnly function can be tested to be correct on any given run and merely won't get stale like the hasOnly property. And speaking of testing for correctness on any given run...

The risk here is that the change involves code that's run regardless of whether --watch is invoked.

...I'm not sure there's much risk involved in this regard since we already have tests for the behavior of only in general. Surely those cover it?

Of course, if somebody can come up with a test that doesn't use --watch but does run the tests twice with onlyd suites/tests removed the second time, to reproduce the same issue that this fixes, we should incorporate that test into this PR; but (again) I'm fairly confident in the correctness of this particular change without such tests -- as long as we don't break the tests we already have, we at least won't be getting worse than we are now.


on what is required of this PR (including intersection with forbidding)

As far as I can tell, effectively, any place that the hasOnly property is being used ought to be replaced with calling the hasOnly function against the root suite. (The hasOnly property is on the runner, so all such replacements would be equivalent to using the hasOnly function against the root suite, and are thus safe/correct.) Prior to the addition of the forbid options, this PR addressed the only use that I'm aware of; however the forbid options are now using it (and the additional PR #2874 moves that usage to achieve error reporting). That means a few things are going to need to happen:

@boneskull Any serious concerns with those recommendations, given the rationale and responses to concerns laid out above?

@ScottFreeCode
Copy link
Contributor

Waaait a second, I just realized something else: @mochajs/core is runner.hasOnly, the (potentially stale) property, meant to be public? Because if so:

  • We'd have to wait for a "major" release to remove it. (As previously stated, I believe it is ultimately correct to replace it with a function that checks the current testsuite so stateleness and any other source-of-truth problems cannot occur; so I would advocate for doing so eventually.)
  • Until then, we'd want to fix it being incorrect on subsequent runs for consumers of the runner and not just for this built-in behavior.

In other words, if runner.hasOnly is public, I think the right thing to do may be to table this PR in favor of #2934 or something like it, and instead use my recommendations (remove setting the hasOnly property to ensure it can no longer be used, fix failing tests by updating uses to use the hasOnly function) when the time comes to make a "major" release.

(That's not my preferred course of action in principle simply because I'd rather get the root cause corrected now, but backwards compatibility of public interfaces would necessitate it if runner.hasOnly is meant to be public...)

@boneskull
Copy link
Contributor

if it's documented or marked @api or @public then yes. otherwise search github and see if anyone is consuming it (unlikely but you never know).

I have no problems with a major release. lets fix root causes.

@ScottFreeCode
Copy link
Contributor

Quick assessment on that:

  • Runner's this.hasOnly is only used in Runner.prototype.run, which is public but does not document hasOnly in the comment; no other reference to hasOnly the property is in lib/runner.js (the only other hasOnly is the function).
  • runner.hasOnly is set by the Mocha.prototype.run function, which is public but merely copies the property from its this.options, with no mention of this.options in its comment doc.
  • this.options is set by the Mocha constructor, which is public but has a list of options that hasOnly is not one of.
  • There are no other mentions of hasOnly in lib/mocha.js either.
  • lib/interfaces/common.js sets mocha.options.hasOnly in its only functions and (redundantly?) in one of the create functions. None of these are documented in comments as being public -- the whole file seems to be intended for implementing the actual interfaces. (Speaking of which, the proposed change should not have any additional backwards-compatibility issues with properly written custom interfaces, as the interface would currently need to be setting both hasOnly and _onlyTests/_onlySuites, and we'd merely be making the former ignored in favor of the latter.)
  • No other files besides these three reference hasOnly.

Seems like a bit of a side-channel on top of everything else...

@jsf-clabot
Copy link

jsf-clabot commented Aug 9, 2017

CLA assistant check
All committers have signed the CLA.

@ddneat
Copy link
Contributor Author

ddneat commented Aug 9, 2017

Wow, just failed rebasing that one. Will fix that.

@coveralls
Copy link

Coverage Status

Changes Unknown when pulling 46e82ed on davidspinat:issue-2429 into ** on mochajs:master**.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.04%) to 89.062% when pulling e723bda on davidspinat:issue-2429 into 075bd51 on mochajs:master.

@ddneat
Copy link
Contributor Author

ddneat commented Aug 9, 2017

@ScottFreeCode @boneskull

Just updated the PR to include the requested changes. Please let me know if i didn't manage to meet your feedback. I'm happy to help.

  • Rebase with master
  • Remove all additional occurrences of the hasOnly property

Cheers.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.02%) to 89.042% when pulling 6486de0 on davidspinat:issue-2429 into 075bd51 on mochajs:master.

@ScottFreeCode
Copy link
Contributor

ScottFreeCode commented Aug 11, 2017

[Editted to add] TL;DR: It doesn't look like this will affect anyone on GitHub if we remove runner.hasOnly but keep options.hasOnly; but even if we remove them both it doesn't look like we're likely to affect more than a couple uses total.

Went through all the GitHub code results (yes, all forty pages) for hasOnly extension:js extension:coffee extension:ts extension:typescript extension:flow extension:es extension:mjs extension:jsx (also looked at extension:cs but it gave me seven pages of C# and no CoffeeScript) and here's what I found:

I'm marking my prior request for changes as having been satisfied, in any case.

@ScottFreeCode
Copy link
Contributor

Still trying to figure out if I'm merging master into this correctly (which was necessary because conflicts); there's one failing test, looking into that.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.03%) to 89.164% when pulling 176ca11 on davidspinat:issue-2429 into 81e16c6 on mochajs:master.

lib/runner.js Outdated
@@ -429,7 +429,7 @@ Runner.prototype.runTest = function (fn) {
if (!test) {
return;
}
if (this.forbidOnly && this.hasOnly) {
if (this.forbidOnly && hasOnly(this.parents().reverse()[0])) {
Copy link
Contributor

Choose a reason for hiding this comment

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

...Just realized this still isn't right, because it won't work for tests outside of any describe. Remind me to add a test for that, but first, gonna fix this and merge...

@coveralls
Copy link

Coverage Status

Coverage increased (+0.03%) to 89.164% when pulling 2a2cdc5 on davidspinat:issue-2429 into 4cbaec7 on mochajs:master.

@ScottFreeCode ScottFreeCode merged commit f01f66e into mochajs:master Sep 29, 2017
@boneskull boneskull removed the status: needs review a maintainer should (re-)review this pull request label Dec 12, 2017
sgilroy pushed a commit to TwineHealth/mocha that referenced this pull request Feb 27, 2019
 (mochajs#2544)

* Fix .only() behaviour when running with watch option

* Remove all occurrences of the hasOnly property
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
semver-patch implementation requires increase of "patch" version number; "bug fixes"
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants