Files
cinny/src/app/features/room/widgets/useRoomWidgets.test.ts
T
jaredandClaude Opus 5 32e5fec6f3 fix(widgets): room widgets render again (bypass broken isValidUrl)
matrix-widget-api 1.17.0's WidgetParser rejects every URL (it compares
URL.protocol "https:" to "https"), so the widgets panel was always empty.
Build Widget objects from the raw state events with a correct scheme
check plus the existing origin check. Unit-tested against a real state
event.

Fixes #15

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
2026-09-12 19:46:06 -04:00

73 lines
2.2 KiB
TypeScript

import { test } from 'node:test';
import assert from 'node:assert/strict';
import type { MatrixEvent } from 'matrix-js-sdk';
import { widgetsFromStateEvents } from './useRoomWidgets';
const APP = 'https://chat.lotusguild.org';
// Minimal fake MatrixEvent, just enough of the surface widgetsFromStateEvents reads.
const fakeEvent = (stateKey: string, sender: string, content: Record<string, unknown>) =>
({
getStateKey: () => stateKey,
getSender: () => sender,
getContent: () => content,
}) as unknown as MatrixEvent;
test('returns a Widget for a valid im.vector.modular.widgets state event', () => {
// Regression test for matrix-widget-api 1.17.0's broken isValidUrl, which
// compares URL.protocol ("https:") to "https" and rejects every URL,
// making WidgetParser.parseWidgetsFromRoomState always return [].
const events = new Map([
[
'w1',
fakeEvent('w1', '@a:example.org', {
id: 'w1',
type: 'custom',
url: 'https://example.com/widget',
name: 'My Widget',
creatorUserId: '@a:example.org',
}),
],
]);
const widgets = widgetsFromStateEvents(events, APP);
assert.equal(widgets.length, 1);
assert.equal(widgets[0].id, 'w1');
assert.equal(widgets[0].templateUrl, 'https://example.com/widget');
assert.equal(widgets[0].creatorUserId, '@a:example.org');
assert.equal(widgets[0].name, 'My Widget');
});
test('skips removed widgets (empty content)', () => {
const events = new Map([['w1', fakeEvent('w1', '@a:example.org', {})]]);
assert.deepEqual(widgetsFromStateEvents(events, APP), []);
});
test('skips non-https and same-origin urls', () => {
const events = new Map([
[
'w1',
fakeEvent('w1', '@a:example.org', {
id: 'w1',
type: 'custom',
url: 'http://example.com/widget',
creatorUserId: '@a:example.org',
}),
],
[
'w2',
fakeEvent('w2', '@a:example.org', {
id: 'w2',
type: 'custom',
url: `${APP}/evil`,
creatorUserId: '@a:example.org',
}),
],
]);
assert.deepEqual(widgetsFromStateEvents(events, APP), []);
});
test('undefined state map yields no widgets', () => {
assert.deepEqual(widgetsFromStateEvents(undefined, APP), []);
});