Skip to content

Commit e993d32

Browse files
committed
Test sendToDevice in ClientWidgetApi
1 parent 7a5a2bc commit e993d32

File tree

1 file changed

+246
-0
lines changed

1 file changed

+246
-0
lines changed

test/ClientWidgetApi-test.ts

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import {
3434
IMatrixApiError,
3535
IReadEventFromWidgetActionRequest,
3636
ISendEventFromWidgetActionRequest,
37+
ISendToDeviceFromWidgetActionRequest,
3738
IUpdateDelayedEventFromWidgetActionRequest,
3839
IUploadFileActionFromWidgetActionRequest,
3940
IWidgetApiErrorResponseDataDetails,
@@ -117,6 +118,7 @@ describe('ClientWidgetApi', () => {
117118
sendEvent: jest.fn(),
118119
sendDelayedEvent: jest.fn(),
119120
updateDelayedEvent: jest.fn(),
121+
sendToDevice: jest.fn(),
120122
validateCapabilities: jest.fn(),
121123
searchUserDirectory: jest.fn(),
122124
getMediaConfig: jest.fn(),
@@ -721,6 +723,250 @@ describe('ClientWidgetApi', () => {
721723
});
722724
});
723725

726+
describe('send_to_device action', () => {
727+
it('sends unencrypted to-device events', async () => {
728+
const event: ISendToDeviceFromWidgetActionRequest = {
729+
api: WidgetApiDirection.FromWidget,
730+
widgetId: 'test',
731+
requestId: '0',
732+
action: WidgetApiFromWidgetAction.SendToDevice,
733+
data: {
734+
type: 'net.example.test',
735+
encrypted: false,
736+
messages: {
737+
'@foo:bar.com': {
738+
'DEVICEID': {
739+
'example_content_key': 'value',
740+
},
741+
},
742+
},
743+
},
744+
};
745+
746+
await loadIframe([`org.matrix.msc3819.send.to_device:${event.data.type}`]);
747+
748+
emitEvent(new CustomEvent('', { detail: event }));
749+
750+
await waitFor(() => {
751+
expect(transport.reply).toHaveBeenCalledWith(event, {});
752+
});
753+
754+
expect(driver.sendToDevice).toHaveBeenCalledWith(
755+
event.data.type,
756+
event.data.encrypted,
757+
event.data.messages,
758+
);
759+
});
760+
761+
it('fails to send to-device events without event type', async () => {
762+
const event: IWidgetApiRequest = {
763+
api: WidgetApiDirection.FromWidget,
764+
widgetId: 'test',
765+
requestId: '0',
766+
action: WidgetApiFromWidgetAction.SendToDevice,
767+
data: {
768+
encrypted: false,
769+
messages: {
770+
'@foo:bar.com': {
771+
'DEVICEID': {
772+
'example_content_key': 'value',
773+
},
774+
},
775+
},
776+
},
777+
};
778+
779+
await loadIframe([`org.matrix.msc3819.send.to_device:${event.data.type}`]);
780+
781+
emitEvent(new CustomEvent('', { detail: event }));
782+
783+
await waitFor(() => {
784+
expect(transport.reply).toBeCalledWith(event, {
785+
error: { message: 'Invalid request - missing event type' },
786+
});
787+
});
788+
789+
expect(driver.sendToDevice).not.toBeCalled();
790+
});
791+
792+
it('fails to send to-device events without event contents', async () => {
793+
const event: IWidgetApiRequest = {
794+
api: WidgetApiDirection.FromWidget,
795+
widgetId: 'test',
796+
requestId: '0',
797+
action: WidgetApiFromWidgetAction.SendToDevice,
798+
data: {
799+
type: 'net.example.test',
800+
encrypted: false,
801+
},
802+
};
803+
804+
await loadIframe([`org.matrix.msc3819.send.to_device:${event.data.type}`]);
805+
806+
emitEvent(new CustomEvent('', { detail: event }));
807+
808+
await waitFor(() => {
809+
expect(transport.reply).toBeCalledWith(event, {
810+
error: { message: 'Invalid request - missing event contents' },
811+
});
812+
});
813+
814+
expect(driver.sendToDevice).not.toBeCalled();
815+
});
816+
817+
it('fails to send to-device events without encryption flag', async () => {
818+
const event: IWidgetApiRequest = {
819+
api: WidgetApiDirection.FromWidget,
820+
widgetId: 'test',
821+
requestId: '0',
822+
action: WidgetApiFromWidgetAction.SendToDevice,
823+
data: {
824+
type: 'net.example.test',
825+
messages: {
826+
'@foo:bar.com': {
827+
'DEVICEID': {
828+
'example_content_key': 'value',
829+
},
830+
},
831+
},
832+
},
833+
};
834+
835+
await loadIframe([`org.matrix.msc3819.send.to_device:${event.data.type}`]);
836+
837+
emitEvent(new CustomEvent('', { detail: event }));
838+
839+
await waitFor(() => {
840+
expect(transport.reply).toBeCalledWith(event, {
841+
error: { message: 'Invalid request - missing encryption flag' },
842+
});
843+
});
844+
845+
expect(driver.sendToDevice).not.toBeCalled();
846+
});
847+
848+
it('fails to send to-device events with any event type', async () => {
849+
const event: ISendToDeviceFromWidgetActionRequest = {
850+
api: WidgetApiDirection.FromWidget,
851+
widgetId: 'test',
852+
requestId: '0',
853+
action: WidgetApiFromWidgetAction.SendToDevice,
854+
data: {
855+
type: 'net.example.test',
856+
encrypted: false,
857+
messages: {
858+
'@foo:bar.com': {
859+
'DEVICEID': {
860+
'example_content_key': 'value',
861+
},
862+
},
863+
},
864+
},
865+
};
866+
867+
await loadIframe([`org.matrix.msc3819.send.to_device:${event.data.type}_different`]);
868+
869+
emitEvent(new CustomEvent('', { detail: event }));
870+
871+
await waitFor(() => {
872+
expect(transport.reply).toBeCalledWith(event, {
873+
error: { message: 'Cannot send to-device events of this type' },
874+
});
875+
});
876+
877+
expect(driver.sendToDevice).not.toBeCalled();
878+
});
879+
880+
it('should reject requests when the driver throws an exception', async () => {
881+
driver.sendToDevice.mockRejectedValue(
882+
new Error("M_FORBIDDEN: You don't have permission to send to-device events"),
883+
);
884+
885+
const event: ISendToDeviceFromWidgetActionRequest = {
886+
api: WidgetApiDirection.FromWidget,
887+
widgetId: 'test',
888+
requestId: '0',
889+
action: WidgetApiFromWidgetAction.SendToDevice,
890+
data: {
891+
type: 'net.example.test',
892+
encrypted: false,
893+
messages: {
894+
'@foo:bar.com': {
895+
'DEVICEID': {
896+
'example_content_key': 'value',
897+
},
898+
},
899+
},
900+
},
901+
};
902+
903+
await loadIframe([`org.matrix.msc3819.send.to_device:${event.data.type}`]);
904+
905+
emitEvent(new CustomEvent('', { detail: event }));
906+
907+
await waitFor(() => {
908+
expect(transport.reply).toBeCalledWith(event, {
909+
error: { message: 'Error sending event' },
910+
});
911+
});
912+
});
913+
914+
it('should reject with Matrix API error response thrown by driver', async () => {
915+
driver.processError.mockImplementation(processCustomMatrixError);
916+
917+
driver.sendToDevice.mockRejectedValue(
918+
new CustomMatrixError(
919+
'failed to send event',
920+
400,
921+
'M_FORBIDDEN',
922+
{
923+
reason: "You don't have permission to send to-device events",
924+
},
925+
),
926+
);
927+
928+
const event: ISendToDeviceFromWidgetActionRequest = {
929+
api: WidgetApiDirection.FromWidget,
930+
widgetId: 'test',
931+
requestId: '0',
932+
action: WidgetApiFromWidgetAction.SendToDevice,
933+
data: {
934+
type: 'net.example.test',
935+
encrypted: false,
936+
messages: {
937+
'@foo:bar.com': {
938+
'DEVICEID': {
939+
'example_content_key': 'value',
940+
},
941+
},
942+
},
943+
},
944+
};
945+
946+
await loadIframe([`org.matrix.msc3819.send.to_device:${event.data.type}`]);
947+
948+
emitEvent(new CustomEvent('', { detail: event }));
949+
950+
await waitFor(() => {
951+
expect(transport.reply).toBeCalledWith(event, {
952+
error: {
953+
message: 'Error sending event',
954+
matrix_api_error: {
955+
http_status: 400,
956+
http_headers: {},
957+
url: '',
958+
response: {
959+
errcode: 'M_FORBIDDEN',
960+
error: 'failed to send event',
961+
reason: "You don't have permission to send to-device events",
962+
},
963+
} satisfies IMatrixApiError,
964+
},
965+
});
966+
});
967+
});
968+
});
969+
724970
describe('org.matrix.msc2876.read_events action', () => {
725971
it('reads state events with any state key', async () => {
726972
driver.readStateEvents.mockResolvedValue([

0 commit comments

Comments
 (0)