Skip to content

Commit

Permalink
feat: ability to read tests in ".jsx" and ".tsx" files
Browse files Browse the repository at this point in the history
  • Loading branch information
DudaGod committed Feb 29, 2024
1 parent e3726ba commit cdba0b9
Show file tree
Hide file tree
Showing 8 changed files with 727 additions and 414 deletions.
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1298,7 +1298,7 @@ The maximum number of tests to be run in one worker before it will be restarted.
By default, `hermione` will run all browsers simultaneously. Sometimes (i.e. when using cloud services, such as SauceLabs) you have to limit the amount of browsers that can be run at the same time. This option effectively limits how many browsers `hermione` will try to run in parallel. Default value is `Infinity`.

#### fileExtensions
Ability to set file extensions, which hermione will search on the file system. Default value is `[.js]`.
Ability to set file extensions, which hermione will search on the file system. Default value is `[".js", ".mjs", ".ts", ".mts", ".jsx", ".tsx"]`.

### plugins
`Hermione` plugins are commonly used to extend built-in functionality. For example, [html-reporter](https://github.com/gemini-testing/html-reporter) and [hermione-safari-commands](https://github.com/gemini-testing/hermione-safari-commands).
Expand Down Expand Up @@ -1619,8 +1619,6 @@ Using `-r` or `--require` option you can load external modules, which exists in
- compilers such as TypeScript via [ts-node](https://www.npmjs.com/package/ts-node) (using `--require ts-node/register`) or Babel via [@babel/register](https://www.npmjs.com/package/@babel/register) (using `--require @babel/register`);
- loaders such as ECMAScript modules via [esm](https://www.npmjs.com/package/esm).

Be sure to update [fileExtensions](#fileExtensions) apropriately, if you are planning to import anything other than `.js`.

### Overriding settings

All options can also be overridden via command-line flags or environment variables. Priorities are the following:
Expand Down
1,000 changes: 590 additions & 410 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@
},
"license": "MIT",
"dependencies": {
"@babel/core": "7.24.0",
"@babel/plugin-transform-modules-commonjs": "7.23.3",
"@babel/plugin-transform-react-jsx": "7.23.4",
"@babel/preset-react": "7.23.3",
"@gemini-testing/commander": "2.15.3",
"@types/mocha": "10.0.1",
"@wdio/globals": "8.21.0",
Expand All @@ -66,6 +70,7 @@
"looks-same": "9.0.0",
"micromatch": "4.0.5",
"mocha": "10.2.0",
"pirates": "4.0.6",
"plugins-loader": "1.2.0",
"png-validator": "1.1.0",
"sharp": "0.30.7",
Expand Down
2 changes: 1 addition & 1 deletion src/config/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ module.exports = {
resetCursor: true,
strictTestsOrder: false,
saveHistoryMode: SAVE_HISTORY_MODE.ALL,
fileExtensions: [".js", ".mjs", ".ts", ".mts"],
fileExtensions: [".js", ".mjs", ".ts", ".mts", ".jsx", ".tsx"],
outputDir: null,
agent: null,
headers: null,
Expand Down
5 changes: 5 additions & 0 deletions src/test-reader/test-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const { TreeBuilder } = require("./tree-builder");
const { readFiles } = require("./mocha-reader");
const { TestReaderEvents } = require("../events");
const { TestParserAPI } = require("./test-parser-api");
const { setupTransformHook } = require("./test-transformer");
const { MasterEvents } = require("../events");
const _ = require("lodash");
const clearRequire = require("clear-require");
Expand Down Expand Up @@ -47,9 +48,13 @@ class TestParser extends EventEmitter {

this.#clearRequireCache(files);

const revertTransformHook = setupTransformHook();

const rand = Math.random();
const esmDecorator = f => f + `?rand=${rand}`;
await readFiles(files, { esmDecorator, config: mochaOpts, eventBus });

revertTransformHook();
}

#applyInstructionsEvents(eventBus) {
Expand Down
47 changes: 47 additions & 0 deletions src/test-reader/test-transformer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import * as babel from "@babel/core";

Check failure on line 1 in src/test-reader/test-transformer.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

Could not find a declaration file for module '@babel/core'. '/home/runner/work/hermione/hermione/node_modules/@babel/core/lib/index.js' implicitly has an 'any' type.

Check failure on line 1 in src/test-reader/test-transformer.ts

View workflow job for this annotation

GitHub Actions / build (20.x)

Could not find a declaration file for module '@babel/core'. '/home/runner/work/hermione/hermione/node_modules/@babel/core/lib/index.js' implicitly has an 'any' type.
import { addHook } from "pirates";

import type { NodePath, PluginObj, TransformOptions } from "@babel/core";

Check failure on line 4 in src/test-reader/test-transformer.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

Could not find a declaration file for module '@babel/core'. '/home/runner/work/hermione/hermione/node_modules/@babel/core/lib/index.js' implicitly has an 'any' type.

Check failure on line 4 in src/test-reader/test-transformer.ts

View workflow job for this annotation

GitHub Actions / build (20.x)

Could not find a declaration file for module '@babel/core'. '/home/runner/work/hermione/hermione/node_modules/@babel/core/lib/index.js' implicitly has an 'any' type.
import type { ImportDeclaration } from "@babel/types";

const TRANSFORM_EXTENSIONS = [".jsx", ".tsx"];

export const setupTransformHook = (): VoidFunction => {
const transformOptions: TransformOptions = {
browserslistConfigFile: false,
babelrc: false,
configFile: false,
compact: false,
plugins: [
[
require("@babel/plugin-transform-react-jsx"),
{
throwIfNamespace: false,
runtime: "automatic",
},
],
require("@babel/plugin-transform-modules-commonjs"),
[
(): PluginObj => ({
name: "remove-css-imports",
visitor: {
ImportDeclaration(path: NodePath<ImportDeclaration>): void {
if (path.node.source.value.match(/\.(css|less|scss)$/)) {
path.remove();
}
},
},
}),
],
],
};

const revertTransformHook = addHook(
(originalCode, filename) => {
return babel.transform(originalCode, { filename, ...transformOptions })!.code as string;
},
{ exts: TRANSFORM_EXTENSIONS },
);

return revertTransformHook;
};
20 changes: 20 additions & 0 deletions test/src/test-reader/test-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,21 @@ describe("test-reader/test-parser", () => {
let TestParser;
let clearRequire;
let readFiles;
let setupTransformHook;
let browserVersionController = {
mkProvider: sinon.stub().returns(() => {}),
};

beforeEach(() => {
clearRequire = sandbox.stub().named("clear-require");
readFiles = sandbox.stub().named("readFiles").resolves();
setupTransformHook = sandbox.stub().named("setupTransformHook").returns(sinon.stub());

TestParser = proxyquire("src/test-reader/test-parser", {
"clear-require": clearRequire,
"./mocha-reader": { readFiles },
"./controllers/browser-version-controller": browserVersionController,
"./test-transformer": { setupTransformHook },
}).TestParser;

sandbox.stub(InstructionsList.prototype, "push").returnsThis();
Expand Down Expand Up @@ -369,6 +372,23 @@ describe("test-reader/test-parser", () => {
assert.notEqual(firstCallModuleName, lastCallModuleName);
});
});

describe("transform hook", () => {
it("should setup hook before read files", async () => {
await loadFiles_({ files: ["foo/bar", "baz/qux"] });

assert.callOrder(setupTransformHook, readFiles);
});

it("should call revert transformation after read files", async () => {
const revertFn = sinon.stub();
setupTransformHook.returns(revertFn);

await loadFiles_({ files: ["foo/bar", "baz/qux"] });

assert.callOrder(readFiles, revertFn);
});
});
});

describe("root suite decorators", () => {
Expand Down
58 changes: 58 additions & 0 deletions test/src/test-reader/test-transformer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import * as pirates from "pirates";
import proxyquire from "proxyquire";
import sinon, { SinonStub } from "sinon";

type SetupTransformHook = typeof import("../../../src/test-reader/test-transformer").setupTransformHook;

describe("test-transformer", () => {
const sandbox = sinon.createSandbox();
let babelTransform: SinonStub;
let setupTransformHook: SetupTransformHook;

beforeEach(() => {
babelTransform = sandbox.stub().returns({ code: "default-code" });

sandbox.stub(pirates, "addHook").returns(sandbox.stub());

({ setupTransformHook } = proxyquire("src/test-reader/test-transformer", {
"@babel/core": { transform: babelTransform },
})).default;
});

afterEach(() => sandbox.restore());

describe("setupTransformHook", () => {
it("should transform '.jsx' and '.tsx' files", () => {
setupTransformHook();

assert.calledOnceWith(pirates.addHook, sinon.match.any, { exts: [".jsx", ".tsx"] });
});

it("should return function to revert transformation", () => {
const revertFn = sandbox.stub();
(pirates.addHook as SinonStub).returns(revertFn);

assert.equal(setupTransformHook(), revertFn);
});

it("should transform code using babel", () => {
let transformedCode;
babelTransform.returns({ code: "transformed-code" });
(pirates.addHook as SinonStub).callsFake(cb => {
transformedCode = cb("original-code", "/path/test.jsx");
});

setupTransformHook();

assert.calledOnceWith(babelTransform, "original-code", {
browserslistConfigFile: false,
babelrc: false,
configFile: false,
compact: false,
plugins: sinon.match.array,
filename: "/path/test.jsx",
});
assert.equal(transformedCode, "transformed-code");
});
});
});

0 comments on commit cdba0b9

Please sign in to comment.