Some checks failed
Deploy analytics worker / Deploy analytics worker to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
i18n upload strings / Upload latest strings (push) Failing after 1s
Deploy bemo / Deploy bemo to ${{ (github.ref == 'refs/heads/bemo-production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
Deploy grafana resources / ${{ github.event_name == 'push' && 'Deploy grafana resources' || 'Validate grafana resources (dry run)' }} (push) Failing after 0s
End to end tests (dotcom) / Check for relevant changes (push) Failing after 0s
End to end tests (examples) / Check for relevant changes (push) Failing after 0s
End to end tests (mermaid readability) / Check for relevant changes (push) Failing after 1s
End to end tests (perf) / Check for relevant changes (push) Failing after 0s
Publish editor extensions / Publish editor extensions (push) Failing after 1s
Publish SDK packages / Remove the publish-packages label (push) Has been skipped
Checks / Tests & checks (push) Has been cancelled
Checks / Build all projects (push) Has been cancelled
Deploy templates / Deploy templates (push) Has been cancelled
End to end tests (dotcom) / End to end tests (dotcom) (push) Has been cancelled
End to end tests (mermaid readability) / End to end tests (mermaid readability) (push) Has been cancelled
End to end tests (perf) / End to end tests (perf) (push) Has been cancelled
Deploy .com / Deploy dotcom to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Has been cancelled
End to end tests (examples) / End to end tests (examples) (push) Has been cancelled
Publish SDK packages / Publish SDK packages (push) Has been cancelled
Publish SDK packages / Tell user released version (push) Has been cancelled
Publish SDK packages / Publishes code templates to separate repositories (push) Has been cancelled
Publish SDK packages / Deploys the template demos with the new SDK version (push) Has been cancelled
686 lines
22 KiB
TypeScript
686 lines
22 KiB
TypeScript
import { expect, type Locator, type Page } from '@playwright/test'
|
|
import { type Editor } from 'tldraw'
|
|
import test from '../fixtures/fixtures'
|
|
import { setupOrReset, sleep } from '../shared-e2e'
|
|
|
|
declare const editor: Editor
|
|
|
|
const PAGE_MENU_ITEM_HEIGHT = 36
|
|
// The list reserves a few pixels of breathing room below the last row; the
|
|
// auto-fit and minimum heights both include it, so the e2e expectations must too.
|
|
const LIST_BOTTOM_PADDING = 4
|
|
const MIN_PAGE_MENU_LIST_HEIGHT = PAGE_MENU_ITEM_HEIGHT + LIST_BOTTOM_PADDING
|
|
|
|
const isMobileProject = () => test.info().project.name.includes('Mobile')
|
|
|
|
async function expectPageItemToBeCurrent(pageItem: Locator, isCurrent: boolean) {
|
|
await expect(pageItem).toHaveAttribute('data-iscurrent', isCurrent ? 'true' : 'false')
|
|
}
|
|
|
|
async function getPageMenuListHeight(pageList: Locator) {
|
|
return await pageList.evaluate((elm) => elm.getBoundingClientRect().height)
|
|
}
|
|
|
|
async function expectPageMenuListHeight(pageList: Locator, expectedHeight: number, tolerance = 1) {
|
|
await expect
|
|
.poll(async () => getPageMenuListHeight(pageList))
|
|
.toBeGreaterThanOrEqual(expectedHeight - tolerance)
|
|
|
|
await expect
|
|
.poll(async () => getPageMenuListHeight(pageList))
|
|
.toBeLessThanOrEqual(expectedHeight + tolerance)
|
|
}
|
|
|
|
async function dragPageMenuResizeHandle(page: Page, deltaY: number) {
|
|
const resizeHandle = page.locator('.tlui-page-menu__resize-handle')
|
|
const box = await resizeHandle.boundingBox()
|
|
if (!box) throw new Error('Could not find page menu resize handle')
|
|
const x = box.x + box.width / 2
|
|
const y = box.y + box.height / 2
|
|
|
|
await page.mouse.move(x, y)
|
|
await page.mouse.down()
|
|
await page.mouse.move(x, y + deltaY, { steps: 4 })
|
|
await page.mouse.up()
|
|
}
|
|
|
|
async function createPagesForReordering(page: Page) {
|
|
await page.evaluate(() => {
|
|
editor.createPage({ name: 'Page 2' })
|
|
editor.createPage({ name: 'Page 3' })
|
|
})
|
|
}
|
|
|
|
async function useCoarsePointer(page: Page) {
|
|
await page.evaluate(() => {
|
|
window.dispatchEvent(new PointerEvent('pointerdown', { pointerType: 'touch' }))
|
|
editor.updateInstanceState({ isCoarsePointer: true })
|
|
})
|
|
await expect.poll(() => page.evaluate(() => editor.getInstanceState().isCoarsePointer)).toBe(true)
|
|
}
|
|
|
|
async function getPageNames(page: Page) {
|
|
return await page.evaluate(() => editor.getPages().map((p) => p.name))
|
|
}
|
|
|
|
test.describe('page menu', () => {
|
|
test.beforeEach(setupOrReset)
|
|
|
|
test.afterEach(async ({ page }) => {
|
|
// press escape a few times
|
|
await page.keyboard.press('Escape')
|
|
await page.keyboard.press('Escape')
|
|
await page.keyboard.press('Escape')
|
|
})
|
|
|
|
test('you can open and close the page menu', async ({ pageMenu }) => {
|
|
const { pagemenuButton, header } = pageMenu
|
|
await expect(header).toBeHidden()
|
|
await pagemenuButton.click()
|
|
await expect(header).toBeVisible()
|
|
await pagemenuButton.click()
|
|
await expect(header).toBeHidden()
|
|
})
|
|
|
|
test('The page list height fits its rows when opened, resized, and reset', async ({
|
|
page,
|
|
pageMenu,
|
|
}) => {
|
|
test.skip(isMobileProject(), 'Desktop page menu resize behavior')
|
|
|
|
await page.evaluate(() => {
|
|
window.localStorage.removeItem('tldraw_page_menu_list_height')
|
|
editor.createPage({ name: 'Page 2' })
|
|
editor.createPage({ name: 'Page 3' })
|
|
})
|
|
|
|
await pageMenu.pagemenuButton.click()
|
|
await expect(pageMenu.pageItems).toHaveCount(3)
|
|
|
|
const autoFitHeight = PAGE_MENU_ITEM_HEIGHT * 3 + LIST_BOTTOM_PADDING
|
|
await expectPageMenuListHeight(pageMenu.pageList, autoFitHeight)
|
|
|
|
await dragPageMenuResizeHandle(page, 120)
|
|
await expect
|
|
.poll(async () => getPageMenuListHeight(pageMenu.pageList))
|
|
.toBeGreaterThan(autoFitHeight)
|
|
|
|
await dragPageMenuResizeHandle(page, -300)
|
|
await expectPageMenuListHeight(pageMenu.pageList, MIN_PAGE_MENU_LIST_HEIGHT)
|
|
|
|
await dragPageMenuResizeHandle(page, 120)
|
|
await page.locator('.tlui-page-menu__resize-handle').dblclick()
|
|
await expectPageMenuListHeight(pageMenu.pageList, autoFitHeight)
|
|
})
|
|
|
|
test('You can change pages', async ({ page, pageMenu }) => {
|
|
const { pagemenuButton, pageItems } = pageMenu
|
|
|
|
await test.step('open page menu', async () => {
|
|
await pagemenuButton.click()
|
|
await expect(pageItems.first()).toBeVisible()
|
|
})
|
|
|
|
await test.step('create a second page', async () => {
|
|
const initialCount = await pageItems.count()
|
|
await pageMenu.createButton.click()
|
|
await sleep(100)
|
|
await expect(pageItems).toHaveCount(initialCount + 1)
|
|
await page.keyboard.press('Enter')
|
|
await page.keyboard.press('Escape') // close the menu
|
|
})
|
|
|
|
await test.step('switch between pages', async () => {
|
|
await pagemenuButton.click()
|
|
await expect(pageItems).toHaveCount(2)
|
|
|
|
const firstPage = pageItems.nth(0)
|
|
const secondPage = pageItems.nth(1)
|
|
|
|
// Wait for both pages to be visible
|
|
await expect(firstPage).toBeVisible()
|
|
await expect(secondPage).toBeVisible()
|
|
|
|
await expectPageItemToBeCurrent(firstPage, false)
|
|
await expectPageItemToBeCurrent(secondPage, true)
|
|
|
|
// Click on second page
|
|
await secondPage.locator('button').first().click()
|
|
await expectPageItemToBeCurrent(firstPage, false)
|
|
await expectPageItemToBeCurrent(secondPage, true)
|
|
|
|
// Click on first page
|
|
await firstPage.locator('button').first().click()
|
|
|
|
await expectPageItemToBeCurrent(firstPage, true)
|
|
await expectPageItemToBeCurrent(secondPage, false)
|
|
})
|
|
})
|
|
|
|
test('You can create a new page by pressing enter after opening the page menu', async ({
|
|
page,
|
|
pageMenu,
|
|
}) => {
|
|
const { pagemenuButton, pageItems, createButton } = pageMenu
|
|
|
|
await test.step('open page menu and get initial count', async () => {
|
|
await pagemenuButton.click()
|
|
await expect(pageItems.first()).toBeVisible()
|
|
})
|
|
|
|
await test.step('create new page using create button', async () => {
|
|
const initialCount = await pageItems.count()
|
|
await createButton.click()
|
|
await sleep(100)
|
|
await expect(pageItems).toHaveCount(initialCount + 1)
|
|
})
|
|
|
|
await test.step('confirm page creation with enter', async () => {
|
|
await page.keyboard.press('Enter')
|
|
})
|
|
})
|
|
|
|
test('On coarse pointers, canceling the new page prompt does not create a page', async ({
|
|
page,
|
|
pageMenu,
|
|
}) => {
|
|
test.skip(!isMobileProject(), 'Coarse-pointer page menu behavior')
|
|
|
|
const { pagemenuButton, createButton } = pageMenu
|
|
|
|
await pagemenuButton.click()
|
|
await useCoarsePointer(page)
|
|
expect(await getPageNames(page)).toEqual(['Page 1'])
|
|
|
|
page.once('dialog', async (dialog) => {
|
|
expect(dialog.type()).toBe('prompt')
|
|
await dialog.dismiss()
|
|
})
|
|
await createButton.tap()
|
|
|
|
expect(await getPageNames(page)).toEqual(['Page 1'])
|
|
})
|
|
|
|
test.describe('You can rename a page', () => {
|
|
test('You can rename a page by double clicking its name', async ({ page, pageMenu }) => {
|
|
const { pagemenuButton, pageItems } = pageMenu
|
|
|
|
await test.step('open page menu', async () => {
|
|
await pagemenuButton.click()
|
|
await expect(pageItems.first()).toBeVisible()
|
|
})
|
|
|
|
await test.step('double click to rename page', async () => {
|
|
const pageItem = await pageMenu.getPageItem(0)
|
|
await pageItem.getByRole('button').first().dblclick()
|
|
|
|
// Should be in edit mode - look for input field
|
|
await expect(pageItem.locator('input')).toBeVisible()
|
|
})
|
|
|
|
await test.step('enter new name', async () => {
|
|
const input = pageItems.first().locator('input')
|
|
await expect(input).toBeVisible()
|
|
|
|
// Clear the input field more reliably
|
|
await input.clear()
|
|
await input.fill('My New Page')
|
|
await page.keyboard.press('Enter')
|
|
})
|
|
|
|
await test.step('verify page was renamed', async () => {
|
|
// Wait for the input to disappear (edit mode ends)
|
|
await expect(pageItems.first().locator('input')).toBeHidden()
|
|
|
|
// Wait a bit more for the rename to process
|
|
await sleep(200)
|
|
|
|
const pageItem = await pageMenu.getPageItem(0)
|
|
await expect(pageItem).toContainText('My New Page')
|
|
})
|
|
})
|
|
|
|
test('You can press enter to confirm a rename without closing the menu', async ({
|
|
page,
|
|
pageMenu,
|
|
}) => {
|
|
const { pagemenuButton, pageItems, header } = pageMenu
|
|
|
|
await pagemenuButton.click()
|
|
await expect(pageItems.first()).toBeVisible()
|
|
|
|
// Double click to start editing
|
|
const pageItem = await pageMenu.getPageItem(0)
|
|
await pageItem.getByRole('button').first().dblclick()
|
|
|
|
// Wait for edit mode to activate
|
|
const input = pageItem.locator('input')
|
|
await expect(input).toBeVisible()
|
|
|
|
// Clear and type new name
|
|
await input.clear()
|
|
await input.fill('Renamed Page')
|
|
await page.keyboard.press('Enter')
|
|
|
|
// Wait for edit mode to end
|
|
await expect(input).toBeHidden()
|
|
|
|
// Menu should still be open
|
|
await expect(header).toBeVisible()
|
|
// Check that the page item now contains the new name
|
|
await expect(pageItem).toContainText('Renamed Page')
|
|
})
|
|
|
|
test('You can press enter after renaming a page to close the menu', async ({
|
|
page,
|
|
pageMenu,
|
|
}) => {
|
|
const { pagemenuButton, pageItems, header } = pageMenu
|
|
|
|
await pagemenuButton.click()
|
|
await expect(pageItems.first()).toBeVisible()
|
|
|
|
// Double click to start editing
|
|
const pageItem = await pageMenu.getPageItem(0)
|
|
await pageItem.getByRole('button').first().dblclick()
|
|
|
|
// Wait for edit mode and use robust input handling
|
|
const input = pageItem.locator('input')
|
|
await expect(input).toBeVisible()
|
|
|
|
await input.clear()
|
|
await input.fill('Another Renamed Page')
|
|
await page.keyboard.press('Enter')
|
|
await page.keyboard.press('Enter')
|
|
|
|
// Menu should be closed
|
|
await expect(header).toBeHidden()
|
|
})
|
|
|
|
test('You can press escape to cancel a page rename and restore the previous name', async ({
|
|
page,
|
|
pageMenu,
|
|
}) => {
|
|
const { pagemenuButton, pageItems } = pageMenu
|
|
|
|
await pagemenuButton.click()
|
|
await expect(pageItems.first()).toBeVisible()
|
|
|
|
// Get original page name
|
|
const pageItem = await pageMenu.getPageItem(0)
|
|
const originalName = await pageItem.getByRole('button').first().textContent()
|
|
|
|
// Double click to start editing
|
|
await pageItem.getByRole('button').first().dblclick()
|
|
|
|
// Wait for edit mode and use robust input handling
|
|
const input = pageItem.locator('input')
|
|
await expect(input).toBeVisible()
|
|
|
|
await input.clear()
|
|
await input.fill('Should Not Save')
|
|
await page.keyboard.press('Escape')
|
|
|
|
// Wait for edit mode to end
|
|
await expect(input).toBeHidden()
|
|
|
|
// Should have original name back
|
|
await expect(pageItem.getByRole('button').first()).toContainText(originalName || '')
|
|
})
|
|
|
|
test('When you create a new page, the new page is focused', async ({ page, pageMenu }) => {
|
|
const { pagemenuButton, pageItems } = pageMenu
|
|
|
|
await test.step('create a new page and verify it becomes active', async () => {
|
|
await pagemenuButton.click()
|
|
const initialCount = await pageItems.count()
|
|
|
|
// Create a new page
|
|
await pageMenu.createButton.click()
|
|
await sleep(100)
|
|
|
|
// To stop editing
|
|
await page.keyboard.press('Enter')
|
|
|
|
// Verify page count increased
|
|
await expect(pageItems).toHaveCount(initialCount + 1)
|
|
|
|
// The new page (last one) should be the active/focused page
|
|
const newPageItem = await pageMenu.getPageItem(initialCount)
|
|
await expectPageItemToBeCurrent(newPageItem, true)
|
|
|
|
// All other pages should not be active
|
|
for (let i = 0; i < initialCount; i++) {
|
|
const otherPageItem = await pageMenu.getPageItem(i)
|
|
await expectPageItemToBeCurrent(otherPageItem, false)
|
|
}
|
|
})
|
|
})
|
|
|
|
test('When you open the page menu, the current page is in view', async ({ page, pageMenu }) => {
|
|
const { pagemenuButton } = pageMenu
|
|
|
|
await test.step('create multiple pages', async () => {
|
|
await pagemenuButton.click()
|
|
// Create several pages to potentially cause scrolling
|
|
for (let i = 0; i < 5; i++) {
|
|
await pageMenu.createButton.click()
|
|
await sleep(100)
|
|
await page.keyboard.press('Enter')
|
|
}
|
|
await page.keyboard.press('Escape')
|
|
})
|
|
|
|
await test.step('navigate to first page and verify it is in view', async () => {
|
|
await pagemenuButton.click()
|
|
|
|
// Click on the first page to make it current
|
|
const firstPage = await pageMenu.getPageItem(0)
|
|
await firstPage.locator('button').first().click()
|
|
|
|
// Close and reopen menu
|
|
await page.keyboard.press('Escape')
|
|
await pagemenuButton.click()
|
|
|
|
// Verify the first page (current page) is visible in the page list
|
|
await expect(firstPage).toBeInViewport()
|
|
|
|
// Also verify it's marked as checked/active
|
|
await expectPageItemToBeCurrent(firstPage, true)
|
|
})
|
|
})
|
|
|
|
test('When you open the page menu, the current page is focused', async ({ page, pageMenu }) => {
|
|
const { pagemenuButton } = pageMenu
|
|
|
|
await test.step('create multiple pages', async () => {
|
|
await pagemenuButton.click()
|
|
// Create a few pages
|
|
await pageMenu.createButton.click()
|
|
await sleep(100)
|
|
await page.keyboard.press('Enter')
|
|
await pageMenu.createButton.click()
|
|
await sleep(100)
|
|
await page.keyboard.press('Enter')
|
|
await page.keyboard.press('Escape')
|
|
})
|
|
|
|
await test.step('switch to middle page and verify focus', async () => {
|
|
await pagemenuButton.click()
|
|
|
|
// Click on the middle page to make it current
|
|
const middlePage = await pageMenu.getPageItem(1)
|
|
await middlePage.locator('button').first().click()
|
|
|
|
// Close and reopen menu
|
|
await page.keyboard.press('Escape')
|
|
await pagemenuButton.click()
|
|
|
|
// Verify the middle page is marked as the current/focused page
|
|
await expectPageItemToBeCurrent(middlePage, true)
|
|
|
|
// Verify other pages are not focused
|
|
const firstPage = await pageMenu.getPageItem(0)
|
|
const lastPage = await pageMenu.getPageItem(2)
|
|
await expectPageItemToBeCurrent(firstPage, false)
|
|
await expectPageItemToBeCurrent(lastPage, false)
|
|
})
|
|
})
|
|
})
|
|
|
|
test.describe('You can drag and drop pages to reorder them', () => {
|
|
test('Pages can be reordered by dragging the row itself', async ({ page, pageMenu }) => {
|
|
test.skip(isMobileProject(), 'Mobile page rows can only be reordered from the drag handle')
|
|
|
|
const { pagemenuButton } = pageMenu
|
|
|
|
await test.step('create multiple pages for reordering', async () => {
|
|
await createPagesForReordering(page)
|
|
})
|
|
|
|
await test.step('drag page to new position by its row', async () => {
|
|
await pagemenuButton.click()
|
|
await expect(pageMenu.pageItems).toHaveCount(3)
|
|
const firstItem = await pageMenu.getPageItem(0)
|
|
const secondItem = await pageMenu.getPageItem(1)
|
|
const firstButton = firstItem.locator('.tlui-page-menu__item__button')
|
|
|
|
await firstButton.dragTo(secondItem)
|
|
await expect.poll(() => getPageNames(page)).toEqual(['Page 2', 'Page 1', 'Page 3'])
|
|
})
|
|
})
|
|
|
|
test('On coarse pointers, pages can only be reordered by dragging the handle', async ({
|
|
page,
|
|
pageMenu,
|
|
}) => {
|
|
test.skip(!isMobileProject(), 'Coarse-pointer page menu behavior')
|
|
|
|
const { pagemenuButton } = pageMenu
|
|
|
|
await test.step('create multiple pages for reordering', async () => {
|
|
await createPagesForReordering(page)
|
|
})
|
|
|
|
await test.step('dragging the row itself does not reorder pages', async () => {
|
|
await pagemenuButton.click()
|
|
await useCoarsePointer(page)
|
|
await expect(pageMenu.pageItems).toHaveCount(3)
|
|
const firstItem = await pageMenu.getPageItem(0)
|
|
const secondItem = await pageMenu.getPageItem(1)
|
|
|
|
await expect(firstItem.getByTestId('page-menu.item-drag-handle')).toBeVisible()
|
|
await firstItem.locator('.tlui-page-menu__item__button').dragTo(secondItem)
|
|
expect(await getPageNames(page)).toEqual(['Page 1', 'Page 2', 'Page 3'])
|
|
})
|
|
|
|
await test.step('dragging the handle reorders pages', async () => {
|
|
await useCoarsePointer(page)
|
|
const firstItem = await pageMenu.getPageItem(0)
|
|
const secondItem = await pageMenu.getPageItem(1)
|
|
|
|
await firstItem.getByTestId('page-menu.item-drag-handle').dragTo(secondItem)
|
|
await expect.poll(() => getPageNames(page)).toEqual(['Page 2', 'Page 1', 'Page 3'])
|
|
})
|
|
})
|
|
})
|
|
|
|
test.describe('You can delete a page', () => {
|
|
test('You can delete a page using the submenu', async ({ page, pageMenu }) => {
|
|
const { pagemenuButton, pageItems } = pageMenu
|
|
|
|
await test.step('create an extra page so we can delete one', async () => {
|
|
await pagemenuButton.click()
|
|
await pageMenu.createButton.click()
|
|
await sleep(100)
|
|
await page.keyboard.press('Enter') // confirm rename
|
|
await page.keyboard.press('Escape') // close the menu
|
|
})
|
|
|
|
await test.step('open page menu and verify we have multiple pages', async () => {
|
|
await pagemenuButton.click()
|
|
const initialCount = await pageItems.count()
|
|
expect(initialCount).toBeGreaterThan(1)
|
|
})
|
|
|
|
await test.step('access page submenu and delete', async () => {
|
|
const pageItem = await pageMenu.getPageItem(1)
|
|
const submenuButton = pageItem.getByTestId('page-menu.item-submenu')
|
|
await submenuButton.click()
|
|
|
|
// Click delete option
|
|
const deleteButton = page.getByRole('menuitem', { name: /delete/i })
|
|
await expect(deleteButton).toBeVisible()
|
|
await deleteButton.click()
|
|
|
|
// Verify page count decreased
|
|
await expect(pageItems).toHaveCount(1)
|
|
})
|
|
})
|
|
})
|
|
|
|
test.describe('You can use the page menu', () => {
|
|
test('Right clicking a page item opens its submenu without reordering pages', async ({
|
|
page,
|
|
pageMenu,
|
|
}) => {
|
|
test.skip(isMobileProject(), 'Mobile emulation does not simulate right-click')
|
|
|
|
await createPagesForReordering(page)
|
|
await pageMenu.pagemenuButton.click()
|
|
await expect(pageMenu.pageItems).toHaveCount(3)
|
|
|
|
const firstPageItem = await pageMenu.getPageItem(0)
|
|
await firstPageItem.locator('.tlui-page-menu__item__button').click({ button: 'right' })
|
|
|
|
await expect(page.getByRole('menuitem', { name: /duplicate/i })).toBeVisible()
|
|
await expect(firstPageItem).toHaveAttribute('data-dragging', 'false')
|
|
expect(await getPageNames(page)).toEqual(['Page 1', 'Page 2', 'Page 3'])
|
|
})
|
|
|
|
test('You can duplicate a page from the page menu', async ({ page, pageMenu }) => {
|
|
const { pagemenuButton, pageItems } = pageMenu
|
|
|
|
await test.step('open page menu and get initial count', async () => {
|
|
await pagemenuButton.click()
|
|
await expect(pageItems.first()).toBeVisible()
|
|
})
|
|
|
|
await test.step('duplicate the first page', async () => {
|
|
const initialCount = await pageItems.count()
|
|
const pageItem = await pageMenu.getPageItem(0)
|
|
|
|
// Click the submenu button (three dots)
|
|
const submenuButton = pageItem.getByTestId('page-menu.item-submenu')
|
|
await submenuButton.click()
|
|
|
|
// Click duplicate option
|
|
const duplicateButton = page.getByRole('menuitem', { name: /duplicate/i })
|
|
await expect(duplicateButton).toBeVisible()
|
|
await duplicateButton.click()
|
|
|
|
// Verify page count increased
|
|
await expect(pageItems).toHaveCount(initialCount + 1)
|
|
})
|
|
})
|
|
|
|
test('You can delete a page from the page menu', async ({ page, pageMenu }) => {
|
|
const { pagemenuButton, pageItems } = pageMenu
|
|
|
|
await test.step('create an extra page so we can delete one', async () => {
|
|
await pagemenuButton.click()
|
|
await pageMenu.createButton.click()
|
|
await sleep(100)
|
|
await page.keyboard.press('Enter')
|
|
await page.keyboard.press('Escape')
|
|
})
|
|
|
|
await test.step('delete a page using submenu', async () => {
|
|
await pagemenuButton.click()
|
|
const initialCount = await pageItems.count()
|
|
expect(initialCount).toBeGreaterThan(1)
|
|
|
|
const pageItem = await pageMenu.getPageItem(1)
|
|
|
|
// Click the submenu button
|
|
const submenuButton = pageItem.getByTestId('page-menu.item-submenu')
|
|
await submenuButton.click()
|
|
|
|
// Click delete option
|
|
const deleteButton = page.getByRole('menuitem', { name: /delete/i })
|
|
await expect(deleteButton).toBeVisible()
|
|
await deleteButton.click()
|
|
|
|
// Verify page count decreased
|
|
await expect(pageItems).toHaveCount(initialCount - 1)
|
|
})
|
|
})
|
|
|
|
test('You can move a page up from the page menu', async ({ page, pageMenu }) => {
|
|
const { pagemenuButton, pageItems } = pageMenu
|
|
|
|
await test.step('create multiple pages for reordering', async () => {
|
|
await pagemenuButton.click()
|
|
// Create two additional pages (will have default names)
|
|
await pageMenu.createButton.click()
|
|
await sleep(100)
|
|
await page.keyboard.press('Enter')
|
|
await pageMenu.createButton.click()
|
|
await sleep(100)
|
|
await page.keyboard.press('Enter')
|
|
await page.keyboard.press('Escape')
|
|
})
|
|
|
|
await test.step('move the last page up', async () => {
|
|
await pagemenuButton.click()
|
|
await expect(pageItems).toHaveCount(3)
|
|
|
|
// Get the last page (index 2) and move it up
|
|
const lastPageItem = await pageMenu.getPageItem(2)
|
|
|
|
// Click the submenu button
|
|
const submenuButton = lastPageItem.getByTestId('page-menu.item-submenu')
|
|
await submenuButton.click()
|
|
|
|
// Click move up option
|
|
const moveUpButton = page.getByRole('menuitem', { name: /move up/i })
|
|
await expect(moveUpButton).toBeVisible()
|
|
await moveUpButton.click()
|
|
|
|
// Wait a moment for the reorder to complete
|
|
await sleep(200)
|
|
|
|
// Close and reopen menu to get fresh state
|
|
await page.keyboard.press('Escape')
|
|
await pagemenuButton.click()
|
|
|
|
// Verify we still have 3 pages - the operation worked
|
|
await expect(pageItems).toHaveCount(3)
|
|
})
|
|
})
|
|
|
|
test('You can move a page down from the page menu', async ({ page, pageMenu }) => {
|
|
const { pagemenuButton, pageItems } = pageMenu
|
|
|
|
await test.step('create multiple pages for reordering', async () => {
|
|
await pagemenuButton.click()
|
|
// Create two additional pages (will have default names)
|
|
await pageMenu.createButton.click()
|
|
await sleep(100)
|
|
await page.keyboard.press('Enter')
|
|
await pageMenu.createButton.click()
|
|
await sleep(100)
|
|
await page.keyboard.press('Enter')
|
|
await page.keyboard.press('Escape')
|
|
})
|
|
|
|
await test.step('move the first page down', async () => {
|
|
await pagemenuButton.click()
|
|
await expect(pageItems).toHaveCount(3)
|
|
|
|
// Get the first page (index 0) and move it down
|
|
const firstPageItem = await pageMenu.getPageItem(0)
|
|
|
|
// Click the submenu button
|
|
const submenuButton = firstPageItem.getByTestId('page-menu.item-submenu')
|
|
await submenuButton.click()
|
|
|
|
// Click move down option
|
|
const moveDownButton = page.getByRole('menuitem', { name: /move down/i })
|
|
await expect(moveDownButton).toBeVisible()
|
|
await moveDownButton.click()
|
|
|
|
// Wait a moment for the reorder to complete
|
|
await sleep(200)
|
|
|
|
// Close and reopen menu to get fresh state
|
|
await page.keyboard.press('Escape')
|
|
await pagemenuButton.click()
|
|
|
|
// Verify we still have 3 pages - the operation worked
|
|
await expect(pageItems).toHaveCount(3)
|
|
})
|
|
})
|
|
})
|
|
})
|