The motivation for Intern 4 is to make it easier to author tests with ES6+ features within tests, with or without transpilation.
Want to skim? Here’s the Intern Roadmap which lists our high level status for each Intern release going forward.
Or if you’re curious to know the details for our plans for Intern this year, read on:
Intern 4 Goals
When Intern began, AMD was the only practical way to effectively load modules both in a browser and within Node.js without a compile step. Since then, ES Modules (ESM) have become the preferred standard way of authoring modules, and various tools such as webpack have changed the way people think about module loading and bundling.
Given the diverse perspectives on how to load modules, we are removing module loading from Intern’s purview. While this may seem like we’re offloading work to the user, it will actually simplify test writing in most cases. Rather than requiring projects to adapt to Intern’s AMD environment, Intern 4 will adapt to the user’s environment.
The result is that Intern and its packages will be loaded like any other module, and Intern can be built/optimized for a target environment and/or loader. We believe this will make it simpler for users and developers to understand and use.
Leverage ES6+ and TypeScript as much as possible
Intern 4 has been completely refactored as a collection of packages that leverage modern ES6+ and TypeScript features. TypeScript gives us the benefits of types and interfaces, making our test interfaces predictable with an extra layer of accuracy and clarity.
For TypeScript users, it will be very difficult to accidentally mis-use Intern’s APIs. And for other users, you’ll simply use Intern as a normal package.
Beyond language syntax features, it will be possible to write async tests with features beyond Promises such as generators and async/await. We still have a fair amount of work to do to make instrumentation and functional testing more natural for ES6+ users that want to test non-transpiled code. We’ve also leveraged decorators to simplify writing reporter classes.
Simplify the architecture
Writing a testing stack that can work in any environment often leads to complexity. We’re working to simplify the architecture where possible as part of this refactoring effort. For example, we’re eliminating the ReporterManager class and simply having the Executor itself be the event hub. We’re also consolidating some of the runtime events, e.g. just
testEnd, rather than
As part of the move away from assuming the presence of a module loader, Intern will no longer dynamically load modules. Instead, when the user loads a particular test executor (e.g. Node.js), all relevant code for that environment is loaded, e.g. all usable reporters, interfaces, and utility functions.
Intern will still have hook points to attach custom reporters or interfaces. And there will be convenience APIs for accessing built-in components.
As with previous Intern major versions, we strive to maintain some reasonable level of backwards compatibility. At the very least, users shouldn’t have to completely rewrite all their existing tests, and we should provide an AMD wrapper to try to fully support existing test suites. However, the main goal is to end up with a better, cleaner architecture.
Looking at the Architecture
Overall architectural changes for Intern 4 include:
- Re-implement Intern in TypeScript with detailed typings
- Use environment-specific executors with static module loading
- The active Intern executor will exist as an
internglobal; test scripts will use this global to interact with Intern (e.g., to load interfaces or to examine the config)
- Reporters will be event listeners attached to the executor; any other interested code can also easily listen to intern events
- The browser version will be a single script that includes all Intern code and, when loaded, will implicitly instantiate a test executor
Intern 4 will be used in the following way in different environments:
- Load the Node.js test executor
- Parse command line arguments
- Create an executor instance using the initialize function, passing in configuration data
- The static
Executor.createfunction became a standalone initialize function for improved flexibility
- This will instantiate a Node.js executor and assign it to the
- Load test suites
- Suites, or at least the application code being tested (which will generally be loaded by suites) must be loaded after the test executor has been created for instrumentation (code coverage analysis, etc.) to work
- Run the executor
- Load the browser script in a test page with a <script> tag
- This will instantiate a Browser test executor and assign it to a global
- Parse query arguments
- Configure the test executor (
- Load suite scripts
- Run the test executor
This will work much like the Node.js case, but the test executor can also be provided a list of paths to unit test suite modules and the path to a loader script. The unit tests will be loaded (using the provided loader script, if specified) and run in unit test mode in remote browsers.
While we’re hopeful that the completion of our above-stated goals will address many of the open issues today, we also have our hearts set on improving Intern’s existing features including intern-cli, SeleniumTunnel, performance benchmarking, visual regression, and accessibility testing. And here we’ll also mention that we still have our sights set on:
- Cucumber integration
- Improved testing sandbox
- Re-evaluating test authoring
- Simplifying the swap of core features such as assertion libraries and WebDriver implementations
Help Us Grow the Intern Community
While it’s heartening to see growing community involvement, we have a lot of work to do! Here are a few ways you can contribute to this project:
- Provide fixes, bugs, documentation, and examples
- Have your company sponsor the development of features!
- Introduce your peers to Intern
- Discuss Intern’s benefits at Meetups, internal brownbags and on social media
- Join the SitePen team for guaranteed contributor time!
- Invite SitePen to present Intern at your next event