Implement push notification toggle in device detail (#9308)

Co-authored-by: Travis Ralston <travisr@matrix.org>
This commit is contained in:
Germain 2022-09-27 13:35:54 +01:00 committed by GitHub
parent ace6591f43
commit 641cf28e4c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 269 additions and 3 deletions

View file

@ -19,11 +19,13 @@ import { act } from 'react-dom/test-utils';
import { CrossSigningInfo } from 'matrix-js-sdk/src/crypto/CrossSigning';
import { DeviceInfo } from 'matrix-js-sdk/src/crypto/deviceinfo';
import { sleep } from 'matrix-js-sdk/src/utils';
import { PUSHER_DEVICE_ID, PUSHER_ENABLED } from 'matrix-js-sdk/src/@types/event';
import DevicesPanel from "../../../../src/components/views/settings/DevicesPanel";
import {
flushPromises,
getMockClientWithEventEmitter,
mkPusher,
mockClientMethodsUser,
} from "../../../test-utils";
@ -40,6 +42,8 @@ describe('<DevicesPanel />', () => {
getStoredCrossSigningForUser: jest.fn().mockReturnValue(new CrossSigningInfo(userId, {}, {})),
getStoredDevice: jest.fn().mockReturnValue(new DeviceInfo('id')),
generateClientSecret: jest.fn(),
getPushers: jest.fn(),
setPusher: jest.fn(),
});
const getComponent = () => <DevicesPanel />;
@ -50,6 +54,15 @@ describe('<DevicesPanel />', () => {
mockClient.getDevices
.mockReset()
.mockResolvedValue({ devices: [device1, device2, device3] });
mockClient.getPushers
.mockReset()
.mockResolvedValue({
pushers: [mkPusher({
[PUSHER_DEVICE_ID.name]: device1.device_id,
[PUSHER_ENABLED.name]: true,
})],
});
});
it('renders device panel with devices', async () => {

View file

@ -40,6 +40,7 @@ describe('<CurrentDeviceSection />', () => {
isLoading: false,
isSigningOut: false,
};
const getComponent = (props = {}): React.ReactElement =>
(<CurrentDeviceSection {...defaultProps} {...props} />);

View file

@ -15,9 +15,11 @@ limitations under the License.
*/
import React from 'react';
import { render } from '@testing-library/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';
describe('<DeviceDetails />', () => {
const baseDevice = {
@ -26,12 +28,17 @@ describe('<DeviceDetails />', () => {
};
const defaultProps = {
device: baseDevice,
pusher: null,
isSigningOut: false,
isLoading: false,
onSignOutDevice: jest.fn(),
saveDeviceName: jest.fn(),
setPusherEnabled: jest.fn(),
supportsMSC3881: true,
};
const getComponent = (props = {}) => <DeviceDetails {...defaultProps} {...props} />;
// 14.03.2022 16:15
const now = 1647270879403;
jest.useFakeTimers();
@ -74,4 +81,82 @@ describe('<DeviceDetails />', () => {
getByTestId('device-detail-sign-out-cta').getAttribute('aria-disabled'),
).toEqual("true");
});
it('renders the push notification section when a pusher exists', () => {
const device = {
...baseDevice,
};
const pusher = mkPusher({
device_id: device.device_id,
});
const { getByTestId } = render(getComponent({
device,
pusher,
isSigningOut: true,
}));
expect(getByTestId('device-detail-push-notification')).toBeTruthy();
});
it('hides the push notification section when no pusher', () => {
const device = {
...baseDevice,
};
const { getByTestId } = render(getComponent({
device,
pusher: null,
isSigningOut: true,
}));
expect(() => getByTestId('device-detail-push-notification')).toThrow();
});
it('disables the checkbox when there is no server support', () => {
const device = {
...baseDevice,
};
const pusher = mkPusher({
device_id: device.device_id,
[PUSHER_ENABLED.name]: false,
});
const { getByTestId } = render(getComponent({
device,
pusher,
isSigningOut: true,
supportsMSC3881: false,
}));
const checkbox = getByTestId('device-detail-push-notification-checkbox');
expect(checkbox.getAttribute('aria-disabled')).toEqual("true");
expect(checkbox.getAttribute('aria-checked')).toEqual("false");
});
it('changes the pusher status when clicked', () => {
const device = {
...baseDevice,
};
const enabled = false;
const pusher = mkPusher({
device_id: device.device_id,
[PUSHER_ENABLED.name]: enabled,
});
const { getByTestId } = render(getComponent({
device,
pusher,
isSigningOut: true,
}));
const checkbox = getByTestId('device-detail-push-notification-checkbox');
fireEvent.click(checkbox);
expect(defaultProps.setPusherEnabled).toHaveBeenCalledWith(device.device_id, !enabled);
});
});

View file

@ -45,6 +45,7 @@ describe('<FilteredDeviceList />', () => {
onDeviceExpandToggle: jest.fn(),
onSignOutDevices: jest.fn(),
saveDeviceName: jest.fn(),
setPusherEnabled: jest.fn(),
expandedDeviceIds: [],
signingOutDeviceIds: [],
devices: {
@ -54,7 +55,10 @@ describe('<FilteredDeviceList />', () => {
[hundredDaysOld.device_id]: hundredDaysOld,
[hundredDaysOldUnverified.device_id]: hundredDaysOldUnverified,
},
pushers: [],
supportsMSC3881: true,
};
const getComponent = (props = {}) =>
(<FilteredDeviceList {...defaultProps} {...props} />);

View file

@ -22,13 +22,14 @@ import { logger } from 'matrix-js-sdk/src/logger';
import { DeviceTrustLevel } from 'matrix-js-sdk/src/crypto/CrossSigning';
import { VerificationRequest } from 'matrix-js-sdk/src/crypto/verification/request/VerificationRequest';
import { sleep } from 'matrix-js-sdk/src/utils';
import { IMyDevice } from 'matrix-js-sdk/src/matrix';
import { IMyDevice, PUSHER_DEVICE_ID, PUSHER_ENABLED } from 'matrix-js-sdk/src/matrix';
import SessionManagerTab from '../../../../../../src/components/views/settings/tabs/user/SessionManagerTab';
import MatrixClientContext from '../../../../../../src/contexts/MatrixClientContext';
import {
flushPromisesWithFakeTimers,
getMockClientWithEventEmitter,
mkPusher,
mockClientMethodsUser,
} from '../../../../../test-utils';
import Modal from '../../../../../../src/Modal';
@ -67,6 +68,9 @@ describe('<SessionManagerTab />', () => {
deleteMultipleDevices: jest.fn(),
generateClientSecret: jest.fn(),
setDeviceDetails: jest.fn(),
doesServerSupportUnstableFeature: jest.fn().mockResolvedValue(true),
getPushers: jest.fn(),
setPusher: jest.fn(),
});
const defaultProps = {};
@ -101,6 +105,15 @@ describe('<SessionManagerTab />', () => {
mockClient.getDevices
.mockReset()
.mockResolvedValue({ devices: [alicesDevice, alicesMobileDevice] });
mockClient.getPushers
.mockReset()
.mockResolvedValue({
pushers: [mkPusher({
[PUSHER_DEVICE_ID.name]: alicesMobileDevice.device_id,
[PUSHER_ENABLED.name]: true,
})],
});
});
it('renders spinner while devices load', () => {
@ -668,4 +681,25 @@ describe('<SessionManagerTab />', () => {
expect(getByTestId('device-rename-error')).toBeTruthy();
});
});
it("lets you change the pusher state", async () => {
const { getByTestId } = render(getComponent());
await act(async () => {
await flushPromisesWithFakeTimers();
});
toggleDeviceDetails(getByTestId, alicesMobileDevice.device_id);
// device details are expanded
expect(getByTestId(`device-detail-${alicesMobileDevice.device_id}`)).toBeTruthy();
expect(getByTestId('device-detail-push-notification')).toBeTruthy();
const checkbox = getByTestId('device-detail-push-notification-checkbox');
expect(checkbox).toBeTruthy();
fireEvent.click(checkbox);
expect(mockClient.setPusher).toHaveBeenCalled();
});
});

View file

@ -30,6 +30,7 @@ import {
EventType,
IEventRelation,
IUnsigned,
IPusher,
} from 'matrix-js-sdk/src/matrix';
import { normalize } from "matrix-js-sdk/src/utils";
import { ReEmitter } from "matrix-js-sdk/src/ReEmitter";
@ -541,3 +542,14 @@ export const mkSpace = (
)));
return space;
};
export const mkPusher = (extra: Partial<IPusher> = {}): IPusher => ({
app_display_name: "app",
app_id: "123",
data: {},
device_display_name: "name",
kind: "http",
lang: "en",
pushkey: "pushpush",
...extra,
});