Skip to content

Commit 9bfdda8

Browse files
yurishkuroclaude
andauthored
test: Add mockDefault helper for default-export mocks (jaegertracing#3694)
Add global.mockDefault = mod => mod to jest-per-test-setup.js. Wrap all jest.mock() factories that return a function/component directly with mockDefault(...) across 33 test files. In H3, only the setup file changes: mod => mod → mod => ({ default: mod }) to make all default-export mocks ESM-compatible in Vitest. Also update ADR section 9 / PR table to mark H2c done. ## AI Usage in this PR (choose one) See [AI Usage Policy](https://github.com/jaegertracing/jaeger/blob/main/CONTRIBUTING_GUIDELINES.md#ai-usage-policy). - [ ] **None**: No AI tools were used in creating this PR - [ ] **Light**: AI provided minor assistance (formatting, simple suggestions) - [ ] **Moderate**: AI helped with code generation or debugging specific parts - [x] **Heavy**: AI generated most or all of the code changes Signed-off-by: Yuri Shkuro <github@ysh.us> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 9607033 commit 9bfdda8

34 files changed

Lines changed: 309 additions & 260 deletions

File tree

docs/adr/0007-vite-plus-migration.md

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -386,23 +386,26 @@ called with `new` in production code): `readJsonFile.test.js` (FileReader ×3),
386386
`DeepDependencies/Graph/index.test.jsx` (LayoutManager), `TracePage/index.test.jsx` (ScrollManager ×3),
387387
`TracePage/TraceGraph/TraceGraph.test.jsx` (MockLayoutManager).
388388

389-
#### PR H2c — Introduce `mockDefault` helper in affected mock factories
389+
#### PR H2c — Introduce `mockDefault` helper in affected mock factories ([#3694](https://github.com/jaegertracing/jaeger-ui/pull/3694))
390390

391391
In Vitest ESM, `vi.mock()` factories must return `{ default: MockComponent }` for default-exported
392-
modules; Jest CJS interop does not require this. Instead of leaving the full rewrite to H3, introduce
393-
a helper that makes the flip a one-line change:
392+
modules; Jest CJS interop does not require this. A helper is introduced so the flip in H3 is a
393+
single-line change rather than touching every factory:
394394

395395
```js
396-
// H2c: add to each affected file — Jest passes mod through unchanged
397-
function mockDefault(mod) { return mod; }
398-
jest.mock('./Foo', () => mockDefault(MockFoo));
396+
// test/jest-per-test-setup.js (H3: change body to `{ default: mod }`)
397+
global.mockDefault = mod => mod;
399398
```
400399

401-
In H3, change only the function body to `return { default: mod }`. Jest hoists `jest.mock()` factories
402-
before imports but specifically allows variables whose names start with `mock` in factory scope —
403-
naming the helper `mockDefault` satisfies this constraint.
400+
All ~33 `jest.mock()` factories that return a function/component directly have been wrapped:
404401

405-
Alternatively, attach it to `global` in the per-test-setup file for a single-location flip in H3.
402+
```js
403+
jest.mock('./Foo', () => mockDefault(function MockFoo() { return <JSX/>; }));
404+
jest.mock('./Bar', () => mockDefault(() => <JSX/>));
405+
jest.mock('./Baz', () => mockDefault(jest.fn(() => <JSX/>)));
406+
```
407+
408+
In H3, only `jest-per-test-setup.js` changes: `mod => mod``mod => ({ default: mod })`.
406409

407410
#### PR H3 — The actual switch
408411

