From e6d41f6c4895147ca34276e4de35e99b4f3f3def Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 24 May 2023 15:14:20 +0100 Subject: [PATCH 1/3] Update tests to demonstrate broken behaviour --- .../views/settings/DevicesPanel-test.tsx | 64 ++++--- .../__snapshots__/DevicesPanel-test.tsx.snap | 161 +++++++++++++++--- .../tabs/user/SessionManagerTab-test.tsx | 5 +- 3 files changed, 180 insertions(+), 50 deletions(-) diff --git a/test/components/views/settings/DevicesPanel-test.tsx b/test/components/views/settings/DevicesPanel-test.tsx index dd334d89475..2f25242c73b 100644 --- a/test/components/views/settings/DevicesPanel-test.tsx +++ b/test/components/views/settings/DevicesPanel-test.tsx @@ -25,18 +25,40 @@ import MatrixClientContext from "../../../../src/contexts/MatrixClientContext"; describe("", () => { const userId = "@alice:server.org"; - const device1 = { device_id: "device_1" }; - const device2 = { device_id: "device_2" }; - const device3 = { device_id: "device_3" }; + + // the local device + const ownDevice = { device_id: "device_1" }; + + // a device which we have verified via cross-signing + const verifiedDevice = { device_id: "device_2" }; + + // a device which we have *not* verified via cross-signing + const unverifiedDevice = { device_id: "device_3" }; + + // a device which is returned by `getDevices` but getDeviceVerificationStatus returns `null` for + // (as it would for a device with no E2E keys). + const nonCryptoDevice = { device_id: "non_crypto" }; + const mockCrypto = { - getDeviceVerificationStatus: jest.fn().mockResolvedValue({ - crossSigningVerified: false, + getDeviceVerificationStatus: jest.fn().mockImplementation((_userId, deviceId) => { + if (_userId !== userId) { + throw new Error(`bad user id ${_userId}`); + } + if (deviceId === ownDevice.device_id || deviceId === verifiedDevice.device_id) { + return { crossSigningVerified: true }; + } else if (deviceId === unverifiedDevice.device_id) { + return { + crossSigningVerified: false, + }; + } else { + return null; + } }), }; const mockClient = getMockClientWithEventEmitter({ ...mockClientMethodsUser(userId), getDevices: jest.fn(), - getDeviceId: jest.fn().mockReturnValue(device1.device_id), + getDeviceId: jest.fn().mockReturnValue(ownDevice.device_id), deleteMultipleDevices: jest.fn(), getStoredDevice: jest.fn().mockReturnValue(new DeviceInfo("id")), generateClientSecret: jest.fn(), @@ -54,12 +76,14 @@ describe("", () => { beforeEach(() => { jest.clearAllMocks(); - mockClient.getDevices.mockReset().mockResolvedValue({ devices: [device1, device2, device3] }); + mockClient.getDevices + .mockReset() + .mockResolvedValue({ devices: [ownDevice, verifiedDevice, unverifiedDevice, nonCryptoDevice] }); mockClient.getPushers.mockReset().mockResolvedValue({ pushers: [ mkPusher({ - [PUSHER_DEVICE_ID.name]: device1.device_id, + [PUSHER_DEVICE_ID.name]: ownDevice.device_id, [PUSHER_ENABLED.name]: true, }), ], @@ -88,16 +112,16 @@ describe("", () => { it("deletes selected devices when interactive auth is not required", async () => { mockClient.deleteMultipleDevices.mockResolvedValue({}); mockClient.getDevices - .mockResolvedValueOnce({ devices: [device1, device2, device3] }) + .mockResolvedValueOnce({ devices: [ownDevice, verifiedDevice, unverifiedDevice] }) // pretend it was really deleted on refresh - .mockResolvedValueOnce({ devices: [device1, device3] }); + .mockResolvedValueOnce({ devices: [ownDevice, unverifiedDevice] }); const { container, getByTestId } = render(getComponent()); await flushPromises(); expect(container.getElementsByClassName("mx_DevicesPanel_device").length).toEqual(3); - toggleDeviceSelection(container, device2.device_id); + toggleDeviceSelection(container, verifiedDevice.device_id); mockClient.getDevices.mockClear(); @@ -106,7 +130,7 @@ describe("", () => { }); expect(container.getElementsByClassName("mx_Spinner").length).toBeTruthy(); - expect(mockClient.deleteMultipleDevices).toHaveBeenCalledWith([device2.device_id], undefined); + expect(mockClient.deleteMultipleDevices).toHaveBeenCalledWith([verifiedDevice.device_id], undefined); await flushPromises(); @@ -124,9 +148,9 @@ describe("", () => { .mockResolvedValueOnce({}); mockClient.getDevices - .mockResolvedValueOnce({ devices: [device1, device2, device3] }) + .mockResolvedValueOnce({ devices: [ownDevice, verifiedDevice, unverifiedDevice] }) // pretend it was really deleted on refresh - .mockResolvedValueOnce({ devices: [device1, device3] }); + .mockResolvedValueOnce({ devices: [ownDevice, unverifiedDevice] }); const { container, getByTestId, getByLabelText } = render(getComponent()); @@ -135,7 +159,7 @@ describe("", () => { // reset mock count after initial load mockClient.getDevices.mockClear(); - toggleDeviceSelection(container, device2.device_id); + toggleDeviceSelection(container, verifiedDevice.device_id); act(() => { fireEvent.click(getByTestId("sign-out-devices-btn")); @@ -145,7 +169,7 @@ describe("", () => { // modal rendering has some weird sleeps await sleep(100); - expect(mockClient.deleteMultipleDevices).toHaveBeenCalledWith([device2.device_id], undefined); + expect(mockClient.deleteMultipleDevices).toHaveBeenCalledWith([verifiedDevice.device_id], undefined); const modal = document.getElementsByClassName("mx_Dialog"); expect(modal).toMatchSnapshot(); @@ -159,7 +183,7 @@ describe("", () => { await flushPromises(); // called again with auth - expect(mockClient.deleteMultipleDevices).toHaveBeenCalledWith([device2.device_id], { + expect(mockClient.deleteMultipleDevices).toHaveBeenCalledWith([verifiedDevice.device_id], { identifier: { type: "m.id.user", user: userId, @@ -182,9 +206,9 @@ describe("", () => { .mockResolvedValueOnce({}); mockClient.getDevices - .mockResolvedValueOnce({ devices: [device1, device2, device3] }) + .mockResolvedValueOnce({ devices: [ownDevice, verifiedDevice, unverifiedDevice] }) // pretend it was really deleted on refresh - .mockResolvedValueOnce({ devices: [device1, device3] }); + .mockResolvedValueOnce({ devices: [ownDevice, unverifiedDevice] }); const { container, getByTestId } = render(getComponent()); @@ -193,7 +217,7 @@ describe("", () => { // reset mock count after initial load mockClient.getDevices.mockClear(); - toggleDeviceSelection(container, device2.device_id); + toggleDeviceSelection(container, verifiedDevice.device_id); act(() => { fireEvent.click(getByTestId("sign-out-devices-btn")); diff --git a/test/components/views/settings/__snapshots__/DevicesPanel-test.tsx.snap b/test/components/views/settings/__snapshots__/DevicesPanel-test.tsx.snap index e8aca7063cf..ad12a99c7c5 100644 --- a/test/components/views/settings/__snapshots__/DevicesPanel-test.tsx.snap +++ b/test/components/views/settings/__snapshots__/DevicesPanel-test.tsx.snap @@ -104,7 +104,7 @@ exports[` renders device panel with devices 1`] = ` class="mx_DevicesPanel_deviceTrust" >
renders device panel with devices 1`] = ` />
@@ -143,7 +143,7 @@ exports[` renders device panel with devices 1`] = ` - Unverified + Verified · renders device panel with devices 1`] = ` > Sign Out -
- Verify -
renders device panel with devices 1`] = ` class="mx_DevicesPanel_header_trust" >
- Unverified devices -
-
-
- Select all -
+ Verified devices
renders device panel with devices 1`] = ` />
@@ -269,7 +251,7 @@ exports[` renders device panel with devices 1`] = ` - Unverified + Verified · renders device panel with devices 1`] = ` +
+
+
+ +
+
+ Unverified devices +
+
@@ -367,6 +366,114 @@ exports[` renders device panel with devices 1`] = `
+
+
+ Verify +
+
+ Rename +
+
+ + + +
+ + +
+
+
+
+ Devices without encryption support +
+
+
+
+ + +