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

Core: Introduce before/after hooks for modules #919

Closed
wants to merge 1 commit into from

Conversation

trentmwillis
Copy link
Member

As discussed in #893. Included tests for the following in support of this feature:

  • before runs before beforeEach
  • after runs after afterEach
  • after only runs after last test in module
  • before only runs before first test in module
  • first test supports before with a promise
  • last test supports after with a promise
  • first test supports before with an assert.async
  • last test supports after with an assert.async
  • support nested module before hooks
  • support nested module after hooks
  • context changes made in before are applied to all tests

@trentmwillis trentmwillis force-pushed the before-after branch 2 times, most recently from a46c1b9 to 64b93ea Compare January 15, 2016 22:05
@trentmwillis
Copy link
Member Author

@leobalter I think this is ready for review. Tried my best to keep the implementation within existing constructs, but required a few new properties to get all the features/behavior this should support.

@@ -56,11 +58,14 @@ extend( QUnit, {
var module = {
name: moduleName,
parentModule: parentModule,
tests: []
tests: [],
testsRun: 0
Copy link
Member

Choose a reason for hiding this comment

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

this might be my only concern on this PR. Exposing a new detail on the API conflicts with the plans for the EventEmitter changes (#882).

Although, the tests array will still prevail and I wonder if we can set an equivalent property on the reference object for the test on that array. Doing that, we would have the tradeoff to filter the array, but it would save us a new API exposure.

Copy link
Member Author

Choose a reason for hiding this comment

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

Looking at the "events details types" issue, I think we would be able to replace module.testsRun with module.status.total when it is implemented since it looks like it will be similar.

I would also be fine with setting an equivalent property on the tests array, though it feels a little less correct.

Copy link
Member

Choose a reason for hiding this comment

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

Looking at the "events details types" issue, I think we would be able to replace module.testsRun with module.status.total when it is implemented since it looks like it will be similar.

👍 that would be great!

Copy link
Member Author

Choose a reason for hiding this comment

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

In the interim, should we proceed with this current implementation? (After I clean up the style issues, of course.)

Copy link
Member

Choose a reason for hiding this comment

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

Yes, sure.

We will need to have the API docs on http://github.com/jquery/api.qunitjs.com to be able to land it, would you mind to help on that part too?

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'll open a PR documenting the new before/after hooks for module. Is there anything else I should document?

Copy link
Member

Choose a reason for hiding this comment

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

I believe they'll be enough for now, QUnit docs will probably face a whole logging details review on a near future.

@leobalter
Copy link
Member

The tests look great and I like the implementation.

My concerns remained only on the API as in #919 (comment)

Other noticed minor style issues for missing spaces between parenthesis, which are not blockers.

@trentmwillis
Copy link
Member Author

Updated the PR (think I got all the style issues).

test.preserveEnvironment = true;
}

if ( hookName === "after" && hookOwner.testsRun !== numberOfTests(hookOwner) - 1 ) {
Copy link
Member

Choose a reason for hiding this comment

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

a small style issue here numberOfTests(hookOwner) => numberOfTests( hookOwner )

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, missed one.

@trentmwillis trentmwillis changed the title [WIP] Core: Introduce before/after hooks for modules Core: Introduce before/after hooks for modules Jan 19, 2016
delete this.module.testEnvironment.beforeEach;
delete this.module.testEnvironment.afterEach;
delete this.module.testEnvironment.after;
Copy link
Member

Choose a reason for hiding this comment

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

This may require treating the change as breaking. @leobalter?

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 think so. We have this delete statement only because we're introducing new properties to the modules' hook: before and after. Anyone previously extending that module with these keywords would get their tests affected.

That same could happen when we moved setup and teardown to beforeEach and afterEach. Similarly we could mention the introduction of QUnit.skip to the API that could interfere with any other use of custom made methods.

Copy link
Member

Choose a reason for hiding this comment

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

Anyone previously extending that module with these keywords would get their tests affected.

Exactly. Code like QUnit.module( name, { after: new Date(2016, 0, 1) }, … ), which is currently supported, will be broken. This is why I abhor the conflation of module options and test context in a single parameter, but there it is. And it's different from adding QUnit.skip because QUnit is our object, but that parameter is explicitly wide open for users, minus our exceptions.

Anyway, while maybe not a huge deal, this is technically breaking.

Copy link
Member

Choose a reason for hiding this comment

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

This is why I abhor the conflation of module options and test context in a single parameter

We should discuss a way to solve this before 2.0. Maybe we need to isolate the hooks from the environment or event remove the possibility to define env values on this object (let this do its job).

@gibson042
Copy link
Member

I wonder if this should cover edge cases like delaying the definition of a test. They're a bit pathological, but it would still be bad to run an after hook more than once.

@trentmwillis
Copy link
Member Author

@gibson042 is that a real use case? If so, I don't really see a realistic way to handle it other than making an explicit declaration of the number of tests your module should have, since we need advanced knowledge of whether or not another test is expected to run.

@leobalter
Copy link
Member

@trentmwillis: is that a real use case?

That example reflects tests added through async files loading, as in AMD. A dirty check could use a global variable to tell they are added.

Anyway, I also believe it's a developer responsibility to organize well tests introduced asynchronously. An update to the example - where I only added a single line: reveals a structure antipattern: https://jsfiddle.net/obuj0czg/1/

@trentmwillis
Copy link
Member Author

Okay, makes sense. Should I attempt to cover that use case? Based on the example you gave, it probably doesn't make much sense without guaranteeing what module a test belongs to

@leobalter
Copy link
Member

Should I attempt to cover that use case?

I believe a simple timeout example is enough to cover it up, testing it works properly on async operations and it does not leak anywhere else. AMD cases will be the responsibility for those who implements it.

@gibson042
Copy link
Member

Anyway, I also believe it's a developer responsibility to organize well tests introduced asynchronously. An update to the example - where I only added a single line: reveals a structure antipattern: https://jsfiddle.net/obuj0czg/1/

Right, pathological. 😄

@gibson042
Copy link
Member

Sorry about the noise. But my point was that we should add documentation and assertions that lock down how after behaves in such cases (either "invoked exactly once, and therefore ignored delayed tests" or "invoked whenever the module's test queue is empty, and therefore after delayed tests").

@trentmwillis
Copy link
Member Author

"invoked whenever the module's test queue is empty, and therefore after delayed tests"

Sorry if I'm missing something obvious, but going back to my earlier point, if a test definition is delayed, then it may not get added to the module's test queue until after the module has already emptied it's test queue. How do we notify the module that even though it has ran all of it's tests, it should not run the after hook until more tests are added and ran?

@gibson042
Copy link
Member

How do we notify the module that even though it has ran all of it's tests, it should not run the after hook until more tests are added and ran?

We don't. We just document and assert our behavior, which will take one of two forms:

  • Invoke after exactly once. Tests added after its invocation will have to manage their own cleanup.
  • Invoke after whenever the module's test queue becomes empty. Tests added after its first invocation will result in successive invocations, and users employing such patterns must structure it to accommodate.

I'm just forcing the above as an explicit choice, rather than an accident of implementation.

@trentmwillis
Copy link
Member Author

I'm just forcing the above as an explicit choice, rather than an accident of implementation.

Okay, cleared that all up. Currently the implementation means your second option is true (it will result in successive invocations), though I think the first option makes more sense. This is because I imagine after callbacks will often pair with before callbacks, which are only run once.

If that makes sense, I'll add a test for that here and document it in the documentation PR.

@leobalter
Copy link
Member

If that makes sense, I'll add a test for that here and document it in the documentation PR.

@trentmwillis ++.

do you mind? It would be great to have it tested and documented.

@trentmwillis trentmwillis force-pushed the before-after branch 2 times, most recently from d4e3c5d to b4694d6 Compare January 28, 2016 18:02
@trentmwillis
Copy link
Member Author

@leobalter updated with a test and updated the doc PR as well. Travis failed but it looks like it's for the same reason the master build is failing currently.

@leobalter
Copy link
Member

I'm sick of browserstack-runner timeouts.

@trentmwillis
Copy link
Member Author

@leobalter @gibson042 is the only remaining question whether or not we should consider this breaking? If so, I'd be fine with feature-flagging this somehow or delaying merge until 2.0.

@leobalter
Copy link
Member

@trentmwillis, I really want to merge and release a new version with it, but I might need to release a major version.

I'm running on other necessary changes (the warning api) to release the next major, so releasing this feature won't be a problem.

@trentmwillis
Copy link
Member Author

@leobalter a major version sounds good. Will let this sit until ready then.

@stefanpenner
Copy link
Contributor

@trentmwillis good work!

@leobalter leobalter mentioned this pull request Mar 25, 2016
@leobalter leobalter added this to the v2.0 milestone Mar 25, 2016
@trentmwillis
Copy link
Member Author

@leobalter this has been rebased and should be good to go. Care to do a once over since it's been awhile?

@leobalter leobalter closed this in d452da1 Apr 18, 2016
flore77 pushed a commit to flore77/qunit that referenced this pull request Aug 10, 2016
@trentmwillis trentmwillis deleted the before-after branch March 2, 2018 16:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

5 participants