Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions docs/accessibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ For example:
</Button>
```

Known reactstrap components that accept the `color` prop and work with custom Treeherder colors: `Badge`, `Button`, `Card`, `Dropdown.Toggle`, `FormText`, `NavBar`, `Progress`, `Spinner`.
Known reactstrap components that accept the `color` prop and work with custom Treeherder colors: `Badge`, `Button`, `Card`, `DropdownToggle`, `FormText`, `NavBar`, `Progress`, `Spinner`.

In case you need to add more custom colors, please add on [treeherder-custom-styles.css](https://github.com/mozilla/treeherder/blob/master/ui/css/treeherder-custom-styles.css#L348) style sheet.

Expand Down Expand Up @@ -102,7 +102,7 @@ If your case is more specific, please check [this guide](https://css-tricks.com/

## Interactive elements

When creating elements that have event listeners, prefer any component of the reactstrap interactive elements. Examples are: `Button`, `Input`, `Dropdown.Toggle`. You can also choose a HTML `<a>` element.
When creating elements that have event listeners, prefer any component of the reactstrap interactive elements. Examples are: `Button`, `Input`, `DropdownToggle`. You can also choose a HTML `<a>` element.

If you need to insert an event listener in a non-interactive element, such as a `span`, add also an `aria-role` of `button`, `link`, `checkbox`, or whatever seems closer to the functionality of the element.

Expand All @@ -116,10 +116,10 @@ If you need to insert an event listener in a non-interactive element, such as a

There is a special case when you are creating a dropdown menu. First of all, try to follow [reactstrap structure](https://reactstrap.github.io/components/dropdowns/).

Lastly, insert an additional tag `prop` to `Dropdown.Item` component.
Lastly, insert an additional tag `prop` to `DropdownItem` component.

```jsx
<Dropdown.Item tag="a"> Menu Item </Dropdown.Item>
<DropdownItem tag="a"> Menu Item </DropdownItem>
```

## Forms, inputs and buttons
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
"prop-types": "15.8.1",
"query-string": "7.0.1",
"react": "18.3.1",
"react-bootstrap": "2.10.10",
"react-dates": "21.8.0",
"react-dom": "18.3.1",
"react-helmet": "6.1.0",
Expand All @@ -56,6 +55,7 @@
"react-split-pane": "0.1.92",
"react-table-6": "6.11.0",
"react-tabs": "6.1.0",
"reactstrap": "8.10.1",
"redoc": "2.4.0",
"redux": "4.2.1",
"redux-debounce": "1.0.1",
Expand Down
5 changes: 0 additions & 5 deletions tests/ui/job-view/Filtering_test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -198,11 +198,6 @@ describe('Filtering', () => {
);
expect(unfilteredPushes).toHaveLength(10);

// Open the filters dropdown to reveal menu items
const filtersDropdown = await waitFor(() => getByTitle('Set filters'));
fireEvent.click(filtersDropdown);

// Wait for dropdown to open and find "My pushes only"
const myPushes = await waitFor(() => getByText('My pushes only'));
fireEvent.click(myPushes);

Expand Down
18 changes: 3 additions & 15 deletions tests/ui/perfherder/alerts-view/alerts_test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -622,20 +622,8 @@ test('Selecting `all` from (frameworks|projects) dropdown shows all (frameworks|
const { queryAllByText, getByTestId } = alertsView();

const allFromDropdown = await waitFor(() => queryAllByText(/all/));
// Find the actual clickable parent elements (dropdown items) that contain the text "all"
const clickableElements = allFromDropdown
.map(
(textNode) =>
textNode.closest('a') ||
textNode.closest('button') ||
textNode.closest('[role="button"]'),
)
.filter(Boolean);

if (clickableElements.length >= 2) {
fireEvent.click(clickableElements[0]);
fireEvent.click(clickableElements[1]);
}
fireEvent.click(allFromDropdown[0]);
fireEvent.click(allFromDropdown[1]);

const alert1 = await waitFor(() => getByTestId('69526'));
const alert2 = await waitFor(() => getByTestId('69530'));
Expand Down Expand Up @@ -752,7 +740,7 @@ test(`table data cannot be sorted by 'Tags & Options'`, async () => {
getAllByTitle('Sorted by tags & options disabled'),
);

expect(sortByTags[0]).toBeDisabled();
expect(sortByTags[0]).toHaveClass('disabled-button');
});

test(`table data can be sorted in ascending order by 'Confidence'`, async () => {
Expand Down
8 changes: 4 additions & 4 deletions tests/ui/perfherder/alerts-view/modal_perf_tags_test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ test('An active/checked tag can be unchecked', async () => {

test('Modal closes on X', async () => {
const handleClose = jest.fn();
const { getByLabelText } = testTagsModal(handleClose);
const { getByText } = testTagsModal(handleClose);

const closeButton = await waitFor(() => getByLabelText('Close'));
const closeButton = await waitFor(() => getByText('×'));

expect(closeButton).toBeInTheDocument();

Expand All @@ -69,7 +69,7 @@ test('Modal does not keep unsaved changes', async () => {
testAlertSummary.performance_tags = ['harness'];

const handleClose = jest.fn();
const { getByLabelText, getByTestId } = testTagsModal(handleClose);
const { getByText, getByTestId } = testTagsModal(handleClose);

let activeTag = await waitFor(() => getByTestId('modal-perf-tag harness'));

Expand All @@ -78,7 +78,7 @@ test('Modal does not keep unsaved changes', async () => {
fireEvent.change(activeTag, { target: { checked: false } });
expect(activeTag.checked).toBeFalsy();

const closeButton = await waitFor(() => getByLabelText('Close'));
const closeButton = await waitFor(() => getByText('×'));
fireEvent.click(closeButton);

expect(handleClose).toHaveBeenCalledTimes(1);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { render, fireEvent } from '@testing-library/react';
import { render } from '@testing-library/react';
import { noop } from 'lodash';
import React from 'react';

Expand Down Expand Up @@ -41,14 +41,10 @@ const testFrameworksDropdown = () => {
};

test('should pin the right number of items to top and bottom frameworks w.r.t config', async () => {
const { container } = testFrameworksDropdown();
testFrameworksDropdown();
// top pinned represents all items in the drop down that is at the top of the list
// bottom pinned represents all items in the drop down that is at the bottom of the list.

// Open the dropdown to render the menu items
const dropdownToggle = container.querySelector('.dropdown-toggle');
fireEvent.click(dropdownToggle);

const topPinned = document.querySelectorAll('.top-pinned');
const bottomPinned = document.querySelectorAll('.bottom-pinned');

Expand Down
16 changes: 0 additions & 16 deletions tests/ui/perfherder/alerts-view/status_dropdown_test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,6 @@ afterEach(cleanup);
test("Summary with no tags shows 'Add tags'", async () => {
const { getByText } = testStatusDropdown([]);

// Open the status dropdown first
const statusDropdown = await waitFor(() => getByText('untriaged'));
fireEvent.click(statusDropdown);

const dropdownItem = await waitFor(() => getByText('Add tags'));

expect(dropdownItem).toBeInTheDocument();
Expand All @@ -65,10 +61,6 @@ test("Summary with no tags shows 'Add tags'", async () => {
test("Summary with tags shows 'Edit tags'", async () => {
const { getByText } = testStatusDropdown(['harness']);

// Open the status dropdown first
const statusDropdown = await waitFor(() => getByText('untriaged'));
fireEvent.click(statusDropdown);

const dropdownItem = await waitFor(() => getByText('Edit tags'));

expect(dropdownItem).toBeInTheDocument();
Expand All @@ -77,10 +69,6 @@ test("Summary with tags shows 'Edit tags'", async () => {
test("Tags modal opens from 'Add tags'", async () => {
const { getByText, getByTestId } = testStatusDropdown([]);

// Open the status dropdown first
const statusDropdown = await waitFor(() => getByText('untriaged'));
fireEvent.click(statusDropdown);

const dropdownItem = await waitFor(() => getByText('Add tags'));

fireEvent.click(dropdownItem);
Expand All @@ -93,10 +81,6 @@ test("Tags modal opens from 'Add tags'", async () => {
test("Tags modal opens from 'Edit tags'", async () => {
const { getByText, getByTestId } = testStatusDropdown(['harness']);

// Open the status dropdown first
const statusDropdown = await waitFor(() => getByText('untriaged'));
fireEvent.click(statusDropdown);

const dropdownItem = await waitFor(() => getByText('Edit tags'));

fireEvent.click(dropdownItem);
Expand Down
8 changes: 6 additions & 2 deletions tests/ui/perfherder/compare-view/compare_table_test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -361,10 +361,14 @@ test('page parameter updates with value 2 when clicking on the second page', asy
expect(result2).toBeInTheDocument();
expect(result10).toBeInTheDocument();

const secondPage = await waitFor(() => findAllByLabelText('Go to page 2'));
const secondPage = await waitFor(() =>
findAllByLabelText('pagination-button-2'),
);
fireEvent.click(secondPage[0]);

const firstPage = await waitFor(() => findAllByLabelText('Go to page 1'));
const firstPage = await waitFor(() =>
findAllByLabelText('pagination-button-1'),
);
expect(firstPage[0]).toBeInTheDocument();
expect(mockUpdateParams).toHaveBeenLastCalledWith({ page: 2 });
});
Expand Down
16 changes: 8 additions & 8 deletions tests/ui/perfherder/dropdown_menu_test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,24 @@ const repoDropdownMenuItems = () =>
);

test('Pinned options are listed first', async () => {
const { container } = repoDropdownMenuItems();
const items = container.querySelectorAll('.dropdown-item');
const { getAllByRole } = repoDropdownMenuItems();
const items = getAllByRole('menuitem', { hidden: true });

expect(items[0].textContent).toContain('fenix');
expect(items[1].textContent).toContain('autoland');
expect(items[2].textContent).toContain('socorro');
});

test('Bogus pinned items are not listed', async () => {
const { container } = repoDropdownMenuItems();
const items = container.querySelectorAll('.dropdown-item');
const { getAllByRole } = repoDropdownMenuItems();
const items = getAllByRole('menuitem', { hidden: true });

expect(items[2].textContent).not.toContain('tunafish');
});

test('Unpinned items are sorted alphabetically', async () => {
const { container } = repoDropdownMenuItems();
const items = container.querySelectorAll('.dropdown-item');
const { getAllByRole } = repoDropdownMenuItems();
const items = getAllByRole('menuitem', { hidden: true });

expect(items[3].textContent).toContain('ash');
expect(items[4].textContent).toContain('mozilla-central');
Expand All @@ -53,8 +53,8 @@ test('Unpinned items are sorted alphabetically', async () => {
});

test('Pinned options are listed only once', async () => {
const { container } = repoDropdownMenuItems();
const items = container.querySelectorAll('.dropdown-item');
const { getAllByRole } = repoDropdownMenuItems();
const items = getAllByRole('menuitem', { hidden: true });

expect(items[4].textContent).not.toContain('autoland');
expect(items[5].textContent).not.toContain('fenix');
Expand Down
89 changes: 7 additions & 82 deletions tests/ui/perfherder/graphs-view/graphs_view_test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,54 +118,14 @@ const graphsViewControls = (
afterEach(cleanup);

test('Changing the platform dropdown in the Test Data Modal displays expected tests', async () => {
const {
getByText,
getByTitle,
getByTestId,
queryByText,
container,
} = graphsViewControls();
const { getByText, getByTitle, getByTestId } = graphsViewControls();

fireEvent.click(getByText('Add test data'));

// Wait for the modal to fully load with platforms
const platform = await waitFor(() => getByTitle('Platform'));

// The Platform title might be on the dropdown div, find the actual button
const platformButton =
platform.querySelector('button') ||
platform.querySelector('.dropdown-toggle');
if (platformButton) {
fireEvent.click(platformButton);
} else {
fireEvent.click(platform);
}

// Small delay to allow dropdown animation
await new Promise((resolve) => {
setTimeout(resolve, 100);
});

// Try to find windows7-32 in the dropdown
let windowsPlatform = queryByText('windows7-32');
const platform = getByTitle('Platform');
fireEvent.click(platform);

// If not found, try clicking the dropdown again (sometimes it needs a second click)
if (!windowsPlatform) {
const dropdownButton = container.querySelector(
'[title="Platform"] button.dropdown-toggle',
);
if (dropdownButton) {
fireEvent.click(dropdownButton);
await new Promise((resolve) => {
setTimeout(resolve, 100);
});
}
}

// Now wait for the platform option to appear
windowsPlatform = await waitFor(() => getByText('windows7-32'), {
timeout: 3000,
});
const windowsPlatform = await waitFor(() => getByText('windows7-32'));
fireEvent.click(windowsPlatform);

// 'mozilla-central windows7-32 a11yr opt e10s stylo'
Expand Down Expand Up @@ -359,8 +319,6 @@ test('Changing the platform dropdown while filtered by text in the Test Data Mod
getByPlaceholderText,
getByTitle,
getByTestId,
queryByText,
container,
} = graphsViewControls();

fireEvent.click(getByText('Add test data'));
Expand All @@ -382,43 +340,10 @@ test('Changing the platform dropdown while filtered by text in the Test Data Mod
expect(presentTests.children).toHaveLength(1);
expect(linuxTest).toBeInTheDocument();

const platform = await waitFor(() => getByTitle('Platform'));

// The Platform title might be on the dropdown div, find the actual button
const platformButton =
platform.querySelector('button') ||
platform.querySelector('.dropdown-toggle');
if (platformButton) {
fireEvent.click(platformButton);
} else {
fireEvent.click(platform);
}

// Small delay to allow dropdown animation
await new Promise((resolve) => {
setTimeout(resolve, 100);
});

// Try to find windows7-32 in the dropdown
let windowsPlatform = queryByText('windows7-32');
const platform = getByTitle('Platform');
fireEvent.click(platform);

// If not found, try clicking the dropdown again (sometimes it needs a second click)
if (!windowsPlatform) {
const dropdownButton = container.querySelector(
'[title="Platform"] button.dropdown-toggle',
);
if (dropdownButton) {
fireEvent.click(dropdownButton);
await new Promise((resolve) => {
setTimeout(resolve, 100);
});
}
}

// Now wait for the platform option to appear
windowsPlatform = await waitFor(() => getByText('windows7-32'), {
timeout: 3000,
});
const windowsPlatform = await waitFor(() => getByText('windows7-32'));
fireEvent.click(windowsPlatform);

// linux64 (default platform of the modal) and windows7-32 (the platform below)
Expand Down
5 changes: 0 additions & 5 deletions ui/css/perf.css
Original file line number Diff line number Diff line change
Expand Up @@ -697,8 +697,3 @@ li.pagination-active.active > button {
.multiline-text {
white-space: pre-line;
}

.pagination .page-item.active .page-link {
background-color: #17a2b8;
border-color: #17a2b8;
}
4 changes: 2 additions & 2 deletions ui/infra-compare/InfraCompareTable.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { Table } from 'react-bootstrap';
import { Table } from 'reactstrap';
import PropTypes from 'prop-types';

import { getJobsUrl } from '../helpers/url';
Expand All @@ -23,7 +23,7 @@ export default class InfraCompareTable extends React.PureComponent {
sz="small"
className="compare-table mb-0 px-0"
key={platform}
ref={(el) => {
innerRef={(el) => {
this.header = el;
}}
>
Expand Down
Loading