Files
speckle-server/packages/server/modules/workspaces/tests/integration/workspaces.graph.spec.ts
T
Chuck Driesler 7bb40134eb fix(workspaces): add filtering to workspace team query (#2586)
* chore(workspaces): add some tests for new filters

* fix(workspaces): args style
2024-08-08 07:15:55 +02:00

405 lines
12 KiB
TypeScript

import { expect } from 'chai'
import cryptoRandomString from 'crypto-random-string'
import {
createTestContext,
testApolloServer,
TestApolloServer
} from '@/test/graphqlHelper'
import {
BasicTestUser,
createAuthTokenForUser,
createTestUsers
} from '@/test/authHelper'
import { Roles } from '@speckle/shared'
import {
CreateProjectInviteDocument,
CreateWorkspaceDocument,
DeleteWorkspaceDocument,
GetActiveUserWorkspacesDocument,
GetWorkspaceDocument,
GetWorkspaceTeamDocument,
UpdateWorkspaceDocument,
UpdateWorkspaceRoleDocument,
ActiveUserLeaveWorkspaceDocument
} from '@/test/graphql/generated/graphql'
import { beforeEachContext } from '@/test/hooks'
import { AllScopes } from '@/modules/core/helpers/mainConstants'
import {
BasicTestWorkspace,
createTestWorkspace,
createWorkspaceInviteDirectly
} from '@/modules/workspaces/tests/helpers/creation'
import { BasicTestCommit, createTestCommit } from '@/test/speckle-helpers/commitHelper'
import { BasicTestStream, createTestStream } from '@/test/speckle-helpers/streamHelper'
import knex from '@/db/knex'
describe('Workspaces GQL CRUD', () => {
let apollo: TestApolloServer
const testAdminUser: BasicTestUser = {
id: '',
name: 'John Speckle',
email: 'john-speckle@example.org',
role: Roles.Server.Admin
}
const testMemberUser: BasicTestUser = {
id: '',
name: 'Alice speckle',
email: 'alice-speckle@example.org',
role: Roles.Server.User
}
before(async () => {
await beforeEachContext()
await createTestUsers([testAdminUser, testMemberUser])
const token = await createAuthTokenForUser(testAdminUser.id, AllScopes)
apollo = await testApolloServer({
context: createTestContext({
auth: true,
userId: testAdminUser.id,
token,
role: testAdminUser.role,
scopes: AllScopes
})
})
})
describe('retrieval operations', () => {
const workspace: BasicTestWorkspace = {
id: '',
ownerId: '',
name: 'Workspace A'
}
const testMemberUser: BasicTestUser = {
id: '',
name: 'Jimmy Speckle',
email: 'jimmy-speckle@example.org'
}
before(async () => {
await createTestWorkspace(workspace, testUser)
await createTestUser(testMemberUser)
await apollo.execute(UpdateWorkspaceRoleDocument, {
input: {
userId: testMemberUser.id,
workspaceId: workspace.id,
role: Roles.Workspace.Member
}
})
})
describe('query workspace', () => {
it('should return a workspace that exists', async () => {
const res = await apollo.execute(GetWorkspaceDocument, {
workspaceId: workspace.id
})
expect(res).to.not.haveGraphQLErrors()
expect(res.data?.workspace).to.exist
})
it('throw a not found error if the workspace does not exist', async () => {
const res = await apollo.execute(GetWorkspaceDocument, {
workspaceId: cryptoRandomString({ length: 6 })
})
expect(res).to.haveGraphQLErrors('not found')
})
})
describe('query workspace.team', () => {
it('should return workspace members', async () => {
const res = await apollo.execute(GetWorkspaceTeamDocument, {
workspaceId: workspace.id
})
expect(res).to.not.haveGraphQLErrors()
expect(res.data?.workspace.team.length).to.equal(2)
})
it('should respect search filters', async () => {
const res = await apollo.execute(GetWorkspaceTeamDocument, {
workspaceId: workspace.id,
filter: {
search: 'jimmy'
}
})
expect(res).to.not.haveGraphQLErrors()
expect(res.data?.workspace.team.length).to.equal(1)
})
it('should respect role filters', async () => {
const res = await apollo.execute(GetWorkspaceTeamDocument, {
workspaceId: workspace.id,
filter: {
role: 'workspace:member'
}
})
expect(res).to.not.haveGraphQLErrors()
expect(res.data?.workspace.team.length).to.equal(1)
})
})
describe('query activeUser.workspaces', () => {
it('should return all workspaces for a user', async () => {
const res = await apollo.execute(GetActiveUserWorkspacesDocument, {})
expect(res).to.not.haveGraphQLErrors()
expect(res.data?.activeUser?.workspaces?.items?.length).to.equal(1)
})
})
})
describe('management operations', () => {
describe('mutation workspaceMutations.create', () => {
it('should create a workspace', async () => {
const workspaceName = cryptoRandomString({ length: 6 })
const createRes = await apollo.execute(CreateWorkspaceDocument, {
input: { name: workspaceName }
})
const getRes = await apollo.execute(GetWorkspaceDocument, {
workspaceId: createRes.data!.workspaceMutations.create.id
})
expect(createRes).to.not.haveGraphQLErrors()
expect(getRes).to.not.haveGraphQLErrors()
expect(getRes.data?.workspace).to.exist
expect(getRes.data?.workspace?.name).to.equal(workspaceName)
})
})
describe('mutation workspaceMutations.delete', () => {
const workspace: BasicTestWorkspace = {
id: '',
ownerId: '',
name: 'My Test Workspace'
}
const workspaceProject: BasicTestStream = {
id: '',
ownerId: '',
name: 'My Test Project',
isPublic: false
}
before(async () => {
await createTestWorkspace(workspace, testAdminUser)
workspaceProject.workspaceId = workspace.id
await createWorkspaceInviteDirectly(
{
workspaceId: workspace.id,
input: {
userId: testMemberUser.id
}
},
testAdminUser.id
)
await createTestStream(workspaceProject, testAdminUser)
await apollo.execute(CreateProjectInviteDocument, {
projectId: workspaceProject.id,
input: { userId: testMemberUser.id }
})
const testVersion: BasicTestCommit = {
id: cryptoRandomString({ length: 10 }),
streamId: workspaceProject.id,
objectId: '',
authorId: ''
}
createTestCommit(testVersion, {
owner: testAdminUser,
stream: workspaceProject
})
})
it('should delete the workspace', async () => {
const deleteRes = await apollo.execute(DeleteWorkspaceDocument, {
workspaceId: workspace.id
})
const getRes = await apollo.execute(GetWorkspaceDocument, {
workspaceId: workspace.id
})
expect(deleteRes).to.not.haveGraphQLErrors()
expect(getRes).to.haveGraphQLErrors('Workspace not found')
})
it('should throw if non-workspace-admin triggers delete', async () => {
const memberApollo: TestApolloServer = (apollo = await testApolloServer({
context: createTestContext({
auth: true,
userId: testAdminUser.id,
token: '',
role: testAdminUser.role,
scopes: AllScopes
})
}))
const res = await memberApollo.execute(DeleteWorkspaceDocument, {
workspaceId: workspace.id
})
expect(res).to.haveGraphQLErrors('not authorized')
})
it('should delete all workspace projects', async () => {
const projects = await knex('streams').where({ workspaceId: workspace.id })
expect(projects.length).to.equal(0)
})
it('should delete pending workspace and project invites', async () => {
const invites = await knex('server_invites').where({
inviterId: testAdminUser.id
})
expect(invites.length).to.equal(0)
})
it('should delete all workspace project commits', async () => {
const versions = await knex('stream_commits').where({
streamId: workspaceProject.id
})
expect(versions.length).to.equal(0)
})
})
describe('mutation workspaceMutations.update', () => {
const workspace: BasicTestWorkspace = {
id: '',
ownerId: '',
name: cryptoRandomString({ length: 6 }),
description: cryptoRandomString({ length: 12 })
}
beforeEach(async () => {
await createTestWorkspace(workspace, testAdminUser)
})
it('should update a workspace', async () => {
const workspaceName = cryptoRandomString({ length: 6 })
const updateRes = await apollo.execute(UpdateWorkspaceDocument, {
input: {
id: workspace.id,
name: workspaceName
}
})
const { data } = await apollo.execute(GetWorkspaceDocument, {
workspaceId: workspace.id
})
expect(updateRes).to.not.haveGraphQLErrors()
expect(data?.workspace.name).to.equal(workspaceName)
})
it('should not allow workspace name to be empty', async () => {
const updateRes = await apollo.execute(UpdateWorkspaceDocument, {
input: {
id: workspace.id,
name: ''
}
})
const { data } = await apollo.execute(GetWorkspaceDocument, {
workspaceId: workspace.id
})
expect(updateRes).to.not.haveGraphQLErrors()
expect(data?.workspace.name).to.equal(workspace.name)
})
it('should allow workspace description to be empty', async () => {
const updateRes = await apollo.execute(UpdateWorkspaceDocument, {
input: {
id: workspace.id,
description: ''
}
})
const { data } = await apollo.execute(GetWorkspaceDocument, {
workspaceId: workspace.id
})
expect(updateRes).to.not.haveGraphQLErrors()
expect(data?.workspace.description).to.equal('')
})
})
describe('mutation activeUserMutations.userWorkspaceMutations', () => {
describe('leave', () => {
it('allows the active user to leave a workspace', async () => {
const name = cryptoRandomString({ length: 6 })
const workspaceCreateResult = await apollo.execute(CreateWorkspaceDocument, {
input: { name }
})
const id = workspaceCreateResult.data?.workspaceMutations.create.id
if (!id) throw new Error('This should have succeeded')
await apollo.execute(UpdateWorkspaceRoleDocument, {
input: {
userId: testMemberUser.id,
workspaceId: id,
role: Roles.Workspace.Admin
}
})
let userWorkspaces = await apollo.execute(GetActiveUserWorkspacesDocument, {})
expect(
userWorkspaces.data?.activeUser?.workspaces.items
.map((i) => i.name)
.includes(name)
).to.be.true
const leaveResult = await apollo.execute(ActiveUserLeaveWorkspaceDocument, {
id
})
expect(leaveResult.errors).to.be.undefined
userWorkspaces = await apollo.execute(GetActiveUserWorkspacesDocument, {})
expect(
userWorkspaces.data?.activeUser?.workspaces.items
.map((i) => i.name)
.includes(name)
).to.be.false
})
it('stops the last workspace admin from leaving the workspace', async () => {
const name = cryptoRandomString({ length: 6 })
const workspaceCreateResult = await apollo.execute(CreateWorkspaceDocument, {
input: { name }
})
const id = workspaceCreateResult.data?.workspaceMutations.create.id
if (!id) throw new Error('This should have succeeded')
const leaveResult = await apollo.execute(ActiveUserLeaveWorkspaceDocument, {
id
})
expect(leaveResult.errors?.length).to.be.greaterThanOrEqual(1)
const userWorkspaces = await apollo.execute(
GetActiveUserWorkspacesDocument,
{}
)
expect(
userWorkspaces.data?.activeUser?.workspaces.items
.map((i) => i.name)
.includes(name)
).to.be.true
})
})
})
})
})