Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
test device filtering
Browse files Browse the repository at this point in the history
  • Loading branch information
Kerry Archibald committed Aug 15, 2022
1 parent e1edc2b commit 69a3b26
Show file tree
Hide file tree
Showing 4 changed files with 310 additions and 15 deletions.
12 changes: 9 additions & 3 deletions src/components/views/settings/devices/FilteredDeviceList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,13 @@ const NoResults: React.FC<NoResultsProps> = ({ filter, clearFilter }) =>
!!filter &&
<>
&nbsp;
<AccessibleButton kind='link_inline' onClick={clearFilter}>{ _t('Show all') }</AccessibleButton>
<AccessibleButton
kind='link_inline'
onClick={clearFilter}
data-testid='devices-clear-filter-btn'
>
{ _t('Show all') }
</AccessibleButton>
</>
}
</div>;
Expand Down Expand Up @@ -157,11 +163,11 @@ const FilteredDeviceList: React.FC<Props> = ({ devices, filter, onFilterChange }
</span>
<Dropdown
id='device-list-filter'
label={_t('Show')}
label={_t('Filter devices')}
value={filter || ALL_FILTER_ID}
onOptionChange={onFilterOptionChange}
>
{ options.map(({ id, label, description }) =>
{ options.map(({ id, label }) =>
<div data-test-id={`device-filter-option-${id}`} key={id}>{ label }</div>,
) }
</Dropdown>
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -1724,7 +1724,7 @@
"Not ready for secure messaging": "Not ready for secure messaging",
"Inactive": "Inactive",
"Inactive for %(inactiveAgeDays)s days or longer": "Inactive for %(inactiveAgeDays)s days or longer",
"Show": "Show",
"Filter devices": "Filter devices",
"Security recommendations": "Security recommendations",
"Improve your account security by following these recommendations": "Improve your account security by following these recommendations",
"View all": "View all",
Expand Down
138 changes: 127 additions & 11 deletions test/components/views/settings/devices/FilteredDeviceList-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,39 @@ limitations under the License.
*/

import React from 'react';
import { render } from '@testing-library/react';
import { act, fireEvent, render } from '@testing-library/react';

import FilteredDeviceList from '../../../../../src/components/views/settings/devices/FilteredDeviceList';
import { DeviceSecurityVariation } from '../../../../../src/components/views/settings/devices/filter';
import { flushPromises, mockPlatformPeg } from '../../../../test-utils';

mockPlatformPeg();

const MS_DAY = 86400000;
describe('<FilteredDeviceList />', () => {
const noMetaDevice = { device_id: 'no-meta-device', isVerified: true };
const oldDevice = { device_id: 'old', last_seen_ts: new Date(1993, 7, 3, 4).getTime(), isVerified: true };
const newDevice = {
device_id: 'new',
last_seen_ts: new Date().getTime() - 500,
last_seen_ts: Date.now() - 500,
last_seen_ip: '123.456.789',
display_name: 'My Device',
isVerified: true,
};
const unverifiedNoMetadata = { device_id: 'unverified-no-metadata', isVerified: false };
const verifiedNoMetadata = { device_id: 'verified-no-metadata', isVerified: true };
const hundredDaysOld = { device_id: '100-days-old', isVerified: true, last_seen_ts: Date.now() - (MS_DAY * 100) };
const hundredDaysOldUnverified = {
device_id: 'unverified-100-days-old',
isVerified: false,
last_seen_ts: Date.now() - (MS_DAY * 100),
};
const defaultProps = {
onFilterChange: jest.fn(),
devices: {
[noMetaDevice.device_id]: noMetaDevice,
[oldDevice.device_id]: oldDevice,
[unverifiedNoMetadata.device_id]: unverifiedNoMetadata,
[verifiedNoMetadata.device_id]: verifiedNoMetadata,
[newDevice.device_id]: newDevice,
[hundredDaysOld.device_id]: hundredDaysOld,
[hundredDaysOldUnverified.device_id]: hundredDaysOldUnverified,
},
};
const getComponent = (props = {}) =>
Expand All @@ -44,14 +57,16 @@ describe('<FilteredDeviceList />', () => {
const { container } = render(getComponent());
const tiles = container.querySelectorAll('.mx_DeviceTile');
expect(tiles[0].getAttribute('data-testid')).toEqual(`device-tile-${newDevice.device_id}`);
expect(tiles[1].getAttribute('data-testid')).toEqual(`device-tile-${oldDevice.device_id}`);
expect(tiles[2].getAttribute('data-testid')).toEqual(`device-tile-${noMetaDevice.device_id}`);
expect(tiles[1].getAttribute('data-testid')).toEqual(`device-tile-${hundredDaysOld.device_id}`);
expect(tiles[2].getAttribute('data-testid')).toEqual(`device-tile-${hundredDaysOldUnverified.device_id}`);
expect(tiles[3].getAttribute('data-testid')).toEqual(`device-tile-${unverifiedNoMetadata.device_id}`);
expect(tiles[4].getAttribute('data-testid')).toEqual(`device-tile-${verifiedNoMetadata.device_id}`);
});

it('updates list order when devices change', () => {
const updatedOldDevice = { ...oldDevice, last_seen_ts: new Date().getTime() };
const updatedOldDevice = { ...hundredDaysOld, last_seen_ts: new Date().getTime() };
const updatedDevices = {
[oldDevice.device_id]: updatedOldDevice,
[hundredDaysOld.device_id]: updatedOldDevice,
[newDevice.device_id]: newDevice,
};
const { container, rerender } = render(getComponent());
Expand All @@ -60,7 +75,108 @@ describe('<FilteredDeviceList />', () => {

const tiles = container.querySelectorAll('.mx_DeviceTile');
expect(tiles.length).toBe(2);
expect(tiles[0].getAttribute('data-testid')).toEqual(`device-tile-${oldDevice.device_id}`);
expect(tiles[0].getAttribute('data-testid')).toEqual(`device-tile-${hundredDaysOld.device_id}`);
expect(tiles[1].getAttribute('data-testid')).toEqual(`device-tile-${newDevice.device_id}`);
});

it('displays no results message when there are no devices', () => {
const { container } = render(getComponent({ devices: {} }));

expect(container.getElementsByClassName('mx_FilteredDeviceList_noResults')).toMatchSnapshot();
});

describe('filtering', () => {
const setFilter = async (
container: HTMLElement,
option: DeviceSecurityVariation | string,
) => await act(async () => {
const dropdown = container.querySelector('[aria-label="Filter devices"]');

fireEvent.click(dropdown);
// tick to let dropdown render
await flushPromises();

fireEvent.click(container.querySelector(`#device-list-filter__${option}`));
});

it('does not display filter description when filter is falsy', () => {
const { container } = render(getComponent({ filter: undefined }));
const tiles = container.querySelectorAll('.mx_DeviceTile');
expect(container.getElementsByClassName('mx_FilteredDeviceList_securityCard').length).toBeFalsy();
expect(tiles.length).toEqual(5);
});

it('updates filter when prop changes', () => {
const { container, rerender } = render(getComponent({ filter: DeviceSecurityVariation.Verified }));
const tiles = container.querySelectorAll('.mx_DeviceTile');
expect(tiles.length).toEqual(3);
expect(tiles[0].getAttribute('data-testid')).toEqual(`device-tile-${newDevice.device_id}`);
expect(tiles[1].getAttribute('data-testid')).toEqual(`device-tile-${hundredDaysOld.device_id}`);
expect(tiles[2].getAttribute('data-testid')).toEqual(`device-tile-${verifiedNoMetadata.device_id}`);

rerender(getComponent({ filter: DeviceSecurityVariation.Inactive }));

const rerenderedTiles = container.querySelectorAll('.mx_DeviceTile');
expect(rerenderedTiles.length).toEqual(2);
expect(rerenderedTiles[0].getAttribute('data-testid')).toEqual(`device-tile-${hundredDaysOld.device_id}`);
expect(rerenderedTiles[1].getAttribute('data-testid')).toEqual(
`device-tile-${hundredDaysOldUnverified.device_id}`,
);
});

it('calls onFilterChange handler', async () => {
const onFilterChange = jest.fn();
const { container } = render(getComponent({ onFilterChange }));
await setFilter(container, DeviceSecurityVariation.Verified);

expect(onFilterChange).toHaveBeenCalledWith(DeviceSecurityVariation.Verified);
});

it('calls onFilterChange handler correctly when setting filter to All', async () => {
const onFilterChange = jest.fn();
const { container } = render(getComponent({ onFilterChange, filter: DeviceSecurityVariation.Verified }));
await setFilter(container, 'ALL');

// filter is cleared
expect(onFilterChange).toHaveBeenCalledWith(undefined);
});

it.each([
[DeviceSecurityVariation.Verified, [newDevice, hundredDaysOld, verifiedNoMetadata]],
[DeviceSecurityVariation.Unverified, [hundredDaysOldUnverified, unverifiedNoMetadata]],
[DeviceSecurityVariation.Inactive, [hundredDaysOld, hundredDaysOldUnverified]],
])('filters correctly for %s', (filter, expectedDevices) => {
const { container } = render(getComponent({ filter }));
expect(container.getElementsByClassName('mx_FilteredDeviceList_securityCard')).toMatchSnapshot();
const tileDeviceIds = [...container.querySelectorAll('.mx_DeviceTile')]
.map(tile => tile.getAttribute('data-testid'));
expect(tileDeviceIds).toEqual(expectedDevices.map(device => `device-tile-${device.device_id}`));
});

it.each([
[DeviceSecurityVariation.Verified],
[DeviceSecurityVariation.Unverified],
[DeviceSecurityVariation.Inactive],
])('renders no results correctly for %s', (filter) => {
const { container } = render(getComponent({ filter, devices: {} }));
expect(container.getElementsByClassName('mx_FilteredDeviceList_securityCard').length).toBeFalsy();
expect(container.getElementsByClassName('mx_FilteredDeviceList_noResults')).toMatchSnapshot();
});

it('clears filter from no results message', () => {
const onFilterChange = jest.fn();
const { getByTestId } = render(getComponent({
onFilterChange,
filter: DeviceSecurityVariation.Verified,
devices: {
[unverifiedNoMetadata.device_id]: unverifiedNoMetadata,
},
}));
act(() => {
fireEvent.click(getByTestId('devices-clear-filter-btn'));
});

expect(onFilterChange).toHaveBeenCalledWith(undefined);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`<FilteredDeviceList /> displays no results message when there are no devices 1`] = `
HTMLCollection [
<div
class="mx_FilteredDeviceList_noResults"
>
No sessions found.
</div>,
]
`;

exports[`<FilteredDeviceList /> filtering filters correctly for Inactive 1`] = `
HTMLCollection [
<div
class="mx_FilteredDeviceList_securityCard"
>
<div
class="mx_DeviceSecurityCard"
>
<div
class="mx_DeviceSecurityCard_icon Inactive"
>
<div
height="16"
width="16"
/>
</div>
<div
class="mx_DeviceSecurityCard_content"
>
<p
class="mx_DeviceSecurityCard_heading"
>
Inactive sessions
</p>
<p
class="mx_DeviceSecurityCard_description"
>
Consider signing out from old sessions (90 days or older) you don't use anymore
</p>
</div>
</div>
</div>,
]
`;

exports[`<FilteredDeviceList /> filtering filters correctly for Unverified 1`] = `
HTMLCollection [
<div
class="mx_FilteredDeviceList_securityCard"
>
<div
class="mx_DeviceSecurityCard"
>
<div
class="mx_DeviceSecurityCard_icon Unverified"
>
<div
height="16"
width="16"
/>
</div>
<div
class="mx_DeviceSecurityCard_content"
>
<p
class="mx_DeviceSecurityCard_heading"
>
Unverified sessions
</p>
<p
class="mx_DeviceSecurityCard_description"
>
Verify your sessions for enhanced secure messaging or sign out from those you don't recognize or use anymore.
</p>
</div>
</div>
</div>,
]
`;

exports[`<FilteredDeviceList /> filtering filters correctly for Verified 1`] = `
HTMLCollection [
<div
class="mx_FilteredDeviceList_securityCard"
>
<div
class="mx_DeviceSecurityCard"
>
<div
class="mx_DeviceSecurityCard_icon Verified"
>
<div
height="16"
width="16"
/>
</div>
<div
class="mx_DeviceSecurityCard_content"
>
<p
class="mx_DeviceSecurityCard_heading"
>
Verified sessions
</p>
<p
class="mx_DeviceSecurityCard_description"
>
For best security, sign out from any session that you don't recognize or use anymore.
</p>
</div>
</div>
</div>,
]
`;

exports[`<FilteredDeviceList /> filtering renders no results correctly for Inactive 1`] = `
HTMLCollection [
<div
class="mx_FilteredDeviceList_noResults"
>
No inactive sessions found.
 
<div
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
data-testid="devices-clear-filter-btn"
role="button"
tabindex="0"
>
Show all
</div>
</div>,
]
`;

exports[`<FilteredDeviceList /> filtering renders no results correctly for Unverified 1`] = `
HTMLCollection [
<div
class="mx_FilteredDeviceList_noResults"
>
No unverified sessions found.
 
<div
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
data-testid="devices-clear-filter-btn"
role="button"
tabindex="0"
>
Show all
</div>
</div>,
]
`;

exports[`<FilteredDeviceList /> filtering renders no results correctly for Verified 1`] = `
HTMLCollection [
<div
class="mx_FilteredDeviceList_noResults"
>
No verified sessions found.
 
<div
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
data-testid="devices-clear-filter-btn"
role="button"
tabindex="0"
>
Show all
</div>
</div>,
]
`;

0 comments on commit 69a3b26

Please sign in to comment.