2
0

Add usage-based new pricing plans

This commit is contained in:
Baptiste Arnaud
2022-09-17 16:37:33 +02:00
committed by Baptiste Arnaud
parent 6a1eaea700
commit 898367a33b
144 changed files with 4631 additions and 1624 deletions

View File

@ -1,10 +1,6 @@
import test, { expect } from '@playwright/test'
import path from 'path'
import { mockSessionApiCalls } from 'playwright/services/browser'
test.beforeEach(({ page }) => mockSessionApiCalls(page))
// Can't test the update features because of the auth mocking.
test('should display user info properly', async ({ page }) => {
await page.goto('/typebots')
await page.click('text=Settings & Members')

View File

@ -0,0 +1,175 @@
import test, { expect } from '@playwright/test'
import cuid from 'cuid'
import { Plan } from 'db'
import {
addSubscriptionToWorkspace,
createResults,
createTypebots,
createWorkspace,
starterWorkspaceId,
} from '../services/database'
test('should display valid usage', async ({ page }) => {
const starterTypebotId = cuid()
createTypebots([{ id: starterTypebotId, workspaceId: starterWorkspaceId }])
await page.goto('/typebots')
await page.click('text=Settings & Members')
await page.click('text=Billing & Usage')
await expect(page.locator('text="/ 10,000"')).toBeVisible()
await expect(page.locator('text="/ 10 GB"')).toBeVisible()
await page.click('text=Pro workspace', { force: true })
await page.click('text=Pro workspace')
await page.click('text="Free workspace"')
await page.click('text=Settings & Members')
await page.click('text=Billing & Usage')
await expect(page.locator('text="/ 300"')).toBeVisible()
await page.click('text=Free workspace', { force: true })
await createResults({
idPrefix: 'usage',
count: 10,
typebotId: starterTypebotId,
isChronological: false,
fakeStorage: 1100 * 1024 * 1024,
})
await page.click('text=Free workspace')
await page.click('text="Starter workspace"')
await page.click('text=Settings & Members')
await page.click('text=Billing & Usage')
await expect(page.locator('text="/ 2,000"')).toBeVisible()
await expect(page.locator('text="/ 2 GB"')).toBeVisible()
await expect(page.locator('text="1.07 GB"')).toBeVisible()
await expect(page.locator('text="200"')).toBeVisible()
await expect(page.locator('[role="progressbar"] >> nth=0')).toHaveAttribute(
'aria-valuenow',
'10'
)
await expect(page.locator('[role="progressbar"] >> nth=1')).toHaveAttribute(
'aria-valuenow',
'54'
)
await createResults({
idPrefix: 'usage2',
typebotId: starterTypebotId,
isChronological: false,
count: 900,
fakeStorage: 1200 * 1024 * 1024,
})
await page.click('text="Settings"')
await page.click('text="Billing & Usage"')
await expect(page.locator('text="/ 2,000"')).toBeVisible()
await expect(page.locator('text="1,100"')).toBeVisible()
await expect(page.locator('text="/ 2 GB"')).toBeVisible()
await expect(page.locator('text="2.25 GB"')).toBeVisible()
await expect(page.locator('[aria-valuenow="55"]')).toBeVisible()
await expect(page.locator('[aria-valuenow="112"]')).toBeVisible()
})
test('plan changes should work', async ({ page }) => {
const workspaceId = await createWorkspace({ name: 'Awesome workspace' })
// Upgrade to STARTER
await page.goto('/typebots')
await page.click('text=Pro workspace')
await page.click('text=Awesome workspace')
await page.click('text=Settings & Members')
await page.click('text=Billing & Usage')
await page.click('button >> text="2,000"')
await page.click('button >> text="3,500"')
await page.click('button >> text="2"')
await page.click('button >> text="4"')
await expect(page.locator('text="$73"')).toBeVisible()
await page.click('button >> text=Upgrade >> nth=0')
await page.waitForNavigation()
expect(page.url()).toContain('https://checkout.stripe.com')
await expect(page.locator('text=$73.00 >> nth=0')).toBeVisible()
await expect(page.locator('text=$30.00 >> nth=0')).toBeVisible()
await expect(page.locator('text=$4.00 >> nth=0')).toBeVisible()
await expect(page.locator('text=user@email.com')).toBeVisible()
await addSubscriptionToWorkspace(
workspaceId,
[
{
price: process.env.STRIPE_STARTER_PRICE_ID,
quantity: 1,
},
{
price: process.env.STRIPE_ADDITIONAL_CHATS_PRICE_ID,
quantity: 3,
},
{
price: process.env.STRIPE_ADDITIONAL_STORAGE_PRICE_ID,
quantity: 2,
},
],
{ plan: Plan.STARTER, additionalChatsIndex: 3, additionalStorageIndex: 2 }
)
// Update plan with additional quotas
await page.goto('/typebots')
await page.click('text=Settings & Members')
await page.click('text=Billing & Usage')
await expect(page.locator('text="/ 3,500"')).toBeVisible()
await expect(page.locator('text="/ 4 GB"')).toBeVisible()
await expect(page.locator('button >> text="3,500"')).toBeVisible()
await expect(page.locator('button >> text="4"')).toBeVisible()
await expect(page.locator('text="$73"')).toBeVisible()
await page.click('button >> text="3,500"')
await page.click('button >> text="2,000"')
await page.click('button >> text="4"')
await page.click('button >> text="6"')
await expect(page.locator('text="$47"')).toBeVisible()
await page.click('button >> text=Update')
await expect(
page.locator(
'text="Workspace STARTER plan successfully updated 🎉" >> nth=0'
)
).toBeVisible()
// Upgrade to PRO
await page.click('button >> text="10,000"')
await page.click('button >> text="14,000"')
await page.click('button >> text="10"')
await page.click('button >> text="12"')
await expect(page.locator('text="$133"')).toBeVisible()
await page.click('button >> text=Upgrade')
await expect(
page.locator('text="Workspace PRO plan successfully updated 🎉" >> nth=0')
).toBeVisible()
// Go to customer portal
await Promise.all([
page.waitForNavigation(),
page.click('text="Billing Portal"'),
])
await expect(page.locator('text="Add payment method"')).toBeVisible()
// Cancel subscription
await page.goto('/typebots')
await page.click('text=Settings & Members')
await page.click('text=Billing & Usage')
await expect(page.locator('[data-testid="plan-tag"]')).toHaveText('Pro')
await page.click('button >> text="Cancel my subscription"')
await expect(page.locator('[data-testid="plan-tag"]')).toHaveText('Free')
})
test('should display invoices', async ({ page }) => {
await page.goto('/typebots')
await page.click('text=Settings & Members')
await page.click('text=Billing & Usage')
await expect(
page.locator('text="No invoices found for this workspace."')
).toBeVisible()
await page.click('text=Pro workspace', { force: true })
await page.click('text=Pro workspace')
await page.click('text=Starter workspace')
await page.click('text=Settings & Members')
await page.click('text=Billing & Usage')
await expect(page.locator('text="Invoices"')).toBeVisible()
await expect(page.locator('text="Wed Jun 01 2022"')).toBeVisible()
await expect(page.locator('text="74567541-0001"')).toBeVisible()
await expect(page.locator('text="€30.00" >> nth=0')).toBeVisible()
})

View File

@ -6,13 +6,10 @@ import {
import { BubbleBlockType, defaultEmbedBubbleContent } from 'models'
import { typebotViewer } from '../../services/selectorUtils'
import cuid from 'cuid'
import { mockSessionApiCalls } from 'playwright/services/browser'
const pdfSrc = 'https://www.orimi.com/pdf-test.pdf'
const siteSrc = 'https://app.cal.com/baptistearno/15min'
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test.describe.parallel('Embed bubble block', () => {
test.describe('Content settings', () => {
test('should import and parse embed correctly', async ({ page }) => {

View File

@ -7,13 +7,10 @@ import { BubbleBlockType, defaultImageBubbleContent } from 'models'
import { typebotViewer } from '../../services/selectorUtils'
import path from 'path'
import cuid from 'cuid'
import { mockSessionApiCalls } from 'playwright/services/browser'
const unsplashImageSrc =
'https://images.unsplash.com/photo-1504297050568-910d24c426d3?ixlib=rb-1.2.1&ixid=MnwxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1287&q=80'
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test.describe.parallel('Image bubble block', () => {
test.describe('Content settings', () => {
test('should upload image file correctly', async ({ page }) => {

View File

@ -6,9 +6,6 @@ import {
import { BubbleBlockType, defaultTextBubbleContent } from 'models'
import { typebotViewer } from '../../services/selectorUtils'
import cuid from 'cuid'
import { mockSessionApiCalls } from 'playwright/services/browser'
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test.describe('Text bubble block', () => {
test('rich text features should work', async ({ page }) => {

View File

@ -10,15 +10,12 @@ import {
} from 'models'
import { typebotViewer } from '../../services/selectorUtils'
import cuid from 'cuid'
import { mockSessionApiCalls } from 'playwright/services/browser'
const videoSrc =
'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerEscapes.mp4'
const youtubeVideoSrc = 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'
const vimeoVideoSrc = 'https://vimeo.com/649301125'
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test.describe.parallel('Video bubble block', () => {
test.describe('Content settings', () => {
test('should import video url correctly', async ({ page }) => {

View File

@ -3,7 +3,6 @@ import cuid from 'cuid'
import { CollaborationType, Plan, WorkspaceRole } from 'db'
import prisma from 'libs/prisma'
import { InputBlockType, defaultTextInputOptions } from 'models'
import { mockSessionApiCalls } from 'playwright/services/browser'
import {
createFolder,
createResults,
@ -11,8 +10,6 @@ import {
parseDefaultGroupWithBlock,
} from '../services/database'
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test.describe('Typebot owner', () => {
test('Can invite collaborators', async ({ page }) => {
const typebotId = cuid()
@ -101,7 +98,7 @@ test.describe('Collaborator', () => {
},
})
await createFolder(guestWorkspaceId, 'Guest folder')
await createResults({ typebotId })
await createResults({ typebotId, count: 10 })
await page.goto(`/typebots`)
await page.click("text=Pro user's workspace")
await page.click('text=Guest workspace #2')

View File

@ -2,14 +2,10 @@ import test, { expect } from '@playwright/test'
import { InputBlockType, defaultTextInputOptions } from 'models'
import {
createTypebots,
freeWorkspaceId,
parseDefaultGroupWithBlock,
starterWorkspaceId,
} from '../services/database'
import path from 'path'
import cuid from 'cuid'
import { mockSessionApiCalls } from 'playwright/services/browser'
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test('should be able to connect custom domain', async ({ page }) => {
const typebotId = cuid()
@ -47,16 +43,13 @@ test('should be able to connect custom domain', async ({ page }) => {
await expect(page.locator('[aria-label="Remove domain"]')).toBeHidden()
})
test.describe('Free workspace', () => {
test.use({
storageState: path.join(__dirname, '../freeUser.json'),
})
test.describe('Starter workspace', () => {
test("Add my domain shouldn't be available", async ({ page }) => {
const typebotId = cuid()
await createTypebots([
{
id: typebotId,
workspaceId: freeWorkspaceId,
workspaceId: starterWorkspaceId,
...parseDefaultGroupWithBlock({
type: InputBlockType.TEXT,
options: defaultTextInputOptions,

View File

@ -1,12 +1,9 @@
import test, { expect, Page } from '@playwright/test'
import cuid from 'cuid'
import path from 'path'
import { mockSessionApiCalls } from 'playwright/services/browser'
import { createFolders, createTypebots } from '../services/database'
import { deleteButtonInConfirmDialog } from '../services/selectorUtils'
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test.describe('Dashboard page', () => {
test('folders navigation should work', async ({ page }) => {
await page.goto('/typebots')
@ -79,7 +76,7 @@ test.describe('Dashboard page', () => {
test.describe('Free user', () => {
test.use({
storageState: path.join(__dirname, '../freeUser.json'),
storageState: path.join(__dirname, '../secondUser.json'),
})
test("create folder shouldn't be available", async ({ page }) => {
await page.goto('/typebots')

View File

@ -8,9 +8,6 @@ import { defaultTextInputOptions, InputBlockType } from 'models'
import path from 'path'
import cuid from 'cuid'
import { typebotViewer } from '../services/selectorUtils'
import { mockSessionApiCalls } from 'playwright/services/browser'
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test.describe.parallel('Editor', () => {
test('Edges connection should work', async ({ page }) => {

View File

@ -8,9 +8,6 @@ import { defaultChoiceInputOptions, InputBlockType, ItemType } from 'models'
import { typebotViewer } from '../../services/selectorUtils'
import cuid from 'cuid'
import path from 'path'
import { mockSessionApiCalls } from 'playwright/services/browser'
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test.describe.parallel('Buttons input block', () => {
test('can edit button items', async ({ page }) => {

View File

@ -6,9 +6,6 @@ import {
import { defaultDateInputOptions, InputBlockType } from 'models'
import { typebotViewer } from '../../services/selectorUtils'
import cuid from 'cuid'
import { mockSessionApiCalls } from 'playwright/services/browser'
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test.describe('Date input block', () => {
test('options should work', async ({ page }) => {

View File

@ -6,9 +6,6 @@ import {
import { defaultEmailInputOptions, InputBlockType } from 'models'
import { typebotViewer } from '../../services/selectorUtils'
import cuid from 'cuid'
import { mockSessionApiCalls } from 'playwright/services/browser'
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test.describe('Email input block', () => {
test('options should work', async ({ page }) => {

View File

@ -8,9 +8,6 @@ import { defaultFileInputOptions, InputBlockType } from 'models'
import { typebotViewer } from '../../services/selectorUtils'
import cuid from 'cuid'
import path from 'path'
import { mockSessionApiCalls } from 'playwright/services/browser'
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test.describe.configure({ mode: 'parallel' })
@ -61,9 +58,6 @@ test('options should work', async ({ page }) => {
})
test.describe('Free workspace', () => {
test.use({
storageState: path.join(__dirname, '../../freeUser.json'),
})
test("shouldn't be able to publish typebot", async ({ page }) => {
const typebotId = cuid()
await createTypebots([

View File

@ -6,9 +6,6 @@ import {
import { defaultNumberInputOptions, InputBlockType } from 'models'
import { typebotViewer } from '../../services/selectorUtils'
import cuid from 'cuid'
import { mockSessionApiCalls } from 'playwright/services/browser'
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test.describe('Number input block', () => {
test('options should work', async ({ page }) => {

View File

@ -6,9 +6,6 @@ import {
import { defaultPaymentInputOptions, InputBlockType } from 'models'
import cuid from 'cuid'
import { stripePaymentForm, typebotViewer } from '../../services/selectorUtils'
import { mockSessionApiCalls } from 'playwright/services/browser'
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test.describe('Payment input block', () => {
test('Can configure Stripe account', async ({ page }) => {

View File

@ -6,9 +6,6 @@ import {
import { defaultPhoneInputOptions, InputBlockType } from 'models'
import { typebotViewer } from '../../services/selectorUtils'
import cuid from 'cuid'
import { mockSessionApiCalls } from 'playwright/services/browser'
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test.describe('Phone input block', () => {
test('options should work', async ({ page }) => {

View File

@ -6,7 +6,6 @@ import {
import { defaultRatingInputOptions, InputBlockType } from 'models'
import { typebotViewer } from '../../services/selectorUtils'
import cuid from 'cuid'
import { mockSessionApiCalls } from 'playwright/services/browser'
const boxSvg = `<svg
xmlns="http://www.w3.org/2000/svg"
@ -21,8 +20,6 @@ const boxSvg = `<svg
<line x1="12" y1="22.08" x2="12" y2="12"></line>
</svg>`
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test('options should work', async ({ page }) => {
const typebotId = cuid()
await createTypebots([

View File

@ -6,9 +6,6 @@ import {
import { defaultTextInputOptions, InputBlockType } from 'models'
import { typebotViewer } from '../../services/selectorUtils'
import cuid from 'cuid'
import { mockSessionApiCalls } from 'playwright/services/browser'
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test.describe.parallel('Text input block', () => {
test('options should work', async ({ page }) => {

View File

@ -6,9 +6,6 @@ import {
import { defaultUrlInputOptions, InputBlockType } from 'models'
import { typebotViewer } from '../../services/selectorUtils'
import cuid from 'cuid'
import { mockSessionApiCalls } from 'playwright/services/browser'
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test.describe('Url input block', () => {
test('options should work', async ({ page }) => {

View File

@ -5,9 +5,6 @@ import {
} from '../../services/database'
import { defaultGoogleAnalyticsOptions, IntegrationBlockType } from 'models'
import cuid from 'cuid'
import { mockSessionApiCalls } from 'playwright/services/browser'
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test.describe('Google Analytics block', () => {
test('its configuration should work', async ({ page }) => {

View File

@ -3,9 +3,6 @@ import { importTypebotInDatabase } from '../../services/database'
import path from 'path'
import { typebotViewer } from '../../services/selectorUtils'
import cuid from 'cuid'
import { mockSessionApiCalls } from 'playwright/services/browser'
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test.describe.parallel('Google sheets integration', () => {
test('Insert row should work', async ({ page }) => {

View File

@ -3,12 +3,9 @@ import { importTypebotInDatabase } from '../../services/database'
import path from 'path'
import { typebotViewer } from '../../services/selectorUtils'
import cuid from 'cuid'
import { mockSessionApiCalls } from 'playwright/services/browser'
const typebotId = cuid()
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test.describe('Send email block', () => {
test('its configuration should work', async ({ page }) => {
if (

View File

@ -3,9 +3,6 @@ import { createWebhook, importTypebotInDatabase } from '../../services/database'
import path from 'path'
import { HttpMethod } from 'models'
import cuid from 'cuid'
import { mockSessionApiCalls } from 'playwright/services/browser'
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test.describe('Webhook block', () => {
test('easy configuration should work', async ({ page }) => {

View File

@ -3,12 +3,9 @@ import path from 'path'
import { typebotViewer } from '../../services/selectorUtils'
import { importTypebotInDatabase } from '../../services/database'
import cuid from 'cuid'
import { mockSessionApiCalls } from 'playwright/services/browser'
const typebotId = cuid()
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test.describe('Code block', () => {
test('code should trigger', async ({ page }) => {
await importTypebotInDatabase(

View File

@ -3,12 +3,9 @@ import path from 'path'
import { typebotViewer } from '../../services/selectorUtils'
import { importTypebotInDatabase } from '../../services/database'
import cuid from 'cuid'
import { mockSessionApiCalls } from 'playwright/services/browser'
const typebotId = cuid()
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test.describe('Condition block', () => {
test('its configuration should work', async ({ page }) => {
await importTypebotInDatabase(

View File

@ -3,12 +3,9 @@ import path from 'path'
import { typebotViewer } from '../../services/selectorUtils'
import { importTypebotInDatabase } from '../../services/database'
import cuid from 'cuid'
import { mockSessionApiCalls } from 'playwright/services/browser'
const typebotId = cuid()
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test.describe('Redirect block', () => {
test('its configuration should work', async ({ page, context }) => {
await importTypebotInDatabase(

View File

@ -3,12 +3,9 @@ import path from 'path'
import { typebotViewer } from '../../services/selectorUtils'
import { importTypebotInDatabase } from '../../services/database'
import cuid from 'cuid'
import { mockSessionApiCalls } from 'playwright/services/browser'
const typebotId = cuid()
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test.describe('Set variable block', () => {
test('its configuration should work', async ({ page }) => {
await importTypebotInDatabase(

View File

@ -3,9 +3,6 @@ import { typebotViewer } from '../../services/selectorUtils'
import { importTypebotInDatabase } from '../../services/database'
import path from 'path'
import cuid from 'cuid'
import { mockSessionApiCalls } from 'playwright/services/browser'
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test('should be configurable', async ({ page }) => {
const typebotId = cuid()

View File

@ -4,7 +4,6 @@ import { readFileSync } from 'fs'
import { defaultTextInputOptions, InputBlockType } from 'models'
import { parse } from 'papaparse'
import path from 'path'
import { mockSessionApiCalls } from 'playwright/services/browser'
import {
createResults,
createTypebots,
@ -15,8 +14,6 @@ import { deleteButtonInConfirmDialog } from '../services/selectorUtils'
const typebotId = cuid()
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test('Submission table header should be parsed correctly', async ({ page }) => {
const typebotId = cuid()
await importTypebotInDatabase(
@ -46,7 +43,7 @@ test('results should be deletable', async ({ page }) => {
}),
},
])
await createResults({ typebotId })
await createResults({ typebotId, count: 200 })
await page.goto(`/typebots/${typebotId}/results`)
await selectFirstResults(page)
await page.click('text="Delete"')
@ -70,7 +67,7 @@ test('submissions table should have infinite scroll', async ({ page }) => {
tableWrapper.scrollTo(0, tableWrapper.scrollHeight)
})
await createResults({ typebotId })
await createResults({ typebotId, count: 200 })
await page.goto(`/typebots/${typebotId}/results`)
await expect(page.locator('text=content199')).toBeVisible()

View File

@ -2,12 +2,9 @@ import test, { expect } from '@playwright/test'
import cuid from 'cuid'
import { defaultTextInputOptions } from 'models'
import path from 'path'
import { mockSessionApiCalls } from 'playwright/services/browser'
import { freeWorkspaceId, importTypebotInDatabase } from '../services/database'
import { typebotViewer } from '../services/selectorUtils'
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test.describe.parallel('Settings page', () => {
test.describe('General', () => {
test('should reflect change in real-time', async ({ page }) => {
@ -123,10 +120,7 @@ test.describe.parallel('Settings page', () => {
})
})
test.describe('Free user', () => {
test.use({
storageState: path.join(__dirname, '../freeUser.json'),
})
test.describe('Free workspace', () => {
test("can't remove branding", async ({ page }) => {
const typebotId = 'free-branding-typebot'
await importTypebotInDatabase(

View File

@ -1,10 +1,7 @@
import test, { expect } from '@playwright/test'
import path from 'path'
import { mockSessionApiCalls } from 'playwright/services/browser'
import { typebotViewer } from '../services/selectorUtils'
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test.describe.parallel('Templates page', () => {
test('From scratch should create a blank typebot', async ({ page }) => {
await page.goto('/typebots/create')

View File

@ -1,7 +1,6 @@
import test, { expect } from '@playwright/test'
import cuid from 'cuid'
import path from 'path'
import { mockSessionApiCalls } from 'playwright/services/browser'
import { importTypebotInDatabase } from '../services/database'
import { typebotViewer } from '../services/selectorUtils'
@ -10,8 +9,6 @@ const hostAvatarUrl =
const guestAvatarUrl =
'https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1287&q=80'
test.beforeEach(({ page }) => mockSessionApiCalls(page))
test.describe.parallel('Theme page', () => {
test.describe('General', () => {
test('should reflect change in real-time', async ({ page }) => {

View File

@ -1,25 +1,30 @@
import test, { expect } from '@playwright/test'
import cuid from 'cuid'
import { defaultTextInputOptions, InputBlockType } from 'models'
import { mockSessionApiCalls } from 'playwright/services/browser'
import { connectedAsOtherUser } from 'playwright/services/browser'
import {
createTypebots,
parseDefaultGroupWithBlock,
sharedWorkspaceId,
proWorkspaceId,
starterWorkspaceId,
} from '../services/database'
const proTypebotId = cuid()
const freeTypebotId = cuid()
test.beforeEach(({ page }) => mockSessionApiCalls(page))
const starterTypebotId = cuid()
test.beforeAll(async () => {
await createTypebots([{ id: proTypebotId, name: 'Pro typebot' }])
await createTypebots([
{
id: freeTypebotId,
name: 'Shared typebot',
workspaceId: sharedWorkspaceId,
id: proTypebotId,
name: 'Pro typebot',
workspaceId: proWorkspaceId,
},
])
await createTypebots([
{
id: starterTypebotId,
name: 'Starter typebot',
workspaceId: starterWorkspaceId,
...parseDefaultGroupWithBlock({
type: InputBlockType.TEXT,
options: {
@ -37,38 +42,34 @@ test.beforeAll(async () => {
test('can switch between workspaces and access typebot', async ({ page }) => {
await page.goto('/typebots')
await expect(page.locator('text="Pro typebot"')).toBeVisible()
await page.click("text=Pro user's workspace")
await page.click('text="Shared workspace"')
await page.click('text=Pro workspace')
await page.click('text="Starter workspace"')
await expect(page.locator('text="Pro typebot"')).toBeHidden()
await page.click('text="Shared typebot"')
await page.click('text="Starter typebot"')
await expect(page.locator('text="Hey there"')).toBeVisible()
})
test('can create and delete a new workspace', async ({ page }) => {
await page.goto('/typebots')
await page.click("text=Pro user's workspace")
await expect(
page.locator('text="Pro user\'s workspace" >> nth=1')
).toBeHidden()
await page.click('text=Pro workspace')
await expect(page.locator('text="Pro workspace" >> nth=1')).toBeHidden()
await page.click('text=New workspace')
await expect(page.locator('text="Pro typebot"')).toBeHidden()
await page.click("text=Pro user's workspace")
await expect(
page.locator('text="Pro user\'s workspace" >> nth=1')
).toBeVisible()
await page.click("text=John Doe's workspace")
await expect(page.locator('text="Pro workspace"')).toBeVisible()
await page.click('text=Settings & Members')
await page.click('text="Settings"')
await page.click('text="Delete workspace"')
await expect(
page.locator(
"text=Are you sure you want to delete Pro user's workspace workspace?"
"text=Are you sure you want to delete John Doe's workspace workspace?"
)
).toBeVisible()
await page.click('text="Delete"')
await expect(page.locator('text=Pro typebot')).toBeVisible()
await page.click("text=Pro user's workspace")
await expect(page.locator('text=Free workspace')).toBeVisible()
await page.click('text=Free workspace')
await expect(
page.locator('text="Pro user\'s workspace" >> nth=1')
page.locator('text="John Doe\'s workspace" >> nth=1')
).toBeHidden()
})
@ -79,17 +80,14 @@ test('can update workspace info', async ({ page }) => {
await page.click('[data-testid="editable-icon"]')
await page.fill('input[placeholder="Search..."]', 'building')
await page.click('text="🏦"')
await page.fill(
'input[value="Pro user\'s workspace"]',
'My awesome workspace'
)
await page.fill('input[value="Pro workspace"]', 'My awesome workspace')
})
test('can manage members', async ({ page }) => {
await page.goto('/typebots')
await page.click('text=Settings & Members')
await page.click('text="Members"')
await expect(page.locator('text="pro-user@email.com"')).toBeVisible()
await expect(page.locator('text="user@email.com"')).toBeVisible()
await expect(page.locator('button >> text="Invite"')).toBeEnabled()
await page.fill(
'input[placeholder="colleague@company.com"]',
@ -104,7 +102,7 @@ test('can manage members', async ({ page }) => {
await expect(page.locator('text="Pending"')).toBeVisible()
await page.fill(
'input[placeholder="colleague@company.com"]',
'free-user@email.com'
'other-user@email.com'
)
await page.click('text="Member" >> nth=0')
await page.click('text="Admin"')
@ -112,18 +110,15 @@ test('can manage members', async ({ page }) => {
await expect(
page.locator('input[placeholder="colleague@company.com"]')
).toHaveAttribute('value', '')
await expect(page.locator('text="free-user@email.com"')).toBeVisible()
await expect(page.locator('text="Free user"')).toBeVisible()
await expect(page.locator('text="other-user@email.com"')).toBeVisible()
await expect(page.locator('text="James Doe"')).toBeVisible()
// Downgrade admin to member
await page.click('text="free-user@email.com"')
await page.click('text="other-user@email.com"')
await page.click('button >> text="Member"')
await expect(page.locator('[data-testid="tag"] >> text="Admin"')).toHaveCount(
1
)
await page.click('text="free-user@email.com"')
await page.click('button >> text="Remove"')
await expect(page.locator('text="free-user@email.com"')).toBeHidden()
await page.click('text="other-user@email.com"')
await page.click('text="guest@email.com"')
await page.click('text="Admin" >> nth=-1')
@ -133,19 +128,46 @@ test('can manage members', async ({ page }) => {
await page.click('text="guest@email.com"')
await page.click('button >> text="Remove"')
await expect(page.locator('text="guest@email.com"')).toBeHidden()
})
test("can't edit workspace as a member", async ({ page }) => {
await connectedAsOtherUser(page)
await page.goto('/typebots')
await page.click("text=Pro user's workspace")
await page.click('text="Shared workspace"')
await page.click('text=Settings & Members')
await expect(page.locator('text="Settings"')).toBeHidden()
await page.click('text="Members"')
await expect(page.locator('text="free-user@email.com"')).toBeVisible()
await expect(page.locator('text="other-user@email.com"')).toBeVisible()
await expect(
page.locator('input[placeholder="colleague@company.com"]')
).toBeHidden()
await page.click('text="free-user@email.com"')
await page.click('text="other-user@email.com"')
await expect(page.locator('button >> text="Remove"')).toBeHidden()
})
test("can't add new members when limit is reached", async ({ page }) => {
await page.goto('/typebots')
await page.click('text="Pro workspace"')
await page.click('text="Free workspace"')
await page.click('text=Settings & Members')
await page.click('text="Members"')
await expect(page.locator('button >> text="Invite"')).toBeDisabled()
await expect(
page.locator(
'text="Upgrade your plan to work with more team members, and unlock awesome power features 🚀"'
)
).toBeVisible()
await page.click('text="Free workspace"', { force: true })
await page.click('text="Free workspace"')
await page.click('text="Starter workspace"')
await page.click('text=Settings & Members')
await page.click('text="Members"')
await page.fill(
'input[placeholder="colleague@company.com"]',
'guest@email.com'
)
await page.click('button >> text="Invite"')
await expect(
page.locator(
'text="Upgrade your plan to work with more team members, and unlock awesome power features 🚀"'
)
).toBeVisible()
await expect(page.locator('button >> text="Invite"')).toBeDisabled()
})