-
Notifications
You must be signed in to change notification settings - Fork 779
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: Run before and after hooks with module context #1762
Core: Run before and after hooks with module context #1762
Conversation
cce3272
to
b28e8b2
Compare
This should make it significantly more robust and easier to see what's actually going on, primarily to help review qunitjs#1762.
(continuing in main-thread, responding to comment about @raycohen Yeah, read-only could be a compromise here. So what we have today:
I see a couple of options:
Summary:
|
This should make it significantly more robust and easier to see what's actually going on, primarily to help review qunitjs#1762.
This should make it significantly more robust and easier to see what's actually going on, primarily to help review #1762.
8692e50
to
1cea733
Compare
test/main/modules.js
Outdated
'child-after: before=PC beforeEach=PC tester=2 afterEach=CP', | ||
'parent-after: before=PC beforeEach=PC tester=2 afterEach=CP after=C' | ||
'child-after: before=PC', | ||
'parent-after: before=P' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the parent after hook can't see that this.after
was set to C
in the child's after hook, because the assignment becomes one of the child module.testEnvironment
's own properties.
Similarly, it doesn't see the C in this.before
, even though all child checks do.
I would say my initial impression is that it seems odd to include the before and after hooks inside the testStart/testEnd events, so the changed order you have seems clearer or less surprising to me. It does seem like open 1 is the simplest to explain. Without being aware of any use cases for reading and writing there, I might vote for that. It seems like there's a refactor available that likely gets anyone using it for that a way forward? |
@raycohen Yeah, same here. By removing env, we remove importance of the other, and when all else is equal I'd rather not change the ordering there to avoid suble changes in external state in people's code. Sounds like option 1 is a good way forward then! |
Use separate properties to be able to distinguish between own and inherited ones. When "appending" to a property, it effectively copies it do the own object, making it hard to notice whether the properties of a parent module really are copied/preserved at each step, vs only visible at step 1 where it copies it thus masking later bugs where we might forget to extend/mixin the parent env. Also add a test for the module scope callback's context object. Ref #1762.
Use separate properties to be able to distinguish between own and inherited ones. When "appending" to a property, it effectively copies it do the own object, making it hard to notice whether the properties of a parent module really are copied/preserved at each step, vs only visible at step 1 where it copies it thus masking later bugs where we might forget to extend/mixin the parent env. Also add a test for the module scope callback's context object. Ref #1762.
The before and after hooks run once per module as long as there is at least one test in the module. Using environment inheritance allows us to use the module context in those hooks, which allows reading the expected changes to the context from a before hook inside nested modules. Once before hooks have run, create a flattened deep copy of the module testEnvironment and assign that to test testEnvironment. At this point nothing should use test.testEnvironment until the before hooks have run. Fixes qunitjs#1328. Ref qunitjs#869.
759a391
to
75469e5
Compare
I'm slowly comin around around to embracing I was pondering if its worth it and possible to avoid this between modules (in the same way we avoid it between module and test. In QUnit 2.x, all context props are owned by the This patch I believe preserves that for tests, per-test hooks, and non-nested module hooks. But, for nested child modules, the "before" hook would now see a I briefly considered if we could "park" these options and defer env creation until the test execution phase begins (e.g. at the "before" hook). However that would mean QUnit.module('parent', { foo: 1 }, function () {
this.foo++;
QUnit.module('child', { bar: 1 }, function () {
// sees this.foo=2 and this.bar=1
var foo = this.foo;
var bar = this.bar;
QUnit.test('example', function (assert) {
assert.equal(foo, 2, 'foo');
assert.equal(bar, 1, 'bar');
});
});
}); I'll cover this with a test, but it shows there's a need to create the env object earlier. The only way to create it correctly and use that same object throughout, is with inheritence. We can't realistically defer env creation, because the callback needs something usable right away. If we really wanted to avoid this behaviour change, we could go deeper and flatten it like today, and also park it for later, and re-create it. But, I think that trades one set of surprises for another. Given we're doing a semver-major, I'd say let's do this more cleanly as you have it, and document that anything hasOwn-filtering for loops can safely stop doing so. We already guruantee env to be a plain object by copying props. The downside is that convenience functions like I guess the remaining question then is: What level of consistency do we want to go for?
@raycohen What do you think? Option 3 feels the purest, but also the largest change. Could a use case benefit from this? I lean towards Option 1 (easy to explain: inheritance exists pre-test, each test clones the current module env; the module env can be seen as a template for the test env), or Option 4 (keep inheritence internal like it is today). |
I think I prefer 1 over 4 because having matching behavior for For 3 I like the implementation but I can't think of any usage-based argument for it. Why would user code care which parent module had set up a given env value? If we go with flattening, a user could manually access that info if they needed, e.g
We could even (in the future, if we realized a compelling use for it) automatically set up a Alternative 2 is interesting but if the goal is behavior the user expects I think Options 1 and 4 are probably better. So, I'm also leaning towards Option 1 |
The before and after hooks run once per module as long as there is at least one test in the module. Using environment inheritance allows us to use the module context in those hooks, which allows reading the expected changes to the context from a before hook inside nested modules.
This is a breaking change from 2.x behavior. Previously the
after
hook ran with the last test's context instead of the module context, which allowed it to access things set onthis
from inside the test. That will no longer be accessible, and some of the tests were relying on that behavior, so I had to refactor them to get that information from variables in scope for both the test and after hook instead.This PR replaces #1559
Fixes #1328.
Ref #869.