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

feat: ability to run unit tests in browser #880

Merged
merged 1 commit into from
Apr 11, 2024

Conversation

DudaGod
Copy link
Member

@DudaGod DudaGod commented Mar 21, 2024

What is done

The ability to run tests in a browser environment is implemented (previously, it was possible to run only in nodejs env). Now you can run the unit tests in the browser. The launch of the component tests will be implemented in the next PR.

To run browser tests, you must specify system.testRunEnv: "browser". And to use your vite config - system.testRunEnv: ["browser", {viteConfig: {...}}]. Browser tests are run separately from tests in node js.

Implementation scheme:

Vite is used as the server that compiles the test code and displays it in the browser. All browser tests go to the url of the vite server. Vite also has presets with support popular frameworks: react, vue, etc.

The logic about launching browsers, managing them, and reading tests in the master and the worker process has not changed. Only a new browser runner has been added, which start the Vite server and sets up communication between workers and browsers via websocket. It also generates the necessary index.html page in memory that the browser opens. On this page, mocha is connected, which downloads passed test file, parses all the tests and saves them in its data structure. The worker is responsible for starting the launch of hooks (beforEach, afterEach) and tests (it). Which sends a vite message via the websocket which test needs to be run. fullTitle is used to identify which runnable must be run. The browser launches the required runnable and returns the result. If there were errors, the test fails, and if everything is OK, the test is successful.


User documentation will be added along with the implementation of component testing (next PR).

@@ -8,7 +8,7 @@
"typings"
],
"scripts": {
"build": "tsc && npm run copy-static && npm run build-bundle -- --minify",
"build": "tsc --build && npm run copy-static && npm run build-bundle -- --minify",
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 order to build browser modules separately (used esm)

"glob-extra": "5.0.2",
"import-meta-resolve": "4.0.0",
Copy link
Member Author

Choose a reason for hiding this comment

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

ponyfill for import.meta.resolve from esm

Copy link
Member

Choose a reason for hiding this comment

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

🐴fill =)

src/config/defaults.js Show resolved Hide resolved

testRunEnv: option({
defaultValue: defaults.testRunEnv,
validate: value => {
Copy link
Member Author

Choose a reason for hiding this comment

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

Valid values:

  • nodejs
  • browser
  • ["browser", {viteConfig: string | object | function}]

src/hermione.ts Outdated
@@ -82,7 +84,10 @@ export class Hermione extends BaseHermione {
this._config.system.mochaOpts.timeout = 0;
}

const runner = MainRunner.create(this._config, this._interceptors);
const runner = (isRunInNodeJsEnv(this._config) ? NodejsEnvRunner : BrowserEnvRunner).create(
Copy link
Member Author

Choose a reason for hiding this comment

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

depending on the value in testRunEnv run nodejs runner or browser runner

}: WaitMessageOpts): Promise<BrowserPayload> {
return new Promise((resolve, reject) => {
const timerId =
timeout > 0
Copy link
Member Author

Choose a reason for hiding this comment

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

If repl mode is use then it set runnable.timeout = 0 so I don't need to use any setTimeout

import type { Test } from "../../../../test-reader/test-object/test";
import type { Hook } from "../../../../test-reader/test-object/hook";

export const wrapExecutionThread = (runUuid: string): typeof NodejsEnvExecutionThread => {
Copy link
Member Author

Choose a reason for hiding this comment

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

Solution which gives me ability to pass runUuid and generate ExecutionThread class for browser. I use it because ExecutionThread class is used inside NodejsEnvTestRunner and I need some api to set it, but ExecutionThread from nodejs don't need this.

}

async _call(runnable: Test | Hook): Promise<void> {
const cmdUuid = crypto.randomUUID();
Copy link
Member Author

Choose a reason for hiding this comment

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

generates uniq for each event

return super.run({ ...opts, ExecutionThreadCls: wrapExecutionThread(this.#runUuid) });
}

_getPreparePageActions(browser: Browser, history: BrowserHistory): (() => Promise<void>)[] {
Copy link
Member Author

Choose a reason for hiding this comment

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

redefine method from parent in order to be able run action before user hook/test

@@ -117,6 +118,19 @@ module.exports = class TestRunner {
return results;
}

_getPreparePageActions(browser, history) {
Copy link
Member Author

Choose a reason for hiding this comment

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

Add API to be able to redefine it through browser runner

@DudaGod DudaGod force-pushed the HERMIONE-1421.run_tests_in_browser branch 2 times, most recently from f6f2c1d to 1aeb516 Compare March 21, 2024 17:59
Copy link
Member

@shadowusr shadowusr left a comment

Choose a reason for hiding this comment

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

Overall, really cool addition! I have no critical review issues.

Left a few questions and comments below, also discussed if it's worth it to consider using socket.io and separate WS server in the future. For now, I don't think any severe changes are necessary and it's surely better to get this shipped faster.

src/config/defaults.js Show resolved Hide resolved
src/runner/browser-env/index.ts Show resolved Hide resolved
src/runner/browser-env/index.ts Outdated Show resolved Hide resolved
src/runner/browser-env/vite/server.ts Outdated Show resolved Hide resolved
src/runner/browser-env/vite/browser-modules/globals.ts Outdated Show resolved Hide resolved
src/worker/browser-env/communicator.ts Outdated Show resolved Hide resolved
src/runner/browser-env/vite/plugins/generate-index-html.ts Outdated Show resolved Hide resolved
@DudaGod DudaGod force-pushed the HERMIONE-1421.run_tests_in_browser branch 2 times, most recently from bf2f69a to 66e0bd1 Compare March 29, 2024 19:47
@DudaGod DudaGod force-pushed the HERMIONE-1421.run_tests_in_browser branch from 66e0bd1 to ff047db Compare April 11, 2024 00:04
@DudaGod DudaGod force-pushed the component_testing branch 2 times, most recently from cc72645 to 02af7e2 Compare April 11, 2024 00:27
@DudaGod DudaGod force-pushed the HERMIONE-1421.run_tests_in_browser branch 2 times, most recently from cf51ec1 to d000370 Compare April 11, 2024 01:19
@DudaGod DudaGod force-pushed the HERMIONE-1421.run_tests_in_browser branch from d000370 to 5a76453 Compare April 11, 2024 01:30
@DudaGod DudaGod merged commit 8c12290 into component_testing Apr 11, 2024
2 checks passed
@DudaGod DudaGod deleted the HERMIONE-1421.run_tests_in_browser branch April 11, 2024 01:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants