Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/renderer/CameraController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,12 +274,12 @@ export class CameraController {

// Vertical bounds
if (this.#isFixedHeight && this.isScrollable()) {
// Fixed height mode with scrollable content
// Fixed height mode with scrollable content - allow vertical panning within bounds
const maxY = 0; // Top of content at top of viewport
const minY = this.#viewportHeight - this.#contentHeight; // Bottom of content at bottom of viewport
boundedY = Math.max(minY, Math.min(maxY, desiredY))
} else if (!this.#isFixedHeight) {
// Auto-height mode: no vertical panning
} else {
// Auto-height mode OR fixed height but not scrollable - no vertical panning
boundedY = 0
}

Expand Down
66 changes: 66 additions & 0 deletions tests/edge-cases.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,72 @@ test.describe('FlameGraph Edge Cases Tests', () => {
utils = new FlameGraphTestUtils(page)
})

test('top frames remain visible after dragging in fixed height mode', async ({ page }) => {
// This tests the fix for the bug where camera.y could become negative
// when in fixed height mode but content fits in viewport (not scrollable),
// causing top flamegraph bars to disappear.
await utils.navigateToTest()

const canvas = await utils.getCanvasElement()
const box = await canvas.boundingBox()
expect(box).not.toBeNull()

// Take a screenshot before dragging to capture the initial state
await expect(page).toHaveScreenshot('before-drag-fixed-height.png')

// Perform a drag operation that would push content up (drag downward)
// In the buggy version, this would set camera.y to a negative value
const startX = box!.x + box!.width / 2
const startY = box!.y + box!.height / 2
const endY = box!.y + box!.height - 50 // Drag down significantly

await page.mouse.move(startX, startY)
await page.mouse.down()
await page.mouse.move(startX, endY, { steps: 10 })
await page.mouse.up()

await page.waitForTimeout(500)

// Take a screenshot after dragging - top frames should still be visible
// The fix ensures camera.y stays at 0 when content fits in viewport
await expect(page).toHaveScreenshot('after-drag-fixed-height.png')

// Verify the canvas is still fully visible and functional
await expect(canvas).toBeVisible()

// Click on the root frame area to verify it's still interactive
await utils.clickFrame(COMMON_POSITIONS.ROOT_FRAME.x, COMMON_POSITIONS.ROOT_FRAME.y)
await page.waitForTimeout(500)

// The flamegraph should still be functional
await expect(canvas).toBeVisible()
})

test('top frames remain visible after fullscreen resize', async ({ page }) => {
// Test that going fullscreen doesn't cause top frames to disappear
await utils.navigateToTest()

const canvas = await utils.getCanvasElement()

// Initial state
await expect(canvas).toBeVisible()
await expect(page).toHaveScreenshot('before-fullscreen.png')

// Simulate fullscreen by changing to a larger viewport
await page.setViewportSize({ width: 1920, height: 1080 })
await page.waitForTimeout(1000)

// Top frames should still be visible at the top of the canvas
await expect(canvas).toBeVisible()
await expect(page).toHaveScreenshot('after-fullscreen.png')

// Verify the root frame is still clickable at the top
await utils.clickFrame(COMMON_POSITIONS.ROOT_FRAME.x, COMMON_POSITIONS.ROOT_FRAME.y)
await page.waitForTimeout(500)

await expect(canvas).toBeVisible()
})

test('handles extreme zoom levels', async ({ page }) => {
await utils.navigateToTest()

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading