2023-06-26 17:12:58 +03:00
|
|
|
import { ok } from 'node:assert';
|
2023-06-29 04:45:45 +03:00
|
|
|
import { afterEach, beforeEach, describe, it } from 'node:test';
|
2023-06-26 17:12:58 +03:00
|
|
|
|
|
|
|
import type { INestApplication } from '@nestjs/common';
|
|
|
|
import { Test } from '@nestjs/testing';
|
|
|
|
import { PrismaClient } from '@prisma/client';
|
2023-06-29 04:45:45 +03:00
|
|
|
// @ts-expect-error graphql-upload is not typed
|
|
|
|
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';
|
2023-06-26 17:12:58 +03:00
|
|
|
import request from 'supertest';
|
|
|
|
|
|
|
|
import { AppModule } from '../app';
|
|
|
|
import type { TokenType } from '../modules/auth';
|
|
|
|
import type { UserType } from '../modules/users';
|
|
|
|
import type { WorkspaceType } from '../modules/workspaces';
|
|
|
|
|
|
|
|
const gql = '/graphql';
|
|
|
|
|
2023-06-29 04:45:45 +03:00
|
|
|
describe('Workspace Module', () => {
|
2023-06-26 17:12:58 +03:00
|
|
|
let app: INestApplication;
|
|
|
|
|
|
|
|
// cleanup database before each test
|
|
|
|
beforeEach(async () => {
|
|
|
|
const client = new PrismaClient();
|
|
|
|
await client.$connect();
|
|
|
|
await client.user.deleteMany({});
|
|
|
|
await client.$disconnect();
|
|
|
|
});
|
|
|
|
|
|
|
|
beforeEach(async () => {
|
|
|
|
const module = await Test.createTestingModule({
|
|
|
|
imports: [AppModule],
|
|
|
|
}).compile();
|
|
|
|
app = module.createNestApplication();
|
2023-06-29 04:45:45 +03:00
|
|
|
app.use(
|
|
|
|
graphqlUploadExpress({
|
|
|
|
maxFileSize: 10 * 1024 * 1024,
|
|
|
|
maxFiles: 5,
|
|
|
|
})
|
|
|
|
);
|
2023-06-26 17:12:58 +03:00
|
|
|
await app.init();
|
|
|
|
});
|
|
|
|
|
|
|
|
afterEach(async () => {
|
|
|
|
await app.close();
|
|
|
|
});
|
|
|
|
|
|
|
|
async function registerUser(
|
|
|
|
name: string,
|
|
|
|
email: string,
|
|
|
|
password: string
|
|
|
|
): Promise<UserType & { token: TokenType }> {
|
|
|
|
const res = await request(app.getHttpServer())
|
|
|
|
.post(gql)
|
|
|
|
.send({
|
|
|
|
query: `
|
|
|
|
mutation {
|
|
|
|
register(name: "${name}", email: "${email}", password: "${password}") {
|
|
|
|
id, name, email, token { token }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
})
|
|
|
|
.expect(200);
|
|
|
|
return res.body.data.register;
|
|
|
|
}
|
|
|
|
|
|
|
|
async function createWorkspace(token: string): Promise<WorkspaceType> {
|
|
|
|
const res = await request(app.getHttpServer())
|
|
|
|
.post(gql)
|
|
|
|
.auth(token, { type: 'bearer' })
|
2023-06-29 04:45:45 +03:00
|
|
|
.field(
|
|
|
|
'operations',
|
|
|
|
JSON.stringify({
|
|
|
|
name: 'createWorkspace',
|
|
|
|
query: `mutation createWorkspace($init: Upload!) {
|
|
|
|
createWorkspace(init: $init) {
|
2023-06-26 17:12:58 +03:00
|
|
|
id
|
|
|
|
}
|
2023-06-29 04:45:45 +03:00
|
|
|
}`,
|
|
|
|
variables: { init: null },
|
|
|
|
})
|
|
|
|
)
|
|
|
|
.field('map', JSON.stringify({ '0': ['variables.init'] }))
|
|
|
|
.attach('0', Buffer.from([0, 0]), 'init.data')
|
2023-06-26 17:12:58 +03:00
|
|
|
.expect(200);
|
|
|
|
return res.body.data.createWorkspace;
|
|
|
|
}
|
|
|
|
|
|
|
|
async function inviteUser(
|
|
|
|
token: string,
|
|
|
|
workspaceId: string,
|
|
|
|
email: string,
|
|
|
|
permission: string
|
|
|
|
): Promise<boolean> {
|
|
|
|
const res = await request(app.getHttpServer())
|
|
|
|
.post(gql)
|
|
|
|
.auth(token, { type: 'bearer' })
|
|
|
|
.send({
|
|
|
|
query: `
|
|
|
|
mutation {
|
|
|
|
invite(workspaceId: "${workspaceId}", email: "${email}", permission: ${permission})
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
})
|
|
|
|
.expect(200);
|
|
|
|
return res.body.data.invite;
|
|
|
|
}
|
|
|
|
|
|
|
|
async function acceptInvite(
|
|
|
|
token: string,
|
|
|
|
workspaceId: string
|
|
|
|
): Promise<boolean> {
|
|
|
|
const res = await request(app.getHttpServer())
|
|
|
|
.post(gql)
|
|
|
|
.auth(token, { type: 'bearer' })
|
|
|
|
.send({
|
|
|
|
query: `
|
|
|
|
mutation {
|
|
|
|
acceptInvite(workspaceId: "${workspaceId}")
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
})
|
|
|
|
.expect(200);
|
|
|
|
return res.body.data.acceptInvite;
|
|
|
|
}
|
|
|
|
|
|
|
|
async function leaveWorkspace(
|
|
|
|
token: string,
|
|
|
|
workspaceId: string
|
|
|
|
): Promise<boolean> {
|
|
|
|
const res = await request(app.getHttpServer())
|
|
|
|
.post(gql)
|
|
|
|
.auth(token, { type: 'bearer' })
|
|
|
|
.send({
|
|
|
|
query: `
|
|
|
|
mutation {
|
|
|
|
leaveWorkspace(workspaceId: "${workspaceId}")
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
})
|
|
|
|
.expect(200);
|
|
|
|
return res.body.data.leaveWorkspace;
|
|
|
|
}
|
|
|
|
|
|
|
|
async function revokeUser(
|
|
|
|
token: string,
|
|
|
|
workspaceId: string,
|
|
|
|
userId: string
|
|
|
|
): Promise<boolean> {
|
|
|
|
const res = await request(app.getHttpServer())
|
|
|
|
.post(gql)
|
|
|
|
.auth(token, { type: 'bearer' })
|
|
|
|
.send({
|
|
|
|
query: `
|
|
|
|
mutation {
|
|
|
|
revoke(workspaceId: "${workspaceId}", userId: "${userId}")
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
})
|
|
|
|
.expect(200);
|
|
|
|
return res.body.data.revoke;
|
|
|
|
}
|
|
|
|
|
2023-06-29 04:45:45 +03:00
|
|
|
it('should register a user', async () => {
|
2023-06-26 17:12:58 +03:00
|
|
|
const user = await registerUser('u1', 'u1@affine.pro', '123456');
|
|
|
|
ok(typeof user.id === 'string', 'user.id is not a string');
|
|
|
|
ok(user.name === 'u1', 'user.name is not valid');
|
|
|
|
ok(user.email === 'u1@affine.pro', 'user.email is not valid');
|
|
|
|
});
|
|
|
|
|
2023-06-29 04:45:45 +03:00
|
|
|
it('should create a workspace', async () => {
|
2023-06-26 17:12:58 +03:00
|
|
|
const user = await registerUser('u1', 'u1@affine.pro', '1');
|
|
|
|
|
|
|
|
const workspace = await createWorkspace(user.token.token);
|
|
|
|
ok(typeof workspace.id === 'string', 'workspace.id is not a string');
|
|
|
|
});
|
|
|
|
|
2023-06-29 04:45:45 +03:00
|
|
|
it('should invite a user', async () => {
|
2023-06-26 17:12:58 +03:00
|
|
|
const u1 = await registerUser('u1', 'u1@affine.pro', '1');
|
|
|
|
const u2 = await registerUser('u2', 'u2@affine.pro', '1');
|
|
|
|
|
|
|
|
const workspace = await createWorkspace(u1.token.token);
|
|
|
|
|
|
|
|
const invite = await inviteUser(
|
|
|
|
u1.token.token,
|
|
|
|
workspace.id,
|
|
|
|
u2.email,
|
|
|
|
'Admin'
|
|
|
|
);
|
|
|
|
ok(invite === true, 'failed to invite user');
|
|
|
|
});
|
|
|
|
|
2023-06-29 04:45:45 +03:00
|
|
|
it('should accept an invite', async () => {
|
2023-06-26 17:12:58 +03:00
|
|
|
const u1 = await registerUser('u1', 'u1@affine.pro', '1');
|
|
|
|
const u2 = await registerUser('u2', 'u2@affine.pro', '1');
|
|
|
|
|
|
|
|
const workspace = await createWorkspace(u1.token.token);
|
|
|
|
await inviteUser(u1.token.token, workspace.id, u2.email, 'Admin');
|
|
|
|
|
|
|
|
const accept = await acceptInvite(u2.token.token, workspace.id);
|
|
|
|
ok(accept === true, 'failed to accept invite');
|
|
|
|
});
|
|
|
|
|
2023-06-29 04:45:45 +03:00
|
|
|
it('should leave a workspace', async () => {
|
2023-06-26 17:12:58 +03:00
|
|
|
const u1 = await registerUser('u1', 'u1@affine.pro', '1');
|
|
|
|
const u2 = await registerUser('u2', 'u2@affine.pro', '1');
|
|
|
|
|
|
|
|
const workspace = await createWorkspace(u1.token.token);
|
|
|
|
await inviteUser(u1.token.token, workspace.id, u2.email, 'Admin');
|
|
|
|
await acceptInvite(u2.token.token, workspace.id);
|
|
|
|
|
|
|
|
const leave = await leaveWorkspace(u2.token.token, workspace.id);
|
|
|
|
ok(leave === true, 'failed to leave workspace');
|
|
|
|
});
|
|
|
|
|
2023-06-29 04:45:45 +03:00
|
|
|
it('should revoke a user', async () => {
|
2023-06-26 17:12:58 +03:00
|
|
|
const u1 = await registerUser('u1', 'u1@affine.pro', '1');
|
|
|
|
const u2 = await registerUser('u2', 'u2@affine.pro', '1');
|
|
|
|
|
|
|
|
const workspace = await createWorkspace(u1.token.token);
|
|
|
|
await inviteUser(u1.token.token, workspace.id, u2.email, 'Admin');
|
|
|
|
|
|
|
|
const revoke = await revokeUser(u1.token.token, workspace.id, u2.id);
|
|
|
|
ok(revoke === true, 'failed to revoke user');
|
|
|
|
});
|
|
|
|
});
|