Consolidate vitest CI & coverage (#33808)

* Consolidate modules vitest coverage

* Use vite-common as base for modules vitest config

* Make knip happier

* Fix coverage paths

* Place modules unit tests alongside src

* Switch to defineProject for better type safety

* Consolidate vitest CI & coverage

Kills off vite-common

* Update comment

* Update lockfile

* Fix shared-components vitest config

* Soften eslint config for tests in modules

* Run eslint on modules/playwright dir too

* Make tsc happy
This commit is contained in:
Michael Telatynski
2026-06-10 16:00:34 +00:00
committed by GitHub
parent 042ded86c7
commit e9a89d9872
34 changed files with 252 additions and 301 deletions
@@ -0,0 +1,142 @@
/*
Copyright 2026 Element Creations Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import { describe, expect, it } from "vitest";
import WidgetLifecycleModule, { type WidgetLifecycleApiAdapter } from "./WidgetLifecycleModule";
import type {
CapabilitiesApprover,
IdentityApprover,
PreloadApprover,
WidgetDescriptor,
Api,
} from "@element-hq/element-web-module-api";
const createApi = (config: unknown = {}) => {
const handlers: {
preload?: PreloadApprover;
identity?: IdentityApprover;
capabilities?: CapabilitiesApprover;
} = {};
const widgetLifecycle: WidgetLifecycleApiAdapter = {
registerPreloadApprover: (approver) => {
handlers.preload = approver;
},
registerIdentityApprover: (approver) => {
handlers.identity = approver;
},
registerCapabilitiesApprover: (approver) => {
handlers.capabilities = approver;
},
};
return {
api: {
config: {
get: () => config,
},
widgetLifecycle,
} as Api,
handlers,
};
};
const widget: WidgetDescriptor = {
id: "widget-id",
templateUrl: "https://example.com/",
creatorUserId: "@user-id",
type: "com.example.custom",
origin: "example.com",
};
describe("WidgetLifecycleModule", () => {
it("approves preload when configured", async () => {
const { api, handlers } = createApi({
widget_permissions: {
"https://example.com/": { preload_approved: true },
},
});
const module = new WidgetLifecycleModule(api);
await module.load();
expect(await handlers.preload?.(widget)).toBe(true);
});
it("approves identity when configured", async () => {
const { api, handlers } = createApi({
widget_permissions: {
"https://example.com/": { identity_approved: true },
},
});
const module = new WidgetLifecycleModule(api);
await module.load();
expect(await handlers.identity?.(widget)).toBe(true);
});
it("approves configured capabilities", async () => {
const { api, handlers } = createApi({
widget_permissions: {
"https://example.com/": {
capabilities_approved: ["org.matrix.msc2931.navigate"],
},
},
});
const module = new WidgetLifecycleModule(api);
await module.load();
const approved = await handlers.capabilities?.(
widget,
new Set(["org.matrix.msc2931.navigate", "org.matrix.msc2762.timeline:*"]),
);
expect(approved).toEqual(new Set(["org.matrix.msc2931.navigate"]));
});
it("returns no approvals when not configured", async () => {
const { api, handlers } = createApi({});
const module = new WidgetLifecycleModule(api);
await module.load();
expect(await handlers.preload?.(widget)).toBe(false);
expect(await handlers.identity?.(widget)).toBe(false);
expect(await handlers.capabilities?.(widget, new Set(["org.matrix.msc2931.navigate"]))).toBeUndefined();
});
it("returns no approvals when config is missing", async () => {
const { api, handlers } = createApi(undefined);
const module = new WidgetLifecycleModule(api);
await module.load();
expect(await handlers.preload?.(widget)).toBe(false);
expect(await handlers.identity?.(widget)).toBe(false);
expect(await handlers.capabilities?.(widget, new Set(["org.matrix.msc2931.navigate"]))).toBeUndefined();
});
it("fails closed on invalid config", async () => {
const { api, handlers } = createApi({
widget_permissions: {
"https://example.com/": {
preload_approved: null,
},
},
});
const module = new WidgetLifecycleModule(api);
await module.load();
expect(await handlers.preload?.(widget)).toBe(false);
expect(await handlers.identity?.(widget)).toBe(false);
expect(await handlers.capabilities?.(widget, new Set(["org.matrix.msc2931.navigate"]))).toBeUndefined();
});
});
@@ -0,0 +1,88 @@
/*
Copyright 2026 Element Creations Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import { describe, expect, it } from "vitest";
import { parseWidgetLifecycleConfig } from "./config";
describe("parseWidgetLifecycleConfig", () => {
it("accepts missing configuration", () => {
expect(parseWidgetLifecycleConfig(undefined)).toEqual({});
});
it("accepts empty configuration", () => {
expect(parseWidgetLifecycleConfig({})).toEqual({});
});
it("accepts valid configuration", () => {
expect(
parseWidgetLifecycleConfig({
widget_permissions: {
"https://localhost": {
preload_approved: true,
identity_approved: false,
capabilities_approved: [],
},
},
}),
).toEqual({
"https://localhost": {
preload_approved: true,
identity_approved: false,
capabilities_approved: [],
},
});
});
it("accepts additional properties", () => {
expect(
parseWidgetLifecycleConfig({
widget_permissions: {
"https://localhost": {
preload_approved: true,
identity_approved: false,
capabilities_approved: ["capability"],
additional: "tmp",
},
},
}),
).toEqual({
"https://localhost": {
preload_approved: true,
identity_approved: false,
capabilities_approved: ["capability"],
additional: "tmp",
},
});
});
it.each([
{ preload_approved: null },
{ preload_approved: 123 },
{ identity_approved: null },
{ identity_approved: 123 },
{ capabilities_approved: null },
{ capabilities_approved: 123 },
{ capabilities_approved: [undefined] },
{ capabilities_approved: [null] },
{ capabilities_approved: [123] },
{ capabilities_approved: [""] },
])("rejects invalid widget configuration %j", (patch) => {
expect(() =>
parseWidgetLifecycleConfig({
widget_permissions: {
"https://localhost": {
preload_approved: true,
identity_approved: false,
capabilities_approved: ["capability"],
...patch,
},
},
}),
).toThrow();
});
});
@@ -0,0 +1,76 @@
/*
Copyright 2026 Element Creations Ltd.
Copyright 2023 Nordeck IT + Consulting GmbH
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import { describe, expect, it } from "vitest";
import { constructWidgetPermissions, sortLongestMatchLast } from "./constructWidgetPermissions";
describe("constructWidgetPermissions", () => {
it("finds exact match", () => {
expect(constructWidgetPermissions({ "https://a.com/": { preload_approved: true } }, "https://a.com/")).toEqual({
preload_approved: true,
});
});
it("finds prefix match", () => {
expect(
constructWidgetPermissions({ "https://a.com/*": { preload_approved: true } }, "https://a.com/some"),
).toEqual({ preload_approved: true });
});
it("merges multiple permissions", () => {
expect(
constructWidgetPermissions(
{
"https://b.com/path": {
preload_approved: false,
capabilities_approved: ["org.matrix.msc2762.timeline:*"],
},
"https://b.com/*": {
preload_approved: true,
identity_approved: true,
capabilities_approved: ["org.matrix.msc2931.navigate"],
},
},
"https://b.com/path",
),
).toEqual({
preload_approved: false,
identity_approved: true,
capabilities_approved: ["org.matrix.msc2762.timeline:*"],
});
});
it("skips unknown url", () => {
expect(constructWidgetPermissions({ "https://a.com/": { preload_approved: true } }, "https://a.com/x")).toEqual(
{},
);
});
});
describe("sortLongestMatchLast", () => {
it("sorts longest match last", () => {
expect(
[
"org.matrix.msc2762.receive.state_event:*",
"org.matrix.msc2762.receive.*",
"org.matrix.msc2762.receive.state_event:m.custom*",
"org.matrix.msc2762.receive.state_event:m.custom#state_key",
"org.matrix.msc2762.receive.state_event:m.custom#*",
"*",
].sort(sortLongestMatchLast),
).toEqual([
"*",
"org.matrix.msc2762.receive.*",
"org.matrix.msc2762.receive.state_event:*",
"org.matrix.msc2762.receive.state_event:m.custom*",
"org.matrix.msc2762.receive.state_event:m.custom#*",
"org.matrix.msc2762.receive.state_event:m.custom#state_key",
]);
});
});
@@ -0,0 +1,35 @@
/*
Copyright 2026 Element Creations Ltd.
Copyright 2023 Nordeck IT + Consulting GmbH
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import { describe, expect, it } from "vitest";
import { matchPattern } from "./matchPattern";
describe("matchPattern", () => {
it.each([
"*",
"org.matrix.msc2762.receive.*",
"org.matrix.msc2762.receive.state_event:*",
"org.matrix.msc2762.receive.state_event:m.custom*",
"org.matrix.msc2762.receive.state_event:m.custom#*",
"org.matrix.msc2762.receive.state_event:m.custom#state_key",
"org.matrix.msc2762.receive.state_event:m.custom#state_key*",
])("matches %s", (pattern) => {
expect(matchPattern("org.matrix.msc2762.receive.state_event:m.custom#state_key", pattern)).toBe(true);
});
it.each([
"org.matrix.msc2762.receive.state_event:",
"org.matrix.msc2762.receive.state_event:m.custom",
"org.matrix.msc2762.receive.state_event:m.custom#other_key",
"org.matrix.msc2762.receive.*:m.custom#state_key",
"org.matrix.msc2762.receive.room_event:m.custom",
])("does not match %s", (pattern) => {
expect(matchPattern("org.matrix.msc2762.receive.state_event:m.custom#state_key", pattern)).toBe(false);
});
});