mirror of
https://github.com/outline/outline.git
synced 2026-06-13 03:14:59 +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>
199 lines
5.3 KiB
TypeScript
199 lines
5.3 KiB
TypeScript
import { subDays } from "date-fns";
|
|
import { Document, Revision, View } from "@server/models";
|
|
import { sequelize, sequelizeReadOnly } from "@server/storage/database";
|
|
import {
|
|
buildDocument,
|
|
buildTeam,
|
|
buildUser,
|
|
buildComment,
|
|
} from "@server/test/factories";
|
|
import UpdateDocumentsPopularityScoreTask from "./UpdateDocumentsPopularityScoreTask";
|
|
|
|
const props = {
|
|
limit: 10000,
|
|
partition: {
|
|
partitionIndex: 0,
|
|
partitionCount: 1,
|
|
},
|
|
};
|
|
|
|
vi.setConfig({ testTimeout: 30000 });
|
|
|
|
describe("UpdateDocumentsPopularityScoreTask", () => {
|
|
let task: UpdateDocumentsPopularityScoreTask;
|
|
|
|
beforeEach(() => {
|
|
task = new UpdateDocumentsPopularityScoreTask();
|
|
vi.spyOn(Date.prototype, "getHours").mockReturnValue(0);
|
|
|
|
// Ensure calculation query sees data created in tests by redirecting to main sequelize instance.
|
|
// We only mock if the instances are different to avoid infinite recursion.
|
|
if (sequelizeReadOnly !== sequelize) {
|
|
vi.spyOn(sequelizeReadOnly, "query").mockImplementation(
|
|
sequelize.query.bind(sequelize)
|
|
);
|
|
}
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
it("should skip execution if not at a 6-hour interval", async () => {
|
|
vi.spyOn(Date.prototype, "getHours").mockReturnValue(1);
|
|
const team = await buildTeam();
|
|
const document = await buildDocument({
|
|
teamId: team.id,
|
|
publishedAt: new Date(),
|
|
});
|
|
|
|
await task.perform(props);
|
|
|
|
const updatedDocument = await Document.findByPk(document.id);
|
|
expect(updatedDocument?.popularityScore).toBe(0);
|
|
});
|
|
|
|
it("should update popularity score based on revisions", async () => {
|
|
const team = await buildTeam();
|
|
const user = await buildUser({ teamId: team.id });
|
|
const document = await buildDocument({
|
|
teamId: team.id,
|
|
publishedAt: new Date(),
|
|
});
|
|
|
|
await Revision.create({
|
|
documentId: document.id,
|
|
userId: user.id,
|
|
title: document.title,
|
|
text: "Content",
|
|
createdAt: subDays(new Date(), 1),
|
|
});
|
|
|
|
await task.perform(props);
|
|
|
|
const updatedDocument = await Document.findByPk(document.id);
|
|
expect(updatedDocument?.popularityScore).toBeGreaterThan(0);
|
|
});
|
|
|
|
it("should update popularity score based on views", async () => {
|
|
const team = await buildTeam();
|
|
const user = await buildUser({ teamId: team.id });
|
|
const document = await buildDocument({
|
|
teamId: team.id,
|
|
publishedAt: new Date(),
|
|
});
|
|
|
|
await View.create({
|
|
documentId: document.id,
|
|
userId: user.id,
|
|
});
|
|
|
|
await task.perform(props);
|
|
|
|
const updatedDocument = await Document.findByPk(document.id);
|
|
expect(updatedDocument?.popularityScore).toBeGreaterThan(0);
|
|
});
|
|
|
|
it("should update popularity score based on comments", async () => {
|
|
const team = await buildTeam();
|
|
const user = await buildUser({ teamId: team.id });
|
|
const document = await buildDocument({
|
|
teamId: team.id,
|
|
publishedAt: new Date(),
|
|
});
|
|
|
|
await buildComment({
|
|
documentId: document.id,
|
|
userId: user.id,
|
|
});
|
|
|
|
await task.perform(props);
|
|
|
|
const updatedDocument = await Document.findByPk(document.id);
|
|
expect(updatedDocument?.popularityScore).toBeGreaterThan(0);
|
|
});
|
|
|
|
it("should handle multiple documents and give higher score to more recent activity", async () => {
|
|
const team = await buildTeam();
|
|
const user = await buildUser({ teamId: team.id });
|
|
|
|
const doc1 = await buildDocument({
|
|
teamId: team.id,
|
|
publishedAt: new Date(),
|
|
});
|
|
const doc2 = await buildDocument({
|
|
teamId: team.id,
|
|
publishedAt: new Date(),
|
|
});
|
|
|
|
// Recent activity for doc1
|
|
await Revision.create({
|
|
documentId: doc1.id,
|
|
userId: user.id,
|
|
title: doc1.title,
|
|
text: "Content",
|
|
createdAt: subDays(new Date(), 1),
|
|
});
|
|
|
|
// Older activity for doc2
|
|
await Revision.create({
|
|
documentId: doc2.id,
|
|
userId: user.id,
|
|
title: doc2.title,
|
|
text: "Content",
|
|
createdAt: subDays(new Date(), 5),
|
|
});
|
|
|
|
await task.perform(props);
|
|
|
|
const updatedDoc1 = await Document.findByPk(doc1.id);
|
|
const updatedDoc2 = await Document.findByPk(doc2.id);
|
|
|
|
expect(updatedDoc1?.popularityScore).toBeGreaterThan(
|
|
updatedDoc2?.popularityScore || 0
|
|
);
|
|
});
|
|
|
|
it("should only process published and non-deleted documents", async () => {
|
|
const team = await buildTeam();
|
|
const user = await buildUser({ teamId: team.id });
|
|
|
|
// Unpublished document (draft)
|
|
const draft = await buildDocument({
|
|
teamId: team.id,
|
|
publishedAt: undefined,
|
|
});
|
|
await Revision.create({
|
|
documentId: draft.id,
|
|
userId: user.id,
|
|
title: draft.title,
|
|
text: "Content",
|
|
createdAt: new Date(),
|
|
});
|
|
|
|
// Deleted document
|
|
const deleted = await buildDocument({
|
|
teamId: team.id,
|
|
publishedAt: new Date(),
|
|
deletedAt: new Date(),
|
|
});
|
|
await Revision.create({
|
|
documentId: deleted.id,
|
|
userId: user.id,
|
|
title: deleted.title,
|
|
text: "Content",
|
|
createdAt: new Date(),
|
|
});
|
|
|
|
await task.perform(props);
|
|
|
|
const updatedDraft = await Document.unscoped().findByPk(draft.id);
|
|
const updatedDeleted = await Document.unscoped().findByPk(deleted.id, {
|
|
paranoid: false,
|
|
});
|
|
|
|
expect(Number(updatedDraft?.popularityScore)).toEqual(0);
|
|
expect(Number(updatedDeleted?.popularityScore)).toEqual(0);
|
|
});
|
|
});
|