-
Notifications
You must be signed in to change notification settings - Fork 778
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: Allowed nested suites/modules #670
Conversation
@dcherman @gibson042 @mmun @stefanpenner: This may be of interest to you. 💪 |
❤️ |
Very quiet here... making me nervous. 😅 |
Sheesh; give us a minute. 😀 Is this intended primarily to demonstrate implementation of previously-agreed API changes, or a possibility for said API changes? I ask because @Krinkle grabbed me in Chicago for some noodling on an assertion grouping API that was recursive, flexible, and intuitive, but still "felt" like QUnit. I don't think he's shared the result yet, but here's the gist: https://gist.github.com/Krinkle/8d696b013ba99ff1cc0d#file-20-unified-test-group-js. The basic idea there was making |
The latter, I suppose: prove that it is actually fairly trivial to implement the same nested functionality provided by pretty much every other JS unit testing framework. This also provides basically the same non-verbose API as all of the others, when coupled with the simple IIFE I typically use to make a few important QUnit top-level properties (in this case: I talked with @Krinkle in Chicago about this stuff as well but he and I seem to have differing opinions here. His primary aim seems to be providing an API that is different and/or more explicit than other JS unit testing framework, whereas I prefer to arrive at the same end without the explicit/verbose nature of having to pass/expect/chain more arguments/parameters than truly necessary (which is really just From the Gist, I could probably accept the API in example "10" ("context") but I think the more extreme version in "20" ("unified test group"), while I understand it, would easily confuse and/or alienate both existing and potential new consumers of the library... at least without using better terminology, examples, and documentation to explain how to use it (i.e. "there are only two things: assertions, and groups of assertions and/or other groups"). Having well-defined concepts for assertions, tests (groups of assertions), and suites (groups of tests and/or other suites) is a standard concept in every unit testing framework that I've ever seen or heard of. @Krinkle's " |
The "unified test group" concept is also not very compatible with any Reporter that comes to mind. What's a "test"? What's a "suite"? How do we track each of them effectively without making our code overly complex to somehow distinguish between them? |
@JamesMGreene sorry i haven't had time to review yet, but this functionality makes me happy. I will try to look into it later this week. |
Don't mind me, I'm just PR-impatient. 😀 |
I largely agreed with @Krinkle, but I'm interested in digging deeper here.
Can you elaborate? I'd like
That looks great. Perhaps also: "groups containing other groups are also known as 'suites' or 'modules' in other test frameworks, including QUnit before version 2.0".
Isn't that more complicated, though? It certainly makes more work when I want to carve out a new subtest (e.g., replacing the containing
I think that's underestimating the audience.
HTML <li class="fail">"suite"<ol>
<li class="pass">"test"<ol>
<li class="pass">assertion</li>
<li class="pass">assertion</li>
</ol></li>
<li class="fail">"test"<ol>
<li class="pass">assertion</li>
<li class="fail">assertion</li>
</ol></li>
</ol></li> Runtime
What do you mean? |
One thing I noticed: The diff in this PR has no occurrence of "async". Especially in the context of the kinda-global before/afterEach method that seems like a big mistake. Otherwise, as mentioned elsewhere, I don't want this to block 2.0, so I'm mostly focused on the remaining pre-2.0 tasks right now. |
I had a further thought that makes me strongly lean towards this option:
Specifically, the module picker, but generally, the fact that only the outermost groups are known before execution starts. And in that sense, I'm even more inclined to point out that what's being offered is not so much "nested suites" as "nested tests". |
I would like to have this one landed for the next version. Even if it's still a 1.x, we could have our first impressions on using the nested suites. |
+1 for infinite-depth nesting. Excited to use this. Thanks guys. |
Actually, that's not true here. The |
I agree with @leobalter on this, plus adding this into a late |
Oh, of course! It's not that code passed to So on that note...
That's the
I think it's out of scope for this PR, but I'd really favor explicitly contextual versions of those, for reasons similar to those that motivated explicitly contextual assertions. There's a hint of it in the last paragraph of #670 (comment) . And a bump on this topic, which I think was lost in the noise: #670 (comment)
My (very late) epiphany has definitely warmed me to this approach, though. Thanks for the clarification, @JamesMGreene. |
execHistory.push( assert.suite.fullName + " -> test2.callback" ); | ||
}); | ||
|
||
suite( "level2", function() { |
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.
Tying invocation of global beforeEach
/afterEach
/test
/suite
functions to suite context by virtue of being executed during a suite callback feels dirty (and exactly like tying invocation of global assertion functions to test context by virtue of being executed during a test callback, which is deservedly on the way out). I know there are backcompat reasons for that behavior with module
, but I think we can do better with this suite
green field.
I'd like them to instead be accessible from either context or arguments, which directly relates to (and partly refutes) the end of #670 (comment) . How to do so may be a matter of great bikeshedding, though. Some of my own goals on that point are as follows, in no particular order:
- Intuitively-readable invocations, possibly paradigm-dependent (e.g., use of BDD names)
- Maximum similarity between
suite
andtest
callbacks, for future iterative convergence - Separate concerns (e.g., no properties on
assert
that do not pertain to assertions, since we might want to allow integrating external assertion libraries)
Allows modules to be nested. This is achieved by adding a function argument to the QUnit.module method, which is a function that is called for immediate processing. Also, testEnvironments for parent modules are invoked in recursively for each test (outer-first). Fixes qunitjs#543 Closes qunitjs#800 Closes qunitjs#859 Closes qunitjs#670 Ref qunitjs#858
Fixes #543
Closes #670
Debatably a work-in-progress... but... it works pretty well so far! 👍
For the sake of comparison (and so I didn't go crazy), I chose to implement this functionality in a separate API method,
QUnit.suite
, rather than trying to makeQUnit.module
work in 2 very different ways. They can conceivably be combined, though.Another note of interest in how I chose to make suites work differently than modules: every test inside of a suite gets its own atomic context object that can be modified along the way by every level's
beforeEach
/afterEach
calls. Conversely, using modules, every test within that module shares a shallow copy of the same context object.