chore: writing some tests for the new components

Signed-off-by: blam <ben@blam.sh>
This commit is contained in:
blam
2023-01-31 16:26:15 +01:00
parent b46f385eff
commit ce0866d2e9
6 changed files with 176 additions and 11 deletions
@@ -0,0 +1,40 @@
/*
* Copyright 2023 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { TaskBorder } from './TaskBorder';
import { render } from '@testing-library/react';
describe('TaskBorder', () => {
it('should render a pending linear progress if the task is not complete', () => {
const { getByRole } = render(
<TaskBorder isComplete={false} isError={false} />,
);
const progressBar = getByRole('progressbar');
expect(progressBar).toBeInTheDocument();
expect(progressBar).toHaveClass('MuiLinearProgress-indeterminate');
});
it('should render a determinate progress bar if the task is complete', () => {
const { getByRole } = render(<TaskBorder isComplete isError />);
const progressBar = getByRole('progressbar');
expect(progressBar).toBeInTheDocument();
expect(progressBar).toHaveClass('MuiLinearProgress-determinate');
});
});
@@ -26,23 +26,20 @@ const useStyles = makeStyles((theme: BackstageTheme) => ({
},
}));
export const TaskBorder = ({
isComplete,
isError,
}: {
export const TaskBorder = (props: {
isComplete: boolean;
isError: boolean;
}) => {
const styles = useStyles();
if (!isComplete) {
if (!props.isComplete) {
return <LinearProgress variant="indeterminate" />;
}
return (
<LinearProgress
variant="determinate"
classes={{ bar: isError ? styles.failed : styles.success }}
classes={{ bar: props.isError ? styles.failed : styles.success }}
value={100}
/>
);
@@ -0,0 +1,50 @@
/*
* Copyright 2023 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { renderInTestApp } from '@backstage/test-utils';
import React, { ReactNode } from 'react';
import { TaskLogStream } from './TaskLogStream';
// The <AutoSizer> inside <LogViewer> needs mocking to render in jsdom
jest.mock('react-virtualized-auto-sizer', () => ({
__esModule: true,
default: (props: {
children: (size: { width: number; height: number }) => ReactNode;
}) => <>{props.children({ width: 400, height: 200 })}</>,
}));
describe('TaskLogStream', () => {
it('should render a log stream with the correct log lines', async () => {
const logs = { step: ['line 1', 'line 2'], step2: ['line 3'] };
const { findByText } = await renderInTestApp(<TaskLogStream logs={logs} />);
const logLines = Object.values(logs).flat();
for (const line of logLines) {
await expect(findByText(line)).resolves.toBeInTheDocument();
}
});
it('should filter out empty log lines', async () => {
const logs = { step: ['line 1', 'line 2'], step2: [] };
const { findAllByRole } = await renderInTestApp(
<TaskLogStream logs={logs} />,
);
await expect(findAllByRole('row')).resolves.toHaveLength(2);
});
});
@@ -25,13 +25,13 @@ const useStyles = makeStyles({
},
});
export const TaskLogStream = (opts: { logs: { [k: string]: string[] } }) => {
export const TaskLogStream = (props: { logs: { [k: string]: string[] } }) => {
const styles = useStyles();
return (
<div className={styles.root}>
<LogViewer
tail
text={Object.values(opts.logs)
text={Object.values(props.logs)
.map(l => l.join('\n'))
.filter(Boolean)
.join('\n')}
@@ -0,0 +1,79 @@
/*
* Copyright 2023 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { StepTime } from './StepTime';
import { render, act } from '@testing-library/react';
describe('StepTime', () => {
it('should return empty when there is no start time', () => {
const step = {
id: 'test',
startedAt: undefined,
endedAt: undefined,
name: 'test',
};
const { container } = render(<StepTime step={step} />);
expect(container.querySelector('span')?.textContent).toBe('');
});
it('should format the time between the start and end date properly', async () => {
const step = {
id: 'test',
startedAt: '2021-01-01T00:00:00Z',
endedAt: '2021-01-01T00:00:01Z',
name: 'test',
};
const { findByText } = render(<StepTime step={step} />);
await expect(findByText('1 second')).resolves.toBeInTheDocument();
});
describe('updates', () => {
beforeEach(() => {
jest.useFakeTimers({ now: new Date('2021-01-01T00:00:00Z') });
});
afterEach(() => {
jest.useRealTimers();
});
it('should update the time every second', async () => {
const step = {
id: 'test',
startedAt: '2021-01-01T00:00:00Z',
endedAt: undefined,
name: 'test',
};
const { findByText } = render(<StepTime step={step} />);
await expect(findByText('0 seconds')).resolves.toBeInTheDocument();
act(() => jest.advanceTimersByTime(1000));
await expect(findByText('1 second')).resolves.toBeInTheDocument();
act(() => jest.advanceTimersByTime(1000 * 60));
await expect(
findByText('1 minute, 1 second'),
).resolves.toBeInTheDocument();
});
});
});
@@ -19,9 +19,7 @@ import { DateTime, Interval } from 'luxon';
import humanizeDuration from 'humanize-duration';
import { Typography } from '@material-ui/core';
export const StepTime = ({
step,
}: {
export const StepTime = (props: {
step: {
id: string;
name: string;
@@ -30,6 +28,7 @@ export const StepTime = ({
};
}) => {
const [time, setTime] = useState('');
const { step } = props;
const calculate = useCallback(() => {
if (!step.startedAt) {