Bug 1748645 - Tests View - Link from the number of alerts to the alerts view for that test (#7355)

* Bug 1748645 - Add link to improvement alerts

* Bug 1748645 - Add link to regression alerts

* Bug 1748645 - fetch alerts for regression link

* Bug 1748645 - add unit tests

* Bug 1748645 - Fix filterText string

* Bug 1748645 - Address PR request

* Bug 1748645 - fix improvements count

* Bug 1748645 - Count untriaged alerts, display the number with link

* Bug 1748645 - Add notes for improvement and regression tooltip
This commit is contained in:
esanuandra 2022-03-02 17:30:49 +02:00 коммит произвёл GitHub
Родитель 40de4922ad
Коммит 79ede943b2
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
10 изменённых файлов: 139 добавлений и 45 удалений

Просмотреть файл

@ -1,5 +1,6 @@
import React from 'react';
import { render, cleanup, waitFor, fireEvent } from '@testing-library/react';
import { MemoryRouter as Router } from 'react-router-dom';
import { noResultsMessage } from '../../../ui/perfherder/perf-helpers/constants';
import TestsTable from '../../../ui/perfherder/tests/TestsTable';
@ -35,13 +36,24 @@ const platformsMap = {
2: 'platform2',
};
const activeFramework = 'awsy';
const allFrameworks = [
{ id: 1, name: 'talos' },
{ id: 4, name: 'awsy' },
];
const testsTable = (data, projectsMap = false, platformsMap = false) =>
render(
<TestsTable
results={data}
projectsMap={projectsMap}
platformsMap={platformsMap}
/>,
<Router>
<TestsTable
results={data}
projectsMap={projectsMap}
platformsMap={platformsMap}
allFrameworks={allFrameworks}
framework={activeFramework}
/>
</Router>,
);
afterEach(cleanup);
@ -99,3 +111,21 @@ test('Test alerts from Alerts column are split into improvements and regressions
expect(regressions[0]).toBeInTheDocument();
expect(regressions[0]).toHaveTextContent('100');
});
test('Improvement alerts number has the corresponding link', async () => {
const { getAllByTestId } = testsTable(results, projectsMap, platformsMap);
const improvements = await waitFor(() => getAllByTestId('improvements'));
const link = `/alerts?hideDwnToInv=0&filterText=Base Content Explicit+test1&page=1&status=4&framework=4`;
expect(improvements[0].children[0]).toHaveAttribute('href', link);
});
test('Regression alerts number has the corresponding link', async () => {
const { getAllByTestId } = testsTable(results, projectsMap, platformsMap);
const regressions = await waitFor(() => getAllByTestId('regressions'));
const link = `/alerts?hideDwnToInv=0&filterText=Base Content Explicit+test1&page=1&status=9&framework=4`;
expect(regressions[0].children[0]).toHaveAttribute('href', link);
});

Просмотреть файл

@ -5,7 +5,7 @@ from collections import defaultdict
import django_filters
from django.conf import settings
from django.db import transaction
from django.db.models import CharField, Count, Q, Subquery, Value
from django.db.models import CharField, Count, Q, Subquery, Value, Case, When
from django.db.models.functions import Concat
from rest_framework import exceptions, filters, generics, pagination, viewsets
from rest_framework.response import Response
@ -749,7 +749,16 @@ class TestSuiteHealthViewSet(viewsets.ViewSet):
.annotate(repositories=GroupConcat('repository_id', distinct=True))
.annotate(platforms=GroupConcat('platform_id', distinct=True))
.annotate(total_alerts=Count('performancealert'))
.annotate(total_regressions=Count('performancealert__is_regression'))
.annotate(
total_regressions=Count(
Case(When(performancealert__is_regression=1, then=Value(1)))
)
)
.annotate(
total_untriaged=Count(
Case(When(performancealert__status=PerformanceAlert.UNTRIAGED, then=Value(1)))
)
)
.order_by('suite', 'test')
)

Просмотреть файл

@ -401,3 +401,4 @@ class TestSuiteHealthSerializer(serializers.Serializer):
repositories = CommaSeparatedField()
total_alerts = serializers.IntegerField()
total_regressions = serializers.IntegerField()
total_untriaged = serializers.IntegerField()

Просмотреть файл