@@ -599,7 +602,7 @@ confirm no errors or unexpected HTML injection.
599602
| ✅ H1 | Rename `.test.js``.test.jsx` in jaeger-ui (121 files, pure rename) ([#3691](https://github.com/jaegertracing/jaeger-ui/pull/3691)) | None | Done |
600603
| ✅ H2a | Replace `require()` in test bodies with static `import` ([#3692](https://github.com/jaegertracing/jaeger-ui/pull/3692)) | None | Done |
601604
| ✅ H2b | Replace arrow function constructors with regular functions (6 files) ([#3693](https://github.com/jaegertracing/jaeger-ui/pull/3693)) | None | Done |
602-
| H2c | Introduce `mockDefault` helper in affected mock factories | None | After H1 |
605+
| H2c | Introduce `mockDefault` helper in affected mock factories ([#3694](https://github.com/jaegertracing/jaeger-ui/pull/3694)) | None | Done |
603606
| H3 | Vitest switch for jaeger-ui | Unknowns 3, 4, 5, 6 | After H2a–c |
604607
| G | Update CLAUDE.md, README, CI workflows | None | After H3 |
605608

packages/jaeger-ui/src/actions/jaeger-api.test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
// Copyright (c) 2017 Uber Technologies, Inc.
22
// SPDX-License-Identifier: Apache-2.0
33

4-
jest.mock(
5-
'node-fetch',
6-
() => () =>
4+
jest.mock('node-fetch', () =>
5+
mockDefault(() =>
76
Promise.resolve({
87
status: 200,
98
data: () => Promise.resolve({ data: null }),
109
json: () => Promise.resolve({ data: null }),
1110
})
11+
)
1212
);
1313

1414
function isPromise(p) {

packages/jaeger-ui/src/actions/path-agnostic-decorations.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import * as getConfig from '../utils/config/get-config';
88
import stringSupplant from '../utils/stringSupplant';
99
import JaegerAPI from '../api/jaeger';
1010

11-
jest.mock('lru-memoize', () => () => x => x);
11+
jest.mock('lru-memoize', () => mockDefault(() => x => x));
1212

1313
describe('getDecoration', () => {
1414
let getConfigSpy;

packages/jaeger-ui/src/components/App/NotFound.test.jsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ import { MemoryRouter } from 'react-router-dom';
77
import '@testing-library/jest-dom';
88
import NotFound from './NotFound';
99

10-
jest.mock('../../utils/prefix-url', () => () => '/');
11-
jest.mock('../common/ErrorMessage', () => ({ error }) => (
12-
<div data-testid="error-message">{error?.message}</div>
13-
));
10+
jest.mock('../../utils/prefix-url', () => mockDefault(() => '/'));
11+
jest.mock('../common/ErrorMessage', () =>
12+
mockDefault(({ error }) => <div data-testid="error-message">{error?.message}</div>)
13+
);
1414

1515
describe('NotFound tests', () => {
1616
it('renders error title and home link without error', () => {

packages/jaeger-ui/src/components/App/Page.test.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) 2017 Uber Technologies, Inc.
22
// SPDX-License-Identifier: Apache-2.0
33

4-
jest.mock('./TopNav', () => () => <div />);
4+
jest.mock('./TopNav', () => mockDefault(() => <div />));
55
jest.mock('../../utils/tracking');
66

77
import React from 'react';

packages/jaeger-ui/src/components/App/index.dev.test.jsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ import { render, screen } from '@testing-library/react';
1111
import '@testing-library/jest-dom';
1212
import { MemoryRouter } from 'react-router-dom';
1313

14-
jest.mock('./NotFound', () => () => <div data-testid="not-found" />);
15-
jest.mock('./Page', () => ({ children }) => <div data-testid="page">{children}</div>);
16-
jest.mock('../DependencyGraph', () => () => <div data-testid="dependency-graph" />);
17-
jest.mock('../DeepDependencies', () => () => <div data-testid="deep-dependencies" />);
18-
jest.mock('../QualityMetrics', () => () => <div data-testid="quality-metrics" />);
19-
jest.mock('../SearchTracePage', () => () => <div data-testid="search-trace" />);
14+
jest.mock('./NotFound', () => mockDefault(() => <div data-testid="not-found" />));
15+
jest.mock('./Page', () => mockDefault(({ children }) => <div data-testid="page">{children}</div>));
16+
jest.mock('../DependencyGraph', () => mockDefault(() => <div data-testid="dependency-graph" />));
17+
jest.mock('../DeepDependencies', () => mockDefault(() => <div data-testid="deep-dependencies" />));
18+
jest.mock('../QualityMetrics', () => mockDefault(() => <div data-testid="quality-metrics" />));
19+
jest.mock('../SearchTracePage', () => mockDefault(() => <div data-testid="search-trace" />));
2020
jest.mock('../TraceDiff', () => ({ __esModule: true, default: () => <div data-testid="trace-diff" /> }));
2121
jest.mock('../TracePage', () => ({ __esModule: true, default: () => <div data-testid="trace-page" /> }));
22-
jest.mock('../Monitor', () => () => <div data-testid="monitor" />);
22+
jest.mock('../Monitor', () => mockDefault(() => <div data-testid="monitor" />));
2323
jest.mock('../PlexusDemo', () => ({ __esModule: true, default: () => <div data-testid="plexus-demo" /> }));
2424

2525
jest.mock('../DependencyGraph/url', () => ({ ROUTE_PATH: '/dependencies' }));
@@ -36,8 +36,8 @@ jest.mock('../../api/jaeger', () => ({
3636
default: { apiRoot: null },
3737
DEFAULT_API_ROOT: 'http://localhost:16686/api',
3838
}));
39-
jest.mock('../../utils/config/process-scripts', () => jest.fn());
40-
jest.mock('../../utils/prefix-url', () => jest.fn(() => '/prefix'));
39+
jest.mock('../../utils/config/process-scripts', () => mockDefault(jest.fn()));
40+
jest.mock('../../utils/prefix-url', () => mockDefault(jest.fn(() => '/prefix')));
4141
jest.mock('../../utils/configure-store', () => ({
4242
store: {
4343
getState: jest.fn(() => ({})),

packages/jaeger-ui/src/components/App/index.test.jsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@ import { render } from '@testing-library/react';
66
import '@testing-library/jest-dom';
77
import { MemoryRouter } from 'react-router-dom';
88

9-
jest.mock('./NotFound', () => () => <div data-testid="not-found" />);
10-
jest.mock('./Page', () => ({ children }) => <div data-testid="page">{children}</div>);
11-
jest.mock('../DependencyGraph', () => () => <div data-testid="dependency-graph" />);
12-
jest.mock('../DeepDependencies', () => () => <div data-testid="deep-dependencies" />);
13-
jest.mock('../QualityMetrics', () => () => <div data-testid="quality-metrics" />);
14-
jest.mock('../SearchTracePage', () => () => <div data-testid="search-trace" />);
9+
jest.mock('./NotFound', () => mockDefault(() => <div data-testid="not-found" />));
10+
jest.mock('./Page', () => mockDefault(({ children }) => <div data-testid="page">{children}</div>));
11+
jest.mock('../DependencyGraph', () => mockDefault(() => <div data-testid="dependency-graph" />));
12+
jest.mock('../DeepDependencies', () => mockDefault(() => <div data-testid="deep-dependencies" />));
13+
jest.mock('../QualityMetrics', () => mockDefault(() => <div data-testid="quality-metrics" />));
14+
jest.mock('../SearchTracePage', () => mockDefault(() => <div data-testid="search-trace" />));
1515
jest.mock('../TraceDiff', () => ({ __esModule: true, default: () => <div data-testid="trace-diff" /> }));
1616
jest.mock('../TracePage', () => ({ __esModule: true, default: () => <div data-testid="trace-page" /> }));
17-
jest.mock('../Monitor', () => () => <div data-testid="monitor" />);
17+
jest.mock('../Monitor', () => mockDefault(() => <div data-testid="monitor" />));
1818

1919
jest.mock('../DependencyGraph/url', () => ({ ROUTE_PATH: '/dependencies' }));
2020
jest.mock('../DeepDependencies/url', () => ({ ROUTE_PATH: '/deep-dependencies' }));
@@ -33,8 +33,8 @@ jest.mock('../../api/jaeger', () => ({
3333
DEFAULT_API_ROOT: 'http://localhost:16686/api',
3434
}));
3535

36-
jest.mock('../../utils/config/process-scripts', () => jest.fn());
37-
jest.mock('../../utils/prefix-url', () => jest.fn(() => '/prefix'));
36+
jest.mock('../../utils/config/process-scripts', () => mockDefault(jest.fn()));
37+
jest.mock('../../utils/prefix-url', () => mockDefault(jest.fn(() => '/prefix')));
3838

3939
const createMockHistory = (pathname = '/') => ({
4040
length: 1,

packages/jaeger-ui/src/components/DeepDependencies/Graph/DdgNodeContent/index.test.jsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
// Copyright (c) 2019 Uber Technologies, Inc.
22
// SPDX-License-Identifier: Apache-2.0
33

4-
jest.mock('./calc-positioning', () => () => ({
5-
radius: 50,
6-
svcWidth: 20,
7-
opWidth: 30,
8-
svcMarginTop: 10,
9-
}));
4+
jest.mock('./calc-positioning', () =>
5+
mockDefault(() => ({
6+
radius: 50,
7+
svcWidth: 20,
8+
opWidth: 30,
9+
svcMarginTop: 10,
10+
}))
11+
);
1012

1113
// Mutable object so individual tests can control the location without re-creating the mock.
1214
const mockLocation = { search: '' };

packages/jaeger-ui/src/components/DeepDependencies/Header/index.test.jsx

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ import * as track from '../index.track';
1010

1111
jest.mock('./HopsSelector', () => {
1212
const mockReact = jest.requireActual('react');
13-
return function MockHopsSelector(props) {
13+
return mockDefault(function MockHopsSelector(props) {
1414
return mockReact.createElement('div', { 'data-testid': 'hops-selector', ...props });
15-
};
15+
});
1616
});
1717

1818
jest.mock('../../common/SearchableSelect', () => {
1919
const mockReact = jest.requireActual('react');
20-
return function MockSearchableSelect(props) {
20+
return mockDefault(function MockSearchableSelect(props) {
2121
const { value, onChange, allowClear, onClear, placeholder, children, className, status } = props;
2222
// Extract options from children
2323
const options = mockReact.Children.toArray(children)
@@ -52,43 +52,45 @@ jest.mock('../../common/SearchableSelect', () => {
5252
value &&
5353
mockReact.createElement('button', { onClick: onClear, 'data-testid': 'clear-button' }, 'Clear')
5454
);
55-
};
55+
});
5656
});
5757

5858
jest.mock('./LayoutSettings', () => {
5959
const mockReact = jest.requireActual('react');
60-
return function MockLayoutSettings(props) {
60+
return mockDefault(function MockLayoutSettings(props) {
6161
return mockReact.createElement('div', { 'data-testid': 'layout-settings', ...props });
62-
};
62+
});
6363
});
6464

6565
jest.mock('../../common/UiFindInput', () => {
6666
const mockReact = jest.requireActual('react');
67-
return mockReact.forwardRef(function MockUiFindInput(props, ref) {
68-
const inputRef = mockReact.useRef(null);
69-
70-
mockReact.useEffect(() => {
71-
if (ref) {
72-
const current = {
73-
focus: () => inputRef.current && inputRef.current.focus(),
74-
blur: () => inputRef.current && inputRef.current.blur(),
75-
select: () => inputRef.current && inputRef.current.select(),
76-
input: inputRef.current,
77-
};
78-
if (typeof ref === 'function') {
79-
ref(current);
80-
} else {
81-
ref.current = current;
67+
return mockDefault(
68+
mockReact.forwardRef(function MockUiFindInput(props, ref) {
69+
const inputRef = mockReact.useRef(null);
70+
71+
mockReact.useEffect(() => {
72+
if (ref) {
73+
const current = {
74+
focus: () => inputRef.current && inputRef.current.focus(),
75+
blur: () => inputRef.current && inputRef.current.blur(),
76+
select: () => inputRef.current && inputRef.current.select(),
77+
input: inputRef.current,
78+
};
79+
if (typeof ref === 'function') {
80+
ref(current);
81+
} else {
82+
ref.current = current;
83+
}
8284
}
83-
}
84-
});
85-
86-
return mockReact.createElement('input', {
87-
ref: inputRef,
88-
'data-testid': 'ui-find-input',
89-
...props.inputProps,
90-
});
91-
});
85+
});
86+
87+
return mockReact.createElement('input', {
88+
ref: inputRef,
89+
'data-testid': 'ui-find-input',
90+
...props.inputProps,
91+
});
92+
})
93+
);
9294
});
9395

9496
describe('<Header>', () => {

packages/jaeger-ui/src/components/DeepDependencies/SidePanel/index.test.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jest.mock('antd', () => ({
1818
Table: () => <div data-testid="mock-table">Table Mock</div>,
1919
}));
2020

21-
jest.mock('./DetailsPanel', () => jest.fn(() => <div data-testid="details-panel" />));
21+
jest.mock('./DetailsPanel', () => mockDefault(jest.fn(() => <div data-testid="details-panel" />)));
2222

2323
describe('<SidePanel>', () => {
2424
let getConfigValueSpy;

0 commit comments

Comments
 (0)