chore: Move to Typescript (#2783)
This PR moves the entire project to Typescript. Due to the ~1000 ignores this will lead to a messy codebase for a while, but the churn is worth it – all of those ignore comments are places that were never type-safe previously. closes #1282
This commit is contained in:
436
server/models/Collection.test.ts
Normal file
436
server/models/Collection.test.ts
Normal file
@@ -0,0 +1,436 @@
|
||||
import randomstring from "randomstring";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { Collection, Document } from "@server/models";
|
||||
import {
|
||||
buildUser,
|
||||
buildGroup,
|
||||
buildCollection,
|
||||
buildTeam,
|
||||
buildDocument,
|
||||
} from "@server/test/factories";
|
||||
import { flushdb, seed } from "@server/test/support";
|
||||
import slugify from "@server/utils/slugify";
|
||||
|
||||
beforeEach(() => flushdb());
|
||||
beforeEach(jest.resetAllMocks);
|
||||
describe("#url", () => {
|
||||
test("should return correct url for the collection", () => {
|
||||
const collection = new Collection({
|
||||
id: "1234",
|
||||
});
|
||||
expect(collection.url).toBe(`/collection/untitled-${collection.urlId}`);
|
||||
});
|
||||
});
|
||||
describe("getDocumentParents", () => {
|
||||
test("should return array of parent document ids", async () => {
|
||||
const parent = await buildDocument();
|
||||
const document = await buildDocument();
|
||||
const collection = await buildCollection({
|
||||
documentStructure: [
|
||||
{ ...parent.toJSON(), children: [document.toJSON()] },
|
||||
],
|
||||
});
|
||||
const result = collection.getDocumentParents(document.id);
|
||||
expect(result.length).toBe(1);
|
||||
expect(result[0]).toBe(parent.id);
|
||||
});
|
||||
|
||||
test("should return array of parent document ids", async () => {
|
||||
const parent = await buildDocument();
|
||||
const document = await buildDocument();
|
||||
const collection = await buildCollection({
|
||||
documentStructure: [
|
||||
{ ...parent.toJSON(), children: [document.toJSON()] },
|
||||
],
|
||||
});
|
||||
const result = collection.getDocumentParents(parent.id);
|
||||
expect(result.length).toBe(0);
|
||||
});
|
||||
|
||||
test("should not error if documentStructure is empty", async () => {
|
||||
const parent = await buildDocument();
|
||||
await buildDocument();
|
||||
const collection = await buildCollection();
|
||||
const result = collection.getDocumentParents(parent.id);
|
||||
expect(result).toBe(undefined);
|
||||
});
|
||||
});
|
||||
describe("getDocumentTree", () => {
|
||||
test("should return document tree", async () => {
|
||||
const document = await buildDocument();
|
||||
const collection = await buildCollection({
|
||||
documentStructure: [document.toJSON()],
|
||||
});
|
||||
expect(collection.getDocumentTree(document.id)).toEqual(document.toJSON());
|
||||
});
|
||||
|
||||
test("should return nested documents in tree", async () => {
|
||||
const parent = await buildDocument();
|
||||
const document = await buildDocument();
|
||||
const collection = await buildCollection({
|
||||
documentStructure: [
|
||||
{ ...parent.toJSON(), children: [document.toJSON()] },
|
||||
],
|
||||
});
|
||||
expect(collection.getDocumentTree(parent.id)).toEqual({
|
||||
...parent.toJSON(),
|
||||
children: [document.toJSON()],
|
||||
});
|
||||
expect(collection.getDocumentTree(document.id)).toEqual(document.toJSON());
|
||||
});
|
||||
});
|
||||
describe("isChildDocument", () => {
|
||||
test("should return false with unexpected data", async () => {
|
||||
const document = await buildDocument();
|
||||
const collection = await buildCollection({
|
||||
documentStructure: [document.toJSON()],
|
||||
});
|
||||
expect(collection.isChildDocument(document.id, document.id)).toEqual(false);
|
||||
expect(collection.isChildDocument(document.id, undefined)).toEqual(false);
|
||||
expect(collection.isChildDocument(undefined, document.id)).toEqual(false);
|
||||
});
|
||||
|
||||
test("should return false if sibling", async () => {
|
||||
const one = await buildDocument();
|
||||
const document = await buildDocument();
|
||||
const collection = await buildCollection({
|
||||
documentStructure: [one.toJSON(), document.toJSON()],
|
||||
});
|
||||
expect(collection.isChildDocument(one.id, document.id)).toEqual(false);
|
||||
expect(collection.isChildDocument(document.id, one.id)).toEqual(false);
|
||||
});
|
||||
|
||||
test("should return true if direct child of parent", async () => {
|
||||
const parent = await buildDocument();
|
||||
const document = await buildDocument();
|
||||
const collection = await buildCollection({
|
||||
documentStructure: [
|
||||
{ ...parent.toJSON(), children: [document.toJSON()] },
|
||||
],
|
||||
});
|
||||
expect(collection.isChildDocument(parent.id, document.id)).toEqual(true);
|
||||
expect(collection.isChildDocument(document.id, parent.id)).toEqual(false);
|
||||
});
|
||||
|
||||
test("should return true if nested child of parent", async () => {
|
||||
const parent = await buildDocument();
|
||||
const nested = await buildDocument();
|
||||
const document = await buildDocument();
|
||||
const collection = await buildCollection({
|
||||
documentStructure: [
|
||||
{
|
||||
...parent.toJSON(),
|
||||
children: [{ ...nested.toJSON(), children: [document.toJSON()] }],
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(collection.isChildDocument(parent.id, document.id)).toEqual(true);
|
||||
expect(collection.isChildDocument(document.id, parent.id)).toEqual(false);
|
||||
});
|
||||
});
|
||||
describe("#addDocumentToStructure", () => {
|
||||
test("should add as last element without index", async () => {
|
||||
const { collection } = await seed();
|
||||
const id = uuidv4();
|
||||
const newDocument = new Document({
|
||||
id,
|
||||
title: "New end node",
|
||||
parentDocumentId: null,
|
||||
});
|
||||
await collection.addDocumentToStructure(newDocument);
|
||||
expect(collection.documentStructure.length).toBe(2);
|
||||
expect(collection.documentStructure[1].id).toBe(id);
|
||||
});
|
||||
|
||||
test("should add with an index", async () => {
|
||||
const { collection } = await seed();
|
||||
const id = uuidv4();
|
||||
const newDocument = new Document({
|
||||
id,
|
||||
title: "New end node",
|
||||
parentDocumentId: null,
|
||||
});
|
||||
await collection.addDocumentToStructure(newDocument, 1);
|
||||
expect(collection.documentStructure.length).toBe(2);
|
||||
expect(collection.documentStructure[1].id).toBe(id);
|
||||
});
|
||||
|
||||
test("should add as a child if with parent", async () => {
|
||||
const { collection, document } = await seed();
|
||||
const id = uuidv4();
|
||||
const newDocument = new Document({
|
||||
id,
|
||||
title: "New end node",
|
||||
parentDocumentId: document.id,
|
||||
});
|
||||
await collection.addDocumentToStructure(newDocument, 1);
|
||||
expect(collection.documentStructure.length).toBe(1);
|
||||
expect(collection.documentStructure[0].id).toBe(document.id);
|
||||
expect(collection.documentStructure[0].children.length).toBe(1);
|
||||
expect(collection.documentStructure[0].children[0].id).toBe(id);
|
||||
});
|
||||
|
||||
test("should add as a child if with parent with index", async () => {
|
||||
const { collection, document } = await seed();
|
||||
const newDocument = new Document({
|
||||
id: uuidv4(),
|
||||
title: "node",
|
||||
parentDocumentId: document.id,
|
||||
});
|
||||
const id = uuidv4();
|
||||
const secondDocument = new Document({
|
||||
id,
|
||||
title: "New start node",
|
||||
parentDocumentId: document.id,
|
||||
});
|
||||
await collection.addDocumentToStructure(newDocument);
|
||||
await collection.addDocumentToStructure(secondDocument, 0);
|
||||
expect(collection.documentStructure.length).toBe(1);
|
||||
expect(collection.documentStructure[0].id).toBe(document.id);
|
||||
expect(collection.documentStructure[0].children.length).toBe(2);
|
||||
expect(collection.documentStructure[0].children[0].id).toBe(id);
|
||||
});
|
||||
describe("options: documentJson", () => {
|
||||
test("should append supplied json over document's own", async () => {
|
||||
const { collection } = await seed();
|
||||
const id = uuidv4();
|
||||
const newDocument = new Document({
|
||||
id: uuidv4(),
|
||||
title: "New end node",
|
||||
parentDocumentId: null,
|
||||
});
|
||||
await collection.addDocumentToStructure(newDocument, undefined, {
|
||||
documentJson: {
|
||||
children: [
|
||||
{
|
||||
id,
|
||||
title: "Totally fake",
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
expect(collection.documentStructure[1].children.length).toBe(1);
|
||||
expect(collection.documentStructure[1].children[0].id).toBe(id);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("#updateDocument", () => {
|
||||
test("should update root document's data", async () => {
|
||||
const { collection, document } = await seed();
|
||||
document.title = "Updated title";
|
||||
await document.save();
|
||||
await collection.updateDocument(document);
|
||||
expect(collection.documentStructure[0].title).toBe("Updated title");
|
||||
});
|
||||
|
||||
test("should update child document's data", async () => {
|
||||
const { collection, document } = await seed();
|
||||
const newDocument = await Document.create({
|
||||
parentDocumentId: document.id,
|
||||
collectionId: collection.id,
|
||||
teamId: collection.teamId,
|
||||
userId: collection.createdById,
|
||||
lastModifiedById: collection.createdById,
|
||||
createdById: collection.createdById,
|
||||
title: "Child document",
|
||||
text: "content",
|
||||
});
|
||||
await collection.addDocumentToStructure(newDocument);
|
||||
newDocument.title = "Updated title";
|
||||
await newDocument.save();
|
||||
await collection.updateDocument(newDocument);
|
||||
const reloaded = await Collection.findByPk(collection.id);
|
||||
expect(reloaded.documentStructure[0].children[0].title).toBe(
|
||||
"Updated title"
|
||||
);
|
||||
});
|
||||
});
|
||||
describe("#removeDocument", () => {
|
||||
test("should save if removing", async () => {
|
||||
const { collection, document } = await seed();
|
||||
jest.spyOn(collection, "save");
|
||||
await collection.deleteDocument(document);
|
||||
expect(collection.save).toBeCalled();
|
||||
});
|
||||
|
||||
test("should remove documents from root", async () => {
|
||||
const { collection, document } = await seed();
|
||||
await collection.deleteDocument(document);
|
||||
expect(collection.documentStructure.length).toBe(0);
|
||||
// Verify that the document was removed
|
||||
const collectionDocuments = await Document.findAndCountAll({
|
||||
where: {
|
||||
collectionId: collection.id,
|
||||
},
|
||||
});
|
||||
expect(collectionDocuments.count).toBe(0);
|
||||
});
|
||||
|
||||
test("should remove a document with child documents", async () => {
|
||||
const { collection, document } = await seed();
|
||||
// Add a child for testing
|
||||
const newDocument = await Document.create({
|
||||
parentDocumentId: document.id,
|
||||
collectionId: collection.id,
|
||||
teamId: collection.teamId,
|
||||
userId: collection.createdById,
|
||||
lastModifiedById: collection.createdById,
|
||||
createdById: collection.createdById,
|
||||
title: "Child document",
|
||||
text: "content",
|
||||
});
|
||||
await collection.addDocumentToStructure(newDocument);
|
||||
expect(collection.documentStructure[0].children.length).toBe(1);
|
||||
// Remove the document
|
||||
await collection.deleteDocument(document);
|
||||
expect(collection.documentStructure.length).toBe(0);
|
||||
const collectionDocuments = await Document.findAndCountAll({
|
||||
where: {
|
||||
collectionId: collection.id,
|
||||
},
|
||||
});
|
||||
expect(collectionDocuments.count).toBe(0);
|
||||
});
|
||||
|
||||
test("should remove a child document", async () => {
|
||||
const { collection, document } = await seed();
|
||||
// Add a child for testing
|
||||
const newDocument = await Document.create({
|
||||
parentDocumentId: document.id,
|
||||
collectionId: collection.id,
|
||||
teamId: collection.teamId,
|
||||
userId: collection.createdById,
|
||||
lastModifiedById: collection.createdById,
|
||||
createdById: collection.createdById,
|
||||
publishedAt: new Date(),
|
||||
title: "Child document",
|
||||
text: "content",
|
||||
});
|
||||
await collection.addDocumentToStructure(newDocument);
|
||||
expect(collection.documentStructure.length).toBe(1);
|
||||
expect(collection.documentStructure[0].children.length).toBe(1);
|
||||
// Remove the document
|
||||
await collection.deleteDocument(newDocument);
|
||||
const reloaded = await Collection.findByPk(collection.id);
|
||||
expect(reloaded.documentStructure.length).toBe(1);
|
||||
expect(reloaded.documentStructure[0].children.length).toBe(0);
|
||||
const collectionDocuments = await Document.findAndCountAll({
|
||||
where: {
|
||||
collectionId: collection.id,
|
||||
},
|
||||
});
|
||||
expect(collectionDocuments.count).toBe(1);
|
||||
});
|
||||
});
|
||||
describe("#membershipUserIds", () => {
|
||||
test("should return collection and group memberships", async () => {
|
||||
const team = await buildTeam();
|
||||
const teamId = team.id;
|
||||
// Make 6 users
|
||||
const users = await Promise.all(
|
||||
Array(6)
|
||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 1-3 arguments, but got 0.
|
||||
.fill()
|
||||
.map(() =>
|
||||
buildUser({
|
||||
teamId,
|
||||
})
|
||||
)
|
||||
);
|
||||
const collection = await buildCollection({
|
||||
userId: users[0].id,
|
||||
permission: null,
|
||||
teamId,
|
||||
});
|
||||
const group1 = await buildGroup({
|
||||
teamId,
|
||||
});
|
||||
const group2 = await buildGroup({
|
||||
teamId,
|
||||
});
|
||||
const createdById = users[0].id;
|
||||
await group1.addUser(users[0], {
|
||||
through: {
|
||||
createdById,
|
||||
},
|
||||
});
|
||||
await group1.addUser(users[1], {
|
||||
through: {
|
||||
createdById,
|
||||
},
|
||||
});
|
||||
await group2.addUser(users[2], {
|
||||
through: {
|
||||
createdById,
|
||||
},
|
||||
});
|
||||
await group2.addUser(users[3], {
|
||||
through: {
|
||||
createdById,
|
||||
},
|
||||
});
|
||||
await collection.addUser(users[4], {
|
||||
through: {
|
||||
createdById,
|
||||
},
|
||||
});
|
||||
await collection.addUser(users[5], {
|
||||
through: {
|
||||
createdById,
|
||||
},
|
||||
});
|
||||
await collection.addGroup(group1, {
|
||||
through: {
|
||||
createdById,
|
||||
},
|
||||
});
|
||||
await collection.addGroup(group2, {
|
||||
through: {
|
||||
createdById,
|
||||
},
|
||||
});
|
||||
const membershipUserIds = await Collection.membershipUserIds(collection.id);
|
||||
expect(membershipUserIds.length).toBe(6);
|
||||
});
|
||||
});
|
||||
describe("#findByPk", () => {
|
||||
test("should return collection with collection Id", async () => {
|
||||
const collection = await buildCollection();
|
||||
const response = await Collection.findByPk(collection.id);
|
||||
expect(response.id).toBe(collection.id);
|
||||
});
|
||||
|
||||
test("should return collection when urlId is present", async () => {
|
||||
const collection = await buildCollection();
|
||||
const id = `${slugify(collection.name)}-${collection.urlId}`;
|
||||
const response = await Collection.findByPk(id);
|
||||
expect(response.id).toBe(collection.id);
|
||||
});
|
||||
|
||||
test("should return undefined when incorrect uuid type", async () => {
|
||||
const collection = await buildCollection();
|
||||
const response = await Collection.findByPk(collection.id + "-incorrect");
|
||||
expect(response).toBe(undefined);
|
||||
});
|
||||
|
||||
test("should return undefined when incorrect urlId length", async () => {
|
||||
const collection = await buildCollection();
|
||||
const id = `${slugify(collection.name)}-${collection.urlId}incorrect`;
|
||||
const response = await Collection.findByPk(id);
|
||||
expect(response).toBe(undefined);
|
||||
});
|
||||
|
||||
test("should return null when no collection is found with uuid", async () => {
|
||||
const response = await Collection.findByPk(
|
||||
"a9e71a81-7342-4ea3-9889-9b9cc8f667da"
|
||||
);
|
||||
expect(response).toBe(null);
|
||||
});
|
||||
|
||||
test("should return null when no collection is found with urlId", async () => {
|
||||
const id = `${slugify("test collection")}-${randomstring.generate(15)}`;
|
||||
const response = await Collection.findByPk(id);
|
||||
expect(response).toBe(null);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user