feat(results): ✨ Brand new Results table
- Resizable columns - Hide / Show columns - Reorganize columns - Expand result
This commit is contained in:
@ -16,121 +16,172 @@ import { deleteButtonInConfirmDialog } from '../services/selectorUtils'
|
||||
|
||||
const typebotId = cuid()
|
||||
|
||||
test.describe('Results page', () => {
|
||||
test('Submission table header should be parsed correctly', async ({
|
||||
page,
|
||||
}) => {
|
||||
const typebotId = cuid()
|
||||
await importTypebotInDatabase(
|
||||
path.join(
|
||||
__dirname,
|
||||
'../fixtures/typebots/results/submissionHeader.json'
|
||||
),
|
||||
{
|
||||
id: typebotId,
|
||||
}
|
||||
)
|
||||
await page.goto(`/typebots/${typebotId}/results`)
|
||||
await expect(page.locator('text=Submitted at')).toBeVisible()
|
||||
await expect(page.locator('text=Welcome')).toBeVisible()
|
||||
await expect(page.locator('text=Email')).toBeVisible()
|
||||
await expect(page.locator('text=Name')).toBeVisible()
|
||||
await expect(page.locator('text=Services')).toBeVisible()
|
||||
await expect(page.locator('text=Additional information')).toBeVisible()
|
||||
await expect(page.locator('text=utm_source')).toBeVisible()
|
||||
await expect(page.locator('text=utm_userid')).toBeVisible()
|
||||
})
|
||||
test('Submission table header should be parsed correctly', async ({ page }) => {
|
||||
const typebotId = cuid()
|
||||
await importTypebotInDatabase(
|
||||
path.join(__dirname, '../fixtures/typebots/results/submissionHeader.json'),
|
||||
{
|
||||
id: typebotId,
|
||||
}
|
||||
)
|
||||
await page.goto(`/typebots/${typebotId}/results`)
|
||||
await expect(page.locator('text=Submitted at')).toBeVisible()
|
||||
await expect(page.locator('text=Welcome')).toBeVisible()
|
||||
await expect(page.locator('text=Email')).toBeVisible()
|
||||
await expect(page.locator('text=Name')).toBeVisible()
|
||||
await expect(page.locator('text=Services')).toBeVisible()
|
||||
await expect(page.locator('text=Additional information')).toBeVisible()
|
||||
await expect(page.locator('text=utm_source')).toBeVisible()
|
||||
await expect(page.locator('text=utm_userid')).toBeVisible()
|
||||
})
|
||||
|
||||
test('results should be deletable', async ({ page }) => {
|
||||
await createTypebots([
|
||||
{
|
||||
id: typebotId,
|
||||
...parseDefaultGroupWithBlock({
|
||||
type: InputBlockType.TEXT,
|
||||
options: defaultTextInputOptions,
|
||||
}),
|
||||
},
|
||||
])
|
||||
await createResults({ typebotId })
|
||||
await page.goto(`/typebots/${typebotId}/results`)
|
||||
await selectFirstResults(page)
|
||||
await page.click('button:has-text("Delete2")')
|
||||
await deleteButtonInConfirmDialog(page).click()
|
||||
await expect(page.locator('text=content199')).toBeHidden()
|
||||
await expect(page.locator('text=content198')).toBeHidden()
|
||||
await page.waitForTimeout(1000)
|
||||
await page.click('[data-testid="checkbox"] >> nth=0')
|
||||
await page.click('button:has-text("Delete198")')
|
||||
await deleteButtonInConfirmDialog(page).click()
|
||||
await page.waitForTimeout(1000)
|
||||
expect(await page.locator('tr').count()).toBe(1)
|
||||
})
|
||||
test('results should be deletable', async ({ page }) => {
|
||||
await createTypebots([
|
||||
{
|
||||
id: typebotId,
|
||||
...parseDefaultGroupWithBlock({
|
||||
type: InputBlockType.TEXT,
|
||||
options: defaultTextInputOptions,
|
||||
}),
|
||||
},
|
||||
])
|
||||
await createResults({ typebotId })
|
||||
await page.goto(`/typebots/${typebotId}/results`)
|
||||
await selectFirstResults(page)
|
||||
await page.click('text="Delete"')
|
||||
await deleteButtonInConfirmDialog(page).click()
|
||||
await expect(page.locator('text=content199')).toBeHidden()
|
||||
await expect(page.locator('text=content198')).toBeHidden()
|
||||
await page.waitForTimeout(1000)
|
||||
await page.click('[data-testid="checkbox"] >> nth=0')
|
||||
await page.click('text="Delete"')
|
||||
await deleteButtonInConfirmDialog(page).click()
|
||||
await page.waitForTimeout(1000)
|
||||
expect(await page.locator('tr').count()).toBe(1)
|
||||
await expect(page.locator('text="Delete"')).toBeHidden()
|
||||
})
|
||||
|
||||
test('submissions table should have infinite scroll', async ({ page }) => {
|
||||
const scrollToBottom = () =>
|
||||
page.evaluate(() => {
|
||||
const tableWrapper = document.querySelector('.table-wrapper')
|
||||
if (!tableWrapper) return
|
||||
tableWrapper.scrollTo(0, tableWrapper.scrollHeight)
|
||||
})
|
||||
|
||||
await createResults({ typebotId })
|
||||
await page.goto(`/typebots/${typebotId}/results`)
|
||||
await expect(page.locator('text=content199')).toBeVisible()
|
||||
|
||||
await expect(page.locator('text=content149')).toBeHidden()
|
||||
await scrollToBottom()
|
||||
await expect(page.locator('text=content149')).toBeVisible()
|
||||
|
||||
await expect(page.locator('text=content99')).toBeHidden()
|
||||
await scrollToBottom()
|
||||
await expect(page.locator('text=content99')).toBeVisible()
|
||||
|
||||
await expect(page.locator('text=content49')).toBeHidden()
|
||||
await scrollToBottom()
|
||||
await expect(page.locator('text=content49')).toBeVisible()
|
||||
await expect(page.locator('text=content0')).toBeVisible()
|
||||
})
|
||||
|
||||
test('should correctly export selection in CSV', async ({ page }) => {
|
||||
await page.goto(`/typebots/${typebotId}/results`)
|
||||
await selectFirstResults(page)
|
||||
const [download] = await Promise.all([
|
||||
page.waitForEvent('download'),
|
||||
page.locator('button:has-text("Export2")').click(),
|
||||
])
|
||||
const path = await download.path()
|
||||
expect(path).toBeDefined()
|
||||
const file = readFileSync(path as string).toString()
|
||||
const { data } = parse(file)
|
||||
validateExportSelection(data)
|
||||
|
||||
await page.click('[data-testid="checkbox"] >> nth=0')
|
||||
const [downloadAll] = await Promise.all([
|
||||
page.waitForEvent('download'),
|
||||
page.locator('button:has-text("Export200")').click(),
|
||||
])
|
||||
const pathAll = await downloadAll.path()
|
||||
expect(pathAll).toBeDefined()
|
||||
const fileAll = readFileSync(pathAll as string).toString()
|
||||
const { data: dataAll } = parse(fileAll)
|
||||
validateExportAll(dataAll)
|
||||
})
|
||||
|
||||
test.describe('Free user', async () => {
|
||||
test.use({
|
||||
storageState: path.join(__dirname, '../freeUser.json'),
|
||||
})
|
||||
test("Incomplete results shouldn't be displayed", async ({ page }) => {
|
||||
await prisma.typebot.update({
|
||||
where: { id: typebotId },
|
||||
data: { workspaceId: freeWorkspaceId },
|
||||
})
|
||||
await page.goto(`/typebots/${typebotId}/results`)
|
||||
await page.click('text=Unlock')
|
||||
await expect(page.locator('text=For solo creator')).toBeVisible()
|
||||
test('submissions table should have infinite scroll', async ({ page }) => {
|
||||
const scrollToBottom = () =>
|
||||
page.evaluate(() => {
|
||||
const tableWrapper = document.querySelector('.table-wrapper')
|
||||
if (!tableWrapper) return
|
||||
tableWrapper.scrollTo(0, tableWrapper.scrollHeight)
|
||||
})
|
||||
|
||||
await createResults({ typebotId })
|
||||
await page.goto(`/typebots/${typebotId}/results`)
|
||||
await expect(page.locator('text=content199')).toBeVisible()
|
||||
|
||||
await expect(page.locator('text=content149')).toBeHidden()
|
||||
await scrollToBottom()
|
||||
await expect(page.locator('text=content149')).toBeVisible()
|
||||
|
||||
await expect(page.locator('text=content99')).toBeHidden()
|
||||
await scrollToBottom()
|
||||
await expect(page.locator('text=content99')).toBeVisible()
|
||||
|
||||
await expect(page.locator('text=content49')).toBeHidden()
|
||||
await scrollToBottom()
|
||||
await expect(page.locator('text=content49')).toBeVisible()
|
||||
await expect(page.locator('text=content0')).toBeVisible()
|
||||
})
|
||||
|
||||
test('should correctly export selection in CSV', async ({ page }) => {
|
||||
await page.goto(`/typebots/${typebotId}/results`)
|
||||
await selectFirstResults(page)
|
||||
const [download] = await Promise.all([
|
||||
page.waitForEvent('download'),
|
||||
page.locator('text="Export"').click(),
|
||||
])
|
||||
const path = await download.path()
|
||||
expect(path).toBeDefined()
|
||||
const file = readFileSync(path as string).toString()
|
||||
const { data } = parse(file)
|
||||
validateExportSelection(data)
|
||||
|
||||
await page.click('[data-testid="checkbox"] >> nth=0')
|
||||
const [downloadAll] = await Promise.all([
|
||||
page.waitForEvent('download'),
|
||||
page.locator('text="Export"').click(),
|
||||
])
|
||||
const pathAll = await downloadAll.path()
|
||||
expect(pathAll).toBeDefined()
|
||||
const fileAll = readFileSync(pathAll as string).toString()
|
||||
const { data: dataAll } = parse(fileAll)
|
||||
validateExportAll(dataAll)
|
||||
})
|
||||
|
||||
test.describe('Free user', async () => {
|
||||
test.use({
|
||||
storageState: path.join(__dirname, '../freeUser.json'),
|
||||
})
|
||||
test("Incomplete results shouldn't be displayed", async ({ page }) => {
|
||||
await prisma.typebot.update({
|
||||
where: { id: typebotId },
|
||||
data: { workspaceId: freeWorkspaceId },
|
||||
})
|
||||
await page.goto(`/typebots/${typebotId}/results`)
|
||||
await page.click('text=Unlock')
|
||||
await expect(page.locator('text=For solo creator')).toBeVisible()
|
||||
})
|
||||
})
|
||||
|
||||
test('Can resize, hide and reorder columns', async ({ page }) => {
|
||||
const typebotId = cuid()
|
||||
await importTypebotInDatabase(
|
||||
path.join(__dirname, '../fixtures/typebots/results/submissionHeader.json'),
|
||||
{
|
||||
id: typebotId,
|
||||
}
|
||||
)
|
||||
await page.goto(`/typebots/${typebotId}/results`)
|
||||
|
||||
// Resize
|
||||
expect((await page.locator('th >> nth=4').boundingBox())?.width).toBe(200)
|
||||
await page.waitForTimeout(500)
|
||||
await page.dragAndDrop(
|
||||
'[data-testid="resize-handle"] >> nth=3',
|
||||
'[data-testid="resize-handle"] >> nth=3',
|
||||
{ targetPosition: { x: 150, y: 0 }, force: true }
|
||||
)
|
||||
await page.waitForTimeout(500)
|
||||
expect((await page.locator('th >> nth=4').boundingBox())?.width).toBe(345)
|
||||
|
||||
// Hide
|
||||
await expect(
|
||||
page.locator('[data-testid="Submitted at header"]')
|
||||
).toBeVisible()
|
||||
await expect(page.locator('[data-testid="Email header"]')).toBeVisible()
|
||||
await page.click('button >> text="Columns"')
|
||||
await page.click('[aria-label="Hide column"] >> nth=0')
|
||||
await page.click('[aria-label="Hide column"] >> nth=1')
|
||||
await expect(page.locator('[data-testid="Submitted at header"]')).toBeHidden()
|
||||
await expect(page.locator('[data-testid="Email header"]')).toBeHidden()
|
||||
|
||||
// Reorder
|
||||
await expect(page.locator('th >> nth=1')).toHaveText('Welcome')
|
||||
await expect(page.locator('th >> nth=2')).toHaveText('Name')
|
||||
await page.dragAndDrop(
|
||||
'[aria-label="Drag"] >> nth=0',
|
||||
'[aria-label="Drag"] >> nth=0',
|
||||
{ targetPosition: { x: 0, y: 80 }, force: true }
|
||||
)
|
||||
await expect(page.locator('th >> nth=1')).toHaveText('Name')
|
||||
await expect(page.locator('th >> nth=2')).toHaveText('Welcome')
|
||||
|
||||
// Preferences should be persisted
|
||||
const saveAndReload = async (page: Page) => {
|
||||
await page.click('text="Theme"')
|
||||
await page.waitForTimeout(2000)
|
||||
await page.goto(`/typebots/${typebotId}/results`)
|
||||
}
|
||||
await saveAndReload(page)
|
||||
expect((await page.locator('th >> nth=1').boundingBox())?.width).toBe(345)
|
||||
await expect(page.locator('[data-testid="Submitted at header"]')).toBeHidden()
|
||||
await expect(page.locator('[data-testid="Email header"]')).toBeHidden()
|
||||
await expect(page.locator('th >> nth=1')).toHaveText('Name')
|
||||
await expect(page.locator('th >> nth=2')).toHaveText('Welcome')
|
||||
})
|
||||
|
||||
const validateExportSelection = (data: unknown[]) => {
|
||||
|
Reference in New Issue
Block a user