-
Notifications
You must be signed in to change notification settings - Fork 39
feat: automated UI testing with Playwright #906
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
5f8b799
test(e2e): add Playwright setup and notebook load spec
vgeorge fbac778
Add Playwright e2e tests with DeckGL canvas interaction support
vgeorge dbfb855
test(e2e): refactor DeckGL helpers and fix optional unproject
vgeorge d4d151d
feat(globe): add GlobeWidget and workspace-based e2e; expose MapLibre…
vgeorge 2ecfc40
test: exclude Playwright e2e tests from vitest
vgeorge d715f73
Merge branch 'main' into feat/playwright-e2e-setup
vgeorge 6cc0130
fix(docs): correct mkdocstrings syntax and auto-generate projection t…
vgeorge cdf80b8
fix(docs): add models page to resolve ViewState cross-reference
vgeorge 837c628
fix(docs): restore map.md to main branch version to fix ViewState cro…
vgeorge 3667c59
revert: restore files to main branch versions
vgeorge 9029ff8
feat: add DeckGL ref exposure for Playwright tests
vgeorge 59f17c8
fix: formatting issues on fixture notebook
vgeorge b4316a4
fix: lint
vgeorge 8c490d2
Merge branch 'main' into feat/playwright-e2e-setup
vgeorge 6a53a1a
fix: add comment, update .gitignore
vgeorge f199458
fix: lint
vgeorge 6057d9c
Merge branch 'main' into feat/playwright-e2e-setup
kylebarron File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { defineConfig, devices } from '@playwright/test'; | ||
|
||
export default defineConfig({ | ||
testDir: './tests/e2e', | ||
testMatch: '**/*.spec.ts', | ||
fullyParallel: false, | ||
forbidOnly: !!process.env.CI, | ||
retries: process.env.CI ? 2 : 0, | ||
workers: 1, | ||
timeout: 60000, | ||
expect: { | ||
timeout: 30000, | ||
}, | ||
reporter: 'list', | ||
|
||
use: { | ||
baseURL: 'http://localhost:8889', | ||
trace: 'on-first-retry', | ||
screenshot: 'only-on-failure', | ||
navigationTimeout: 30000, | ||
browserName: 'chromium', | ||
}, | ||
|
||
projects: [ | ||
{ | ||
name: 'chromium', | ||
use: { ...devices['Desktop Chrome'] }, | ||
}, | ||
], | ||
|
||
webServer: { | ||
command: 'uv run --group dev jupyter lab --no-browser --port=8889 --notebook-dir=tests/e2e/fixtures --IdentityProvider.token=""', | ||
url: 'http://localhost:8889', | ||
reuseExistingServer: false, // Always restart for clean state | ||
timeout: 30000, | ||
}, | ||
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# End-to-End Tests | ||
|
||
Playwright tests for Lonboard widgets in JupyterLab. | ||
|
||
## Running Tests | ||
|
||
```bash | ||
npm run test:e2e # Run all tests | ||
npm run test:e2e:ui # Run with UI mode | ||
npm run jupyter:test # Start test JupyterLab manually (port 8889) | ||
``` | ||
|
||
## Architecture | ||
|
||
- Tests run on port 8889 (isolated from dev on 8888) | ||
- Fresh JupyterLab server per test run | ||
- Fixtures in `tests/e2e/fixtures/` | ||
|
||
## DeckGL Canvas Interactions | ||
|
||
Playwright mouse events don't trigger DeckGL handlers. Use helpers from `helpers/deckgl/`: | ||
|
||
```typescript | ||
import { deckPointerEvent } from "./helpers/deckgl"; | ||
|
||
// Use canvas-relative coordinates (pixels from canvas top-left corner) | ||
await deckPointerEvent(page, "click", 200, 300); | ||
await deckPointerEvent(page, "hover", 400, 500); | ||
``` | ||
|
||
The helpers automatically convert pixel coordinates to geographic coordinates and invoke DeckGL event handlers. See JSDoc comments in `helpers/deckgl/interactions.ts` for implementation details. | ||
|
||
Example: `bbox-select.spec.ts` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { test, expect, Page } from "@playwright/test"; | ||
import { deckPointerEvent } from "./helpers/deckgl"; | ||
import { | ||
openNotebookFresh, | ||
runFirstNCells, | ||
executeCellAndWaitForOutput, | ||
} from "./helpers/notebook"; | ||
import { validateBounds } from "./helpers/assertions"; | ||
|
||
/** | ||
* Draws a bounding box on the DeckGL canvas by clicking start and end positions. | ||
*/ | ||
async function drawBbox( | ||
page: Page, | ||
start: { x: number; y: number }, | ||
end: { x: number; y: number }, | ||
) { | ||
// Click to set bbox start position | ||
await deckPointerEvent(page, "click", start.x, start.y); | ||
await page.waitForTimeout(300); | ||
|
||
// Hover to preview bbox size | ||
await deckPointerEvent(page, "hover", end.x, end.y); | ||
await page.waitForTimeout(300); | ||
|
||
// Click to set bbox end position and complete drawing | ||
await deckPointerEvent(page, "click", end.x, end.y); | ||
await page.waitForTimeout(500); | ||
} | ||
|
||
test.describe("BBox selection", () => { | ||
test("draws bbox and syncs selected_bounds to Python", async ({ page }) => { | ||
const { notebookRoot } = await openNotebookFresh(page, "simple-map.ipynb", { | ||
workspaceId: `bbox-${Date.now()}`, | ||
}); | ||
await runFirstNCells(page, notebookRoot, 2); | ||
await page.waitForTimeout(2000); | ||
|
||
// Start bbox selection mode | ||
const bboxButton = page.getByRole("button", { name: "Select BBox" }); | ||
await expect(bboxButton).toBeVisible({ timeout: 10000 }); | ||
await bboxButton.click(); | ||
|
||
// Verify drawing mode is active | ||
const cancelButton = page.getByRole("button", { name: "Cancel drawing" }); | ||
await expect(cancelButton).toBeVisible({ timeout: 5000 }); | ||
|
||
// Draw bbox using canvas-relative coordinates (pixels from canvas top-left) | ||
await drawBbox(page, { x: 200, y: 200 }, { x: 400, y: 400 }); | ||
|
||
// Verify bbox was drawn | ||
const clearButton = page.getByRole("button", { | ||
name: "Clear bounding box", | ||
}); | ||
await expect(clearButton).toBeVisible({ timeout: 2000 }); | ||
|
||
// Execute cell to check selected bounds | ||
const output = await executeCellAndWaitForOutput(notebookRoot, 2); | ||
|
||
// Verify bounds are valid geographic coordinates | ||
const outputText = await output.textContent(); | ||
validateBounds(outputText); | ||
}); | ||
}); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.