Live location sharing - display wire error in room (#8198)

* expose wire errors in more useful way

* add wire error state to room live share warning bar

Signed-off-by: Kerry Archibald <kerrya@element.io>

* stylelint

Signed-off-by: Kerry Archibald <kerrya@element.io>

* add types to getLabel helper

Signed-off-by: Kerry Archibald <kerrya@element.io>
pull/21833/head
Kerry 2022-03-31 10:57:12 +02:00 committed by GitHub
parent 60ca8996d3
commit 1175226bcb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 296 additions and 58 deletions

View File

@ -48,3 +48,13 @@ limitations under the License.
.mx_RoomLiveShareWarning_spinner { .mx_RoomLiveShareWarning_spinner {
margin-right: $spacing-16; margin-right: $spacing-16;
} }
.mx_RoomLiveShareWarning_closeButton {
@mixin ButtonResetDefault;
margin-left: $spacing-16;
}
.mx_RoomLiveShareWarning_closeButtonIcon {
height: $font-18px;
padding: $spacing-4;
}

View File

@ -18,19 +18,16 @@ import React, { useCallback, useEffect, useState } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { Room, Beacon } from 'matrix-js-sdk/src/matrix'; import { Room, Beacon } from 'matrix-js-sdk/src/matrix';
import { formatDuration } from '../../../DateUtils';
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
import { useEventEmitterState } from '../../../hooks/useEventEmitter'; import { useEventEmitterState } from '../../../hooks/useEventEmitter';
import { OwnBeaconStore, OwnBeaconStoreEvent } from '../../../stores/OwnBeaconStore';
import AccessibleButton from '../elements/AccessibleButton';
import StyledLiveBeaconIcon from './StyledLiveBeaconIcon';
import { formatDuration } from '../../../DateUtils';
import { getBeaconMsUntilExpiry, sortBeaconsByLatestExpiry } from '../../../utils/beacon';
import Spinner from '../elements/Spinner';
import { useInterval } from '../../../hooks/useTimeout'; import { useInterval } from '../../../hooks/useTimeout';
import { OwnBeaconStore, OwnBeaconStoreEvent } from '../../../stores/OwnBeaconStore';
interface Props { import { getBeaconMsUntilExpiry, sortBeaconsByLatestExpiry } from '../../../utils/beacon';
roomId: Room['roomId']; import AccessibleButton from '../elements/AccessibleButton';
} import Spinner from '../elements/Spinner';
import StyledLiveBeaconIcon from './StyledLiveBeaconIcon';
import { Icon as CloseIcon } from '../../../../res/img/image-view/close.svg';
const MINUTE_MS = 60000; const MINUTE_MS = 60000;
const HOUR_MS = MINUTE_MS * 60; const HOUR_MS = MINUTE_MS * 60;
@ -72,24 +69,20 @@ const useMsRemaining = (beacon: Beacon): number => {
type LiveBeaconsState = { type LiveBeaconsState = {
beacon?: Beacon; beacon?: Beacon;
onStopSharing?: () => void; onStopSharing?: () => void;
onResetWireError?: () => void;
stoppingInProgress?: boolean; stoppingInProgress?: boolean;
hasStopSharingError?: boolean; hasStopSharingError?: boolean;
hasWireError?: boolean;
}; };
const useLiveBeacons = (roomId: Room['roomId']): LiveBeaconsState => { const useLiveBeacons = (liveBeaconIds: string[], roomId: string): LiveBeaconsState => {
const [stoppingInProgress, setStoppingInProgress] = useState(false); const [stoppingInProgress, setStoppingInProgress] = useState(false);
const [error, setError] = useState<Error>(); const [error, setError] = useState<Error>();
// do we have an active geolocation.watchPosition const hasWireError = useEventEmitterState(
const isMonitoringLiveLocation = useEventEmitterState(
OwnBeaconStore.instance, OwnBeaconStore.instance,
OwnBeaconStoreEvent.MonitoringLivePosition, OwnBeaconStoreEvent.WireError,
() => OwnBeaconStore.instance.isMonitoringLiveLocation, () =>
); OwnBeaconStore.instance.hasWireErrors(roomId),
const liveBeaconIds = useEventEmitterState(
OwnBeaconStore.instance,
OwnBeaconStoreEvent.LivenessChange,
() => OwnBeaconStore.instance.getLiveBeaconIds(roomId),
); );
// reset stopping in progress on change in live ids // reset stopping in progress on change in live ids
@ -98,10 +91,6 @@ const useLiveBeacons = (roomId: Room['roomId']): LiveBeaconsState => {
setError(undefined); setError(undefined);
}, [liveBeaconIds]); }, [liveBeaconIds]);
if (!isMonitoringLiveLocation || !liveBeaconIds?.length) {
return {};
}
// select the beacon with latest expiry to display expiry time // select the beacon with latest expiry to display expiry time
const beacon = liveBeaconIds.map(beaconId => OwnBeaconStore.instance.getBeaconById(beaconId)) const beacon = liveBeaconIds.map(beaconId => OwnBeaconStore.instance.getBeaconById(beaconId))
.sort(sortBeaconsByLatestExpiry) .sort(sortBeaconsByLatestExpiry)
@ -120,7 +109,18 @@ const useLiveBeacons = (roomId: Room['roomId']): LiveBeaconsState => {
} }
}; };
return { onStopSharing, beacon, stoppingInProgress, hasStopSharingError: !!error }; const onResetWireError = () => {
liveBeaconIds.map(beaconId => OwnBeaconStore.instance.resetWireError(beaconId));
};
return {
onStopSharing,
onResetWireError,
beacon,
stoppingInProgress,
hasWireError,
hasStopSharingError: !!error,
};
}; };
const LiveTimeRemaining: React.FC<{ beacon: Beacon }> = ({ beacon }) => { const LiveTimeRemaining: React.FC<{ beacon: Beacon }> = ({ beacon }) => {
@ -135,44 +135,103 @@ const LiveTimeRemaining: React.FC<{ beacon: Beacon }> = ({ beacon }) => {
>{ liveTimeRemaining }</span>; >{ liveTimeRemaining }</span>;
}; };
const RoomLiveShareWarning: React.FC<Props> = ({ roomId }) => { const getLabel = (hasWireError: boolean, hasStopSharingError: boolean): string => {
if (hasWireError) {
return _t('An error occured whilst sharing your live location, please try again');
}
if (hasStopSharingError) {
return _t('An error occurred while stopping your live location, please try again');
}
return _t('You are sharing your live location');
};
interface RoomLiveShareWarningInnerProps {
liveBeaconIds: string[];
roomId: Room['roomId'];
}
const RoomLiveShareWarningInner: React.FC<RoomLiveShareWarningInnerProps> = ({ liveBeaconIds, roomId }) => {
const { const {
onStopSharing, onStopSharing,
onResetWireError,
beacon, beacon,
stoppingInProgress, stoppingInProgress,
hasStopSharingError, hasStopSharingError,
} = useLiveBeacons(roomId); hasWireError,
} = useLiveBeacons(liveBeaconIds, roomId);
if (!beacon) { if (!beacon) {
return null; return null;
} }
const hasError = hasStopSharingError || hasWireError;
const onButtonClick = () => {
if (hasWireError) {
onResetWireError();
} else {
onStopSharing();
}
};
return <div return <div
className={classNames('mx_RoomLiveShareWarning')} className={classNames('mx_RoomLiveShareWarning')}
> >
<StyledLiveBeaconIcon className="mx_RoomLiveShareWarning_icon" withError={hasStopSharingError} /> <StyledLiveBeaconIcon className="mx_RoomLiveShareWarning_icon" withError={hasError} />
<span className="mx_RoomLiveShareWarning_label"> <span className="mx_RoomLiveShareWarning_label">
{ hasStopSharingError ? { getLabel(hasWireError, hasStopSharingError) }
_t('An error occurred while stopping your live location, please try again') :
_t('You are sharing your live location')
}
</span> </span>
{ stoppingInProgress && { stoppingInProgress &&
<span className='mx_RoomLiveShareWarning_spinner'><Spinner h={16} w={16} /></span> <span className='mx_RoomLiveShareWarning_spinner'><Spinner h={16} w={16} /></span>
} }
{ !stoppingInProgress && !hasStopSharingError && <LiveTimeRemaining beacon={beacon} /> } { !stoppingInProgress && !hasError && <LiveTimeRemaining beacon={beacon} /> }
<AccessibleButton <AccessibleButton
data-test-id='room-live-share-stop-sharing' data-test-id='room-live-share-primary-button'
onClick={onStopSharing} onClick={onButtonClick}
kind='danger' kind='danger'
element='button' element='button'
disabled={stoppingInProgress} disabled={stoppingInProgress}
> >
{ hasStopSharingError ? _t('Retry') : _t('Stop sharing') } { hasError ? _t('Retry') : _t('Stop sharing') }
</AccessibleButton> </AccessibleButton>
{ hasWireError && <AccessibleButton
data-test-id='room-live-share-wire-error-close-button'
title={_t('Stop sharing and close')}
element='button'
className='mx_RoomLiveShareWarning_closeButton'
onClick={onStopSharing}
>
<CloseIcon className='mx_RoomLiveShareWarning_closeButtonIcon' />
</AccessibleButton> }
</div>; </div>;
}; };
interface Props {
roomId: Room['roomId'];
}
const RoomLiveShareWarning: React.FC<Props> = ({ roomId }) => {
// do we have an active geolocation.watchPosition
const isMonitoringLiveLocation = useEventEmitterState(
OwnBeaconStore.instance,
OwnBeaconStoreEvent.MonitoringLivePosition,
() => OwnBeaconStore.instance.isMonitoringLiveLocation,
);
const liveBeaconIds = useEventEmitterState(
OwnBeaconStore.instance,
OwnBeaconStoreEvent.LivenessChange,
() => OwnBeaconStore.instance.getLiveBeaconIds(roomId),
);
if (!isMonitoringLiveLocation || !liveBeaconIds.length) {
return null;
}
// split into outer/inner to avoid watching various parts of live beacon state
// when there are none
return <RoomLiveShareWarningInner liveBeaconIds={liveBeaconIds} roomId={roomId} />;
};
export default RoomLiveShareWarning; export default RoomLiveShareWarning;

View File

@ -2898,8 +2898,10 @@
"Join the beta": "Join the beta", "Join the beta": "Join the beta",
"You are sharing your live location": "You are sharing your live location", "You are sharing your live location": "You are sharing your live location",
"%(timeRemaining)s left": "%(timeRemaining)s left", "%(timeRemaining)s left": "%(timeRemaining)s left",
"An error occured whilst sharing your live location, please try again": "An error occured whilst sharing your live location, please try again",
"An error occurred while stopping your live location, please try again": "An error occurred while stopping your live location, please try again", "An error occurred while stopping your live location, please try again": "An error occurred while stopping your live location, please try again",
"Stop sharing": "Stop sharing", "Stop sharing": "Stop sharing",
"Stop sharing and close": "Stop sharing and close",
"Avatar": "Avatar", "Avatar": "Avatar",
"This room is public": "This room is public", "This room is public": "This room is public",
"Away": "Away", "Away": "Away",

View File

@ -130,16 +130,24 @@ export class OwnBeaconStore extends AsyncStoreWithClient<OwnBeaconStoreState> {
return !!this.getLiveBeaconIds(roomId).length; return !!this.getLiveBeaconIds(roomId).length;
} }
/**
* Some live beacon has a wire error
* Optionally filter by room
*/
public hasWireErrors(roomId?: string): boolean {
return this.getLiveBeaconIds(roomId).some(this.beaconHasWireError);
}
/** /**
* If a beacon has failed to publish position * If a beacon has failed to publish position
* past the allowed consecutive failure count (BAIL_AFTER_CONSECUTIVE_ERROR_COUNT) * past the allowed consecutive failure count (BAIL_AFTER_CONSECUTIVE_ERROR_COUNT)
* Then consider it to have an error * Then consider it to have an error
*/ */
public hasWireError(beaconId: string): boolean { public beaconHasWireError = (beaconId: string): boolean => {
return this.beaconWireErrorCounts.get(beaconId) >= BAIL_AFTER_CONSECUTIVE_ERROR_COUNT; return this.beaconWireErrorCounts.get(beaconId) >= BAIL_AFTER_CONSECUTIVE_ERROR_COUNT;
} };
public resetWireError(beaconId: string): void { public resetWireError = (beaconId: string): void => {
this.incrementBeaconWireErrorCount(beaconId, false); this.incrementBeaconWireErrorCount(beaconId, false);
// always publish to all live beacons together // always publish to all live beacons together
@ -147,7 +155,7 @@ export class OwnBeaconStore extends AsyncStoreWithClient<OwnBeaconStoreState> {
// to keep lastPublishedTimestamp simple // to keep lastPublishedTimestamp simple
// and extra published locations don't hurt // and extra published locations don't hurt
this.publishCurrentLocationToBeacons(); this.publishCurrentLocationToBeacons();
} };
public getLiveBeaconIds(roomId?: string): string[] { public getLiveBeaconIds(roomId?: string): string[] {
if (!roomId) { if (!roomId) {
@ -230,7 +238,7 @@ export class OwnBeaconStore extends AsyncStoreWithClient<OwnBeaconStoreState> {
* Live beacon ids that do not have wire errors * Live beacon ids that do not have wire errors
*/ */
private get healthyLiveBeaconIds() { private get healthyLiveBeaconIds() {
return this.liveBeaconIds.filter(beaconId => !this.hasWireError(beaconId)); return this.liveBeaconIds.filter(beaconId => !this.beaconHasWireError(beaconId));
} }
private initialiseBeaconState = () => { private initialiseBeaconState = () => {
@ -458,7 +466,7 @@ export class OwnBeaconStore extends AsyncStoreWithClient<OwnBeaconStoreState> {
* - emit if beacon error count crossed threshold * - emit if beacon error count crossed threshold
*/ */
private incrementBeaconWireErrorCount = (beaconId: string, isError: boolean): void => { private incrementBeaconWireErrorCount = (beaconId: string, isError: boolean): void => {
const hadError = this.hasWireError(beaconId); const hadError = this.beaconHasWireError(beaconId);
if (isError) { if (isError) {
// increment error count // increment error count
@ -471,7 +479,7 @@ export class OwnBeaconStore extends AsyncStoreWithClient<OwnBeaconStoreState> {
this.beaconWireErrorCounts.delete(beaconId); this.beaconWireErrorCounts.delete(beaconId);
} }
if (this.hasWireError(beaconId) !== hadError) { if (this.beaconHasWireError(beaconId) !== hadError) {
this.emit(OwnBeaconStoreEvent.WireError, beaconId); this.emit(OwnBeaconStoreEvent.WireError, beaconId);
} }
}; };

View File

@ -101,6 +101,7 @@ describe('<RoomLiveShareWarning />', () => {
}); });
afterEach(async () => { afterEach(async () => {
jest.spyOn(OwnBeaconStore.instance, 'hasWireErrors').mockRestore();
await resetAsyncStoreWithClient(OwnBeaconStore.instance); await resetAsyncStoreWithClient(OwnBeaconStore.instance);
}); });
@ -238,13 +239,13 @@ describe('<RoomLiveShareWarning />', () => {
const component = getComponent({ roomId: room2Id }); const component = getComponent({ roomId: room2Id });
act(() => { act(() => {
findByTestId(component, 'room-live-share-stop-sharing').at(0).simulate('click'); findByTestId(component, 'room-live-share-primary-button').at(0).simulate('click');
component.setProps({}); component.setProps({});
}); });
expect(mockClient.unstable_setLiveBeacon).toHaveBeenCalledTimes(2); expect(mockClient.unstable_setLiveBeacon).toHaveBeenCalledTimes(2);
expect(component.find('Spinner').length).toBeTruthy(); expect(component.find('Spinner').length).toBeTruthy();
expect(findByTestId(component, 'room-live-share-stop-sharing').at(0).props().disabled).toBeTruthy(); expect(findByTestId(component, 'room-live-share-primary-button').at(0).props().disabled).toBeTruthy();
}); });
it('displays error when stop sharing fails', async () => { it('displays error when stop sharing fails', async () => {
@ -256,7 +257,7 @@ describe('<RoomLiveShareWarning />', () => {
.mockResolvedValue(({ event_id: '1' })); .mockResolvedValue(({ event_id: '1' }));
await act(async () => { await act(async () => {
findByTestId(component, 'room-live-share-stop-sharing').at(0).simulate('click'); findByTestId(component, 'room-live-share-primary-button').at(0).simulate('click');
await flushPromisesWithFakeTimers(); await flushPromisesWithFakeTimers();
}); });
component.setProps({}); component.setProps({});
@ -264,7 +265,7 @@ describe('<RoomLiveShareWarning />', () => {
expect(component.html()).toMatchSnapshot(); expect(component.html()).toMatchSnapshot();
act(() => { act(() => {
findByTestId(component, 'room-live-share-stop-sharing').at(0).simulate('click'); findByTestId(component, 'room-live-share-primary-button').at(0).simulate('click');
component.setProps({}); component.setProps({});
}); });
@ -277,7 +278,7 @@ describe('<RoomLiveShareWarning />', () => {
// stop the beacon // stop the beacon
act(() => { act(() => {
findByTestId(component, 'room-live-share-stop-sharing').at(0).simulate('click'); findByTestId(component, 'room-live-share-primary-button').at(0).simulate('click');
}); });
// time travel until room1Beacon1 is expired // time travel until room1Beacon1 is expired
act(() => { act(() => {
@ -293,9 +294,83 @@ describe('<RoomLiveShareWarning />', () => {
}); });
// button not disabled and expiry time shown // button not disabled and expiry time shown
expect(findByTestId(component, 'room-live-share-stop-sharing').at(0).props().disabled).toBeFalsy(); expect(findByTestId(component, 'room-live-share-primary-button').at(0).props().disabled).toBeFalsy();
expect(findByTestId(component, 'room-live-share-expiry').text()).toEqual('1h left'); expect(findByTestId(component, 'room-live-share-expiry').text()).toEqual('1h left');
}); });
}); });
describe('with wire errors', () => {
it('displays wire error when mounted with wire errors', async () => {
const hasWireErrorsSpy = jest.spyOn(OwnBeaconStore.instance, 'hasWireErrors').mockReturnValue(true);
const component = getComponent({ roomId: room2Id });
expect(component).toMatchSnapshot();
expect(hasWireErrorsSpy).toHaveBeenCalledWith(room2Id);
});
it('displays wire error when wireError event is emitted and beacons have errors', async () => {
const hasWireErrorsSpy = jest.spyOn(OwnBeaconStore.instance, 'hasWireErrors').mockReturnValue(false);
const component = getComponent({ roomId: room2Id });
// update mock and emit event
act(() => {
hasWireErrorsSpy.mockReturnValue(true);
OwnBeaconStore.instance.emit(OwnBeaconStoreEvent.WireError, room2Beacon1.getType());
});
component.setProps({});
// renders wire error ui
expect(component.find('.mx_RoomLiveShareWarning_label').text()).toEqual(
'An error occured whilst sharing your live location, please try again',
);
expect(findByTestId(component, 'room-live-share-wire-error-close-button').length).toBeTruthy();
});
it('stops displaying wire error when errors are cleared', async () => {
const hasWireErrorsSpy = jest.spyOn(OwnBeaconStore.instance, 'hasWireErrors').mockReturnValue(true);
const component = getComponent({ roomId: room2Id });
// update mock and emit event
act(() => {
hasWireErrorsSpy.mockReturnValue(false);
OwnBeaconStore.instance.emit(OwnBeaconStoreEvent.WireError, room2Beacon1.getType());
});
component.setProps({});
// renders error-free ui
expect(component.find('.mx_RoomLiveShareWarning_label').text()).toEqual(
'You are sharing your live location',
);
expect(findByTestId(component, 'room-live-share-wire-error-close-button').length).toBeFalsy();
});
it('clicking retry button resets wire errors', async () => {
jest.spyOn(OwnBeaconStore.instance, 'hasWireErrors').mockReturnValue(true);
const resetErrorSpy = jest.spyOn(OwnBeaconStore.instance, 'resetWireError');
const component = getComponent({ roomId: room2Id });
act(() => {
findByTestId(component, 'room-live-share-primary-button').at(0).simulate('click');
});
expect(resetErrorSpy).toHaveBeenCalledWith(room2Beacon1.getType());
expect(resetErrorSpy).toHaveBeenCalledWith(room2Beacon2.getType());
});
it('clicking close button stops beacons', async () => {
jest.spyOn(OwnBeaconStore.instance, 'hasWireErrors').mockReturnValue(true);
const stopBeaconSpy = jest.spyOn(OwnBeaconStore.instance, 'stopBeacon');
const component = getComponent({ roomId: room2Id });
act(() => {
findByTestId(component, 'room-live-share-wire-error-close-button').at(0).simulate('click');
});
expect(stopBeaconSpy).toHaveBeenCalledWith(room2Beacon1.getType());
expect(stopBeaconSpy).toHaveBeenCalledWith(room2Beacon2.getType());
});
});
}); });
}); });

View File

@ -1,7 +1,86 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<RoomLiveShareWarning /> when user has live beacons and geolocation is available renders correctly with one live beacon in room 1`] = `"<div class=\\"mx_RoomLiveShareWarning\\"><div class=\\"mx_StyledLiveBeaconIcon mx_RoomLiveShareWarning_icon\\"></div><span class=\\"mx_RoomLiveShareWarning_label\\">You are sharing your live location</span><span data-test-id=\\"room-live-share-expiry\\" class=\\"mx_RoomLiveShareWarning_expiry\\">1h left</span><button data-test-id=\\"room-live-share-stop-sharing\\" role=\\"button\\" tabindex=\\"0\\" class=\\"mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_danger\\">Stop sharing</button></div>"`; exports[`<RoomLiveShareWarning /> when user has live beacons and geolocation is available renders correctly with one live beacon in room 1`] = `"<div class=\\"mx_RoomLiveShareWarning\\"><div class=\\"mx_StyledLiveBeaconIcon mx_RoomLiveShareWarning_icon\\"></div><span class=\\"mx_RoomLiveShareWarning_label\\">You are sharing your live location</span><span data-test-id=\\"room-live-share-expiry\\" class=\\"mx_RoomLiveShareWarning_expiry\\">1h left</span><button data-test-id=\\"room-live-share-primary-button\\" role=\\"button\\" tabindex=\\"0\\" class=\\"mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_danger\\">Stop sharing</button></div>"`;
exports[`<RoomLiveShareWarning /> when user has live beacons and geolocation is available renders correctly with two live beacons in room 1`] = `"<div class=\\"mx_RoomLiveShareWarning\\"><div class=\\"mx_StyledLiveBeaconIcon mx_RoomLiveShareWarning_icon\\"></div><span class=\\"mx_RoomLiveShareWarning_label\\">You are sharing your live location</span><span data-test-id=\\"room-live-share-expiry\\" class=\\"mx_RoomLiveShareWarning_expiry\\">12h left</span><button data-test-id=\\"room-live-share-stop-sharing\\" role=\\"button\\" tabindex=\\"0\\" class=\\"mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_danger\\">Stop sharing</button></div>"`; exports[`<RoomLiveShareWarning /> when user has live beacons and geolocation is available renders correctly with two live beacons in room 1`] = `"<div class=\\"mx_RoomLiveShareWarning\\"><div class=\\"mx_StyledLiveBeaconIcon mx_RoomLiveShareWarning_icon\\"></div><span class=\\"mx_RoomLiveShareWarning_label\\">You are sharing your live location</span><span data-test-id=\\"room-live-share-expiry\\" class=\\"mx_RoomLiveShareWarning_expiry\\">12h left</span><button data-test-id=\\"room-live-share-primary-button\\" role=\\"button\\" tabindex=\\"0\\" class=\\"mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_danger\\">Stop sharing</button></div>"`;
exports[`<RoomLiveShareWarning /> when user has live beacons and geolocation is available stopping beacons displays error when stop sharing fails 1`] = `"<div class=\\"mx_RoomLiveShareWarning\\"><div class=\\"mx_StyledLiveBeaconIcon mx_RoomLiveShareWarning_icon mx_StyledLiveBeaconIcon_error\\"></div><span class=\\"mx_RoomLiveShareWarning_label\\">An error occurred while stopping your live location, please try again</span><button data-test-id=\\"room-live-share-stop-sharing\\" role=\\"button\\" tabindex=\\"0\\" class=\\"mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_danger\\">Retry</button></div>"`; exports[`<RoomLiveShareWarning /> when user has live beacons and geolocation is available stopping beacons displays error when stop sharing fails 1`] = `"<div class=\\"mx_RoomLiveShareWarning\\"><div class=\\"mx_StyledLiveBeaconIcon mx_RoomLiveShareWarning_icon mx_StyledLiveBeaconIcon_error\\"></div><span class=\\"mx_RoomLiveShareWarning_label\\">An error occurred while stopping your live location, please try again</span><button data-test-id=\\"room-live-share-primary-button\\" role=\\"button\\" tabindex=\\"0\\" class=\\"mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_danger\\">Retry</button></div>"`;
exports[`<RoomLiveShareWarning /> when user has live beacons and geolocation is available with wire errors displays wire error when mounted with wire errors 1`] = `
<RoomLiveShareWarning
roomId="$room2:server.org"
>
<RoomLiveShareWarningInner
liveBeaconIds={
Array [
"org.matrix.msc3489.beacon_info.@alice:server.org.3",
"org.matrix.msc3489.beacon_info.@alice:server.org.4",
]
}
roomId="$room2:server.org"
>
<div
className="mx_RoomLiveShareWarning"
>
<StyledLiveBeaconIcon
className="mx_RoomLiveShareWarning_icon"
withError={true}
>
<div
className="mx_StyledLiveBeaconIcon mx_RoomLiveShareWarning_icon mx_StyledLiveBeaconIcon_error"
/>
</StyledLiveBeaconIcon>
<span
className="mx_RoomLiveShareWarning_label"
>
An error occured whilst sharing your live location, please try again
</span>
<AccessibleButton
data-test-id="room-live-share-primary-button"
disabled={false}
element="button"
kind="danger"
onClick={[Function]}
role="button"
tabIndex={0}
>
<button
className="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_danger"
data-test-id="room-live-share-primary-button"
onClick={[Function]}
onKeyDown={[Function]}
onKeyUp={[Function]}
role="button"
tabIndex={0}
>
Retry
</button>
</AccessibleButton>
<AccessibleButton
className="mx_RoomLiveShareWarning_closeButton"
data-test-id="room-live-share-wire-error-close-button"
element="button"
onClick={[Function]}
role="button"
tabIndex={0}
title="Stop sharing and close"
>
<button
className="mx_AccessibleButton mx_RoomLiveShareWarning_closeButton"
data-test-id="room-live-share-wire-error-close-button"
onClick={[Function]}
onKeyDown={[Function]}
onKeyUp={[Function]}
role="button"
tabIndex={0}
title="Stop sharing and close"
>
<div
className="mx_RoomLiveShareWarning_closeButtonIcon"
/>
</button>
</AccessibleButton>
</div>
</RoomLiveShareWarningInner>
</RoomLiveShareWarning>
`;

View File

@ -863,7 +863,8 @@ describe('OwnBeaconStore', () => {
// called for each position from watchPosition // called for each position from watchPosition
expect(mockClient.sendEvent).toHaveBeenCalledTimes(5); expect(mockClient.sendEvent).toHaveBeenCalledTimes(5);
expect(store.hasWireError(alicesRoom1BeaconInfo.getType())).toBe(false); expect(store.beaconHasWireError(alicesRoom1BeaconInfo.getType())).toBe(false);
expect(store.hasWireErrors()).toBe(false);
}); });
it('continues publishing positions when a beacon fails intermittently', async () => { it('continues publishing positions when a beacon fails intermittently', async () => {
@ -889,7 +890,8 @@ describe('OwnBeaconStore', () => {
// called for each position from watchPosition // called for each position from watchPosition
expect(mockClient.sendEvent).toHaveBeenCalledTimes(5); expect(mockClient.sendEvent).toHaveBeenCalledTimes(5);
expect(store.hasWireError(alicesRoom1BeaconInfo.getType())).toBe(false); expect(store.beaconHasWireError(alicesRoom1BeaconInfo.getType())).toBe(false);
expect(store.hasWireErrors()).toBe(false);
expect(emitSpy).not.toHaveBeenCalledWith( expect(emitSpy).not.toHaveBeenCalledWith(
OwnBeaconStoreEvent.WireError, alicesRoom1BeaconInfo.getType(), OwnBeaconStoreEvent.WireError, alicesRoom1BeaconInfo.getType(),
); );
@ -911,7 +913,8 @@ describe('OwnBeaconStore', () => {
// only two allowed failures // only two allowed failures
expect(mockClient.sendEvent).toHaveBeenCalledTimes(2); expect(mockClient.sendEvent).toHaveBeenCalledTimes(2);
expect(store.hasWireError(alicesRoom1BeaconInfo.getType())).toBe(true); expect(store.beaconHasWireError(alicesRoom1BeaconInfo.getType())).toBe(true);
expect(store.hasWireErrors()).toBe(true);
expect(emitSpy).toHaveBeenCalledWith( expect(emitSpy).toHaveBeenCalledWith(
OwnBeaconStoreEvent.WireError, alicesRoom1BeaconInfo.getType(), OwnBeaconStoreEvent.WireError, alicesRoom1BeaconInfo.getType(),
); );
@ -933,7 +936,9 @@ describe('OwnBeaconStore', () => {
// only two allowed failures // only two allowed failures
expect(mockClient.sendEvent).toHaveBeenCalledTimes(2); expect(mockClient.sendEvent).toHaveBeenCalledTimes(2);
expect(store.hasWireError(alicesRoom1BeaconInfo.getType())).toBe(true); expect(store.beaconHasWireError(alicesRoom1BeaconInfo.getType())).toBe(true);
expect(store.hasWireErrors()).toBe(true);
expect(store.hasWireErrors(room1Id)).toBe(true);
expect(emitSpy).toHaveBeenCalledWith( expect(emitSpy).toHaveBeenCalledWith(
OwnBeaconStoreEvent.WireError, alicesRoom1BeaconInfo.getType(), OwnBeaconStoreEvent.WireError, alicesRoom1BeaconInfo.getType(),
); );
@ -942,7 +947,7 @@ describe('OwnBeaconStore', () => {
emitSpy.mockClear(); emitSpy.mockClear();
store.resetWireError(alicesRoom1BeaconInfo.getType()); store.resetWireError(alicesRoom1BeaconInfo.getType());
expect(store.hasWireError(alicesRoom1BeaconInfo.getType())).toBe(false); expect(store.beaconHasWireError(alicesRoom1BeaconInfo.getType())).toBe(false);
// 2 more positions from watchPosition in this period // 2 more positions from watchPosition in this period
await advanceAndFlushPromises(10000); await advanceAndFlushPromises(10000);