chore: Improve perf of server tests (#5785)

This commit is contained in:
Tom Moor
2023-09-06 07:14:49 -04:00
committed by GitHub
parent a724a21c21
commit 3eb947e9a5
69 changed files with 2045 additions and 1551 deletions

View File

@@ -191,7 +191,13 @@ describe("#attachments.delete", () => {
},
});
expect(res.status).toEqual(200);
expect(await Attachment.count()).toEqual(0);
expect(
await Attachment.count({
where: {
teamId: user.teamId,
},
})
).toEqual(0);
});
it("should allow deleting an attachment without a document created by user", async () => {
@@ -209,7 +215,13 @@ describe("#attachments.delete", () => {
},
});
expect(res.status).toEqual(200);
expect(await Attachment.count()).toEqual(0);
expect(
await Attachment.count({
where: {
teamId: user.teamId,
},
})
).toEqual(0);
});
it("should allow deleting an attachment without a document if admin", async () => {
@@ -226,7 +238,13 @@ describe("#attachments.delete", () => {
},
});
expect(res.status).toEqual(200);
expect(await Attachment.count()).toEqual(0);
expect(
await Attachment.count({
where: {
teamId: user.teamId,
},
})
).toEqual(0);
});
it("should not allow deleting an attachment in another team", async () => {

View File

@@ -1,3 +1,5 @@
import { faker } from "@faker-js/faker";
import { v4 as uuidv4 } from "uuid";
import { buildUser, buildTeam } from "@server/test/factories";
import {
getTestServer,
@@ -5,7 +7,7 @@ import {
setSelfHosted,
} from "@server/test/support";
const mockTeamInSessionId = "1e023d05-951c-41c6-9012-c9fa0402e1c3";
const mockTeamInSessionId = uuidv4();
jest.mock("@server/utils/authentication", () => ({
getSessionsInCookie() {
@@ -25,9 +27,7 @@ describe("#auth.info", () => {
id: mockTeamInSessionId,
});
const user = await buildUser({
teamId: team.id,
});
const user = await buildUser({ teamId: team.id });
await buildUser();
await buildUser({
teamId: team2.id,
@@ -53,9 +53,7 @@ describe("#auth.info", () => {
it("should require the team to not be deleted", async () => {
const team = await buildTeam();
const user = await buildUser({
teamId: team.id,
});
const user = await buildUser({ teamId: team.id });
await team.destroy();
const res = await server.post("/api/auth.info", {
body: {
@@ -107,19 +105,20 @@ describe("#auth.config", () => {
});
it("should return available providers for team subdomain", async () => {
const subdomain = faker.internet.domainWord();
await buildTeam({
guestSignin: false,
subdomain: "example",
subdomain,
authenticationProviders: [
{
name: "slack",
providerId: "123",
providerId: uuidv4(),
},
],
});
const res = await server.post("/api/auth.config", {
headers: {
host: `example.outline.dev`,
host: `${subdomain}.outline.dev`,
},
});
const body = await res.json();
@@ -129,19 +128,20 @@ describe("#auth.config", () => {
});
it("should return available providers for team custom domain", async () => {
const domain = faker.internet.domainName();
await buildTeam({
guestSignin: false,
domain: "docs.mycompany.com",
domain,
authenticationProviders: [
{
name: "slack",
providerId: "123",
providerId: uuidv4(),
},
],
});
const res = await server.post("/api/auth.config", {
headers: {
host: "docs.mycompany.com",
host: domain,
},
});
const body = await res.json();
@@ -151,19 +151,20 @@ describe("#auth.config", () => {
});
it("should return email provider for team when guest signin enabled", async () => {
const subdomain = faker.internet.domainWord();
await buildTeam({
guestSignin: true,
subdomain: "example",
subdomain,
authenticationProviders: [
{
name: "slack",
providerId: "123",
providerId: uuidv4(),
},
],
});
const res = await server.post("/api/auth.config", {
headers: {
host: "example.outline.dev",
host: `${subdomain}.outline.dev`,
},
});
const body = await res.json();
@@ -174,20 +175,21 @@ describe("#auth.config", () => {
});
it("should not return provider when disabled", async () => {
const subdomain = faker.internet.domainWord();
await buildTeam({
guestSignin: false,
subdomain: "example",
subdomain,
authenticationProviders: [
{
name: "slack",
providerId: "123",
providerId: uuidv4(),
enabled: false,
},
],
});
const res = await server.post("/api/auth.config", {
headers: {
host: "example.outline.dev",
host: `${subdomain}.outline.dev`,
},
});
const body = await res.json();
@@ -204,7 +206,7 @@ describe("#auth.config", () => {
authenticationProviders: [
{
name: "slack",
providerId: "123",
providerId: uuidv4(),
},
],
});
@@ -223,7 +225,7 @@ describe("#auth.config", () => {
authenticationProviders: [
{
name: "slack",
providerId: "123",
providerId: uuidv4(),
},
],
});

View File

@@ -93,9 +93,7 @@ describe("#authenticationProviders.update", () => {
it("should require authorization", async () => {
const team = await buildTeam();
const user = await buildUser({
teamId: team.id,
});
const user = await buildUser({ teamId: team.id });
const authenticationProviders = await team.$get("authenticationProviders");
const res = await server.post("/api/authenticationProviders.update", {
body: {

View File

@@ -7,8 +7,9 @@ import {
buildGroup,
buildCollection,
buildDocument,
buildTeam,
} from "@server/test/factories";
import { seed, getTestServer } from "@server/test/support";
import { getTestServer } from "@server/test/support";
const server = getTestServer();
@@ -21,7 +22,12 @@ describe("#collections.list", () => {
});
it("should return collections", async () => {
const { user, collection } = await seed();
const team = await buildTeam();
const user = await buildUser({ teamId: team.id });
const collection = await buildCollection({
userId: user.id,
teamId: team.id,
});
const res = await server.post("/api/collections.list", {
body: {
token: user.getJwtToken(),
@@ -36,7 +42,12 @@ describe("#collections.list", () => {
});
it("should not return private collections actor is not a member of", async () => {
const { user, collection } = await seed();
const team = await buildTeam();
const user = await buildUser({ teamId: team.id });
const collection = await buildCollection({
userId: user.id,
teamId: team.id,
});
await buildCollection({
permission: null,
teamId: user.teamId,
@@ -143,7 +154,7 @@ describe("#collections.move", () => {
it("should require authorization", async () => {
const user = await buildUser();
const { collection } = await seed();
const collection = await buildCollection();
const res = await server.post("/api/collections.move", {
body: {
token: user.getJwtToken(),
@@ -155,7 +166,9 @@ describe("#collections.move", () => {
});
it("should return success", async () => {
const { admin, collection } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const collection = await buildCollection({ teamId: team.id });
const res = await server.post("/api/collections.move", {
body: {
token: admin.getJwtToken(),
@@ -169,7 +182,9 @@ describe("#collections.move", () => {
});
it("should return error when index is not valid", async () => {
const { admin, collection } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const collection = await buildCollection({ teamId: team.id });
const res = await server.post("/api/collections.move", {
body: {
token: admin.getJwtToken(),
@@ -181,7 +196,13 @@ describe("#collections.move", () => {
});
it("if index collision occurs, should updated index of other collection", async () => {
const { user, admin, collection } = await seed();
const team = await buildTeam();
const user = await buildUser({ teamId: team.id });
const admin = await buildAdmin({ teamId: team.id });
const collection = await buildCollection({
userId: user.id,
teamId: team.id,
});
const createdCollectionResponse = await server.post(
"/api/collections.create",
{
@@ -209,7 +230,9 @@ describe("#collections.move", () => {
});
it("if index collision with an extra collection, should updated index of other collection", async () => {
const { user, admin } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const user = await buildUser({ teamId: team.id });
const createdCollectionAResponse = await server.post(
"/api/collections.create",
{
@@ -267,7 +290,7 @@ describe("#collections.move", () => {
describe("#collections.export", () => {
it("should not allow export of private collection not a member", async () => {
const { user } = await seed();
const user = await buildUser();
const collection = await buildCollection({
permission: null,
teamId: user.teamId,
@@ -282,7 +305,9 @@ describe("#collections.export", () => {
});
it("should allow export of private collection when the actor is a member", async () => {
const { admin, collection } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const collection = await buildCollection({ teamId: team.id });
collection.permission = null;
await collection.save();
await CollectionUser.create({
@@ -337,7 +362,12 @@ describe("#collections.export", () => {
});
it("should return unauthorized if user is not admin", async () => {
const { user, collection } = await seed();
const team = await buildTeam();
const user = await buildUser({ teamId: team.id });
const collection = await buildCollection({
userId: user.id,
teamId: team.id,
});
const res = await server.post("/api/collections.export", {
body: {
token: user.getJwtToken(),
@@ -384,7 +414,7 @@ describe("#collections.export_all", () => {
});
it("should return success", async () => {
const { admin } = await seed();
const admin = await buildAdmin();
const res = await server.post("/api/collections.export_all", {
body: {
token: admin.getJwtToken(),
@@ -460,7 +490,7 @@ describe("#collections.add_user", () => {
});
it("should require authorization", async () => {
const { collection } = await seed();
const collection = await buildCollection();
const user = await buildUser();
const anotherUser = await buildUser({
teamId: user.teamId,
@@ -623,7 +653,7 @@ describe("#collections.remove_group", () => {
});
it("should require authorization", async () => {
const { collection } = await seed();
const collection = await buildCollection();
const user = await buildUser();
const group = await buildGroup({
teamId: user.teamId,
@@ -694,7 +724,7 @@ describe("#collections.remove_user", () => {
});
it("should require authorization", async () => {
const { collection } = await seed();
const collection = await buildCollection();
const user = await buildUser();
const anotherUser = await buildUser({
teamId: user.teamId,
@@ -861,7 +891,12 @@ describe("#collections.group_memberships", () => {
describe("#collections.memberships", () => {
it("should return members in private collection", async () => {
const { collection, user } = await seed();
const team = await buildTeam();
const user = await buildUser({ teamId: team.id });
const collection = await buildCollection({
userId: user.id,
teamId: team.id,
});
collection.permission = null;
await collection.save();
@@ -882,7 +917,12 @@ describe("#collections.memberships", () => {
});
it("should allow filtering members in collection by name", async () => {
const { collection, user } = await seed();
const team = await buildTeam();
const user = await buildUser({ teamId: team.id });
const collection = await buildCollection({
userId: user.id,
teamId: team.id,
});
const user2 = await buildUser({
name: "Won't find",
});
@@ -906,7 +946,12 @@ describe("#collections.memberships", () => {
});
it("should allow filtering members in collection by permission", async () => {
const { collection, user } = await seed();
const team = await buildTeam();
const user = await buildUser({ teamId: team.id });
const collection = await buildCollection({
userId: user.id,
teamId: team.id,
});
const user2 = await buildUser();
await CollectionUser.create({
createdById: user.id,
@@ -941,7 +986,7 @@ describe("#collections.memberships", () => {
});
it("should require authorization", async () => {
const { collection } = await seed();
const collection = await buildCollection();
const user = await buildUser();
const res = await server.post("/api/collections.memberships", {
body: {
@@ -955,7 +1000,12 @@ describe("#collections.memberships", () => {
describe("#collections.info", () => {
it("should return collection", async () => {
const { user, collection } = await seed();
const team = await buildTeam();
const user = await buildUser({ teamId: team.id });
const collection = await buildCollection({
userId: user.id,
teamId: team.id,
});
const res = await server.post("/api/collections.info", {
body: {
token: user.getJwtToken(),
@@ -968,7 +1018,12 @@ describe("#collections.info", () => {
});
it("should require user member of collection", async () => {
const { user, collection } = await seed();
const team = await buildTeam();
const user = await buildUser({ teamId: team.id });
const collection = await buildCollection({
userId: user.id,
teamId: team.id,
});
collection.permission = null;
await collection.save();
await CollectionUser.destroy({
@@ -987,7 +1042,12 @@ describe("#collections.info", () => {
});
it("should allow user member of collection", async () => {
const { user, collection } = await seed();
const team = await buildTeam();
const user = await buildUser({ teamId: team.id });
const collection = await buildCollection({
userId: user.id,
teamId: team.id,
});
collection.permission = null;
await collection.save();
await CollectionUser.create({
@@ -1015,7 +1075,7 @@ describe("#collections.info", () => {
});
it("should require authorization", async () => {
const { collection } = await seed();
const collection = await buildCollection();
const user = await buildUser();
const res = await server.post("/api/collections.info", {
body: {
@@ -1067,7 +1127,7 @@ describe("#collections.create", () => {
});
it("should allow setting sharing to false", async () => {
const { user } = await seed();
const user = await buildUser();
const res = await server.post("/api/collections.create", {
body: {
token: user.getJwtToken(),
@@ -1082,7 +1142,7 @@ describe("#collections.create", () => {
});
it("should return correct policies with private collection", async () => {
const { user } = await seed();
const user = await buildUser();
const res = await server.post("/api/collections.create", {
body: {
token: user.getJwtToken(),
@@ -1098,7 +1158,7 @@ describe("#collections.create", () => {
});
it("if index collision, should updated index of other collection", async () => {
const { user } = await seed();
const user = await buildUser();
const createdCollectionAResponse = await server.post(
"/api/collections.create",
{
@@ -1129,7 +1189,7 @@ describe("#collections.create", () => {
});
it("if index collision with an extra collection, should updated index of other collection", async () => {
const { user } = await seed();
const user = await buildUser();
const createdCollectionAResponse = await server.post(
"/api/collections.create",
{
@@ -1188,7 +1248,7 @@ describe("#collections.update", () => {
});
it("should require authorization", async () => {
const { collection } = await seed();
const collection = await buildCollection();
const user = await buildUser();
const res = await server.post("/api/collections.update", {
body: {
@@ -1201,7 +1261,9 @@ describe("#collections.update", () => {
});
it("allows editing non-private collection", async () => {
const { admin, collection } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const collection = await buildCollection({ teamId: team.id });
const res = await server.post("/api/collections.update", {
body: {
token: admin.getJwtToken(),
@@ -1216,7 +1278,9 @@ describe("#collections.update", () => {
});
it("allows editing sort", async () => {
const { admin, collection } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const collection = await buildCollection({ teamId: team.id });
const sort = {
field: "index",
direction: "desc",
@@ -1235,7 +1299,9 @@ describe("#collections.update", () => {
});
it("allows editing individual fields", async () => {
const { admin, collection } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const collection = await buildCollection({ teamId: team.id });
const res = await server.post("/api/collections.update", {
body: {
token: admin.getJwtToken(),
@@ -1250,7 +1316,9 @@ describe("#collections.update", () => {
});
it("allows editing from non-private to private collection, and trims whitespace", async () => {
const { admin, collection } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const collection = await buildCollection({ teamId: team.id });
const res = await server.post("/api/collections.update", {
body: {
token: admin.getJwtToken(),
@@ -1269,7 +1337,9 @@ describe("#collections.update", () => {
});
it("allows editing from private to non-private collection", async () => {
const { admin, collection } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const collection = await buildCollection({ teamId: team.id });
collection.permission = null;
await collection.save();
await CollectionUser.create({
@@ -1296,7 +1366,9 @@ describe("#collections.update", () => {
});
it("allows editing by read-write collection user", async () => {
const { admin, collection } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const collection = await buildCollection({ teamId: team.id });
collection.permission = null;
await collection.save();
await CollectionUser.create({
@@ -1352,7 +1424,12 @@ describe("#collections.update", () => {
});
it("does not allow editing by read-only collection user", async () => {
const { user, collection } = await seed();
const team = await buildTeam();
const user = await buildUser({ teamId: team.id });
const collection = await buildCollection({
userId: user.id,
teamId: team.id,
});
collection.permission = null;
await collection.save();
await CollectionUser.update(
@@ -1378,7 +1455,9 @@ describe("#collections.update", () => {
});
it("does not allow setting unknown sort fields", async () => {
const { admin, collection } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const collection = await buildCollection({ teamId: team.id });
const sort = {
field: "blah",
direction: "desc",
@@ -1394,7 +1473,9 @@ describe("#collections.update", () => {
});
it("does not allow setting unknown sort directions", async () => {
const { admin, collection } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const collection = await buildCollection({ teamId: team.id });
const sort = {
field: "title",
direction: "blah",
@@ -1419,7 +1500,7 @@ describe("#collections.delete", () => {
});
it("should require authorization", async () => {
const { collection } = await seed();
const collection = await buildCollection();
const user = await buildUser();
const res = await server.post("/api/collections.delete", {
body: {
@@ -1431,7 +1512,9 @@ describe("#collections.delete", () => {
});
it("should not allow deleting last collection", async () => {
const { admin, collection } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const collection = await buildCollection({ teamId: team.id });
const res = await server.post("/api/collections.delete", {
body: {
token: admin.getJwtToken(),
@@ -1442,12 +1525,11 @@ describe("#collections.delete", () => {
});
it("should delete collection", async () => {
const { admin, collection } = await seed();
// to ensure it isn't the last collection
await buildCollection({
teamId: admin.teamId,
createdById: admin.id,
});
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const collection = await buildCollection({ teamId: team.id });
await buildCollection({ teamId: team.id });
const res = await server.post("/api/collections.delete", {
body: {
token: admin.getJwtToken(),
@@ -1460,7 +1542,9 @@ describe("#collections.delete", () => {
});
it("should delete published documents", async () => {
const { admin, collection } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const collection = await buildCollection({ teamId: team.id });
// to ensure it isn't the last collection
await buildCollection({
teamId: admin.teamId,

View File

@@ -807,7 +807,11 @@ router.post(
authorize(user, "delete", collection);
const total = await Collection.count();
const total = await Collection.count({
where: {
teamId: user.teamId,
},
});
if (total === 1) {
throw ValidationError("Cannot delete last collection");
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,11 @@
import { buildEvent, buildUser } from "@server/test/factories";
import { seed, getTestServer, setCloudHosted } from "@server/test/support";
import {
buildAdmin,
buildCollection,
buildDocument,
buildEvent,
buildUser,
} from "@server/test/factories";
import { getTestServer, setCloudHosted } from "@server/test/support";
const server = getTestServer();
@@ -7,7 +13,17 @@ describe("#events.list", () => {
beforeEach(setCloudHosted);
it("should only return activity events", async () => {
const { user, admin, document, collection } = await seed();
const user = await buildUser();
const admin = await buildAdmin({ teamId: user.teamId });
const collection = await buildCollection({
userId: user.id,
teamId: user.teamId,
});
const document = await buildDocument({
userId: user.id,
collectionId: collection.id,
teamId: user.teamId,
});
// audit event
await buildEvent({
name: "users.promote",
@@ -35,7 +51,17 @@ describe("#events.list", () => {
});
it("should return audit events", async () => {
const { user, admin, document, collection } = await seed();
const user = await buildUser();
const admin = await buildAdmin({ teamId: user.teamId });
const collection = await buildCollection({
userId: user.id,
teamId: user.teamId,
});
const document = await buildDocument({
userId: user.id,
collectionId: collection.id,
teamId: user.teamId,
});
// audit event
const auditEvent = await buildEvent({
name: "users.promote",
@@ -65,7 +91,17 @@ describe("#events.list", () => {
});
it("should allow filtering by actorId", async () => {
const { user, admin, document, collection } = await seed();
const user = await buildUser();
const admin = await buildAdmin({ teamId: user.teamId });
const collection = await buildCollection({
userId: user.id,
teamId: user.teamId,
});
const document = await buildDocument({
userId: user.id,
collectionId: collection.id,
teamId: user.teamId,
});
// audit event
const auditEvent = await buildEvent({
name: "users.promote",
@@ -95,7 +131,17 @@ describe("#events.list", () => {
});
it("should allow filtering by documentId", async () => {
const { user, admin, document, collection } = await seed();
const user = await buildUser();
const admin = await buildAdmin({ teamId: user.teamId });
const collection = await buildCollection({
userId: user.id,
teamId: user.teamId,
});
const document = await buildDocument({
userId: user.id,
collectionId: collection.id,
teamId: user.teamId,
});
const event = await buildEvent({
name: "documents.publish",
collectionId: collection.id,
@@ -116,7 +162,16 @@ describe("#events.list", () => {
});
it("should not return events for documentId without authorization", async () => {
const { user, document, collection } = await seed();
const user = await buildUser();
const collection = await buildCollection({
userId: user.id,
teamId: user.teamId,
});
const document = await buildDocument({
userId: user.id,
collectionId: collection.id,
teamId: user.teamId,
});
const actor = await buildUser();
await buildEvent({
name: "documents.publish",
@@ -137,7 +192,17 @@ describe("#events.list", () => {
});
it("should allow filtering by event name", async () => {
const { user, admin, document, collection } = await seed();
const user = await buildUser();
const admin = await buildAdmin({ teamId: user.teamId });
const collection = await buildCollection({
userId: user.id,
teamId: user.teamId,
});
const document = await buildDocument({
userId: user.id,
collectionId: collection.id,
teamId: user.teamId,
});
// audit event
await buildEvent({
name: "users.promote",
@@ -166,7 +231,17 @@ describe("#events.list", () => {
});
it("should return events with deleted actors", async () => {
const { user, admin, document, collection } = await seed();
const user = await buildUser();
const admin = await buildAdmin({ teamId: user.teamId });
const collection = await buildCollection({
userId: user.id,
teamId: user.teamId,
});
const document = await buildDocument({
userId: user.id,
collectionId: collection.id,
teamId: user.teamId,
});
// event viewable in activity stream
const event = await buildEvent({
name: "documents.publish",
@@ -188,7 +263,7 @@ describe("#events.list", () => {
});
it("should require authorization for audit events", async () => {
const { user } = await seed();
const user = await buildUser();
const res = await server.post("/api/events.list", {
body: {
token: user.getJwtToken(),

View File

@@ -42,9 +42,7 @@ describe("#fileOperations.info", () => {
const admin = await buildAdmin({
teamId: team.id,
});
const user = await buildUser({
teamId: team.id,
});
const user = await buildUser({ teamId: team.id });
const exportData = await buildFileOperation({
type: FileOperationType.Export,
teamId: team.id,
@@ -244,9 +242,7 @@ describe("#fileOperations.redirect", () => {
it("should require authorization", async () => {
const team = await buildTeam();
const user = await buildUser({
teamId: team.id,
});
const user = await buildUser({ teamId: team.id });
const admin = await buildAdmin();
const exportData = await buildFileOperation({
state: FileOperationState.Complete,
@@ -283,15 +279,25 @@ describe("#fileOperations.delete", () => {
},
});
expect(deleteResponse.status).toBe(200);
expect(await Event.count()).toBe(1);
expect(await FileOperation.count()).toBe(0);
expect(
await Event.count({
where: {
teamId: team.id,
},
})
).toBe(1);
expect(
await FileOperation.count({
where: {
teamId: team.id,
},
})
).toBe(0);
});
it("should require authorization", async () => {
const team = await buildTeam();
const user = await buildUser({
teamId: team.id,
});
const user = await buildUser({ teamId: team.id });
const admin = await buildAdmin();
const exportData = await buildFileOperation({
type: FileOperationType.Export,

View File

@@ -1,4 +1,4 @@
import { Event } from "@server/models";
import { Event, Group, User } from "@server/models";
import { buildUser, buildAdmin, buildGroup } from "@server/test/factories";
import { getTestServer } from "@server/test/support";
@@ -60,8 +60,7 @@ describe("#groups.update", () => {
expect(res.status).toEqual(403);
});
describe("when user is admin", () => {
// @ts-expect-error ts-migrate(7034) FIXME: Variable 'user' implicitly has type 'any' in some ... Remove this comment to see the full error message
let user, group;
let user: User, group: Group;
beforeEach(async () => {
user = await buildAdmin();
group = await buildGroup({
@@ -71,14 +70,16 @@ describe("#groups.update", () => {
it("allows admin to edit a group", async () => {
const res = await server.post("/api/groups.update", {
body: {
// @ts-expect-error ts-migrate(7005) FIXME: Variable 'user' implicitly has an 'any' type.
token: user.getJwtToken(),
// @ts-expect-error ts-migrate(7005) FIXME: Variable 'group' implicitly has an 'any' type.
id: group.id,
name: "Test",
},
});
const events = await Event.findAll();
const events = await Event.findAll({
where: {
teamId: user.teamId,
},
});
expect(events.length).toEqual(1);
const body = await res.json();
expect(res.status).toEqual(200);
@@ -87,32 +88,29 @@ describe("#groups.update", () => {
it("does not create an event if the update is a noop", async () => {
const res = await server.post("/api/groups.update", {
body: {
// @ts-expect-error ts-migrate(7005) FIXME: Variable 'user' implicitly has an 'any' type.
token: user.getJwtToken(),
// @ts-expect-error ts-migrate(7005) FIXME: Variable 'group' implicitly has an 'any' type.
id: group.id,
// @ts-expect-error ts-migrate(7005) FIXME: Variable 'group' implicitly has an 'any' type.
name: group.name,
},
});
const events = await Event.findAll();
const events = await Event.findAll({
where: {
teamId: user.teamId,
},
});
expect(events.length).toEqual(0);
const body = await res.json();
expect(res.status).toEqual(200);
// @ts-expect-error ts-migrate(7005) FIXME: Variable 'group' implicitly has an 'any' type.
expect(body.data.name).toBe(group.name);
});
it("fails with validation error when name already taken", async () => {
await buildGroup({
// @ts-expect-error ts-migrate(7005) FIXME: Variable 'user' implicitly has an 'any' type.
teamId: user.teamId,
name: "test",
});
const res = await server.post("/api/groups.update", {
body: {
// @ts-expect-error ts-migrate(7005) FIXME: Variable 'user' implicitly has an 'any' type.
token: user.getJwtToken(),
// @ts-expect-error ts-migrate(7005) FIXME: Variable 'group' implicitly has an 'any' type.
id: group.id,
name: "TEST",
},

View File

@@ -1,10 +1,11 @@
import { seed, getTestServer } from "@server/test/support";
import { buildUser } from "@server/test/factories";
import { getTestServer } from "@server/test/support";
const server = getTestServer();
describe("#pagination", () => {
it("should allow offset and limit", async () => {
const { user } = await seed();
const user = await buildUser();
const res = await server.post("/api/users.list", {
body: {
token: user.getJwtToken(),
@@ -16,7 +17,7 @@ describe("#pagination", () => {
});
it("should not allow negative limit", async () => {
const { user } = await seed();
const user = await buildUser();
const res = await server.post("/api/users.list", {
body: {
token: user.getJwtToken(),
@@ -27,7 +28,7 @@ describe("#pagination", () => {
});
it("should not allow non-integer limit", async () => {
const { user } = await seed();
const user = await buildUser();
const res = await server.post("/api/users.list", {
body: {
token: user.getJwtToken(),
@@ -38,7 +39,7 @@ describe("#pagination", () => {
});
it("should not allow negative offset", async () => {
const { user } = await seed();
const user = await buildUser();
const res = await server.post("/api/users.list", {
body: {
token: user.getJwtToken(),
@@ -49,7 +50,7 @@ describe("#pagination", () => {
});
it("should not allow non-integer offset", async () => {
const { user } = await seed();
const user = await buildUser();
const res = await server.post("/api/users.list", {
body: {
token: user.getJwtToken(),

View File

@@ -201,9 +201,7 @@ describe("#notifications.list", () => {
describe("#notifications.update", () => {
it("should mark notification as viewed", async () => {
const team = await buildTeam();
const user = await buildUser({
teamId: team.id,
});
const user = await buildUser({ teamId: team.id });
const actor = await buildUser({
teamId: team.id,
});
@@ -243,9 +241,7 @@ describe("#notifications.update", () => {
it("should archive the notification", async () => {
const team = await buildTeam();
const user = await buildUser({
teamId: team.id,
});
const user = await buildUser({ teamId: team.id });
const actor = await buildUser({
teamId: team.id,
});

View File

@@ -1,12 +1,20 @@
import { CollectionUser, Revision } from "@server/models";
import { buildDocument, buildUser } from "@server/test/factories";
import { seed, getTestServer } from "@server/test/support";
import {
buildCollection,
buildDocument,
buildUser,
} from "@server/test/factories";
import { getTestServer } from "@server/test/support";
const server = getTestServer();
describe("#revisions.info", () => {
it("should return a document revision", async () => {
const { user, document } = await seed();
const user = await buildUser();
const document = await buildDocument({
userId: user.id,
teamId: user.teamId,
});
const revision = await Revision.createFromDocument(document);
const res = await server.post("/api/revisions.info", {
body: {
@@ -36,7 +44,11 @@ describe("#revisions.info", () => {
describe("#revisions.diff", () => {
it("should return the document HTML if no previous revision", async () => {
const { user, document } = await seed();
const user = await buildUser();
const document = await buildDocument({
userId: user.id,
teamId: user.teamId,
});
const revision = await Revision.createFromDocument(document);
const res = await server.post("/api/revisions.diff", {
body: {
@@ -57,8 +69,13 @@ describe("#revisions.diff", () => {
});
it("should allow returning HTML directly with accept header", async () => {
const { user, document } = await seed();
const user = await buildUser();
const document = await buildDocument({
userId: user.id,
teamId: user.teamId,
});
const revision = await Revision.createFromDocument(document);
const res = await server.post("/api/revisions.diff", {
body: {
token: user.getJwtToken(),
@@ -81,7 +98,11 @@ describe("#revisions.diff", () => {
});
it("should compare to previous revision by default", async () => {
const { user, document } = await seed();
const user = await buildUser();
const document = await buildDocument({
userId: user.id,
teamId: user.teamId,
});
await Revision.createFromDocument(document);
await document.update({ text: "New text" });
@@ -121,7 +142,11 @@ describe("#revisions.diff", () => {
describe("#revisions.list", () => {
it("should return a document's revisions", async () => {
const { user, document } = await seed();
const user = await buildUser();
const document = await buildDocument({
userId: user.id,
teamId: user.teamId,
});
await Revision.createFromDocument(document);
const res = await server.post("/api/revisions.list", {
body: {
@@ -137,7 +162,16 @@ describe("#revisions.list", () => {
});
it("should not return revisions for document in collection not a member of", async () => {
const { user, document, collection } = await seed();
const user = await buildUser();
const collection = await buildCollection({
userId: user.id,
teamId: user.teamId,
});
const document = await buildDocument({
userId: user.id,
collectionId: collection.id,
teamId: user.teamId,
});
await Revision.createFromDocument(document);
collection.permission = null;
await collection.save();

View File

@@ -6,9 +6,10 @@ import {
buildShare,
buildAdmin,
buildCollection,
buildTeam,
} from "@server/test/factories";
import { seed, getTestServer } from "@server/test/support";
import { getTestServer } from "@server/test/support";
const server = getTestServer();
@@ -29,7 +30,10 @@ describe("#shares.list", () => {
});
it("should only return shares created by user", async () => {
const { user, admin, document } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const user = await buildUser({ teamId: team.id });
const document = await buildDocument({ userId: user.id, teamId: team.id });
await buildShare({
documentId: document.id,
teamId: user.teamId,
@@ -53,7 +57,11 @@ describe("#shares.list", () => {
});
it("should not return revoked shares", async () => {
const { user, document } = await seed();
const user = await buildUser();
const document = await buildDocument({
userId: user.id,
teamId: user.teamId,
});
const share = await buildShare({
documentId: document.id,
teamId: user.teamId,
@@ -71,7 +79,11 @@ describe("#shares.list", () => {
});
it("should not return unpublished shares", async () => {
const { user, document } = await seed();
const user = await buildUser();
const document = await buildDocument({
userId: user.id,
teamId: user.teamId,
});
await buildShare({
published: false,
documentId: document.id,
@@ -89,7 +101,11 @@ describe("#shares.list", () => {
});
it("should not return shares to deleted documents", async () => {
const { user, document } = await seed();
const user = await buildUser();
const document = await buildDocument({
userId: user.id,
teamId: user.teamId,
});
await buildShare({
documentId: document.id,
teamId: user.teamId,
@@ -107,7 +123,10 @@ describe("#shares.list", () => {
});
it("admins should return shares created by all users", async () => {
const { user, admin, document } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const user = await buildUser({ teamId: team.id });
const document = await buildDocument({ userId: user.id, teamId: team.id });
const share = await buildShare({
documentId: document.id,
teamId: admin.teamId,
@@ -126,7 +145,18 @@ describe("#shares.list", () => {
});
it("admins should not return shares in collection not a member of", async () => {
const { admin, document, collection } = await seed();
const team = await buildTeam();
const user = await buildUser({ teamId: team.id });
const admin = await buildAdmin({ teamId: team.id });
const collection = await buildCollection({
userId: user.id,
teamId: team.id,
});
const document = await buildDocument({
userId: user.id,
collectionId: collection.id,
teamId: team.id,
});
await buildShare({
documentId: document.id,
teamId: admin.teamId,
@@ -179,7 +209,11 @@ describe("#shares.create", () => {
});
it("should allow creating a share record for document", async () => {
const { user, document } = await seed();
const user = await buildUser();
const document = await buildDocument({
userId: user.id,
teamId: user.teamId,
});
const res = await server.post("/api/shares.create", {
body: {
token: user.getJwtToken(),
@@ -193,7 +227,17 @@ describe("#shares.create", () => {
});
it("should allow creating a share record with read-only permissions but no publishing", async () => {
const { user, document, collection } = await seed();
const team = await buildTeam();
const user = await buildUser({ teamId: team.id });
const collection = await buildCollection({
userId: user.id,
teamId: team.id,
});
const document = await buildDocument({
userId: user.id,
collectionId: collection.id,
teamId: team.id,
});
collection.permission = null;
await collection.save();
await CollectionUser.update(
@@ -227,7 +271,11 @@ describe("#shares.create", () => {
});
it("should allow creating a share record if link previously revoked", async () => {
const { user, document } = await seed();
const user = await buildUser();
const document = await buildDocument({
userId: user.id,
teamId: user.teamId,
});
const share = await buildShare({
documentId: document.id,
teamId: user.teamId,
@@ -247,7 +295,11 @@ describe("#shares.create", () => {
});
it("should return existing share link for document and user", async () => {
const { user, document } = await seed();
const user = await buildUser();
const document = await buildDocument({
userId: user.id,
teamId: user.teamId,
});
const share = await buildShare({
documentId: document.id,
teamId: user.teamId,
@@ -265,9 +317,11 @@ describe("#shares.create", () => {
});
it("should allow creating a share record if team sharing disabled but not publishing", async () => {
const { user, document, team } = await seed();
await team.update({
sharing: false,
const team = await buildTeam({ sharing: false });
const user = await buildUser({ teamId: team.id });
const document = await buildDocument({
teamId: user.teamId,
userId: user.id,
});
const res = await server.post("/api/shares.create", {
body: {
@@ -288,10 +342,17 @@ describe("#shares.create", () => {
});
it("should allow creating a share record if collection sharing disabled but not publishing", async () => {
const { user, collection, document } = await seed();
await collection.update({
const user = await buildUser();
const collection = await buildCollection({
userId: user.id,
teamId: user.teamId,
sharing: false,
});
const document = await buildDocument({
userId: user.id,
collectionId: collection.id,
teamId: user.teamId,
});
const res = await server.post("/api/shares.create", {
body: {
token: user.getJwtToken(),
@@ -311,7 +372,7 @@ describe("#shares.create", () => {
});
it("should require authentication", async () => {
const { document } = await seed();
const document = await buildDocument();
const res = await server.post("/api/shares.create", {
body: {
documentId: document.id,
@@ -323,7 +384,7 @@ describe("#shares.create", () => {
});
it("should require authorization", async () => {
const { document } = await seed();
const document = await buildDocument();
const user = await buildUser();
const res = await server.post("/api/shares.create", {
body: {
@@ -390,7 +451,11 @@ describe("#shares.info", () => {
});
it("should require authentication", async () => {
const { user, document } = await seed();
const user = await buildUser();
const document = await buildDocument({
userId: user.id,
teamId: user.teamId,
});
const share = await buildShare({
documentId: document.id,
teamId: user.teamId,
@@ -407,7 +472,9 @@ describe("#shares.info", () => {
});
it("should require authorization", async () => {
const { admin, document } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const document = await buildDocument({ teamId: team.id });
const user = await buildUser();
const share = await buildShare({
documentId: document.id,
@@ -449,7 +516,11 @@ describe("#shares.info", () => {
});
it("should allow reading share by documentId", async () => {
const { user, document } = await seed();
const user = await buildUser();
const document = await buildDocument({
userId: user.id,
teamId: user.teamId,
});
const share = await buildShare({
documentId: document.id,
teamId: user.teamId,
@@ -468,7 +539,16 @@ describe("#shares.info", () => {
expect(body.data.shares[0].published).toBe(true);
});
it("should return share for parent document with includeChildDocuments=true", async () => {
const { user, document, collection } = await seed();
const user = await buildUser();
const collection = await buildCollection({
userId: user.id,
teamId: user.teamId,
});
const document = await buildDocument({
userId: user.id,
collectionId: collection.id,
teamId: user.teamId,
});
const childDocument = await buildDocument({
teamId: document.teamId,
parentDocumentId: document.id,
@@ -480,6 +560,7 @@ describe("#shares.info", () => {
userId: user.id,
includeChildDocuments: true,
});
await collection.reload();
await collection.addDocumentToStructure(childDocument, 0);
const res = await server.post("/api/shares.info", {
body: {
@@ -498,7 +579,17 @@ describe("#shares.info", () => {
expect(body.policies[0].abilities.update).toBe(true);
});
it("should not return share for parent document with includeChildDocuments=false", async () => {
const { user, document, collection } = await seed();
const team = await buildTeam();
const user = await buildUser({ teamId: team.id });
const collection = await buildCollection({
userId: user.id,
teamId: team.id,
});
const document = await buildDocument({
userId: user.id,
collectionId: collection.id,
teamId: team.id,
});
const childDocument = await buildDocument({
teamId: document.teamId,
parentDocumentId: document.id,
@@ -520,7 +611,16 @@ describe("#shares.info", () => {
expect(res.status).toEqual(204);
});
it("should return shares for parent document and current document", async () => {
const { user, document, collection } = await seed();
const user = await buildUser();
const collection = await buildCollection({
userId: user.id,
teamId: user.teamId,
});
const document = await buildDocument({
userId: user.id,
collectionId: collection.id,
teamId: user.teamId,
});
const childDocument = await buildDocument({
teamId: document.teamId,
parentDocumentId: document.id,
@@ -538,6 +638,7 @@ describe("#shares.info", () => {
userId: user.id,
includeChildDocuments: true,
});
await collection.reload();
await collection.addDocumentToStructure(childDocument, 0);
const res = await server.post("/api/shares.info", {
body: {
@@ -561,7 +662,11 @@ describe("#shares.info", () => {
describe("#shares.update", () => {
it("should fail for invalid urlId", async () => {
const { user, document } = await seed();
const user = await buildUser();
const document = await buildDocument({
userId: user.id,
teamId: user.teamId,
});
const share = await buildShare({
documentId: document.id,
teamId: user.teamId,
@@ -594,7 +699,11 @@ describe("#shares.update", () => {
});
it("should update urlId", async () => {
const { user, document } = await seed();
const user = await buildUser();
const document = await buildDocument({
userId: user.id,
teamId: user.teamId,
});
const share = await buildShare({
documentId: document.id,
teamId: user.teamId,
@@ -612,7 +721,11 @@ describe("#shares.update", () => {
});
it("should allow clearing urlId", async () => {
const { user, document } = await seed();
const user = await buildUser();
const document = await buildDocument({
userId: user.id,
teamId: user.teamId,
});
const share = await buildShare({
documentId: document.id,
teamId: user.teamId,
@@ -638,7 +751,11 @@ describe("#shares.update", () => {
});
it("should allow user to update a share", async () => {
const { user, document } = await seed();
const user = await buildUser();
const document = await buildDocument({
userId: user.id,
teamId: user.teamId,
});
const share = await buildShare({
documentId: document.id,
teamId: user.teamId,
@@ -657,7 +774,11 @@ describe("#shares.update", () => {
});
it("should allow author to update a share", async () => {
const { user, document } = await seed();
const user = await buildUser();
const document = await buildDocument({
userId: user.id,
teamId: user.teamId,
});
const share = await buildShare({
documentId: document.id,
teamId: user.teamId,
@@ -677,7 +798,10 @@ describe("#shares.update", () => {
});
it("should allow admin to update a share", async () => {
const { user, admin, document } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const user = await buildUser({ teamId: team.id });
const document = await buildDocument({ userId: user.id, teamId: team.id });
const share = await buildShare({
documentId: document.id,
teamId: user.teamId,
@@ -697,7 +821,11 @@ describe("#shares.update", () => {
});
it("should require authentication", async () => {
const { user, document } = await seed();
const user = await buildUser();
const document = await buildDocument({
userId: user.id,
teamId: user.teamId,
});
const share = await buildShare({
documentId: document.id,
teamId: user.teamId,
@@ -715,7 +843,9 @@ describe("#shares.update", () => {
});
it("should require authorization", async () => {
const { admin, document } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const document = await buildDocument({ teamId: team.id });
const user = await buildUser();
const share = await buildShare({
documentId: document.id,
@@ -747,7 +877,11 @@ describe("#shares.revoke", () => {
});
it("should allow author to revoke a share", async () => {
const { user, document } = await seed();
const user = await buildUser();
const document = await buildDocument({
userId: user.id,
teamId: user.teamId,
});
const share = await buildShare({
documentId: document.id,
teamId: user.teamId,
@@ -763,7 +897,11 @@ describe("#shares.revoke", () => {
});
it("should 404 if shares document is deleted", async () => {
const { user, document } = await seed();
const user = await buildUser();
const document = await buildDocument({
userId: user.id,
teamId: user.teamId,
});
const share = await buildShare({
documentId: document.id,
teamId: user.teamId,
@@ -780,7 +918,10 @@ describe("#shares.revoke", () => {
});
it("should allow admin to revoke a share", async () => {
const { user, admin, document } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const user = await buildUser({ teamId: team.id });
const document = await buildDocument({ userId: user.id, teamId: team.id });
const share = await buildShare({
documentId: document.id,
teamId: user.teamId,
@@ -796,7 +937,11 @@ describe("#shares.revoke", () => {
});
it("should require authentication", async () => {
const { user, document } = await seed();
const user = await buildUser();
const document = await buildDocument({
userId: user.id,
teamId: user.teamId,
});
const share = await buildShare({
documentId: document.id,
teamId: user.teamId,
@@ -813,7 +958,9 @@ describe("#shares.revoke", () => {
});
it("should require authorization", async () => {
const { admin, document } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const document = await buildDocument({ teamId: team.id });
const user = await buildUser();
const share = await buildShare({
documentId: document.id,

View File

@@ -54,7 +54,11 @@ describe("#subscriptions.create", () => {
expect(res.status).toEqual(200);
expect(body.ok).toEqual(true);
const events = await Event.findAll();
const events = await Event.findAll({
where: {
teamId: document.teamId,
},
});
expect(events.length).toEqual(1);
expect(events[0].name).toEqual("subscriptions.create");
@@ -625,7 +629,11 @@ describe("#subscriptions.delete", () => {
},
});
const events = await Event.findAll();
const events = await Event.findAll({
where: {
teamId: document.teamId,
},
});
expect(events.length).toEqual(1);
expect(events[0].name).toEqual("subscriptions.delete");

View File

@@ -1,7 +1,12 @@
import { faker } from "@faker-js/faker";
import { TeamDomain } from "@server/models";
import { buildAdmin, buildCollection, buildTeam } from "@server/test/factories";
import {
seed,
buildAdmin,
buildCollection,
buildTeam,
buildUser,
} from "@server/test/factories";
import {
getTestServer,
setCloudHosted,
setSelfHosted,
@@ -18,24 +23,24 @@ describe("teams.create", () => {
const res = await server.post("/api/teams.create", {
body: {
token: user.getJwtToken(),
name: "new workspace",
name: "factory inc",
},
});
const body = await res.json();
expect(res.status).toEqual(200);
expect(body.data.team.name).toEqual("new workspace");
expect(body.data.team.subdomain).toEqual("new-workspace");
expect(body.data.team.name).toEqual("factory inc");
expect(body.data.team.subdomain).toEqual("factory-inc");
});
it("requires a cloud hosted deployment", async () => {
setSelfHosted();
await setSelfHosted();
const team = await buildTeam();
const user = await buildAdmin({ teamId: team.id });
const res = await server.post("/api/teams.create", {
body: {
token: user.getJwtToken(),
name: "new workspace",
name: faker.company.name(),
},
});
expect(res.status).toEqual(402);
@@ -44,16 +49,17 @@ describe("teams.create", () => {
describe("#team.update", () => {
it("should update team details", async () => {
const { admin } = await seed();
const admin = await buildAdmin();
const name = faker.company.name();
const res = await server.post("/api/team.update", {
body: {
token: admin.getJwtToken(),
name: "New name",
name,
},
});
const body = await res.json();
expect(res.status).toEqual(200);
expect(body.data.name).toEqual("New name");
expect(body.data.name).toEqual(name);
});
it("should not invalidate request if subdomain is sent as null", async () => {
@@ -68,7 +74,8 @@ describe("#team.update", () => {
});
it("should add new allowed Domains, removing empty string values", async () => {
const { admin, team } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const res = await server.post("/api/team.update", {
body: {
token: admin.getJwtToken(),
@@ -98,10 +105,11 @@ describe("#team.update", () => {
});
it("should remove old allowed Domains", async () => {
const { admin, team } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const existingTeamDomain = await TeamDomain.create({
teamId: team.id,
name: "example-company.com",
name: faker.internet.domainName(),
createdById: admin.id,
});
@@ -124,10 +132,11 @@ describe("#team.update", () => {
});
it("should add new allowed domains and remove old ones", async () => {
const { admin, team } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const existingTeamDomain = await TeamDomain.create({
teamId: team.id,
name: "example-company.com",
name: faker.internet.domainName(),
createdById: admin.id,
});
@@ -155,7 +164,7 @@ describe("#team.update", () => {
});
it("should only allow member,viewer or admin as default role", async () => {
const { admin } = await seed();
const admin = await buildAdmin();
const res = await server.post("/api/team.update", {
body: {
token: admin.getJwtToken(),
@@ -175,7 +184,8 @@ describe("#team.update", () => {
});
it("should allow identical team details", async () => {
const { admin, team } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const res = await server.post("/api/team.update", {
body: {
token: admin.getJwtToken(),
@@ -188,18 +198,17 @@ describe("#team.update", () => {
});
it("should require admin", async () => {
const { user } = await seed();
const user = await buildUser();
const res = await server.post("/api/team.update", {
body: {
token: user.getJwtToken(),
name: "New name",
name: faker.company.name(),
},
});
expect(res.status).toEqual(403);
});
it("should require authentication", async () => {
await seed();
const res = await server.post("/api/team.update");
expect(res.status).toEqual(401);
});

View File

@@ -1,3 +1,4 @@
import env from "@server/env";
import { User } from "@server/models";
import { buildDocument, buildUser } from "@server/test/factories";
import { getTestServer } from "@server/test/support";
@@ -134,7 +135,7 @@ describe("#urls.unfurl", () => {
const res = await server.post("/api/urls.unfurl", {
body: {
token: user.getJwtToken(),
url: `http://localhost:3000/${document.url}`,
url: `${env.URL}/${document.url}`,
documentId: document.id,
},
});

View File

@@ -1,44 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`#users.activate should activate a suspended user 1`] = `
{
"data": {
"avatarUrl": null,
"color": "#e600e0",
"createdAt": "2018-01-02T00:00:00.000Z",
"email": "user1@example.com",
"id": "46fde1d4-0050-428f-9f0b-0bf77f4bdf61",
"isAdmin": false,
"isSuspended": false,
"isViewer": false,
"language": "en_US",
"lastActiveAt": null,
"name": "User 1",
"notificationSettings": {},
"preferences": null,
"updatedAt": "2018-01-02T00:00:00.000Z",
},
"ok": true,
"policies": [
{
"abilities": {
"activate": true,
"delete": true,
"demote": true,
"promote": true,
"read": true,
"readDetails": true,
"resendInvite": true,
"suspend": true,
"update": true,
},
"id": "46fde1d4-0050-428f-9f0b-0bf77f4bdf61",
},
],
"status": 200,
}
`;
exports[`#users.activate should require admin 1`] = `
{
"error": "admin_required",
@@ -57,123 +18,6 @@ exports[`#users.delete should require authentication 1`] = `
}
`;
exports[`#users.demote should demote an admin 1`] = `
{
"data": {
"avatarUrl": null,
"color": "#e600e0",
"createdAt": "2018-01-02T00:00:00.000Z",
"email": "user1@example.com",
"id": "46fde1d4-0050-428f-9f0b-0bf77f4bdf61",
"isAdmin": false,
"isSuspended": false,
"isViewer": false,
"language": "en_US",
"lastActiveAt": null,
"name": "User 1",
"notificationSettings": {},
"preferences": null,
"updatedAt": "2018-01-02T00:00:00.000Z",
},
"ok": true,
"policies": [
{
"abilities": {
"activate": true,
"delete": true,
"demote": true,
"promote": true,
"read": true,
"readDetails": true,
"resendInvite": true,
"suspend": true,
"update": true,
},
"id": "46fde1d4-0050-428f-9f0b-0bf77f4bdf61",
},
],
"status": 200,
}
`;
exports[`#users.demote should demote an admin to member 1`] = `
{
"data": {
"avatarUrl": null,
"color": "#e600e0",
"createdAt": "2018-01-02T00:00:00.000Z",
"email": "user1@example.com",
"id": "46fde1d4-0050-428f-9f0b-0bf77f4bdf61",
"isAdmin": false,
"isSuspended": false,
"isViewer": false,
"language": "en_US",
"lastActiveAt": null,
"name": "User 1",
"notificationSettings": {},
"preferences": null,
"updatedAt": "2018-01-02T00:00:00.000Z",
},
"ok": true,
"policies": [
{
"abilities": {
"activate": true,
"delete": true,
"demote": true,
"promote": true,
"read": true,
"readDetails": true,
"resendInvite": true,
"suspend": true,
"update": true,
},
"id": "46fde1d4-0050-428f-9f0b-0bf77f4bdf61",
},
],
"status": 200,
}
`;
exports[`#users.demote should demote an admin to viewer 1`] = `
{
"data": {
"avatarUrl": null,
"color": "#e600e0",
"createdAt": "2018-01-02T00:00:00.000Z",
"email": "user1@example.com",
"id": "46fde1d4-0050-428f-9f0b-0bf77f4bdf61",
"isAdmin": false,
"isSuspended": false,
"isViewer": true,
"language": "en_US",
"lastActiveAt": null,
"name": "User 1",
"notificationSettings": {},
"preferences": null,
"updatedAt": "2018-01-02T00:00:00.000Z",
},
"ok": true,
"policies": [
{
"abilities": {
"activate": true,
"delete": true,
"demote": true,
"promote": true,
"read": true,
"readDetails": true,
"resendInvite": true,
"suspend": true,
"update": true,
},
"id": "46fde1d4-0050-428f-9f0b-0bf77f4bdf61",
},
],
"status": 200,
}
`;
exports[`#users.demote should not allow demoting self 1`] = `
{
"error": "validation_error",
@@ -192,45 +36,6 @@ exports[`#users.demote should require admin 1`] = `
}
`;
exports[`#users.promote should promote a new admin 1`] = `
{
"data": {
"avatarUrl": null,
"color": "#e600e0",
"createdAt": "2018-01-02T00:00:00.000Z",
"email": "user1@example.com",
"id": "46fde1d4-0050-428f-9f0b-0bf77f4bdf61",
"isAdmin": true,
"isSuspended": false,
"isViewer": false,
"language": "en_US",
"lastActiveAt": null,
"name": "User 1",
"notificationSettings": {},
"preferences": null,
"updatedAt": "2018-01-02T00:00:00.000Z",
},
"ok": true,
"policies": [
{
"abilities": {
"activate": true,
"delete": true,
"demote": true,
"promote": false,
"read": true,
"readDetails": true,
"resendInvite": true,
"suspend": true,
"update": true,
},
"id": "46fde1d4-0050-428f-9f0b-0bf77f4bdf61",
},
],
"status": 200,
}
`;
exports[`#users.promote should require admin 1`] = `
{
"error": "admin_required",
@@ -258,45 +63,6 @@ exports[`#users.suspend should require admin 1`] = `
}
`;
exports[`#users.suspend should suspend an user 1`] = `
{
"data": {
"avatarUrl": null,
"color": "#e600e0",
"createdAt": "2018-01-02T00:00:00.000Z",
"email": "user1@example.com",
"id": "46fde1d4-0050-428f-9f0b-0bf77f4bdf61",
"isAdmin": false,
"isSuspended": true,
"isViewer": false,
"language": "en_US",
"lastActiveAt": null,
"name": "User 1",
"notificationSettings": {},
"preferences": null,
"updatedAt": "2018-01-02T00:00:00.000Z",
},
"ok": true,
"policies": [
{
"abilities": {
"activate": true,
"delete": true,
"demote": false,
"promote": false,
"read": true,
"readDetails": true,
"resendInvite": true,
"suspend": true,
"update": true,
},
"id": "46fde1d4-0050-428f-9f0b-0bf77f4bdf61",
},
],
"status": 200,
}
`;
exports[`#users.update should require authentication 1`] = `
{
"error": "authentication_required",

View File

@@ -4,7 +4,7 @@ import {
buildUser,
buildInvite,
} from "@server/test/factories";
import { seed, getTestServer } from "@server/test/support";
import { getTestServer } from "@server/test/support";
const server = getTestServer();
@@ -117,21 +117,27 @@ describe("#users.list", () => {
});
it("should return teams paginated user list", async () => {
const { admin, user } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
await buildUser({ teamId: team.id });
const res = await server.post("/api/users.list", {
body: {
token: admin.getJwtToken(),
sort: "createdAt",
direction: "DESC",
},
});
const body = await res.json();
expect(res.status).toEqual(200);
expect(body.data.length).toEqual(2);
expect(body.data[0].id).toEqual(user.id);
expect(body.data[1].id).toEqual(admin.id);
});
it("should allow filtering by id", async () => {
const { admin, user } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const user = await buildUser({ teamId: team.id });
const res = await server.post("/api/users.list", {
body: {
token: admin.getJwtToken(),
@@ -145,7 +151,9 @@ describe("#users.list", () => {
});
it("should require admin for detailed info", async () => {
const { user, admin } = await seed();
const team = await buildTeam();
await buildAdmin({ teamId: team.id });
const user = await buildUser({ teamId: team.id });
const res = await server.post("/api/users.list", {
body: {
token: user.getJwtToken(),
@@ -156,8 +164,6 @@ describe("#users.list", () => {
expect(body.data.length).toEqual(2);
expect(body.data[0].email).toEqual(undefined);
expect(body.data[1].email).toEqual(undefined);
expect(body.data[0].id).toEqual(user.id);
expect(body.data[1].id).toEqual(admin.id);
});
});
@@ -381,7 +387,7 @@ describe("#users.delete", () => {
describe("#users.update", () => {
it("should update user profile information", async () => {
const { user } = await seed();
const user = await buildUser();
const res = await server.post("/api/users.update", {
body: {
token: user.getJwtToken(),
@@ -427,7 +433,7 @@ describe("#users.update", () => {
});
it("should fail upon sending invalid user preference", async () => {
const { user } = await seed();
const user = await buildUser();
const res = await server.post("/api/users.update", {
body: {
token: user.getJwtToken(),
@@ -439,7 +445,7 @@ describe("#users.update", () => {
});
it("should fail upon sending invalid user preference value", async () => {
const { user } = await seed();
const user = await buildUser();
const res = await server.post("/api/users.update", {
body: {
token: user.getJwtToken(),
@@ -451,7 +457,7 @@ describe("#users.update", () => {
});
it("should update rememberLastPath user preference", async () => {
const { user } = await seed();
const user = await buildUser();
const res = await server.post("/api/users.update", {
body: {
token: user.getJwtToken(),
@@ -476,16 +482,17 @@ describe("#users.update", () => {
describe("#users.promote", () => {
it("should promote a new admin", async () => {
const { admin, user } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const user = await buildUser({ teamId: team.id });
const res = await server.post("/api/users.promote", {
body: {
token: admin.getJwtToken(),
id: user.id,
},
});
const body = await res.json();
expect(res.status).toEqual(200);
expect(body).toMatchSnapshot();
});
it("should require admin", async () => {
@@ -504,7 +511,10 @@ describe("#users.promote", () => {
describe("#users.demote", () => {
it("should demote an admin", async () => {
const { admin, user } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const user = await buildUser({ teamId: team.id });
await user.update({
isAdmin: true,
}); // Make another admin
@@ -515,13 +525,14 @@ describe("#users.demote", () => {
id: user.id,
},
});
const body = await res.json();
expect(res.status).toEqual(200);
expect(body).toMatchSnapshot();
});
it("should demote an admin to viewer", async () => {
const { admin, user } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const user = await buildUser({ teamId: team.id });
await user.update({
isAdmin: true,
}); // Make another admin
@@ -533,13 +544,14 @@ describe("#users.demote", () => {
to: "viewer",
},
});
const body = await res.json();
expect(res.status).toEqual(200);
expect(body).toMatchSnapshot();
});
it("should demote an admin to member", async () => {
const { admin, user } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const user = await buildUser({ teamId: team.id });
await user.update({
isAdmin: true,
}); // Make another admin
@@ -551,9 +563,7 @@ describe("#users.demote", () => {
to: "member",
},
});
const body = await res.json();
expect(res.status).toEqual(200);
expect(body).toMatchSnapshot();
});
it("should not allow demoting self", async () => {
@@ -585,16 +595,17 @@ describe("#users.demote", () => {
describe("#users.suspend", () => {
it("should suspend an user", async () => {
const { admin, user } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const user = await buildUser({ teamId: team.id });
const res = await server.post("/api/users.suspend", {
body: {
token: admin.getJwtToken(),
id: user.id,
},
});
const body = await res.json();
expect(res.status).toEqual(200);
expect(body).toMatchSnapshot();
});
it("should not allow suspending the user themselves", async () => {
@@ -626,7 +637,10 @@ describe("#users.suspend", () => {
describe("#users.activate", () => {
it("should activate a suspended user", async () => {
const { admin, user } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const user = await buildUser({ teamId: team.id });
await user.update({
suspendedById: admin.id,
suspendedAt: new Date(),
@@ -638,9 +652,7 @@ describe("#users.activate", () => {
id: user.id,
},
});
const body = await res.json();
expect(res.status).toEqual(200);
expect(body).toMatchSnapshot();
});
it("should require admin", async () => {
@@ -660,9 +672,7 @@ describe("#users.activate", () => {
describe("#users.count", () => {
it("should count active users", async () => {
const team = await buildTeam();
const user = await buildUser({
teamId: team.id,
});
const user = await buildUser({ teamId: team.id });
const res = await server.post("/api/users.count", {
body: {
token: user.getJwtToken(),
@@ -699,9 +709,7 @@ describe("#users.count", () => {
it("should count suspended users", async () => {
const team = await buildTeam();
const user = await buildUser({
teamId: team.id,
});
const user = await buildUser({ teamId: team.id });
await buildUser({
teamId: team.id,
suspendedAt: new Date(),

View File

@@ -1,13 +1,23 @@
import { CollectionPermission } from "@shared/types";
import { View, CollectionUser } from "@server/models";
import { buildUser } from "@server/test/factories";
import { seed, getTestServer } from "@server/test/support";
import {
buildAdmin,
buildCollection,
buildDocument,
buildTeam,
buildUser,
} from "@server/test/factories";
import { getTestServer } from "@server/test/support";
const server = getTestServer();
describe("#views.list", () => {
it("should return views for a document", async () => {
const { user, document } = await seed();
const user = await buildUser();
const document = await buildDocument({
userId: user.id,
teamId: user.teamId,
});
await View.incrementOrCreate({
documentId: document.id,
userId: user.id,
@@ -25,7 +35,10 @@ describe("#views.list", () => {
});
it("should not return views for suspended user by default", async () => {
const { user, admin, document } = await seed();
const team = await buildTeam();
const admin = await buildAdmin({ teamId: team.id });
const user = await buildUser({ teamId: team.id });
const document = await buildDocument({ userId: user.id, teamId: team.id });
await View.incrementOrCreate({
documentId: document.id,
userId: user.id,
@@ -45,7 +58,17 @@ describe("#views.list", () => {
});
it("should return views for a document in read-only collection", async () => {
const { user, document, collection } = await seed();
const team = await buildTeam();
const user = await buildUser({ teamId: team.id });
const collection = await buildCollection({
userId: user.id,
teamId: team.id,
});
const document = await buildDocument({
userId: user.id,
collectionId: collection.id,
teamId: team.id,
});
collection.permission = null;
await collection.save();
await CollectionUser.create({
@@ -71,7 +94,7 @@ describe("#views.list", () => {
});
it("should require authentication", async () => {
const { document } = await seed();
const document = await buildDocument();
const res = await server.post("/api/views.list", {
body: {
documentId: document.id,
@@ -83,7 +106,7 @@ describe("#views.list", () => {
});
it("should require authorization", async () => {
const { document } = await seed();
const document = await buildDocument();
const user = await buildUser();
const res = await server.post("/api/views.list", {
body: {
@@ -97,7 +120,11 @@ describe("#views.list", () => {
describe("#views.create", () => {
it("should allow creating a view record for document", async () => {
const { user, document } = await seed();
const user = await buildUser();
const document = await buildDocument({
userId: user.id,
teamId: user.teamId,
});
const res = await server.post("/api/views.create", {
body: {
token: user.getJwtToken(),
@@ -110,7 +137,17 @@ describe("#views.create", () => {
});
it("should allow creating a view record for document in read-only collection", async () => {
const { user, document, collection } = await seed();
const team = await buildTeam();
const user = await buildUser({ teamId: team.id });
const collection = await buildCollection({
userId: user.id,
teamId: team.id,
});
const document = await buildDocument({
userId: user.id,
collectionId: collection.id,
teamId: team.id,
});
collection.permission = null;
await collection.save();
await CollectionUser.create({
@@ -131,7 +168,7 @@ describe("#views.create", () => {
});
it("should require authentication", async () => {
const { document } = await seed();
const document = await buildDocument();
const res = await server.post("/api/views.create", {
body: {
documentId: document.id,
@@ -143,7 +180,7 @@ describe("#views.create", () => {
});
it("should require authorization", async () => {
const { document } = await seed();
const document = await buildDocument();
const user = await buildUser();
const res = await server.post("/api/views.create", {
body: {