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-09-09 02:02:01 +03:00
|
|
|
import ava, { TestFn } from 'ava';
|
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';
|
2023-08-29 13:07:05 +03:00
|
|
|
import {
|
|
|
|
acceptInvite,
|
|
|
|
createWorkspace,
|
2023-08-31 15:29:25 +03:00
|
|
|
currentUser,
|
2023-08-29 13:07:05 +03:00
|
|
|
getPublicWorkspace,
|
|
|
|
getWorkspaceSharedPages,
|
|
|
|
inviteUser,
|
|
|
|
revokePage,
|
|
|
|
sharePage,
|
|
|
|
signUp,
|
|
|
|
updateWorkspace,
|
|
|
|
} from './utils';
|
2023-06-26 17:12:58 +03:00
|
|
|
|
2023-09-09 02:02:01 +03:00
|
|
|
const test = ava as TestFn<{
|
|
|
|
app: INestApplication;
|
|
|
|
client: PrismaClient;
|
|
|
|
}>;
|
2023-09-01 22:41:29 +03:00
|
|
|
|
2023-09-09 02:02:01 +03:00
|
|
|
test.beforeEach(async t => {
|
|
|
|
const client = new PrismaClient();
|
2023-09-01 22:41:29 +03:00
|
|
|
await client.$connect();
|
|
|
|
await client.user.deleteMany({});
|
|
|
|
await client.update.deleteMany({});
|
|
|
|
await client.snapshot.deleteMany({});
|
|
|
|
await client.workspace.deleteMany({});
|
|
|
|
await client.$disconnect();
|
|
|
|
const module = await Test.createTestingModule({
|
|
|
|
imports: [AppModule],
|
|
|
|
}).compile();
|
2023-09-09 02:02:01 +03:00
|
|
|
const app = module.createNestApplication();
|
2023-09-01 22:41:29 +03:00
|
|
|
app.use(
|
|
|
|
graphqlUploadExpress({
|
|
|
|
maxFileSize: 10 * 1024 * 1024,
|
|
|
|
maxFiles: 5,
|
|
|
|
})
|
|
|
|
);
|
|
|
|
await app.init();
|
2023-09-09 02:02:01 +03:00
|
|
|
t.context.client = client;
|
|
|
|
t.context.app = app;
|
2023-09-01 22:41:29 +03:00
|
|
|
});
|
|
|
|
|
2023-09-09 02:02:01 +03:00
|
|
|
test.afterEach(async t => {
|
|
|
|
await t.context.app.close();
|
2023-09-01 22:41:29 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
test('should register a user', async t => {
|
2023-09-09 02:02:01 +03:00
|
|
|
const user = await signUp(t.context.app, 'u1', 'u1@affine.pro', '123456');
|
2023-09-05 11:01:45 +03:00
|
|
|
t.is(typeof user.id, 'string', 'user.id is not a string');
|
|
|
|
t.is(user.name, 'u1', 'user.name is not valid');
|
|
|
|
t.is(user.email, 'u1@affine.pro', 'user.email is not valid');
|
2023-09-01 22:41:29 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
test.skip('should be throttled at call signUp', async t => {
|
2023-09-09 02:02:01 +03:00
|
|
|
const { app } = t.context;
|
2023-09-01 22:41:29 +03:00
|
|
|
let token = '';
|
|
|
|
for (let i = 0; i < 10; i++) {
|
|
|
|
token = (await signUp(app, `u${i}`, `u${i}@affine.pro`, `${i}`)).token
|
|
|
|
.token;
|
|
|
|
// throttles are applied to each endpoint separately
|
|
|
|
await currentUser(app, token);
|
|
|
|
}
|
2023-09-05 11:01:45 +03:00
|
|
|
await t.throwsAsync(() => signUp(app, 'u11', 'u11@affine.pro', '11'));
|
|
|
|
await t.throwsAsync(() => currentUser(app, token));
|
2023-09-01 22:41:29 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
test('should create a workspace', async t => {
|
2023-09-09 02:02:01 +03:00
|
|
|
const { app } = t.context;
|
2023-09-01 22:41:29 +03:00
|
|
|
const user = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
|
|
|
|
|
|
|
const workspace = await createWorkspace(app, user.token.token);
|
2023-09-05 11:01:45 +03:00
|
|
|
t.is(typeof workspace.id, 'string', 'workspace.id is not a string');
|
2023-09-01 22:41:29 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
test('should can publish workspace', async t => {
|
2023-09-09 02:02:01 +03:00
|
|
|
const { app } = t.context;
|
2023-09-01 22:41:29 +03:00
|
|
|
const user = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
|
|
|
const workspace = await createWorkspace(app, user.token.token);
|
|
|
|
|
|
|
|
const isPublic = await updateWorkspace(
|
|
|
|
app,
|
|
|
|
user.token.token,
|
|
|
|
workspace.id,
|
|
|
|
true
|
|
|
|
);
|
2023-09-05 11:01:45 +03:00
|
|
|
t.true(isPublic, 'failed to publish workspace');
|
2023-09-01 22:41:29 +03:00
|
|
|
|
|
|
|
const isPrivate = await updateWorkspace(
|
|
|
|
app,
|
|
|
|
user.token.token,
|
|
|
|
workspace.id,
|
|
|
|
false
|
|
|
|
);
|
2023-09-05 11:01:45 +03:00
|
|
|
t.false(isPrivate, 'failed to unpublish workspace');
|
2023-09-01 22:41:29 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
test('should can read published workspace', async t => {
|
2023-09-09 02:02:01 +03:00
|
|
|
const { app } = t.context;
|
2023-09-01 22:41:29 +03:00
|
|
|
const user = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
|
|
|
const workspace = await createWorkspace(app, user.token.token);
|
|
|
|
|
2023-09-05 11:01:45 +03:00
|
|
|
await t.throwsAsync(() => getPublicWorkspace(app, 'not_exists_ws'));
|
|
|
|
await t.throwsAsync(() => getPublicWorkspace(app, workspace.id));
|
2023-09-01 22:41:29 +03:00
|
|
|
|
|
|
|
await updateWorkspace(app, user.token.token, workspace.id, true);
|
|
|
|
|
|
|
|
const publicWorkspace = await getPublicWorkspace(app, workspace.id);
|
2023-09-05 11:01:45 +03:00
|
|
|
t.is(publicWorkspace.id, workspace.id, 'failed to get public workspace');
|
2023-09-01 22:41:29 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
test('should share a page', async t => {
|
2023-09-09 02:02:01 +03:00
|
|
|
const { app } = t.context;
|
2023-09-01 22:41:29 +03:00
|
|
|
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
|
|
|
const u2 = await signUp(app, 'u2', 'u2@affine.pro', '1');
|
|
|
|
|
|
|
|
const workspace = await createWorkspace(app, u1.token.token);
|
|
|
|
|
|
|
|
const share = await sharePage(app, u1.token.token, workspace.id, 'page1');
|
2023-09-05 11:01:45 +03:00
|
|
|
t.true(share, 'failed to share page');
|
2023-09-01 22:41:29 +03:00
|
|
|
const pages = await getWorkspaceSharedPages(
|
|
|
|
app,
|
|
|
|
u1.token.token,
|
|
|
|
workspace.id
|
|
|
|
);
|
2023-09-05 11:01:45 +03:00
|
|
|
t.is(pages.length, 1, 'failed to get shared pages');
|
|
|
|
t.is(pages[0], 'page1', 'failed to get shared page: page1');
|
2023-09-01 22:41:29 +03:00
|
|
|
|
|
|
|
const msg1 = await sharePage(app, u2.token.token, workspace.id, 'page2');
|
2023-09-05 11:01:45 +03:00
|
|
|
t.is(msg1, 'Permission denied', 'unauthorized user can share page');
|
2023-09-01 22:41:29 +03:00
|
|
|
const msg2 = await revokePage(app, u2.token.token, 'not_exists_ws', 'page2');
|
2023-09-05 11:01:45 +03:00
|
|
|
t.is(msg2, 'Permission denied', 'unauthorized user can share page');
|
2023-09-01 22:41:29 +03:00
|
|
|
|
|
|
|
await inviteUser(app, u1.token.token, workspace.id, u2.email, 'Admin');
|
|
|
|
await acceptInvite(app, u2.token.token, workspace.id);
|
|
|
|
const invited = await sharePage(app, u2.token.token, workspace.id, 'page2');
|
2023-09-05 11:01:45 +03:00
|
|
|
t.true(invited, 'failed to share page');
|
2023-09-01 22:41:29 +03:00
|
|
|
|
|
|
|
const revoke = await revokePage(app, u1.token.token, workspace.id, 'page1');
|
2023-09-05 11:01:45 +03:00
|
|
|
t.true(revoke, 'failed to revoke page');
|
2023-09-01 22:41:29 +03:00
|
|
|
const pages2 = await getWorkspaceSharedPages(
|
|
|
|
app,
|
|
|
|
u1.token.token,
|
|
|
|
workspace.id
|
|
|
|
);
|
2023-09-05 11:01:45 +03:00
|
|
|
t.is(pages2.length, 1, 'failed to get shared pages');
|
|
|
|
t.is(pages2[0], 'page2', 'failed to get shared page: page2');
|
2023-09-01 22:41:29 +03:00
|
|
|
|
|
|
|
const msg3 = await revokePage(app, u1.token.token, workspace.id, 'page3');
|
2023-09-05 11:01:45 +03:00
|
|
|
t.false(msg3, 'can revoke non-exists page');
|
2023-09-01 22:41:29 +03:00
|
|
|
|
|
|
|
const msg4 = await revokePage(app, u1.token.token, workspace.id, 'page2');
|
2023-09-05 11:01:45 +03:00
|
|
|
t.true(msg4, 'failed to revoke page');
|
2023-09-01 22:41:29 +03:00
|
|
|
const page3 = await getWorkspaceSharedPages(
|
|
|
|
app,
|
|
|
|
u1.token.token,
|
|
|
|
workspace.id
|
|
|
|
);
|
2023-09-05 11:01:45 +03:00
|
|
|
t.is(page3.length, 0, 'failed to get shared pages');
|
2023-09-01 22:41:29 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
test('should can get workspace doc', async t => {
|
2023-09-09 02:02:01 +03:00
|
|
|
const { app } = t.context;
|
2023-09-01 22:41:29 +03:00
|
|
|
const u1 = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
|
|
|
const u2 = await signUp(app, 'u2', 'u2@affine.pro', '2');
|
|
|
|
const workspace = await createWorkspace(app, u1.token.token);
|
|
|
|
|
|
|
|
const res1 = await request(app.getHttpServer())
|
|
|
|
.get(`/api/workspaces/${workspace.id}/docs/${workspace.id}`)
|
|
|
|
.auth(u1.token.token, { type: 'bearer' })
|
|
|
|
.expect(200)
|
|
|
|
.type('application/octet-stream');
|
|
|
|
|
2023-09-05 11:01:45 +03:00
|
|
|
t.deepEqual(
|
|
|
|
res1.body,
|
|
|
|
Buffer.from([0, 0]),
|
|
|
|
'failed to get doc with u1 token'
|
|
|
|
);
|
2023-09-01 22:41:29 +03:00
|
|
|
|
|
|
|
await request(app.getHttpServer())
|
|
|
|
.get(`/api/workspaces/${workspace.id}/docs/${workspace.id}`)
|
|
|
|
.expect(403);
|
|
|
|
await request(app.getHttpServer())
|
|
|
|
.get(`/api/workspaces/${workspace.id}/docs/${workspace.id}`)
|
|
|
|
.auth(u2.token.token, { type: 'bearer' })
|
|
|
|
.expect(403);
|
|
|
|
|
|
|
|
await inviteUser(app, u1.token.token, workspace.id, u2.email, 'Admin');
|
|
|
|
await request(app.getHttpServer())
|
|
|
|
.get(`/api/workspaces/${workspace.id}/docs/${workspace.id}`)
|
|
|
|
.auth(u2.token.token, { type: 'bearer' })
|
|
|
|
.expect(403);
|
|
|
|
|
|
|
|
await acceptInvite(app, u2.token.token, workspace.id);
|
|
|
|
const res2 = await request(app.getHttpServer())
|
|
|
|
.get(`/api/workspaces/${workspace.id}/docs/${workspace.id}`)
|
|
|
|
.auth(u2.token.token, { type: 'bearer' })
|
|
|
|
.expect(200)
|
|
|
|
.type('application/octet-stream');
|
|
|
|
|
2023-09-05 11:01:45 +03:00
|
|
|
t.deepEqual(
|
|
|
|
res2.body,
|
|
|
|
Buffer.from([0, 0]),
|
|
|
|
'failed to get doc with u2 token'
|
|
|
|
);
|
2023-09-01 22:41:29 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
test('should be able to get public workspace doc', async t => {
|
2023-09-09 02:02:01 +03:00
|
|
|
const { app } = t.context;
|
2023-09-01 22:41:29 +03:00
|
|
|
const user = await signUp(app, 'u1', 'u1@affine.pro', '1');
|
|
|
|
const workspace = await createWorkspace(app, user.token.token);
|
|
|
|
|
|
|
|
const isPublic = await updateWorkspace(
|
|
|
|
app,
|
|
|
|
user.token.token,
|
|
|
|
workspace.id,
|
|
|
|
true
|
|
|
|
);
|
|
|
|
|
2023-09-05 11:01:45 +03:00
|
|
|
t.true(isPublic, 'failed to publish workspace');
|
2023-09-01 22:41:29 +03:00
|
|
|
|
|
|
|
const res = await request(app.getHttpServer())
|
|
|
|
.get(`/api/workspaces/${workspace.id}/docs/${workspace.id}`)
|
|
|
|
.expect(200)
|
|
|
|
.type('application/octet-stream');
|
|
|
|
|
2023-09-05 11:01:45 +03:00
|
|
|
t.deepEqual(res.body, Buffer.from([0, 0]), 'failed to get public doc');
|
2023-06-26 17:12:58 +03:00
|
|
|
});
|