Skip to content

Commit c99ba2b

Browse files
chore(frontend): replace querySelector with Testing Library patterns (#13289)
Signed-off-by: Priyanshu-u07 <connect.priyanshu8271@gmail.com>
1 parent cb92ff0 commit c99ba2b

12 files changed

Lines changed: 78 additions & 66 deletions

frontend/src/components/NewRunParameters.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ describe('NewRunParameters', () => {
5252

5353
expect(handleParamChange).toHaveBeenCalledTimes(1);
5454
expect(handleParamChange).toHaveBeenLastCalledWith(0, '{\n "test": "value"\n}');
55-
expect(document.querySelector('.ace_editor')).toBeInTheDocument();
55+
expect(screen.getByTestId('json-editor-newRunPipelineParam0')).toBeInTheDocument();
5656
});
5757

5858
it('fires handleParamChange callback on change', () => {

frontend/src/components/NewRunParameters.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ class ParamEditor extends React.Component<ParamEditorProps, ParamEditorState> {
170170
/>
171171
)}
172172
{this.state.isJsonField && this.state.isEditorOpen && (
173-
<div className={css.row}>
173+
<div className={css.row} data-testid={`json-editor-${id}`}>
174174
<Editor
175175
width='100%'
176176
minLines={3}

frontend/src/components/NewRunParametersV2.test.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -917,7 +917,7 @@ describe('NewRunParametersV2', () => {
917917
});
918918

919919
it('does not display any text fields if there are no parameters', () => {
920-
const { container } = render(
920+
render(
921921
<CommonTestWrapper>
922922
<NewRunParametersV2
923923
titleMessage='Specify parameters required by the pipeline'
@@ -927,7 +927,9 @@ describe('NewRunParametersV2', () => {
927927
</CommonTestWrapper>,
928928
);
929929

930-
expect(container.querySelector('input').type).toEqual('checkbox');
930+
// The only input should be the pipeline root checkbox — no text fields for parameters
931+
expect(screen.getByRole('checkbox')).toBeInTheDocument();
932+
expect(screen.queryAllByRole('textbox')).toHaveLength(0);
931933
});
932934

933935
// Test for fix: Default parameters not displayed in Compare Runs

frontend/src/components/graph/ArtifactNode.test.tsx

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,23 +32,27 @@ describe('ArtifactNode', () => {
3232
expect(screen.getByText('my-artifact')).toBeInTheDocument();
3333
});
3434

35-
it('renders with LIVE state and yellow icon', () => {
36-
const { container } = renderWithProvider(
35+
it('renders with LIVE state and correct icon', () => {
36+
renderWithProvider(
3737
<ArtifactNode
3838
id='artifact-1'
3939
data={{ label: 'live-artifact', state: Artifact.State.LIVE }}
4040
/>,
4141
);
4242
expect(screen.getByText('live-artifact')).toBeInTheDocument();
43-
expect(container.querySelector('.text-mui-yellow-800')).toBeInTheDocument();
43+
const liveIcon = screen.getByTestId('artifact-icon-live');
44+
expect(liveIcon).toBeInTheDocument();
45+
expect(liveIcon).toHaveClass('text-mui-yellow-800');
4446
});
4547

46-
it('renders with undefined state and grey icon', () => {
47-
const { container } = renderWithProvider(
48+
it('renders with undefined state and default icon', () => {
49+
renderWithProvider(
4850
<ArtifactNode id='artifact-1' data={{ label: 'unknown-artifact', state: undefined }} />,
4951
);
5052
expect(screen.getByText('unknown-artifact')).toBeInTheDocument();
51-
expect(container.querySelector('.text-mui-grey-300-dark')).toBeInTheDocument();
53+
const defaultIcon = screen.getByTestId('artifact-icon-default');
54+
expect(defaultIcon).toBeInTheDocument();
55+
expect(defaultIcon).toHaveClass('text-mui-grey-300-dark');
5256
});
5357

5458
it('sets the title attribute on the button', () => {
@@ -59,9 +63,9 @@ describe('ArtifactNode', () => {
5963
});
6064

6165
it('renders with the correct id on the label span', () => {
62-
const { container } = renderWithProvider(
66+
renderWithProvider(
6367
<ArtifactNode id='artifact-42' data={{ label: 'test', state: undefined }} />,
6468
);
65-
expect(container.querySelector('#artifact-42')).toBeInTheDocument();
69+
expect(screen.getByTestId('artifact-42')).toBeInTheDocument();
6670
});
6771
});

frontend/src/components/graph/ArtifactNode.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ function ArtifactNode({ id, data }: ArtifactNodeProps) {
3939
<div className='flex items-center justify-between w-60 rounded-lg shadow-lg bg-white'>
4040
{icon}
4141
<div className='flex flex-grow justify-center items-center rounded-r-lg overflow-hidden'>
42-
<span className='text-sm truncate' id={id}>
42+
<span className='text-sm truncate' id={id} data-testid={id}>
4343
{data.label}
4444
</span>
4545
</div>
@@ -65,13 +65,19 @@ export default ArtifactNode;
6565

6666
function getIcon(state: Artifact.State | undefined) {
6767
if (state === undefined) {
68-
return getIconWrapper(<FolderIcon className='text-mui-grey-300-dark' />);
68+
return getIconWrapper(
69+
<FolderIcon data-testid='artifact-icon-default' className='text-mui-grey-300-dark' />,
70+
);
6971
}
7072
switch (state) {
7173
case Artifact.State.LIVE:
72-
return getIconWrapper(<FolderIcon className='text-mui-yellow-800' />);
74+
return getIconWrapper(
75+
<FolderIcon data-testid='artifact-icon-live' className='text-mui-yellow-800' />,
76+
);
7377
default:
74-
return getIconWrapper(<FolderIcon className='text-mui-grey-300-dark' />);
78+
return getIconWrapper(
79+
<FolderIcon data-testid='artifact-icon-default' className='text-mui-grey-300-dark' />,
80+
);
7581
}
7682
}
7783

frontend/src/components/graph/ExecutionNode.test.tsx

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -32,34 +32,34 @@ describe('ExecutionNode', () => {
3232
expect(screen.getByText('train-step')).toBeInTheDocument();
3333
});
3434

35-
it('renders with COMPLETE state and green background', () => {
36-
const { container } = renderWithProvider(
35+
it('renders with COMPLETE state and correct icon', () => {
36+
renderWithProvider(
3737
<ExecutionNode
3838
id='exec-1'
3939
data={{ label: 'completed-step', state: Execution.State.COMPLETE }}
4040
/>,
4141
);
4242
expect(screen.getByText('completed-step')).toBeInTheDocument();
43-
expect(container.querySelector('.bg-mui-green-50')).toBeInTheDocument();
43+
expect(screen.getByTestId('CheckCircleIcon')).toBeInTheDocument();
4444
});
4545

46-
it('renders with RUNNING state and green background', () => {
47-
const { container } = renderWithProvider(
46+
it('renders with RUNNING state and correct icon', () => {
47+
renderWithProvider(
4848
<ExecutionNode
4949
id='exec-1'
5050
data={{ label: 'running-step', state: Execution.State.RUNNING }}
5151
/>,
5252
);
5353
expect(screen.getByText('running-step')).toBeInTheDocument();
54-
expect(container.querySelector('.bg-mui-green-50')).toBeInTheDocument();
54+
expect(screen.getByTestId('RefreshIcon')).toBeInTheDocument();
5555
});
5656

57-
it('renders with FAILED state and red background', () => {
58-
const { container } = renderWithProvider(
57+
it('renders with FAILED state and correct icon', () => {
58+
renderWithProvider(
5959
<ExecutionNode id='exec-1' data={{ label: 'failed-step', state: Execution.State.FAILED }} />,
6060
);
6161
expect(screen.getByText('failed-step')).toBeInTheDocument();
62-
expect(container.querySelector('.bg-mui-red-50')).toBeInTheDocument();
62+
expect(screen.getByTestId('ErrorIcon')).toBeInTheDocument();
6363
});
6464

6565
it('sets the title attribute', () => {
@@ -76,32 +76,32 @@ describe('getIcon', () => {
7676
});
7777

7878
it.each([
79-
['COMPLETE', Execution.State.COMPLETE, '.bg-mui-green-50', 'CheckCircleIcon'],
80-
['RUNNING', Execution.State.RUNNING, '.bg-mui-green-50', 'RefreshIcon'],
81-
['FAILED', Execution.State.FAILED, '.bg-mui-red-50', 'ErrorIcon'],
82-
['NEW', Execution.State.NEW, '.bg-mui-blue-50', 'PowerSettingsNewIcon'],
83-
['CANCELED', Execution.State.CANCELED, '.bg-mui-grey-200', undefined],
84-
['CACHED', Execution.State.CACHED, '.bg-mui-green-50', 'CloudDownloadIcon'],
85-
['UNKNOWN', Execution.State.UNKNOWN, '.bg-mui-grey-200', 'MoreHorizIcon'],
86-
] as const)('returns the correct icon for %s state', (_label, state, bgClass, iconTestId) => {
87-
const { container } = render(getIcon(state)!);
88-
expect(container.querySelector(bgClass)).toBeInTheDocument();
89-
if (iconTestId) {
90-
expect(container.querySelector(`[data-testid="${iconTestId}"]`)).toBeInTheDocument();
91-
}
92-
});
79+
['COMPLETE', Execution.State.COMPLETE, 'CheckCircleIcon', 'bg-mui-green-50'],
80+
['RUNNING', Execution.State.RUNNING, 'RefreshIcon', 'bg-mui-green-50'],
81+
['FAILED', Execution.State.FAILED, 'ErrorIcon', 'bg-mui-red-50'],
82+
['NEW', Execution.State.NEW, 'PowerSettingsNewIcon', 'bg-mui-blue-50'],
83+
['CANCELED', Execution.State.CANCELED, 'StopCircleIcon', 'bg-mui-grey-200'],
84+
['CACHED', Execution.State.CACHED, 'CloudDownloadIcon', 'bg-mui-green-50'],
85+
['UNKNOWN', Execution.State.UNKNOWN, 'MoreHorizIcon', 'bg-mui-grey-200'],
86+
] as const)(
87+
'returns the correct icon for %s state',
88+
(_label, state, iconTestId, backgroundClass) => {
89+
render(getIcon(state)!);
90+
const stateIcon = screen.getByTestId(iconTestId);
91+
expect(stateIcon).toBeInTheDocument();
92+
expect(stateIcon.parentElement).toHaveClass(backgroundClass);
93+
},
94+
);
9395
});
9496

9597
describe('getExecutionIcon', () => {
96-
it('returns a grey ListAlt icon for undefined state', () => {
97-
const { container } = render(getExecutionIcon(undefined));
98-
expect(container.querySelector('.text-mui-grey-500')).toBeInTheDocument();
99-
expect(container.querySelector('[data-testid="ListAltIcon"]')).toBeInTheDocument();
98+
it('returns a default ListAlt icon for undefined state', () => {
99+
render(getExecutionIcon(undefined));
100+
expect(screen.getByTestId('execution-icon-default')).toBeInTheDocument();
100101
});
101102

102-
it('returns a blue ListAlt icon for defined state', () => {
103-
const { container } = render(getExecutionIcon(Execution.State.RUNNING));
104-
expect(container.querySelector('.text-mui-blue-600')).toBeInTheDocument();
105-
expect(container.querySelector('[data-testid="ListAltIcon"]')).toBeInTheDocument();
103+
it('returns an active ListAlt icon for defined state', () => {
104+
render(getExecutionIcon(Execution.State.RUNNING));
105+
expect(screen.getByTestId('execution-icon-active')).toBeInTheDocument();
106106
});
107107
});

frontend/src/components/graph/ExecutionNode.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,9 @@ export default ExecutionNode;
8282

8383
export function getExecutionIcon(state: Execution.State | undefined) {
8484
if (state === undefined) {
85-
return <ListAltIcon className='text-mui-grey-500' />;
85+
return <ListAltIcon data-testid='execution-icon-default' className='text-mui-grey-500' />;
8686
}
87-
return <ListAltIcon className='text-mui-blue-600' />;
87+
return <ListAltIcon data-testid='execution-icon-active' className='text-mui-blue-600' />;
8888
}
8989

9090
export function getIcon(state: Execution.State | undefined) {
@@ -119,7 +119,7 @@ export function getIcon(state: Execution.State | undefined) {
119119
);
120120
case Execution.State.COMPLETE:
121121
return getStateIconWrapper(
122-
<CheckCircleIcon className='text-mui-green-600 bla' />,
122+
<CheckCircleIcon className='text-mui-green-600' />,
123123
'bg-mui-green-50',
124124
);
125125
default:

frontend/src/components/graph/SubDagNode.test.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,23 +41,23 @@ describe('SubDagNode', () => {
4141
expect(screen.getByText('sub-pipeline')).toBeInTheDocument();
4242
});
4343

44-
it('sets the title attribute on the button', () => {
44+
it('sets accessible label on the button', () => {
4545
renderWithProvider(<SubDagNode id='subdag-1' data={defaultData} />);
46-
expect(screen.getByTitle('sub-pipeline')).toBeInTheDocument();
46+
expect(screen.getByRole('button', { name: 'sub-pipeline' })).toBeInTheDocument();
4747
});
4848

49-
it('renders with COMPLETE state', () => {
49+
it('renders COMPLETE state icon', () => {
5050
renderWithProvider(
5151
<SubDagNode id='subdag-1' data={{ ...defaultData, state: Execution.State.COMPLETE }} />,
5252
);
53-
expect(screen.getByText('sub-pipeline')).toBeInTheDocument();
53+
expect(screen.getByTestId('CheckCircleIcon')).toBeInTheDocument();
5454
});
5555

56-
it('renders with RUNNING state', () => {
56+
it('renders RUNNING state icon', () => {
5757
renderWithProvider(
5858
<SubDagNode id='subdag-1' data={{ ...defaultData, state: Execution.State.RUNNING }} />,
5959
);
60-
expect(screen.getByText('sub-pipeline')).toBeInTheDocument();
60+
expect(screen.getByTestId('RefreshIcon')).toBeInTheDocument();
6161
});
6262

6363
it('calls expand callback when expand button is clicked', () => {
@@ -69,7 +69,7 @@ describe('SubDagNode', () => {
6969
});
7070

7171
it('renders with the correct id on the label span', () => {
72-
const { container } = renderWithProvider(<SubDagNode id='subdag-42' data={defaultData} />);
73-
expect(container.querySelector('#subdag-42')).toBeInTheDocument();
72+
renderWithProvider(<SubDagNode id='subdag-42' data={defaultData} />);
73+
expect(screen.getByTestId('subdag-42')).toBeInTheDocument();
7474
});
7575
});

frontend/src/components/graph/SubDagNode.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ function SubDagNode({ id, data }: SubDagNodeProps) {
5353
{executionIcon}
5454
</div>
5555
<div className='px-4 py-4 w-44 flex flex-col justify-center items-center '>
56-
<span className='w-full truncate' id={id}>
56+
<span className='w-full truncate' id={id} data-testid={id}>
5757
{data.label}
5858
</span>
5959
</div>

frontend/src/icons/StopCircle.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ interface StopCircleProps {
2020

2121
export default function StopCircle({ colorClass }: StopCircleProps) {
2222
return (
23-
<div className={colorClass}>
23+
<div className={colorClass} data-testid='StopCircleIcon'>
2424
<svg
2525
xmlns='http://www.w3.org/2000/svg'
2626
enableBackground='new 0 0 24 24'

0 commit comments

Comments
 (0)