Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 6585fb1

Browse files
justinbotturt2live
andauthored
Add actions for integration manager to send and read certain events (#9740)
* Add send_event action * Add read_events action * Add e2e tests for send_event * Allow more event types to be read * Fix error message * Add e2e tests for read_events * Run i18n * Improve error messages * Fix types * Remove unused test helpers * Fix more type errors * Run prettier * Fix more type errors * Fix validation Since typeof null is "object" Co-authored-by: Travis Ralston <[email protected]>
1 parent d6e447b commit 6585fb1

File tree

4 files changed

+711
-3
lines changed

4 files changed

+711
-3
lines changed
Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
/*
2+
Copyright 2022 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
/// <reference types="cypress" />
18+
19+
import { SynapseInstance } from "../../plugins/synapsedocker";
20+
import { UserCredentials } from "../../support/login";
21+
22+
const ROOM_NAME = "Integration Manager Test";
23+
const USER_DISPLAY_NAME = "Alice";
24+
25+
const INTEGRATION_MANAGER_TOKEN = "DefinitelySecret_DoNotUseThisForReal";
26+
const INTEGRATION_MANAGER_HTML = `
27+
<html lang="en">
28+
<head>
29+
<title>Fake Integration Manager</title>
30+
</head>
31+
<body>
32+
<input type="text" id="target-room-id"/>
33+
<input type="text" id="event-type"/>
34+
<input type="text" id="state-key"/>
35+
<button name="Send" id="send-action">Press to send action</button>
36+
<button name="Close" id="close">Press to close</button>
37+
<p id="message-response">No response</p>
38+
<script>
39+
document.getElementById("send-action").onclick = () => {
40+
window.parent.postMessage(
41+
{
42+
action: "read_events",
43+
room_id: document.getElementById("target-room-id").value,
44+
type: document.getElementById("event-type").value,
45+
state_key: JSON.parse(document.getElementById("state-key").value),
46+
},
47+
'*',
48+
);
49+
};
50+
document.getElementById("close").onclick = () => {
51+
window.parent.postMessage(
52+
{
53+
action: "close_scalar",
54+
},
55+
'*',
56+
);
57+
};
58+
// Listen for a postmessage response
59+
window.addEventListener("message", (event) => {
60+
document.getElementById("message-response").innerText = JSON.stringify(event.data);
61+
});
62+
</script>
63+
</body>
64+
</html>
65+
`;
66+
67+
function openIntegrationManager() {
68+
cy.get(".mx_RightPanel_roomSummaryButton").click();
69+
cy.get(".mx_RoomSummaryCard_appsGroup").within(() => {
70+
cy.contains("Add widgets, bridges & bots").click();
71+
});
72+
}
73+
74+
function sendActionFromIntegrationManager(
75+
integrationManagerUrl: string,
76+
targetRoomId: string,
77+
eventType: string,
78+
stateKey: string | boolean,
79+
) {
80+
cy.accessIframe(`iframe[src*="${integrationManagerUrl}"]`).within(() => {
81+
cy.get("#target-room-id").should("exist").type(targetRoomId);
82+
cy.get("#event-type").should("exist").type(eventType);
83+
cy.get("#state-key").should("exist").type(JSON.stringify(stateKey));
84+
cy.get("#send-action").should("exist").click();
85+
});
86+
}
87+
88+
describe("Integration Manager: Read Events", () => {
89+
let testUser: UserCredentials;
90+
let synapse: SynapseInstance;
91+
let integrationManagerUrl: string;
92+
93+
beforeEach(() => {
94+
cy.serveHtmlFile(INTEGRATION_MANAGER_HTML).then((url) => {
95+
integrationManagerUrl = url;
96+
});
97+
cy.startSynapse("default").then((data) => {
98+
synapse = data;
99+
100+
cy.initTestUser(synapse, USER_DISPLAY_NAME, () => {
101+
cy.window().then((win) => {
102+
win.localStorage.setItem("mx_scalar_token", INTEGRATION_MANAGER_TOKEN);
103+
win.localStorage.setItem(`mx_scalar_token_at_${integrationManagerUrl}`, INTEGRATION_MANAGER_TOKEN);
104+
});
105+
}).then((user) => {
106+
testUser = user;
107+
});
108+
109+
cy.setAccountData("m.widgets", {
110+
"m.integration_manager": {
111+
content: {
112+
type: "m.integration_manager",
113+
name: "Integration Manager",
114+
url: integrationManagerUrl,
115+
data: {
116+
api_url: integrationManagerUrl,
117+
},
118+
},
119+
id: "integration-manager",
120+
},
121+
}).as("integrationManager");
122+
123+
// Succeed when checking the token is valid
124+
cy.intercept(`${integrationManagerUrl}/account?scalar_token=${INTEGRATION_MANAGER_TOKEN}*`, (req) => {
125+
req.continue((res) => {
126+
return res.send(200, {
127+
user_id: testUser.userId,
128+
});
129+
});
130+
});
131+
132+
cy.createRoom({
133+
name: ROOM_NAME,
134+
}).as("roomId");
135+
});
136+
});
137+
138+
afterEach(() => {
139+
cy.stopSynapse(synapse);
140+
cy.stopWebServers();
141+
});
142+
143+
it("should read a state event by state key", () => {
144+
cy.all([cy.get<string>("@roomId"), cy.get<{}>("@integrationManager")]).then(([roomId]) => {
145+
cy.viewRoomByName(ROOM_NAME);
146+
147+
const eventType = "io.element.integrations.installations";
148+
const eventContent = {
149+
foo: "bar",
150+
};
151+
const stateKey = "state-key-123";
152+
153+
// Send a state event
154+
cy.getClient()
155+
.then(async (client) => {
156+
return await client.sendStateEvent(roomId, eventType, eventContent, stateKey);
157+
})
158+
.then((event) => {
159+
openIntegrationManager();
160+
161+
// Read state events
162+
sendActionFromIntegrationManager(integrationManagerUrl, roomId, eventType, stateKey);
163+
164+
// Check the response
165+
cy.accessIframe(`iframe[src*="${integrationManagerUrl}"]`).within(() => {
166+
cy.get("#message-response")
167+
.should("include.text", event.event_id)
168+
.should("include.text", `"content":${JSON.stringify(eventContent)}`);
169+
});
170+
});
171+
});
172+
});
173+
174+
it("should read a state event with empty state key", () => {
175+
cy.all([cy.get<string>("@roomId"), cy.get<{}>("@integrationManager")]).then(([roomId]) => {
176+
cy.viewRoomByName(ROOM_NAME);
177+
178+
const eventType = "io.element.integrations.installations";
179+
const eventContent = {
180+
foo: "bar",
181+
};
182+
const stateKey = "";
183+
184+
// Send a state event
185+
cy.getClient()
186+
.then(async (client) => {
187+
return await client.sendStateEvent(roomId, eventType, eventContent, stateKey);
188+
})
189+
.then((event) => {
190+
openIntegrationManager();
191+
192+
// Read state events
193+
sendActionFromIntegrationManager(integrationManagerUrl, roomId, eventType, stateKey);
194+
195+
// Check the response
196+
cy.accessIframe(`iframe[src*="${integrationManagerUrl}"]`).within(() => {
197+
cy.get("#message-response")
198+
.should("include.text", event.event_id)
199+
.should("include.text", `"content":${JSON.stringify(eventContent)}`);
200+
});
201+
});
202+
});
203+
});
204+
205+
it("should read state events with any state key", () => {
206+
cy.all([cy.get<string>("@roomId"), cy.get<{}>("@integrationManager")]).then(([roomId]) => {
207+
cy.viewRoomByName(ROOM_NAME);
208+
209+
const eventType = "io.element.integrations.installations";
210+
211+
const stateKey1 = "state-key-123";
212+
const eventContent1 = {
213+
foo1: "bar1",
214+
};
215+
const stateKey2 = "state-key-456";
216+
const eventContent2 = {
217+
foo2: "bar2",
218+
};
219+
const stateKey3 = "state-key-789";
220+
const eventContent3 = {
221+
foo3: "bar3",
222+
};
223+
224+
// Send state events
225+
cy.getClient()
226+
.then(async (client) => {
227+
return Promise.all([
228+
client.sendStateEvent(roomId, eventType, eventContent1, stateKey1),
229+
client.sendStateEvent(roomId, eventType, eventContent2, stateKey2),
230+
client.sendStateEvent(roomId, eventType, eventContent3, stateKey3),
231+
]);
232+
})
233+
.then((events) => {
234+
openIntegrationManager();
235+
236+
// Read state events
237+
sendActionFromIntegrationManager(
238+
integrationManagerUrl,
239+
roomId,
240+
eventType,
241+
true, // Any state key
242+
);
243+
244+
// Check the response
245+
cy.accessIframe(`iframe[src*="${integrationManagerUrl}"]`).within(() => {
246+
cy.get("#message-response")
247+
.should("include.text", events[0].event_id)
248+
.should("include.text", `"content":${JSON.stringify(eventContent1)}`)
249+
.should("include.text", events[1].event_id)
250+
.should("include.text", `"content":${JSON.stringify(eventContent2)}`)
251+
.should("include.text", events[2].event_id)
252+
.should("include.text", `"content":${JSON.stringify(eventContent3)}`);
253+
});
254+
});
255+
});
256+
});
257+
258+
it("should fail to read an event type which is not allowed", () => {
259+
cy.all([cy.get<string>("@roomId"), cy.get<{}>("@integrationManager")]).then(([roomId]) => {
260+
cy.viewRoomByName(ROOM_NAME);
261+
262+
const eventType = "com.example.event";
263+
const stateKey = "";
264+
265+
openIntegrationManager();
266+
267+
// Read state events
268+
sendActionFromIntegrationManager(integrationManagerUrl, roomId, eventType, stateKey);
269+
270+
// Check the response
271+
cy.accessIframe(`iframe[src*="${integrationManagerUrl}"]`).within(() => {
272+
cy.get("#message-response").should("include.text", "Failed to read events");
273+
});
274+
});
275+
});
276+
});

0 commit comments

Comments
 (0)