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();
+
+ 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(
+ ,
+ );
+
+ await expect(findAllByRole('row')).resolves.toHaveLength(2);
+ });
+});
diff --git a/plugins/scaffolder/src/next/OngoingTask/TaskLogStream.tsx b/plugins/scaffolder/src/next/OngoingTask/TaskLogStream.tsx
index 65c0022e1d..2cfcdf1da6 100644
--- a/plugins/scaffolder/src/next/OngoingTask/TaskLogStream.tsx
+++ b/plugins/scaffolder/src/next/OngoingTask/TaskLogStream.tsx
@@ -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 (
l.join('\n'))
.filter(Boolean)
.join('\n')}
diff --git a/plugins/scaffolder/src/next/OngoingTask/TaskSteps/StepTime.test.tsx b/plugins/scaffolder/src/next/OngoingTask/TaskSteps/StepTime.test.tsx
new file mode 100644
index 0000000000..185d2fa7fb
--- /dev/null
+++ b/plugins/scaffolder/src/next/OngoingTask/TaskSteps/StepTime.test.tsx
@@ -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();
+
+ 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();
+
+ 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();
+
+ 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();
+ });
+ });
+});
diff --git a/plugins/scaffolder/src/next/OngoingTask/TaskSteps/StepTime.tsx b/plugins/scaffolder/src/next/OngoingTask/TaskSteps/StepTime.tsx
index 746007a7d3..2ec89f385a 100644
--- a/plugins/scaffolder/src/next/OngoingTask/TaskSteps/StepTime.tsx
+++ b/plugins/scaffolder/src/next/OngoingTask/TaskSteps/StepTime.tsx
@@ -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) {