Skip to content

Commit 9360364

Browse files
Copilotd-gubert
andcommitted
Add UIKit room context test app and E2E tests
Co-authored-by: d-gubert <[email protected]> Agent-Logs-Url: https://github.com/RocketChat/Rocket.Chat/sessions/1d9fe17e-f376-436c-a62e-97a42942ac9e
1 parent 6e2a8da commit 9360364

File tree

3 files changed

+199
-0
lines changed

3 files changed

+199
-0
lines changed

apps/meteor/tests/data/apps/app-packages/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@ export const appImplementsIPreFileUpload = path.resolve(__dirname, './file-uploa
55
export const appAPIParameterTest = path.resolve(__dirname, './api-parameter-test_0.0.1.zip');
66

77
export const appCausingNestedRequests = path.resolve(__dirname, './nested-requests_0.0.1.zip');
8+
9+
export const appUiKitRoomTest = path.resolve(__dirname, './uikit-room-test_0.0.1.zip');
Binary file not shown.
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
import type { ILoggerStorageEntry } from '@rocket.chat/apps-engine/server/logging';
2+
import type { App } from '@rocket.chat/core-typings';
3+
import { expect } from 'chai';
4+
import { after, before, describe, it } from 'mocha';
5+
6+
import { getCredentials, request, credentials } from '../../data/api-data';
7+
import { appUiKitRoomTest } from '../../data/apps/app-packages';
8+
import { apps } from '../../data/apps/apps-data';
9+
import { cleanupApps, installLocalTestPackage } from '../../data/apps/helper';
10+
import { IS_EE } from '../../e2e/config/constants';
11+
12+
const roomId = 'GENERAL';
13+
14+
(IS_EE ? describe : describe.skip)('Apps - UIKit Room Context in Modal Interactions', () => {
15+
let app: App;
16+
17+
before((done) => getCredentials(done));
18+
19+
before(async () => {
20+
await cleanupApps();
21+
app = await installLocalTestPackage(appUiKitRoomTest);
22+
});
23+
24+
after(() => cleanupApps());
25+
26+
const sendUiKitInteraction = (type: string, payload: object) =>
27+
request
28+
.post(`/api/apps/ui.interaction/${app.id}`)
29+
.set(credentials)
30+
.send({
31+
type,
32+
...payload,
33+
});
34+
35+
const getAppLogs = () => request.get(apps(`/${app.id}/logs`)).set(credentials);
36+
37+
/**
38+
* Find a log entry by handler method name and first log argument.
39+
* Each app logger.debug call creates a log entry with args[0] as the label and args[1] as the value.
40+
*/
41+
const findLogEntry = (logs: ILoggerStorageEntry[], methodFragment: string, firstArg: string) =>
42+
logs.find(
43+
(log) =>
44+
(log.method as string).includes(methodFragment) &&
45+
log.entries.some((entry) => Array.isArray(entry.args) && entry.args[0] === firstArg),
46+
);
47+
48+
it('should include room data in executeBlockActionHandler when rid is sent', async () => {
49+
const viewId = `test-view-id-${Date.now()}`;
50+
51+
const interactionRes = await sendUiKitInteraction('blockAction', {
52+
actionId: 'test_button',
53+
triggerId: `test-trigger-${Date.now()}`,
54+
rid: roomId,
55+
container: {
56+
type: 'view',
57+
id: viewId,
58+
},
59+
payload: {
60+
blockId: 'test_block',
61+
value: 'test_value',
62+
},
63+
});
64+
65+
expect(interactionRes.status, 'blockAction interaction failed').to.equal(200);
66+
67+
const logsRes = await getAppLogs();
68+
69+
expect(logsRes.status, 'Fetching app logs failed').to.equal(200);
70+
expect(logsRes.body).to.have.a.property('success', true);
71+
expect(logsRes.body.logs).to.be.an('array').with.lengthOf.greaterThan(0);
72+
73+
const blockActionLog = findLogEntry(logsRes.body.logs, 'executeBlockActionHandler', 'block_action_room');
74+
75+
expect(blockActionLog, 'Block action handler log not found').to.exist;
76+
77+
const roomEntry = blockActionLog?.entries.find((entry) => Array.isArray(entry.args) && entry.args[0] === 'block_action_room');
78+
79+
expect(roomEntry, 'Room log entry not found in block action handler').to.exist;
80+
81+
// The second arg is data.room.id (the room id string) when room is present
82+
expect(roomEntry?.args[1], 'Room id should match the sent rid').to.equal(roomId);
83+
});
84+
85+
it('should include room data in executeViewSubmitHandler when rid is sent', async () => {
86+
const viewId = `test-view-id-${Date.now()}`;
87+
88+
const interactionRes = await sendUiKitInteraction('viewSubmit', {
89+
actionId: 'test_button',
90+
triggerId: `test-trigger-${Date.now()}`,
91+
rid: roomId,
92+
viewId,
93+
payload: {
94+
view: {
95+
id: viewId,
96+
type: 'modal',
97+
appId: app.id,
98+
title: { type: 'plain_text', text: 'Test Modal' },
99+
blocks: [],
100+
state: {},
101+
},
102+
},
103+
});
104+
105+
expect(interactionRes.status, 'viewSubmit interaction failed').to.equal(200);
106+
107+
const logsRes = await getAppLogs();
108+
109+
expect(logsRes.status, 'Fetching app logs failed').to.equal(200);
110+
expect(logsRes.body).to.have.a.property('success', true);
111+
112+
const viewSubmitLog = findLogEntry(logsRes.body.logs, 'executeViewSubmitHandler', 'view_submit_room');
113+
114+
expect(viewSubmitLog, 'View submit handler log not found').to.exist;
115+
116+
const roomEntry = viewSubmitLog?.entries.find((entry) => Array.isArray(entry.args) && entry.args[0] === 'view_submit_room');
117+
118+
expect(roomEntry, 'Room log entry not found in view submit handler').to.exist;
119+
120+
expect(roomEntry?.args[1], 'Room id should match the sent rid').to.equal(roomId);
121+
});
122+
123+
it('should include room data in executeViewClosedHandler when rid is sent', async () => {
124+
const viewId = `test-view-id-${Date.now()}`;
125+
126+
const interactionRes = await sendUiKitInteraction('viewClosed', {
127+
rid: roomId,
128+
payload: {
129+
viewId,
130+
view: {
131+
id: viewId,
132+
type: 'modal',
133+
appId: app.id,
134+
title: { type: 'plain_text', text: 'Test Modal' },
135+
blocks: [],
136+
state: {},
137+
},
138+
isCleared: false,
139+
},
140+
});
141+
142+
expect(interactionRes.status, 'viewClosed interaction failed').to.equal(200);
143+
144+
const logsRes = await getAppLogs();
145+
146+
expect(logsRes.status, 'Fetching app logs failed').to.equal(200);
147+
expect(logsRes.body).to.have.a.property('success', true);
148+
149+
const viewClosedLog = findLogEntry(logsRes.body.logs, 'executeViewClosedHandler', 'view_closed_room');
150+
151+
expect(viewClosedLog, 'View closed handler log not found').to.exist;
152+
153+
const roomEntry = viewClosedLog?.entries.find((entry) => Array.isArray(entry.args) && entry.args[0] === 'view_closed_room');
154+
155+
expect(roomEntry, 'Room log entry not found in view closed handler').to.exist;
156+
157+
expect(roomEntry?.args[1], 'Room id should match the sent rid').to.equal(roomId);
158+
});
159+
160+
it('should not include room data when rid is not sent', async () => {
161+
const viewId = `test-view-id-no-rid-${Date.now()}`;
162+
163+
const interactionRes = await sendUiKitInteraction('viewSubmit', {
164+
actionId: 'test_button',
165+
triggerId: `test-trigger-${Date.now()}`,
166+
viewId,
167+
payload: {
168+
view: {
169+
id: viewId,
170+
type: 'modal',
171+
appId: app.id,
172+
title: { type: 'plain_text', text: 'Test Modal Without Room' },
173+
blocks: [],
174+
state: {},
175+
},
176+
},
177+
});
178+
179+
expect(interactionRes.status, 'viewSubmit interaction without rid failed').to.equal(200);
180+
181+
const logsRes = await getAppLogs();
182+
183+
expect(logsRes.status, 'Fetching app logs failed').to.equal(200);
184+
expect(logsRes.body).to.have.a.property('success', true);
185+
186+
const viewSubmitLog = findLogEntry(logsRes.body.logs, 'executeViewSubmitHandler', 'view_submit_room');
187+
188+
expect(viewSubmitLog, 'View submit handler log not found').to.exist;
189+
190+
const roomEntry = viewSubmitLog?.entries.find((entry) => Array.isArray(entry.args) && entry.args[0] === 'view_submit_room');
191+
192+
expect(roomEntry, 'Room log entry not found').to.exist;
193+
194+
// When no rid is provided, the app logs 'no-room' as the fallback value
195+
expect(roomEntry?.args[1], 'Room data should not be present when no rid is provided').to.equal('no-room');
196+
});
197+
});

0 commit comments

Comments
 (0)