mirror of
https://github.com/outline/outline.git
synced 2026-06-13 11:25:03 +03:00
091346dfe8
* wip * Remove obsolete snapshots * simplify * chore(test): Convert mocks to TypeScript and tighten fetch mock types Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Remove unneccessary patches * Migrate to msw instead of custom fetch mock * Address PR review comments - Split chained vi.useFakeTimers().setSystemTime() into separate calls. - Switch test setup to dynamic imports so EventEmitter.defaultMaxListeners assignment runs before module init (static imports were hoisted above it). - Drop redundant NODE_ENV guard in monkeyPatchSequelizeErrorsForJest; its sole caller already gates on env.isTest. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
314 lines
7.7 KiB
TypeScript
314 lines
7.7 KiB
TypeScript
import { NotificationEventType } from "@shared/types";
|
|
import { Notification } from "@server/models";
|
|
import {
|
|
buildUser,
|
|
buildDocument,
|
|
buildGroup,
|
|
buildGroupUser,
|
|
buildComment,
|
|
} from "@server/test/factories";
|
|
import GroupMentionedInCommentNotificationsTask from "./GroupMentionedInCommentNotificationsTask";
|
|
|
|
const ip = "127.0.0.1";
|
|
|
|
beforeEach(async () => {
|
|
vi.resetAllMocks();
|
|
});
|
|
|
|
describe("GroupMentionedInCommentNotificationsTask", () => {
|
|
it("should send notifications to all group members with access", async () => {
|
|
const spy = vi.spyOn(Notification, "create");
|
|
const actor = await buildUser();
|
|
const document = await buildDocument({
|
|
teamId: actor.teamId,
|
|
});
|
|
const comment = await buildComment({
|
|
userId: actor.id,
|
|
documentId: document.id,
|
|
});
|
|
|
|
const group = await buildGroup({
|
|
teamId: actor.teamId,
|
|
});
|
|
|
|
const member1 = await buildUser({ teamId: actor.teamId });
|
|
const member2 = await buildUser({ teamId: actor.teamId });
|
|
|
|
await buildGroupUser({
|
|
groupId: group.id,
|
|
userId: member1.id,
|
|
});
|
|
await buildGroupUser({
|
|
groupId: group.id,
|
|
userId: member2.id,
|
|
});
|
|
|
|
member1.setNotificationEventType(
|
|
NotificationEventType.GroupMentionedInComment
|
|
);
|
|
await member1.save();
|
|
|
|
member2.setNotificationEventType(
|
|
NotificationEventType.GroupMentionedInComment
|
|
);
|
|
await member2.save();
|
|
|
|
const task = new GroupMentionedInCommentNotificationsTask();
|
|
await task.perform({
|
|
name: "comments.create",
|
|
modelId: comment.id,
|
|
documentId: document.id,
|
|
teamId: actor.teamId,
|
|
actorId: actor.id,
|
|
ip,
|
|
data: {
|
|
groupId: group.id,
|
|
actorId: actor.id,
|
|
},
|
|
});
|
|
|
|
expect(spy).toHaveBeenCalledTimes(2);
|
|
expect(spy).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
event: NotificationEventType.GroupMentionedInComment,
|
|
groupId: group.id,
|
|
userId: member1.id,
|
|
actorId: actor.id,
|
|
documentId: document.id,
|
|
commentId: comment.id,
|
|
})
|
|
);
|
|
expect(spy).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
event: NotificationEventType.GroupMentionedInComment,
|
|
groupId: group.id,
|
|
userId: member2.id,
|
|
actorId: actor.id,
|
|
documentId: document.id,
|
|
commentId: comment.id,
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should not send notification to actor", async () => {
|
|
const spy = vi.spyOn(Notification, "create");
|
|
const actor = await buildUser();
|
|
const document = await buildDocument({
|
|
teamId: actor.teamId,
|
|
});
|
|
const comment = await buildComment({
|
|
userId: actor.id,
|
|
documentId: document.id,
|
|
});
|
|
|
|
const group = await buildGroup({
|
|
teamId: actor.teamId,
|
|
});
|
|
|
|
await buildGroupUser({
|
|
groupId: group.id,
|
|
userId: actor.id,
|
|
});
|
|
|
|
actor.setNotificationEventType(
|
|
NotificationEventType.GroupMentionedInComment
|
|
);
|
|
await actor.save();
|
|
|
|
const task = new GroupMentionedInCommentNotificationsTask();
|
|
await task.perform({
|
|
name: "comments.create",
|
|
modelId: comment.id,
|
|
documentId: document.id,
|
|
teamId: actor.teamId,
|
|
actorId: actor.id,
|
|
ip,
|
|
data: {
|
|
groupId: group.id,
|
|
actorId: actor.id,
|
|
},
|
|
});
|
|
|
|
expect(spy).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("should not send notification if group has mentions disabled", async () => {
|
|
const spy = vi.spyOn(Notification, "create");
|
|
const actor = await buildUser();
|
|
const document = await buildDocument({
|
|
teamId: actor.teamId,
|
|
});
|
|
const comment = await buildComment({
|
|
userId: actor.id,
|
|
documentId: document.id,
|
|
});
|
|
|
|
const group = await buildGroup({
|
|
teamId: actor.teamId,
|
|
disableMentions: true,
|
|
});
|
|
|
|
const member = await buildUser({ teamId: actor.teamId });
|
|
await buildGroupUser({
|
|
groupId: group.id,
|
|
userId: member.id,
|
|
});
|
|
|
|
member.setNotificationEventType(
|
|
NotificationEventType.GroupMentionedInComment
|
|
);
|
|
await member.save();
|
|
|
|
const task = new GroupMentionedInCommentNotificationsTask();
|
|
await task.perform({
|
|
name: "comments.create",
|
|
modelId: comment.id,
|
|
documentId: document.id,
|
|
teamId: actor.teamId,
|
|
actorId: actor.id,
|
|
ip,
|
|
data: {
|
|
groupId: group.id,
|
|
actorId: actor.id,
|
|
},
|
|
});
|
|
|
|
expect(spy).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("should not send notification to users without subscription", async () => {
|
|
const spy = vi.spyOn(Notification, "create");
|
|
const actor = await buildUser();
|
|
const document = await buildDocument({
|
|
teamId: actor.teamId,
|
|
});
|
|
const comment = await buildComment({
|
|
userId: actor.id,
|
|
documentId: document.id,
|
|
});
|
|
|
|
const group = await buildGroup({
|
|
teamId: actor.teamId,
|
|
});
|
|
|
|
const member = await buildUser({ teamId: actor.teamId });
|
|
await buildGroupUser({
|
|
groupId: group.id,
|
|
userId: member.id,
|
|
});
|
|
|
|
// member doesn't have notification subscription enabled
|
|
member.setNotificationEventType(
|
|
NotificationEventType.GroupMentionedInComment,
|
|
false
|
|
);
|
|
await member.save();
|
|
|
|
const task = new GroupMentionedInCommentNotificationsTask();
|
|
await task.perform({
|
|
name: "comments.create",
|
|
modelId: comment.id,
|
|
documentId: document.id,
|
|
teamId: actor.teamId,
|
|
actorId: actor.id,
|
|
ip,
|
|
data: {
|
|
groupId: group.id,
|
|
actorId: actor.id,
|
|
},
|
|
});
|
|
|
|
expect(spy).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("should handle large groups with batching", async () => {
|
|
const spy = vi.spyOn(Notification, "create");
|
|
const actor = await buildUser();
|
|
const document = await buildDocument({
|
|
teamId: actor.teamId,
|
|
});
|
|
const comment = await buildComment({
|
|
userId: actor.id,
|
|
documentId: document.id,
|
|
});
|
|
|
|
const group = await buildGroup({
|
|
teamId: actor.teamId,
|
|
});
|
|
|
|
// Create 25 members to test batching (batch size is 10)
|
|
const members = [];
|
|
for (let i = 0; i < 25; i++) {
|
|
const member = await buildUser({ teamId: actor.teamId });
|
|
await buildGroupUser({
|
|
groupId: group.id,
|
|
userId: member.id,
|
|
});
|
|
member.setNotificationEventType(
|
|
NotificationEventType.GroupMentionedInComment
|
|
);
|
|
await member.save();
|
|
members.push(member);
|
|
}
|
|
|
|
const task = new GroupMentionedInCommentNotificationsTask();
|
|
await task.perform({
|
|
name: "comments.create",
|
|
modelId: comment.id,
|
|
documentId: document.id,
|
|
teamId: actor.teamId,
|
|
actorId: actor.id,
|
|
ip,
|
|
data: {
|
|
groupId: group.id,
|
|
actorId: actor.id,
|
|
},
|
|
});
|
|
|
|
expect(spy).toHaveBeenCalledTimes(25);
|
|
});
|
|
|
|
it("should not send notification if document does not exist", async () => {
|
|
const spy = vi.spyOn(Notification, "create");
|
|
const actor = await buildUser();
|
|
const document = await buildDocument({
|
|
teamId: actor.teamId,
|
|
});
|
|
const comment = await buildComment({
|
|
userId: actor.id,
|
|
documentId: document.id,
|
|
});
|
|
|
|
const group = await buildGroup({
|
|
teamId: actor.teamId,
|
|
});
|
|
|
|
const member = await buildUser({ teamId: actor.teamId });
|
|
await buildGroupUser({
|
|
groupId: group.id,
|
|
userId: member.id,
|
|
});
|
|
|
|
member.setNotificationEventType(
|
|
NotificationEventType.GroupMentionedInComment
|
|
);
|
|
await member.save();
|
|
|
|
const task = new GroupMentionedInCommentNotificationsTask();
|
|
await task.perform({
|
|
name: "comments.create",
|
|
modelId: comment.id,
|
|
documentId: "non-existent-id",
|
|
teamId: actor.teamId,
|
|
actorId: actor.id,
|
|
ip,
|
|
data: {
|
|
groupId: group.id,
|
|
actorId: actor.id,
|
|
},
|
|
});
|
|
|
|
expect(spy).not.toHaveBeenCalled();
|
|
});
|
|
});
|