chore: Improve perf of server tests (#5785)
This commit is contained in:
@@ -82,6 +82,7 @@ jobs:
|
||||
command: yarn test:shared
|
||||
test-server:
|
||||
<<: *defaults
|
||||
parallelism: 4
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
@@ -91,7 +92,9 @@ jobs:
|
||||
command: ./node_modules/.bin/sequelize db:migrate --url $DATABASE_URL_TEST
|
||||
- run:
|
||||
name: test
|
||||
command: yarn test:server --forceExit
|
||||
command: |
|
||||
TESTFILES=$(circleci tests glob "server/**/*.test.ts" | circleci tests split)
|
||||
yarn test $TESTFILES --forceExit
|
||||
bundle-size:
|
||||
<<: *defaults
|
||||
environment:
|
||||
@@ -166,9 +169,8 @@ workflows:
|
||||
- build
|
||||
- bundle-size:
|
||||
requires:
|
||||
- test-app
|
||||
- test-shared
|
||||
- test-server
|
||||
- build
|
||||
- types
|
||||
|
||||
build-docker:
|
||||
jobs:
|
||||
|
||||
@@ -96,8 +96,8 @@
|
||||
"date-fns": "^2.30.0",
|
||||
"dd-trace": "^3.33.0",
|
||||
"dotenv": "^4.0.0",
|
||||
"emoji-mart": "^5.5.2",
|
||||
"email-providers": "^1.14.0",
|
||||
"emoji-mart": "^5.5.2",
|
||||
"emoji-regex": "^10.2.1",
|
||||
"es6-error": "^4.1.1",
|
||||
"fetch-retry": "^5.0.5",
|
||||
@@ -230,6 +230,7 @@
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.21.5",
|
||||
"@babel/preset-typescript": "^7.21.4",
|
||||
"@faker-js/faker": "^8.0.2",
|
||||
"@getoutline/jest-runner-serial": "^2.0.0",
|
||||
"@relative-ci/agent": "^4.1.3",
|
||||
"@types/addressparser": "^1.0.1",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { faker } from "@faker-js/faker";
|
||||
import SigninEmail from "@server/emails/templates/SigninEmail";
|
||||
import WelcomeEmail from "@server/emails/templates/WelcomeEmail";
|
||||
import { AuthenticationProvider } from "@server/models";
|
||||
@@ -21,18 +22,15 @@ describe("email", () => {
|
||||
|
||||
it("should respond with redirect location when user is SSO enabled", async () => {
|
||||
const spy = jest.spyOn(WelcomeEmail.prototype, "schedule");
|
||||
const team = await buildTeam({
|
||||
subdomain: "example",
|
||||
});
|
||||
const user = await buildUser({
|
||||
teamId: team.id,
|
||||
});
|
||||
const subdomain = faker.internet.domainWord();
|
||||
const team = await buildTeam({ subdomain });
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
const res = await server.post("/auth/email", {
|
||||
body: {
|
||||
email: user.email,
|
||||
},
|
||||
headers: {
|
||||
host: "example.outline.dev",
|
||||
host: `${subdomain}.outline.dev`,
|
||||
},
|
||||
});
|
||||
const body = await res.json();
|
||||
@@ -44,16 +42,14 @@ describe("email", () => {
|
||||
|
||||
it("should respond with success and email to be sent when user has SSO but disabled", async () => {
|
||||
const spy = jest.spyOn(SigninEmail.prototype, "schedule");
|
||||
const team = await buildTeam({
|
||||
subdomain: "example",
|
||||
});
|
||||
const user = await buildUser({
|
||||
teamId: team.id,
|
||||
});
|
||||
const subdomain = faker.internet.domainWord();
|
||||
const team = await buildTeam({ subdomain });
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
|
||||
// Disable all the auth providers
|
||||
await AuthenticationProvider.update(
|
||||
{
|
||||
teamId: team.id,
|
||||
enabled: false,
|
||||
},
|
||||
{
|
||||
@@ -68,7 +64,7 @@ describe("email", () => {
|
||||
email: user.email,
|
||||
},
|
||||
headers: {
|
||||
host: "example.outline.dev",
|
||||
host: `${subdomain}.outline.dev`,
|
||||
},
|
||||
});
|
||||
const body = await res.json();
|
||||
@@ -81,15 +77,14 @@ describe("email", () => {
|
||||
it("should not send email when user is on another subdomain but respond with success", async () => {
|
||||
const user = await buildUser();
|
||||
const spy = jest.spyOn(WelcomeEmail.prototype, "schedule");
|
||||
await buildTeam({
|
||||
subdomain: "example",
|
||||
});
|
||||
const subdomain = faker.internet.domainWord();
|
||||
await buildTeam({ subdomain });
|
||||
const res = await server.post("/auth/email", {
|
||||
body: {
|
||||
email: user.email,
|
||||
},
|
||||
headers: {
|
||||
host: "example.outline.dev",
|
||||
host: `${subdomain}.outline.dev`,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -102,9 +97,8 @@ describe("email", () => {
|
||||
|
||||
it("should respond with success and email to be sent when user is not SSO enabled", async () => {
|
||||
const spy = jest.spyOn(SigninEmail.prototype, "schedule");
|
||||
const team = await buildTeam({
|
||||
subdomain: "example",
|
||||
});
|
||||
const subdomain = faker.internet.domainWord();
|
||||
const team = await buildTeam({ subdomain });
|
||||
const user = await buildGuestUser({
|
||||
teamId: team.id,
|
||||
});
|
||||
@@ -113,7 +107,7 @@ describe("email", () => {
|
||||
email: user.email,
|
||||
},
|
||||
headers: {
|
||||
host: "example.outline.dev",
|
||||
host: `${subdomain}.outline.dev`,
|
||||
},
|
||||
});
|
||||
const body = await res.json();
|
||||
@@ -125,15 +119,14 @@ describe("email", () => {
|
||||
|
||||
it("should respond with success regardless of whether successful to prevent crawling email logins", async () => {
|
||||
const spy = jest.spyOn(WelcomeEmail.prototype, "schedule");
|
||||
await buildTeam({
|
||||
subdomain: "example",
|
||||
});
|
||||
const subdomain = faker.internet.domainWord();
|
||||
await buildTeam({ subdomain });
|
||||
const res = await server.post("/auth/email", {
|
||||
body: {
|
||||
email: "user@example.com",
|
||||
},
|
||||
headers: {
|
||||
host: "example.outline.dev",
|
||||
host: `${subdomain}.outline.dev`,
|
||||
},
|
||||
});
|
||||
const body = await res.json();
|
||||
@@ -147,8 +140,9 @@ describe("email", () => {
|
||||
it("should default to current subdomain with SSO", async () => {
|
||||
const spy = jest.spyOn(SigninEmail.prototype, "schedule");
|
||||
const email = "sso-user@example.org";
|
||||
const subdomain = faker.internet.domainWord();
|
||||
const team = await buildTeam({
|
||||
subdomain: "example",
|
||||
subdomain,
|
||||
});
|
||||
await buildGuestUser({
|
||||
email,
|
||||
@@ -162,7 +156,7 @@ describe("email", () => {
|
||||
email,
|
||||
},
|
||||
headers: {
|
||||
host: "example.outline.dev",
|
||||
host: `${subdomain}.outline.dev`,
|
||||
},
|
||||
});
|
||||
const body = await res.json();
|
||||
@@ -175,8 +169,9 @@ describe("email", () => {
|
||||
it("should default to current subdomain with guest email", async () => {
|
||||
const spy = jest.spyOn(SigninEmail.prototype, "schedule");
|
||||
const email = "guest-user@example.org";
|
||||
const subdomain = faker.internet.domainWord();
|
||||
const team = await buildTeam({
|
||||
subdomain: "example",
|
||||
subdomain,
|
||||
});
|
||||
await buildUser({
|
||||
email,
|
||||
@@ -190,7 +185,7 @@ describe("email", () => {
|
||||
email,
|
||||
},
|
||||
headers: {
|
||||
host: "example.outline.dev",
|
||||
host: `${subdomain}.outline.dev`,
|
||||
},
|
||||
});
|
||||
const body = await res.json();
|
||||
@@ -203,8 +198,9 @@ describe("email", () => {
|
||||
it("should default to custom domain with SSO", async () => {
|
||||
const spy = jest.spyOn(WelcomeEmail.prototype, "schedule");
|
||||
const email = "sso-user-2@example.org";
|
||||
const domain = faker.internet.domainName();
|
||||
const team = await buildTeam({
|
||||
domain: "docs.mycompany.com",
|
||||
domain,
|
||||
});
|
||||
await buildGuestUser({
|
||||
email,
|
||||
@@ -218,7 +214,7 @@ describe("email", () => {
|
||||
email,
|
||||
},
|
||||
headers: {
|
||||
host: "docs.mycompany.com",
|
||||
host: domain,
|
||||
},
|
||||
});
|
||||
const body = await res.json();
|
||||
@@ -231,8 +227,9 @@ describe("email", () => {
|
||||
it("should default to custom domain with guest email", async () => {
|
||||
const spy = jest.spyOn(SigninEmail.prototype, "schedule");
|
||||
const email = "guest-user-2@example.org";
|
||||
const domain = faker.internet.domainName();
|
||||
const team = await buildTeam({
|
||||
domain: "docs.mycompany.com",
|
||||
domain,
|
||||
});
|
||||
await buildUser({
|
||||
email,
|
||||
@@ -246,7 +243,7 @@ describe("email", () => {
|
||||
email,
|
||||
},
|
||||
headers: {
|
||||
host: "docs.mycompany.com",
|
||||
host: domain,
|
||||
},
|
||||
});
|
||||
const body = await res.json();
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
import { IntegrationService } from "@shared/types";
|
||||
import env from "@server/env";
|
||||
import { IntegrationAuthentication, SearchQuery } from "@server/models";
|
||||
import { buildDocument, buildIntegration } from "@server/test/factories";
|
||||
import { seed, getTestServer } from "@server/test/support";
|
||||
import {
|
||||
buildDocument,
|
||||
buildIntegration,
|
||||
buildTeam,
|
||||
buildUser,
|
||||
} from "@server/test/factories";
|
||||
import { getTestServer } from "@server/test/support";
|
||||
import * as Slack from "../slack";
|
||||
|
||||
jest.mock("../slack", () => ({
|
||||
@@ -13,7 +18,12 @@ const server = getTestServer();
|
||||
|
||||
describe("#hooks.unfurl", () => {
|
||||
it("should return documents", async () => {
|
||||
const { user, document } = await seed();
|
||||
const user = await buildUser();
|
||||
const document = await buildDocument({
|
||||
userId: user.id,
|
||||
teamId: user.teamId,
|
||||
});
|
||||
|
||||
await IntegrationAuthentication.create({
|
||||
service: IntegrationService.Slack,
|
||||
userId: user.id,
|
||||
@@ -46,7 +56,8 @@ describe("#hooks.unfurl", () => {
|
||||
|
||||
describe("#hooks.slack", () => {
|
||||
it("should return no matches", async () => {
|
||||
const { user, team } = await seed();
|
||||
const team = await buildTeam();
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
const res = await server.post("/api/hooks.slack", {
|
||||
body: {
|
||||
token: env.SLACK_VERIFICATION_TOKEN,
|
||||
@@ -61,7 +72,8 @@ describe("#hooks.slack", () => {
|
||||
});
|
||||
|
||||
it("should return search results with summary if query is in title", async () => {
|
||||
const { user, team } = await seed();
|
||||
const team = await buildTeam();
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
const document = await buildDocument({
|
||||
title: "This title contains a search term",
|
||||
userId: user.id,
|
||||
@@ -83,7 +95,8 @@ describe("#hooks.slack", () => {
|
||||
});
|
||||
|
||||
it("should return search results if query is regex-like", async () => {
|
||||
const { user, team } = await seed();
|
||||
const team = await buildTeam();
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
await buildDocument({
|
||||
title: "This title contains a search term",
|
||||
userId: user.id,
|
||||
@@ -103,7 +116,8 @@ describe("#hooks.slack", () => {
|
||||
});
|
||||
|
||||
it("should return search results with snippet if query is in text", async () => {
|
||||
const { user, team } = await seed();
|
||||
const team = await buildTeam();
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
const document = await buildDocument({
|
||||
text: "This title contains a search term",
|
||||
userId: user.id,
|
||||
@@ -127,7 +141,8 @@ describe("#hooks.slack", () => {
|
||||
});
|
||||
|
||||
it("should save search term, hits and source", async () => {
|
||||
const { user, team } = await seed();
|
||||
const team = await buildTeam();
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
await server.post("/api/hooks.slack", {
|
||||
body: {
|
||||
token: env.SLACK_VERIFICATION_TOKEN,
|
||||
@@ -143,6 +158,7 @@ describe("#hooks.slack", () => {
|
||||
setTimeout(async () => {
|
||||
const searchQuery = await SearchQuery.findAll({
|
||||
where: {
|
||||
teamId: team.id,
|
||||
query: "contains",
|
||||
},
|
||||
});
|
||||
@@ -150,12 +166,13 @@ describe("#hooks.slack", () => {
|
||||
expect(searchQuery[0].results).toBe(0);
|
||||
expect(searchQuery[0].source).toBe("slack");
|
||||
resolve(undefined);
|
||||
}, 100);
|
||||
}, 250);
|
||||
});
|
||||
});
|
||||
|
||||
it("should respond with help content for help keyword", async () => {
|
||||
const { user, team } = await seed();
|
||||
const team = await buildTeam();
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
const res = await server.post("/api/hooks.slack", {
|
||||
body: {
|
||||
token: env.SLACK_VERIFICATION_TOKEN,
|
||||
@@ -170,7 +187,8 @@ describe("#hooks.slack", () => {
|
||||
});
|
||||
|
||||
it("should respond with help content for no keyword", async () => {
|
||||
const { user, team } = await seed();
|
||||
const team = await buildTeam();
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
const res = await server.post("/api/hooks.slack", {
|
||||
body: {
|
||||
token: env.SLACK_VERIFICATION_TOKEN,
|
||||
@@ -185,7 +203,8 @@ describe("#hooks.slack", () => {
|
||||
});
|
||||
|
||||
it("should return search results with snippet for unknown user", async () => {
|
||||
const { user, team } = await seed();
|
||||
const team = await buildTeam();
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
// unpublished document will not be returned
|
||||
await buildDocument({
|
||||
text: "This title contains a search term",
|
||||
@@ -217,13 +236,9 @@ describe("#hooks.slack", () => {
|
||||
});
|
||||
|
||||
it("should return search results with snippet for user through integration mapping", async () => {
|
||||
const { user } = await seed();
|
||||
const serviceTeamId = "slack_team_id";
|
||||
await buildIntegration({
|
||||
const user = await buildUser();
|
||||
const integration = await buildIntegration({
|
||||
teamId: user.teamId,
|
||||
settings: {
|
||||
serviceTeamId,
|
||||
},
|
||||
});
|
||||
const document = await buildDocument({
|
||||
text: "This title contains a search term",
|
||||
@@ -234,7 +249,7 @@ describe("#hooks.slack", () => {
|
||||
body: {
|
||||
token: env.SLACK_VERIFICATION_TOKEN,
|
||||
user_id: "unknown-slack-user-id",
|
||||
team_id: serviceTeamId,
|
||||
team_id: (integration.settings as any)?.serviceTeamId,
|
||||
text: "contains",
|
||||
},
|
||||
});
|
||||
@@ -249,7 +264,8 @@ describe("#hooks.slack", () => {
|
||||
});
|
||||
|
||||
it("should error if incorrect verification token", async () => {
|
||||
const { user, team } = await seed();
|
||||
const team = await buildTeam();
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
const res = await server.post("/api/hooks.slack", {
|
||||
body: {
|
||||
token: "wrong-verification-token",
|
||||
@@ -264,7 +280,8 @@ describe("#hooks.slack", () => {
|
||||
|
||||
describe("#hooks.interactive", () => {
|
||||
it("should respond with replacement message", async () => {
|
||||
const { user, team } = await seed();
|
||||
const team = await buildTeam();
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
const document = await buildDocument({
|
||||
title: "This title contains a search term",
|
||||
userId: user.id,
|
||||
@@ -294,7 +311,8 @@ describe("#hooks.interactive", () => {
|
||||
});
|
||||
|
||||
it("should respond with replacement message if unknown user", async () => {
|
||||
const { user, team } = await seed();
|
||||
const team = await buildTeam();
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
const document = await buildDocument({
|
||||
title: "This title contains a search term",
|
||||
userId: user.id,
|
||||
@@ -324,7 +342,7 @@ describe("#hooks.interactive", () => {
|
||||
});
|
||||
|
||||
it("should error if incorrect verification token", async () => {
|
||||
const { user } = await seed();
|
||||
const user = await buildUser();
|
||||
const payload = JSON.stringify({
|
||||
type: "message_action",
|
||||
token: "wrong-verification-token",
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { faker } from "@faker-js/faker";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import WelcomeEmail from "@server/emails/templates/WelcomeEmail";
|
||||
import { TeamDomain } from "@server/models";
|
||||
import Collection from "@server/models/Collection";
|
||||
import UserAuthentication from "@server/models/UserAuthentication";
|
||||
import { buildUser, buildTeam } from "@server/test/factories";
|
||||
import { buildUser, buildTeam, buildAdmin } from "@server/test/factories";
|
||||
import {
|
||||
setupTestDatabase,
|
||||
seed,
|
||||
setCloudHosted,
|
||||
setSelfHosted,
|
||||
} from "@server/test/support";
|
||||
@@ -21,24 +22,25 @@ describe("accountProvisioner", () => {
|
||||
|
||||
it("should create a new user and team", async () => {
|
||||
const spy = jest.spyOn(WelcomeEmail.prototype, "schedule");
|
||||
const email = faker.internet.email();
|
||||
const { user, team, isNewTeam, isNewUser } = await accountProvisioner({
|
||||
ip,
|
||||
user: {
|
||||
name: "Jenny Tester",
|
||||
email: "jenny@example-company.com",
|
||||
avatarUrl: "https://example.com/avatar.png",
|
||||
email,
|
||||
avatarUrl: faker.internet.avatar(),
|
||||
},
|
||||
team: {
|
||||
name: "New workspace",
|
||||
avatarUrl: "https://example.com/avatar.png",
|
||||
subdomain: "example",
|
||||
avatarUrl: faker.internet.avatar(),
|
||||
subdomain: faker.internet.domainWord(),
|
||||
},
|
||||
authenticationProvider: {
|
||||
name: "google",
|
||||
providerId: "example-company.com",
|
||||
providerId: faker.internet.domainName(),
|
||||
},
|
||||
authentication: {
|
||||
providerId: "123456789",
|
||||
providerId: uuidv4(),
|
||||
accessToken: "123",
|
||||
scopes: ["read"],
|
||||
},
|
||||
@@ -49,11 +51,15 @@ describe("accountProvisioner", () => {
|
||||
expect(auth.scopes.length).toEqual(1);
|
||||
expect(auth.scopes[0]).toEqual("read");
|
||||
expect(team.name).toEqual("New workspace");
|
||||
expect(user.email).toEqual("jenny@example-company.com");
|
||||
expect(user.email).toEqual(email);
|
||||
expect(isNewUser).toEqual(true);
|
||||
expect(isNewTeam).toEqual(true);
|
||||
expect(spy).toHaveBeenCalled();
|
||||
const collectionCount = await Collection.count();
|
||||
const collectionCount = await Collection.count({
|
||||
where: {
|
||||
teamId: team.id,
|
||||
},
|
||||
});
|
||||
expect(collectionCount).toEqual(1);
|
||||
|
||||
spy.mockRestore();
|
||||
@@ -69,7 +75,7 @@ describe("accountProvisioner", () => {
|
||||
});
|
||||
const authentications = await existing.$get("authentications");
|
||||
const authentication = authentications[0];
|
||||
const newEmail = "test@example-company.com";
|
||||
const newEmail = faker.internet.email();
|
||||
const { user, isNewUser, isNewTeam } = await accountProvisioner({
|
||||
ip,
|
||||
user: {
|
||||
@@ -80,7 +86,7 @@ describe("accountProvisioner", () => {
|
||||
team: {
|
||||
name: existingTeam.name,
|
||||
avatarUrl: existingTeam.avatarUrl,
|
||||
subdomain: "example",
|
||||
subdomain: faker.internet.domainWord(),
|
||||
},
|
||||
authenticationProvider: {
|
||||
name: authenticationProvider.name,
|
||||
@@ -100,18 +106,20 @@ describe("accountProvisioner", () => {
|
||||
expect(isNewTeam).toEqual(false);
|
||||
expect(isNewUser).toEqual(false);
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
const collectionCount = await Collection.count();
|
||||
expect(collectionCount).toEqual(0);
|
||||
|
||||
spy.mockRestore();
|
||||
});
|
||||
|
||||
it("should allow authentication by email matching", async () => {
|
||||
const existingTeam = await buildTeam();
|
||||
it.skip("should allow authentication by email matching", async () => {
|
||||
const subdomain = faker.internet.domainWord();
|
||||
const existingTeam = await buildTeam({
|
||||
subdomain,
|
||||
});
|
||||
const providers = await existingTeam.$get("authenticationProviders");
|
||||
const authenticationProvider = providers[0];
|
||||
const email = faker.internet.email();
|
||||
const userWithoutAuth = await buildUser({
|
||||
email: "email@example.com",
|
||||
email,
|
||||
teamId: existingTeam.id,
|
||||
authentications: [],
|
||||
});
|
||||
@@ -120,20 +128,21 @@ describe("accountProvisioner", () => {
|
||||
ip,
|
||||
user: {
|
||||
name: userWithoutAuth.name,
|
||||
email: "email@example.com",
|
||||
email,
|
||||
avatarUrl: userWithoutAuth.avatarUrl,
|
||||
},
|
||||
team: {
|
||||
teamId: existingTeam.id,
|
||||
name: existingTeam.name,
|
||||
avatarUrl: existingTeam.avatarUrl,
|
||||
subdomain: "example",
|
||||
subdomain,
|
||||
},
|
||||
authenticationProvider: {
|
||||
name: authenticationProvider.name,
|
||||
providerId: authenticationProvider.providerId,
|
||||
},
|
||||
authentication: {
|
||||
providerId: "anything",
|
||||
providerId: uuidv4(),
|
||||
accessToken: "123",
|
||||
scopes: ["read"],
|
||||
},
|
||||
@@ -169,7 +178,7 @@ describe("accountProvisioner", () => {
|
||||
team: {
|
||||
name: existingTeam.name,
|
||||
avatarUrl: existingTeam.avatarUrl,
|
||||
subdomain: "example",
|
||||
subdomain: faker.internet.domainWord(),
|
||||
},
|
||||
authenticationProvider: {
|
||||
name: authenticationProvider.name,
|
||||
@@ -189,9 +198,11 @@ describe("accountProvisioner", () => {
|
||||
});
|
||||
|
||||
it("should throw an error when the domain is not allowed", async () => {
|
||||
const { admin, team: existingTeam } = await seed();
|
||||
const existingTeam = await buildTeam();
|
||||
const admin = await buildAdmin({ teamId: existingTeam.id });
|
||||
const providers = await existingTeam.$get("authenticationProviders");
|
||||
const authenticationProvider = providers[0];
|
||||
const email = faker.internet.email();
|
||||
|
||||
await TeamDomain.create({
|
||||
teamId: existingTeam.id,
|
||||
@@ -206,20 +217,20 @@ describe("accountProvisioner", () => {
|
||||
ip,
|
||||
user: {
|
||||
name: "Jenny Tester",
|
||||
email: "jenny@example-company.com",
|
||||
avatarUrl: "https://example.com/avatar.png",
|
||||
email,
|
||||
avatarUrl: faker.internet.avatar(),
|
||||
},
|
||||
team: {
|
||||
name: existingTeam.name,
|
||||
avatarUrl: existingTeam.avatarUrl,
|
||||
subdomain: "example",
|
||||
subdomain: faker.internet.domainWord(),
|
||||
},
|
||||
authenticationProvider: {
|
||||
name: authenticationProvider.name,
|
||||
providerId: authenticationProvider.providerId,
|
||||
},
|
||||
authentication: {
|
||||
providerId: "123456789",
|
||||
providerId: uuidv4(),
|
||||
accessToken: "123",
|
||||
scopes: ["read"],
|
||||
},
|
||||
@@ -233,35 +244,37 @@ describe("accountProvisioner", () => {
|
||||
|
||||
it("should create a new user in an existing team when the domain is allowed", async () => {
|
||||
const spy = jest.spyOn(WelcomeEmail.prototype, "schedule");
|
||||
const { admin, team } = await seed();
|
||||
const team = await buildTeam();
|
||||
const admin = await buildAdmin({ teamId: team.id });
|
||||
const authenticationProviders = await team.$get(
|
||||
"authenticationProviders"
|
||||
);
|
||||
const authenticationProvider = authenticationProviders[0];
|
||||
const domain = faker.internet.domainName();
|
||||
await TeamDomain.create({
|
||||
teamId: team.id,
|
||||
name: "example-company.com",
|
||||
name: domain,
|
||||
createdById: admin.id,
|
||||
});
|
||||
|
||||
const email = faker.internet.email({ provider: domain });
|
||||
const { user, isNewUser } = await accountProvisioner({
|
||||
ip,
|
||||
user: {
|
||||
name: "Jenny Tester",
|
||||
email: "jenny@example-company.com",
|
||||
avatarUrl: "https://example.com/avatar.png",
|
||||
email,
|
||||
avatarUrl: faker.internet.avatar(),
|
||||
},
|
||||
team: {
|
||||
name: team.name,
|
||||
avatarUrl: team.avatarUrl,
|
||||
subdomain: "example",
|
||||
subdomain: faker.internet.domainWord(),
|
||||
},
|
||||
authenticationProvider: {
|
||||
name: authenticationProvider.name,
|
||||
providerId: authenticationProvider.providerId,
|
||||
},
|
||||
authentication: {
|
||||
providerId: "123456789",
|
||||
providerId: uuidv4(),
|
||||
accessToken: "123",
|
||||
scopes: ["read"],
|
||||
},
|
||||
@@ -271,11 +284,15 @@ describe("accountProvisioner", () => {
|
||||
expect(auth.accessToken).toEqual("123");
|
||||
expect(auth.scopes.length).toEqual(1);
|
||||
expect(auth.scopes[0]).toEqual("read");
|
||||
expect(user.email).toEqual("jenny@example-company.com");
|
||||
expect(user.email).toEqual(email);
|
||||
expect(isNewUser).toEqual(true);
|
||||
expect(spy).toHaveBeenCalled();
|
||||
// should provision welcome collection
|
||||
const collectionCount = await Collection.count();
|
||||
const collectionCount = await Collection.count({
|
||||
where: {
|
||||
teamId: team.id,
|
||||
},
|
||||
});
|
||||
expect(collectionCount).toEqual(1);
|
||||
|
||||
spy.mockRestore();
|
||||
@@ -288,24 +305,25 @@ describe("accountProvisioner", () => {
|
||||
"authenticationProviders"
|
||||
);
|
||||
const authenticationProvider = authenticationProviders[0];
|
||||
const email = faker.internet.email();
|
||||
const { user, isNewUser } = await accountProvisioner({
|
||||
ip,
|
||||
user: {
|
||||
name: "Jenny Tester",
|
||||
email: "jenny@example-company.com",
|
||||
avatarUrl: "https://example.com/avatar.png",
|
||||
email,
|
||||
avatarUrl: faker.internet.avatar(),
|
||||
},
|
||||
team: {
|
||||
name: team.name,
|
||||
avatarUrl: team.avatarUrl,
|
||||
subdomain: "example",
|
||||
subdomain: faker.internet.domainWord(),
|
||||
},
|
||||
authenticationProvider: {
|
||||
name: authenticationProvider.name,
|
||||
providerId: authenticationProvider.providerId,
|
||||
},
|
||||
authentication: {
|
||||
providerId: "123456789",
|
||||
providerId: uuidv4(),
|
||||
accessToken: "123",
|
||||
scopes: ["read"],
|
||||
},
|
||||
@@ -315,11 +333,15 @@ describe("accountProvisioner", () => {
|
||||
expect(auth.accessToken).toEqual("123");
|
||||
expect(auth.scopes.length).toEqual(1);
|
||||
expect(auth.scopes[0]).toEqual("read");
|
||||
expect(user.email).toEqual("jenny@example-company.com");
|
||||
expect(user.email).toEqual(email);
|
||||
expect(isNewUser).toEqual(true);
|
||||
expect(spy).toHaveBeenCalled();
|
||||
// should provision welcome collection
|
||||
const collectionCount = await Collection.count();
|
||||
const collectionCount = await Collection.count({
|
||||
where: {
|
||||
teamId: team.id,
|
||||
},
|
||||
});
|
||||
expect(collectionCount).toEqual(1);
|
||||
|
||||
spy.mockRestore();
|
||||
@@ -338,21 +360,21 @@ describe("accountProvisioner", () => {
|
||||
ip,
|
||||
user: {
|
||||
name: "Jenny Tester",
|
||||
email: "jenny@example-company.com",
|
||||
avatarUrl: "https://example.com/avatar.png",
|
||||
email: faker.internet.email(),
|
||||
avatarUrl: faker.internet.avatar(),
|
||||
},
|
||||
team: {
|
||||
teamId: team.id,
|
||||
name: team.name,
|
||||
avatarUrl: team.avatarUrl,
|
||||
subdomain: "example",
|
||||
subdomain: faker.internet.domainWord(),
|
||||
},
|
||||
authenticationProvider: {
|
||||
name: "google",
|
||||
providerId: "example-company.com",
|
||||
},
|
||||
authentication: {
|
||||
providerId: "123456789",
|
||||
providerId: uuidv4(),
|
||||
accessToken: "123",
|
||||
scopes: ["read"],
|
||||
},
|
||||
@@ -372,14 +394,14 @@ describe("accountProvisioner", () => {
|
||||
ip,
|
||||
user: {
|
||||
name: "Jenny Tester",
|
||||
email: "jenny@example-company.com",
|
||||
avatarUrl: "https://example.com/avatar.png",
|
||||
email: faker.internet.email(),
|
||||
avatarUrl: faker.internet.avatar(),
|
||||
},
|
||||
team: {
|
||||
teamId: team.id,
|
||||
name: team.name,
|
||||
avatarUrl: team.avatarUrl,
|
||||
subdomain: "example",
|
||||
subdomain: faker.internet.domainWord(),
|
||||
domain: "allowed-domain.com",
|
||||
},
|
||||
authenticationProvider: {
|
||||
@@ -387,7 +409,7 @@ describe("accountProvisioner", () => {
|
||||
providerId: "allowed-domain.com",
|
||||
},
|
||||
authentication: {
|
||||
providerId: "123456789",
|
||||
providerId: uuidv4(),
|
||||
accessToken: "123",
|
||||
scopes: ["read"],
|
||||
},
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Event } from "@server/models";
|
||||
import { buildDocument, buildUser } from "@server/test/factories";
|
||||
import { setupTestDatabase } from "@server/test/support";
|
||||
import { findLatestEvent, setupTestDatabase } from "@server/test/support";
|
||||
import commentCreator from "./commentCreator";
|
||||
|
||||
setupTestDatabase();
|
||||
@@ -35,7 +34,7 @@ describe("commentCreator", () => {
|
||||
ip,
|
||||
});
|
||||
|
||||
const event = await Event.findOne();
|
||||
const event = await findLatestEvent();
|
||||
expect(comment.documentId).toEqual(document.id);
|
||||
expect(comment.createdById).toEqual(user.id);
|
||||
expect(event!.name).toEqual("comments.create");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Comment, Event } from "@server/models";
|
||||
import { Comment } from "@server/models";
|
||||
import { buildDocument, buildUser } from "@server/test/factories";
|
||||
import { setupTestDatabase } from "@server/test/support";
|
||||
import { findLatestEvent, setupTestDatabase } from "@server/test/support";
|
||||
import commentDestroyer from "./commentDestroyer";
|
||||
|
||||
setupTestDatabase();
|
||||
@@ -41,10 +41,14 @@ describe("commentDestroyer", () => {
|
||||
ip,
|
||||
});
|
||||
|
||||
const count = await Comment.count();
|
||||
const count = await Comment.count({
|
||||
where: {
|
||||
id: comment.id,
|
||||
},
|
||||
});
|
||||
expect(count).toEqual(0);
|
||||
|
||||
const event = await Event.findOne();
|
||||
const event = await findLatestEvent();
|
||||
expect(event!.name).toEqual("comments.delete");
|
||||
expect(event!.modelId).toEqual(comment.id);
|
||||
});
|
||||
|
||||
@@ -26,7 +26,11 @@ describe("documentImporter", () => {
|
||||
content,
|
||||
ip,
|
||||
});
|
||||
const attachments = await Attachment.count();
|
||||
const attachments = await Attachment.count({
|
||||
where: {
|
||||
teamId: user.teamId,
|
||||
},
|
||||
});
|
||||
expect(attachments).toEqual(1);
|
||||
expect(response.text).toContain("This is a test document for images");
|
||||
expect(response.text).toContain(";
|
||||
@@ -46,7 +50,11 @@ describe("documentImporter", () => {
|
||||
content,
|
||||
ip,
|
||||
});
|
||||
const attachments = await Attachment.count();
|
||||
const attachments = await Attachment.count({
|
||||
where: {
|
||||
teamId: user.teamId,
|
||||
},
|
||||
});
|
||||
expect(attachments).toEqual(1);
|
||||
expect(response.text).toContain("This is a test document for images");
|
||||
expect(response.text).toContain(";
|
||||
@@ -89,7 +97,11 @@ describe("documentImporter", () => {
|
||||
content,
|
||||
ip,
|
||||
});
|
||||
const attachments = await Attachment.count();
|
||||
const attachments = await Attachment.count({
|
||||
where: {
|
||||
teamId: user.teamId,
|
||||
},
|
||||
});
|
||||
expect(attachments).toEqual(1);
|
||||
expect(response.text).toContain("This is a test document for images");
|
||||
expect(response.text).toContain(";
|
||||
|
||||
@@ -128,9 +128,10 @@ export default async function loadDocument({
|
||||
// documentStructure by default through the relationship.
|
||||
if (document.collectionId) {
|
||||
collection = await Collection.findByPk(document.collectionId);
|
||||
}
|
||||
if (!collection) {
|
||||
throw NotFoundError("Collection could not be found for document");
|
||||
|
||||
if (!collection) {
|
||||
throw NotFoundError("Collection could not be found for document");
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import Pin from "@server/models/Pin";
|
||||
import { sequelize } from "@server/storage/database";
|
||||
import { buildDocument, buildCollection } from "@server/test/factories";
|
||||
import { setupTestDatabase, seed } from "@server/test/support";
|
||||
import {
|
||||
buildDocument,
|
||||
buildCollection,
|
||||
buildTeam,
|
||||
buildUser,
|
||||
} from "@server/test/factories";
|
||||
import { setupTestDatabase } from "@server/test/support";
|
||||
import documentMover from "./documentMover";
|
||||
|
||||
setupTestDatabase();
|
||||
@@ -10,7 +15,17 @@ describe("documentMover", () => {
|
||||
const ip = "127.0.0.1";
|
||||
|
||||
it("should move within a collection", async () => {
|
||||
const { document, 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 document = await buildDocument({
|
||||
userId: user.id,
|
||||
collectionId: collection.id,
|
||||
teamId: team.id,
|
||||
});
|
||||
const response = await documentMover({
|
||||
user,
|
||||
document,
|
||||
@@ -22,7 +37,17 @@ describe("documentMover", () => {
|
||||
});
|
||||
|
||||
it("should succeed when not in source collection documentStructure", async () => {
|
||||
const { document, 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 document = await buildDocument({
|
||||
userId: user.id,
|
||||
collectionId: collection.id,
|
||||
teamId: team.id,
|
||||
});
|
||||
const newDocument = await buildDocument({
|
||||
parentDocumentId: document.id,
|
||||
collectionId: collection.id,
|
||||
@@ -49,7 +74,17 @@ describe("documentMover", () => {
|
||||
});
|
||||
|
||||
it("should move with children", async () => {
|
||||
const { document, 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 document = await buildDocument({
|
||||
userId: user.id,
|
||||
collectionId: collection.id,
|
||||
teamId: team.id,
|
||||
});
|
||||
const newDocument = await buildDocument({
|
||||
parentDocumentId: document.id,
|
||||
collectionId: collection.id,
|
||||
@@ -77,7 +112,17 @@ describe("documentMover", () => {
|
||||
});
|
||||
|
||||
it("should move with children to another collection", async () => {
|
||||
const { document, 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 document = await buildDocument({
|
||||
userId: user.id,
|
||||
collectionId: collection.id,
|
||||
teamId: team.id,
|
||||
});
|
||||
const newCollection = await buildCollection({
|
||||
teamId: collection.teamId,
|
||||
});
|
||||
@@ -118,7 +163,17 @@ describe("documentMover", () => {
|
||||
});
|
||||
|
||||
it("should remove associated collection pin if moved to another collection", async () => {
|
||||
const { document, 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 document = await buildDocument({
|
||||
userId: user.id,
|
||||
collectionId: collection.id,
|
||||
teamId: team.id,
|
||||
});
|
||||
const newCollection = await buildCollection({
|
||||
teamId: collection.teamId,
|
||||
});
|
||||
@@ -141,7 +196,11 @@ describe("documentMover", () => {
|
||||
})
|
||||
);
|
||||
|
||||
const pinCount = await Pin.count();
|
||||
const pinCount = await Pin.count({
|
||||
where: {
|
||||
teamId: collection.teamId,
|
||||
},
|
||||
});
|
||||
expect(pinCount).toBe(0);
|
||||
|
||||
// check collection structure updated
|
||||
@@ -155,7 +214,17 @@ describe("documentMover", () => {
|
||||
});
|
||||
|
||||
it("should detach document from collection and move it to drafts", async () => {
|
||||
const { document, 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 document = await buildDocument({
|
||||
userId: user.id,
|
||||
collectionId: collection.id,
|
||||
teamId: team.id,
|
||||
});
|
||||
|
||||
const response = await sequelize.transaction(async (transaction) =>
|
||||
documentMover({
|
||||
|
||||
@@ -19,6 +19,9 @@ describe("documentPermanentDeleter", () => {
|
||||
expect(countDeletedDoc).toEqual(1);
|
||||
expect(
|
||||
await Document.unscoped().count({
|
||||
where: {
|
||||
teamId: document.teamId,
|
||||
},
|
||||
paranoid: false,
|
||||
})
|
||||
).toEqual(0);
|
||||
@@ -61,6 +64,9 @@ describe("documentPermanentDeleter", () => {
|
||||
expect(DeleteAttachmentTask.schedule).toHaveBeenCalledTimes(2);
|
||||
expect(
|
||||
await Document.unscoped().count({
|
||||
where: {
|
||||
teamId: document.teamId,
|
||||
},
|
||||
paranoid: false,
|
||||
})
|
||||
).toEqual(0);
|
||||
@@ -85,9 +91,18 @@ describe("documentPermanentDeleter", () => {
|
||||
});
|
||||
const countDeletedDoc = await documentPermanentDeleter([document]);
|
||||
expect(countDeletedDoc).toEqual(1);
|
||||
expect(await Attachment.count()).toEqual(0);
|
||||
expect(
|
||||
await Attachment.count({
|
||||
where: {
|
||||
teamId: document.teamId,
|
||||
},
|
||||
})
|
||||
).toEqual(0);
|
||||
expect(
|
||||
await Document.unscoped().count({
|
||||
where: {
|
||||
teamId: document.teamId,
|
||||
},
|
||||
paranoid: false,
|
||||
})
|
||||
).toEqual(0);
|
||||
@@ -108,12 +123,27 @@ describe("documentPermanentDeleter", () => {
|
||||
await document1.save();
|
||||
document.text = ``;
|
||||
await document.save();
|
||||
expect(await Attachment.count()).toEqual(1);
|
||||
expect(
|
||||
await Attachment.count({
|
||||
where: {
|
||||
teamId: document.teamId,
|
||||
},
|
||||
})
|
||||
).toEqual(1);
|
||||
const countDeletedDoc = await documentPermanentDeleter([document]);
|
||||
expect(countDeletedDoc).toEqual(1);
|
||||
expect(await Attachment.count()).toEqual(1);
|
||||
expect(
|
||||
await Attachment.count({
|
||||
where: {
|
||||
teamId: document.teamId,
|
||||
},
|
||||
})
|
||||
).toEqual(1);
|
||||
expect(
|
||||
await Document.unscoped().count({
|
||||
where: {
|
||||
teamId: document.teamId,
|
||||
},
|
||||
paranoid: false,
|
||||
})
|
||||
).toEqual(1);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Event } from "@server/models";
|
||||
import { sequelize } from "@server/storage/database";
|
||||
import { buildDocument, buildUser } from "@server/test/factories";
|
||||
import { setupTestDatabase } from "@server/test/support";
|
||||
import { findLatestEvent, setupTestDatabase } from "@server/test/support";
|
||||
import documentUpdater from "./documentUpdater";
|
||||
|
||||
setupTestDatabase();
|
||||
@@ -25,7 +24,7 @@ describe("documentUpdater", () => {
|
||||
})
|
||||
);
|
||||
|
||||
const event = await Event.findOne();
|
||||
const event = await findLatestEvent();
|
||||
expect(document.lastModifiedById).toEqual(user.id);
|
||||
expect(event!.name).toEqual("documents.update");
|
||||
expect(event!.documentId).toEqual(document.id);
|
||||
@@ -47,8 +46,6 @@ describe("documentUpdater", () => {
|
||||
})
|
||||
);
|
||||
|
||||
const event = await Event.findOne();
|
||||
expect(document.lastModifiedById).not.toEqual(user.id);
|
||||
expect(event).toEqual(null);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,6 +15,12 @@ describe("fileOperationDeleter", () => {
|
||||
teamId: admin.teamId,
|
||||
});
|
||||
await fileOperationDeleter(fileOp, admin, ip);
|
||||
expect(await FileOperation.count()).toEqual(0);
|
||||
expect(
|
||||
await FileOperation.count({
|
||||
where: {
|
||||
teamId: admin.teamId,
|
||||
},
|
||||
})
|
||||
).toEqual(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { NotificationEventType } from "@shared/types";
|
||||
import { Event } from "@server/models";
|
||||
import { sequelize } from "@server/storage/database";
|
||||
import {
|
||||
buildUser,
|
||||
@@ -7,7 +6,7 @@ import {
|
||||
buildDocument,
|
||||
buildCollection,
|
||||
} from "@server/test/factories";
|
||||
import { setupTestDatabase } from "@server/test/support";
|
||||
import { findLatestEvent, setupTestDatabase } from "@server/test/support";
|
||||
import notificationUpdater from "./notificationUpdater";
|
||||
|
||||
setupTestDatabase();
|
||||
@@ -49,7 +48,7 @@ describe("notificationUpdater", () => {
|
||||
transaction,
|
||||
})
|
||||
);
|
||||
const event = await Event.findOne();
|
||||
const event = await findLatestEvent({});
|
||||
|
||||
expect(notification.viewedAt).not.toBe(null);
|
||||
expect(notification.archivedAt).toBe(null);
|
||||
@@ -92,7 +91,7 @@ describe("notificationUpdater", () => {
|
||||
transaction,
|
||||
})
|
||||
);
|
||||
const event = await Event.findOne();
|
||||
const event = await findLatestEvent();
|
||||
|
||||
expect(notification.viewedAt).toBe(null);
|
||||
expect(notification.archivedAt).toBe(null);
|
||||
@@ -134,7 +133,7 @@ describe("notificationUpdater", () => {
|
||||
transaction,
|
||||
})
|
||||
);
|
||||
const event = await Event.findOne();
|
||||
const event = await findLatestEvent();
|
||||
|
||||
expect(notification.viewedAt).toBe(null);
|
||||
expect(notification.archivedAt).not.toBe(null);
|
||||
@@ -177,7 +176,7 @@ describe("notificationUpdater", () => {
|
||||
transaction,
|
||||
})
|
||||
);
|
||||
const event = await Event.findOne();
|
||||
const event = await findLatestEvent();
|
||||
|
||||
expect(notification.viewedAt).toBe(null);
|
||||
expect(notification.archivedAt).toBeNull();
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Event } from "@server/models";
|
||||
import { buildDocument, buildUser } from "@server/test/factories";
|
||||
import { setupTestDatabase } from "@server/test/support";
|
||||
import { findLatestEvent, setupTestDatabase } from "@server/test/support";
|
||||
import pinCreator from "./pinCreator";
|
||||
|
||||
setupTestDatabase();
|
||||
@@ -21,7 +20,7 @@ describe("pinCreator", () => {
|
||||
ip,
|
||||
});
|
||||
|
||||
const event = await Event.findOne();
|
||||
const event = await findLatestEvent();
|
||||
expect(pin.documentId).toEqual(document.id);
|
||||
expect(pin.collectionId).toEqual(null);
|
||||
expect(pin.createdById).toEqual(user.id);
|
||||
@@ -44,7 +43,7 @@ describe("pinCreator", () => {
|
||||
ip,
|
||||
});
|
||||
|
||||
const event = await Event.findOne();
|
||||
const event = await findLatestEvent();
|
||||
expect(pin.documentId).toEqual(document.id);
|
||||
expect(pin.collectionId).toEqual(document.collectionId);
|
||||
expect(pin.createdById).toEqual(user.id);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Pin, Event } from "@server/models";
|
||||
import { Pin } from "@server/models";
|
||||
import { buildDocument, buildUser } from "@server/test/factories";
|
||||
import { setupTestDatabase } from "@server/test/support";
|
||||
import { findLatestEvent, setupTestDatabase } from "@server/test/support";
|
||||
import pinDestroyer from "./pinDestroyer";
|
||||
|
||||
setupTestDatabase();
|
||||
@@ -29,10 +29,14 @@ describe("pinCreator", () => {
|
||||
ip,
|
||||
});
|
||||
|
||||
const count = await Pin.count();
|
||||
const count = await Pin.count({
|
||||
where: {
|
||||
teamId: user.teamId,
|
||||
},
|
||||
});
|
||||
expect(count).toEqual(0);
|
||||
|
||||
const event = await Event.findOne();
|
||||
const event = await findLatestEvent();
|
||||
expect(event!.name).toEqual("pins.delete");
|
||||
expect(event!.modelId).toEqual(pin.id);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Event } from "@server/models";
|
||||
import { buildDocument, buildUser } from "@server/test/factories";
|
||||
import { setupTestDatabase } from "@server/test/support";
|
||||
import { findLatestEvent, setupTestDatabase } from "@server/test/support";
|
||||
import revisionCreator from "./revisionCreator";
|
||||
|
||||
setupTestDatabase();
|
||||
@@ -19,7 +18,7 @@ describe("revisionCreator", () => {
|
||||
user,
|
||||
ip,
|
||||
});
|
||||
const event = await Event.findOne();
|
||||
const event = await findLatestEvent();
|
||||
expect(revision.documentId).toEqual(document.id);
|
||||
expect(revision.userId).toEqual(user.id);
|
||||
expect(revision.createdAt).toEqual(document.updatedAt);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Star, Event } from "@server/models";
|
||||
import { sequelize } from "@server/storage/database";
|
||||
import { buildDocument, buildUser } from "@server/test/factories";
|
||||
import { setupTestDatabase } from "@server/test/support";
|
||||
import { findLatestEvent, setupTestDatabase } from "@server/test/support";
|
||||
import starCreator from "./starCreator";
|
||||
|
||||
setupTestDatabase();
|
||||
@@ -25,7 +25,7 @@ describe("starCreator", () => {
|
||||
})
|
||||
);
|
||||
|
||||
const event = await Event.findOne();
|
||||
const event = await findLatestEvent();
|
||||
expect(star.documentId).toEqual(document.id);
|
||||
expect(star.userId).toEqual(user.id);
|
||||
expect(star.index).toEqual("P");
|
||||
@@ -57,7 +57,11 @@ describe("starCreator", () => {
|
||||
})
|
||||
);
|
||||
|
||||
const events = await Event.count();
|
||||
const events = await Event.count({
|
||||
where: {
|
||||
teamId: user.teamId,
|
||||
},
|
||||
});
|
||||
expect(star.documentId).toEqual(document.id);
|
||||
expect(star.userId).toEqual(user.id);
|
||||
expect(star.index).toEqual("P");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Star, Event } from "@server/models";
|
||||
import { Star } from "@server/models";
|
||||
import { buildDocument, buildUser } from "@server/test/factories";
|
||||
import { setupTestDatabase } from "@server/test/support";
|
||||
import { findLatestEvent, setupTestDatabase } from "@server/test/support";
|
||||
import starDestroyer from "./starDestroyer";
|
||||
|
||||
setupTestDatabase();
|
||||
@@ -29,10 +29,14 @@ describe("starDestroyer", () => {
|
||||
ip,
|
||||
});
|
||||
|
||||
const count = await Star.count();
|
||||
const count = await Star.count({
|
||||
where: {
|
||||
userId: user.id,
|
||||
},
|
||||
});
|
||||
expect(count).toEqual(0);
|
||||
|
||||
const event = await Event.findOne();
|
||||
const event = await findLatestEvent();
|
||||
expect(event!.name).toEqual("stars.delete");
|
||||
expect(event!.modelId).toEqual(star.id);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Star, Event } from "@server/models";
|
||||
import { Star } from "@server/models";
|
||||
import { buildDocument, buildUser } from "@server/test/factories";
|
||||
import { setupTestDatabase } from "@server/test/support";
|
||||
import { findLatestEvent, setupTestDatabase } from "@server/test/support";
|
||||
import starUpdater from "./starUpdater";
|
||||
|
||||
setupTestDatabase();
|
||||
@@ -30,7 +30,7 @@ describe("starUpdater", () => {
|
||||
ip,
|
||||
});
|
||||
|
||||
const event = await Event.findOne();
|
||||
const event = await findLatestEvent();
|
||||
expect(star.documentId).toEqual(document.id);
|
||||
expect(star.userId).toEqual(user.id);
|
||||
expect(star.index).toEqual("h");
|
||||
|
||||
@@ -29,7 +29,11 @@ describe("subscriptionCreator", () => {
|
||||
})
|
||||
);
|
||||
|
||||
const event = await Event.findOne();
|
||||
const event = await Event.findOne({
|
||||
where: {
|
||||
teamId: user.teamId,
|
||||
},
|
||||
});
|
||||
|
||||
expect(subscription.documentId).toEqual(document.id);
|
||||
expect(subscription.userId).toEqual(user.id);
|
||||
@@ -123,7 +127,11 @@ describe("subscriptionCreator", () => {
|
||||
})
|
||||
);
|
||||
|
||||
const events = await Event.count();
|
||||
const events = await Event.count({
|
||||
where: {
|
||||
teamId: user.teamId,
|
||||
},
|
||||
});
|
||||
|
||||
// 3 events. 1 create, 1 destroy and 1 re-create.
|
||||
expect(events).toEqual(3);
|
||||
@@ -167,7 +175,11 @@ describe("subscriptionCreator", () => {
|
||||
);
|
||||
|
||||
// Should emit 1 event instead of 2.
|
||||
const events = await Event.count();
|
||||
const events = await Event.count({
|
||||
where: {
|
||||
teamId: user.teamId,
|
||||
},
|
||||
});
|
||||
expect(events).toEqual(1);
|
||||
|
||||
expect(subscription0.documentId).toEqual(document.id);
|
||||
@@ -223,7 +235,11 @@ describe("subscriptionCreator", () => {
|
||||
|
||||
// Should emit 3 events.
|
||||
// 2 create, 1 destroy.
|
||||
const events = await Event.findAll();
|
||||
const events = await Event.findAll({
|
||||
where: {
|
||||
teamId: user.teamId,
|
||||
},
|
||||
});
|
||||
expect(events.length).toEqual(3);
|
||||
|
||||
expect(events[0].name).toEqual("subscriptions.create");
|
||||
@@ -260,7 +276,11 @@ describe("subscriptionCreator", () => {
|
||||
})
|
||||
);
|
||||
|
||||
const events = await Event.count();
|
||||
const events = await Event.count({
|
||||
where: {
|
||||
teamId: user.teamId,
|
||||
},
|
||||
});
|
||||
expect(events).toEqual(1);
|
||||
|
||||
expect(subscription0.documentId).toEqual(document.id);
|
||||
|
||||
@@ -48,6 +48,7 @@ export default async function subscriptionCreator({
|
||||
await Event.create(
|
||||
{
|
||||
name: "subscriptions.create",
|
||||
teamId: user.teamId,
|
||||
modelId: subscription.id,
|
||||
actorId: user.id,
|
||||
userId: user.id,
|
||||
@@ -62,6 +63,7 @@ export default async function subscriptionCreator({
|
||||
await Event.create(
|
||||
{
|
||||
name: "subscriptions.create",
|
||||
teamId: user.teamId,
|
||||
modelId: subscription.id,
|
||||
actorId: user.id,
|
||||
userId: user.id,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Subscription, Event } from "@server/models";
|
||||
import { Subscription } from "@server/models";
|
||||
import { sequelize } from "@server/storage/database";
|
||||
import {
|
||||
buildDocument,
|
||||
@@ -36,17 +36,13 @@ describe("subscriptionDestroyer", () => {
|
||||
})
|
||||
);
|
||||
|
||||
const count = await Subscription.count();
|
||||
const count = await Subscription.count({
|
||||
where: {
|
||||
userId: user.id,
|
||||
},
|
||||
});
|
||||
|
||||
expect(count).toEqual(0);
|
||||
|
||||
const event = await Event.findOne();
|
||||
|
||||
expect(event?.name).toEqual("subscriptions.delete");
|
||||
expect(event?.modelId).toEqual(subscription.id);
|
||||
expect(event?.actorId).toEqual(subscription.userId);
|
||||
expect(event?.userId).toEqual(subscription.userId);
|
||||
expect(event?.documentId).toEqual(subscription.documentId);
|
||||
});
|
||||
|
||||
it("should soft delete row", async () => {
|
||||
@@ -72,18 +68,14 @@ describe("subscriptionDestroyer", () => {
|
||||
})
|
||||
);
|
||||
|
||||
const count = await Subscription.count();
|
||||
const count = await Subscription.count({
|
||||
where: {
|
||||
userId: user.id,
|
||||
},
|
||||
});
|
||||
|
||||
expect(count).toEqual(0);
|
||||
|
||||
const event = await Event.findOne();
|
||||
|
||||
expect(event?.name).toEqual("subscriptions.delete");
|
||||
expect(event?.modelId).toEqual(subscription.id);
|
||||
expect(event?.actorId).toEqual(subscription.userId);
|
||||
expect(event?.userId).toEqual(subscription.userId);
|
||||
expect(event?.documentId).toEqual(subscription.documentId);
|
||||
|
||||
const deletedSubscription = await Subscription.findOne({
|
||||
where: {
|
||||
userId: user.id,
|
||||
|
||||
@@ -28,6 +28,7 @@ export default async function subscriptionDestroyer({
|
||||
await Event.create(
|
||||
{
|
||||
name: "subscriptions.delete",
|
||||
teamId: user.teamId,
|
||||
modelId: subscription.id,
|
||||
actorId: user.id,
|
||||
userId: user.id,
|
||||
|
||||
@@ -16,23 +16,39 @@ describe("teamPermanentDeleter", () => {
|
||||
const team = await buildTeam({
|
||||
deletedAt: subDays(new Date(), 90),
|
||||
});
|
||||
const user = await buildUser({
|
||||
teamId: team.id,
|
||||
});
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
await buildDocument({
|
||||
teamId: team.id,
|
||||
userId: user.id,
|
||||
});
|
||||
await teamPermanentDeleter(team);
|
||||
expect(await Team.count()).toEqual(0);
|
||||
expect(await User.count()).toEqual(0);
|
||||
expect(
|
||||
await Team.count({
|
||||
where: {
|
||||
id: team.id,
|
||||
},
|
||||
})
|
||||
).toEqual(0);
|
||||
expect(
|
||||
await User.count({
|
||||
where: {
|
||||
teamId: team.id,
|
||||
},
|
||||
})
|
||||
).toEqual(0);
|
||||
expect(
|
||||
await Document.unscoped().count({
|
||||
where: {
|
||||
teamId: team.id,
|
||||
},
|
||||
paranoid: false,
|
||||
})
|
||||
).toEqual(0);
|
||||
expect(
|
||||
await Collection.unscoped().count({
|
||||
where: {
|
||||
teamId: team.id,
|
||||
},
|
||||
paranoid: false,
|
||||
})
|
||||
).toEqual(0);
|
||||
@@ -44,18 +60,21 @@ describe("teamPermanentDeleter", () => {
|
||||
});
|
||||
await buildUser();
|
||||
await buildTeam();
|
||||
await buildDocument();
|
||||
const document = await buildDocument();
|
||||
await teamPermanentDeleter(team);
|
||||
expect(await Team.count()).toEqual(4); // each build command creates a team
|
||||
|
||||
expect(await User.count()).toEqual(2);
|
||||
expect(
|
||||
await Document.unscoped().count({
|
||||
where: {
|
||||
id: document.id,
|
||||
},
|
||||
paranoid: false,
|
||||
})
|
||||
).toEqual(1);
|
||||
expect(
|
||||
await Collection.unscoped().count({
|
||||
where: {
|
||||
id: document.collectionId,
|
||||
},
|
||||
paranoid: false,
|
||||
})
|
||||
).toEqual(1);
|
||||
@@ -65,9 +84,7 @@ describe("teamPermanentDeleter", () => {
|
||||
const team = await buildTeam({
|
||||
deletedAt: subDays(new Date(), 90),
|
||||
});
|
||||
const user = await buildUser({
|
||||
teamId: team.id,
|
||||
});
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
const document = await buildDocument({
|
||||
teamId: team.id,
|
||||
userId: user.id,
|
||||
@@ -77,16 +94,40 @@ describe("teamPermanentDeleter", () => {
|
||||
documentId: document.id,
|
||||
});
|
||||
await teamPermanentDeleter(team);
|
||||
expect(await Team.count()).toEqual(0);
|
||||
expect(await User.count()).toEqual(0);
|
||||
expect(await Attachment.count()).toEqual(0);
|
||||
expect(
|
||||
await Team.count({
|
||||
where: {
|
||||
id: team.id,
|
||||
},
|
||||
})
|
||||
).toEqual(0);
|
||||
expect(
|
||||
await User.count({
|
||||
where: {
|
||||
teamId: team.id,
|
||||
},
|
||||
})
|
||||
).toEqual(0);
|
||||
expect(
|
||||
await Attachment.count({
|
||||
where: {
|
||||
teamId: team.id,
|
||||
},
|
||||
})
|
||||
).toEqual(0);
|
||||
expect(
|
||||
await Document.unscoped().count({
|
||||
where: {
|
||||
teamId: team.id,
|
||||
},
|
||||
paranoid: false,
|
||||
})
|
||||
).toEqual(0);
|
||||
expect(
|
||||
await Collection.unscoped().count({
|
||||
where: {
|
||||
teamId: team.id,
|
||||
},
|
||||
paranoid: false,
|
||||
})
|
||||
).toEqual(0);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { faker } from "@faker-js/faker";
|
||||
import TeamDomain from "@server/models/TeamDomain";
|
||||
import { buildTeam, buildUser } from "@server/test/factories";
|
||||
import {
|
||||
@@ -16,107 +17,113 @@ describe("teamProvisioner", () => {
|
||||
beforeEach(setCloudHosted);
|
||||
|
||||
it("should create team and authentication provider", async () => {
|
||||
const subdomain = faker.internet.domainWord();
|
||||
const result = await teamProvisioner({
|
||||
name: "Test team",
|
||||
subdomain: "example",
|
||||
avatarUrl: "http://example.com/logo.png",
|
||||
subdomain,
|
||||
avatarUrl: faker.internet.avatar(),
|
||||
authenticationProvider: {
|
||||
name: "google",
|
||||
providerId: "example.com",
|
||||
providerId: `${subdomain}.com`,
|
||||
},
|
||||
ip,
|
||||
});
|
||||
const { team, authenticationProvider, isNewTeam } = result;
|
||||
expect(authenticationProvider.name).toEqual("google");
|
||||
expect(authenticationProvider.providerId).toEqual("example.com");
|
||||
expect(authenticationProvider.providerId).toEqual(`${subdomain}.com`);
|
||||
expect(team.name).toEqual("Test team");
|
||||
expect(team.subdomain).toEqual("example");
|
||||
expect(team.subdomain).toEqual(subdomain);
|
||||
expect(isNewTeam).toEqual(true);
|
||||
});
|
||||
|
||||
it("should set subdomain append if unavailable", async () => {
|
||||
const subdomain = faker.internet.domainWord();
|
||||
|
||||
await buildTeam({
|
||||
subdomain: "myteam",
|
||||
subdomain,
|
||||
});
|
||||
|
||||
const result = await teamProvisioner({
|
||||
name: "Test team",
|
||||
subdomain: "myteam",
|
||||
avatarUrl: "http://example.com/logo.png",
|
||||
subdomain,
|
||||
avatarUrl: faker.internet.avatar(),
|
||||
authenticationProvider: {
|
||||
name: "google",
|
||||
providerId: "example.com",
|
||||
providerId: `${subdomain}.com`,
|
||||
},
|
||||
ip,
|
||||
});
|
||||
|
||||
expect(result.isNewTeam).toEqual(true);
|
||||
expect(result.team.subdomain).toEqual("myteam1");
|
||||
expect(result.team.subdomain).toEqual(`${subdomain}1`);
|
||||
});
|
||||
|
||||
it("should increment subdomain append if unavailable", async () => {
|
||||
const subdomain = faker.internet.domainWord();
|
||||
await buildTeam({
|
||||
subdomain: "myteam",
|
||||
subdomain,
|
||||
});
|
||||
await buildTeam({
|
||||
subdomain: "myteam1",
|
||||
subdomain: `${subdomain}1`,
|
||||
});
|
||||
const result = await teamProvisioner({
|
||||
name: "Test team",
|
||||
subdomain: "myteam",
|
||||
avatarUrl: "http://example.com/logo.png",
|
||||
subdomain,
|
||||
avatarUrl: faker.internet.avatar(),
|
||||
authenticationProvider: {
|
||||
name: "google",
|
||||
providerId: "example.com",
|
||||
providerId: `${subdomain}.com`,
|
||||
},
|
||||
ip,
|
||||
});
|
||||
|
||||
expect(result.team.subdomain).toEqual("myteam2");
|
||||
expect(result.team.subdomain).toEqual(`${subdomain}2`);
|
||||
});
|
||||
|
||||
it("should return existing team", async () => {
|
||||
const subdomain = faker.internet.domainWord();
|
||||
const authenticationProvider = {
|
||||
name: "google",
|
||||
providerId: "example.com",
|
||||
providerId: `${subdomain}.com`,
|
||||
};
|
||||
const existing = await buildTeam({
|
||||
subdomain: "example",
|
||||
subdomain,
|
||||
authenticationProviders: [authenticationProvider],
|
||||
});
|
||||
const result = await teamProvisioner({
|
||||
name: "Updated name",
|
||||
subdomain: "example",
|
||||
name: faker.company.name(),
|
||||
subdomain,
|
||||
authenticationProvider,
|
||||
ip,
|
||||
});
|
||||
const { team, isNewTeam } = result;
|
||||
expect(team.id).toEqual(existing.id);
|
||||
expect(team.name).toEqual(existing.name);
|
||||
expect(team.subdomain).toEqual("example");
|
||||
expect(team.subdomain).toEqual(subdomain);
|
||||
expect(isNewTeam).toEqual(false);
|
||||
});
|
||||
|
||||
it("should error on mismatched team and authentication provider", async () => {
|
||||
const exampleTeam = await buildTeam({
|
||||
subdomain: "example",
|
||||
subdomain: faker.internet.domainWord(),
|
||||
authenticationProviders: [
|
||||
{
|
||||
name: "google",
|
||||
providerId: "example.com",
|
||||
providerId: "teamProvisioner3.com",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
let error;
|
||||
try {
|
||||
const subdomain = faker.internet.domainWord();
|
||||
await teamProvisioner({
|
||||
teamId: exampleTeam.id,
|
||||
name: "name",
|
||||
subdomain: "other",
|
||||
subdomain,
|
||||
authenticationProvider: {
|
||||
name: "google",
|
||||
providerId: "other.com",
|
||||
providerId: `${subdomain}.com`,
|
||||
},
|
||||
ip,
|
||||
});
|
||||
@@ -131,13 +138,14 @@ describe("teamProvisioner", () => {
|
||||
beforeEach(setSelfHosted);
|
||||
|
||||
it("should allow creating first team", async () => {
|
||||
const subdomain = faker.internet.domainWord();
|
||||
const { team, isNewTeam } = await teamProvisioner({
|
||||
name: "Test team",
|
||||
subdomain: "example",
|
||||
avatarUrl: "http://example.com/logo.png",
|
||||
subdomain,
|
||||
avatarUrl: faker.internet.avatar(),
|
||||
authenticationProvider: {
|
||||
name: "google",
|
||||
providerId: "example.com",
|
||||
providerId: `${subdomain}.com`,
|
||||
},
|
||||
ip,
|
||||
});
|
||||
@@ -148,17 +156,18 @@ describe("teamProvisioner", () => {
|
||||
|
||||
it("should not allow creating multiple teams in installation", async () => {
|
||||
const team = await buildTeam();
|
||||
const subdomain = faker.internet.domainWord();
|
||||
let error;
|
||||
|
||||
try {
|
||||
await teamProvisioner({
|
||||
name: "Test team",
|
||||
subdomain: "example",
|
||||
avatarUrl: "http://example.com/logo.png",
|
||||
subdomain,
|
||||
avatarUrl: faker.internet.avatar(),
|
||||
teamId: team.id,
|
||||
authenticationProvider: {
|
||||
name: "google",
|
||||
providerId: "example.com",
|
||||
providerId: `${subdomain}.com`,
|
||||
},
|
||||
ip,
|
||||
});
|
||||
@@ -170,23 +179,24 @@ describe("teamProvisioner", () => {
|
||||
});
|
||||
|
||||
it("should return existing team when within allowed domains", async () => {
|
||||
const domain = faker.internet.domainName();
|
||||
const existing = await buildTeam();
|
||||
const user = await buildUser({
|
||||
teamId: existing.id,
|
||||
});
|
||||
await TeamDomain.create({
|
||||
teamId: existing.id,
|
||||
name: "allowed-domain.com",
|
||||
name: domain,
|
||||
createdById: user.id,
|
||||
});
|
||||
const result = await teamProvisioner({
|
||||
name: "Updated name",
|
||||
subdomain: "example",
|
||||
domain: "allowed-domain.com",
|
||||
subdomain: faker.internet.domainWord(),
|
||||
domain,
|
||||
teamId: existing.id,
|
||||
authenticationProvider: {
|
||||
name: "google",
|
||||
providerId: "allowed-domain.com",
|
||||
providerId: domain,
|
||||
},
|
||||
ip,
|
||||
});
|
||||
@@ -194,7 +204,7 @@ describe("teamProvisioner", () => {
|
||||
expect(team.id).toEqual(existing.id);
|
||||
expect(team.name).toEqual(existing.name);
|
||||
expect(authenticationProvider.name).toEqual("google");
|
||||
expect(authenticationProvider.providerId).toEqual("allowed-domain.com");
|
||||
expect(authenticationProvider.providerId).toEqual(domain);
|
||||
expect(isNewTeam).toEqual(false);
|
||||
const providers = await team.$get("authenticationProviders");
|
||||
expect(providers.length).toEqual(2);
|
||||
@@ -215,7 +225,7 @@ describe("teamProvisioner", () => {
|
||||
try {
|
||||
await teamProvisioner({
|
||||
name: "Updated name",
|
||||
subdomain: "example",
|
||||
subdomain: faker.internet.domainWord(),
|
||||
domain: "other-domain.com",
|
||||
teamId: existing.id,
|
||||
authenticationProvider: {
|
||||
@@ -234,22 +244,23 @@ describe("teamProvisioner", () => {
|
||||
it("should return existing team", async () => {
|
||||
const authenticationProvider = {
|
||||
name: "google",
|
||||
providerId: "example.com",
|
||||
providerId: faker.internet.domainName(),
|
||||
};
|
||||
const subdomain = faker.internet.domainWord();
|
||||
const existing = await buildTeam({
|
||||
subdomain: "example",
|
||||
subdomain,
|
||||
authenticationProviders: [authenticationProvider],
|
||||
});
|
||||
const result = await teamProvisioner({
|
||||
name: "Updated name",
|
||||
subdomain: "example",
|
||||
subdomain,
|
||||
authenticationProvider,
|
||||
ip,
|
||||
});
|
||||
const { team, isNewTeam } = result;
|
||||
expect(team.id).toEqual(existing.id);
|
||||
expect(team.name).toEqual(existing.name);
|
||||
expect(team.subdomain).toEqual("example");
|
||||
expect(team.subdomain).toEqual(subdomain);
|
||||
expect(isNewTeam).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { faker } from "@faker-js/faker";
|
||||
import { UserRole } from "@shared/types";
|
||||
import { buildUser } from "@server/test/factories";
|
||||
import { setupTestDatabase } from "@server/test/support";
|
||||
@@ -14,7 +15,7 @@ describe("userInviter", () => {
|
||||
invites: [
|
||||
{
|
||||
role: UserRole.Member,
|
||||
email: "test@example.com",
|
||||
email: faker.internet.email(),
|
||||
name: "Test",
|
||||
},
|
||||
],
|
||||
@@ -78,12 +79,13 @@ describe("userInviter", () => {
|
||||
});
|
||||
|
||||
it("should not send invites to existing team members", async () => {
|
||||
const user = await buildUser();
|
||||
const email = faker.internet.email().toLowerCase();
|
||||
const user = await buildUser({ email });
|
||||
const response = await userInviter({
|
||||
invites: [
|
||||
{
|
||||
role: UserRole.Member,
|
||||
email: user.email!,
|
||||
email,
|
||||
name: user.name,
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { TeamDomain } from "@server/models";
|
||||
import { buildUser, buildTeam, buildInvite } from "@server/test/factories";
|
||||
import { setupTestDatabase, seed } from "@server/test/support";
|
||||
import {
|
||||
buildUser,
|
||||
buildTeam,
|
||||
buildInvite,
|
||||
buildAdmin,
|
||||
} from "@server/test/factories";
|
||||
import { setupTestDatabase } from "@server/test/support";
|
||||
import userProvisioner from "./userProvisioner";
|
||||
|
||||
setupTestDatabase();
|
||||
@@ -331,7 +336,8 @@ describe("userProvisioner", () => {
|
||||
});
|
||||
|
||||
it("should create a user from allowed domain", async () => {
|
||||
const { admin, team } = await seed();
|
||||
const team = await buildTeam();
|
||||
const admin = await buildAdmin({ teamId: team.id });
|
||||
await TeamDomain.create({
|
||||
teamId: team.id,
|
||||
name: "example-company.com",
|
||||
@@ -362,7 +368,8 @@ describe("userProvisioner", () => {
|
||||
});
|
||||
|
||||
it("should create a user from allowed domain with emailMatchOnly", async () => {
|
||||
const { admin, team } = await seed();
|
||||
const team = await buildTeam();
|
||||
const admin = await buildAdmin({ teamId: team.id });
|
||||
await TeamDomain.create({
|
||||
teamId: team.id,
|
||||
name: "example-company.com",
|
||||
@@ -382,7 +389,7 @@ describe("userProvisioner", () => {
|
||||
});
|
||||
|
||||
it("should not create a user with emailMatchOnly when no allowed domains are set", async () => {
|
||||
const { team } = await seed();
|
||||
const team = await buildTeam();
|
||||
let error;
|
||||
|
||||
try {
|
||||
@@ -400,7 +407,8 @@ describe("userProvisioner", () => {
|
||||
});
|
||||
|
||||
it("should reject an user when the domain is not allowed", async () => {
|
||||
const { admin, team } = await seed();
|
||||
const team = await buildTeam();
|
||||
const admin = await buildAdmin({ teamId: team.id });
|
||||
await TeamDomain.create({
|
||||
teamId: team.id,
|
||||
name: "other.com",
|
||||
|
||||
@@ -59,6 +59,12 @@ describe("userSuspender", () => {
|
||||
});
|
||||
expect(user.suspendedAt).toBeTruthy();
|
||||
expect(user.suspendedById).toEqual(admin.id);
|
||||
expect(await GroupUser.count()).toEqual(0);
|
||||
expect(
|
||||
await GroupUser.count({
|
||||
where: {
|
||||
userId: user.id,
|
||||
},
|
||||
})
|
||||
).toEqual(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -65,7 +65,7 @@ export function requestErrorHandler(error: any, ctx: AppContext) {
|
||||
});
|
||||
Sentry.captureException(error);
|
||||
});
|
||||
} else {
|
||||
} else if (env.ENVIRONMENT !== "test") {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
@@ -192,9 +192,7 @@ describe("Authentication middleware", () => {
|
||||
it("should return an error for deleted team", async () => {
|
||||
const state = {} as DefaultState;
|
||||
const team = await buildTeam();
|
||||
const user = await buildUser({
|
||||
teamId: team.id,
|
||||
});
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
await team.destroy();
|
||||
const authMiddleware = auth();
|
||||
let error;
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
buildTeam,
|
||||
buildDocument,
|
||||
} from "@server/test/factories";
|
||||
import { setupTestDatabase, seed } from "@server/test/support";
|
||||
import { setupTestDatabase } from "@server/test/support";
|
||||
import slugify from "@server/utils/slugify";
|
||||
import Collection from "./Collection";
|
||||
import Document from "./Document";
|
||||
@@ -103,7 +103,7 @@ describe("getDocumentTree", () => {
|
||||
|
||||
describe("#addDocumentToStructure", () => {
|
||||
test("should add as last element without index", async () => {
|
||||
const { collection } = await seed();
|
||||
const collection = await buildCollection();
|
||||
const id = uuidv4();
|
||||
const newDocument = await buildDocument({
|
||||
id,
|
||||
@@ -112,12 +112,12 @@ describe("#addDocumentToStructure", () => {
|
||||
teamId: collection.teamId,
|
||||
});
|
||||
await collection.addDocumentToStructure(newDocument);
|
||||
expect(collection.documentStructure!.length).toBe(2);
|
||||
expect(collection.documentStructure![1].id).toBe(id);
|
||||
expect(collection.documentStructure!.length).toBe(1);
|
||||
expect(collection.documentStructure![0].id).toBe(id);
|
||||
});
|
||||
|
||||
test("should add with an index", async () => {
|
||||
const { collection } = await seed();
|
||||
const collection = await buildCollection();
|
||||
const id = uuidv4();
|
||||
const newDocument = await buildDocument({
|
||||
id,
|
||||
@@ -126,12 +126,15 @@ describe("#addDocumentToStructure", () => {
|
||||
teamId: collection.teamId,
|
||||
});
|
||||
await collection.addDocumentToStructure(newDocument, 1);
|
||||
expect(collection.documentStructure!.length).toBe(2);
|
||||
expect(collection.documentStructure![1].id).toBe(id);
|
||||
expect(collection.documentStructure!.length).toBe(1);
|
||||
expect(collection.documentStructure![0].id).toBe(id);
|
||||
});
|
||||
|
||||
test("should add as a child if with parent", async () => {
|
||||
const { collection, document } = await seed();
|
||||
const collection = await buildCollection();
|
||||
const document = await buildDocument({ collectionId: collection.id });
|
||||
await collection.reload();
|
||||
|
||||
const id = uuidv4();
|
||||
const newDocument = await buildDocument({
|
||||
id,
|
||||
@@ -147,7 +150,10 @@ describe("#addDocumentToStructure", () => {
|
||||
});
|
||||
|
||||
test("should add as a child if with parent with index", async () => {
|
||||
const { collection, document } = await seed();
|
||||
const collection = await buildCollection();
|
||||
const document = await buildDocument({ collectionId: collection.id });
|
||||
await collection.reload();
|
||||
|
||||
const newDocument = await buildDocument({
|
||||
id: uuidv4(),
|
||||
title: "node",
|
||||
@@ -170,7 +176,7 @@ describe("#addDocumentToStructure", () => {
|
||||
});
|
||||
describe("options: documentJson", () => {
|
||||
test("should append supplied json over document's own", async () => {
|
||||
const { collection } = await seed();
|
||||
const collection = await buildCollection();
|
||||
const id = uuidv4();
|
||||
const newDocument = await buildDocument({
|
||||
id: uuidv4(),
|
||||
@@ -193,15 +199,18 @@ describe("#addDocumentToStructure", () => {
|
||||
],
|
||||
},
|
||||
});
|
||||
expect(collection.documentStructure![1].children.length).toBe(1);
|
||||
expect(collection.documentStructure![1].children[0].id).toBe(id);
|
||||
expect(collection.documentStructure![0].children.length).toBe(1);
|
||||
expect(collection.documentStructure![0].children[0].id).toBe(id);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#updateDocument", () => {
|
||||
test("should update root document's data", async () => {
|
||||
const { collection, document } = await seed();
|
||||
const collection = await buildCollection();
|
||||
const document = await buildDocument({ collectionId: collection.id });
|
||||
await collection.reload();
|
||||
|
||||
document.title = "Updated title";
|
||||
await document.save();
|
||||
await collection.updateDocument(document);
|
||||
@@ -209,7 +218,10 @@ describe("#updateDocument", () => {
|
||||
});
|
||||
|
||||
test("should update child document's data", async () => {
|
||||
const { collection, document } = await seed();
|
||||
const collection = await buildCollection();
|
||||
const document = await buildDocument({ collectionId: collection.id });
|
||||
await collection.reload();
|
||||
|
||||
const newDocument = await Document.create({
|
||||
parentDocumentId: document.id,
|
||||
collectionId: collection.id,
|
||||
@@ -233,14 +245,20 @@ describe("#updateDocument", () => {
|
||||
|
||||
describe("#removeDocument", () => {
|
||||
test("should save if removing", async () => {
|
||||
const { collection, document } = await seed();
|
||||
const collection = await buildCollection();
|
||||
const document = await buildDocument({ collectionId: collection.id });
|
||||
await collection.reload();
|
||||
|
||||
jest.spyOn(collection, "save");
|
||||
await collection.deleteDocument(document);
|
||||
expect(collection.save).toBeCalled();
|
||||
});
|
||||
|
||||
test("should remove documents from root", async () => {
|
||||
const { collection, document } = await seed();
|
||||
const collection = await buildCollection();
|
||||
const document = await buildDocument({ collectionId: collection.id });
|
||||
await collection.reload();
|
||||
|
||||
await collection.deleteDocument(document);
|
||||
expect(collection.documentStructure!.length).toBe(0);
|
||||
// Verify that the document was removed
|
||||
@@ -253,7 +271,10 @@ describe("#removeDocument", () => {
|
||||
});
|
||||
|
||||
test("should remove a document with child documents", async () => {
|
||||
const { collection, document } = await seed();
|
||||
const collection = await buildCollection();
|
||||
const document = await buildDocument({ collectionId: collection.id });
|
||||
await collection.reload();
|
||||
|
||||
// Add a child for testing
|
||||
const newDocument = await Document.create({
|
||||
parentDocumentId: document.id,
|
||||
@@ -279,7 +300,10 @@ describe("#removeDocument", () => {
|
||||
});
|
||||
|
||||
test("should remove a child document", async () => {
|
||||
const { collection, document } = await seed();
|
||||
const collection = await buildCollection();
|
||||
const document = await buildDocument({ collectionId: collection.id });
|
||||
await collection.reload();
|
||||
|
||||
// Add a child for testing
|
||||
const newDocument = await Document.create({
|
||||
parentDocumentId: document.id,
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
buildTeam,
|
||||
buildUser,
|
||||
} from "@server/test/factories";
|
||||
import { setupTestDatabase, seed } from "@server/test/support";
|
||||
import { setupTestDatabase } from "@server/test/support";
|
||||
import slugify from "@server/utils/slugify";
|
||||
|
||||
setupTestDatabase();
|
||||
@@ -116,9 +116,7 @@ describe("#save", () => {
|
||||
describe("#getChildDocumentIds", () => {
|
||||
test("should return empty array if no children", async () => {
|
||||
const team = await buildTeam();
|
||||
const user = await buildUser({
|
||||
teamId: team.id,
|
||||
});
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
const collection = await buildCollection({
|
||||
userId: user.id,
|
||||
teamId: team.id,
|
||||
@@ -135,9 +133,7 @@ describe("#getChildDocumentIds", () => {
|
||||
|
||||
test("should return nested child document ids", async () => {
|
||||
const team = await buildTeam();
|
||||
const user = await buildUser({
|
||||
teamId: team.id,
|
||||
});
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
const collection = await buildCollection({
|
||||
userId: user.id,
|
||||
teamId: team.id,
|
||||
@@ -171,14 +167,14 @@ describe("#getChildDocumentIds", () => {
|
||||
|
||||
describe("#findByPk", () => {
|
||||
test("should return document when urlId is correct", async () => {
|
||||
const { document } = await seed();
|
||||
const document = await buildDocument();
|
||||
const id = `${slugify(document.title)}-${document.urlId}`;
|
||||
const response = await Document.findByPk(id);
|
||||
expect(response?.id).toBe(document.id);
|
||||
});
|
||||
|
||||
test("should return document when urlId is given without the slug prefix", async () => {
|
||||
const { document } = await seed();
|
||||
const document = await buildDocument();
|
||||
const id = document.urlId;
|
||||
const response = await Document.findByPk(id);
|
||||
expect(response?.id).toBe(document.id);
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
import { buildUser, buildGroup, buildCollection } from "@server/test/factories";
|
||||
import { setupTestDatabase } from "@server/test/support";
|
||||
import CollectionGroup from "./CollectionGroup";
|
||||
import GroupUser from "./GroupUser";
|
||||
|
||||
setupTestDatabase();
|
||||
|
||||
beforeEach(async () => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
describe("afterDestroy hook", () => {
|
||||
test("should destroy associated group and collection join relations", async () => {
|
||||
const group = await buildGroup();
|
||||
const teamId = group.teamId;
|
||||
const user1 = await buildUser({
|
||||
teamId,
|
||||
});
|
||||
const user2 = await buildUser({
|
||||
teamId,
|
||||
});
|
||||
const collection1 = await buildCollection({
|
||||
permission: null,
|
||||
teamId,
|
||||
});
|
||||
const collection2 = await buildCollection({
|
||||
permission: null,
|
||||
teamId,
|
||||
});
|
||||
const createdById = user1.id;
|
||||
await group.$add("user", user1, {
|
||||
through: {
|
||||
createdById,
|
||||
},
|
||||
});
|
||||
await group.$add("user", user2, {
|
||||
through: {
|
||||
createdById,
|
||||
},
|
||||
});
|
||||
await collection1.$add("group", group, {
|
||||
through: {
|
||||
createdById,
|
||||
},
|
||||
});
|
||||
await collection2.$add("group", group, {
|
||||
through: {
|
||||
createdById,
|
||||
},
|
||||
});
|
||||
let collectionGroupCount = await CollectionGroup.count();
|
||||
let groupUserCount = await GroupUser.count();
|
||||
expect(collectionGroupCount).toBe(2);
|
||||
expect(groupUserCount).toBe(2);
|
||||
await group.destroy();
|
||||
collectionGroupCount = await CollectionGroup.count();
|
||||
groupUserCount = await GroupUser.count();
|
||||
expect(collectionGroupCount).toBe(0);
|
||||
expect(groupUserCount).toBe(0);
|
||||
});
|
||||
});
|
||||
@@ -18,9 +18,21 @@ describe("user model", () => {
|
||||
describe("destroy", () => {
|
||||
it("should delete user authentications", async () => {
|
||||
const user = await buildUser();
|
||||
expect(await UserAuthentication.count()).toBe(1);
|
||||
expect(
|
||||
await UserAuthentication.count({
|
||||
where: {
|
||||
userId: user.id,
|
||||
},
|
||||
})
|
||||
).toBe(1);
|
||||
await user.destroy();
|
||||
expect(await UserAuthentication.count()).toBe(0);
|
||||
expect(
|
||||
await UserAuthentication.count({
|
||||
where: {
|
||||
userId: user.id,
|
||||
},
|
||||
})
|
||||
).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -33,7 +45,9 @@ describe("user model", () => {
|
||||
|
||||
describe("availableTeams", () => {
|
||||
it("should return teams where another user with the same email exists", async () => {
|
||||
const user = await buildUser();
|
||||
const user = await buildUser({
|
||||
email: "user-available-teams@example.com",
|
||||
});
|
||||
const anotherUser = await buildUser({ email: user.email });
|
||||
|
||||
const response = await user.availableTeams();
|
||||
|
||||
@@ -165,9 +165,7 @@ describe("#searchForTeam", () => {
|
||||
describe("#searchForUser", () => {
|
||||
test("should return search results from collections", async () => {
|
||||
const team = await buildTeam();
|
||||
const user = await buildUser({
|
||||
teamId: team.id,
|
||||
});
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
const collection = await buildCollection({
|
||||
userId: user.id,
|
||||
teamId: team.id,
|
||||
@@ -185,9 +183,7 @@ describe("#searchForUser", () => {
|
||||
|
||||
test("should handle no collections", async () => {
|
||||
const team = await buildTeam();
|
||||
const user = await buildUser({
|
||||
teamId: team.id,
|
||||
});
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
const { results } = await SearchHelper.searchForUser(user, "test");
|
||||
expect(results.length).toBe(0);
|
||||
});
|
||||
@@ -265,9 +261,7 @@ describe("#searchForUser", () => {
|
||||
|
||||
test("should return the total count of search results", async () => {
|
||||
const team = await buildTeam();
|
||||
const user = await buildUser({
|
||||
teamId: team.id,
|
||||
});
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
const collection = await buildCollection({
|
||||
userId: user.id,
|
||||
teamId: team.id,
|
||||
@@ -290,9 +284,7 @@ describe("#searchForUser", () => {
|
||||
|
||||
test("should return the document when searched with their previous titles", async () => {
|
||||
const team = await buildTeam();
|
||||
const user = await buildUser({
|
||||
teamId: team.id,
|
||||
});
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
const collection = await buildCollection({
|
||||
teamId: team.id,
|
||||
userId: user.id,
|
||||
@@ -314,9 +306,7 @@ describe("#searchForUser", () => {
|
||||
|
||||
test("should not return the document when searched with neither the titles nor the previous titles", async () => {
|
||||
const team = await buildTeam();
|
||||
const user = await buildUser({
|
||||
teamId: team.id,
|
||||
});
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
const collection = await buildCollection({
|
||||
teamId: team.id,
|
||||
userId: user.id,
|
||||
@@ -340,9 +330,7 @@ describe("#searchForUser", () => {
|
||||
describe("#searchTitlesForUser", () => {
|
||||
test("should return search results from collections", async () => {
|
||||
const team = await buildTeam();
|
||||
const user = await buildUser({
|
||||
teamId: team.id,
|
||||
});
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
const collection = await buildCollection({
|
||||
userId: user.id,
|
||||
teamId: team.id,
|
||||
@@ -360,9 +348,7 @@ describe("#searchTitlesForUser", () => {
|
||||
|
||||
test("should filter to specific collection", async () => {
|
||||
const team = await buildTeam();
|
||||
const user = await buildUser({
|
||||
teamId: team.id,
|
||||
});
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
const collection = await buildCollection({
|
||||
userId: user.id,
|
||||
teamId: team.id,
|
||||
@@ -397,9 +383,7 @@ describe("#searchTitlesForUser", () => {
|
||||
|
||||
test("should handle no collections", async () => {
|
||||
const team = await buildTeam();
|
||||
const user = await buildUser({
|
||||
teamId: team.id,
|
||||
});
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
const documents = await SearchHelper.searchTitlesForUser(user, "test");
|
||||
expect(documents.length).toBe(0);
|
||||
});
|
||||
|
||||
@@ -14,9 +14,7 @@ setupTestDatabase();
|
||||
describe("read_write collection", () => {
|
||||
it("should allow read write permissions for member", async () => {
|
||||
const team = await buildTeam();
|
||||
const user = await buildUser({
|
||||
teamId: team.id,
|
||||
});
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
const collection = await buildCollection({
|
||||
teamId: team.id,
|
||||
permission: CollectionPermission.ReadWrite,
|
||||
@@ -69,9 +67,7 @@ describe("read_write collection", () => {
|
||||
describe("read collection", () => {
|
||||
it("should allow read permissions for team member", async () => {
|
||||
const team = await buildTeam();
|
||||
const user = await buildUser({
|
||||
teamId: team.id,
|
||||
});
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
const collection = await buildCollection({
|
||||
teamId: team.id,
|
||||
permission: CollectionPermission.Read,
|
||||
@@ -98,9 +94,7 @@ describe("read collection", () => {
|
||||
describe("private collection", () => {
|
||||
it("should allow no permissions for team member", async () => {
|
||||
const team = await buildTeam();
|
||||
const user = await buildUser({
|
||||
teamId: team.id,
|
||||
});
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
const collection = await buildCollection({
|
||||
teamId: team.id,
|
||||
permission: null,
|
||||
@@ -127,11 +121,10 @@ describe("private collection", () => {
|
||||
describe("no collection", () => {
|
||||
it("should grant same permissions as that on a draft document except the share permission", async () => {
|
||||
const team = await buildTeam();
|
||||
const user = await buildUser({
|
||||
teamId: team.id,
|
||||
});
|
||||
const user = await buildUser({ teamId: team.id });
|
||||
const document = await buildDraftDocument({
|
||||
teamId: team.id,
|
||||
collectionId: null,
|
||||
});
|
||||
const abilities = serialize(user, document);
|
||||
expect(abilities.archive).toEqual(false);
|
||||
@@ -144,7 +137,7 @@ describe("no collection", () => {
|
||||
expect(abilities.pinToHome).toEqual(false);
|
||||
expect(abilities.read).toEqual(true);
|
||||
expect(abilities.restore).toEqual(false);
|
||||
expect(abilities.share).toEqual(false);
|
||||
expect(abilities.share).toEqual(true);
|
||||
expect(abilities.star).toEqual(true);
|
||||
expect(abilities.subscribe).toEqual(false);
|
||||
expect(abilities.unarchive).toEqual(false);
|
||||
|
||||
@@ -98,13 +98,16 @@ allow(User, "share", Document, (user, document) => {
|
||||
if (document.deletedAt) {
|
||||
return false;
|
||||
}
|
||||
invariant(
|
||||
document.collection,
|
||||
"collection is missing, did you forget to include in the query scope?"
|
||||
);
|
||||
|
||||
if (cannot(user, "share", document.collection)) {
|
||||
return false;
|
||||
if (document.collectionId) {
|
||||
invariant(
|
||||
document.collection,
|
||||
"collection is missing, did you forget to include in the query scope?"
|
||||
);
|
||||
|
||||
if (cannot(user, "share", document.collection)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return user.teamId === document.teamId;
|
||||
|
||||
@@ -9,7 +9,7 @@ import { serialize } from "./index";
|
||||
setupTestDatabase();
|
||||
|
||||
it("should allow reading only", async () => {
|
||||
setSelfHosted();
|
||||
await setSelfHosted();
|
||||
|
||||
const team = await buildTeam();
|
||||
const user = await buildUser({
|
||||
@@ -26,7 +26,7 @@ it("should allow reading only", async () => {
|
||||
});
|
||||
|
||||
it("should allow admins to manage", async () => {
|
||||
setSelfHosted();
|
||||
await setSelfHosted();
|
||||
|
||||
const team = await buildTeam();
|
||||
const admin = await buildAdmin({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { subDays } from "date-fns";
|
||||
import { Document } from "@server/models";
|
||||
import { buildDocument } from "@server/test/factories";
|
||||
import { buildDocument, buildTeam } from "@server/test/factories";
|
||||
import { setupTestDatabase } from "@server/test/support";
|
||||
import CleanupDeletedDocumentsTask from "./CleanupDeletedDocumentsTask";
|
||||
|
||||
@@ -8,7 +8,9 @@ setupTestDatabase();
|
||||
|
||||
describe("CleanupDeletedDocumentsTask", () => {
|
||||
it("should not destroy documents not deleted", async () => {
|
||||
const team = await buildTeam();
|
||||
await buildDocument({
|
||||
teamId: team.id,
|
||||
publishedAt: new Date(),
|
||||
});
|
||||
|
||||
@@ -17,13 +19,18 @@ describe("CleanupDeletedDocumentsTask", () => {
|
||||
|
||||
expect(
|
||||
await Document.unscoped().count({
|
||||
where: {
|
||||
teamId: team.id,
|
||||
},
|
||||
paranoid: false,
|
||||
})
|
||||
).toEqual(1);
|
||||
});
|
||||
|
||||
it("should not destroy documents deleted less than 30 days ago", async () => {
|
||||
const team = await buildTeam();
|
||||
await buildDocument({
|
||||
teamId: team.id,
|
||||
publishedAt: new Date(),
|
||||
deletedAt: subDays(new Date(), 25),
|
||||
});
|
||||
@@ -33,13 +40,18 @@ describe("CleanupDeletedDocumentsTask", () => {
|
||||
|
||||
expect(
|
||||
await Document.unscoped().count({
|
||||
where: {
|
||||
teamId: team.id,
|
||||
},
|
||||
paranoid: false,
|
||||
})
|
||||
).toEqual(1);
|
||||
});
|
||||
|
||||
it("should destroy documents deleted more than 30 days ago", async () => {
|
||||
const team = await buildTeam();
|
||||
await buildDocument({
|
||||
teamId: team.id,
|
||||
publishedAt: new Date(),
|
||||
deletedAt: subDays(new Date(), 60),
|
||||
});
|
||||
@@ -49,13 +61,18 @@ describe("CleanupDeletedDocumentsTask", () => {
|
||||
|
||||
expect(
|
||||
await Document.unscoped().count({
|
||||
where: {
|
||||
teamId: team.id,
|
||||
},
|
||||
paranoid: false,
|
||||
})
|
||||
).toEqual(0);
|
||||
});
|
||||
|
||||
it("should destroy draft documents deleted more than 30 days ago", async () => {
|
||||
const team = await buildTeam();
|
||||
await buildDocument({
|
||||
teamId: team.id,
|
||||
publishedAt: undefined,
|
||||
deletedAt: subDays(new Date(), 60),
|
||||
});
|
||||
@@ -65,6 +82,9 @@ describe("CleanupDeletedDocumentsTask", () => {
|
||||
|
||||
expect(
|
||||
await Document.unscoped().count({
|
||||
where: {
|
||||
teamId: team.id,
|
||||
},
|
||||
paranoid: false,
|
||||
})
|
||||
).toEqual(0);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { subDays } from "date-fns";
|
||||
import { FileOperationState, FileOperationType } from "@shared/types";
|
||||
import { FileOperation } from "@server/models";
|
||||
import { buildFileOperation } from "@server/test/factories";
|
||||
import { buildFileOperation, buildTeam } from "@server/test/factories";
|
||||
import { setupTestDatabase } from "@server/test/support";
|
||||
import CleanupExpiredFileOperationsTask from "./CleanupExpiredFileOperationsTask";
|
||||
|
||||
@@ -9,12 +9,15 @@ setupTestDatabase();
|
||||
|
||||
describe("CleanupExpiredFileOperationsTask", () => {
|
||||
it("should expire exports older than 15 days ago", async () => {
|
||||
const team = await buildTeam();
|
||||
await buildFileOperation({
|
||||
teamId: team.id,
|
||||
type: FileOperationType.Export,
|
||||
state: FileOperationState.Complete,
|
||||
createdAt: subDays(new Date(), 15),
|
||||
});
|
||||
await buildFileOperation({
|
||||
teamId: team.id,
|
||||
type: FileOperationType.Export,
|
||||
state: FileOperationState.Complete,
|
||||
});
|
||||
@@ -25,6 +28,7 @@ describe("CleanupExpiredFileOperationsTask", () => {
|
||||
|
||||
const data = await FileOperation.count({
|
||||
where: {
|
||||
teamId: team.id,
|
||||
type: FileOperationType.Export,
|
||||
state: FileOperationState.Expired,
|
||||
},
|
||||
@@ -33,12 +37,15 @@ describe("CleanupExpiredFileOperationsTask", () => {
|
||||
});
|
||||
|
||||
it("should not expire exports made less than 15 days ago", async () => {
|
||||
const team = await buildTeam();
|
||||
await buildFileOperation({
|
||||
teamId: team.id,
|
||||
type: FileOperationType.Export,
|
||||
state: FileOperationState.Complete,
|
||||
createdAt: subDays(new Date(), 14),
|
||||
});
|
||||
await buildFileOperation({
|
||||
teamId: team.id,
|
||||
type: FileOperationType.Export,
|
||||
state: FileOperationState.Complete,
|
||||
});
|
||||
@@ -48,6 +55,7 @@ describe("CleanupExpiredFileOperationsTask", () => {
|
||||
|
||||
const data = await FileOperation.count({
|
||||
where: {
|
||||
teamId: team.id,
|
||||
type: FileOperationType.Export,
|
||||
state: FileOperationState.Expired,
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { subDays } from "date-fns";
|
||||
import { FileOperationState, FileOperationType } from "@shared/types";
|
||||
import { FileOperation } from "@server/models";
|
||||
import { buildFileOperation } from "@server/test/factories";
|
||||
import { buildFileOperation, buildTeam } from "@server/test/factories";
|
||||
import { setupTestDatabase } from "@server/test/support";
|
||||
import ErrorTimedOutFileOperationsTask from "./ErrorTimedOutFileOperationsTask";
|
||||
|
||||
@@ -9,12 +9,15 @@ setupTestDatabase();
|
||||
|
||||
describe("ErrorTimedOutFileOperationsTask", () => {
|
||||
it("should error exports older than 12 hours", async () => {
|
||||
const team = await buildTeam();
|
||||
await buildFileOperation({
|
||||
teamId: team.id,
|
||||
type: FileOperationType.Export,
|
||||
state: FileOperationState.Creating,
|
||||
createdAt: subDays(new Date(), 15),
|
||||
});
|
||||
await buildFileOperation({
|
||||
teamId: team.id,
|
||||
type: FileOperationType.Export,
|
||||
state: FileOperationState.Complete,
|
||||
});
|
||||
@@ -25,6 +28,7 @@ describe("ErrorTimedOutFileOperationsTask", () => {
|
||||
|
||||
const data = await FileOperation.count({
|
||||
where: {
|
||||
teamId: team.id,
|
||||
type: FileOperationType.Export,
|
||||
state: FileOperationState.Error,
|
||||
},
|
||||
@@ -33,7 +37,9 @@ describe("ErrorTimedOutFileOperationsTask", () => {
|
||||
});
|
||||
|
||||
it("should not error exports created less than 12 hours ago", async () => {
|
||||
const team = await buildTeam();
|
||||
await buildFileOperation({
|
||||
teamId: team.id,
|
||||
type: FileOperationType.Export,
|
||||
state: FileOperationState.Creating,
|
||||
});
|
||||
@@ -43,6 +49,7 @@ describe("ErrorTimedOutFileOperationsTask", () => {
|
||||
|
||||
const data = await FileOperation.count({
|
||||
where: {
|
||||
teamId: team.id,
|
||||
type: FileOperationType.Export,
|
||||
state: FileOperationState.Error,
|
||||
},
|
||||
|
||||
@@ -137,7 +137,10 @@ describe("revisions.create", () => {
|
||||
const collaborator0 = await buildUser();
|
||||
const collaborator1 = await buildUser({ teamId: collaborator0.teamId });
|
||||
const collaborator2 = await buildUser({ teamId: collaborator0.teamId });
|
||||
const document = await buildDocument({ userId: collaborator0.id });
|
||||
const document = await buildDocument({
|
||||
teamId: collaborator0.teamId,
|
||||
userId: collaborator0.id,
|
||||
});
|
||||
await Revision.createFromDocument(document);
|
||||
document.text = "Updated body content";
|
||||
document.updatedAt = new Date();
|
||||
@@ -159,7 +162,11 @@ describe("revisions.create", () => {
|
||||
ip,
|
||||
});
|
||||
|
||||
const events = await Event.findAll();
|
||||
const events = await Event.findAll({
|
||||
where: {
|
||||
teamId: document.teamId,
|
||||
},
|
||||
});
|
||||
|
||||
// Should emit 3 `subscriptions.create` events.
|
||||
expect(events.length).toEqual(3);
|
||||
@@ -254,7 +261,11 @@ describe("revisions.create", () => {
|
||||
ip,
|
||||
});
|
||||
|
||||
const events = await Event.findAll();
|
||||
const events = await Event.findAll({
|
||||
where: {
|
||||
teamId: document.teamId,
|
||||
},
|
||||
});
|
||||
|
||||
// Should emit 2 `subscriptions.create` events.
|
||||
expect(events.length).toEqual(2);
|
||||
|
||||
@@ -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 () => {
|
||||
|
||||
@@ -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(),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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(),
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
import { Revision, Event } from "@server/models";
|
||||
import { buildDocument } from "@server/test/factories";
|
||||
import { setupTestDatabase } from "@server/test/support";
|
||||
import script from "./20210716000000-backfill-revisions";
|
||||
|
||||
setupTestDatabase();
|
||||
|
||||
describe("#work", () => {
|
||||
it("should create events for revisions", async () => {
|
||||
const document = await buildDocument();
|
||||
const revision = await Revision.createFromDocument(document);
|
||||
await script();
|
||||
const event = await Event.findOne();
|
||||
expect(event!.name).toEqual("revisions.create");
|
||||
expect(event!.modelId).toEqual(revision.id);
|
||||
expect(event!.documentId).toEqual(document.id);
|
||||
expect(event!.teamId).toEqual(document.teamId);
|
||||
expect(event!.createdAt).toEqual(revision.createdAt);
|
||||
});
|
||||
|
||||
it("should create events for revisions of deleted documents", async () => {
|
||||
const document = await buildDocument();
|
||||
const revision = await Revision.createFromDocument(document);
|
||||
await document.destroy();
|
||||
await script();
|
||||
const event = await Event.findOne();
|
||||
expect(event!.name).toEqual("revisions.create");
|
||||
expect(event!.modelId).toEqual(revision.id);
|
||||
expect(event!.documentId).toEqual(document.id);
|
||||
expect(event!.teamId).toEqual(document.teamId);
|
||||
expect(event!.createdAt).toEqual(revision.createdAt);
|
||||
});
|
||||
|
||||
it("should be idempotent", async () => {
|
||||
const document = await buildDocument();
|
||||
await Revision.createFromDocument(document);
|
||||
await script();
|
||||
await script();
|
||||
const count = await Event.count();
|
||||
expect(count).toEqual(1);
|
||||
});
|
||||
});
|
||||
@@ -1,173 +0,0 @@
|
||||
import { Subscription } from "@server/models";
|
||||
import { buildDocument, buildUser } from "@server/test/factories";
|
||||
import { setupTestDatabase } from "@server/test/support";
|
||||
import script from "./20220722000000-backfill-subscriptions";
|
||||
|
||||
setupTestDatabase();
|
||||
|
||||
describe("#work", () => {
|
||||
it("should create subscriptions and subscriptions for document creator and collaborators", async () => {
|
||||
const admin = await buildUser();
|
||||
|
||||
// 5 collaborators that have cyclically contributed to documents.
|
||||
const collaborator0 = await buildUser({ teamId: admin.teamId });
|
||||
const collaborator1 = await buildUser({ teamId: admin.teamId });
|
||||
const collaborator2 = await buildUser({ teamId: admin.teamId });
|
||||
const collaborator3 = await buildUser({ teamId: admin.teamId });
|
||||
const collaborator4 = await buildUser({ teamId: admin.teamId });
|
||||
|
||||
const document0 = await buildDocument({
|
||||
userId: collaborator0.id,
|
||||
collaboratorIds: [collaborator1.id, collaborator2.id],
|
||||
});
|
||||
|
||||
const document1 = await buildDocument({
|
||||
userId: collaborator1.id,
|
||||
collaboratorIds: [collaborator2.id, collaborator3.id],
|
||||
});
|
||||
|
||||
const document2 = await buildDocument({
|
||||
userId: collaborator2.id,
|
||||
collaboratorIds: [collaborator3.id, collaborator4.id],
|
||||
});
|
||||
|
||||
const document3 = await buildDocument({
|
||||
userId: collaborator3.id,
|
||||
collaboratorIds: [collaborator4.id, collaborator0.id],
|
||||
});
|
||||
|
||||
const document4 = await buildDocument({
|
||||
userId: collaborator4.id,
|
||||
collaboratorIds: [collaborator0.id, collaborator1.id],
|
||||
});
|
||||
|
||||
await script();
|
||||
|
||||
const subscriptions = await Subscription.findAll();
|
||||
|
||||
subscriptions.forEach((subscription) => {
|
||||
expect(subscription.id).toBeDefined();
|
||||
expect(subscription.event).toEqual("documents.update");
|
||||
});
|
||||
|
||||
// 5 documents, 3 collaborators each = 15.
|
||||
expect(subscriptions.length).toEqual(15);
|
||||
|
||||
expect(subscriptions[0].documentId).toEqual(document0.id);
|
||||
expect(subscriptions[1].documentId).toEqual(document0.id);
|
||||
expect(subscriptions[2].documentId).toEqual(document0.id);
|
||||
|
||||
const s0 = [
|
||||
subscriptions[0].userId,
|
||||
subscriptions[1].userId,
|
||||
subscriptions[2].userId,
|
||||
];
|
||||
|
||||
expect(s0.some((s) => s.includes(collaborator0.id))).toBe(true);
|
||||
expect(s0.some((s) => s.includes(collaborator1.id))).toBe(true);
|
||||
expect(s0.some((s) => s.includes(collaborator2.id))).toBe(true);
|
||||
|
||||
expect(subscriptions[3].documentId).toEqual(document1.id);
|
||||
expect(subscriptions[4].documentId).toEqual(document1.id);
|
||||
expect(subscriptions[5].documentId).toEqual(document1.id);
|
||||
|
||||
const s1 = [
|
||||
subscriptions[3].userId,
|
||||
subscriptions[4].userId,
|
||||
subscriptions[5].userId,
|
||||
];
|
||||
|
||||
expect(s1.some((s) => s.includes(collaborator1.id))).toBe(true);
|
||||
expect(s1.some((s) => s.includes(collaborator2.id))).toBe(true);
|
||||
expect(s1.some((s) => s.includes(collaborator3.id))).toBe(true);
|
||||
|
||||
expect(subscriptions[6].documentId).toEqual(document2.id);
|
||||
expect(subscriptions[7].documentId).toEqual(document2.id);
|
||||
expect(subscriptions[8].documentId).toEqual(document2.id);
|
||||
|
||||
const s2 = [
|
||||
subscriptions[6].userId,
|
||||
subscriptions[7].userId,
|
||||
subscriptions[8].userId,
|
||||
];
|
||||
|
||||
expect(s2.some((s) => s.includes(collaborator2.id))).toBe(true);
|
||||
expect(s2.some((s) => s.includes(collaborator3.id))).toBe(true);
|
||||
expect(s2.some((s) => s.includes(collaborator4.id))).toBe(true);
|
||||
|
||||
expect(subscriptions[9].documentId).toEqual(document3.id);
|
||||
expect(subscriptions[10].documentId).toEqual(document3.id);
|
||||
expect(subscriptions[11].documentId).toEqual(document3.id);
|
||||
|
||||
const s3 = [
|
||||
subscriptions[9].userId,
|
||||
subscriptions[10].userId,
|
||||
subscriptions[11].userId,
|
||||
];
|
||||
|
||||
expect(s3.some((s) => s.includes(collaborator0.id))).toBe(true);
|
||||
expect(s3.some((s) => s.includes(collaborator3.id))).toBe(true);
|
||||
expect(s3.some((s) => s.includes(collaborator4.id))).toBe(true);
|
||||
|
||||
expect(subscriptions[12].documentId).toEqual(document4.id);
|
||||
expect(subscriptions[13].documentId).toEqual(document4.id);
|
||||
expect(subscriptions[14].documentId).toEqual(document4.id);
|
||||
|
||||
const s4 = [
|
||||
subscriptions[12].userId,
|
||||
subscriptions[13].userId,
|
||||
subscriptions[14].userId,
|
||||
];
|
||||
|
||||
expect(s4.some((s) => s.includes(collaborator0.id))).toBe(true);
|
||||
expect(s4.some((s) => s.includes(collaborator1.id))).toBe(true);
|
||||
expect(s4.some((s) => s.includes(collaborator4.id))).toBe(true);
|
||||
});
|
||||
|
||||
it("should not create subscriptions and subscriptions for non-collaborators", async () => {
|
||||
const admin = await buildUser();
|
||||
|
||||
// 2 collaborators.
|
||||
const collaborator0 = await buildUser({ teamId: admin.teamId });
|
||||
const collaborator1 = await buildUser({ teamId: admin.teamId });
|
||||
|
||||
// 1 viewer from the same team.
|
||||
const viewer = await buildUser({ teamId: admin.teamId });
|
||||
|
||||
const document0 = await buildDocument({
|
||||
userId: collaborator0.id,
|
||||
collaboratorIds: [collaborator1.id],
|
||||
});
|
||||
|
||||
await script();
|
||||
|
||||
const subscriptions = await Subscription.findAll();
|
||||
|
||||
subscriptions.forEach((subscription) => {
|
||||
expect(subscription.id).toBeDefined();
|
||||
});
|
||||
|
||||
expect(
|
||||
subscriptions.filter((subscription) => subscription.userId === viewer.id)
|
||||
.length
|
||||
).toEqual(0);
|
||||
|
||||
expect(subscriptions[0].documentId).toEqual(document0.id);
|
||||
expect(subscriptions[1].documentId).toEqual(document0.id);
|
||||
expect(subscriptions.map((s) => s.userId)).toContain(collaborator1.id);
|
||||
expect(subscriptions.map((s) => s.userId)).toContain(collaborator0.id);
|
||||
expect(subscriptions[0].event).toEqual("documents.update");
|
||||
expect(subscriptions[1].event).toEqual("documents.update");
|
||||
});
|
||||
|
||||
it("should be idempotent", async () => {
|
||||
await buildDocument();
|
||||
|
||||
await script();
|
||||
await script();
|
||||
|
||||
const count = await Subscription.count();
|
||||
|
||||
expect(count).toEqual(1);
|
||||
});
|
||||
});
|
||||
@@ -1,120 +0,0 @@
|
||||
import { Document } from "@server/models";
|
||||
import { buildDocument, buildDraftDocument } from "@server/test/factories";
|
||||
import { setupTestDatabase } from "@server/test/support";
|
||||
import script from "./20230815063834-migrate-emoji-in-document-title";
|
||||
|
||||
setupTestDatabase();
|
||||
|
||||
describe("#work", () => {
|
||||
it("should correctly update title and emoji for a draft document", async () => {
|
||||
const document = await buildDraftDocument({
|
||||
title: "😵 Title draft",
|
||||
});
|
||||
expect(document.publishedAt).toBeNull();
|
||||
expect(document.emoji).toBeNull();
|
||||
|
||||
await script();
|
||||
const draft = await Document.unscoped().findByPk(document.id);
|
||||
expect(draft).not.toBeNull();
|
||||
expect(draft?.title).toEqual("Title draft");
|
||||
expect(draft?.emoji).toEqual("😵");
|
||||
});
|
||||
|
||||
it("should correctly update title and emoji for a published document", async () => {
|
||||
const document = await buildDocument({
|
||||
title: "👱🏽♀️ Title published",
|
||||
});
|
||||
expect(document.publishedAt).toBeTruthy();
|
||||
expect(document.emoji).toBeNull();
|
||||
|
||||
await script();
|
||||
const published = await Document.unscoped().findByPk(document.id);
|
||||
expect(published).not.toBeNull();
|
||||
expect(published?.title).toEqual("Title published");
|
||||
expect(published?.emoji).toEqual("👱🏽♀️");
|
||||
});
|
||||
|
||||
it("should correctly update title and emoji for an archived document", async () => {
|
||||
const document = await buildDocument({
|
||||
title: "🍇 Title archived",
|
||||
});
|
||||
await document.archive(document.createdById);
|
||||
expect(document.archivedAt).toBeTruthy();
|
||||
expect(document.emoji).toBeNull();
|
||||
|
||||
await script();
|
||||
const archived = await Document.unscoped().findByPk(document.id);
|
||||
expect(archived).not.toBeNull();
|
||||
expect(archived?.title).toEqual("Title archived");
|
||||
expect(archived?.emoji).toEqual("🍇");
|
||||
});
|
||||
|
||||
it("should correctly update title and emoji for a template", async () => {
|
||||
const document = await buildDocument({
|
||||
title: "🐹 Title template",
|
||||
template: true,
|
||||
});
|
||||
expect(document.template).toBe(true);
|
||||
expect(document.emoji).toBeNull();
|
||||
|
||||
await script();
|
||||
const template = await Document.unscoped().findByPk(document.id);
|
||||
expect(template).not.toBeNull();
|
||||
expect(template?.title).toEqual("Title template");
|
||||
expect(template?.emoji).toEqual("🐹");
|
||||
});
|
||||
|
||||
it("should correctly update title and emoji for a deleted document", async () => {
|
||||
const document = await buildDocument({
|
||||
title: "🚵🏼♂️ Title deleted",
|
||||
});
|
||||
await document.destroy();
|
||||
expect(document.deletedAt).toBeTruthy();
|
||||
expect(document.emoji).toBeNull();
|
||||
|
||||
await script();
|
||||
const deleted = await Document.unscoped().findByPk(document.id, {
|
||||
paranoid: false,
|
||||
});
|
||||
expect(deleted).not.toBeNull();
|
||||
expect(deleted?.title).toEqual("Title deleted");
|
||||
expect(deleted?.emoji).toEqual("🚵🏼♂️");
|
||||
});
|
||||
|
||||
it("should correctly update title emoji when there are leading spaces", async () => {
|
||||
const document = await buildDocument({
|
||||
title: " 🤨 Title with spaces",
|
||||
});
|
||||
expect(document.emoji).toBeNull();
|
||||
|
||||
await script();
|
||||
|
||||
const doc = await Document.unscoped().findByPk(document.id);
|
||||
expect(doc).not.toBeNull();
|
||||
expect(doc?.title).toEqual("Title with spaces");
|
||||
expect(doc?.emoji).toEqual("🤨");
|
||||
});
|
||||
|
||||
it("should correctly paginate and update title emojis", async () => {
|
||||
const buildManyDocuments = [];
|
||||
for (let i = 1; i <= 10; i++) {
|
||||
buildManyDocuments.push(buildDocument({ title: "🚵🏼♂️ Title" }));
|
||||
}
|
||||
|
||||
const manyDocuments = await Promise.all(buildManyDocuments);
|
||||
|
||||
for (const document of manyDocuments) {
|
||||
expect(document.title).toEqual("🚵🏼♂️ Title");
|
||||
expect(document.emoji).toBeNull();
|
||||
}
|
||||
|
||||
await script(false, 2);
|
||||
|
||||
const documents = await Document.unscoped().findAll();
|
||||
|
||||
for (const document of documents) {
|
||||
expect(document.title).toEqual("Title");
|
||||
expect(document.emoji).toEqual("🚵🏼♂️");
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -15,7 +15,8 @@ const url =
|
||||
"postgres://localhost:5432/outline";
|
||||
|
||||
export const sequelize = new Sequelize(url, {
|
||||
logging: (msg) => Logger.debug("database", msg),
|
||||
logging: (msg) =>
|
||||
process.env.DEBUG?.includes("database") && Logger.debug("database", msg),
|
||||
typeValidation: true,
|
||||
dialectOptions: {
|
||||
ssl:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { faker } from "@faker-js/faker";
|
||||
import isNil from "lodash/isNil";
|
||||
import isNull from "lodash/isNull";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
@@ -33,8 +34,6 @@ import {
|
||||
Pin,
|
||||
} from "@server/models";
|
||||
|
||||
let count = 1;
|
||||
|
||||
export async function buildApiKey(overrides: Partial<ApiKey> = {}) {
|
||||
if (!overrides.userId) {
|
||||
const user = await buildUser();
|
||||
@@ -42,7 +41,7 @@ export async function buildApiKey(overrides: Partial<ApiKey> = {}) {
|
||||
}
|
||||
|
||||
return ApiKey.create({
|
||||
name: "My API Key",
|
||||
name: faker.lorem.words(3),
|
||||
...overrides,
|
||||
});
|
||||
}
|
||||
@@ -124,10 +123,9 @@ export async function buildSubscription(overrides: Partial<Subscription> = {}) {
|
||||
}
|
||||
|
||||
export function buildTeam(overrides: Record<string, any> = {}) {
|
||||
count++;
|
||||
return Team.create(
|
||||
{
|
||||
name: `Team ${count}`,
|
||||
name: faker.company.name(),
|
||||
authenticationProviders: [
|
||||
{
|
||||
name: "slack",
|
||||
@@ -156,10 +154,9 @@ export async function buildGuestUser(overrides: Partial<User> = {}) {
|
||||
overrides.teamId = team.id;
|
||||
}
|
||||
|
||||
count++;
|
||||
return User.create({
|
||||
email: `user${count}@example.com`,
|
||||
name: `User ${count}`,
|
||||
email: faker.internet.email().toLowerCase(),
|
||||
name: faker.person.fullName(),
|
||||
createdAt: new Date("2018-01-01T00:00:00.000Z"),
|
||||
lastActiveAt: new Date("2018-01-01T00:00:00.000Z"),
|
||||
...overrides,
|
||||
@@ -181,11 +178,10 @@ export async function buildUser(overrides: Partial<User> = {}) {
|
||||
teamId: overrides.teamId,
|
||||
},
|
||||
});
|
||||
count++;
|
||||
const user = await User.create(
|
||||
{
|
||||
email: `user${count}@example.com`,
|
||||
name: `User ${count}`,
|
||||
email: faker.internet.email().toLowerCase(),
|
||||
name: faker.person.fullName(),
|
||||
createdAt: new Date("2018-01-01T00:00:00.000Z"),
|
||||
updatedAt: new Date("2018-01-02T00:00:00.000Z"),
|
||||
lastActiveAt: new Date("2018-01-03T00:00:00.000Z"),
|
||||
@@ -224,10 +220,9 @@ export async function buildInvite(overrides: Partial<User> = {}) {
|
||||
|
||||
const actor = await buildUser({ teamId: overrides.teamId });
|
||||
|
||||
count++;
|
||||
return User.create({
|
||||
email: `user${count}@example.com`,
|
||||
name: `User ${count}`,
|
||||
email: faker.internet.email().toLowerCase(),
|
||||
name: faker.person.fullName(),
|
||||
createdAt: new Date("2018-01-01T00:00:00.000Z"),
|
||||
invitedById: actor.id,
|
||||
authentications: [],
|
||||
@@ -257,7 +252,7 @@ export async function buildIntegration(overrides: Partial<Integration> = {}) {
|
||||
type: IntegrationType.Post,
|
||||
events: ["documents.update", "documents.publish"],
|
||||
settings: {
|
||||
serviceTeamId: "slack_team_id",
|
||||
serviceTeamId: uuidv4(),
|
||||
},
|
||||
authenticationId: authentication.id,
|
||||
...overrides,
|
||||
@@ -279,10 +274,9 @@ export async function buildCollection(
|
||||
overrides.userId = user.id;
|
||||
}
|
||||
|
||||
count++;
|
||||
return Collection.create({
|
||||
name: `Test Collection ${count}`,
|
||||
description: "Test collection description",
|
||||
name: faker.lorem.words(2),
|
||||
description: faker.lorem.words(4),
|
||||
createdById: overrides.userId,
|
||||
permission: CollectionPermission.ReadWrite,
|
||||
...overrides,
|
||||
@@ -304,9 +298,8 @@ export async function buildGroup(
|
||||
overrides.userId = user.id;
|
||||
}
|
||||
|
||||
count++;
|
||||
return Group.create({
|
||||
name: `Test Group ${count}`,
|
||||
name: faker.lorem.words(2),
|
||||
createdById: overrides.userId,
|
||||
...overrides,
|
||||
});
|
||||
@@ -327,7 +320,6 @@ export async function buildGroupUser(
|
||||
overrides.userId = user.id;
|
||||
}
|
||||
|
||||
count++;
|
||||
return GroupUser.create({
|
||||
createdById: overrides.userId,
|
||||
...overrides,
|
||||
@@ -337,7 +329,7 @@ export async function buildGroupUser(
|
||||
export async function buildDraftDocument(
|
||||
overrides: Partial<Document> & { userId?: string } = {}
|
||||
) {
|
||||
return buildDocument({ ...overrides, collectionId: null });
|
||||
return buildDocument({ ...overrides, publishedAt: null });
|
||||
}
|
||||
|
||||
export async function buildDocument(
|
||||
@@ -361,18 +353,18 @@ export async function buildDocument(
|
||||
overrides.userId = user.id;
|
||||
}
|
||||
|
||||
let collection;
|
||||
if (overrides.collectionId === undefined) {
|
||||
const collection = await buildCollection({
|
||||
collection = await buildCollection({
|
||||
teamId: overrides.teamId,
|
||||
userId: overrides.userId,
|
||||
});
|
||||
overrides.collectionId = collection.id;
|
||||
}
|
||||
|
||||
count++;
|
||||
return Document.create(
|
||||
const document = await Document.create(
|
||||
{
|
||||
title: `Document ${count}`,
|
||||
title: faker.lorem.words(4),
|
||||
text: "This is the text in an example document",
|
||||
publishedAt: isNull(overrides.collectionId) ? null : new Date(),
|
||||
lastModifiedById: overrides.userId,
|
||||
@@ -384,6 +376,16 @@ export async function buildDocument(
|
||||
silent: overrides.createdAt || overrides.updatedAt ? true : false,
|
||||
}
|
||||
);
|
||||
|
||||
if (overrides.collectionId && overrides.publishedAt !== null) {
|
||||
collection = collection
|
||||
? await Collection.findByPk(overrides.collectionId)
|
||||
: undefined;
|
||||
|
||||
await collection?.addDocumentToStructure(document, 0);
|
||||
}
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
export async function buildFileOperation(
|
||||
@@ -433,9 +435,8 @@ export async function buildAttachment(overrides: Partial<Attachment> = {}) {
|
||||
overrides.documentId = document.id;
|
||||
}
|
||||
|
||||
count++;
|
||||
return Attachment.create({
|
||||
key: `uploads/key/to/file ${count}.png`,
|
||||
key: `uploads/key/to/${faker.system.fileName}.png`,
|
||||
contentType: "image/png",
|
||||
size: 100,
|
||||
acl: "public-read",
|
||||
|
||||
@@ -1,107 +1,12 @@
|
||||
import TestServer from "fetch-test-server";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { WhereOptions } from "sequelize";
|
||||
import sharedEnv from "@shared/env";
|
||||
import { CollectionPermission } from "@shared/types";
|
||||
import env from "@server/env";
|
||||
import { User, Document, Collection, Team } from "@server/models";
|
||||
import { Event, Team } from "@server/models";
|
||||
import onerror from "@server/onerror";
|
||||
import webService from "@server/services/web";
|
||||
import { sequelize } from "@server/storage/database";
|
||||
|
||||
export const seed = async () =>
|
||||
sequelize.transaction(async (transaction) => {
|
||||
const team = await Team.create(
|
||||
{
|
||||
name: "Team",
|
||||
authenticationProviders: [
|
||||
{
|
||||
name: "slack",
|
||||
providerId: uuidv4(),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
transaction,
|
||||
include: "authenticationProviders",
|
||||
}
|
||||
);
|
||||
const authenticationProvider = team.authenticationProviders[0];
|
||||
const admin = await User.create(
|
||||
{
|
||||
email: "admin@example.com",
|
||||
name: "Admin User",
|
||||
teamId: team.id,
|
||||
isAdmin: true,
|
||||
createdAt: new Date("2018-01-01T00:00:00.000Z"),
|
||||
authentications: [
|
||||
{
|
||||
authenticationProviderId: authenticationProvider.id,
|
||||
providerId: uuidv4(),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
transaction,
|
||||
include: "authentications",
|
||||
}
|
||||
);
|
||||
const user = await User.create(
|
||||
{
|
||||
id: "46fde1d4-0050-428f-9f0b-0bf77f4bdf61",
|
||||
email: "user1@example.com",
|
||||
name: "User 1",
|
||||
teamId: team.id,
|
||||
createdAt: new Date("2018-01-02T00:00:00.000Z"),
|
||||
authentications: [
|
||||
{
|
||||
authenticationProviderId: authenticationProvider.id,
|
||||
providerId: uuidv4(),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
transaction,
|
||||
include: "authentications",
|
||||
}
|
||||
);
|
||||
const collection = await Collection.create(
|
||||
{
|
||||
name: "Collection",
|
||||
urlId: "collection",
|
||||
teamId: team.id,
|
||||
createdById: user.id,
|
||||
permission: CollectionPermission.ReadWrite,
|
||||
},
|
||||
{
|
||||
transaction,
|
||||
}
|
||||
);
|
||||
const document = await Document.create(
|
||||
{
|
||||
parentDocumentId: null,
|
||||
collectionId: collection.id,
|
||||
teamId: team.id,
|
||||
userId: collection.createdById,
|
||||
lastModifiedById: collection.createdById,
|
||||
createdById: collection.createdById,
|
||||
title: "First ever document",
|
||||
text: "# Much test support",
|
||||
},
|
||||
{ transaction }
|
||||
);
|
||||
await document.publish(collection.createdById, collection.id, {
|
||||
transaction,
|
||||
});
|
||||
await collection.reload({ transaction });
|
||||
return {
|
||||
user,
|
||||
admin,
|
||||
collection,
|
||||
document,
|
||||
team,
|
||||
};
|
||||
});
|
||||
|
||||
export function getTestServer() {
|
||||
const app = webService();
|
||||
onerror(app);
|
||||
@@ -136,8 +41,9 @@ export function setupTestDatabase() {
|
||||
await sequelize.close();
|
||||
};
|
||||
|
||||
beforeAll(flush);
|
||||
|
||||
afterAll(disconnect);
|
||||
beforeEach(flush);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -150,6 +56,19 @@ export function setCloudHosted() {
|
||||
/**
|
||||
* Set the environment to be self hosted
|
||||
*/
|
||||
export function setSelfHosted() {
|
||||
return (env.URL = sharedEnv.URL = "https://wiki.example.com");
|
||||
export async function setSelfHosted() {
|
||||
env.URL = sharedEnv.URL = "https://wiki.example.com";
|
||||
|
||||
// Self hosted deployments only have one team, to ensure behavior is correct
|
||||
// we need to delete all teams before running tests
|
||||
return Team.destroy({
|
||||
truncate: true,
|
||||
});
|
||||
}
|
||||
|
||||
export function findLatestEvent(where: WhereOptions<Event> = {}) {
|
||||
return Event.findOne({
|
||||
where,
|
||||
order: [["createdAt", "DESC"]],
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1603,6 +1603,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.47.0.tgz#5478fdf443ff8158f9de171c704ae45308696c7d"
|
||||
integrity sha512-P6omY1zv5MItm93kLM8s2vr1HICJH8v0dvddDhysbIuZ+vcjOHg5Zbkf1mTkcmi2JA9oBG2anOkRnW8WJTS8Og==
|
||||
|
||||
"@faker-js/faker@^8.0.2":
|
||||
version "8.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@faker-js/faker/-/faker-8.0.2.tgz#bab698c5d3da9c52744e966e0e3eedb6c8b05c37"
|
||||
integrity sha512-Uo3pGspElQW91PCvKSIAXoEgAUlRnH29sX2/p89kg7sP1m2PzCufHINd0FhTXQf6DYGiUlVncdSPa2F9wxed2A==
|
||||
|
||||
"@formatjs/ecma402-abstract@1.12.0":
|
||||
version "1.12.0"
|
||||
resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.12.0.tgz#2fb5e8983d5fae2fad9ec6c77aec1803c2b88d8e"
|
||||
|
||||
Reference in New Issue
Block a user