You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-08-09 10:22:46 +03:00
497 lines
17 KiB
TypeScript
497 lines
17 KiB
TypeScript
import * as utils from "../test-utils/test-utils";
|
|
import { IActionsObject, PushProcessor } from "../../src/pushprocessor";
|
|
import { EventType, IContent, MatrixClient, MatrixEvent } from "../../src";
|
|
|
|
describe("NotificationService", function () {
|
|
const testUserId = "@ali:matrix.org";
|
|
const testDisplayName = "Alice M";
|
|
const testRoomId = "!fl1bb13:localhost";
|
|
|
|
let testEvent: MatrixEvent;
|
|
|
|
let pushProcessor: PushProcessor;
|
|
|
|
// These would be better if individual rules were configured in the tests themselves.
|
|
const matrixClient = {
|
|
getRoom: function () {
|
|
return {
|
|
currentState: {
|
|
getMember: function () {
|
|
return {
|
|
name: testDisplayName,
|
|
};
|
|
},
|
|
getJoinedMemberCount: function () {
|
|
return 0;
|
|
},
|
|
members: {},
|
|
},
|
|
};
|
|
},
|
|
credentials: {
|
|
userId: testUserId,
|
|
},
|
|
pushRules: {
|
|
device: {},
|
|
global: {
|
|
content: [
|
|
{
|
|
actions: [
|
|
"notify",
|
|
{
|
|
set_tweak: "sound",
|
|
value: "default",
|
|
},
|
|
{
|
|
set_tweak: "highlight",
|
|
},
|
|
],
|
|
enabled: true,
|
|
pattern: "ali",
|
|
rule_id: ".m.rule.contains_user_name",
|
|
},
|
|
{
|
|
actions: [
|
|
"notify",
|
|
{
|
|
set_tweak: "sound",
|
|
value: "default",
|
|
},
|
|
{
|
|
set_tweak: "highlight",
|
|
},
|
|
],
|
|
enabled: true,
|
|
pattern: "coffee",
|
|
rule_id: "coffee",
|
|
},
|
|
{
|
|
actions: [
|
|
"notify",
|
|
{
|
|
set_tweak: "sound",
|
|
value: "default",
|
|
},
|
|
{
|
|
set_tweak: "highlight",
|
|
},
|
|
],
|
|
enabled: true,
|
|
pattern: "foo*bar",
|
|
rule_id: "foobar",
|
|
},
|
|
{
|
|
actions: [
|
|
"notify",
|
|
{
|
|
set_tweak: "sound",
|
|
value: "default",
|
|
},
|
|
{
|
|
set_tweak: "highlight",
|
|
},
|
|
],
|
|
enabled: true,
|
|
pattern: "p[io]ng",
|
|
rule_id: "pingpong",
|
|
},
|
|
{
|
|
actions: [
|
|
"notify",
|
|
{
|
|
set_tweak: "sound",
|
|
value: "default",
|
|
},
|
|
{
|
|
set_tweak: "highlight",
|
|
},
|
|
],
|
|
enabled: true,
|
|
pattern: "I ate [0-9] pies",
|
|
rule_id: "pies",
|
|
},
|
|
{
|
|
actions: [
|
|
"notify",
|
|
{
|
|
set_tweak: "sound",
|
|
value: "default",
|
|
},
|
|
{
|
|
set_tweak: "highlight",
|
|
},
|
|
],
|
|
enabled: true,
|
|
pattern: "b[!ai]ke",
|
|
rule_id: "bakebike",
|
|
},
|
|
],
|
|
override: [
|
|
{
|
|
actions: [
|
|
"notify",
|
|
{
|
|
set_tweak: "sound",
|
|
value: "default",
|
|
},
|
|
{
|
|
set_tweak: "highlight",
|
|
},
|
|
],
|
|
conditions: [
|
|
{
|
|
kind: "contains_display_name",
|
|
},
|
|
],
|
|
enabled: true,
|
|
rule_id: ".m.rule.contains_display_name",
|
|
},
|
|
{
|
|
actions: [
|
|
"notify",
|
|
{
|
|
set_tweak: "sound",
|
|
value: "default",
|
|
},
|
|
],
|
|
conditions: [
|
|
{
|
|
is: "2",
|
|
kind: "room_member_count",
|
|
},
|
|
],
|
|
enabled: true,
|
|
rule_id: ".m.rule.room_one_to_one",
|
|
},
|
|
{
|
|
rule_id: ".org.matrix.msc3914.rule.room.call",
|
|
default: true,
|
|
enabled: true,
|
|
conditions: [
|
|
{
|
|
kind: "event_match",
|
|
key: "type",
|
|
pattern: "org.matrix.msc3401.call",
|
|
},
|
|
{
|
|
kind: "call_started",
|
|
},
|
|
],
|
|
actions: ["notify", { set_tweak: "sound", value: "default" }],
|
|
},
|
|
],
|
|
room: [],
|
|
sender: [],
|
|
underride: [
|
|
{
|
|
actions: ["dont-notify"],
|
|
conditions: [
|
|
{
|
|
key: "content.msgtype",
|
|
kind: "event_match",
|
|
pattern: "m.notice",
|
|
},
|
|
],
|
|
enabled: true,
|
|
rule_id: ".m.rule.suppress_notices",
|
|
},
|
|
{
|
|
actions: [
|
|
"notify",
|
|
{
|
|
set_tweak: "highlight",
|
|
value: false,
|
|
},
|
|
],
|
|
conditions: [],
|
|
enabled: true,
|
|
rule_id: ".m.rule.fallback",
|
|
},
|
|
],
|
|
},
|
|
},
|
|
} as unknown as MatrixClient;
|
|
|
|
beforeEach(function () {
|
|
testEvent = utils.mkEvent({
|
|
type: "m.room.message",
|
|
room: testRoomId,
|
|
user: "@alfred:localhost",
|
|
event: true,
|
|
content: {
|
|
body: "",
|
|
msgtype: "m.text",
|
|
},
|
|
});
|
|
matrixClient.pushRules = PushProcessor.rewriteDefaultRules(matrixClient.pushRules!);
|
|
pushProcessor = new PushProcessor(matrixClient);
|
|
});
|
|
|
|
// User IDs
|
|
|
|
it("should bing on a user ID.", function () {
|
|
testEvent.event.content!.body = "Hello @ali:matrix.org, how are you?";
|
|
const actions = pushProcessor.actionsForEvent(testEvent);
|
|
expect(actions.tweaks.highlight).toEqual(true);
|
|
});
|
|
|
|
it("should bing on a partial user ID with an @.", function () {
|
|
testEvent.event.content!.body = "Hello @ali, how are you?";
|
|
const actions = pushProcessor.actionsForEvent(testEvent);
|
|
expect(actions.tweaks.highlight).toEqual(true);
|
|
});
|
|
|
|
it("should bing on a partial user ID without @.", function () {
|
|
testEvent.event.content!.body = "Hello ali, how are you?";
|
|
const actions = pushProcessor.actionsForEvent(testEvent);
|
|
expect(actions.tweaks.highlight).toEqual(true);
|
|
});
|
|
|
|
it("should bing on a case-insensitive user ID.", function () {
|
|
testEvent.event.content!.body = "Hello @AlI:matrix.org, how are you?";
|
|
const actions = pushProcessor.actionsForEvent(testEvent);
|
|
expect(actions.tweaks.highlight).toEqual(true);
|
|
});
|
|
|
|
// Display names
|
|
|
|
it("should bing on a display name.", function () {
|
|
testEvent.event.content!.body = "Hello Alice M, how are you?";
|
|
const actions = pushProcessor.actionsForEvent(testEvent);
|
|
expect(actions.tweaks.highlight).toEqual(true);
|
|
});
|
|
|
|
it("should bing on a case-insensitive display name.", function () {
|
|
testEvent.event.content!.body = "Hello ALICE M, how are you?";
|
|
const actions = pushProcessor.actionsForEvent(testEvent);
|
|
expect(actions.tweaks.highlight).toEqual(true);
|
|
});
|
|
|
|
// Bing words
|
|
|
|
it("should bing on a bing word.", function () {
|
|
testEvent.event.content!.body = "I really like coffee";
|
|
const actions = pushProcessor.actionsForEvent(testEvent);
|
|
expect(actions.tweaks.highlight).toEqual(true);
|
|
});
|
|
|
|
it("should bing on case-insensitive bing words.", function () {
|
|
testEvent.event.content!.body = "Coffee is great";
|
|
const actions = pushProcessor.actionsForEvent(testEvent);
|
|
expect(actions.tweaks.highlight).toEqual(true);
|
|
});
|
|
|
|
it("should bing on wildcard (.*) bing words.", function () {
|
|
testEvent.event.content!.body = "It was foomahbar I think.";
|
|
const actions = pushProcessor.actionsForEvent(testEvent);
|
|
expect(actions.tweaks.highlight).toEqual(true);
|
|
});
|
|
|
|
it("should bing on character group ([abc]) bing words.", function () {
|
|
testEvent.event.content!.body = "Ping!";
|
|
let actions = pushProcessor.actionsForEvent(testEvent);
|
|
expect(actions.tweaks.highlight).toEqual(true);
|
|
testEvent.event.content!.body = "Pong!";
|
|
actions = pushProcessor.actionsForEvent(testEvent);
|
|
expect(actions.tweaks.highlight).toEqual(true);
|
|
});
|
|
|
|
it("should bing on character range ([a-z]) bing words.", function () {
|
|
testEvent.event.content!.body = "I ate 6 pies";
|
|
const actions = pushProcessor.actionsForEvent(testEvent);
|
|
expect(actions.tweaks.highlight).toEqual(true);
|
|
});
|
|
|
|
it("should bing on character negation ([!a]) bing words.", function () {
|
|
testEvent.event.content!.body = "boke";
|
|
let actions = pushProcessor.actionsForEvent(testEvent);
|
|
expect(actions.tweaks.highlight).toEqual(true);
|
|
testEvent.event.content!.body = "bake";
|
|
actions = pushProcessor.actionsForEvent(testEvent);
|
|
expect(actions.tweaks.highlight).toEqual(false);
|
|
});
|
|
|
|
it("should not bing on room server ACL changes", function () {
|
|
testEvent = utils.mkEvent({
|
|
type: EventType.RoomServerAcl,
|
|
room: testRoomId,
|
|
user: "@alfred:localhost",
|
|
skey: "",
|
|
event: true,
|
|
content: {},
|
|
});
|
|
|
|
const actions = pushProcessor.actionsForEvent(testEvent);
|
|
expect(actions.tweaks.highlight).toBeFalsy();
|
|
expect(actions.tweaks.sound).toBeFalsy();
|
|
expect(actions.notify).toBeFalsy();
|
|
});
|
|
|
|
// invalid
|
|
|
|
it("should gracefully handle bad input.", function () {
|
|
testEvent.event.content!.body = { foo: "bar" };
|
|
const actions = pushProcessor.actionsForEvent(testEvent);
|
|
expect(actions.tweaks.highlight).toEqual(false);
|
|
});
|
|
|
|
it("a rule with no conditions matches every event.", function () {
|
|
expect(
|
|
pushProcessor.ruleMatchesEvent(
|
|
{
|
|
rule_id: "rule1",
|
|
actions: [],
|
|
conditions: [],
|
|
default: false,
|
|
enabled: true,
|
|
},
|
|
testEvent,
|
|
),
|
|
).toBe(true);
|
|
expect(
|
|
pushProcessor.ruleMatchesEvent(
|
|
{
|
|
rule_id: "rule1",
|
|
actions: [],
|
|
default: false,
|
|
enabled: true,
|
|
},
|
|
testEvent,
|
|
),
|
|
).toBe(true);
|
|
});
|
|
|
|
describe("group call started push rule", () => {
|
|
beforeEach(() => {
|
|
matrixClient.pushRules!.global!.underride!.find((r) => r.rule_id === ".m.rule.fallback")!.enabled = false;
|
|
});
|
|
|
|
const getActionsForEvent = (prevContent: IContent, content: IContent): IActionsObject => {
|
|
testEvent = utils.mkEvent({
|
|
type: "org.matrix.msc3401.call",
|
|
room: testRoomId,
|
|
user: "@alice:foo",
|
|
skey: "state_key",
|
|
event: true,
|
|
content: content,
|
|
prev_content: prevContent,
|
|
});
|
|
|
|
return pushProcessor.actionsForEvent(testEvent);
|
|
};
|
|
|
|
const assertDoesNotify = (actions: IActionsObject): void => {
|
|
expect(actions?.notify).toBeTruthy();
|
|
expect(actions?.tweaks?.sound).toBeTruthy();
|
|
expect(actions?.tweaks?.highlight).toBeFalsy();
|
|
};
|
|
|
|
const assertDoesNotNotify = (actions: IActionsObject): void => {
|
|
expect(actions?.notify).toBeFalsy();
|
|
expect(actions?.tweaks?.sound).toBeFalsy();
|
|
expect(actions?.tweaks?.highlight).toBeFalsy();
|
|
};
|
|
|
|
it.each(["m.ring", "m.prompt"])(
|
|
"should notify when new group call event appears with %s intent",
|
|
(intent: string) => {
|
|
assertDoesNotify(
|
|
getActionsForEvent(
|
|
{},
|
|
{
|
|
"m.intent": intent,
|
|
"m.type": "m.voice",
|
|
"m.name": "Call",
|
|
},
|
|
),
|
|
);
|
|
},
|
|
);
|
|
|
|
it("should notify when a call is un-terminated", () => {
|
|
assertDoesNotify(
|
|
getActionsForEvent(
|
|
{
|
|
"m.intent": "m.ring",
|
|
"m.type": "m.voice",
|
|
"m.name": "Call",
|
|
"m.terminated": "All users left",
|
|
},
|
|
{
|
|
"m.intent": "m.ring",
|
|
"m.type": "m.voice",
|
|
"m.name": "Call",
|
|
},
|
|
),
|
|
);
|
|
});
|
|
|
|
it("should not notify when call is terminated", () => {
|
|
assertDoesNotNotify(
|
|
getActionsForEvent(
|
|
{
|
|
"m.intent": "m.ring",
|
|
"m.type": "m.voice",
|
|
"m.name": "Call",
|
|
},
|
|
{
|
|
"m.intent": "m.ring",
|
|
"m.type": "m.voice",
|
|
"m.name": "Call",
|
|
"m.terminated": "All users left",
|
|
},
|
|
),
|
|
);
|
|
});
|
|
|
|
it("should ignore with m.room intent", () => {
|
|
assertDoesNotNotify(
|
|
getActionsForEvent(
|
|
{},
|
|
{
|
|
"m.intent": "m.room",
|
|
"m.type": "m.voice",
|
|
"m.name": "Call",
|
|
},
|
|
),
|
|
);
|
|
});
|
|
|
|
describe("ignoring non-relevant state changes", () => {
|
|
it("should ignore intent changes", () => {
|
|
assertDoesNotNotify(
|
|
getActionsForEvent(
|
|
{
|
|
"m.intent": "m.ring",
|
|
"m.type": "m.voice",
|
|
"m.name": "Call",
|
|
},
|
|
{
|
|
"m.intent": "m.ring",
|
|
"m.type": "m.video",
|
|
"m.name": "Call",
|
|
},
|
|
),
|
|
);
|
|
});
|
|
|
|
it("should ignore name changes", () => {
|
|
assertDoesNotNotify(
|
|
getActionsForEvent(
|
|
{
|
|
"m.intent": "m.ring",
|
|
"m.type": "m.voice",
|
|
"m.name": "Call",
|
|
},
|
|
{
|
|
"m.intent": "m.ring",
|
|
"m.type": "m.voice",
|
|
"m.name": "New call",
|
|
},
|
|
),
|
|
);
|
|
});
|
|
});
|
|
});
|
|
});
|