Add tests for builds page and XcmetricsLayout
Signed-off-by: Niklas Granander <ngranander@spotify.com>
This commit is contained in:
@@ -28,7 +28,7 @@ export const mockBuild = {
|
||||
day: '2021-01-01',
|
||||
compilationEndTimestamp: '2021-01-01T00:00:01Z',
|
||||
tag: '',
|
||||
projectName: 'Project',
|
||||
projectName: 'ProjectName',
|
||||
compilationEndTimestampMicroseconds: 1,
|
||||
errorCount: 1,
|
||||
id: 'buildId',
|
||||
@@ -67,10 +67,13 @@ export const XcmetricsClient: XcmetricsApi = {
|
||||
_perPage?: number,
|
||||
) => {
|
||||
return Promise.resolve({
|
||||
items: [mockBuild],
|
||||
items: [
|
||||
mockBuild,
|
||||
{ ...mockBuild, buildStatus: 'failed', projectName: 'ProjectName2' },
|
||||
],
|
||||
metadata: {
|
||||
per: 10,
|
||||
total: 1,
|
||||
total: 2,
|
||||
page: 1,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2021 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 { renderInTestApp } from '@backstage/test-utils';
|
||||
import { ApiProvider, ApiRegistry } from '@backstage/core-app-api';
|
||||
import { BuildListComponent } from './BuildListComponent';
|
||||
import { xcmetricsApiRef } from '../../api';
|
||||
|
||||
jest.mock('../../api/XcmetricsClient');
|
||||
const client = require('../../api/XcmetricsClient');
|
||||
|
||||
jest.mock('../BuildListFilterComponent', () => ({
|
||||
BuildListFilterComponent: () => 'BuildListFilterComponent',
|
||||
}));
|
||||
|
||||
describe('BuildListComponent', () => {
|
||||
it('should render', async () => {
|
||||
const rendered = await renderInTestApp(
|
||||
<ApiProvider
|
||||
apis={ApiRegistry.with(xcmetricsApiRef, client.XcmetricsClient)}
|
||||
>
|
||||
<BuildListComponent />
|
||||
</ApiProvider>,
|
||||
);
|
||||
|
||||
expect(rendered.getByText('Builds')).toBeInTheDocument();
|
||||
expect(
|
||||
rendered.getByText(client.mockBuild.projectName),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should show errors', async () => {
|
||||
const message = 'error';
|
||||
client.XcmetricsClient.getFilteredBuilds = jest
|
||||
.fn()
|
||||
.mockRejectedValue({ message });
|
||||
|
||||
const rendered = await renderInTestApp(
|
||||
<ApiProvider
|
||||
apis={ApiRegistry.with(xcmetricsApiRef, client.XcmetricsClient)}
|
||||
>
|
||||
<BuildListComponent />
|
||||
</ApiProvider>,
|
||||
);
|
||||
|
||||
expect(rendered.getByText(message)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright 2021 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 { renderInTestApp } from '@backstage/test-utils';
|
||||
import { ApiProvider, ApiRegistry } from '@backstage/core-app-api';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { BuildListFilterComponent } from './BuildListFilterComponent';
|
||||
import { BuildFilters, xcmetricsApiRef } from '../../api';
|
||||
import { RenderResult } from '@testing-library/react';
|
||||
|
||||
jest.mock('../../api/XcmetricsClient');
|
||||
const client = require('../../api/XcmetricsClient');
|
||||
|
||||
jest.mock('../DatePickerComponent', () => ({
|
||||
DatePickerComponent: () => 'DatePickerComponent',
|
||||
}));
|
||||
|
||||
const initialValues = {
|
||||
from: '2020-07-30',
|
||||
to: '2021-07-30',
|
||||
};
|
||||
|
||||
const renderWithFiltersVisible = async (
|
||||
callback?: (filters: BuildFilters) => void,
|
||||
) => {
|
||||
const rendered = await renderInTestApp(
|
||||
<ApiProvider
|
||||
apis={ApiRegistry.with(xcmetricsApiRef, client.XcmetricsClient)}
|
||||
>
|
||||
<BuildListFilterComponent
|
||||
initialValues={initialValues}
|
||||
onFilterChange={callback ?? jest.fn()}
|
||||
/>
|
||||
</ApiProvider>,
|
||||
);
|
||||
|
||||
userEvent.click(rendered.getByLabelText('show filters'));
|
||||
return rendered;
|
||||
};
|
||||
|
||||
const setStatusFilter = async (rendered: RenderResult, option: string) => {
|
||||
const statusSelect = rendered.getAllByTestId('select')[0];
|
||||
userEvent.click(statusSelect);
|
||||
userEvent.click((await rendered.findAllByText(option))[0]);
|
||||
};
|
||||
|
||||
const setProjectFilter = async (rendered: RenderResult, option: string) => {
|
||||
const statusSelect = rendered.getAllByTestId('select')[1];
|
||||
userEvent.click(statusSelect);
|
||||
const options = await rendered.findAllByText(option);
|
||||
userEvent.click(options[options.length - 1]);
|
||||
};
|
||||
|
||||
describe('BuildListFilterComponent', () => {
|
||||
it('should render', async () => {
|
||||
const rendered = await renderInTestApp(
|
||||
<ApiProvider
|
||||
apis={ApiRegistry.with(xcmetricsApiRef, client.XcmetricsClient)}
|
||||
>
|
||||
<BuildListFilterComponent
|
||||
initialValues={initialValues}
|
||||
onFilterChange={jest.fn()}
|
||||
/>
|
||||
</ApiProvider>,
|
||||
);
|
||||
|
||||
expect(rendered.getByText('Filters (0)')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should toggle between showing and hiding filters', async () => {
|
||||
const rendered = await renderWithFiltersVisible();
|
||||
|
||||
expect(
|
||||
(await rendered.findAllByText('DatePickerComponent')).length,
|
||||
).toEqual(2);
|
||||
expect(await rendered.findByText('Status')).toBeInTheDocument();
|
||||
expect(await rendered.findByText('Project')).toBeInTheDocument();
|
||||
|
||||
userEvent.click(rendered.getByLabelText('hide filters'));
|
||||
expect(rendered.queryByText('DatePickerComponent')).toBeNull();
|
||||
expect(rendered.queryByText('Status')).toBeNull();
|
||||
expect(rendered.queryByText('Project')).toBeNull();
|
||||
});
|
||||
|
||||
it('should load projects', async () => {
|
||||
const callback = jest.fn();
|
||||
const rendered = await renderWithFiltersVisible(callback);
|
||||
userEvent.click((await rendered.findAllByText('All'))[1]);
|
||||
|
||||
expect(
|
||||
await rendered.findByText(client.mockBuild.projectName),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should call back with a status when status is selected', async () => {
|
||||
const callback = jest.fn();
|
||||
const rendered = await renderWithFiltersVisible(callback);
|
||||
|
||||
await setStatusFilter(rendered, 'Succeeded');
|
||||
expect(callback).toBeCalledWith({
|
||||
...initialValues,
|
||||
buildStatus: 'succeeded',
|
||||
});
|
||||
|
||||
await setStatusFilter(rendered, 'All');
|
||||
expect(callback).toBeCalledWith(initialValues);
|
||||
});
|
||||
|
||||
it('should call back with a project when project is selected', async () => {
|
||||
const callback = jest.fn();
|
||||
const rendered = await renderWithFiltersVisible(callback);
|
||||
|
||||
await setProjectFilter(rendered, client.mockBuild.projectName);
|
||||
expect(callback).toBeCalledWith({
|
||||
...initialValues,
|
||||
project: client.mockBuild.projectName,
|
||||
});
|
||||
|
||||
await setProjectFilter(rendered, 'All');
|
||||
expect(callback).toBeCalledWith(initialValues);
|
||||
});
|
||||
|
||||
it('should display a count of active (changed) filters', async () => {
|
||||
const rendered = await renderWithFiltersVisible();
|
||||
|
||||
await setStatusFilter(rendered, 'Failed');
|
||||
await setProjectFilter(rendered, client.mockBuild.projectName);
|
||||
|
||||
expect(await rendered.findByText('Filters (2)')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should clear all filters', async () => {
|
||||
const callback = jest.fn();
|
||||
const rendered = await renderWithFiltersVisible(callback);
|
||||
|
||||
await setStatusFilter(rendered, 'Failed');
|
||||
await setProjectFilter(rendered, client.mockBuild.projectName);
|
||||
|
||||
callback.mockClear();
|
||||
userEvent.click(await rendered.findByText('Clear all'));
|
||||
|
||||
expect(callback).toHaveBeenCalledWith(initialValues);
|
||||
expect(await rendered.findByText('Filters (0)')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
+8
-6
@@ -52,15 +52,17 @@ export const BuildListFilterComponent = ({
|
||||
|
||||
useEffect(() => onFilterChange(values), [onFilterChange, values]);
|
||||
|
||||
const numFilters =
|
||||
Number(values.from !== initialValues.from) +
|
||||
Number(values.to !== initialValues.to) +
|
||||
Number(!!values.buildStatus) +
|
||||
Number(!!values.project);
|
||||
const numFilters = Object.keys(values).reduce((sum, key) => {
|
||||
const filtersKey = key as keyof BuildFilters;
|
||||
return sum + Number(values[filtersKey] !== initialValues[filtersKey]);
|
||||
}, 0);
|
||||
|
||||
const title = (
|
||||
<>
|
||||
<IconButton onClick={() => setOpen(!open)} aria-label="filter list">
|
||||
<IconButton
|
||||
onClick={() => setOpen(!open)}
|
||||
aria-label={`${open ? 'hide' : 'show'} filters`}
|
||||
>
|
||||
<FilterList />
|
||||
</IconButton>
|
||||
Filters ({numFilters})
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2021 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 { renderInTestApp } from '@backstage/test-utils';
|
||||
import { DatePickerComponent } from './DatePickerComponent';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
describe('DatePickerComponent', () => {
|
||||
it('should render', async () => {
|
||||
const label = 'label';
|
||||
const rendered = await renderInTestApp(
|
||||
<DatePickerComponent label={label} />,
|
||||
);
|
||||
expect(rendered.getByText(label)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should accept a date', async () => {
|
||||
const label = 'label';
|
||||
const callback = jest.fn();
|
||||
const rendered = await renderInTestApp(
|
||||
<DatePickerComponent label={label} onDateChange={callback} />,
|
||||
);
|
||||
const input = rendered.getByLabelText(label);
|
||||
|
||||
userEvent.type(input, '2020-02-02');
|
||||
expect(callback).toBeCalledWith('2020-02-02');
|
||||
});
|
||||
|
||||
it('should not accept non date', async () => {
|
||||
const label = 'label';
|
||||
const callback = jest.fn();
|
||||
const rendered = await renderInTestApp(
|
||||
<DatePickerComponent label={label} onDateChange={callback} />,
|
||||
);
|
||||
const input = rendered.getByLabelText(label);
|
||||
|
||||
userEvent.type(input, 'test');
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -74,6 +74,7 @@ export const DatePickerComponent = ({
|
||||
<div className={classes.root}>
|
||||
<Typography variant="button">{label}</Typography>
|
||||
<BootstrapInput
|
||||
inputProps={{ 'aria-label': label }}
|
||||
type="date"
|
||||
fullWidth
|
||||
onChange={event => onDateChange?.(event.target.value)}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2021 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 { renderInTestApp } from '@backstage/test-utils';
|
||||
import { ApiProvider, ApiRegistry } from '@backstage/core-app-api';
|
||||
import { XcmetricsLayout } from './XcmetricsLayout';
|
||||
import { xcmetricsApiRef } from '../../api';
|
||||
|
||||
jest.mock('../../api/XcmetricsClient');
|
||||
const client = require('../../api/XcmetricsClient');
|
||||
|
||||
jest.mock('../OverviewComponent', () => ({
|
||||
OverviewComponent: () => 'OverviewComponent',
|
||||
}));
|
||||
|
||||
jest.mock('../BuildListComponent', () => ({
|
||||
BuildListComponent: () => 'BuildListComponent',
|
||||
}));
|
||||
|
||||
describe('XcmetricsLayout', () => {
|
||||
it('should render', async () => {
|
||||
const rendered = await renderInTestApp(
|
||||
<ApiProvider
|
||||
apis={ApiRegistry.with(xcmetricsApiRef, client.XcmetricsClient)}
|
||||
>
|
||||
<XcmetricsLayout />
|
||||
</ApiProvider>,
|
||||
);
|
||||
|
||||
expect(rendered.getByText('Overview')).toBeInTheDocument();
|
||||
expect(rendered.getByText('Builds')).toBeInTheDocument();
|
||||
|
||||
expect(rendered.getByText('OverviewComponent')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -13,10 +13,11 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { xcmetricsPlugin } from './plugin';
|
||||
import { XcmetricsPage, xcmetricsPlugin } from './plugin';
|
||||
|
||||
describe('xcmetrics', () => {
|
||||
it('should export plugin', () => {
|
||||
expect(xcmetricsPlugin).toBeDefined();
|
||||
expect(XcmetricsPage).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user