Files
speckle-server/packages/server/modules/gatekeeper/tests/integration/workspace.graph.spec.ts
T
Kristaps Fabians Geikins 4b06f42db7 chore(server): run TS files directly (no compilation) (#5134)
* sort of works

* type fixes

* added option to run old way too
2025-07-23 11:20:40 +02:00

316 lines
10 KiB
TypeScript

import { db } from '@/db/knex'
import { AllScopes } from '@/modules/core/helpers/mainConstants'
import {
createRandomEmail,
createRandomString
} from '@/modules/core/helpers/testHelpers'
import { WorkspaceSeatType } from '@/modules/gatekeeper/domain/billing'
import { upsertWorkspaceSubscriptionFactory } from '@/modules/gatekeeper/repositories/billing'
import { getFeatureFlags } from '@/modules/shared/helpers/envHelper'
import {
assignToWorkspace,
createTestWorkspace
} from '@/modules/workspaces/tests/helpers/creation'
import type { BasicTestUser } from '@/test/authHelper'
import {
createAuthTokenForUser,
createTestUser,
createTestUsers,
login
} from '@/test/authHelper'
import {
GetWorkspaceDocument,
GetWorkspacePlanUsageDocument,
GetWorkspaceWithSubscriptionDocument
} from '@/modules/core/graph/generated/graphql'
import type { TestApolloServer } from '@/test/graphqlHelper'
import { createTestContext, testApolloServer } from '@/test/graphqlHelper'
import { beforeEachContext } from '@/test/hooks'
import type { BasicTestBranch } from '@/test/speckle-helpers/branchHelper'
import { createTestBranches } from '@/test/speckle-helpers/branchHelper'
import { createTestCommit, createTestObject } from '@/test/speckle-helpers/commitHelper'
import type { BasicTestStream } from '@/test/speckle-helpers/streamHelper'
import { createTestStream } from '@/test/speckle-helpers/streamHelper'
import { PaidWorkspacePlans, Roles } from '@speckle/shared'
import { expect } from 'chai'
import cryptoRandomString from 'crypto-random-string'
import dayjs from 'dayjs'
const { FF_BILLING_INTEGRATION_ENABLED, FF_WORKSPACES_MODULE_ENABLED } =
getFeatureFlags()
describe('Workspaces Billing', () => {
let apollo: TestApolloServer
const testAdminUser: BasicTestUser = {
id: '',
name: 'John Speckle',
email: 'john-speckle@example.org',
role: Roles.Server.Admin,
verified: true
}
before(async () => {
await beforeEachContext()
await createTestUsers([testAdminUser])
const token = await createAuthTokenForUser(testAdminUser.id, AllScopes)
apollo = await testApolloServer({
context: await createTestContext({
auth: true,
userId: testAdminUser.id,
token,
role: testAdminUser.role,
scopes: AllScopes
})
})
})
;(FF_BILLING_INTEGRATION_ENABLED ? describe : describe.skip)(
'query workspace.readOnly',
() => {
it('should return false for workspace plan status valid', async () => {
const workspace = {
id: '',
name: 'test ws',
slug: cryptoRandomString({ length: 10 }),
ownerId: ''
}
await createTestWorkspace(workspace, testAdminUser, {
addPlan: { name: PaidWorkspacePlans.Team, status: 'valid' }
})
const res = await apollo.execute(GetWorkspaceDocument, {
workspaceId: workspace.id
})
expect(res).to.not.haveGraphQLErrors()
expect(res.data?.workspace?.readOnly).to.be.false
})
it('should return true for workspace plan status canceled', async () => {
const workspace = {
id: '',
name: 'test ws',
slug: cryptoRandomString({ length: 10 }),
ownerId: ''
}
await createTestWorkspace(workspace, testAdminUser, {
addPlan: { name: PaidWorkspacePlans.Team, status: 'canceled' }
})
const res = await apollo.execute(GetWorkspaceDocument, {
workspaceId: workspace.id
})
expect(res).to.not.haveGraphQLErrors()
expect(res.data?.workspace?.readOnly).to.be.true
})
}
)
;(FF_BILLING_INTEGRATION_ENABLED ? describe : describe.skip)(
'workspace.subscription',
() => {
describe('subscription.seats', () => {
it('should return the number of assigned seats', async () => {
const user = await createTestUser({
name: createRandomString(),
email: createRandomEmail(),
role: Roles.Server.Admin,
verified: true
})
const workspace = {
id: createRandomString(),
name: createRandomString(),
slug: cryptoRandomString({ length: 10 }),
ownerId: user.id
}
await createTestWorkspace(workspace, user, {
addPlan: { name: 'pro', status: 'valid' }
})
await upsertWorkspaceSubscriptionFactory({ db })({
workspaceSubscription: {
workspaceId: workspace.id,
createdAt: new Date(),
updatedAt: new Date(),
currentBillingCycleEnd: dayjs().add(1, 'month').toDate(),
currency: 'usd',
billingInterval: 'monthly',
updateIntent: null,
subscriptionData: {
subscriptionId: cryptoRandomString({ length: 10 }),
customerId: cryptoRandomString({ length: 10 }),
cancelAt: null,
status: 'active',
currentPeriodEnd: new Date(),
products: [
{
priceId: createRandomString(),
quantity: 12,
productId: createRandomString(),
subscriptionItemId: createRandomString()
}
]
}
}
})
const session = await login(user)
const res = await session.execute(GetWorkspaceWithSubscriptionDocument, {
workspaceId: workspace.id
})
expect(res).to.not.haveGraphQLErrors()
const seats = res.data?.workspace.subscription?.seats
expect(seats?.editors.assigned).to.eq(1)
})
it('should return the number of viewers', async () => {
const user = await createTestUser({
name: createRandomString(),
email: createRandomEmail(),
role: Roles.Server.Admin,
verified: true
})
const workspace = {
id: createRandomString(),
name: createRandomString(),
slug: cryptoRandomString({ length: 10 }),
ownerId: user.id
}
await createTestWorkspace(workspace, user, {
addPlan: { name: 'pro', status: 'valid' }
})
await upsertWorkspaceSubscriptionFactory({ db })({
workspaceSubscription: {
workspaceId: workspace.id,
createdAt: new Date(),
updatedAt: new Date(),
currentBillingCycleEnd: dayjs().add(1, 'month').toDate(),
currency: 'usd',
updateIntent: null,
billingInterval: 'monthly',
subscriptionData: {
subscriptionId: cryptoRandomString({ length: 10 }),
customerId: cryptoRandomString({ length: 10 }),
cancelAt: null,
status: 'active',
currentPeriodEnd: new Date(),
products: [
{
priceId: createRandomString(),
quantity: 12,
productId: createRandomString(),
subscriptionItemId: createRandomString()
}
]
}
}
})
const viewer1 = await createTestUser({
name: createRandomString(),
email: createRandomEmail(),
role: Roles.Server.User,
verified: true
})
await assignToWorkspace(
workspace,
viewer1,
Roles.Workspace.Member,
WorkspaceSeatType.Viewer
)
const viewer2 = await createTestUser({
name: createRandomString(),
email: createRandomEmail(),
role: Roles.Server.User,
verified: true
})
await assignToWorkspace(
workspace,
viewer2,
Roles.Workspace.Member,
WorkspaceSeatType.Viewer
)
const session = await login(user)
const res = await session.execute(GetWorkspaceWithSubscriptionDocument, {
workspaceId: workspace.id
})
expect(res).to.not.haveGraphQLErrors()
const seats = res.data?.workspace.subscription?.seats
expect(seats?.viewers.assigned).to.eq(2)
})
})
}
)
;(FF_WORKSPACES_MODULE_ENABLED ? describe : describe.skip)(
'workspace.subscription.usage',
() => {
it('should return accurate usage information', async () => {
const user = await createTestUser({
name: createRandomString(),
email: createRandomEmail(),
role: Roles.Server.Admin,
verified: true
})
const workspace = {
id: createRandomString(),
name: createRandomString(),
slug: cryptoRandomString({ length: 10 }),
ownerId: user.id
}
await createTestWorkspace(workspace, user, {
addPlan: { name: 'pro', status: 'valid' }
})
const project: BasicTestStream = {
id: createRandomString(),
name: createRandomString(),
ownerId: user.id,
isPublic: true,
workspaceId: workspace.id
}
await createTestStream(project, user)
const modelWithVersions: BasicTestBranch = {
id: '',
streamId: project.id,
authorId: user.id,
name: createRandomString()
}
const modelWithoutVersions: BasicTestBranch = {
id: '',
streamId: project.id,
authorId: user.id,
name: createRandomString()
}
await createTestBranches(
[modelWithVersions, modelWithoutVersions].map((branch) => ({
owner: user,
stream: project,
branch
}))
)
const objectId = await createTestObject({ projectId: project.id })
await createTestCommit({
id: '',
authorId: user.id,
objectId,
streamId: project.id,
branchName: modelWithVersions.name,
branchId: ''
})
const session = await login(user)
const res = await session.execute(GetWorkspacePlanUsageDocument, {
workspaceId: workspace.id
})
expect(res).to.not.haveGraphQLErrors()
expect(res?.data?.workspace?.plan?.usage?.projectCount).to.equal(1)
expect(res?.data?.workspace?.plan?.usage?.modelCount).to.equal(2)
})
}
)
})