Skip to content
This repository has been archived by the owner on Mar 24, 2024. It is now read-only.

Commit

Permalink
Improve Jest performance (#640)
Browse files Browse the repository at this point in the history
On my M1 MacBook Air I can now run **all** the tests in about 16 seconds. Running a single small test file is down from 15sec to <2sec.

There were a few components to this:
- Jest would take several seconds to load `jest.config.ts` files (jestjs/jest#11337). Fixed by replacing them with `jest.config.json` files.
- Jest tries to use the native `find` if available over node fs, but it doesn't pass any exclude options to find, which means that it has to wait a few seconds for `find`, then filter a huge list of all .js files in app/node_modules. Upgrading jest lets us pass a config option to force it to use node fs instead (jestjs/jest#11264 (comment)).
- `jsdom` is no longer the default environment in jest, and there is some overhead to jsdom. We are embracing this change by only enabling jsdom in certain test files that need it. Unfortunately Jest only recognizes the `/** @jest-environment jsdom */` comment if it is at the very beginning of the file, so I had to replace our eslint-plugin-header rule with a custom rule to enforce the presence of license headers.
- Converted the custom `?raw` transformer to .js instead of .ts, since we are not using ts-node anymore.
- Actually executing the test files with ts-jest was slow, because it has to run the TS compiler. Instead we can use babel-jest which doesn't do type checking. kulshekhar/ts-jest#961 (comment) (This also requires enabling `isolatedModules` in tsconfig.) For better or worse, our regular webpack build already typechecks our test files.
  • Loading branch information
jtbandes committed Apr 24, 2021
1 parent 18b06c0 commit 504305c
Show file tree
Hide file tree
Showing 86 changed files with 1,069 additions and 898 deletions.
8 changes: 1 addition & 7 deletions .eslintrc.yaml
Expand Up @@ -16,7 +16,6 @@ plugins:
- react
- react-hooks
- "@typescript-eslint"
- header
- file-progress

extends:
Expand Down Expand Up @@ -88,12 +87,7 @@ rules:
- error
- additionalHooks: "(useAsync(?!AppConfigurationValue))"
no-new-func: error
header/header:
- error
- line
- - " This Source Code Form is subject to the terms of the Mozilla Public"
- " License, v2.0. If a copy of the MPL was not distributed with this"
- " file, You can obtain one at http://mozilla.org/MPL/2.0/"
foxglove-license-header: error

curly: error
"@typescript-eslint/no-unused-vars":
Expand Down
3 changes: 2 additions & 1 deletion .vscode/settings.json
Expand Up @@ -19,7 +19,8 @@
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.preferences.importModuleSpecifier": "non-relative",
"eslint.options": {
"reportUnusedDisableDirectives": true
"reportUnusedDisableDirectives": true,
"rulePaths": ["eslint-rules"]
},
// enable intellisense in custom snippets (see snippets.code-snippets)
"editor.suggest.snippetsPreventQuickSuggestions": false
Expand Down
1 change: 1 addition & 0 deletions app/PanelAPI/useBlocksByTopic.test.tsx
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
1 change: 1 addition & 0 deletions app/PanelAPI/useDataSourceInfo.test.tsx
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
1 change: 1 addition & 0 deletions app/PanelAPI/useMessageReducer.test.tsx
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
1 change: 1 addition & 0 deletions app/PanelAPI/useMessagesByTopic.test.tsx
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
1 change: 1 addition & 0 deletions app/components/ButtonBase.test.tsx
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
1 change: 1 addition & 0 deletions app/components/DocumentDropListener.test.tsx
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
1 change: 1 addition & 0 deletions app/components/ExperimentalFeatureSettings.test.tsx
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
1 change: 1 addition & 0 deletions app/components/GlobalKeyListener.test.tsx
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
1 change: 1 addition & 0 deletions app/components/Icon.test.tsx
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
1 change: 1 addition & 0 deletions app/components/MessagePathSyntax/MessagePathInput.test.ts
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
12 changes: 7 additions & 5 deletions app/components/MessagePipeline/index.test.tsx
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down Expand Up @@ -164,26 +165,27 @@ describe("MessagePipelineProvider/useMessagePipeline", () => {

it("waits for the previous frame to finish before calling setGlobalVariables again", async () => {
const player = new FakePlayer();
jest.spyOn(player, "setGlobalVariables");
const mockSetGlobalVariables = jest.spyOn(player, "setGlobalVariables");
const { result, rerender } = renderHook(Hook, {
wrapper: Wrapper,
initialProps: { maybePlayer: { player }, globalVariables: {} },
});
await tick();
await tick();

expect(player.setGlobalVariables).toHaveBeenCalledWith({});
expect(player.setGlobalVariables).toHaveBeenCalledTimes(1);
expect(mockSetGlobalVariables.mock.calls).toEqual([[{}]]);
const onFrameRendered = result.current.pauseFrame("Wait");

// Pass in new globalVariables and make sure they aren't used until the frame is done
rerender({ maybePlayer: { player }, globalVariables: { futureTime: 1 } });
await tick();
expect(player.setGlobalVariables).toHaveBeenCalledTimes(1);
expect(mockSetGlobalVariables.mock.calls).toEqual([[{}]]);

// Once the frame is done, setGlobalVariables will be called with the new value
onFrameRendered();
await tick();
expect(player.setGlobalVariables).toHaveBeenCalledWith({ futureTime: 1 });
await tick();
expect(mockSetGlobalVariables.mock.calls).toEqual([[{}], [{ futureTime: 1 }]]);
});

it("sets subscriptions", () => {
Expand Down
1 change: 1 addition & 0 deletions app/components/Panel.test.tsx
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
1 change: 1 addition & 0 deletions app/components/ShareJsonModal.test.tsx
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
3 changes: 2 additions & 1 deletion app/components/Tree/index.stories.tsx
Expand Up @@ -17,7 +17,8 @@ import { storiesOf } from "@storybook/react";
import { useState } from "react";

import Menu from "@foxglove-studio/app/components/Menu";
import Tree, { Node } from "@foxglove-studio/app/components/Tree";
import Tree from "@foxglove-studio/app/components/Tree";
import { Node } from "@foxglove-studio/app/components/Tree/Node";

function getInitialState() {
const root = {
Expand Down
3 changes: 0 additions & 3 deletions app/components/Tree/index.tsx
Expand Up @@ -16,9 +16,6 @@ import React, { PureComponent } from "react";
import { Node } from "./Node";
import TreeNode from "./TreeNode";

// export the node flow type
export { Node } from "./Node";

type Props = {
disableCheckbox?: boolean;
enableVisibilityToggle?: boolean;
Expand Down
1 change: 1 addition & 0 deletions app/dataProviders/CombinedDataProvider.test.ts
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
1 change: 1 addition & 0 deletions app/dataProviders/ParseMessagesDataProvider.test.ts
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
1 change: 1 addition & 0 deletions app/dataProviders/RpcDataProvider.test.ts
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
1 change: 1 addition & 0 deletions app/dataProviders/getRemoteBagGuid.test.ts
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
1 change: 1 addition & 0 deletions app/hooks/useContextSelector.test.tsx
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
1 change: 1 addition & 0 deletions app/hooks/usePrompt.test.tsx
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
23 changes: 23 additions & 0 deletions app/jest.config.json
@@ -0,0 +1,23 @@
{
"//": "Note: we use babel-jest rather than ts-jest for performance reasons.",
"transform": {
"\\.tsx?$": "<rootDir>/test/transformers/typescriptTransformerWithRawImports.js",
"\\.ne$": "<rootDir>/test/transformers/neTransformer.js",
"\\.(bin|template|wasm)$": "<rootDir>/test/transformers/rawTransformer.js"
},
"globals": {
"ReactNull": null
},
"setupFiles": ["<rootDir>/test/setup.ts", "<rootDir>/test/setupEnzyme.ts", "jest-canvas-mock"],
"setupFilesAfterEnv": ["<rootDir>/test/setupTestFramework.ts"],
"restoreMocks": true,
"moduleNameMapper": {
"\\.svg$": "<rootDir>/test/mocks/MockSvg.tsx",
"react-monaco-editor": "<rootDir>/test/stubs/MonacoEditor.tsx",
"\\.(glb|md|png)$": "<rootDir>/test/mocks/fileMock.ts",
"\\.(css|scss)$": "<rootDir>/test/mocks/styleMock.ts"
},
"testRunner": "jest-circus/runner",
"//": "Native find is slow because it does not exclude files: https://github.com/facebook/jest/pull/11264#issuecomment-825377579",
"haste": { "forceNodeFilesystemAPI": true }
}
30 changes: 0 additions & 30 deletions app/jest.config.ts

This file was deleted.

1 change: 1 addition & 0 deletions app/package.json
Expand Up @@ -89,6 +89,7 @@
"@storybook/addon-essentials": "6.2.5",
"@storybook/builder-webpack5": "6.2.5",
"@storybook/react": "6.2.5",
"@testing-library/dom": "7.30.1",
"@testing-library/react": "11.2.6",
"@testing-library/react-hooks": "5.1.1",
"@types/argparse": "^2.0.5",
Expand Down
1 change: 1 addition & 0 deletions app/panels/Internals.test.tsx
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
1 change: 1 addition & 0 deletions app/panels/Plot/PlotMenu.test.ts
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
1 change: 1 addition & 0 deletions app/panels/Publish/index.test.tsx
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
1 change: 1 addition & 0 deletions app/panels/ThreeDimensionalViz/FrameCompatibility.test.tsx
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
1 change: 1 addition & 0 deletions app/panels/ThreeDimensionalViz/SearchText.test.tsx
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
1 change: 1 addition & 0 deletions app/panels/diagnostics/DiagnosticsHistory.test.ts
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
1 change: 1 addition & 0 deletions app/players/RandomAccessPlayer.test.ts
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
1 change: 1 addition & 0 deletions app/players/UserNodePlayer/index.test.ts
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
@@ -1,3 +1,3 @@
rules:
# do not require license header for userUtils
"header/header": off
foxglove-license-header: off
1 change: 1 addition & 0 deletions app/players/automatedRun/AutomatedRunPlayer.test.ts
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
2 changes: 1 addition & 1 deletion app/players/types.ts
Expand Up @@ -87,7 +87,7 @@ export interface Player {
setGlobalVariables(globalVariables: GlobalVariables): void;
}

export const enum PlayerPresence {
export enum PlayerPresence {
NOT_PRESENT = "NOT_PRESENT",
CONSTRUCTING = "CONSTRUCTING",
INITIALIZING = "INITIALIZING",
Expand Down
1 change: 1 addition & 0 deletions app/reducers/layoutHistory.test.ts
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
1 change: 1 addition & 0 deletions app/reducers/panels.test.ts
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
1 change: 1 addition & 0 deletions app/reducers/recentLayouts.test.ts
@@ -1,3 +1,4 @@
/** @jest-environment jsdom */
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
Expand Down
2 changes: 1 addition & 1 deletion app/test/mocks/fileMock.ts
Expand Up @@ -2,4 +2,4 @@
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/

module.exports = "test-file-stub";
export default "test-file-stub";
2 changes: 1 addition & 1 deletion app/test/mocks/styleMock.ts
Expand Up @@ -2,4 +2,4 @@
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/

module.exports = {};
export default {};
12 changes: 0 additions & 12 deletions app/test/sentry-stub.ts

This file was deleted.

0 comments on commit 504305c

Please sign in to comment.