@ -262,6 +262,10 @@ class AlertsView extends React.Component {
if (filterText) {
params.filter_text = filterText;
}
if (status === 'all regressions') {
delete params.status;
params.hide_improvements = true;
}
if (hideDownstream) {
params.hide_related_and_invalid = hideDownstream;
}

Просмотреть файл

@ -83,6 +83,7 @@ export const summaryStatusMap = {
wontfix: 6,
fixed: 7,
backedout: 8,
'all regressions': 9,
};
export const alertStatusMap = {

Просмотреть файл

@ -0,0 +1,70 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
import SimpleTooltip from '../../shared/SimpleTooltip';
import { summaryStatusMap } from '../perf-helpers/constants';
export default class AlertsLink extends React.PureComponent {
getTooltip = (type) => {
return (
<>
{type.charAt(0).toUpperCase() + type.slice(1)} <br />
<i>Note: Untriaged {type} can be seen through untriaged link</i>
</>
);
};
render() {
const { alerts, framework: frameworkName, allFrameworks } = this.props;
const {
total_alerts: totalAlerts,
total_regressions: regressions,
total_untriaged: untriaged,
suite,
test,
} = alerts;
const improvements = totalAlerts - regressions;
const framework = allFrameworks.find((item) => item.name === frameworkName);
const filterText = suite && test ? suite.concat(`+${test}`) : suite || test;
return (
<div className="d-flex justify-content-center">
<div data-testid="improvements" className="w-50">
<Link
to={`./alerts?hideDwnToInv=0&filterText=${filterText}&page=1&status=${summaryStatusMap.improvement}&framework=${framework.id}`}
target="_blank"
>
<SimpleTooltip
text={`${improvements || 0}`}
tooltipText={this.getTooltip('improvements')}
/>
</Link>
</div>
<div data-testid="regressions" className="w-50">
<Link
to={`./alerts?hideDwnToInv=0&filterText=${filterText}&page=1&status=${summaryStatusMap['all regressions']}&framework=${framework.id}`}
target="_blank"
>
<SimpleTooltip
text={`${regressions || 0}`}
tooltipText={this.getTooltip('regressions')}
/>
</Link>
</div>
<div data-testid="untriaged" className="w-50">
<Link
to={`./alerts?hideDwnToInv=0&filterText=${filterText}&page=1&status=${summaryStatusMap.untriaged}&framework=${framework.id}`}
target="_blank"
>
<SimpleTooltip text={`${untriaged || 0}`} tooltipText="Untriaged" />
</Link>
</div>
</div>
);
}
}
AlertsLink.propTypes = {
alerts: PropTypes.shape({}).isRequired,
};

Просмотреть файл

@ -1,35 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import SimpleTooltip from '../../shared/SimpleTooltip';
export default class AlertsList extends React.PureComponent {
render() {
const { alerts } = this.props;
const {
total_alerts: totalAlerts,
total_regressions: regressions,
} = alerts;
const improvements = totalAlerts - regressions;
return (
<div className="d-flex justify-content-around">
<div data-testid="improvements">
<SimpleTooltip
text={`${improvements || 0}`}
tooltipText="Improvements"
/>
</div>
<div data-testid="regressions">
<SimpleTooltip
text={`${regressions || 0}`}
tooltipText="Regressions"
/>
</div>
</div>
);
}
}
AlertsList.propTypes = {
alerts: PropTypes.shape({}).isRequired,
};

Просмотреть файл

@ -8,12 +8,13 @@ import { Perfdocs, perfViews } from '../perf-helpers/perfdocs';
import ItemList from './ItemList';
import PlatformList from './PlatformList';
import AlertsList from './AlertsList';
import AlertsLink from './AlertsLink';
export default function TestsTable(props) {
const {
results,
framework,
allFrameworks,
projectsMap,
platformsMap,
defaultPageSize,
@ -93,7 +94,13 @@ export default function TestsTable(props) {
accessor: 'total_alerts',
Cell: (props) => {
const { original } = props;
return <AlertsList alerts={original} />;
return (
<AlertsLink
alerts={original}
framework={framework}
allFrameworks={allFrameworks}
/>
);
},
width: 100,
style: { textAlign: 'center' },

Просмотреть файл

@ -57,7 +57,12 @@ export default class TestsTableControls extends React.Component {
};
render() {
const { dropdownOptions, projectsMap, platformsMap } = this.props;
const {
dropdownOptions,
projectsMap,
platformsMap,
allFrameworks,
} = this.props;
const { results } = this.state;
let framework = false;
if (dropdownOptions[0] !== undefined)
@ -73,6 +78,7 @@ export default class TestsTableControls extends React.Component {
<TestsTable
results={results}
framework={framework}
allFrameworks={allFrameworks}
projectsMap={projectsMap}
platformsMap={platformsMap}
/>

Просмотреть файл

@ -174,6 +174,7 @@ class TestsView extends React.PureComponent {
dropdownOptions={dropdowns}
projectsMap={projectsMap}
platformsMap={platformsMap}
allFrameworks={frameworks}
/>
</Container>
</ErrorBoundary>