Apply prettier formatting

This commit is contained in:
Michael Weimann 2022-12-12 12:24:14 +01:00
parent 1cac306093
commit 526645c791
No known key found for this signature in database
GPG key ID: 53F535A266BB9584
1576 changed files with 65385 additions and 62478 deletions

View file

@ -14,15 +14,15 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import { fireEvent, render } from '@testing-library/react';
import { act } from 'react-dom/test-utils';
import React from "react";
import { fireEvent, render } from "@testing-library/react";
import { act } from "react-dom/test-utils";
import CurrentDeviceSection from '../../../../../src/components/views/settings/devices/CurrentDeviceSection';
import { DeviceType } from '../../../../../src/utils/device/parseUserAgent';
import CurrentDeviceSection from "../../../../../src/components/views/settings/devices/CurrentDeviceSection";
import { DeviceType } from "../../../../../src/utils/device/parseUserAgent";
describe('<CurrentDeviceSection />', () => {
const deviceId = 'alices_device';
describe("<CurrentDeviceSection />", () => {
const deviceId = "alices_device";
const alicesVerifiedDevice = {
device_id: deviceId,
@ -44,60 +44,59 @@ describe('<CurrentDeviceSection />', () => {
isSigningOut: false,
};
const getComponent = (props = {}): React.ReactElement =>
(<CurrentDeviceSection {...defaultProps} {...props} />);
const getComponent = (props = {}): React.ReactElement => <CurrentDeviceSection {...defaultProps} {...props} />;
it('renders spinner while device is loading', () => {
it("renders spinner while device is loading", () => {
const { container } = render(getComponent({ device: undefined, isLoading: true }));
expect(container.getElementsByClassName('mx_Spinner').length).toBeTruthy();
expect(container.getElementsByClassName("mx_Spinner").length).toBeTruthy();
});
it('handles when device is falsy', async () => {
it("handles when device is falsy", async () => {
const { container } = render(getComponent({ device: undefined }));
expect(container).toMatchSnapshot();
});
it('renders device and correct security card when device is verified', () => {
it("renders device and correct security card when device is verified", () => {
const { container } = render(getComponent());
expect(container).toMatchSnapshot();
});
it('renders device and correct security card when device is unverified', () => {
it("renders device and correct security card when device is unverified", () => {
const { container } = render(getComponent({ device: alicesUnverifiedDevice }));
expect(container).toMatchSnapshot();
});
it('displays device details on main tile click', () => {
it("displays device details on main tile click", () => {
const { getByTestId, container } = render(getComponent({ device: alicesUnverifiedDevice }));
act(() => {
fireEvent.click(getByTestId(`device-tile-${alicesUnverifiedDevice.device_id}`));
});
expect(container.getElementsByClassName('mx_DeviceDetails').length).toBeTruthy();
expect(container.getElementsByClassName("mx_DeviceDetails").length).toBeTruthy();
act(() => {
fireEvent.click(getByTestId(`device-tile-${alicesUnverifiedDevice.device_id}`));
});
// device details are hidden
expect(container.getElementsByClassName('mx_DeviceDetails').length).toBeFalsy();
expect(container.getElementsByClassName("mx_DeviceDetails").length).toBeFalsy();
});
it('displays device details on toggle click', () => {
it("displays device details on toggle click", () => {
const { container, getByTestId } = render(getComponent({ device: alicesUnverifiedDevice }));
act(() => {
fireEvent.click(getByTestId('current-session-toggle-details'));
fireEvent.click(getByTestId("current-session-toggle-details"));
});
expect(container.getElementsByClassName('mx_DeviceDetails')).toMatchSnapshot();
expect(container.getElementsByClassName("mx_DeviceDetails")).toMatchSnapshot();
act(() => {
fireEvent.click(getByTestId('current-session-toggle-details'));
fireEvent.click(getByTestId("current-session-toggle-details"));
});
// device details are hidden
expect(container.getElementsByClassName('mx_DeviceDetails').length).toBeFalsy();
expect(container.getElementsByClassName("mx_DeviceDetails").length).toBeFalsy();
});
});

View file

@ -14,19 +14,19 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import { fireEvent, render, RenderResult } from '@testing-library/react';
import React from "react";
import { fireEvent, render, RenderResult } from "@testing-library/react";
import { DeviceDetailHeading } from '../../../../../src/components/views/settings/devices/DeviceDetailHeading';
import { flushPromisesWithFakeTimers } from '../../../../test-utils';
import { DeviceType } from '../../../../../src/utils/device/parseUserAgent';
import { DeviceDetailHeading } from "../../../../../src/components/views/settings/devices/DeviceDetailHeading";
import { flushPromisesWithFakeTimers } from "../../../../test-utils";
import { DeviceType } from "../../../../../src/utils/device/parseUserAgent";
jest.useFakeTimers();
describe('<DeviceDetailHeading />', () => {
describe("<DeviceDetailHeading />", () => {
const device = {
device_id: '123',
display_name: 'My device',
device_id: "123",
display_name: "My device",
isVerified: true,
deviceType: DeviceType.Unknown,
};
@ -34,104 +34,101 @@ describe('<DeviceDetailHeading />', () => {
device,
saveDeviceName: jest.fn(),
};
const getComponent = (props = {}) =>
<DeviceDetailHeading {...defaultProps} {...props} />;
const getComponent = (props = {}) => <DeviceDetailHeading {...defaultProps} {...props} />;
const setInputValue = (getByTestId: RenderResult['getByTestId'], value: string) => {
const input = getByTestId('device-rename-input');
const setInputValue = (getByTestId: RenderResult["getByTestId"], value: string) => {
const input = getByTestId("device-rename-input");
fireEvent.change(input, { target: { value } });
};
it('renders device name', () => {
it("renders device name", () => {
const { container } = render(getComponent());
expect({ container }).toMatchSnapshot();
});
it('renders device id as fallback when device has no display name ', () => {
const { getByText } = render(getComponent({
device: { ...device, display_name: undefined },
}));
it("renders device id as fallback when device has no display name ", () => {
const { getByText } = render(
getComponent({
device: { ...device, display_name: undefined },
}),
);
expect(getByText(device.device_id)).toBeTruthy();
});
it('displays name edit form on rename button click', () => {
it("displays name edit form on rename button click", () => {
const { getByTestId, container } = render(getComponent());
fireEvent.click(getByTestId('device-heading-rename-cta'));
fireEvent.click(getByTestId("device-heading-rename-cta"));
expect({ container }).toMatchSnapshot();
});
it('cancelling edit switches back to original display', () => {
it("cancelling edit switches back to original display", () => {
const { getByTestId, container } = render(getComponent());
// start editing
fireEvent.click(getByTestId('device-heading-rename-cta'));
fireEvent.click(getByTestId("device-heading-rename-cta"));
// stop editing
fireEvent.click(getByTestId('device-rename-cancel-cta'));
fireEvent.click(getByTestId("device-rename-cancel-cta"));
expect(container.getElementsByClassName('mx_DeviceDetailHeading').length).toBe(1);
expect(container.getElementsByClassName("mx_DeviceDetailHeading").length).toBe(1);
});
it('clicking submit updates device name with edited value', () => {
it("clicking submit updates device name with edited value", () => {
const saveDeviceName = jest.fn();
const { getByTestId } = render(getComponent({ saveDeviceName }));
// start editing
fireEvent.click(getByTestId('device-heading-rename-cta'));
fireEvent.click(getByTestId("device-heading-rename-cta"));
setInputValue(getByTestId, 'new device name');
setInputValue(getByTestId, "new device name");
fireEvent.click(getByTestId('device-rename-submit-cta'));
fireEvent.click(getByTestId("device-rename-submit-cta"));
expect(saveDeviceName).toHaveBeenCalledWith('new device name');
expect(saveDeviceName).toHaveBeenCalledWith("new device name");
});
it('disables form while device name is saving', () => {
it("disables form while device name is saving", () => {
const { getByTestId, container } = render(getComponent());
// start editing
fireEvent.click(getByTestId('device-heading-rename-cta'));
fireEvent.click(getByTestId("device-heading-rename-cta"));
setInputValue(getByTestId, 'new device name');
setInputValue(getByTestId, "new device name");
fireEvent.click(getByTestId('device-rename-submit-cta'));
fireEvent.click(getByTestId("device-rename-submit-cta"));
// buttons disabled
expect(
getByTestId('device-rename-cancel-cta').getAttribute('aria-disabled'),
).toEqual("true");
expect(
getByTestId('device-rename-submit-cta').getAttribute('aria-disabled'),
).toEqual("true");
expect(getByTestId("device-rename-cancel-cta").getAttribute("aria-disabled")).toEqual("true");
expect(getByTestId("device-rename-submit-cta").getAttribute("aria-disabled")).toEqual("true");
expect(container.getElementsByClassName('mx_Spinner').length).toBeTruthy();
expect(container.getElementsByClassName("mx_Spinner").length).toBeTruthy();
});
it('toggles out of editing mode when device name is saved successfully', async () => {
it("toggles out of editing mode when device name is saved successfully", async () => {
const { getByTestId } = render(getComponent());
// start editing
fireEvent.click(getByTestId('device-heading-rename-cta'));
setInputValue(getByTestId, 'new device name');
fireEvent.click(getByTestId('device-rename-submit-cta'));
fireEvent.click(getByTestId("device-heading-rename-cta"));
setInputValue(getByTestId, "new device name");
fireEvent.click(getByTestId("device-rename-submit-cta"));
await flushPromisesWithFakeTimers();
// read mode displayed
expect(getByTestId('device-detail-heading')).toBeTruthy();
expect(getByTestId("device-detail-heading")).toBeTruthy();
});
it('displays error when device name fails to save', async () => {
const saveDeviceName = jest.fn().mockRejectedValueOnce('oups').mockResolvedValue({});
it("displays error when device name fails to save", async () => {
const saveDeviceName = jest.fn().mockRejectedValueOnce("oups").mockResolvedValue({});
const { getByTestId, queryByText, container } = render(getComponent({ saveDeviceName }));
// start editing
fireEvent.click(getByTestId('device-heading-rename-cta'));
setInputValue(getByTestId, 'new device name');
fireEvent.click(getByTestId('device-rename-submit-cta'));
fireEvent.click(getByTestId("device-heading-rename-cta"));
setInputValue(getByTestId, "new device name");
fireEvent.click(getByTestId("device-rename-submit-cta"));
// flush promise
await flushPromisesWithFakeTimers();
@ -139,14 +136,14 @@ describe('<DeviceDetailHeading />', () => {
await flushPromisesWithFakeTimers();
// error message displayed
expect(queryByText('Failed to set display name')).toBeTruthy();
expect(queryByText("Failed to set display name")).toBeTruthy();
// spinner removed
expect(container.getElementsByClassName('mx_Spinner').length).toBeFalsy();
expect(container.getElementsByClassName("mx_Spinner").length).toBeFalsy();
// try again
fireEvent.click(getByTestId('device-rename-submit-cta'));
fireEvent.click(getByTestId("device-rename-submit-cta"));
// error message cleared
expect(queryByText('Failed to set display name')).toBeFalsy();
expect(queryByText("Failed to set display name")).toBeFalsy();
});
});

View file

@ -14,17 +14,17 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import { fireEvent, render } from '@testing-library/react';
import { PUSHER_ENABLED } from 'matrix-js-sdk/src/@types/event';
import React from "react";
import { fireEvent, render } from "@testing-library/react";
import { PUSHER_ENABLED } from "matrix-js-sdk/src/@types/event";
import DeviceDetails from '../../../../../src/components/views/settings/devices/DeviceDetails';
import { mkPusher } from '../../../../test-utils/test-utils';
import { DeviceType } from '../../../../../src/utils/device/parseUserAgent';
import DeviceDetails from "../../../../../src/components/views/settings/devices/DeviceDetails";
import { mkPusher } from "../../../../test-utils/test-utils";
import { DeviceType } from "../../../../../src/utils/device/parseUserAgent";
describe('<DeviceDetails />', () => {
describe("<DeviceDetails />", () => {
const baseDevice = {
device_id: 'my-device',
device_id: "my-device",
isVerified: false,
deviceType: DeviceType.Unknown,
};
@ -49,27 +49,27 @@ describe('<DeviceDetails />', () => {
jest.setSystemTime(now);
});
it('renders device without metadata', () => {
it("renders device without metadata", () => {
const { container } = render(getComponent());
expect(container).toMatchSnapshot();
});
it('renders device with metadata', () => {
it("renders device with metadata", () => {
const device = {
...baseDevice,
display_name: 'My Device',
last_seen_ip: '123.456.789',
display_name: "My Device",
last_seen_ip: "123.456.789",
last_seen_ts: now - 60000000,
appName: 'Element Web',
client: 'Firefox 100',
deviceModel: 'Iphone X',
deviceOperatingSystem: 'Windows 95',
appName: "Element Web",
client: "Firefox 100",
deviceModel: "Iphone X",
deviceOperatingSystem: "Windows 95",
};
const { container } = render(getComponent({ device }));
expect(container).toMatchSnapshot();
});
it('renders a verified device', () => {
it("renders a verified device", () => {
const device = {
...baseDevice,
isVerified: true,
@ -78,17 +78,15 @@ describe('<DeviceDetails />', () => {
expect(container).toMatchSnapshot();
});
it('disables sign out button while sign out is pending', () => {
it("disables sign out button while sign out is pending", () => {
const device = {
...baseDevice,
};
const { getByTestId } = render(getComponent({ device, isSigningOut: true }));
expect(
getByTestId('device-detail-sign-out-cta').getAttribute('aria-disabled'),
).toEqual("true");
expect(getByTestId("device-detail-sign-out-cta").getAttribute("aria-disabled")).toEqual("true");
});
it('renders the push notification section when a pusher exists', () => {
it("renders the push notification section when a pusher exists", () => {
const device = {
...baseDevice,
};
@ -96,30 +94,34 @@ describe('<DeviceDetails />', () => {
device_id: device.device_id,
});
const { getByTestId } = render(getComponent({
device,
pusher,
isSigningOut: true,
}));
const { getByTestId } = render(
getComponent({
device,
pusher,
isSigningOut: true,
}),
);
expect(getByTestId('device-detail-push-notification')).toBeTruthy();
expect(getByTestId("device-detail-push-notification")).toBeTruthy();
});
it('hides the push notification section when no pusher', () => {
it("hides the push notification section when no pusher", () => {
const device = {
...baseDevice,
};
const { getByTestId } = render(getComponent({
device,
pusher: null,
isSigningOut: true,
}));
const { getByTestId } = render(
getComponent({
device,
pusher: null,
isSigningOut: true,
}),
);
expect(() => getByTestId('device-detail-push-notification')).toThrow();
expect(() => getByTestId("device-detail-push-notification")).toThrow();
});
it('disables the checkbox when there is no server support', () => {
it("disables the checkbox when there is no server support", () => {
const device = {
...baseDevice,
};
@ -128,20 +130,22 @@ describe('<DeviceDetails />', () => {
[PUSHER_ENABLED.name]: false,
});
const { getByTestId } = render(getComponent({
device,
pusher,
isSigningOut: true,
supportsMSC3881: false,
}));
const { getByTestId } = render(
getComponent({
device,
pusher,
isSigningOut: true,
supportsMSC3881: false,
}),
);
const checkbox = getByTestId('device-detail-push-notification-checkbox');
const checkbox = getByTestId("device-detail-push-notification-checkbox");
expect(checkbox.getAttribute('aria-disabled')).toEqual("true");
expect(checkbox.getAttribute('aria-checked')).toEqual("false");
expect(checkbox.getAttribute("aria-disabled")).toEqual("true");
expect(checkbox.getAttribute("aria-checked")).toEqual("false");
});
it('changes the pusher status when clicked', () => {
it("changes the pusher status when clicked", () => {
const device = {
...baseDevice,
};
@ -153,35 +157,39 @@ describe('<DeviceDetails />', () => {
[PUSHER_ENABLED.name]: enabled,
});
const { getByTestId } = render(getComponent({
device,
pusher,
isSigningOut: true,
}));
const { getByTestId } = render(
getComponent({
device,
pusher,
isSigningOut: true,
}),
);
const checkbox = getByTestId('device-detail-push-notification-checkbox');
const checkbox = getByTestId("device-detail-push-notification-checkbox");
fireEvent.click(checkbox);
expect(defaultProps.setPushNotifications).toHaveBeenCalledWith(device.device_id, !enabled);
});
it('changes the local notifications settings status when clicked', () => {
it("changes the local notifications settings status when clicked", () => {
const device = {
...baseDevice,
};
const enabled = false;
const { getByTestId } = render(getComponent({
device,
localNotificationSettings: {
is_silenced: !enabled,
},
isSigningOut: true,
}));
const { getByTestId } = render(
getComponent({
device,
localNotificationSettings: {
is_silenced: !enabled,
},
isSigningOut: true,
}),
);
const checkbox = getByTestId('device-detail-push-notification-checkbox');
const checkbox = getByTestId("device-detail-push-notification-checkbox");
fireEvent.click(checkbox);
expect(defaultProps.setPushNotifications).toHaveBeenCalledWith(device.device_id, !enabled);

View file

@ -14,35 +14,32 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import { fireEvent, render } from '@testing-library/react';
import React from "react";
import { fireEvent, render } from "@testing-library/react";
import {
DeviceExpandDetailsButton,
} from '../../../../../src/components/views/settings/devices/DeviceExpandDetailsButton';
import { DeviceExpandDetailsButton } from "../../../../../src/components/views/settings/devices/DeviceExpandDetailsButton";
describe('<DeviceExpandDetailsButton />', () => {
describe("<DeviceExpandDetailsButton />", () => {
const defaultProps = {
isExpanded: false,
onClick: jest.fn(),
};
const getComponent = (props = {}) =>
<DeviceExpandDetailsButton {...defaultProps} {...props} />;
const getComponent = (props = {}) => <DeviceExpandDetailsButton {...defaultProps} {...props} />;
it('renders when not expanded', () => {
it("renders when not expanded", () => {
const { container } = render(getComponent());
expect({ container }).toMatchSnapshot();
});
it('renders when expanded', () => {
it("renders when expanded", () => {
const { container } = render(getComponent({ isExpanded: true }));
expect({ container }).toMatchSnapshot();
});
it('calls onClick', () => {
it("calls onClick", () => {
const onClick = jest.fn();
const { getByTestId } = render(getComponent({ 'data-testid': 'test', onClick }));
fireEvent.click(getByTestId('test'));
const { getByTestId } = render(getComponent({ "data-testid": "test", onClick }));
fireEvent.click(getByTestId("test"));
expect(onClick).toHaveBeenCalled();
});

View file

@ -14,31 +14,32 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { render } from '@testing-library/react';
import React from 'react';
import { render } from "@testing-library/react";
import React from "react";
import DeviceSecurityCard from '../../../../../src/components/views/settings/devices/DeviceSecurityCard';
import { DeviceSecurityVariation } from '../../../../../src/components/views/settings/devices/types';
import DeviceSecurityCard from "../../../../../src/components/views/settings/devices/DeviceSecurityCard";
import { DeviceSecurityVariation } from "../../../../../src/components/views/settings/devices/types";
describe('<DeviceSecurityCard />', () => {
describe("<DeviceSecurityCard />", () => {
const defaultProps = {
variation: DeviceSecurityVariation.Verified,
heading: 'Verified session',
description: 'nice',
heading: "Verified session",
description: "nice",
};
const getComponent = (props = {}): React.ReactElement =>
<DeviceSecurityCard {...defaultProps} {...props} />;
const getComponent = (props = {}): React.ReactElement => <DeviceSecurityCard {...defaultProps} {...props} />;
it('renders basic card', () => {
it("renders basic card", () => {
const { container } = render(getComponent());
expect(container).toMatchSnapshot();
});
it('renders with children', () => {
const { container } = render(getComponent({
children: <div>hey</div>,
variation: DeviceSecurityVariation.Unverified,
}));
it("renders with children", () => {
const { container } = render(
getComponent({
children: <div>hey</div>,
variation: DeviceSecurityVariation.Unverified,
}),
);
expect(container).toMatchSnapshot();
});
});

View file

@ -14,24 +14,22 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import { render } from '@testing-library/react';
import { IMyDevice } from 'matrix-js-sdk/src/matrix';
import React from "react";
import { render } from "@testing-library/react";
import { IMyDevice } from "matrix-js-sdk/src/matrix";
import DeviceTile from '../../../../../src/components/views/settings/devices/DeviceTile';
import { DeviceType } from '../../../../../src/utils/device/parseUserAgent';
import DeviceTile from "../../../../../src/components/views/settings/devices/DeviceTile";
import { DeviceType } from "../../../../../src/utils/device/parseUserAgent";
describe('<DeviceTile />', () => {
describe("<DeviceTile />", () => {
const defaultProps = {
device: {
device_id: '123',
device_id: "123",
isVerified: false,
deviceType: DeviceType.Unknown,
},
};
const getComponent = (props = {}) => (
<DeviceTile {...defaultProps} {...props} />
);
const getComponent = (props = {}) => <DeviceTile {...defaultProps} {...props} />;
// 14.03.2022 16:15
const now = 1647270879403;
@ -41,96 +39,94 @@ describe('<DeviceTile />', () => {
jest.setSystemTime(now);
});
it('renders a device with no metadata', () => {
it("renders a device with no metadata", () => {
const { container } = render(getComponent());
expect(container).toMatchSnapshot();
});
it('applies interactive class when tile has click handler', () => {
it("applies interactive class when tile has click handler", () => {
const onClick = jest.fn();
const { getByTestId } = render(getComponent({ onClick }));
expect(
getByTestId('device-tile-123').className.includes('mx_DeviceTile_interactive'),
).toBeTruthy();
expect(getByTestId("device-tile-123").className.includes("mx_DeviceTile_interactive")).toBeTruthy();
});
it('renders a verified device with no metadata', () => {
it("renders a verified device with no metadata", () => {
const { container } = render(getComponent());
expect(container).toMatchSnapshot();
});
it('renders display name with a tooltip', () => {
it("renders display name with a tooltip", () => {
const device: IMyDevice = {
device_id: '123',
display_name: 'My device',
device_id: "123",
display_name: "My device",
};
const { container } = render(getComponent({ device }));
expect(container).toMatchSnapshot();
});
it('renders last seen ip metadata', () => {
it("renders last seen ip metadata", () => {
const device: IMyDevice = {
device_id: '123',
display_name: 'My device',
last_seen_ip: '1.2.3.4',
device_id: "123",
display_name: "My device",
last_seen_ip: "1.2.3.4",
};
const { getByTestId } = render(getComponent({ device }));
expect(getByTestId('device-metadata-lastSeenIp').textContent).toEqual(device.last_seen_ip);
expect(getByTestId("device-metadata-lastSeenIp").textContent).toEqual(device.last_seen_ip);
});
it('separates metadata with a dot', () => {
it("separates metadata with a dot", () => {
const device: IMyDevice = {
device_id: '123',
last_seen_ip: '1.2.3.4',
device_id: "123",
last_seen_ip: "1.2.3.4",
last_seen_ts: now - 60000,
};
const { container } = render(getComponent({ device }));
expect(container).toMatchSnapshot();
});
describe('Last activity', () => {
describe("Last activity", () => {
const MS_DAY = 24 * 60 * 60 * 1000;
it('renders with day of week and time when last activity is less than 6 days ago', () => {
it("renders with day of week and time when last activity is less than 6 days ago", () => {
const device: IMyDevice = {
device_id: '123',
last_seen_ip: '1.2.3.4',
last_seen_ts: now - (MS_DAY * 3),
device_id: "123",
last_seen_ip: "1.2.3.4",
last_seen_ts: now - MS_DAY * 3,
};
const { getByTestId } = render(getComponent({ device }));
expect(getByTestId('device-metadata-lastActivity').textContent).toEqual('Last activity Fri 15:14');
expect(getByTestId("device-metadata-lastActivity").textContent).toEqual("Last activity Fri 15:14");
});
it('renders with month and date when last activity is more than 6 days ago', () => {
it("renders with month and date when last activity is more than 6 days ago", () => {
const device: IMyDevice = {
device_id: '123',
last_seen_ip: '1.2.3.4',
last_seen_ts: now - (MS_DAY * 8),
device_id: "123",
last_seen_ip: "1.2.3.4",
last_seen_ts: now - MS_DAY * 8,
};
const { getByTestId } = render(getComponent({ device }));
expect(getByTestId('device-metadata-lastActivity').textContent).toEqual('Last activity Mar 6');
expect(getByTestId("device-metadata-lastActivity").textContent).toEqual("Last activity Mar 6");
});
it('renders with month, date, year when activity is in a different calendar year', () => {
it("renders with month, date, year when activity is in a different calendar year", () => {
const device: IMyDevice = {
device_id: '123',
last_seen_ip: '1.2.3.4',
last_seen_ts: new Date('2021-12-29').getTime(),
device_id: "123",
last_seen_ip: "1.2.3.4",
last_seen_ts: new Date("2021-12-29").getTime(),
};
const { getByTestId } = render(getComponent({ device }));
expect(getByTestId('device-metadata-lastActivity').textContent).toEqual('Last activity Dec 29, 2021');
expect(getByTestId("device-metadata-lastActivity").textContent).toEqual("Last activity Dec 29, 2021");
});
it('renders with inactive notice when last activity was more than 90 days ago', () => {
it("renders with inactive notice when last activity was more than 90 days ago", () => {
const device: IMyDevice = {
device_id: '123',
last_seen_ip: '1.2.3.4',
last_seen_ts: now - (MS_DAY * 100),
device_id: "123",
last_seen_ip: "1.2.3.4",
last_seen_ts: now - MS_DAY * 100,
};
const { getByTestId, queryByTestId } = render(getComponent({ device }));
expect(getByTestId('device-metadata-inactive').textContent).toEqual('Inactive for 90+ days (Dec 4, 2021)');
expect(getByTestId("device-metadata-inactive").textContent).toEqual("Inactive for 90+ days (Dec 4, 2021)");
// last activity and verification not shown when inactive
expect(queryByTestId('device-metadata-lastActivity')).toBeFalsy();
expect(queryByTestId('device-metadata-verificationStatus')).toBeFalsy();
expect(queryByTestId("device-metadata-lastActivity")).toBeFalsy();
expect(queryByTestId("device-metadata-verificationStatus")).toBeFalsy();
});
});
});

View file

@ -14,61 +14,60 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { render } from '@testing-library/react';
import React from 'react';
import { render } from "@testing-library/react";
import React from "react";
import { DeviceTypeIcon } from '../../../../../src/components/views/settings/devices/DeviceTypeIcon';
import { DeviceType } from '../../../../../src/utils/device/parseUserAgent';
import { DeviceTypeIcon } from "../../../../../src/components/views/settings/devices/DeviceTypeIcon";
import { DeviceType } from "../../../../../src/utils/device/parseUserAgent";
describe('<DeviceTypeIcon />', () => {
describe("<DeviceTypeIcon />", () => {
const defaultProps = {
isVerified: false,
isSelected: false,
};
const getComponent = (props = {}) =>
<DeviceTypeIcon {...defaultProps} {...props} />;
const getComponent = (props = {}) => <DeviceTypeIcon {...defaultProps} {...props} />;
it('renders an unverified device', () => {
it("renders an unverified device", () => {
const { container } = render(getComponent());
expect(container).toMatchSnapshot();
});
it('renders a verified device', () => {
it("renders a verified device", () => {
const { container } = render(getComponent({ isVerified: true }));
expect(container).toMatchSnapshot();
});
it('renders correctly when selected', () => {
it("renders correctly when selected", () => {
const { container } = render(getComponent({ isSelected: true }));
expect(container).toMatchSnapshot();
});
it('renders an unknown device icon when no device type given', () => {
it("renders an unknown device icon when no device type given", () => {
const { getByLabelText } = render(getComponent());
expect(getByLabelText('Unknown session type')).toBeTruthy();
expect(getByLabelText("Unknown session type")).toBeTruthy();
});
it('renders a desktop device type', () => {
it("renders a desktop device type", () => {
const deviceType = DeviceType.Desktop;
const { getByLabelText } = render(getComponent({ deviceType }));
expect(getByLabelText('Desktop session')).toBeTruthy();
expect(getByLabelText("Desktop session")).toBeTruthy();
});
it('renders a web device type', () => {
it("renders a web device type", () => {
const deviceType = DeviceType.Web;
const { getByLabelText } = render(getComponent({ deviceType }));
expect(getByLabelText('Web session')).toBeTruthy();
expect(getByLabelText("Web session")).toBeTruthy();
});
it('renders a mobile device type', () => {
it("renders a mobile device type", () => {
const deviceType = DeviceType.Mobile;
const { getByLabelText } = render(getComponent({ deviceType }));
expect(getByLabelText('Mobile session')).toBeTruthy();
expect(getByLabelText("Mobile session")).toBeTruthy();
});
it('renders an unknown device type', () => {
it("renders an unknown device type", () => {
const deviceType = DeviceType.Unknown;
const { getByLabelText } = render(getComponent({ deviceType }));
expect(getByLabelText('Unknown session type')).toBeTruthy();
expect(getByLabelText("Unknown session type")).toBeTruthy();
});
});

View file

@ -14,43 +14,46 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import { act, fireEvent, render } from '@testing-library/react';
import React from "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/types';
import { flushPromises, mockPlatformPeg } from '../../../../test-utils';
import { DeviceType } from '../../../../../src/utils/device/parseUserAgent';
import { FilteredDeviceList } from "../../../../../src/components/views/settings/devices/FilteredDeviceList";
import { DeviceSecurityVariation } from "../../../../../src/components/views/settings/devices/types";
import { flushPromises, mockPlatformPeg } from "../../../../test-utils";
import { DeviceType } from "../../../../../src/utils/device/parseUserAgent";
mockPlatformPeg();
const MS_DAY = 86400000;
describe('<FilteredDeviceList />', () => {
describe("<FilteredDeviceList />", () => {
const newDevice = {
device_id: 'new',
device_id: "new",
last_seen_ts: Date.now() - 500,
last_seen_ip: '123.456.789',
display_name: 'My Device',
last_seen_ip: "123.456.789",
display_name: "My Device",
isVerified: true,
deviceType: DeviceType.Unknown,
};
const unverifiedNoMetadata = {
device_id: 'unverified-no-metadata',
device_id: "unverified-no-metadata",
isVerified: false,
deviceType: DeviceType.Unknown };
deviceType: DeviceType.Unknown,
};
const verifiedNoMetadata = {
device_id: 'verified-no-metadata',
device_id: "verified-no-metadata",
isVerified: true,
deviceType: DeviceType.Unknown };
deviceType: DeviceType.Unknown,
};
const hundredDaysOld = {
device_id: '100-days-old',
device_id: "100-days-old",
isVerified: true,
last_seen_ts: Date.now() - (MS_DAY * 100),
deviceType: DeviceType.Unknown };
last_seen_ts: Date.now() - MS_DAY * 100,
deviceType: DeviceType.Unknown,
};
const hundredDaysOldUnverified = {
device_id: 'unverified-100-days-old',
device_id: "unverified-100-days-old",
isVerified: false,
last_seen_ts: Date.now() - (MS_DAY * 100),
last_seen_ts: Date.now() - MS_DAY * 100,
deviceType: DeviceType.Unknown,
};
const defaultProps = {
@ -76,20 +79,19 @@ describe('<FilteredDeviceList />', () => {
supportsMSC3881: true,
};
const getComponent = (props = {}) =>
(<FilteredDeviceList {...defaultProps} {...props} />);
const getComponent = (props = {}) => <FilteredDeviceList {...defaultProps} {...props} />;
it('renders devices in correct order', () => {
it("renders devices in correct order", () => {
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-${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}`);
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-${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', () => {
it("updates list order when devices change", () => {
const updatedOldDevice = { ...hundredDaysOld, last_seen_ts: new Date().getTime() };
const updatedDevices = {
[hundredDaysOld.device_id]: updatedOldDevice,
@ -99,58 +101,56 @@ describe('<FilteredDeviceList />', () => {
rerender(getComponent({ devices: updatedDevices }));
const tiles = container.querySelectorAll('.mx_DeviceTile');
const tiles = container.querySelectorAll(".mx_DeviceTile");
expect(tiles.length).toBe(2);
expect(tiles[0].getAttribute('data-testid')).toEqual(`device-tile-${hundredDaysOld.device_id}`);
expect(tiles[1].getAttribute('data-testid')).toEqual(`device-tile-${newDevice.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', () => {
it("displays no results message when there are no devices", () => {
const { container } = render(getComponent({ devices: {} }));
expect(container.getElementsByClassName('mx_FilteredDeviceList_noResults')).toMatchSnapshot();
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"]');
describe("filtering", () => {
const setFilter = async (container: HTMLElement, option: DeviceSecurityVariation | string) =>
await act(async () => {
const dropdown = container.querySelector('[aria-label="Filter devices"]');
fireEvent.click(dropdown as Element);
// tick to let dropdown render
await flushPromises();
fireEvent.click(dropdown as Element);
// tick to let dropdown render
await flushPromises();
fireEvent.click(container.querySelector(`#device-list-filter__${option}`) as Element);
});
fireEvent.click(container.querySelector(`#device-list-filter__${option}`) as Element);
});
it('does not display filter description when filter is falsy', () => {
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();
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', () => {
it("updates filter when prop changes", () => {
const { container, rerender } = render(getComponent({ filter: DeviceSecurityVariation.Verified }));
const tiles = container.querySelectorAll('.mx_DeviceTile');
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}`);
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');
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(
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 () => {
it("calls onFilterChange handler", async () => {
const onFilterChange = jest.fn();
const { container } = render(getComponent({ onFilterChange }));
await setFilter(container, DeviceSecurityVariation.Verified);
@ -158,10 +158,10 @@ describe('<FilteredDeviceList />', () => {
expect(onFilterChange).toHaveBeenCalledWith(DeviceSecurityVariation.Verified);
});
it('calls onFilterChange handler correctly when setting filter to All', async () => {
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');
await setFilter(container, "ALL");
// filter is cleared
expect(onFilterChange).toHaveBeenCalledWith(undefined);
@ -171,51 +171,54 @@ describe('<FilteredDeviceList />', () => {
[DeviceSecurityVariation.Verified, [newDevice, hundredDaysOld, verifiedNoMetadata]],
[DeviceSecurityVariation.Unverified, [hundredDaysOldUnverified, unverifiedNoMetadata]],
[DeviceSecurityVariation.Inactive, [hundredDaysOld, hundredDaysOldUnverified]],
])('filters correctly for %s', (filter, expectedDevices) => {
])("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}`));
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) => {
])("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();
expect(container.getElementsByClassName("mx_FilteredDeviceList_securityCard").length).toBeFalsy();
expect(container.getElementsByClassName("mx_FilteredDeviceList_noResults")).toMatchSnapshot();
});
it('clears filter from no results message', () => {
it("clears filter from no results message", () => {
const onFilterChange = jest.fn();
const { getByTestId } = render(getComponent({
onFilterChange,
filter: DeviceSecurityVariation.Verified,
devices: {
[unverifiedNoMetadata.device_id]: unverifiedNoMetadata,
},
}));
const { getByTestId } = render(
getComponent({
onFilterChange,
filter: DeviceSecurityVariation.Verified,
devices: {
[unverifiedNoMetadata.device_id]: unverifiedNoMetadata,
},
}),
);
act(() => {
fireEvent.click(getByTestId('devices-clear-filter-btn'));
fireEvent.click(getByTestId("devices-clear-filter-btn"));
});
expect(onFilterChange).toHaveBeenCalledWith(undefined);
});
});
describe('device details', () => {
it('renders expanded devices with device details', () => {
describe("device details", () => {
it("renders expanded devices with device details", () => {
const expandedDeviceIds = [newDevice.device_id, hundredDaysOld.device_id];
const { container, getByTestId } = render(getComponent({ expandedDeviceIds }));
expect(container.getElementsByClassName('mx_DeviceDetails').length).toBeTruthy();
expect(container.getElementsByClassName("mx_DeviceDetails").length).toBeTruthy();
expect(getByTestId(`device-detail-${newDevice.device_id}`)).toBeTruthy();
expect(getByTestId(`device-detail-${hundredDaysOld.device_id}`)).toBeTruthy();
});
it('clicking toggle calls onDeviceExpandToggle', () => {
it("clicking toggle calls onDeviceExpandToggle", () => {
const onDeviceExpandToggle = jest.fn();
const { getByTestId } = render(getComponent({ onDeviceExpandToggle }));

View file

@ -14,40 +14,40 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { fireEvent, render } from '@testing-library/react';
import React from 'react';
import { fireEvent, render } from "@testing-library/react";
import React from "react";
import FilteredDeviceListHeader from '../../../../../src/components/views/settings/devices/FilteredDeviceListHeader';
import FilteredDeviceListHeader from "../../../../../src/components/views/settings/devices/FilteredDeviceListHeader";
describe('<FilteredDeviceListHeader />', () => {
describe("<FilteredDeviceListHeader />", () => {
const defaultProps = {
selectedDeviceCount: 0,
isAllSelected: false,
toggleSelectAll: jest.fn(),
children: <div>test</div>,
['data-testid']: 'test123',
["data-testid"]: "test123",
};
const getComponent = (props = {}) => (<FilteredDeviceListHeader {...defaultProps} {...props} />);
const getComponent = (props = {}) => <FilteredDeviceListHeader {...defaultProps} {...props} />;
it('renders correctly when no devices are selected', () => {
it("renders correctly when no devices are selected", () => {
const { container } = render(getComponent());
expect(container).toMatchSnapshot();
});
it('renders correctly when all devices are selected', () => {
it("renders correctly when all devices are selected", () => {
const { container } = render(getComponent({ isAllSelected: true }));
expect(container).toMatchSnapshot();
});
it('renders correctly when some devices are selected', () => {
it("renders correctly when some devices are selected", () => {
const { getByText } = render(getComponent({ selectedDeviceCount: 2 }));
expect(getByText('2 sessions selected')).toBeTruthy();
expect(getByText("2 sessions selected")).toBeTruthy();
});
it('clicking checkbox toggles selection', () => {
it("clicking checkbox toggles selection", () => {
const toggleSelectAll = jest.fn();
const { getByTestId } = render(getComponent({ toggleSelectAll }));
fireEvent.click(getByTestId('device-select-all-checkbox'));
fireEvent.click(getByTestId("device-select-all-checkbox"));
expect(toggleSelectAll).toHaveBeenCalled();
});

View file

@ -14,21 +14,21 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { cleanup, render, waitFor } from '@testing-library/react';
import { mocked } from 'jest-mock';
import React from 'react';
import { MSC3906Rendezvous, RendezvousFailureReason } from 'matrix-js-sdk/src/rendezvous';
import { cleanup, render, waitFor } from "@testing-library/react";
import { mocked } from "jest-mock";
import React from "react";
import { MSC3906Rendezvous, RendezvousFailureReason } from "matrix-js-sdk/src/rendezvous";
import LoginWithQR, { Click, Mode, Phase } from '../../../../../src/components/views/auth/LoginWithQR';
import type { MatrixClient } from 'matrix-js-sdk/src/matrix';
import LoginWithQR, { Click, Mode, Phase } from "../../../../../src/components/views/auth/LoginWithQR";
import type { MatrixClient } from "matrix-js-sdk/src/matrix";
jest.mock('matrix-js-sdk/src/rendezvous');
jest.mock('matrix-js-sdk/src/rendezvous/transports');
jest.mock('matrix-js-sdk/src/rendezvous/channels');
jest.mock("matrix-js-sdk/src/rendezvous");
jest.mock("matrix-js-sdk/src/rendezvous/transports");
jest.mock("matrix-js-sdk/src/rendezvous/channels");
const mockedFlow = jest.fn();
jest.mock('../../../../../src/components/views/auth/LoginWithQRFlow', () => (props) => {
jest.mock("../../../../../src/components/views/auth/LoginWithQRFlow", () => (props) => {
mockedFlow(props);
return <div />;
});
@ -43,7 +43,7 @@ function makeClient() {
on: jest.fn(),
isSynapseAdministrator: jest.fn().mockResolvedValue(false),
isRoomEncrypted: jest.fn().mockReturnValue(false),
mxcUrlToHttp: jest.fn().mockReturnValue('mock-mxcUrlToHttp'),
mxcUrlToHttp: jest.fn().mockReturnValue("mock-mxcUrlToHttp"),
doesServerSupportUnstableFeature: jest.fn().mockReturnValue(true),
removeListener: jest.fn(),
requestLoginToken: jest.fn(),
@ -57,33 +57,36 @@ function unresolvedPromise<T>(): Promise<T> {
return new Promise(() => {});
}
describe('<LoginWithQR />', () => {
describe("<LoginWithQR />", () => {
let client = makeClient();
const defaultProps = {
mode: Mode.Show,
onFinished: jest.fn(),
};
const mockConfirmationDigits = 'mock-confirmation-digits';
const mockRendezvousCode = 'mock-rendezvous-code';
const newDeviceId = 'new-device-id';
const mockConfirmationDigits = "mock-confirmation-digits";
const mockRendezvousCode = "mock-rendezvous-code";
const newDeviceId = "new-device-id";
const getComponent = (props: { client: MatrixClient, onFinished?: () => void }) =>
(<React.StrictMode><LoginWithQR {...defaultProps} {...props} /></React.StrictMode>);
const getComponent = (props: { client: MatrixClient; onFinished?: () => void }) => (
<React.StrictMode>
<LoginWithQR {...defaultProps} {...props} />
</React.StrictMode>
);
beforeEach(() => {
mockedFlow.mockReset();
jest.resetAllMocks();
jest.spyOn(MSC3906Rendezvous.prototype, 'generateCode').mockResolvedValue();
jest.spyOn(MSC3906Rendezvous.prototype, "generateCode").mockResolvedValue();
// @ts-ignore
// workaround for https://github.com/facebook/jest/issues/9675
MSC3906Rendezvous.prototype.code = mockRendezvousCode;
jest.spyOn(MSC3906Rendezvous.prototype, 'cancel').mockResolvedValue();
jest.spyOn(MSC3906Rendezvous.prototype, 'startAfterShowingCode').mockResolvedValue(mockConfirmationDigits);
jest.spyOn(MSC3906Rendezvous.prototype, 'declineLoginOnExistingDevice').mockResolvedValue();
jest.spyOn(MSC3906Rendezvous.prototype, 'approveLoginOnExistingDevice').mockResolvedValue(newDeviceId);
jest.spyOn(MSC3906Rendezvous.prototype, 'verifyNewDeviceOnExistingDevice').mockResolvedValue(undefined);
jest.spyOn(MSC3906Rendezvous.prototype, "cancel").mockResolvedValue();
jest.spyOn(MSC3906Rendezvous.prototype, "startAfterShowingCode").mockResolvedValue(mockConfirmationDigits);
jest.spyOn(MSC3906Rendezvous.prototype, "declineLoginOnExistingDevice").mockResolvedValue();
jest.spyOn(MSC3906Rendezvous.prototype, "approveLoginOnExistingDevice").mockResolvedValue(newDeviceId);
jest.spyOn(MSC3906Rendezvous.prototype, "verifyNewDeviceOnExistingDevice").mockResolvedValue(undefined);
client.requestLoginToken.mockResolvedValue({
login_token: 'token',
login_token: "token",
expires_in: 1000,
});
});
@ -95,9 +98,9 @@ describe('<LoginWithQR />', () => {
cleanup();
});
test('no homeserver support', async () => {
test("no homeserver support", async () => {
// simulate no support
jest.spyOn(MSC3906Rendezvous.prototype, 'generateCode').mockRejectedValue('');
jest.spyOn(MSC3906Rendezvous.prototype, "generateCode").mockRejectedValue("");
render(getComponent({ client }));
await waitFor(() =>
expect(mockedFlow).toHaveBeenLastCalledWith({
@ -110,8 +113,8 @@ describe('<LoginWithQR />', () => {
expect(rendezvous.generateCode).toHaveBeenCalled();
});
test('failed to connect', async () => {
jest.spyOn(MSC3906Rendezvous.prototype, 'startAfterShowingCode').mockRejectedValue('');
test("failed to connect", async () => {
jest.spyOn(MSC3906Rendezvous.prototype, "startAfterShowingCode").mockRejectedValue("");
render(getComponent({ client }));
await waitFor(() =>
expect(mockedFlow).toHaveBeenLastCalledWith({
@ -125,15 +128,19 @@ describe('<LoginWithQR />', () => {
expect(rendezvous.startAfterShowingCode).toHaveBeenCalled();
});
test('render QR then cancel and try again', async () => {
test("render QR then cancel and try again", async () => {
const onFinished = jest.fn();
jest.spyOn(MSC3906Rendezvous.prototype, 'startAfterShowingCode').mockImplementation(() => unresolvedPromise());
jest.spyOn(MSC3906Rendezvous.prototype, "startAfterShowingCode").mockImplementation(() => unresolvedPromise());
render(getComponent({ client, onFinished }));
const rendezvous = mocked(MSC3906Rendezvous).mock.instances[0];
await waitFor(() => expect(mockedFlow).toHaveBeenLastCalledWith(expect.objectContaining({
phase: Phase.ShowingQR,
})));
await waitFor(() =>
expect(mockedFlow).toHaveBeenLastCalledWith(
expect.objectContaining({
phase: Phase.ShowingQR,
}),
),
);
// display QR code
expect(mockedFlow).toHaveBeenLastCalledWith({
phase: Phase.ShowingQR,
@ -151,9 +158,13 @@ describe('<LoginWithQR />', () => {
// try again
onClick(Click.TryAgain);
await waitFor(() => expect(mockedFlow).toHaveBeenLastCalledWith(expect.objectContaining({
phase: Phase.ShowingQR,
})));
await waitFor(() =>
expect(mockedFlow).toHaveBeenLastCalledWith(
expect.objectContaining({
phase: Phase.ShowingQR,
}),
),
);
// display QR code
expect(mockedFlow).toHaveBeenLastCalledWith({
phase: Phase.ShowingQR,
@ -162,15 +173,19 @@ describe('<LoginWithQR />', () => {
});
});
test('render QR then back', async () => {
test("render QR then back", async () => {
const onFinished = jest.fn();
jest.spyOn(MSC3906Rendezvous.prototype, 'startAfterShowingCode').mockReturnValue(unresolvedPromise());
jest.spyOn(MSC3906Rendezvous.prototype, "startAfterShowingCode").mockReturnValue(unresolvedPromise());
render(getComponent({ client, onFinished }));
const rendezvous = mocked(MSC3906Rendezvous).mock.instances[0];
await waitFor(() => expect(mockedFlow).toHaveBeenLastCalledWith(expect.objectContaining({
phase: Phase.ShowingQR,
})));
await waitFor(() =>
expect(mockedFlow).toHaveBeenLastCalledWith(
expect.objectContaining({
phase: Phase.ShowingQR,
}),
),
);
// display QR code
expect(mockedFlow).toHaveBeenLastCalledWith({
phase: Phase.ShowingQR,
@ -187,14 +202,18 @@ describe('<LoginWithQR />', () => {
expect(rendezvous.cancel).toHaveBeenCalledWith(RendezvousFailureReason.UserCancelled);
});
test('render QR then decline', async () => {
test("render QR then decline", async () => {
const onFinished = jest.fn();
render(getComponent({ client, onFinished }));
const rendezvous = mocked(MSC3906Rendezvous).mock.instances[0];
await waitFor(() => expect(mockedFlow).toHaveBeenLastCalledWith(expect.objectContaining({
phase: Phase.Connected,
})));
await waitFor(() =>
expect(mockedFlow).toHaveBeenLastCalledWith(
expect.objectContaining({
phase: Phase.Connected,
}),
),
);
expect(mockedFlow).toHaveBeenLastCalledWith({
phase: Phase.Connected,
confirmationDigits: mockConfirmationDigits,
@ -211,7 +230,7 @@ describe('<LoginWithQR />', () => {
expect(rendezvous.declineLoginOnExistingDevice).toHaveBeenCalled();
});
test('approve - no crypto', async () => {
test("approve - no crypto", async () => {
// @ts-ignore
client.crypto = undefined;
const onFinished = jest.fn();
@ -219,9 +238,13 @@ describe('<LoginWithQR />', () => {
render(getComponent({ client, onFinished }));
const rendezvous = mocked(MSC3906Rendezvous).mock.instances[0];
await waitFor(() => expect(mockedFlow).toHaveBeenLastCalledWith(expect.objectContaining({
phase: Phase.Connected,
})));
await waitFor(() =>
expect(mockedFlow).toHaveBeenLastCalledWith(
expect.objectContaining({
phase: Phase.Connected,
}),
),
);
expect(mockedFlow).toHaveBeenLastCalledWith({
phase: Phase.Connected,
confirmationDigits: mockConfirmationDigits,
@ -234,27 +257,36 @@ describe('<LoginWithQR />', () => {
const onClick = mockedFlow.mock.calls[0][0].onClick;
await onClick(Click.Approve);
await waitFor(() => expect(mockedFlow).toHaveBeenLastCalledWith(expect.objectContaining({
phase: Phase.WaitingForDevice,
})));
await waitFor(() =>
expect(mockedFlow).toHaveBeenLastCalledWith(
expect.objectContaining({
phase: Phase.WaitingForDevice,
}),
),
);
expect(rendezvous.approveLoginOnExistingDevice).toHaveBeenCalledWith('token');
expect(rendezvous.approveLoginOnExistingDevice).toHaveBeenCalledWith("token");
expect(onFinished).toHaveBeenCalledWith(true);
});
test('approve + verifying', async () => {
test("approve + verifying", async () => {
const onFinished = jest.fn();
// @ts-ignore
client.crypto = {};
jest.spyOn(MSC3906Rendezvous.prototype, 'verifyNewDeviceOnExistingDevice')
.mockImplementation(() => unresolvedPromise());
jest.spyOn(MSC3906Rendezvous.prototype, "verifyNewDeviceOnExistingDevice").mockImplementation(() =>
unresolvedPromise(),
);
render(getComponent({ client, onFinished }));
const rendezvous = mocked(MSC3906Rendezvous).mock.instances[0];
await waitFor(() => expect(mockedFlow).toHaveBeenLastCalledWith(expect.objectContaining({
phase: Phase.Connected,
})));
await waitFor(() =>
expect(mockedFlow).toHaveBeenLastCalledWith(
expect.objectContaining({
phase: Phase.Connected,
}),
),
);
expect(mockedFlow).toHaveBeenLastCalledWith({
phase: Phase.Connected,
confirmationDigits: mockConfirmationDigits,
@ -267,25 +299,33 @@ describe('<LoginWithQR />', () => {
const onClick = mockedFlow.mock.calls[0][0].onClick;
onClick(Click.Approve);
await waitFor(() => expect(mockedFlow).toHaveBeenLastCalledWith(expect.objectContaining({
phase: Phase.Verifying,
})));
await waitFor(() =>
expect(mockedFlow).toHaveBeenLastCalledWith(
expect.objectContaining({
phase: Phase.Verifying,
}),
),
);
expect(rendezvous.approveLoginOnExistingDevice).toHaveBeenCalledWith('token');
expect(rendezvous.approveLoginOnExistingDevice).toHaveBeenCalledWith("token");
expect(rendezvous.verifyNewDeviceOnExistingDevice).toHaveBeenCalled();
// expect(onFinished).toHaveBeenCalledWith(true);
});
test('approve + verify', async () => {
test("approve + verify", async () => {
const onFinished = jest.fn();
// @ts-ignore
client.crypto = {};
render(getComponent({ client, onFinished }));
const rendezvous = mocked(MSC3906Rendezvous).mock.instances[0];
await waitFor(() => expect(mockedFlow).toHaveBeenLastCalledWith(expect.objectContaining({
phase: Phase.Connected,
})));
await waitFor(() =>
expect(mockedFlow).toHaveBeenLastCalledWith(
expect.objectContaining({
phase: Phase.Connected,
}),
),
);
expect(mockedFlow).toHaveBeenLastCalledWith({
phase: Phase.Connected,
confirmationDigits: mockConfirmationDigits,
@ -297,7 +337,7 @@ describe('<LoginWithQR />', () => {
// approve
const onClick = mockedFlow.mock.calls[0][0].onClick;
await onClick(Click.Approve);
expect(rendezvous.approveLoginOnExistingDevice).toHaveBeenCalledWith('token');
expect(rendezvous.approveLoginOnExistingDevice).toHaveBeenCalledWith("token");
expect(rendezvous.verifyNewDeviceOnExistingDevice).toHaveBeenCalled();
expect(onFinished).toHaveBeenCalledWith(true);
});

View file

@ -14,14 +14,14 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react';
import React from 'react';
import { RendezvousFailureReason } from 'matrix-js-sdk/src/rendezvous';
import { cleanup, fireEvent, render, screen, waitFor } from "@testing-library/react";
import React from "react";
import { RendezvousFailureReason } from "matrix-js-sdk/src/rendezvous";
import LoginWithQRFlow from '../../../../../src/components/views/auth/LoginWithQRFlow';
import { Click, Phase } from '../../../../../src/components/views/auth/LoginWithQR';
import LoginWithQRFlow from "../../../../../src/components/views/auth/LoginWithQRFlow";
import { Click, Phase } from "../../../../../src/components/views/auth/LoginWithQR";
describe('<LoginWithQRFlow />', () => {
describe("<LoginWithQRFlow />", () => {
const onClick = jest.fn();
const defaultProps = {
@ -34,81 +34,81 @@ describe('<LoginWithQRFlow />', () => {
failureReason?: RendezvousFailureReason;
code?: string;
confirmationDigits?: string;
}) =>
(<LoginWithQRFlow {...defaultProps} {...props} />);
}) => <LoginWithQRFlow {...defaultProps} {...props} />;
beforeEach(() => {
});
beforeEach(() => {});
afterEach(() => {
onClick.mockReset();
cleanup();
});
it('renders spinner while loading', async () => {
it("renders spinner while loading", async () => {
const { container } = render(getComponent({ phase: Phase.Loading }));
expect(container).toMatchSnapshot();
});
it('renders spinner whilst QR generating', async () => {
it("renders spinner whilst QR generating", async () => {
const { container } = render(getComponent({ phase: Phase.ShowingQR }));
expect(screen.getAllByTestId('cancel-button')).toHaveLength(1);
expect(screen.getAllByTestId("cancel-button")).toHaveLength(1);
expect(container).toMatchSnapshot();
fireEvent.click(screen.getByTestId('cancel-button'));
fireEvent.click(screen.getByTestId("cancel-button"));
expect(onClick).toHaveBeenCalledWith(Click.Cancel);
});
it('renders QR code', async () => {
const { container } = render(getComponent({ phase: Phase.ShowingQR, code: 'mock-code' }));
it("renders QR code", async () => {
const { container } = render(getComponent({ phase: Phase.ShowingQR, code: "mock-code" }));
// QR code is rendered async so we wait for it:
await waitFor(() => screen.getAllByAltText('QR Code').length === 1);
await waitFor(() => screen.getAllByAltText("QR Code").length === 1);
expect(container).toMatchSnapshot();
});
it('renders spinner while connecting', async () => {
it("renders spinner while connecting", async () => {
const { container } = render(getComponent({ phase: Phase.Connecting }));
expect(screen.getAllByTestId('cancel-button')).toHaveLength(1);
expect(screen.getAllByTestId("cancel-button")).toHaveLength(1);
expect(container).toMatchSnapshot();
fireEvent.click(screen.getByTestId('cancel-button'));
fireEvent.click(screen.getByTestId("cancel-button"));
expect(onClick).toHaveBeenCalledWith(Click.Cancel);
});
it('renders code when connected', async () => {
const { container } = render(getComponent({ phase: Phase.Connected, confirmationDigits: 'mock-digits' }));
expect(screen.getAllByText('mock-digits')).toHaveLength(1);
expect(screen.getAllByTestId('decline-login-button')).toHaveLength(1);
expect(screen.getAllByTestId('approve-login-button')).toHaveLength(1);
it("renders code when connected", async () => {
const { container } = render(getComponent({ phase: Phase.Connected, confirmationDigits: "mock-digits" }));
expect(screen.getAllByText("mock-digits")).toHaveLength(1);
expect(screen.getAllByTestId("decline-login-button")).toHaveLength(1);
expect(screen.getAllByTestId("approve-login-button")).toHaveLength(1);
expect(container).toMatchSnapshot();
fireEvent.click(screen.getByTestId('decline-login-button'));
fireEvent.click(screen.getByTestId("decline-login-button"));
expect(onClick).toHaveBeenCalledWith(Click.Decline);
fireEvent.click(screen.getByTestId('approve-login-button'));
fireEvent.click(screen.getByTestId("approve-login-button"));
expect(onClick).toHaveBeenCalledWith(Click.Approve);
});
it('renders spinner while signing in', async () => {
it("renders spinner while signing in", async () => {
const { container } = render(getComponent({ phase: Phase.WaitingForDevice }));
expect(screen.getAllByTestId('cancel-button')).toHaveLength(1);
expect(screen.getAllByTestId("cancel-button")).toHaveLength(1);
expect(container).toMatchSnapshot();
fireEvent.click(screen.getByTestId('cancel-button'));
fireEvent.click(screen.getByTestId("cancel-button"));
expect(onClick).toHaveBeenCalledWith(Click.Cancel);
});
it('renders spinner while verifying', async () => {
it("renders spinner while verifying", async () => {
const { container } = render(getComponent({ phase: Phase.Verifying }));
expect(container).toMatchSnapshot();
});
describe('errors', () => {
describe("errors", () => {
for (const failureReason of Object.values(RendezvousFailureReason)) {
it(`renders ${failureReason}`, async () => {
const { container } = render(getComponent({
phase: Phase.Error,
failureReason,
}));
expect(screen.getAllByTestId('cancellation-message')).toHaveLength(1);
expect(screen.getAllByTestId('try-again-button')).toHaveLength(1);
const { container } = render(
getComponent({
phase: Phase.Error,
failureReason,
}),
);
expect(screen.getAllByTestId("cancellation-message")).toHaveLength(1);
expect(screen.getAllByTestId("try-again-button")).toHaveLength(1);
expect(container).toMatchSnapshot();
fireEvent.click(screen.getByTestId('try-again-button'));
fireEvent.click(screen.getByTestId("try-again-button"));
expect(onClick).toHaveBeenCalledWith(Click.TryAgain);
});
}

View file

@ -14,15 +14,15 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { render } from '@testing-library/react';
import { mocked } from 'jest-mock';
import { IServerVersions, MatrixClient } from 'matrix-js-sdk/src/matrix';
import React from 'react';
import { render } from "@testing-library/react";
import { mocked } from "jest-mock";
import { IServerVersions, MatrixClient } from "matrix-js-sdk/src/matrix";
import React from "react";
import LoginWithQRSection from '../../../../../src/components/views/settings/devices/LoginWithQRSection';
import { MatrixClientPeg } from '../../../../../src/MatrixClientPeg';
import { SettingLevel } from '../../../../../src/settings/SettingLevel';
import SettingsStore from '../../../../../src/settings/SettingsStore';
import LoginWithQRSection from "../../../../../src/components/views/settings/devices/LoginWithQRSection";
import { MatrixClientPeg } from "../../../../../src/MatrixClientPeg";
import { SettingLevel } from "../../../../../src/settings/SettingLevel";
import SettingsStore from "../../../../../src/settings/SettingsStore";
function makeClient() {
return mocked({
@ -34,7 +34,7 @@ function makeClient() {
on: jest.fn(),
isSynapseAdministrator: jest.fn().mockResolvedValue(false),
isRoomEncrypted: jest.fn().mockReturnValue(false),
mxcUrlToHttp: jest.fn().mockReturnValue('mock-mxcUrlToHttp'),
mxcUrlToHttp: jest.fn().mockReturnValue("mock-mxcUrlToHttp"),
removeListener: jest.fn(),
currentState: {
on: jest.fn(),
@ -49,9 +49,9 @@ function makeVersions(unstableFeatures: Record<string, boolean>): IServerVersion
};
}
describe('<LoginWithQRSection />', () => {
describe("<LoginWithQRSection />", () => {
beforeAll(() => {
jest.spyOn(MatrixClientPeg, 'get').mockReturnValue(makeClient());
jest.spyOn(MatrixClientPeg, "get").mockReturnValue(makeClient());
});
const defaultProps = {
@ -59,35 +59,38 @@ describe('<LoginWithQRSection />', () => {
versions: makeVersions({}),
};
const getComponent = (props = {}) =>
(<LoginWithQRSection {...defaultProps} {...props} />);
const getComponent = (props = {}) => <LoginWithQRSection {...defaultProps} {...props} />;
describe('should not render', () => {
it('no support at all', () => {
describe("should not render", () => {
it("no support at all", () => {
const { container } = render(getComponent());
expect(container).toMatchSnapshot();
});
it('feature enabled', async () => {
await SettingsStore.setValue('feature_qr_signin_reciprocate_show', null, SettingLevel.DEVICE, true);
it("feature enabled", async () => {
await SettingsStore.setValue("feature_qr_signin_reciprocate_show", null, SettingLevel.DEVICE, true);
const { container } = render(getComponent());
expect(container).toMatchSnapshot();
});
it('only feature + MSC3882 enabled', async () => {
await SettingsStore.setValue('feature_qr_signin_reciprocate_show', null, SettingLevel.DEVICE, true);
const { container } = render(getComponent({ versions: makeVersions({ 'org.matrix.msc3882': true }) }));
it("only feature + MSC3882 enabled", async () => {
await SettingsStore.setValue("feature_qr_signin_reciprocate_show", null, SettingLevel.DEVICE, true);
const { container } = render(getComponent({ versions: makeVersions({ "org.matrix.msc3882": true }) }));
expect(container).toMatchSnapshot();
});
});
describe('should render panel', () => {
it('enabled by feature + MSC3882 + MSC3886', async () => {
await SettingsStore.setValue('feature_qr_signin_reciprocate_show', null, SettingLevel.DEVICE, true);
const { container } = render(getComponent({ versions: makeVersions({
'org.matrix.msc3882': true,
'org.matrix.msc3886': true,
}) }));
describe("should render panel", () => {
it("enabled by feature + MSC3882 + MSC3886", async () => {
await SettingsStore.setValue("feature_qr_signin_reciprocate_show", null, SettingLevel.DEVICE, true);
const { container } = render(
getComponent({
versions: makeVersions({
"org.matrix.msc3882": true,
"org.matrix.msc3886": true,
}),
}),
);
expect(container).toMatchSnapshot();
});
});

View file

@ -14,37 +14,36 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import { act, fireEvent, render } from '@testing-library/react';
import React from "react";
import { act, fireEvent, render } from "@testing-library/react";
import SecurityRecommendations from '../../../../../src/components/views/settings/devices/SecurityRecommendations';
import { DeviceSecurityVariation } from '../../../../../src/components/views/settings/devices/types';
import SecurityRecommendations from "../../../../../src/components/views/settings/devices/SecurityRecommendations";
import { DeviceSecurityVariation } from "../../../../../src/components/views/settings/devices/types";
const MS_DAY = 24 * 60 * 60 * 1000;
describe('<SecurityRecommendations />', () => {
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) };
describe("<SecurityRecommendations />", () => {
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',
device_id: "unverified-100-days-old",
isVerified: false,
last_seen_ts: Date.now() - (MS_DAY * 100),
last_seen_ts: Date.now() - MS_DAY * 100,
};
const defaultProps = {
devices: {},
goToFilteredList: jest.fn(),
currentDeviceId: 'abc123',
currentDeviceId: "abc123",
};
const getComponent = (props = {}) =>
(<SecurityRecommendations {...defaultProps} {...props} />);
const getComponent = (props = {}) => <SecurityRecommendations {...defaultProps} {...props} />;
it('renders null when no devices', () => {
it("renders null when no devices", () => {
const { container } = render(getComponent());
expect(container.firstChild).toBeNull();
});
it('renders unverified devices section when user has unverified devices', () => {
it("renders unverified devices section when user has unverified devices", () => {
const devices = {
[unverifiedNoMetadata.device_id]: unverifiedNoMetadata,
[verifiedNoMetadata.device_id]: verifiedNoMetadata,
@ -54,7 +53,7 @@ describe('<SecurityRecommendations />', () => {
expect(container).toMatchSnapshot();
});
it('does not render unverified devices section when only the current device is unverified', () => {
it("does not render unverified devices section when only the current device is unverified", () => {
const devices = {
[unverifiedNoMetadata.device_id]: unverifiedNoMetadata,
[verifiedNoMetadata.device_id]: verifiedNoMetadata,
@ -64,7 +63,7 @@ describe('<SecurityRecommendations />', () => {
expect(container.firstChild).toBeFalsy();
});
it('renders inactive devices section when user has inactive devices', () => {
it("renders inactive devices section when user has inactive devices", () => {
const devices = {
[verifiedNoMetadata.device_id]: verifiedNoMetadata,
[hundredDaysOldUnverified.device_id]: hundredDaysOldUnverified,
@ -73,7 +72,7 @@ describe('<SecurityRecommendations />', () => {
expect(container).toMatchSnapshot();
});
it('renders both cards when user has both unverified and inactive devices', () => {
it("renders both cards when user has both unverified and inactive devices", () => {
const devices = {
[verifiedNoMetadata.device_id]: verifiedNoMetadata,
[hundredDaysOld.device_id]: hundredDaysOld,
@ -83,7 +82,7 @@ describe('<SecurityRecommendations />', () => {
expect(container).toMatchSnapshot();
});
it('clicking view all unverified devices button works', () => {
it("clicking view all unverified devices button works", () => {
const goToFilteredList = jest.fn();
const devices = {
[verifiedNoMetadata.device_id]: verifiedNoMetadata,
@ -93,13 +92,13 @@ describe('<SecurityRecommendations />', () => {
const { getByTestId } = render(getComponent({ devices, goToFilteredList }));
act(() => {
fireEvent.click(getByTestId('unverified-devices-cta'));
fireEvent.click(getByTestId("unverified-devices-cta"));
});
expect(goToFilteredList).toHaveBeenCalledWith(DeviceSecurityVariation.Unverified);
});
it('clicking view all inactive devices button works', () => {
it("clicking view all inactive devices button works", () => {
const goToFilteredList = jest.fn();
const devices = {
[verifiedNoMetadata.device_id]: verifiedNoMetadata,
@ -109,7 +108,7 @@ describe('<SecurityRecommendations />', () => {
const { getByTestId } = render(getComponent({ devices, goToFilteredList }));
act(() => {
fireEvent.click(getByTestId('inactive-devices-cta'));
fireEvent.click(getByTestId("inactive-devices-cta"));
});
expect(goToFilteredList).toHaveBeenCalledWith(DeviceSecurityVariation.Inactive);

View file

@ -14,18 +14,18 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { fireEvent, render } from '@testing-library/react';
import React from 'react';
import { act } from 'react-dom/test-utils';
import { fireEvent, render } from "@testing-library/react";
import React from "react";
import { act } from "react-dom/test-utils";
import SelectableDeviceTile from '../../../../../src/components/views/settings/devices/SelectableDeviceTile';
import { DeviceType } from '../../../../../src/utils/device/parseUserAgent';
import SelectableDeviceTile from "../../../../../src/components/views/settings/devices/SelectableDeviceTile";
import { DeviceType } from "../../../../../src/utils/device/parseUserAgent";
describe('<SelectableDeviceTile />', () => {
describe("<SelectableDeviceTile />", () => {
const device = {
display_name: 'My Device',
device_id: 'my-device',
last_seen_ip: '123.456.789',
display_name: "My Device",
device_id: "my-device",
last_seen_ip: "123.456.789",
isVerified: false,
deviceType: DeviceType.Unknown,
};
@ -36,20 +36,19 @@ describe('<SelectableDeviceTile />', () => {
children: <div>test</div>,
isSelected: false,
};
const getComponent = (props = {}) =>
(<SelectableDeviceTile {...defaultProps} {...props} />);
const getComponent = (props = {}) => <SelectableDeviceTile {...defaultProps} {...props} />;
it('renders unselected device tile with checkbox', () => {
it("renders unselected device tile with checkbox", () => {
const { container } = render(getComponent());
expect(container).toMatchSnapshot();
});
it('renders selected tile', () => {
it("renders selected tile", () => {
const { container } = render(getComponent({ isSelected: true }));
expect(container.querySelector(`#device-tile-checkbox-${device.device_id}`)).toMatchSnapshot();
});
it('calls onSelect on checkbox click', () => {
it("calls onSelect on checkbox click", () => {
const onSelect = jest.fn();
const { container } = render(getComponent({ onSelect }));
@ -60,7 +59,7 @@ describe('<SelectableDeviceTile />', () => {
expect(onSelect).toHaveBeenCalled();
});
it('calls onClick on device tile info click', () => {
it("calls onClick on device tile info click", () => {
const onClick = jest.fn();
const { getByText } = render(getComponent({ onClick }));
@ -71,14 +70,18 @@ describe('<SelectableDeviceTile />', () => {
expect(onClick).toHaveBeenCalled();
});
it('does not call onClick when clicking device tiles actions', () => {
it("does not call onClick when clicking device tiles actions", () => {
const onClick = jest.fn();
const onDeviceActionClick = jest.fn();
const children = <button onClick={onDeviceActionClick} data-testid='device-action-button'>test</button>;
const children = (
<button onClick={onDeviceActionClick} data-testid="device-action-button">
test
</button>
);
const { getByTestId } = render(getComponent({ onClick, children }));
act(() => {
fireEvent.click(getByTestId('device-action-button'));
fireEvent.click(getByTestId("device-action-button"));
});
// action click handler called

View file

@ -18,15 +18,15 @@ import { deleteDevicesWithInteractiveAuth } from "../../../../../src/components/
import Modal from "../../../../../src/Modal";
import { getMockClientWithEventEmitter, mockClientMethodsUser } from "../../../../test-utils";
describe('deleteDevices()', () => {
const userId = '@alice:server.org';
const deviceIds = ['device_1', 'device_2'];
describe("deleteDevices()", () => {
const userId = "@alice:server.org";
const deviceIds = ["device_1", "device_2"];
const mockClient = getMockClientWithEventEmitter({
...mockClientMethodsUser(userId),
deleteMultipleDevices: jest.fn(),
});
const modalSpy = jest.spyOn(Modal, 'createDialog');
const modalSpy = jest.spyOn(Modal, "createDialog");
const interactiveAuthError = { httpStatus: 401, data: { flows: [] } };
@ -34,7 +34,7 @@ describe('deleteDevices()', () => {
jest.clearAllMocks();
});
it('deletes devices and calls onFinished when interactive auth is not required', async () => {
it("deletes devices and calls onFinished when interactive auth is not required", async () => {
mockClient.deleteMultipleDevices.mockResolvedValue({});
const onFinished = jest.fn();
@ -47,16 +47,14 @@ describe('deleteDevices()', () => {
expect(modalSpy).not.toHaveBeenCalled();
});
it('throws without opening auth dialog when delete fails with a non-401 status code', async () => {
const error = new Error('');
it("throws without opening auth dialog when delete fails with a non-401 status code", async () => {
const error = new Error("");
// @ts-ignore
error.httpStatus = 404;
mockClient.deleteMultipleDevices.mockRejectedValue(error);
const onFinished = jest.fn();
await expect(
deleteDevicesWithInteractiveAuth(mockClient, deviceIds, onFinished),
).rejects.toThrow(error);
await expect(deleteDevicesWithInteractiveAuth(mockClient, deviceIds, onFinished)).rejects.toThrow(error);
expect(onFinished).not.toHaveBeenCalled();
@ -64,8 +62,8 @@ describe('deleteDevices()', () => {
expect(modalSpy).not.toHaveBeenCalled();
});
it('throws without opening auth dialog when delete fails without data.flows', async () => {
const error = new Error('');
it("throws without opening auth dialog when delete fails without data.flows", async () => {
const error = new Error("");
// @ts-ignore
error.httpStatus = 401;
// @ts-ignore
@ -73,9 +71,7 @@ describe('deleteDevices()', () => {
mockClient.deleteMultipleDevices.mockRejectedValue(error);
const onFinished = jest.fn();
await expect(
deleteDevicesWithInteractiveAuth(mockClient, deviceIds, onFinished),
).rejects.toThrow(error);
await expect(deleteDevicesWithInteractiveAuth(mockClient, deviceIds, onFinished)).rejects.toThrow(error);
expect(onFinished).not.toHaveBeenCalled();
@ -83,7 +79,7 @@ describe('deleteDevices()', () => {
expect(modalSpy).not.toHaveBeenCalled();
});
it('opens interactive auth dialog when delete fails with 401', async () => {
it("opens interactive auth dialog when delete fails with 401", async () => {
mockClient.deleteMultipleDevices.mockRejectedValue(interactiveAuthError);
const onFinished = jest.fn();
@ -94,12 +90,10 @@ describe('deleteDevices()', () => {
// opened modal
expect(modalSpy).toHaveBeenCalled();
const [, {
title, authData, aestheticsForStagePhases,
}] = modalSpy.mock.calls[0];
const [, { title, authData, aestheticsForStagePhases }] = modalSpy.mock.calls[0];
// modal opened as expected
expect(title).toEqual('Authentication');
expect(title).toEqual("Authentication");
expect(authData).toEqual(interactiveAuthError.data);
expect(aestheticsForStagePhases).toMatchSnapshot();
});

View file

@ -14,58 +14,48 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {
filterDevicesBySecurityRecommendation,
} from "../../../../../src/components/views/settings/devices/filter";
import {
DeviceSecurityVariation,
} from "../../../../../src/components/views/settings/devices/types";
import { filterDevicesBySecurityRecommendation } from "../../../../../src/components/views/settings/devices/filter";
import { DeviceSecurityVariation } from "../../../../../src/components/views/settings/devices/types";
import { DeviceType } from "../../../../../src/utils/device/parseUserAgent";
const MS_DAY = 86400000;
describe('filterDevicesBySecurityRecommendation()', () => {
describe("filterDevicesBySecurityRecommendation()", () => {
const unverifiedNoMetadata = {
device_id: 'unverified-no-metadata',
device_id: "unverified-no-metadata",
isVerified: false,
deviceType: DeviceType.Unknown,
};
const verifiedNoMetadata = {
device_id: 'verified-no-metadata',
device_id: "verified-no-metadata",
isVerified: true,
deviceType: DeviceType.Unknown,
};
const hundredDaysOld = {
device_id: '100-days-old',
device_id: "100-days-old",
isVerified: true,
last_seen_ts: Date.now() - (MS_DAY * 100),
last_seen_ts: Date.now() - MS_DAY * 100,
deviceType: DeviceType.Unknown,
};
const hundredDaysOldUnverified = {
device_id: 'unverified-100-days-old',
device_id: "unverified-100-days-old",
isVerified: false,
last_seen_ts: Date.now() - (MS_DAY * 100),
last_seen_ts: Date.now() - MS_DAY * 100,
deviceType: DeviceType.Unknown,
};
const fiftyDaysOld = {
device_id: '50-days-old',
device_id: "50-days-old",
isVerified: true,
last_seen_ts: Date.now() - (MS_DAY * 50),
last_seen_ts: Date.now() - MS_DAY * 50,
deviceType: DeviceType.Unknown,
};
const devices = [
unverifiedNoMetadata,
verifiedNoMetadata,
hundredDaysOld,
hundredDaysOldUnverified,
fiftyDaysOld,
];
const devices = [unverifiedNoMetadata, verifiedNoMetadata, hundredDaysOld, hundredDaysOldUnverified, fiftyDaysOld];
it('returns all devices when no securityRecommendations are passed', () => {
it("returns all devices when no securityRecommendations are passed", () => {
expect(filterDevicesBySecurityRecommendation(devices, [])).toBe(devices);
});
it('returns devices older than 90 days as inactive', () => {
it("returns devices older than 90 days as inactive", () => {
expect(filterDevicesBySecurityRecommendation(devices, [DeviceSecurityVariation.Inactive])).toEqual([
// devices without ts metadata are not filtered as inactive
hundredDaysOld,
@ -73,7 +63,7 @@ describe('filterDevicesBySecurityRecommendation()', () => {
]);
});
it('returns correct devices for verified filter', () => {
it("returns correct devices for verified filter", () => {
expect(filterDevicesBySecurityRecommendation(devices, [DeviceSecurityVariation.Verified])).toEqual([
verifiedNoMetadata,
hundredDaysOld,
@ -81,19 +71,19 @@ describe('filterDevicesBySecurityRecommendation()', () => {
]);
});
it('returns correct devices for unverified filter', () => {
it("returns correct devices for unverified filter", () => {
expect(filterDevicesBySecurityRecommendation(devices, [DeviceSecurityVariation.Unverified])).toEqual([
unverifiedNoMetadata,
hundredDaysOldUnverified,
]);
});
it('returns correct devices for combined verified and inactive filters', () => {
expect(filterDevicesBySecurityRecommendation(
devices,
[DeviceSecurityVariation.Unverified, DeviceSecurityVariation.Inactive],
)).toEqual([
hundredDaysOldUnverified,
]);
it("returns correct devices for combined verified and inactive filters", () => {
expect(
filterDevicesBySecurityRecommendation(devices, [
DeviceSecurityVariation.Unverified,
DeviceSecurityVariation.Inactive,
]),
).toEqual([hundredDaysOldUnverified]);
});
});