Device manager - sign out of multiple sessions (#9325)

* add device selection that does nothing

* multi select and sign out of sessions

* test multiple selection

* fix type after rebase
This commit is contained in:
Kerry 2022-09-30 09:07:50 +02:00 committed by GitHub
parent 7a33818bd7
commit 772df30212
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 224 additions and 33 deletions

View file

@ -214,6 +214,7 @@ exports[`<DevicesPanel /> renders device panel with devices 1`] = `
class="mx_Checkbox mx_SelectableDeviceTile_checkbox mx_Checkbox_hasKind mx_Checkbox_kind_solid"
>
<input
data-testid="device-tile-checkbox-device_2"
id="device-tile-checkbox-device_2"
type="checkbox"
/>
@ -295,6 +296,7 @@ exports[`<DevicesPanel /> renders device panel with devices 1`] = `
class="mx_Checkbox mx_SelectableDeviceTile_checkbox mx_Checkbox_hasKind mx_Checkbox_kind_solid"
>
<input
data-testid="device-tile-checkbox-device_3"
id="device-tile-checkbox-device_3"
type="checkbox"
/>

View file

@ -46,9 +46,12 @@ describe('<FilteredDeviceList />', () => {
onSignOutDevices: jest.fn(),
saveDeviceName: jest.fn(),
setPushNotifications: jest.fn(),
setPusherEnabled: jest.fn(),
setSelectedDeviceIds: jest.fn(),
localNotificationSettings: new Map(),
expandedDeviceIds: [],
signingOutDeviceIds: [],
localNotificationSettings: new Map(),
selectedDeviceIds: [],
devices: {
[unverifiedNoMetadata.device_id]: unverifiedNoMetadata,
[verifiedNoMetadata.device_id]: verifiedNoMetadata,

View file

@ -3,6 +3,7 @@
exports[`<SelectableDeviceTile /> renders selected tile 1`] = `
<input
checked=""
data-testid="device-tile-checkbox-my-device"
id="device-tile-checkbox-my-device"
type="checkbox"
/>
@ -17,6 +18,7 @@ exports[`<SelectableDeviceTile /> renders unselected device tile with checkbox 1
class="mx_Checkbox mx_SelectableDeviceTile_checkbox mx_Checkbox_hasKind mx_Checkbox_kind_solid"
>
<input
data-testid="device-tile-checkbox-my-device"
id="device-tile-checkbox-my-device"
type="checkbox"
/>

View file

@ -100,6 +100,19 @@ describe('<SessionManagerTab />', () => {
fireEvent.click(toggle);
};
const toggleDeviceSelection = (
getByTestId: ReturnType<typeof render>['getByTestId'],
deviceId: DeviceWithVerification['device_id'],
) => {
const checkbox = getByTestId(`device-tile-checkbox-${deviceId}`);
fireEvent.click(checkbox);
};
const isDeviceSelected = (
getByTestId: ReturnType<typeof render>['getByTestId'],
deviceId: DeviceWithVerification['device_id'],
): boolean => !!(getByTestId(`device-tile-checkbox-${deviceId}`) as HTMLInputElement).checked;
beforeEach(() => {
jest.clearAllMocks();
jest.spyOn(logger, 'error').mockRestore();
@ -597,6 +610,33 @@ describe('<SessionManagerTab />', () => {
'[data-testid="device-detail-sign-out-cta"]',
) as Element).getAttribute('aria-disabled')).toEqual(null);
});
it('deletes multiple devices', async () => {
mockClient.getDevices.mockResolvedValue({ devices: [
alicesDevice, alicesMobileDevice, alicesOlderMobileDevice,
] });
mockClient.deleteMultipleDevices.mockResolvedValue({});
const { getByTestId } = render(getComponent());
await act(async () => {
await flushPromisesWithFakeTimers();
});
toggleDeviceSelection(getByTestId, alicesMobileDevice.device_id);
toggleDeviceSelection(getByTestId, alicesOlderMobileDevice.device_id);
fireEvent.click(getByTestId('sign-out-selection-cta'));
// delete called with both ids
expect(mockClient.deleteMultipleDevices).toHaveBeenCalledWith(
[
alicesMobileDevice.device_id,
alicesOlderMobileDevice.device_id,
],
undefined,
);
});
});
});
@ -702,6 +742,77 @@ describe('<SessionManagerTab />', () => {
});
});
describe('Multiple selection', () => {
beforeEach(() => {
mockClient.getDevices.mockResolvedValue({ devices: [
alicesDevice, alicesMobileDevice, alicesOlderMobileDevice,
] });
});
it('toggles session selection', async () => {
const { getByTestId, getByText } = render(getComponent());
await act(async () => {
await flushPromisesWithFakeTimers();
});
toggleDeviceSelection(getByTestId, alicesMobileDevice.device_id);
toggleDeviceSelection(getByTestId, alicesOlderMobileDevice.device_id);
// header displayed correctly
expect(getByText('2 sessions selected')).toBeTruthy();
expect(isDeviceSelected(getByTestId, alicesMobileDevice.device_id)).toBeTruthy();
expect(isDeviceSelected(getByTestId, alicesOlderMobileDevice.device_id)).toBeTruthy();
toggleDeviceSelection(getByTestId, alicesMobileDevice.device_id);
// unselected
expect(isDeviceSelected(getByTestId, alicesMobileDevice.device_id)).toBeFalsy();
// still selected
expect(isDeviceSelected(getByTestId, alicesOlderMobileDevice.device_id)).toBeTruthy();
});
it('cancel button clears selection', async () => {
const { getByTestId, getByText } = render(getComponent());
await act(async () => {
await flushPromisesWithFakeTimers();
});
toggleDeviceSelection(getByTestId, alicesMobileDevice.device_id);
toggleDeviceSelection(getByTestId, alicesOlderMobileDevice.device_id);
// header displayed correctly
expect(getByText('2 sessions selected')).toBeTruthy();
fireEvent.click(getByTestId('cancel-selection-cta'));
// unselected
expect(isDeviceSelected(getByTestId, alicesMobileDevice.device_id)).toBeFalsy();
expect(isDeviceSelected(getByTestId, alicesOlderMobileDevice.device_id)).toBeFalsy();
});
it('changing the filter clears selection', async () => {
const { getByTestId } = render(getComponent());
await act(async () => {
await flushPromisesWithFakeTimers();
});
toggleDeviceSelection(getByTestId, alicesMobileDevice.device_id);
expect(isDeviceSelected(getByTestId, alicesMobileDevice.device_id)).toBeTruthy();
fireEvent.click(getByTestId('unverified-devices-cta'));
// our session manager waits a tick for rerender
await flushPromisesWithFakeTimers();
// unselected
expect(isDeviceSelected(getByTestId, alicesOlderMobileDevice.device_id)).toBeFalsy();
});
});
it("lets you change the pusher state", async () => {
const { getByTestId } = render(getComponent());