-
Notifications
You must be signed in to change notification settings - Fork 781
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
Not strict mode safe #1557
Comments
Yikes, that should indeed just work as expected. E.g. because it's easier that way for a particular way of running tests, or even if by accident. There's no reason not to support it and it's easy to do so indeed. @ef4 Could you link to an example of how you run tests in a browser such that qunit itself ends up processed by a bundler? I'm curious to see how and why this is done, learning that would enable me to better test for and support that in the future, and could inspire ecosystem improvements to reduce manual setup for new projects. I ask because we usually recommend just dropping qunit as-is into a test page or test runner, typically right before importing your application code, dependencies/polyfills, and test suites (which may be bundled, if needed or helpful.) I've tagged this as help-welcome; feel free to submit a PR. Otherwise, I'll probably patch it for you during the next release prep in a week or two. Thanks for reporting! |
I kinda want to flip the question around and ask what this really means to you:
because the QUnit docs are silent on the topic of how to consume QUnit in the browser from NPM. I can certainly write some manual transformation that will do It comes down to what other commenters said already in #1551. Getting qunit into the page via an import is preferable to a script tag because it's just better aligned with how NPM works. NPM packages don't naturally expose URLs, they only offer My specific use case is that I'm working on making it possible to build Ember apps with a variety of different build tools, including webpack and snowpack. All Ember apps default to using qunit and their test blueprints import it, like here. How that is implemented has shifted over time, and in current stable releases qunit is running through webpack and that works OK. It was my attempt to run it through snowpack that inspired this issue, because snowpack uses entirely browser-native ES modules, and so tries to wrap QUnit in an ES module. |
This fixes qunitjs#1557 by adopting [globalThis](https://github.com/tc39/proposal-global), and polyfilling it for environments that don't implement it yet via `@ungap/global-this`.
This fixes qunitjs#1557 by adopting [globalThis](https://github.com/tc39/proposal-global), and polyfilling it for environments that don't implement it yet via `@ungap/global-this`.
This fixes qunitjs#1557 by adopting [globalThis](https://github.com/tc39/proposal-global), and polyfilling it for environments that don't implement it yet via `@ungap/global-this`.
This fixes qunitjs#1557 by adopting [globalThis](https://github.com/tc39/proposal-global), and polyfilling it for environments that don't implement it yet via `@ungap/global-this`.
This fixes qunitjs#1557 by adopting [globalThis](https://github.com/tc39/proposal-global), and polyfilling it for environments that don't implement it yet via `@ungap/global-this`.
When bundling qunit as a library in another build, the use of `this` would cause an error strict mode due to being undefined there. Adopt [ES2020 globalThis](https://github.com/tc39/proposal-global), and polyfill it for environments that don't implement it yet. Fixes #1557. Closes #1558.
I understand that the context you're in needs a different answer, but in general whether the library is downloaded from npm is in my opinion orthogonal to how a test suite is written or run with a browser. When debugging, or using a runner that takes an HTML file and static directory and serves it up and listens for events from a test framework, then you add qunit to that HTML file the same way as you would your main application and test files (or if they're bundled, then you load it from the same place as you load your bundle). For example: <!DOCTYPE html>
<link rel="stylesheet" href="node_modules/qunit/qunit/qunit.css">
<div id="qunit"></div>
<script src="node_modules/qunit/qunit.js"></script>
<script src="dist/bundle.js"></script> This is documented in the Intro (though we should probably default the example to node_modules instead of recommending use of the CDN, which feels pretty weird looking at it now). This is all you need to do load QUnit when using For some test runners, it is possible (or required) to let the HTML be managed for you. These tend to have a config file where you list the JS file paths. You already specify the path to your bundle there, and if not done automatically, one would also specify the path to qunit there. For example, Karma takes an array of
This is the kind of code a bundler like Rollup, or framework like Karma might have internally. As individual project using QUnit that should never be needed indeed. I would expect that whatever minimal configuration is needed to tell the test runner where your bundle is, or where your code and test suites are, would also be where you can tell it where qunit.js is. (Similar for Mocha or Jasmine, I would expect.) In my experience, such runners don't have a need to expand these into URLs or remap them, but if that's the case then that would presumably work the same way for qunit.js as for bundle.js or tests.js.
This is a new perspective for me, so bear with me for a minute. I think it's different from the other dependencies because it isn't a library that your code or your tests depend on to call utility methods from. QUnit is managing the test execution itself, as an application. It also exposes a singleton API as In my view, importing it is more likely to cause unwanted side-effects, and generally more effort to set up and maintain - compared to including it side-by-side with your own code as standalone app. Having said that, I'm sure my preferred approach has other limitations that can't think of right now. My own preferences aside, QUnit is simple and flexible and as a project it should not be opinionated on things like this. Whichever approach you take, it should Just Work ™, out-of-the-box, and do the best it can do within the strengths and limitations native to that approach. I understand from @rwjblue 's review that this is a regression in 2.14, which makes it doubly bad. I'll cut patch release later this week. Thanks! |
Thank you for merging and releasing. I can give you a concrete list of things that fail to work out-of-the-box when QUnit must be consumed via
Each of these issues becomes a non-issue when you use ES modules instead. You just get to delete all the config mentioned above.
As a core contributor to one of the most frameworky frameworks out there (Ember), this is not an alien concept to me. But we have found that it's better to give users access to framework methods via imports than via globals. There is far better tooling support for the imports. It really doesn't matter who is ultimately at the top of the callstack. At the point where the user's code is calling some part of QUnit, that is a function call across a package boundary, and that is what ES imports are designed for. |
Thanks, these definitely help see the balanced perspective. Basically, for linting I think listing the QUnit global in the test directory is not very different from enabling Web APIs in a /src/client directory, or Node APIs in a /src/server/ directory etc. In practice, I think one would benefit from going a step further and use eslint-plugin-qunit which would need to be enabled from the eslint config for the test directory, and takes cares of the global automatically. TypeScript definitions are also available by default for QUnit (not yet bundled, but will be in the future). I won't respond in detail to the other points, other than to say I don't think there's any need to build, transform, or create endpoints of any kind for QUnit. It is already distributed as ready-for-use application. You only need one build for your own code (if your code requires building), and in the HTML file or abstraction thereof where you point to your artefact, you also point to All in all, I think our approaches both involve some amount of trade-off and added cost which we may consider significant or negligible depending on our familiarity and available automation. Both offer a range of benefits, and we choose differently. No problem with that! I'm glad this little bug makes that work again, and I do understand this represents a notable part of the ecosystem. |
You keep saying that, but that's not actually correct. There are many scenarios, including ones that use only stock NPM, where that breaks. For example, NPM 7 now supports workspaces, so NPM may unilaterally choose to move qunit from |
can we re-open this? this is pretty important. We don't need to be supporting legacy environments, and we can ship ESM native packages now (which are strict mode by default, which is a feature of ESM) that would still be compatible everywhere. I'd like to split the qunit package as well.
|
As distributed on NPM, qunit is not strict-mode safe. It relies on global
this
.The reason this matters is that people are increasingly relying on the browser's native module loader to pull in all dependencies during development (snowpack, vite). These tools can wrap the vast majority of NPM packages up as modules to achieve interoperability, but they can't readily escape the strict mode requirement imposed by modules.
Strict mode has been javascript best practice for twelve years now. All qunit's own source is already authored under strict mode. It's only the published build that relies on non-strict behavior.
This issue could be resolved by publishing an ESM build as discussed in #1551, but it could also be resolved with a smaller change by switching to a different technique for locating
globalThis
.globalThis
is now a stable (stage4) ECMAScript feature, and there are broadly-compatible polyfills for it that take care of cross-engine issues.The text was updated successfully, but these errors were encountered: