♻️ Export bot-engine code into its own package
This commit is contained in:
221
apps/viewer/src/test/chat.spec.ts
Normal file
221
apps/viewer/src/test/chat.spec.ts
Normal file
@@ -0,0 +1,221 @@
|
||||
import { getTestAsset } from '@/test/utils/playwright'
|
||||
import test, { expect } from '@playwright/test'
|
||||
import { createId } from '@paralleldrive/cuid2'
|
||||
import prisma from '@typebot.io/lib/prisma'
|
||||
import { SendMessageInput } from '@typebot.io/schemas'
|
||||
import {
|
||||
createWebhook,
|
||||
deleteTypebots,
|
||||
deleteWebhooks,
|
||||
importTypebotInDatabase,
|
||||
} from '@typebot.io/lib/playwright/databaseActions'
|
||||
import { HttpMethod } from '@typebot.io/schemas/features/blocks/integrations/webhook/enums'
|
||||
|
||||
test.afterEach(async () => {
|
||||
await deleteWebhooks(['chat-webhook-id'])
|
||||
await deleteTypebots(['chat-sub-bot'])
|
||||
})
|
||||
|
||||
test('API chat execution should work on preview bot', async ({ request }) => {
|
||||
const typebotId = createId()
|
||||
const publicId = `${typebotId}-public`
|
||||
await importTypebotInDatabase(getTestAsset('typebots/chat/main.json'), {
|
||||
id: typebotId,
|
||||
publicId,
|
||||
})
|
||||
await importTypebotInDatabase(getTestAsset('typebots/chat/linkedBot.json'), {
|
||||
id: 'chat-sub-bot',
|
||||
publicId: 'chat-sub-bot-public',
|
||||
})
|
||||
await createWebhook(typebotId, {
|
||||
id: 'chat-webhook-id',
|
||||
method: HttpMethod.GET,
|
||||
url: 'https://api.chucknorris.io/jokes/random',
|
||||
})
|
||||
|
||||
await test.step('Start the chat', async () => {
|
||||
const { sessionId, messages, input, resultId } = await (
|
||||
await request.post(`/api/v1/sendMessage`, {
|
||||
data: {
|
||||
startParams: {
|
||||
typebot: typebotId,
|
||||
isPreview: true,
|
||||
},
|
||||
} satisfies SendMessageInput,
|
||||
})
|
||||
).json()
|
||||
expect(resultId).toBeUndefined()
|
||||
expect(sessionId).toBeDefined()
|
||||
expect(messages[0].content.richText).toStrictEqual([
|
||||
{ children: [{ text: 'Hi there! 👋' }], type: 'p' },
|
||||
])
|
||||
expect(messages[1].content.richText).toStrictEqual([
|
||||
{ children: [{ text: "Welcome. What's your name?" }], type: 'p' },
|
||||
])
|
||||
expect(input.type).toBe('text input')
|
||||
})
|
||||
})
|
||||
|
||||
test('API chat execution should work on published bot', async ({ request }) => {
|
||||
const typebotId = createId()
|
||||
const publicId = `${typebotId}-public`
|
||||
await importTypebotInDatabase(getTestAsset('typebots/chat/main.json'), {
|
||||
id: typebotId,
|
||||
publicId,
|
||||
})
|
||||
await importTypebotInDatabase(getTestAsset('typebots/chat/linkedBot.json'), {
|
||||
id: 'chat-sub-bot',
|
||||
publicId: 'chat-sub-bot-public',
|
||||
})
|
||||
await createWebhook(typebotId, {
|
||||
id: 'chat-webhook-id',
|
||||
method: HttpMethod.GET,
|
||||
url: 'https://api.chucknorris.io/jokes/random',
|
||||
})
|
||||
let chatSessionId: string
|
||||
|
||||
await test.step('Start the chat', async () => {
|
||||
const { sessionId, messages, input, resultId } = await (
|
||||
await request.post(`/api/v1/sendMessage`, {
|
||||
data: {
|
||||
startParams: {
|
||||
typebot: publicId,
|
||||
},
|
||||
} satisfies SendMessageInput,
|
||||
})
|
||||
).json()
|
||||
chatSessionId = sessionId
|
||||
expect(resultId).toBeDefined()
|
||||
const result = await prisma.result.findUnique({
|
||||
where: {
|
||||
id: resultId,
|
||||
},
|
||||
})
|
||||
expect(result).toBeDefined()
|
||||
expect(sessionId).toBeDefined()
|
||||
expect(messages[0].content.richText).toStrictEqual([
|
||||
{ children: [{ text: 'Hi there! 👋' }], type: 'p' },
|
||||
])
|
||||
expect(messages[1].content.richText).toStrictEqual([
|
||||
{ children: [{ text: "Welcome. What's your name?" }], type: 'p' },
|
||||
])
|
||||
expect(input.type).toBe('text input')
|
||||
})
|
||||
|
||||
await test.step('Answer Name question', async () => {
|
||||
const { messages, input } = await (
|
||||
await request.post(`/api/v1/sendMessage`, {
|
||||
data: { message: 'John', sessionId: chatSessionId },
|
||||
})
|
||||
).json()
|
||||
expect(messages[0].content.richText).toStrictEqual([
|
||||
{ children: [{ text: 'Nice to meet you John' }], type: 'p' },
|
||||
])
|
||||
expect(messages[1].content.url).toMatch(new RegExp('giphy.com', 'gm'))
|
||||
expect(input.type).toBe('number input')
|
||||
})
|
||||
|
||||
await test.step('Answer Age question', async () => {
|
||||
const { messages, input } = await (
|
||||
await request.post(`/api/v1/sendMessage`, {
|
||||
data: { message: '24', sessionId: chatSessionId },
|
||||
})
|
||||
).json()
|
||||
expect(messages[0].content.richText).toStrictEqual([
|
||||
{ children: [{ text: 'Ok, you are an adult then 😁' }], type: 'p' },
|
||||
])
|
||||
expect(messages[1].content.richText).toStrictEqual([
|
||||
{ children: [{ text: 'My magic number is 42' }], type: 'p' },
|
||||
])
|
||||
expect(messages[2].content.richText).toStrictEqual([
|
||||
{
|
||||
children: [{ text: 'How would you rate the experience so far?' }],
|
||||
type: 'p',
|
||||
},
|
||||
])
|
||||
expect(input.type).toBe('rating input')
|
||||
})
|
||||
|
||||
await test.step('Answer Rating question', async () => {
|
||||
const { messages, input } = await (
|
||||
await request.post(`/api/v1/sendMessage`, {
|
||||
data: { message: '8', sessionId: chatSessionId },
|
||||
})
|
||||
).json()
|
||||
expect(messages[0].content.richText).toStrictEqual([
|
||||
{
|
||||
children: [{ text: "I'm gonna shoot multiple inputs now..." }],
|
||||
type: 'p',
|
||||
},
|
||||
])
|
||||
expect(input.type).toBe('email input')
|
||||
})
|
||||
|
||||
await test.step('Answer Email question with wrong input', async () => {
|
||||
const { messages, input } = await (
|
||||
await request.post(`/api/v1/sendMessage`, {
|
||||
data: { message: 'invalid email', sessionId: chatSessionId },
|
||||
})
|
||||
).json()
|
||||
expect(messages[0].content.richText).toStrictEqual([
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: "This email doesn't seem to be valid. Can you type it again?",
|
||||
},
|
||||
],
|
||||
type: 'p',
|
||||
},
|
||||
])
|
||||
expect(input.type).toBe('email input')
|
||||
})
|
||||
|
||||
await test.step('Answer Email question with valid input', async () => {
|
||||
const { messages, input } = await (
|
||||
await request.post(`/api/v1/sendMessage`, {
|
||||
data: { message: 'typebot@email.com', sessionId: chatSessionId },
|
||||
})
|
||||
).json()
|
||||
expect(messages.length).toBe(0)
|
||||
expect(input.type).toBe('url input')
|
||||
})
|
||||
|
||||
await test.step('Answer URL question', async () => {
|
||||
const { messages, input } = await (
|
||||
await request.post(`/api/v1/sendMessage`, {
|
||||
data: { message: 'https://typebot.io', sessionId: chatSessionId },
|
||||
})
|
||||
).json()
|
||||
expect(messages.length).toBe(0)
|
||||
expect(input.type).toBe('choice input')
|
||||
})
|
||||
|
||||
await test.step('Answer Buttons question with invalid choice', async () => {
|
||||
const { messages } = await (
|
||||
await request.post(`/api/v1/sendMessage`, {
|
||||
data: { message: 'Yes', sessionId: chatSessionId },
|
||||
})
|
||||
).json()
|
||||
expect(messages[0].content.richText).toStrictEqual([
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: 'Ok, you are solid 👏',
|
||||
},
|
||||
],
|
||||
type: 'p',
|
||||
},
|
||||
])
|
||||
expect(messages[1].content.richText).toStrictEqual([
|
||||
{
|
||||
children: [
|
||||
{
|
||||
text: "Let's trigger a webhook...",
|
||||
},
|
||||
],
|
||||
type: 'p',
|
||||
},
|
||||
])
|
||||
expect(messages[2].content.richText.length).toBeGreaterThan(0)
|
||||
})
|
||||
})
|
||||
33
apps/viewer/src/test/chatwoot.spec.ts
Normal file
33
apps/viewer/src/test/chatwoot.spec.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import { createId } from '@paralleldrive/cuid2'
|
||||
import { createTypebots } from '@typebot.io/lib/playwright/databaseActions'
|
||||
import { parseDefaultGroupWithBlock } from '@typebot.io/lib/playwright/databaseHelpers'
|
||||
import {
|
||||
defaultChatwootOptions,
|
||||
IntegrationBlockType,
|
||||
} from '@typebot.io/schemas'
|
||||
|
||||
const typebotId = createId()
|
||||
|
||||
const chatwootTestWebsiteToken = 'tueXiiqEmrWUCZ4NUyoR7nhE'
|
||||
|
||||
test('should work as expected', async ({ page }) => {
|
||||
await createTypebots([
|
||||
{
|
||||
id: typebotId,
|
||||
...parseDefaultGroupWithBlock(
|
||||
{
|
||||
type: IntegrationBlockType.CHATWOOT,
|
||||
options: {
|
||||
...defaultChatwootOptions,
|
||||
websiteToken: chatwootTestWebsiteToken,
|
||||
},
|
||||
},
|
||||
{ withGoButton: true }
|
||||
),
|
||||
},
|
||||
])
|
||||
await page.goto(`/${typebotId}-public`)
|
||||
await page.getByRole('button', { name: 'Go' }).click()
|
||||
await expect(page.locator('#chatwoot_live_chat_widget')).toBeVisible()
|
||||
})
|
||||
96
apps/viewer/src/test/fileUpload.spec.ts
Normal file
96
apps/viewer/src/test/fileUpload.spec.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import { createId } from '@paralleldrive/cuid2'
|
||||
import { parse } from 'papaparse'
|
||||
import { readFileSync } from 'fs'
|
||||
import { isDefined } from '@typebot.io/lib'
|
||||
import {
|
||||
createWorkspaces,
|
||||
importTypebotInDatabase,
|
||||
injectFakeResults,
|
||||
} from '@typebot.io/lib/playwright/databaseActions'
|
||||
import { getTestAsset } from '@/test/utils/playwright'
|
||||
import { Plan } from '@typebot.io/prisma'
|
||||
import { env } from '@typebot.io/env'
|
||||
|
||||
const THREE_GIGABYTES = 3 * 1024 * 1024 * 1024
|
||||
|
||||
test('should work as expected', async ({ page, browser }) => {
|
||||
const typebotId = createId()
|
||||
await importTypebotInDatabase(getTestAsset('typebots/fileUpload.json'), {
|
||||
id: typebotId,
|
||||
publicId: `${typebotId}-public`,
|
||||
})
|
||||
await page.goto(`/${typebotId}-public`)
|
||||
await page
|
||||
.locator(`input[type="file"]`)
|
||||
.setInputFiles([
|
||||
getTestAsset('typebots/api.json'),
|
||||
getTestAsset('typebots/fileUpload.json'),
|
||||
getTestAsset('typebots/hugeGroup.json'),
|
||||
])
|
||||
await expect(page.locator(`text="3"`)).toBeVisible()
|
||||
await page.locator('text="Upload 3 files"').click()
|
||||
await expect(page.locator(`text="3 files uploaded"`)).toBeVisible()
|
||||
await page.goto(`${env.NEXTAUTH_URL}/typebots/${typebotId}/results`)
|
||||
await expect(page.getByRole('link', { name: 'api.json' })).toHaveAttribute(
|
||||
'href',
|
||||
/.+\/api\.json/
|
||||
)
|
||||
await expect(
|
||||
page.getByRole('link', { name: 'fileUpload.json' })
|
||||
).toHaveAttribute('href', /.+\/fileUpload\.json/)
|
||||
await expect(
|
||||
page.getByRole('link', { name: 'hugeGroup.json' })
|
||||
).toHaveAttribute('href', /.+\/hugeGroup\.json/)
|
||||
|
||||
await page.click('[data-testid="checkbox"] >> nth=0')
|
||||
const [download] = await Promise.all([
|
||||
page.waitForEvent('download'),
|
||||
page.getByRole('button', { name: 'Export' }).click(),
|
||||
])
|
||||
const downloadPath = await download.path()
|
||||
expect(downloadPath).toBeDefined()
|
||||
const file = readFileSync(downloadPath as string).toString()
|
||||
const { data } = parse(file)
|
||||
expect(data).toHaveLength(2)
|
||||
expect((data[1] as unknown[])[1]).toContain(env.S3_ENDPOINT)
|
||||
|
||||
const urls = (
|
||||
await Promise.all(
|
||||
[
|
||||
page.getByRole('link', { name: 'api.json' }),
|
||||
page.getByRole('link', { name: 'fileUpload.json' }),
|
||||
page.getByRole('link', { name: 'hugeGroup.json' }),
|
||||
].map((elem) => elem.getAttribute('href'))
|
||||
)
|
||||
).filter(isDefined)
|
||||
|
||||
const page2 = await browser.newPage()
|
||||
await page2.goto(urls[0])
|
||||
await expect(page2.locator('pre')).toBeVisible()
|
||||
|
||||
page.getByRole('button', { name: 'Delete' }).click()
|
||||
await page.locator('button >> text="Delete"').click()
|
||||
await expect(page.locator('text="api.json"')).toBeHidden()
|
||||
await page2.goto(urls[0])
|
||||
await expect(page2.locator('pre')).toBeHidden()
|
||||
})
|
||||
|
||||
test.describe('Storage limit is reached', () => {
|
||||
const typebotId = createId()
|
||||
const workspaceId = createId()
|
||||
|
||||
test.beforeAll(async () => {
|
||||
await createWorkspaces([{ id: workspaceId, plan: Plan.STARTER }])
|
||||
await importTypebotInDatabase(getTestAsset('typebots/fileUpload.json'), {
|
||||
id: typebotId,
|
||||
publicId: `${typebotId}-public`,
|
||||
workspaceId,
|
||||
})
|
||||
await injectFakeResults({
|
||||
typebotId,
|
||||
count: 20,
|
||||
fakeStorage: THREE_GIGABYTES,
|
||||
})
|
||||
})
|
||||
})
|
||||
28
apps/viewer/src/test/results.spec.ts
Normal file
28
apps/viewer/src/test/results.spec.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { getTestAsset } from '@/test/utils/playwright'
|
||||
import test, { expect } from '@playwright/test'
|
||||
import { createId } from '@paralleldrive/cuid2'
|
||||
import { importTypebotInDatabase } from '@typebot.io/lib/playwright/databaseActions'
|
||||
import { env } from '@typebot.io/env'
|
||||
|
||||
test('Big groups should work as expected', async ({ page }) => {
|
||||
const typebotId = createId()
|
||||
await importTypebotInDatabase(getTestAsset('typebots/hugeGroup.json'), {
|
||||
id: typebotId,
|
||||
publicId: `${typebotId}-public`,
|
||||
})
|
||||
await page.goto(`/${typebotId}-public`)
|
||||
await page.locator('input').fill('Baptiste')
|
||||
await page.locator('input').press('Enter')
|
||||
await page.locator('input').fill('26')
|
||||
await page.locator('input').press('Enter')
|
||||
await page.getByRole('button', { name: 'Yes' }).click()
|
||||
await page.goto(`${env.NEXTAUTH_URL}/typebots/${typebotId}/results`)
|
||||
await expect(page.locator('text="Baptiste"')).toBeVisible()
|
||||
await expect(page.locator('text="26"')).toBeVisible()
|
||||
await expect(page.locator('text="Yes"')).toBeVisible()
|
||||
await page.hover('tbody > tr')
|
||||
await page.click('button >> text="Open"')
|
||||
await expect(page.locator('text="Baptiste" >> nth=1')).toBeVisible()
|
||||
await expect(page.locator('text="26" >> nth=1')).toBeVisible()
|
||||
await expect(page.locator('text="Yes" >> nth=1')).toBeVisible()
|
||||
})
|
||||
41
apps/viewer/src/test/sendEmail.spec.ts
Normal file
41
apps/viewer/src/test/sendEmail.spec.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import { createId } from '@paralleldrive/cuid2'
|
||||
import { importTypebotInDatabase } from '@typebot.io/lib/playwright/databaseActions'
|
||||
import { getTestAsset } from '@/test/utils/playwright'
|
||||
import { SmtpCredentials } from '@typebot.io/schemas'
|
||||
import { env } from '@typebot.io/env'
|
||||
import { createSmtpCredentials } from './utils/databaseActions'
|
||||
|
||||
export const mockSmtpCredentials: SmtpCredentials['data'] = {
|
||||
from: {
|
||||
email: 'pedro.morissette@ethereal.email',
|
||||
name: 'Pedro Morissette',
|
||||
},
|
||||
host: 'smtp.ethereal.email',
|
||||
port: 587,
|
||||
username: 'pedro.morissette@ethereal.email',
|
||||
password: 'ctDZ8SyeFyTT5MReJM',
|
||||
}
|
||||
|
||||
test.beforeAll(async () => {
|
||||
try {
|
||||
const credentialsId = 'send-email-credentials'
|
||||
await createSmtpCredentials(credentialsId, mockSmtpCredentials)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
})
|
||||
|
||||
test('should send an email', async ({ page }) => {
|
||||
const typebotId = createId()
|
||||
await importTypebotInDatabase(getTestAsset('typebots/sendEmail.json'), {
|
||||
id: typebotId,
|
||||
publicId: `${typebotId}-public`,
|
||||
})
|
||||
await page.goto(`/${typebotId}-public`)
|
||||
await page.locator('text=Send email').click()
|
||||
await expect(page.getByText('Email sent!')).toBeVisible()
|
||||
await page.goto(`${env.NEXTAUTH_URL}/typebots/${typebotId}/results`)
|
||||
await page.click('text="See logs"')
|
||||
await expect(page.locator('text="Email successfully sent"')).toBeVisible()
|
||||
})
|
||||
187
apps/viewer/src/test/settings.spec.ts
Normal file
187
apps/viewer/src/test/settings.spec.ts
Normal file
@@ -0,0 +1,187 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import { createId } from '@paralleldrive/cuid2'
|
||||
import {
|
||||
defaultSettings,
|
||||
defaultTextInputOptions,
|
||||
InputBlockType,
|
||||
Metadata,
|
||||
} from '@typebot.io/schemas'
|
||||
import {
|
||||
createTypebots,
|
||||
updateTypebot,
|
||||
} from '@typebot.io/lib/playwright/databaseActions'
|
||||
import { parseDefaultGroupWithBlock } from '@typebot.io/lib/playwright/databaseHelpers'
|
||||
|
||||
const settings = defaultSettings({ isBrandingEnabled: true })
|
||||
|
||||
test('Result should be overwritten on page refresh', async ({ page }) => {
|
||||
const typebotId = createId()
|
||||
await createTypebots([
|
||||
{
|
||||
id: typebotId,
|
||||
settings: {
|
||||
...settings,
|
||||
general: {
|
||||
...settings.general,
|
||||
rememberUser: {
|
||||
isEnabled: true,
|
||||
storage: 'session',
|
||||
},
|
||||
},
|
||||
},
|
||||
...parseDefaultGroupWithBlock({
|
||||
type: InputBlockType.TEXT,
|
||||
options: defaultTextInputOptions,
|
||||
}),
|
||||
},
|
||||
])
|
||||
|
||||
const [, response] = await Promise.all([
|
||||
page.goto(`/${typebotId}-public`),
|
||||
page.waitForResponse(/sendMessage/),
|
||||
])
|
||||
const { resultId } = await response.json()
|
||||
expect(resultId).toBeDefined()
|
||||
await expect(page.getByRole('textbox')).toBeVisible()
|
||||
|
||||
const [, secondResponse] = await Promise.all([
|
||||
page.reload(),
|
||||
page.waitForResponse(/sendMessage/),
|
||||
])
|
||||
const { resultId: secondResultId } = await secondResponse.json()
|
||||
expect(secondResultId).toBe(resultId)
|
||||
})
|
||||
|
||||
test.describe('Create result on page refresh enabled', () => {
|
||||
test('should work', async ({ page }) => {
|
||||
const typebotId = createId()
|
||||
await createTypebots([
|
||||
{
|
||||
id: typebotId,
|
||||
...parseDefaultGroupWithBlock({
|
||||
type: InputBlockType.TEXT,
|
||||
options: defaultTextInputOptions,
|
||||
}),
|
||||
},
|
||||
])
|
||||
const [, response] = await Promise.all([
|
||||
page.goto(`/${typebotId}-public`),
|
||||
page.waitForResponse(/sendMessage/),
|
||||
])
|
||||
const { resultId } = await response.json()
|
||||
expect(resultId).toBeDefined()
|
||||
|
||||
await expect(page.getByRole('textbox')).toBeVisible()
|
||||
const [, secondResponse] = await Promise.all([
|
||||
page.reload(),
|
||||
page.waitForResponse(/sendMessage/),
|
||||
])
|
||||
const { resultId: secondResultId } = await secondResponse.json()
|
||||
expect(secondResultId).not.toBe(resultId)
|
||||
})
|
||||
})
|
||||
|
||||
test('Hide query params', async ({ page }) => {
|
||||
const typebotId = createId()
|
||||
await createTypebots([
|
||||
{
|
||||
id: typebotId,
|
||||
...parseDefaultGroupWithBlock({
|
||||
type: InputBlockType.TEXT,
|
||||
options: defaultTextInputOptions,
|
||||
}),
|
||||
},
|
||||
])
|
||||
await page.goto(`/${typebotId}-public?Name=John`)
|
||||
await page.waitForTimeout(1000)
|
||||
expect(page.url()).toEqual(`http://localhost:3001/${typebotId}-public`)
|
||||
await updateTypebot({
|
||||
id: typebotId,
|
||||
settings: {
|
||||
...settings,
|
||||
general: { ...settings.general, isHideQueryParamsEnabled: false },
|
||||
},
|
||||
})
|
||||
await page.goto(`/${typebotId}-public?Name=John`)
|
||||
await page.waitForTimeout(1000)
|
||||
expect(page.url()).toEqual(
|
||||
`http://localhost:3001/${typebotId}-public?Name=John`
|
||||
)
|
||||
})
|
||||
|
||||
test('Show close message', async ({ page }) => {
|
||||
const typebotId = createId()
|
||||
await createTypebots([
|
||||
{
|
||||
id: typebotId,
|
||||
...parseDefaultGroupWithBlock({
|
||||
type: InputBlockType.TEXT,
|
||||
options: defaultTextInputOptions,
|
||||
}),
|
||||
isClosed: true,
|
||||
},
|
||||
])
|
||||
await page.goto(`/${typebotId}-public`)
|
||||
await expect(page.locator('text=This bot is now closed')).toBeVisible()
|
||||
})
|
||||
|
||||
test('Should correctly parse metadata', async ({ page }) => {
|
||||
const typebotId = createId()
|
||||
const customMetadata: Metadata = {
|
||||
description: 'My custom description',
|
||||
title: 'Custom title',
|
||||
favIconUrl: 'https://www.baptistearno.com/favicon.png',
|
||||
imageUrl: 'https://www.baptistearno.com/images/site-preview.png',
|
||||
customHeadCode: '<meta name="author" content="John Doe">',
|
||||
}
|
||||
await createTypebots([
|
||||
{
|
||||
id: typebotId,
|
||||
settings: {
|
||||
...settings,
|
||||
metadata: customMetadata,
|
||||
},
|
||||
...parseDefaultGroupWithBlock({
|
||||
type: InputBlockType.TEXT,
|
||||
options: defaultTextInputOptions,
|
||||
}),
|
||||
},
|
||||
])
|
||||
await page.goto(`/${typebotId}-public`)
|
||||
expect(
|
||||
await page.evaluate(`document.querySelector('title').textContent`)
|
||||
).toBe(customMetadata.title)
|
||||
expect(
|
||||
await page.evaluate(
|
||||
() =>
|
||||
(document.querySelector('meta[name="description"]') as HTMLMetaElement)
|
||||
.content
|
||||
)
|
||||
).toBe(customMetadata.description)
|
||||
expect(
|
||||
await page.evaluate(
|
||||
() =>
|
||||
(document.querySelector('meta[property="og:image"]') as HTMLMetaElement)
|
||||
.content
|
||||
)
|
||||
).toBe(customMetadata.imageUrl)
|
||||
expect(
|
||||
await page.evaluate(() =>
|
||||
(
|
||||
document.querySelector('link[rel="icon"]') as HTMLLinkElement
|
||||
).getAttribute('href')
|
||||
)
|
||||
).toBe(customMetadata.favIconUrl)
|
||||
await expect(
|
||||
page.locator(
|
||||
`input[placeholder="${defaultTextInputOptions.labels.placeholder}"]`
|
||||
)
|
||||
).toBeVisible()
|
||||
expect(
|
||||
await page.evaluate(
|
||||
() =>
|
||||
(document.querySelector('meta[name="author"]') as HTMLMetaElement)
|
||||
.content
|
||||
)
|
||||
).toBe('John Doe')
|
||||
})
|
||||
57
apps/viewer/src/test/typebotLink.spec.ts
Normal file
57
apps/viewer/src/test/typebotLink.spec.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { getTestAsset } from '@/test/utils/playwright'
|
||||
import test, { expect } from '@playwright/test'
|
||||
import { env } from '@typebot.io/env'
|
||||
import { importTypebotInDatabase } from '@typebot.io/lib/playwright/databaseActions'
|
||||
|
||||
const typebotId = 'cl0ibhi7s0018n21aarlmg0cm'
|
||||
const typebotWithMergeDisabledId = 'cl0ibhi7s0018n21aarlag0cm'
|
||||
const linkedTypebotId = 'cl0ibhv8d0130n21aw8doxhj5'
|
||||
|
||||
test.beforeAll(async () => {
|
||||
try {
|
||||
await importTypebotInDatabase(
|
||||
getTestAsset('typebots/linkTypebots/1.json'),
|
||||
{ id: typebotId, publicId: `${typebotId}-public` }
|
||||
)
|
||||
await importTypebotInDatabase(
|
||||
getTestAsset('typebots/linkTypebots/1-merge-disabled.json'),
|
||||
{
|
||||
id: typebotWithMergeDisabledId,
|
||||
publicId: `${typebotWithMergeDisabledId}-public`,
|
||||
}
|
||||
)
|
||||
await importTypebotInDatabase(
|
||||
getTestAsset('typebots/linkTypebots/2.json'),
|
||||
{ id: linkedTypebotId, publicId: `${linkedTypebotId}-public` }
|
||||
)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
})
|
||||
|
||||
test('should work as expected', async ({ page }) => {
|
||||
await page.goto(`/${typebotId}-public`)
|
||||
await page.locator('input').fill('Hello there!')
|
||||
await page.locator('input').press('Enter')
|
||||
await expect(page.getByText('Cheers!')).toBeVisible()
|
||||
await page.goto(`${env.NEXTAUTH_URL}/typebots/${typebotId}/results`)
|
||||
await expect(page.locator('text=Hello there!')).toBeVisible()
|
||||
})
|
||||
|
||||
test.describe('Merge disabled', () => {
|
||||
test('should work as expected', async ({ page }) => {
|
||||
await page.goto(`/${typebotWithMergeDisabledId}-public`)
|
||||
await page.locator('input').fill('Hello there!')
|
||||
await page.locator('input').press('Enter')
|
||||
await expect(page.getByText('Cheers!')).toBeVisible()
|
||||
await page.goto(
|
||||
`${process.env.NEXTAUTH_URL}/typebots/${typebotWithMergeDisabledId}/results`
|
||||
)
|
||||
await expect(page.locator('text=Submitted at')).toBeVisible()
|
||||
await expect(page.locator('text=Hello there!')).toBeHidden()
|
||||
await page.goto(
|
||||
`${process.env.NEXTAUTH_URL}/typebots/${linkedTypebotId}/results`
|
||||
)
|
||||
await expect(page.locator('text=Hello there!')).toBeVisible()
|
||||
})
|
||||
})
|
||||
19
apps/viewer/src/test/variables.spec.ts
Normal file
19
apps/viewer/src/test/variables.spec.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { getTestAsset } from '@/test/utils/playwright'
|
||||
import test, { expect } from '@playwright/test'
|
||||
import { createId } from '@paralleldrive/cuid2'
|
||||
import { importTypebotInDatabase } from '@typebot.io/lib/playwright/databaseActions'
|
||||
|
||||
test('should correctly be injected', async ({ page }) => {
|
||||
const typebotId = createId()
|
||||
await importTypebotInDatabase(
|
||||
getTestAsset('typebots/predefinedVariables.json'),
|
||||
{ id: typebotId, publicId: `${typebotId}-public` }
|
||||
)
|
||||
await page.goto(`/${typebotId}-public`)
|
||||
await expect(page.locator('text="Your name is"')).toBeVisible()
|
||||
await page.goto(`/${typebotId}-public?Name=Baptiste&Email=email@test.com`)
|
||||
await expect(page.locator('text="Your name is Baptiste"')).toBeVisible()
|
||||
await expect(page.getByPlaceholder('Type your email...')).toHaveValue(
|
||||
'email@test.com'
|
||||
)
|
||||
})
|
||||
67
apps/viewer/src/test/webhook.spec.ts
Normal file
67
apps/viewer/src/test/webhook.spec.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import { createId } from '@paralleldrive/cuid2'
|
||||
import { HttpMethod } from '@typebot.io/schemas/features/blocks/integrations/webhook/enums'
|
||||
import {
|
||||
createWebhook,
|
||||
importTypebotInDatabase,
|
||||
} from '@typebot.io/lib/playwright/databaseActions'
|
||||
import { getTestAsset } from '@/test/utils/playwright'
|
||||
|
||||
const typebotId = createId()
|
||||
|
||||
test.beforeEach(async () => {
|
||||
await importTypebotInDatabase(getTestAsset('typebots/webhook.json'), {
|
||||
id: typebotId,
|
||||
publicId: `${typebotId}-public`,
|
||||
})
|
||||
|
||||
try {
|
||||
await createWebhook(typebotId, {
|
||||
id: 'failing-webhook',
|
||||
url: 'http://localhost:3001/api/mock/fail',
|
||||
method: HttpMethod.POST,
|
||||
})
|
||||
|
||||
await createWebhook(typebotId, {
|
||||
id: 'partial-body-webhook',
|
||||
url: 'http://localhost:3000/api/mock/webhook-easy-config',
|
||||
method: HttpMethod.POST,
|
||||
body: `{
|
||||
"name": "{{Name}}",
|
||||
"age": {{Age}},
|
||||
"gender": "{{Gender}}"
|
||||
}`,
|
||||
})
|
||||
|
||||
await createWebhook(typebotId, {
|
||||
id: 'full-body-webhook',
|
||||
url: 'http://localhost:3000/api/mock/webhook-easy-config',
|
||||
method: HttpMethod.POST,
|
||||
body: `{{Full body}}`,
|
||||
})
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
})
|
||||
|
||||
test('should execute webhooks properly', async ({ page }) => {
|
||||
await page.goto(`/${typebotId}-public`)
|
||||
await page.locator('text=Send failing webhook').click()
|
||||
await page.locator('[placeholder="Type a name..."]').fill('John')
|
||||
await page.locator('text="Send"').click()
|
||||
await page.locator('[placeholder="Type an age..."]').fill('30')
|
||||
await page.locator('text="Send"').click()
|
||||
await page.locator('text="Male"').click()
|
||||
await expect(
|
||||
page.getByText('{"name":"John","age":25,"gender":"male"}')
|
||||
).toBeVisible()
|
||||
await expect(
|
||||
page.getByText('{"name":"John","age":30,"gender":"Male"}')
|
||||
).toBeVisible()
|
||||
await page.goto(`http://localhost:3000/typebots/${typebotId}/results`)
|
||||
await page.click('text="See logs"')
|
||||
await expect(
|
||||
page.locator('text="Webhook successfuly executed." >> nth=1')
|
||||
).toBeVisible()
|
||||
await expect(page.locator('text="Webhook returned an error."')).toBeVisible()
|
||||
})
|
||||
Reference in New Issue
Block a user