Skip to content

Commit b511a15

Browse files
committed
Retain screenshots on failure
1 parent ed84b5c commit b511a15

File tree

2 files changed

+91
-81
lines changed

2 files changed

+91
-81
lines changed

playwright.config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ export default defineConfig({
1313
reporter: process.env.CI ? "github" : "list",
1414
use: {
1515
baseURL: "http://localhost:3000",
16-
trace: "on-first-retry",
16+
trace: "retain-on-first-failure",
17+
screenshot: "only-on-failure",
1718
},
1819

1920
projects: [

test/e2e/community-events.spec.ts

Lines changed: 89 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -41,84 +41,93 @@ test("map loads and Zurich meetup link works", async ({ page }) => {
4141
expect(newPage.url()).toContain("meetup.com/graphql-zurich")
4242
})
4343

44-
test("map tooltip appears on marker hover", async ({ page }) => {
45-
await page.goto("/community/events")
46-
const mapCanvas = page.locator("canvas").first()
47-
await expect(mapCanvas).toBeVisible({ timeout: 10000 })
48-
await expect
49-
.poll(async () => {
50-
const box = await mapCanvas.boundingBox()
51-
return Boolean(box && box.width > 100 && box.height > 100)
44+
test(
45+
"map tooltip appears on marker hover",
46+
async ({ page }) => {
47+
await page.goto("/community/events")
48+
const mapCanvas = page.locator("canvas").first()
49+
await expect(mapCanvas).toBeVisible({ timeout: 10000 })
50+
await expect
51+
.poll(async () => {
52+
const box = await mapCanvas.boundingBox()
53+
return Boolean(box && box.width > 100 && box.height > 100)
54+
})
55+
.toBe(true)
56+
const tooltip = page.getByRole("tooltip")
57+
await expect(tooltip).toHaveCount(0)
58+
await mapCanvas.hover()
59+
const { clientX, clientY } = await page.evaluate(() => {
60+
const canvas = document.querySelector(
61+
"canvas",
62+
) as HTMLCanvasElement | null
63+
if (!canvas) throw new Error("Canvas not found")
64+
const targetLat = 51.51
65+
const targetLon = -0.12
66+
const aspectRatio = 1.65
67+
const cellSize = 8
68+
const mercatorLimit = 85.05112878
69+
const minDisplayedLatitude = -60
70+
const baseLatitudeOffset = 4
71+
const baseLongitudeOffset = 0.1
72+
const clamp01 = (value: number) => {
73+
if (value <= 0) return 0
74+
if (value >= 1) return 1
75+
return value
76+
}
77+
const normalizeLongitude = (value: number) => {
78+
let lon = value
79+
while (lon <= -180) lon += 360
80+
while (lon > 180) lon -= 360
81+
return lon
82+
}
83+
const latToRawV = (lat: number) => {
84+
const clampedLat = Math.max(
85+
-mercatorLimit,
86+
Math.min(mercatorLimit, lat),
87+
)
88+
const rad = (clampedLat * Math.PI) / 180
89+
return (
90+
0.5 - Math.log(Math.tan(Math.PI * 0.25 + rad * 0.5)) / (2 * Math.PI)
91+
)
92+
}
93+
const maxProjectedV = latToRawV(mercatorLimit)
94+
const minProjectedV = latToRawV(minDisplayedLatitude)
95+
const lonLatToUV = (lon: number, lat: number) => {
96+
const adjustedLon = normalizeLongitude(lon + baseLongitudeOffset)
97+
const u = (adjustedLon + 180) / 360
98+
const adjustedLat = Math.max(
99+
minDisplayedLatitude,
100+
Math.min(mercatorLimit, lat + baseLatitudeOffset),
101+
)
102+
const rawV = latToRawV(adjustedLat)
103+
const normalizedV = clamp01(
104+
(rawV - maxProjectedV) / (minProjectedV - maxProjectedV),
105+
)
106+
return [u, normalizedV] as const
107+
}
108+
const { width, height } = canvas
109+
const pixelRatio = window.devicePixelRatio || 1
110+
const worldHeight = Math.min(width / aspectRatio, height)
111+
const worldWidth = worldHeight * aspectRatio
112+
const panX = width * 0.5 - worldWidth * 0.5
113+
const panY = height * 0.5 - worldHeight * 0.5
114+
const [u, v] = lonLatToUV(targetLon, targetLat)
115+
const markerY = 1 - v
116+
const screenX = panX + u * worldWidth
117+
const screenY = panY + markerY * worldHeight
118+
const deviceCell = cellSize * pixelRatio
119+
const cellX = Math.floor(screenX / deviceCell)
120+
const cellY = Math.floor(screenY / deviceCell)
121+
const centerX = (cellX + 0.5) * deviceCell
122+
const centerY = (cellY + 0.5) * deviceCell
123+
const rect = canvas.getBoundingClientRect()
124+
const clientX = rect.left + centerX / pixelRatio
125+
const clientY = rect.bottom - centerY / pixelRatio
126+
return { clientX, clientY }
52127
})
53-
.toBe(true)
54-
const tooltip = page.getByRole("tooltip")
55-
await expect(tooltip).toHaveCount(0)
56-
await mapCanvas.hover()
57-
const { clientX, clientY } = await page.evaluate(() => {
58-
const canvas = document.querySelector("canvas") as HTMLCanvasElement | null
59-
if (!canvas) throw new Error("Canvas not found")
60-
const targetLat = 51.51
61-
const targetLon = -0.12
62-
const aspectRatio = 1.65
63-
const cellSize = 8
64-
const mercatorLimit = 85.05112878
65-
const minDisplayedLatitude = -60
66-
const baseLatitudeOffset = 4
67-
const baseLongitudeOffset = 0.1
68-
const clamp01 = (value: number) => {
69-
if (value <= 0) return 0
70-
if (value >= 1) return 1
71-
return value
72-
}
73-
const normalizeLongitude = (value: number) => {
74-
let lon = value
75-
while (lon <= -180) lon += 360
76-
while (lon > 180) lon -= 360
77-
return lon
78-
}
79-
const latToRawV = (lat: number) => {
80-
const clampedLat = Math.max(-mercatorLimit, Math.min(mercatorLimit, lat))
81-
const rad = (clampedLat * Math.PI) / 180
82-
return (
83-
0.5 - Math.log(Math.tan(Math.PI * 0.25 + rad * 0.5)) / (2 * Math.PI)
84-
)
85-
}
86-
const maxProjectedV = latToRawV(mercatorLimit)
87-
const minProjectedV = latToRawV(minDisplayedLatitude)
88-
const lonLatToUV = (lon: number, lat: number) => {
89-
const adjustedLon = normalizeLongitude(lon + baseLongitudeOffset)
90-
const u = (adjustedLon + 180) / 360
91-
const adjustedLat = Math.max(
92-
minDisplayedLatitude,
93-
Math.min(mercatorLimit, lat + baseLatitudeOffset),
94-
)
95-
const rawV = latToRawV(adjustedLat)
96-
const normalizedV = clamp01(
97-
(rawV - maxProjectedV) / (minProjectedV - maxProjectedV),
98-
)
99-
return [u, normalizedV] as const
100-
}
101-
const { width, height } = canvas
102-
const pixelRatio = window.devicePixelRatio || 1
103-
const worldHeight = Math.min(width / aspectRatio, height)
104-
const worldWidth = worldHeight * aspectRatio
105-
const panX = width * 0.5 - worldWidth * 0.5
106-
const panY = height * 0.5 - worldHeight * 0.5
107-
const [u, v] = lonLatToUV(targetLon, targetLat)
108-
const markerY = 1 - v
109-
const screenX = panX + u * worldWidth
110-
const screenY = panY + markerY * worldHeight
111-
const deviceCell = cellSize * pixelRatio
112-
const cellX = Math.floor(screenX / deviceCell)
113-
const cellY = Math.floor(screenY / deviceCell)
114-
const centerX = (cellX + 0.5) * deviceCell
115-
const centerY = (cellY + 0.5) * deviceCell
116-
const rect = canvas.getBoundingClientRect()
117-
const clientX = rect.left + centerX / pixelRatio
118-
const clientY = rect.bottom - centerY / pixelRatio
119-
return { clientX, clientY }
120-
})
121-
await page.mouse.move(clientX, clientY)
122-
await expect(tooltip).toHaveText("London GraphQL", { timeout: 5000 })
123-
await expect(tooltip).toBeVisible()
124-
})
128+
await page.mouse.move(clientX, clientY)
129+
await expect(tooltip).toHaveText("London GraphQL", { timeout: 5000 })
130+
await expect(tooltip).toBeVisible()
131+
},
132+
{ timeout: 60_000 },
133+
)

0 commit comments

Comments
 (0)