✨ Introduce bot v2 in builder (#328)
Also, the new engine is the default for updated typebots for viewer Closes #211
This commit is contained in:
@ -1,161 +0,0 @@
|
||||
import { TypebotViewer } from 'bot-engine'
|
||||
import { AnswerInput, PublicTypebot, Typebot, VariableWithValue } from 'models'
|
||||
import { useRouter } from 'next/router'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import {
|
||||
injectCustomHeadCode,
|
||||
isDefined,
|
||||
isNotDefined,
|
||||
isNotEmpty,
|
||||
} from 'utils'
|
||||
import { SEO } from './Seo'
|
||||
import { ErrorPage } from './ErrorPage'
|
||||
import { createResultQuery, updateResultQuery } from '@/features/results'
|
||||
import { upsertAnswerQuery } from '@/features/answers'
|
||||
import { gtmBodyElement } from '@/lib/google-tag-manager'
|
||||
import {
|
||||
getExistingResultFromSession,
|
||||
setResultInSession,
|
||||
} from '@/utils/sessionStorage'
|
||||
|
||||
export type TypebotPageProps = {
|
||||
publishedTypebot: Omit<PublicTypebot, 'createdAt' | 'updatedAt'> & {
|
||||
typebot: Pick<Typebot, 'name' | 'isClosed' | 'isArchived'>
|
||||
}
|
||||
url: string
|
||||
isIE: boolean
|
||||
customHeadCode: string | null
|
||||
}
|
||||
|
||||
export const TypebotPage = ({
|
||||
publishedTypebot,
|
||||
isIE,
|
||||
url,
|
||||
customHeadCode,
|
||||
}: TypebotPageProps) => {
|
||||
const { asPath, push } = useRouter()
|
||||
const [showTypebot, setShowTypebot] = useState(false)
|
||||
const [predefinedVariables, setPredefinedVariables] = useState<{
|
||||
[key: string]: string
|
||||
}>()
|
||||
const [error, setError] = useState<Error | undefined>(
|
||||
isIE ? new Error('Internet explorer is not supported') : undefined
|
||||
)
|
||||
const [resultId, setResultId] = useState<string | undefined>()
|
||||
const [variableUpdateQueue, setVariableUpdateQueue] = useState<
|
||||
VariableWithValue[][]
|
||||
>([])
|
||||
const [chatStarted, setChatStarted] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
setShowTypebot(true)
|
||||
const urlParams = new URLSearchParams(location.search)
|
||||
clearQueryParams()
|
||||
const predefinedVariables: { [key: string]: string } = {}
|
||||
urlParams.forEach((value, key) => {
|
||||
predefinedVariables[key] = value
|
||||
})
|
||||
setPredefinedVariables(predefinedVariables)
|
||||
initializeResult().then()
|
||||
if (isDefined(customHeadCode)) injectCustomHeadCode(customHeadCode)
|
||||
const gtmId = publishedTypebot.settings.metadata.googleTagManagerId
|
||||
if (isNotEmpty(gtmId)) document.body.prepend(gtmBodyElement(gtmId))
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
|
||||
const clearQueryParams = () => {
|
||||
const hasQueryParams = asPath.includes('?')
|
||||
if (
|
||||
hasQueryParams &&
|
||||
publishedTypebot.settings.general.isHideQueryParamsEnabled !== false
|
||||
)
|
||||
push(asPath.split('?')[0], undefined, { shallow: true })
|
||||
}
|
||||
|
||||
const initializeResult = async () => {
|
||||
const resultIdFromSession = getExistingResultFromSession()
|
||||
if (resultIdFromSession) setResultId(resultIdFromSession)
|
||||
else {
|
||||
const { error, data } = await createResultQuery(
|
||||
publishedTypebot.typebotId
|
||||
)
|
||||
if (error) return setError(error)
|
||||
if (data?.hasReachedLimit)
|
||||
return setError(new Error('This bot is now closed.'))
|
||||
if (data?.result) {
|
||||
setResultId(data.result.id)
|
||||
if (
|
||||
publishedTypebot.settings.general.isNewResultOnRefreshEnabled !== true
|
||||
)
|
||||
setResultInSession(data.result.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!resultId || variableUpdateQueue.length === 0) return
|
||||
Promise.all(variableUpdateQueue.map(sendNewVariables(resultId))).then()
|
||||
setVariableUpdateQueue([])
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [resultId])
|
||||
|
||||
const handleNewVariables = async (variables: VariableWithValue[]) => {
|
||||
if (!resultId)
|
||||
return setVariableUpdateQueue([...variableUpdateQueue, variables])
|
||||
await sendNewVariables(resultId)(variables)
|
||||
}
|
||||
|
||||
const sendNewVariables =
|
||||
(resultId: string) => async (variables: VariableWithValue[]) => {
|
||||
if (publishedTypebot.settings.general.isResultSavingEnabled === false)
|
||||
return
|
||||
const { error } = await updateResultQuery(resultId, { variables })
|
||||
if (error) setError(error)
|
||||
}
|
||||
|
||||
const handleNewAnswer = async (
|
||||
answer: AnswerInput & { uploadedFiles: boolean }
|
||||
) => {
|
||||
if (!resultId) return setError(new Error('Error: result was not created'))
|
||||
if (publishedTypebot.settings.general.isResultSavingEnabled !== false) {
|
||||
const { error } = await upsertAnswerQuery({ ...answer, resultId })
|
||||
if (error) setError(error)
|
||||
}
|
||||
if (chatStarted) return
|
||||
updateResultQuery(resultId, {
|
||||
hasStarted: true,
|
||||
}).then(({ error }) => (error ? setError(error) : setChatStarted(true)))
|
||||
}
|
||||
|
||||
const handleCompleted = async () => {
|
||||
if (publishedTypebot.settings.general.isResultSavingEnabled === false)
|
||||
return
|
||||
if (!resultId) return setError(new Error('Error: result was not created'))
|
||||
const { error } = await updateResultQuery(resultId, { isCompleted: true })
|
||||
if (error) setError(error)
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return <ErrorPage error={error} />
|
||||
}
|
||||
return (
|
||||
<div style={{ height: '100vh' }}>
|
||||
<SEO
|
||||
url={url}
|
||||
typebotName={publishedTypebot.typebot.name}
|
||||
metadata={publishedTypebot.settings.metadata}
|
||||
/>
|
||||
{showTypebot && (
|
||||
<TypebotViewer
|
||||
typebot={publishedTypebot}
|
||||
resultId={resultId}
|
||||
predefinedVariables={predefinedVariables}
|
||||
onNewAnswer={handleNewAnswer}
|
||||
onCompleted={handleCompleted}
|
||||
onVariablesUpdated={handleNewVariables}
|
||||
isLoading={isNotDefined(resultId)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
@ -1,50 +1,161 @@
|
||||
import { Standard } from '@typebot.io/react'
|
||||
import { BackgroundType, Typebot } from 'models'
|
||||
import { TypebotViewer } from 'bot-engine'
|
||||
import { AnswerInput, PublicTypebot, Typebot, VariableWithValue } from 'models'
|
||||
import { useRouter } from 'next/router'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import {
|
||||
injectCustomHeadCode,
|
||||
isDefined,
|
||||
isNotDefined,
|
||||
isNotEmpty,
|
||||
} from 'utils'
|
||||
import { SEO } from './Seo'
|
||||
import { ErrorPage } from './ErrorPage'
|
||||
import { createResultQuery, updateResultQuery } from '@/features/results'
|
||||
import { upsertAnswerQuery } from '@/features/answers'
|
||||
import { gtmBodyElement } from '@/lib/google-tag-manager'
|
||||
import {
|
||||
getExistingResultFromSession,
|
||||
setResultInSession,
|
||||
} from '@/utils/sessionStorage'
|
||||
|
||||
export type TypebotPageProps = {
|
||||
publishedTypebot: Omit<PublicTypebot, 'createdAt' | 'updatedAt'> & {
|
||||
typebot: Pick<Typebot, 'name' | 'isClosed' | 'isArchived' | 'publicId'>
|
||||
}
|
||||
url: string
|
||||
typebot?: Pick<Typebot, 'settings' | 'theme' | 'name' | 'publicId'>
|
||||
isIE: boolean
|
||||
customHeadCode: string | null
|
||||
}
|
||||
|
||||
export const TypebotPage = ({ url, typebot }: TypebotPageProps) => {
|
||||
const { asPath, push, query } = useRouter()
|
||||
export const TypebotPageV2 = ({
|
||||
publishedTypebot,
|
||||
isIE,
|
||||
url,
|
||||
customHeadCode,
|
||||
}: TypebotPageProps) => {
|
||||
const { asPath, push } = useRouter()
|
||||
const [showTypebot, setShowTypebot] = useState(false)
|
||||
const [predefinedVariables, setPredefinedVariables] = useState<{
|
||||
[key: string]: string
|
||||
}>()
|
||||
const [error, setError] = useState<Error | undefined>(
|
||||
isIE ? new Error('Internet explorer is not supported') : undefined
|
||||
)
|
||||
const [resultId, setResultId] = useState<string | undefined>()
|
||||
const [variableUpdateQueue, setVariableUpdateQueue] = useState<
|
||||
VariableWithValue[][]
|
||||
>([])
|
||||
const [chatStarted, setChatStarted] = useState(false)
|
||||
|
||||
const background = typebot?.theme.general.background
|
||||
useEffect(() => {
|
||||
setShowTypebot(true)
|
||||
const urlParams = new URLSearchParams(location.search)
|
||||
clearQueryParams()
|
||||
const predefinedVariables: { [key: string]: string } = {}
|
||||
urlParams.forEach((value, key) => {
|
||||
predefinedVariables[key] = value
|
||||
})
|
||||
setPredefinedVariables(predefinedVariables)
|
||||
initializeResult().then()
|
||||
if (isDefined(customHeadCode)) injectCustomHeadCode(customHeadCode)
|
||||
const gtmId = publishedTypebot.settings.metadata.googleTagManagerId
|
||||
if (isNotEmpty(gtmId)) document.body.prepend(gtmBodyElement(gtmId))
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
|
||||
const clearQueryParamsIfNecessary = () => {
|
||||
const clearQueryParams = () => {
|
||||
const hasQueryParams = asPath.includes('?')
|
||||
if (
|
||||
!hasQueryParams ||
|
||||
!(typebot?.settings.general.isHideQueryParamsEnabled ?? true)
|
||||
hasQueryParams &&
|
||||
publishedTypebot.settings.general.isHideQueryParamsEnabled !== false
|
||||
)
|
||||
return
|
||||
push(asPath.split('?')[0], undefined, { shallow: true })
|
||||
push(asPath.split('?')[0], undefined, { shallow: true })
|
||||
}
|
||||
|
||||
const initializeResult = async () => {
|
||||
const resultIdFromSession = getExistingResultFromSession()
|
||||
if (resultIdFromSession) setResultId(resultIdFromSession)
|
||||
else {
|
||||
const { error, data } = await createResultQuery(
|
||||
publishedTypebot.typebotId
|
||||
)
|
||||
if (error) return setError(error)
|
||||
if (data?.hasReachedLimit)
|
||||
return setError(new Error('This bot is now closed.'))
|
||||
if (data?.result) {
|
||||
setResultId(data.result.id)
|
||||
if (
|
||||
publishedTypebot.settings.general.isNewResultOnRefreshEnabled !== true
|
||||
)
|
||||
setResultInSession(data.result.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!resultId || variableUpdateQueue.length === 0) return
|
||||
Promise.all(variableUpdateQueue.map(sendNewVariables(resultId))).then()
|
||||
setVariableUpdateQueue([])
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [resultId])
|
||||
|
||||
const handleNewVariables = async (variables: VariableWithValue[]) => {
|
||||
if (!resultId)
|
||||
return setVariableUpdateQueue([...variableUpdateQueue, variables])
|
||||
await sendNewVariables(resultId)(variables)
|
||||
}
|
||||
|
||||
const sendNewVariables =
|
||||
(resultId: string) => async (variables: VariableWithValue[]) => {
|
||||
if (publishedTypebot.settings.general.isResultSavingEnabled === false)
|
||||
return
|
||||
const { error } = await updateResultQuery(resultId, { variables })
|
||||
if (error) setError(error)
|
||||
}
|
||||
|
||||
const handleNewAnswer = async (
|
||||
answer: AnswerInput & { uploadedFiles: boolean }
|
||||
) => {
|
||||
if (!resultId) return setError(new Error('Error: result was not created'))
|
||||
if (publishedTypebot.settings.general.isResultSavingEnabled !== false) {
|
||||
const { error } = await upsertAnswerQuery({ ...answer, resultId })
|
||||
if (error) setError(error)
|
||||
}
|
||||
if (chatStarted) return
|
||||
updateResultQuery(resultId, {
|
||||
hasStarted: true,
|
||||
}).then(({ error }) => (error ? setError(error) : setChatStarted(true)))
|
||||
}
|
||||
|
||||
const handleCompleted = async () => {
|
||||
if (publishedTypebot.settings.general.isResultSavingEnabled === false)
|
||||
return
|
||||
if (!resultId) return setError(new Error('Error: result was not created'))
|
||||
const { error } = await updateResultQuery(resultId, { isCompleted: true })
|
||||
if (error) setError(error)
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return <ErrorPage error={error} />
|
||||
}
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
height: '100vh',
|
||||
// Set background color to avoid SSR flash
|
||||
backgroundColor:
|
||||
background?.type === BackgroundType.COLOR
|
||||
? background?.content
|
||||
: 'white',
|
||||
}}
|
||||
>
|
||||
{typebot && (
|
||||
<SEO
|
||||
url={url}
|
||||
typebotName={typebot.name}
|
||||
metadata={typebot.settings.metadata}
|
||||
<div style={{ height: '100vh' }}>
|
||||
<SEO
|
||||
url={url}
|
||||
typebotName={publishedTypebot.typebot.name}
|
||||
metadata={publishedTypebot.settings.metadata}
|
||||
/>
|
||||
{showTypebot && (
|
||||
<TypebotViewer
|
||||
typebot={publishedTypebot}
|
||||
resultId={resultId}
|
||||
predefinedVariables={predefinedVariables}
|
||||
onNewAnswer={handleNewAnswer}
|
||||
onCompleted={handleCompleted}
|
||||
onVariablesUpdated={handleNewVariables}
|
||||
isLoading={isNotDefined(resultId)}
|
||||
/>
|
||||
)}
|
||||
<Standard
|
||||
typebot={typebot?.publicId ?? query.publicId?.toString() ?? 'n'}
|
||||
onInit={clearQueryParamsIfNecessary}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
50
apps/viewer/src/components/TypebotPageV3.tsx
Normal file
50
apps/viewer/src/components/TypebotPageV3.tsx
Normal file
@ -0,0 +1,50 @@
|
||||
import { Standard } from '@typebot.io/react'
|
||||
import { BackgroundType, Typebot } from 'models'
|
||||
import { useRouter } from 'next/router'
|
||||
import { SEO } from './Seo'
|
||||
|
||||
export type TypebotPageProps = {
|
||||
url: string
|
||||
typebot?: Pick<Typebot, 'settings' | 'theme' | 'name' | 'publicId'>
|
||||
}
|
||||
|
||||
export const TypebotPageV3 = ({ url, typebot }: TypebotPageProps) => {
|
||||
const { asPath, push, query } = useRouter()
|
||||
|
||||
const background = typebot?.theme.general.background
|
||||
|
||||
const clearQueryParamsIfNecessary = () => {
|
||||
const hasQueryParams = asPath.includes('?')
|
||||
if (
|
||||
!hasQueryParams ||
|
||||
!(typebot?.settings.general.isHideQueryParamsEnabled ?? true)
|
||||
)
|
||||
return
|
||||
push(asPath.split('?')[0], undefined, { shallow: true })
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
height: '100vh',
|
||||
// Set background color to avoid SSR flash
|
||||
backgroundColor:
|
||||
background?.type === BackgroundType.COLOR
|
||||
? background?.content
|
||||
: 'white',
|
||||
}}
|
||||
>
|
||||
{typebot && (
|
||||
<SEO
|
||||
url={url}
|
||||
typebotName={typebot.name}
|
||||
metadata={typebot.settings.metadata}
|
||||
/>
|
||||
)}
|
||||
<Standard
|
||||
typebot={typebot?.publicId ?? query.publicId?.toString() ?? 'n'}
|
||||
onInit={clearQueryParamsIfNecessary}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -8,7 +8,6 @@ import {
|
||||
importTypebotInDatabase,
|
||||
injectFakeResults,
|
||||
} from 'utils/playwright/databaseActions'
|
||||
import { typebotViewer } from 'utils/playwright/testHelpers'
|
||||
import { getTestAsset } from '@/test/utils/playwright'
|
||||
import { Plan } from 'db'
|
||||
|
||||
@ -21,18 +20,16 @@ test('should work as expected', async ({ page, browser }) => {
|
||||
publicId: `${typebotId}-public`,
|
||||
})
|
||||
await page.goto(`/${typebotId}-public`)
|
||||
await typebotViewer(page)
|
||||
await page
|
||||
.locator(`input[type="file"]`)
|
||||
.setInputFiles([
|
||||
getTestAsset('typebots/api.json'),
|
||||
getTestAsset('typebots/fileUpload.json'),
|
||||
getTestAsset('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 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(`${process.env.NEXTAUTH_URL}/typebots/${typebotId}/results`)
|
||||
await expect(page.getByRole('link', { name: 'api.json' })).toHaveAttribute(
|
||||
'href',
|
||||
@ -100,18 +97,16 @@ test.describe('Storage limit is reached', () => {
|
||||
page,
|
||||
}) => {
|
||||
await page.goto(`/${typebotId}-public`)
|
||||
await typebotViewer(page)
|
||||
await page
|
||||
.locator(`input[type="file"]`)
|
||||
.setInputFiles([
|
||||
getTestAsset('typebots/api.json'),
|
||||
getTestAsset('typebots/fileUpload.json'),
|
||||
getTestAsset('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 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.evaluate(() =>
|
||||
window.localStorage.setItem('workspaceId', 'starterWorkspace')
|
||||
)
|
||||
|
@ -1,117 +0,0 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import { createId } from '@paralleldrive/cuid2'
|
||||
import { parse } from 'papaparse'
|
||||
import { readFileSync } from 'fs'
|
||||
import { isDefined } from 'utils'
|
||||
import {
|
||||
createWorkspaces,
|
||||
importTypebotInDatabase,
|
||||
injectFakeResults,
|
||||
} from 'utils/playwright/databaseActions'
|
||||
import { getTestAsset } from '@/test/utils/playwright'
|
||||
import { Plan } from 'db'
|
||||
|
||||
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(`/next/${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(`${process.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(process.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,
|
||||
})
|
||||
})
|
||||
|
||||
test("shouldn't upload anything if limit has been reached", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto(`/next/${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.evaluate(() =>
|
||||
window.localStorage.setItem('workspaceId', 'starterWorkspace')
|
||||
)
|
||||
await page.goto(`${process.env.NEXTAUTH_URL}/typebots/${typebotId}/results`)
|
||||
await expect(page.locator('text="150%"')).toBeVisible()
|
||||
await expect(page.locator('text="api.json"')).toBeHidden()
|
||||
})
|
||||
})
|
@ -3,7 +3,6 @@ import { createId } from '@paralleldrive/cuid2'
|
||||
import { createTypebots } from 'utils/playwright/databaseActions'
|
||||
import { parseDefaultGroupWithBlock } from 'utils/playwright/databaseHelpers'
|
||||
import { defaultChatwootOptions, IntegrationBlockType } from 'models'
|
||||
import { typebotViewer } from 'utils/playwright/testHelpers'
|
||||
|
||||
const typebotId = createId()
|
||||
|
||||
@ -26,6 +25,6 @@ test('should work as expected', async ({ page }) => {
|
||||
},
|
||||
])
|
||||
await page.goto(`/${typebotId}-public`)
|
||||
await typebotViewer(page).getByRole('button', { name: 'Go' }).click()
|
||||
await page.getByRole('button', { name: 'Go' }).click()
|
||||
await expect(page.locator('#chatwoot_live_chat_widget')).toBeVisible()
|
||||
})
|
||||
|
@ -1,30 +0,0 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import { createId } from '@paralleldrive/cuid2'
|
||||
import { createTypebots } from 'utils/playwright/databaseActions'
|
||||
import { parseDefaultGroupWithBlock } from 'utils/playwright/databaseHelpers'
|
||||
import { defaultChatwootOptions, IntegrationBlockType } from 'models'
|
||||
|
||||
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(`/next/${typebotId}-public`)
|
||||
await page.getByRole('button', { name: 'Go' }).click()
|
||||
await expect(page.locator('#chatwoot_live_chat_widget')).toBeVisible()
|
||||
})
|
@ -3,7 +3,6 @@ import { createSmtpCredentials } from '../../../../test/utils/databaseActions'
|
||||
import { createId } from '@paralleldrive/cuid2'
|
||||
import { SmtpCredentialsData } from 'models'
|
||||
import { importTypebotInDatabase } from 'utils/playwright/databaseActions'
|
||||
import { typebotViewer } from 'utils/playwright/testHelpers'
|
||||
import { getTestAsset } from '@/test/utils/playwright'
|
||||
|
||||
export const mockSmtpCredentials: SmtpCredentialsData = {
|
||||
@ -33,23 +32,8 @@ test('should send an email', async ({ page }) => {
|
||||
publicId: `${typebotId}-public`,
|
||||
})
|
||||
await page.goto(`/${typebotId}-public`)
|
||||
const [response] = await Promise.all([
|
||||
page.waitForResponse((resp) =>
|
||||
resp.request().url().includes(`integrations/email`)
|
||||
),
|
||||
typebotViewer(page).locator('text=Send email').click(),
|
||||
])
|
||||
const { previewUrl } = await response.json()
|
||||
await page.goto(previewUrl)
|
||||
await expect(page.locator('text="Hey!"')).toBeVisible()
|
||||
await expect(
|
||||
page.locator(`text="${mockSmtpCredentials.from.name}"`)
|
||||
).toBeVisible()
|
||||
await expect(page.locator('text="<test1@gmail.com>" >> nth=0')).toBeVisible()
|
||||
await expect(page.locator('text="<test2@gmail.com>" >> nth=0')).toBeVisible()
|
||||
await expect(
|
||||
page.locator('text="<baptiste.arnaud95@gmail.com>" >> nth=0')
|
||||
).toBeVisible()
|
||||
await page.locator('text=Send email').click()
|
||||
await expect(page.getByText('Email sent!')).toBeVisible()
|
||||
await page.goto(`${process.env.NEXTAUTH_URL}/typebots/${typebotId}/results`)
|
||||
await page.click('text="See logs"')
|
||||
await expect(page.locator('text="Email successfully sent"')).toBeVisible()
|
||||
|
@ -1,40 +0,0 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import { createSmtpCredentials } from '../../../../test/utils/databaseActions'
|
||||
import { createId } from '@paralleldrive/cuid2'
|
||||
import { SmtpCredentialsData } from 'models'
|
||||
import { importTypebotInDatabase } from 'utils/playwright/databaseActions'
|
||||
import { getTestAsset } from '@/test/utils/playwright'
|
||||
|
||||
const mockSmtpCredentials: SmtpCredentialsData = {
|
||||
from: {
|
||||
email: 'sunny.cremin66@ethereal.email',
|
||||
name: 'Sunny Cremin',
|
||||
},
|
||||
host: 'smtp.ethereal.email',
|
||||
port: 587,
|
||||
username: 'sunny.cremin66@ethereal.email',
|
||||
password: 'yJDHkf2bYbNydaRvTq',
|
||||
}
|
||||
|
||||
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(`/next/${typebotId}-public`)
|
||||
await page.locator('text=Send email').click()
|
||||
await expect(page.getByText('Email sent!')).toBeVisible()
|
||||
await page.goto(`${process.env.NEXTAUTH_URL}/typebots/${typebotId}/results`)
|
||||
await page.click('text="See logs"')
|
||||
await expect(page.locator('text="Email successfully sent"')).toBeVisible()
|
||||
})
|
@ -1,190 +1,67 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import { createId } from '@paralleldrive/cuid2'
|
||||
import { HttpMethod, Typebot } from 'models'
|
||||
import { HttpMethod } from 'models'
|
||||
import {
|
||||
createWebhook,
|
||||
importTypebotInDatabase,
|
||||
} from 'utils/playwright/databaseActions'
|
||||
import { typebotViewer } from 'utils/playwright/testHelpers'
|
||||
import { apiToken } from 'utils/playwright/databaseSetup'
|
||||
import { getTestAsset } from '@/test/utils/playwright'
|
||||
|
||||
const typebotId = createId()
|
||||
|
||||
test.describe('Bot', () => {
|
||||
test.beforeEach(async () => {
|
||||
await importTypebotInDatabase(getTestAsset('typebots/webhook.json'), {
|
||||
id: typebotId,
|
||||
publicId: `${typebotId}-public`,
|
||||
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,
|
||||
})
|
||||
|
||||
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: '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) {
|
||||
// Webhooks already created
|
||||
}
|
||||
})
|
||||
|
||||
test('should execute webhooks properly', async ({ page }) => {
|
||||
await page.goto(`/${typebotId}-public`)
|
||||
await typebotViewer(page).locator('text=Send failing webhook').click()
|
||||
await typebotViewer(page)
|
||||
.locator('[placeholder="Type a name..."]')
|
||||
.fill('John')
|
||||
await typebotViewer(page).locator('text="Send"').click()
|
||||
await typebotViewer(page)
|
||||
.locator('[placeholder="Type an age..."]')
|
||||
.fill('30')
|
||||
await typebotViewer(page).locator('text="Send"').click()
|
||||
await typebotViewer(page).locator('text="Male"').click()
|
||||
await expect(
|
||||
typebotViewer(page).getByText('{"name":"John","age":25,"gender":"male"}')
|
||||
).toBeVisible()
|
||||
await expect(
|
||||
typebotViewer(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()
|
||||
})
|
||||
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.describe('API', () => {
|
||||
const typebotId = 'webhook-flow'
|
||||
|
||||
test.beforeAll(async () => {
|
||||
try {
|
||||
await importTypebotInDatabase(getTestAsset('typebots/api.json'), {
|
||||
id: typebotId,
|
||||
})
|
||||
await createWebhook(typebotId)
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
})
|
||||
|
||||
test('can list typebots', async ({ request }) => {
|
||||
expect((await request.get(`/api/typebots`)).status()).toBe(401)
|
||||
const response = await request.get(`/api/typebots`, {
|
||||
headers: { Authorization: `Bearer ${apiToken}` },
|
||||
})
|
||||
const { typebots } = (await response.json()) as { typebots: Typebot[] }
|
||||
expect(typebots.length).toBeGreaterThanOrEqual(1)
|
||||
expect(typebots.find((typebot) => typebot.id === typebotId)).toMatchObject({
|
||||
id: typebotId,
|
||||
name: 'My typebot',
|
||||
})
|
||||
})
|
||||
|
||||
test('can get webhook blocks', async ({ request }) => {
|
||||
expect(
|
||||
(await request.get(`/api/typebots/${typebotId}/webhookBlocks`)).status()
|
||||
).toBe(401)
|
||||
const response = await request.get(
|
||||
`/api/typebots/${typebotId}/webhookBlocks`,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${apiToken}` },
|
||||
}
|
||||
)
|
||||
const { blocks } = await response.json()
|
||||
expect(blocks).toHaveLength(1)
|
||||
expect(blocks[0]).toEqual({
|
||||
blockId: 'webhookBlock',
|
||||
name: 'Webhook > webhookBlock',
|
||||
})
|
||||
})
|
||||
|
||||
test('can subscribe webhook', async ({ request }) => {
|
||||
expect(
|
||||
(
|
||||
await request.post(
|
||||
`/api/typebots/${typebotId}/blocks/webhookBlock/subscribeWebhook`,
|
||||
{ data: { url: 'https://test.com' } }
|
||||
)
|
||||
).status()
|
||||
).toBe(401)
|
||||
const response = await request.post(
|
||||
`/api/typebots/${typebotId}/blocks/webhookBlock/subscribeWebhook`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${apiToken}`,
|
||||
},
|
||||
data: { url: 'https://test.com' },
|
||||
}
|
||||
)
|
||||
const body = await response.json()
|
||||
expect(body).toEqual({
|
||||
message: 'success',
|
||||
})
|
||||
})
|
||||
|
||||
test('can unsubscribe webhook', async ({ request }) => {
|
||||
expect(
|
||||
(
|
||||
await request.post(
|
||||
`/api/typebots/${typebotId}/blocks/webhookBlock/unsubscribeWebhook`
|
||||
)
|
||||
).status()
|
||||
).toBe(401)
|
||||
const response = await request.post(
|
||||
`/api/typebots/${typebotId}/blocks/webhookBlock/unsubscribeWebhook`,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${apiToken}` },
|
||||
}
|
||||
)
|
||||
const body = await response.json()
|
||||
expect(body).toEqual({
|
||||
message: 'success',
|
||||
})
|
||||
})
|
||||
|
||||
test('can get a sample result', async ({ request }) => {
|
||||
expect(
|
||||
(
|
||||
await request.get(
|
||||
`/api/typebots/${typebotId}/blocks/webhookBlock/sampleResult`
|
||||
)
|
||||
).status()
|
||||
).toBe(401)
|
||||
const response = await request.get(
|
||||
`/api/typebots/${typebotId}/blocks/webhookBlock/sampleResult`,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${apiToken}` },
|
||||
}
|
||||
)
|
||||
const data = await response.json()
|
||||
expect(data).toMatchObject({
|
||||
message: 'This is a sample result, it has been generated ⬇️',
|
||||
Welcome: 'Hi!',
|
||||
Email: 'test@email.com',
|
||||
Name: 'answer value',
|
||||
Services: 'Website dev, Content Marketing, Social Media, UI / UX Design',
|
||||
'Additional information': 'answer value',
|
||||
})
|
||||
})
|
||||
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()
|
||||
})
|
||||
|
@ -1,67 +0,0 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import { createId } from '@paralleldrive/cuid2'
|
||||
import { HttpMethod } from 'models'
|
||||
import {
|
||||
createWebhook,
|
||||
importTypebotInDatabase,
|
||||
} from 'utils/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) {
|
||||
// Webhooks already created
|
||||
}
|
||||
})
|
||||
|
||||
test('should execute webhooks properly', async ({ page }) => {
|
||||
await page.goto(`/next/${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()
|
||||
})
|
@ -1,9 +1,8 @@
|
||||
import { getTestAsset } from '@/test/utils/playwright'
|
||||
import test, { expect } from '@playwright/test'
|
||||
import { importTypebotInDatabase } from 'utils/playwright/databaseActions'
|
||||
import { typebotViewer } from 'utils/playwright/testHelpers'
|
||||
|
||||
const typebotId = 'cl0ibhi7s0018n21aarlmg0cm1'
|
||||
const typebotId = 'cl0ibhi7s0018n21aarlmg0cm'
|
||||
const linkedTypebotId = 'cl0ibhv8d0130n21aw8doxhj5'
|
||||
|
||||
test.beforeAll(async () => {
|
||||
@ -23,16 +22,9 @@ test.beforeAll(async () => {
|
||||
|
||||
test('should work as expected', async ({ page }) => {
|
||||
await page.goto(`/${typebotId}-public`)
|
||||
await typebotViewer(page).locator('input').fill('Hello there!')
|
||||
await Promise.all([
|
||||
page.waitForResponse(
|
||||
(resp) =>
|
||||
resp.request().url().includes(`/api/typebots/t/results`) &&
|
||||
resp.status() === 200 &&
|
||||
resp.request().method() === 'PUT'
|
||||
),
|
||||
typebotViewer(page).locator('input').press('Enter'),
|
||||
])
|
||||
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/${typebotId}/results`)
|
||||
await expect(page.locator('text=Hello there!')).toBeVisible()
|
||||
})
|
||||
|
@ -1,30 +0,0 @@
|
||||
import { getTestAsset } from '@/test/utils/playwright'
|
||||
import test, { expect } from '@playwright/test'
|
||||
import { importTypebotInDatabase } from 'utils/playwright/databaseActions'
|
||||
|
||||
const typebotId = 'cl0ibhi7s0018n21aarlmg0cm'
|
||||
const linkedTypebotId = 'cl0ibhv8d0130n21aw8doxhj5'
|
||||
|
||||
test.beforeAll(async () => {
|
||||
try {
|
||||
await importTypebotInDatabase(
|
||||
getTestAsset('typebots/linkTypebots/1.json'),
|
||||
{ id: typebotId, publicId: `${typebotId}-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(`/next/${typebotId}-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/${typebotId}/results`)
|
||||
await expect(page.locator('text=Hello there!')).toBeVisible()
|
||||
})
|
@ -1,12 +1,7 @@
|
||||
import { getTestAsset } from '@/test/utils/playwright'
|
||||
import test, { expect } from '@playwright/test'
|
||||
import { createId } from '@paralleldrive/cuid2'
|
||||
import {
|
||||
importTypebotInDatabase,
|
||||
injectFakeResults,
|
||||
} from 'utils/playwright/databaseActions'
|
||||
import { apiToken } from 'utils/playwright/databaseSetup'
|
||||
import { typebotViewer } from 'utils/playwright/testHelpers'
|
||||
import { importTypebotInDatabase } from 'utils/playwright/databaseActions'
|
||||
|
||||
test('Big groups should work as expected', async ({ page }) => {
|
||||
const typebotId = createId()
|
||||
@ -15,11 +10,11 @@ test('Big groups should work as expected', async ({ page }) => {
|
||||
publicId: `${typebotId}-public`,
|
||||
})
|
||||
await page.goto(`/${typebotId}-public`)
|
||||
await typebotViewer(page).locator('input').fill('Baptiste')
|
||||
await typebotViewer(page).locator('input').press('Enter')
|
||||
await typebotViewer(page).locator('input').fill('26')
|
||||
await typebotViewer(page).locator('input').press('Enter')
|
||||
await typebotViewer(page).locator('button >> text=Yes').click()
|
||||
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.locator('button >> text=Yes').click()
|
||||
await page.goto(`${process.env.NEXTAUTH_URL}/typebots/${typebotId}/results`)
|
||||
await expect(page.locator('text="Baptiste"')).toBeVisible()
|
||||
await expect(page.locator('text="26"')).toBeVisible()
|
||||
@ -30,22 +25,3 @@ test('Big groups should work as expected', async ({ page }) => {
|
||||
await expect(page.locator('text="26" >> nth=1')).toBeVisible()
|
||||
await expect(page.locator('text="Yes" >> nth=1')).toBeVisible()
|
||||
})
|
||||
|
||||
test('can list results with API', async ({ request }) => {
|
||||
const typebotId = createId()
|
||||
await importTypebotInDatabase(getTestAsset('typebots/api.json'), {
|
||||
id: typebotId,
|
||||
})
|
||||
await injectFakeResults({ typebotId, count: 20 })
|
||||
expect(
|
||||
(await request.get(`/api/typebots/${typebotId}/results`)).status()
|
||||
).toBe(401)
|
||||
const response = await request.get(
|
||||
`/api/typebots/${typebotId}/results?limit=10`,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${apiToken}` },
|
||||
}
|
||||
)
|
||||
const { results } = await response.json()
|
||||
expect(results).toHaveLength(10)
|
||||
})
|
||||
|
@ -1,27 +0,0 @@
|
||||
import { getTestAsset } from '@/test/utils/playwright'
|
||||
import test, { expect } from '@playwright/test'
|
||||
import { createId } from '@paralleldrive/cuid2'
|
||||
import { importTypebotInDatabase } from 'utils/playwright/databaseActions'
|
||||
|
||||
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(`/next/${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.locator('button >> text=Yes').click()
|
||||
await page.goto(`${process.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()
|
||||
})
|
@ -8,9 +8,8 @@ import {
|
||||
} from 'models'
|
||||
import { createTypebots, updateTypebot } from 'utils/playwright/databaseActions'
|
||||
import { parseDefaultGroupWithBlock } from 'utils/playwright/databaseHelpers'
|
||||
import { typebotViewer } from 'utils/playwright/testHelpers'
|
||||
|
||||
test('Result should be in storage by default', async ({ page }) => {
|
||||
test('Result should be overwritten on page refresh', async ({ page }) => {
|
||||
const typebotId = createId()
|
||||
await createTypebots([
|
||||
{
|
||||
@ -21,18 +20,21 @@ test('Result should be in storage by default', async ({ page }) => {
|
||||
}),
|
||||
},
|
||||
])
|
||||
await Promise.all([
|
||||
|
||||
const [, response] = await Promise.all([
|
||||
page.goto(`/${typebotId}-public`),
|
||||
page.waitForResponse(
|
||||
(resp) =>
|
||||
resp.request().url().includes(`/api/typebots/${typebotId}/results`) &&
|
||||
resp.status() === 200 &&
|
||||
resp.request().method() === 'POST'
|
||||
),
|
||||
page.waitForResponse(/sendMessage/),
|
||||
])
|
||||
await page.reload()
|
||||
const resultId = await page.evaluate(() => sessionStorage.getItem('resultId'))
|
||||
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', () => {
|
||||
@ -54,28 +56,20 @@ test.describe('Create result on page refresh enabled', () => {
|
||||
}),
|
||||
},
|
||||
])
|
||||
await Promise.all([
|
||||
const [, response] = await Promise.all([
|
||||
page.goto(`/${typebotId}-public`),
|
||||
page.waitForResponse(
|
||||
(resp) =>
|
||||
resp.request().url().includes(`/api/typebots/${typebotId}/results`) &&
|
||||
resp.status() === 200 &&
|
||||
resp.request().method() === 'POST'
|
||||
),
|
||||
page.waitForResponse(/sendMessage/),
|
||||
])
|
||||
await Promise.all([
|
||||
const { resultId } = await response.json()
|
||||
expect(resultId).toBeDefined()
|
||||
|
||||
await expect(page.getByRole('textbox')).toBeVisible()
|
||||
const [, secondResponse] = await Promise.all([
|
||||
page.reload(),
|
||||
page.waitForResponse(
|
||||
(resp) =>
|
||||
resp.request().url().includes(`/api/typebots/${typebotId}/results`) &&
|
||||
resp.status() === 200 &&
|
||||
resp.request().method() === 'POST'
|
||||
),
|
||||
page.waitForResponse(/sendMessage/),
|
||||
])
|
||||
const resultId = await page.evaluate(() =>
|
||||
sessionStorage.getItem('resultId')
|
||||
)
|
||||
expect(resultId).toBe(null)
|
||||
const { resultId: secondResultId } = await secondResponse.json()
|
||||
expect(secondResultId).not.toBe(resultId)
|
||||
})
|
||||
})
|
||||
|
||||
@ -125,14 +119,12 @@ test('Show close message', async ({ page }) => {
|
||||
|
||||
test('Should correctly parse metadata', async ({ page }) => {
|
||||
const typebotId = createId()
|
||||
const googleTagManagerId = 'GTM-M72NXKB'
|
||||
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">',
|
||||
googleTagManagerId,
|
||||
}
|
||||
await createTypebots([
|
||||
{
|
||||
@ -148,11 +140,6 @@ test('Should correctly parse metadata', async ({ page }) => {
|
||||
},
|
||||
])
|
||||
await page.goto(`/${typebotId}-public`)
|
||||
await expect(
|
||||
typebotViewer(page).locator(
|
||||
`input[placeholder="${defaultTextInputOptions.labels.placeholder}"]`
|
||||
)
|
||||
).toBeVisible()
|
||||
expect(
|
||||
await page.evaluate(`document.querySelector('title').textContent`)
|
||||
).toBe(customMetadata.title)
|
||||
@ -177,6 +164,11 @@ test('Should correctly parse metadata', async ({ page }) => {
|
||||
).getAttribute('href')
|
||||
)
|
||||
).toBe(customMetadata.favIconUrl)
|
||||
await expect(
|
||||
page.locator(
|
||||
`input[placeholder="${defaultTextInputOptions.labels.placeholder}"]`
|
||||
)
|
||||
).toBeVisible()
|
||||
expect(
|
||||
await page.evaluate(
|
||||
() =>
|
||||
@ -184,12 +176,4 @@ test('Should correctly parse metadata', async ({ page }) => {
|
||||
.content
|
||||
)
|
||||
).toBe('John Doe')
|
||||
expect(
|
||||
await page.evaluate(
|
||||
(googleTagManagerId) =>
|
||||
document.querySelector(
|
||||
`iframe[src="https://www.googletagmanager.com/ns.html?id=${googleTagManagerId}"]`
|
||||
) as HTMLMetaElement
|
||||
)
|
||||
).toBeDefined()
|
||||
})
|
||||
|
@ -1,179 +0,0 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import { createId } from '@paralleldrive/cuid2'
|
||||
import {
|
||||
defaultSettings,
|
||||
defaultTextInputOptions,
|
||||
InputBlockType,
|
||||
Metadata,
|
||||
} from 'models'
|
||||
import { createTypebots, updateTypebot } from 'utils/playwright/databaseActions'
|
||||
import { parseDefaultGroupWithBlock } from 'utils/playwright/databaseHelpers'
|
||||
|
||||
test('Result should be overwritten on page refresh', async ({ page }) => {
|
||||
const typebotId = createId()
|
||||
await createTypebots([
|
||||
{
|
||||
id: typebotId,
|
||||
...parseDefaultGroupWithBlock({
|
||||
type: InputBlockType.TEXT,
|
||||
options: defaultTextInputOptions,
|
||||
}),
|
||||
},
|
||||
])
|
||||
|
||||
const [, response] = await Promise.all([
|
||||
page.goto(`/next/${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,
|
||||
settings: {
|
||||
...defaultSettings,
|
||||
general: {
|
||||
...defaultSettings.general,
|
||||
isNewResultOnRefreshEnabled: true,
|
||||
},
|
||||
},
|
||||
...parseDefaultGroupWithBlock({
|
||||
type: InputBlockType.TEXT,
|
||||
options: defaultTextInputOptions,
|
||||
}),
|
||||
},
|
||||
])
|
||||
const [, response] = await Promise.all([
|
||||
page.goto(`/next/${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(`/next/${typebotId}-public?Name=John`)
|
||||
await page.waitForTimeout(1000)
|
||||
expect(page.url()).toEqual(`http://localhost:3001/next/${typebotId}-public`)
|
||||
await updateTypebot({
|
||||
id: typebotId,
|
||||
settings: {
|
||||
...defaultSettings,
|
||||
general: { ...defaultSettings.general, isHideQueryParamsEnabled: false },
|
||||
},
|
||||
})
|
||||
await page.goto(`/next/${typebotId}-public?Name=John`)
|
||||
await page.waitForTimeout(1000)
|
||||
expect(page.url()).toEqual(
|
||||
`http://localhost:3001/next/${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(`/next/${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: {
|
||||
...defaultSettings,
|
||||
metadata: customMetadata,
|
||||
},
|
||||
...parseDefaultGroupWithBlock({
|
||||
type: InputBlockType.TEXT,
|
||||
options: defaultTextInputOptions,
|
||||
}),
|
||||
},
|
||||
])
|
||||
await page.goto(`/next/${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')
|
||||
})
|
@ -8,7 +8,6 @@ import {
|
||||
importTypebotInDatabase,
|
||||
injectFakeResults,
|
||||
} from 'utils/playwright/databaseActions'
|
||||
import { typebotViewer } from 'utils/playwright/testHelpers'
|
||||
|
||||
test('should not start if chat limit is reached', async ({ page, context }) => {
|
||||
await test.step('Free plan', async () => {
|
||||
@ -38,9 +37,7 @@ test('should not start if chat limit is reached', async ({ page, context }) => {
|
||||
})
|
||||
await injectFakeResults({ typebotId, count: 3000 })
|
||||
await page.goto(`/${typebotId}-public`)
|
||||
await expect(
|
||||
typebotViewer(page).locator('text="Hey there, upload please"')
|
||||
).toBeVisible()
|
||||
await expect(page.locator('text="Hey there, upload please"')).toBeVisible()
|
||||
})
|
||||
|
||||
await test.step('Custom plan', async () => {
|
||||
@ -63,9 +60,7 @@ test('should not start if chat limit is reached', async ({ page, context }) => {
|
||||
})
|
||||
const page = await context.newPage()
|
||||
await page.goto(`/${typebotId}-public`)
|
||||
await expect(
|
||||
typebotViewer(page).locator('text="Hey there, upload please"')
|
||||
).toBeVisible()
|
||||
await expect(page.locator('text="Hey there, upload please"')).toBeVisible()
|
||||
await injectFakeResults({ typebotId, count: 2000 })
|
||||
await page.goto(`/${typebotId}-public`)
|
||||
await expect(page.locator('text="This bot is now closed."')).toBeVisible()
|
||||
|
@ -1,70 +0,0 @@
|
||||
import { getTestAsset } from '@/test/utils/playwright'
|
||||
import test, { expect } from '@playwright/test'
|
||||
import { createId } from '@paralleldrive/cuid2'
|
||||
import { Plan } from 'db'
|
||||
import { defaultSettings } from 'models'
|
||||
import {
|
||||
createWorkspaces,
|
||||
importTypebotInDatabase,
|
||||
injectFakeResults,
|
||||
} from 'utils/playwright/databaseActions'
|
||||
|
||||
test('should not start if chat limit is reached', async ({ page, context }) => {
|
||||
await test.step('Free plan', async () => {
|
||||
const workspaceId = createId()
|
||||
const typebotId = createId()
|
||||
await createWorkspaces([{ id: workspaceId, plan: Plan.FREE }])
|
||||
await importTypebotInDatabase(getTestAsset('typebots/fileUpload.json'), {
|
||||
id: typebotId,
|
||||
publicId: `${typebotId}-public`,
|
||||
workspaceId,
|
||||
})
|
||||
await injectFakeResults({ typebotId, count: 400 })
|
||||
await page.goto(`/next/${typebotId}-public`)
|
||||
await expect(page.locator('text="This bot is now closed."')).toBeVisible()
|
||||
await page.goto(`${process.env.NEXTAUTH_URL}/typebots/${typebotId}/results`)
|
||||
await expect(page.locator('text="133%"')).toBeVisible()
|
||||
})
|
||||
|
||||
await test.step('Lifetime plan', async () => {
|
||||
const workspaceId = createId()
|
||||
const typebotId = createId()
|
||||
await createWorkspaces([{ id: workspaceId, plan: Plan.LIFETIME }])
|
||||
await importTypebotInDatabase(getTestAsset('typebots/fileUpload.json'), {
|
||||
id: typebotId,
|
||||
publicId: `${typebotId}-public`,
|
||||
workspaceId,
|
||||
})
|
||||
await injectFakeResults({ typebotId, count: 3000 })
|
||||
await page.goto(`/next/${typebotId}-public`)
|
||||
await expect(page.locator('text="Hey there, upload please"')).toBeVisible()
|
||||
})
|
||||
|
||||
await test.step('Custom plan', async () => {
|
||||
const workspaceId = createId()
|
||||
const typebotId = createId()
|
||||
await createWorkspaces([
|
||||
{ id: workspaceId, plan: Plan.CUSTOM, customChatsLimit: 1000 },
|
||||
])
|
||||
await importTypebotInDatabase(getTestAsset('typebots/fileUpload.json'), {
|
||||
id: typebotId,
|
||||
publicId: `${typebotId}-public`,
|
||||
workspaceId,
|
||||
settings: {
|
||||
...defaultSettings,
|
||||
general: {
|
||||
...defaultSettings.general,
|
||||
isNewResultOnRefreshEnabled: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
const page = await context.newPage()
|
||||
await page.goto(`/next/${typebotId}-public`)
|
||||
await expect(page.locator('text="Hey there, upload please"')).toBeVisible()
|
||||
await injectFakeResults({ typebotId, count: 2000 })
|
||||
await page.goto(`/next/${typebotId}-public`)
|
||||
await expect(page.locator('text="This bot is now closed."')).toBeVisible()
|
||||
await page.goto(`${process.env.NEXTAUTH_URL}/typebots/${typebotId}/results`)
|
||||
await expect(page.locator('text="200%"')).toBeVisible()
|
||||
})
|
||||
})
|
@ -2,7 +2,6 @@ import { getTestAsset } from '@/test/utils/playwright'
|
||||
import test, { expect } from '@playwright/test'
|
||||
import { createId } from '@paralleldrive/cuid2'
|
||||
import { importTypebotInDatabase } from 'utils/playwright/databaseActions'
|
||||
import { typebotViewer } from 'utils/playwright/testHelpers'
|
||||
|
||||
test('should correctly be injected', async ({ page }) => {
|
||||
const typebotId = createId()
|
||||
@ -11,12 +10,10 @@ test('should correctly be injected', async ({ page }) => {
|
||||
{ id: typebotId, publicId: `${typebotId}-public` }
|
||||
)
|
||||
await page.goto(`/${typebotId}-public`)
|
||||
await expect(typebotViewer(page).locator('text="Your name is"')).toBeVisible()
|
||||
await expect(page.locator('text="Your name is"')).toBeVisible()
|
||||
await page.goto(`/${typebotId}-public?Name=Baptiste&Email=email@test.com`)
|
||||
await expect(
|
||||
typebotViewer(page).locator('text="Your name is Baptiste"')
|
||||
).toBeVisible()
|
||||
await expect(
|
||||
typebotViewer(page).locator('input[value="email@test.com"]')
|
||||
).toBeVisible()
|
||||
await expect(page.locator('text="Your name is Baptiste"')).toBeVisible()
|
||||
await expect(page.getByPlaceholder('Type your email...')).toHaveValue(
|
||||
'email@test.com'
|
||||
)
|
||||
})
|
||||
|
@ -1,21 +0,0 @@
|
||||
import { getTestAsset } from '@/test/utils/playwright'
|
||||
import test, { expect } from '@playwright/test'
|
||||
import { createId } from '@paralleldrive/cuid2'
|
||||
import { importTypebotInDatabase } from 'utils/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(`/next/${typebotId}-public`)
|
||||
await expect(page.locator('text="Your name is"')).toBeVisible()
|
||||
await page.goto(
|
||||
`/next/${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'
|
||||
)
|
||||
})
|
@ -3,8 +3,9 @@ import { ErrorPage } from '@/components/ErrorPage'
|
||||
import { NotFoundPage } from '@/components/NotFoundPage'
|
||||
import { GetServerSideProps, GetServerSidePropsContext } from 'next'
|
||||
import { env, getViewerUrl, isDefined, isNotDefined, omit } from 'utils'
|
||||
import { TypebotPage, TypebotPageProps } from '../components/TypebotPage'
|
||||
import prisma from '../lib/prisma'
|
||||
import { TypebotPageProps, TypebotPageV2 } from '@/components/TypebotPageV2'
|
||||
import { TypebotPageV3 } from '@/components/TypebotPageV3'
|
||||
|
||||
export const getServerSideProps: GetServerSideProps = async (
|
||||
context: GetServerSidePropsContext
|
||||
@ -76,7 +77,14 @@ const getTypebotFromCustomDomain = async (
|
||||
const publishedTypebot = await prisma.publicTypebot.findFirst({
|
||||
where: { typebot: { customDomain } },
|
||||
include: {
|
||||
typebot: { select: { name: true, isClosed: true, isArchived: true } },
|
||||
typebot: {
|
||||
select: {
|
||||
name: true,
|
||||
isClosed: true,
|
||||
isArchived: true,
|
||||
publicId: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
if (isNotDefined(publishedTypebot)) return null
|
||||
@ -99,7 +107,19 @@ const App = ({ publishedTypebot, ...props }: TypebotPageProps) => {
|
||||
return <NotFoundPage />
|
||||
if (publishedTypebot.typebot.isClosed)
|
||||
return <ErrorPage error={new Error('This bot is now closed')} />
|
||||
return <TypebotPage publishedTypebot={publishedTypebot} {...props} />
|
||||
return publishedTypebot.version === '3' ? (
|
||||
<TypebotPageV3
|
||||
url={props.url}
|
||||
typebot={{
|
||||
name: publishedTypebot.typebot.name,
|
||||
publicId: publishedTypebot.typebot.publicId,
|
||||
settings: publishedTypebot.settings,
|
||||
theme: publishedTypebot.theme,
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<TypebotPageV2 publishedTypebot={publishedTypebot} {...props} />
|
||||
)
|
||||
}
|
||||
|
||||
export default App
|
||||
|
@ -1,71 +0,0 @@
|
||||
import { IncomingMessage } from 'http'
|
||||
import { GetServerSideProps, GetServerSidePropsContext } from 'next'
|
||||
import { env, getViewerUrl, isNotDefined } from 'utils'
|
||||
import prisma from '@/lib/prisma'
|
||||
import { TypebotPage, TypebotPageProps } from '@/components/TypebotPageV2'
|
||||
|
||||
export const getServerSideProps: GetServerSideProps = async (
|
||||
context: GetServerSidePropsContext
|
||||
) => {
|
||||
const { host, forwardedHost } = getHost(context.req)
|
||||
const pathname = context.resolvedUrl.split('?')[0]
|
||||
try {
|
||||
if (!host) return { props: {} }
|
||||
const viewerUrls = (getViewerUrl({ returnAll: true }) ?? '').split(',')
|
||||
const isMatchingViewerUrl =
|
||||
env('E2E_TEST') === 'true'
|
||||
? true
|
||||
: viewerUrls.some(
|
||||
(url) =>
|
||||
host.split(':')[0].includes(url.split('//')[1].split(':')[0]) ||
|
||||
(forwardedHost &&
|
||||
forwardedHost
|
||||
.split(':')[0]
|
||||
.includes(url.split('//')[1].split(':')[0]))
|
||||
)
|
||||
const typebot = isMatchingViewerUrl
|
||||
? await getTypebotFromPublicId(context.query.publicId?.toString())
|
||||
: null
|
||||
return {
|
||||
props: {
|
||||
typebot,
|
||||
url: `https://${forwardedHost ?? host}${pathname}`,
|
||||
},
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
return {
|
||||
props: {},
|
||||
url: `https://${forwardedHost ?? host}${pathname}`,
|
||||
}
|
||||
}
|
||||
|
||||
const getTypebotFromPublicId = async (
|
||||
publicId?: string
|
||||
): Promise<TypebotPageProps['typebot'] | null> => {
|
||||
const typebot = (await prisma.typebot.findUnique({
|
||||
where: { publicId: publicId ?? '' },
|
||||
select: {
|
||||
theme: true,
|
||||
name: true,
|
||||
settings: true,
|
||||
publicId: true,
|
||||
},
|
||||
})) as TypebotPageProps['typebot'] | null
|
||||
if (isNotDefined(typebot)) return null
|
||||
return typebot
|
||||
}
|
||||
|
||||
const getHost = (
|
||||
req?: IncomingMessage
|
||||
): { host?: string; forwardedHost?: string } => ({
|
||||
host: req?.headers ? req.headers.host : window.location.host,
|
||||
forwardedHost: req?.headers['x-forwarded-host'] as string | undefined,
|
||||
})
|
||||
|
||||
const App = ({ typebot, url }: TypebotPageProps) => (
|
||||
<TypebotPage typebot={typebot} url={url} />
|
||||
)
|
||||
|
||||
export default App
|
Reference in New Issue
Block a user