analytics / e2e /tests /dashboard /annotations.spec.ts
Leon4gr45's picture
Upload folder using huggingface_hub (part 2)
936b397 verified
Raw
History Blame Contribute Delete
8.54 kB
import { test, expect } from '@playwright/test'
import { setupSite, populateStats, register } from '../fixtures'
import { randomID } from '../test-utils'
test.use({ locale: 'en-GB' })
test('user can create annotations across granularities, edit, and delete them', async ({
page,
request
}) => {
const user = {
email: `site-owner-for-annotations-${randomID()}@example.com`,
// name matters in this test
name: 'J R.R. Smith',
password: 'VeryStrongVerySecret'
}
await register({
page,
request,
user
})
const { domain } = await setupSite({ page, request, user })
await populateStats({
request,
domain,
events: [
{
user_id: 0,
name: 'pageview',
pathname: '/',
timestamp: '2026-04-01 00:00:00'
},
{
user_id: 1,
name: 'pageview',
pathname: '/',
timestamp: '2026-06-29 05:00:00'
},
{
user_id: 2,
name: 'pageview',
pathname: '/',
timestamp: '2026-06-29 10:00:00'
}
]
})
await page.goto(`/${domain}?period=7d&date=2026-07-06&comparison=off`, {
waitUntil: 'commit'
})
const mondayIn7d = page.getByTestId('graph-dot-series-1-bucket-0')
const mondayMarker7d = page.getByTestId('annotation-marker-on-bucket-0')
const tooltip = page.getByTestId('graph-tooltip')
// inputs in create / edit modals
const noteField = page.getByRole('textbox', { name: 'Note' })
const saveButton = page.getByRole('button', { name: 'Save' })
const siteNoteText = 'Company-wide: launch day'
const personalNoteText = 'Feature available for 50% of customers'
const updatedNoteText = 'Feature fully released (correction)'
const personalNoteAttribution = 'Personal note • 29 Jun 10:00'
const siteNoteAttribution = `${user.name} • 29 Jun`
// Asserts the tooltip's annotation list matches provided list exactly
const expectTooltipAnnotations = async (
expected: Array<{ note: string; attribution: string }>
) => {
const rows = tooltip.locator('div.group')
await expect(rows).toHaveCount(expected.length)
for (const [i, { note, attribution }] of expected.entries()) {
const row = rows.nth(i)
await expect(row).toContainText(note)
await expect(row.getByText(attribution, { exact: true })).toBeVisible()
}
}
// Needed because the tests expect a particular graph interval
const setGraphInterval = async (label: 'Hours' | 'Days' | 'Months') => {
await page.getByTestId('dashboard-options-menu').click()
await page.getByRole('button', { name: label, exact: true }).click()
await page.keyboard.press('Escape')
}
await test.step('in 7d view, create date-granularity site annotation on Monday', async () => {
await setGraphInterval('Days')
// hovered tooltip
await mondayIn7d.hover()
await expect(tooltip).toBeVisible()
await expectTooltipAnnotations([])
await expect(tooltip).toContainText('Click to view day')
await expect(tooltip).toContainText('Right click for more actions')
// persisted tooltip
await mondayIn7d.click({ button: 'right' })
await expect(tooltip).toBeVisible()
await expect(tooltip.locator('button')).toContainText([
'Add note',
'View day'
])
await tooltip.getByRole('button', { name: 'Add note' }).click()
const createModalHeading = page.getByRole('heading', {
name: 'Add note for Mon, 29 Jun',
exact: true
})
await expect(createModalHeading).toBeVisible()
await noteField.fill(siteNoteText)
await page.getByRole('radio', { name: /Site note/ }).check()
await saveButton.click()
await expect(createModalHeading).toBeHidden()
await expect(mondayMarker7d).toBeVisible()
})
await test.step('right-click Monday and zoom in via "View day"', async () => {
await mondayIn7d.hover()
await expectTooltipAnnotations([
{ note: siteNoteText, attribution: siteNoteAttribution }
])
await mondayIn7d.click({ button: 'right' })
await tooltip.getByRole('button', { name: 'View day' }).click()
await expect(page).toHaveURL(/period=day&date=2026-06-29/)
// Date-granularity annotations don't map to hour buckets — no marker in day view.
await expect(page.getByTestId(/^annotation-marker-on-bucket-/)).toHaveCount(
0
)
})
await test.step('in day view, create minute-granularity personal annotation at 10:00', async () => {
await setGraphInterval('Hours')
const hour10InDay = page.getByTestId('graph-dot-series-1-bucket-10')
await hour10InDay.hover()
await hour10InDay.click({ button: 'right' })
await expect(tooltip).toBeVisible()
await tooltip.getByRole('button', { name: 'Add note' }).click()
const createModalHeading = page.getByRole('heading', {
name: 'Add note for Mon, 29 Jun at 10:00',
exact: true
})
await expect(createModalHeading).toBeVisible()
await expect(tooltip).toBeHidden()
await noteField.fill(personalNoteText)
await saveButton.click()
await expect(createModalHeading).toBeHidden()
await expect(
page.getByTestId('annotation-marker-on-bucket-10')
).toBeVisible()
})
await test.step('zoom back out to 7d, both annotations are visible on Monday', async () => {
await page.goBack({ waitUntil: 'commit' })
await setGraphInterval('Days')
await expect(mondayMarker7d).toBeVisible()
const expectedOnMonday = [
{ note: siteNoteText, attribution: siteNoteAttribution },
{ note: personalNoteText, attribution: personalNoteAttribution }
]
await mondayIn7d.hover()
await expect(tooltip).toBeVisible()
await expectTooltipAnnotations(expectedOnMonday)
await mondayIn7d.click({ button: 'right' })
await expect(tooltip).toBeVisible()
await expectTooltipAnnotations(expectedOnMonday)
})
await test.step('edit personal annotation', async () => {
const personalRow = tooltip.locator('div.group', {
hasText: personalNoteText
})
await personalRow.hover()
await personalRow.getByRole('button', { name: 'Edit note' }).click()
const updateModalHeading = page.getByRole('heading', {
name: 'Update note for Mon, 29 Jun at 10:00',
exact: true
})
await expect(updateModalHeading).toBeVisible()
await expect(tooltip).toBeHidden()
await expect(noteField).toHaveValue(personalNoteText)
await noteField.fill(updatedNoteText)
await saveButton.click()
await expect(updateModalHeading).toBeHidden()
await mondayIn7d.hover()
await mondayIn7d.click({ button: 'right' })
await expectTooltipAnnotations([
{ note: siteNoteText, attribution: siteNoteAttribution },
{ note: updatedNoteText, attribution: personalNoteAttribution }
])
})
await test.step('delete personal annotation', async () => {
const personalNote = tooltip.locator('div.group', {
hasText: updatedNoteText
})
await personalNote.hover()
await personalNote.getByRole('button', { name: 'Edit note' }).click()
const updateModalHeading = page.getByRole('heading', {
name: 'Update note for Mon, 29 Jun at 10:00',
exact: true
})
await expect(updateModalHeading).toBeVisible()
await page.getByRole('button', { name: 'Delete note' }).click()
const deleteModalHeading = page.getByRole('heading', {
name: `Delete personal note "${updatedNoteText}"?`,
exact: true
})
await expect(deleteModalHeading).toBeVisible()
await expect(updateModalHeading).toBeHidden()
await page.getByRole('button', { name: 'Delete', exact: true }).click()
await expect(deleteModalHeading).toBeHidden()
await mondayIn7d.hover()
await expectTooltipAnnotations([
{ note: siteNoteText, attribution: siteNoteAttribution }
])
await expect(mondayMarker7d).toBeVisible()
})
await test.step('date annotations are shown for All period', async () => {
await page.getByTestId('current-query-period').click()
await page
.getByTestId('query-period-picker')
.getByRole('link', { name: 'All time' })
.click()
await expect(page).toHaveURL(/period=all/)
const marker = page.getByTestId(/^annotation-marker-on-bucket-/)
await expect(marker).toHaveCount(1)
await expect(marker).toBeVisible()
await setGraphInterval('Months')
await page.getByText('June 2026', { exact: true }).hover()
await expectTooltipAnnotations([
{ note: siteNoteText, attribution: siteNoteAttribution }
])
})
})