✨ Add usage-based new pricing plans
This commit is contained in:
committed by
Baptiste Arnaud
parent
6a1eaea700
commit
898367a33b
@ -8,51 +8,88 @@ import {
|
||||
Typebot,
|
||||
Webhook,
|
||||
} from 'models'
|
||||
import { Plan, PrismaClient, WorkspaceRole } from 'db'
|
||||
import { GraphNavigation, Plan, PrismaClient, WorkspaceRole } from 'db'
|
||||
import { readFileSync } from 'fs'
|
||||
import { encrypt } from 'utils'
|
||||
import { createFakeResults, encrypt } from 'utils'
|
||||
|
||||
const prisma = new PrismaClient()
|
||||
|
||||
const proWorkspaceId = 'proWorkspaceViewer'
|
||||
const userId = 'userId'
|
||||
export const freeWorkspaceId = 'freeWorkspace'
|
||||
export const starterWorkspaceId = 'starterWorkspace'
|
||||
|
||||
export const teardownDatabase = async () => {
|
||||
try {
|
||||
await prisma.workspace.deleteMany({
|
||||
where: { members: { some: { userId: { in: ['proUser'] } } } },
|
||||
})
|
||||
await prisma.user.deleteMany({
|
||||
where: { id: { in: ['proUser'] } },
|
||||
})
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
return
|
||||
await prisma.workspace.deleteMany({
|
||||
where: {
|
||||
members: {
|
||||
some: { userId },
|
||||
},
|
||||
},
|
||||
})
|
||||
await prisma.user.deleteMany({
|
||||
where: { id: userId },
|
||||
})
|
||||
return prisma.webhook.deleteMany()
|
||||
}
|
||||
|
||||
export const setupDatabase = () => createUser()
|
||||
export const setupDatabase = async () => {
|
||||
await createWorkspaces()
|
||||
await createUser()
|
||||
}
|
||||
|
||||
export const createUser = () =>
|
||||
prisma.user.create({
|
||||
export const createWorkspaces = async () =>
|
||||
prisma.workspace.createMany({
|
||||
data: [
|
||||
{
|
||||
id: freeWorkspaceId,
|
||||
name: 'Free workspace',
|
||||
plan: Plan.FREE,
|
||||
},
|
||||
{
|
||||
id: starterWorkspaceId,
|
||||
name: 'Starter workspace',
|
||||
plan: Plan.STARTER,
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
export const createUser = async () => {
|
||||
await prisma.user.create({
|
||||
data: {
|
||||
id: 'proUser',
|
||||
id: userId,
|
||||
email: 'user@email.com',
|
||||
name: 'User',
|
||||
apiTokens: { create: { token: 'userToken', name: 'default' } },
|
||||
workspaces: {
|
||||
create: {
|
||||
role: WorkspaceRole.ADMIN,
|
||||
workspace: {
|
||||
create: {
|
||||
id: proWorkspaceId,
|
||||
name: 'Pro workspace',
|
||||
plan: Plan.PRO,
|
||||
name: 'John Doe',
|
||||
graphNavigation: GraphNavigation.TRACKPAD,
|
||||
apiTokens: {
|
||||
createMany: {
|
||||
data: [
|
||||
{
|
||||
name: 'Token 1',
|
||||
token: 'jirowjgrwGREHEtoken1',
|
||||
createdAt: new Date(2022, 1, 1),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Github',
|
||||
token: 'jirowjgrwGREHEgdrgithub',
|
||||
createdAt: new Date(2022, 1, 2),
|
||||
},
|
||||
{
|
||||
name: 'N8n',
|
||||
token: 'jirowjgrwGREHrgwhrwn8n',
|
||||
createdAt: new Date(2022, 1, 3),
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
await prisma.memberInWorkspace.createMany({
|
||||
data: [
|
||||
{ role: WorkspaceRole.ADMIN, userId, workspaceId: freeWorkspaceId },
|
||||
{ role: WorkspaceRole.ADMIN, userId, workspaceId: starterWorkspaceId },
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
export const createWebhook = (typebotId: string, webhook?: Partial<Webhook>) =>
|
||||
prisma.webhook.create({
|
||||
@ -66,12 +103,12 @@ export const createWebhook = (typebotId: string, webhook?: Partial<Webhook>) =>
|
||||
|
||||
export const createTypebots = async (partialTypebots: Partial<Typebot>[]) => {
|
||||
await prisma.typebot.createMany({
|
||||
data: partialTypebots.map(parseTestTypebot) as any[],
|
||||
data: partialTypebots.map(parseTestTypebot),
|
||||
})
|
||||
return prisma.publicTypebot.createMany({
|
||||
data: partialTypebots.map((t) =>
|
||||
parseTypebotToPublicTypebot(t.id + '-published', parseTestTypebot(t))
|
||||
) as any[],
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
@ -107,7 +144,7 @@ const parseTestTypebot = (partialTypebot: Partial<Typebot>): Typebot => ({
|
||||
id: partialTypebot.id ?? 'typebot',
|
||||
folderId: null,
|
||||
name: 'My typebot',
|
||||
workspaceId: proWorkspaceId,
|
||||
workspaceId: freeWorkspaceId,
|
||||
icon: null,
|
||||
theme: defaultTheme,
|
||||
settings: defaultSettings,
|
||||
@ -170,7 +207,7 @@ export const importTypebotInDatabase = async (
|
||||
const typebot: Typebot = {
|
||||
...JSON.parse(readFileSync(path).toString()),
|
||||
...updates,
|
||||
workspaceId: proWorkspaceId,
|
||||
workspaceId: starterWorkspaceId,
|
||||
}
|
||||
await prisma.typebot.create({
|
||||
data: typebot,
|
||||
@ -183,39 +220,7 @@ export const importTypebotInDatabase = async (
|
||||
})
|
||||
}
|
||||
|
||||
export const createResults = async ({ typebotId }: { typebotId: string }) => {
|
||||
await prisma.result.deleteMany()
|
||||
await prisma.result.createMany({
|
||||
data: [
|
||||
...Array.from(Array(200)).map((_, idx) => {
|
||||
const today = new Date()
|
||||
const rand = Math.random()
|
||||
return {
|
||||
id: `result${idx}`,
|
||||
typebotId,
|
||||
createdAt: new Date(
|
||||
today.setTime(today.getTime() + 1000 * 60 * 60 * 24 * idx)
|
||||
),
|
||||
isCompleted: rand > 0.5,
|
||||
}
|
||||
}),
|
||||
],
|
||||
})
|
||||
return createAnswers()
|
||||
}
|
||||
|
||||
const createAnswers = () => {
|
||||
return prisma.answer.createMany({
|
||||
data: [
|
||||
...Array.from(Array(200)).map((_, idx) => ({
|
||||
resultId: `result${idx}`,
|
||||
content: `content${idx}`,
|
||||
blockId: 'block1',
|
||||
groupId: 'group1',
|
||||
})),
|
||||
],
|
||||
})
|
||||
}
|
||||
export const createResults = createFakeResults(prisma)
|
||||
|
||||
export const createSmtpCredentials = (
|
||||
id: string,
|
||||
@ -229,7 +234,7 @@ export const createSmtpCredentials = (
|
||||
iv,
|
||||
name: smtpData.from.email as string,
|
||||
type: CredentialsType.SMTP,
|
||||
workspaceId: proWorkspaceId,
|
||||
workspaceId: freeWorkspaceId,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ test.beforeAll(async () => {
|
||||
{ id: typebotId }
|
||||
)
|
||||
await createWebhook(typebotId)
|
||||
await createResults({ typebotId })
|
||||
await createResults({ typebotId, count: 20 })
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
|
@ -3,12 +3,12 @@ import cuid from 'cuid'
|
||||
import path from 'path'
|
||||
import { parse } from 'papaparse'
|
||||
import { typebotViewer } from '../services/selectorUtils'
|
||||
import { importTypebotInDatabase } from '../services/database'
|
||||
import { createResults, importTypebotInDatabase } from '../services/database'
|
||||
import { readFileSync } from 'fs'
|
||||
import { isDefined } from 'utils'
|
||||
import { mockSessionApiCalls } from 'playwright/services/browser'
|
||||
import { describe } from 'node:test'
|
||||
|
||||
test.beforeEach(({ page }) => mockSessionApiCalls(page))
|
||||
const THREE_GIGABYTES = 3 * 1024 * 1024 * 1024
|
||||
|
||||
test('should work as expected', async ({ page, browser }) => {
|
||||
const typebotId = cuid()
|
||||
@ -85,3 +85,46 @@ test('should work as expected', async ({ page, browser }) => {
|
||||
page2.locator('span:has-text("The specified key does not exist.")')
|
||||
).toBeVisible()
|
||||
})
|
||||
|
||||
describe('Storage limit is reached', () => {
|
||||
const typebotId = cuid()
|
||||
|
||||
test.beforeAll(async () => {
|
||||
await importTypebotInDatabase(
|
||||
path.join(__dirname, '../fixtures/typebots/fileUpload.json'),
|
||||
{
|
||||
id: typebotId,
|
||||
publicId: `${typebotId}-public`,
|
||||
}
|
||||
)
|
||||
await createResults({
|
||||
typebotId,
|
||||
count: 20,
|
||||
fakeStorage: THREE_GIGABYTES,
|
||||
})
|
||||
})
|
||||
|
||||
test("shouldn't upload anything if limit has been reached", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto(`/${typebotId}-public`)
|
||||
await typebotViewer(page)
|
||||
.locator(`input[type="file"]`)
|
||||
.setInputFiles([
|
||||
path.join(__dirname, '../fixtures/typebots/api.json'),
|
||||
path.join(__dirname, '../fixtures/typebots/fileUpload.json'),
|
||||
path.join(__dirname, '../fixtures/typebots/hugeGroup.json'),
|
||||
])
|
||||
await expect(typebotViewer(page).locator(`text="3"`)).toBeVisible()
|
||||
await typebotViewer(page).locator('text="Upload 3 files"').click()
|
||||
await expect(
|
||||
typebotViewer(page).locator(`text="3 files uploaded"`)
|
||||
).toBeVisible()
|
||||
await page.evaluate(() =>
|
||||
window.localStorage.setItem('workspaceId', 'starterWorkspace')
|
||||
)
|
||||
await page.goto(`${process.env.BUILDER_URL}/typebots/${typebotId}/results`)
|
||||
await expect(page.locator('text="150%"')).toBeVisible()
|
||||
await expect(page.locator('text="api.json"')).toBeHidden()
|
||||
})
|
||||
})
|
||||
|
23
apps/viewer/playwright/tests/limits.spec.ts
Normal file
23
apps/viewer/playwright/tests/limits.spec.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import {
|
||||
createResults,
|
||||
freeWorkspaceId,
|
||||
importTypebotInDatabase,
|
||||
} from '../services/database'
|
||||
import cuid from 'cuid'
|
||||
import path from 'path'
|
||||
|
||||
test('should not start if chat limit is reached', async ({ page }) => {
|
||||
const typebotId = cuid()
|
||||
await importTypebotInDatabase(
|
||||
path.join(__dirname, '../fixtures/typebots/fileUpload.json'),
|
||||
{
|
||||
id: typebotId,
|
||||
publicId: `${typebotId}-public`,
|
||||
workspaceId: freeWorkspaceId,
|
||||
}
|
||||
)
|
||||
await createResults({ typebotId, count: 320 })
|
||||
await page.goto(`/${typebotId}-public`)
|
||||
await expect(page.locator('text="This bot is now closed."')).toBeVisible()
|
||||
})
|
Reference in New Issue
Block a user