Skip to content

Commit cb42136

Browse files
committed
test: update bottom sheet
1 parent 1a0fc0e commit cb42136

File tree

2 files changed

+92
-61
lines changed

2 files changed

+92
-61
lines changed

e2e/bottom-sheet.e2e.ts

Lines changed: 55 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ import { BottomSheetModel } from "./models/bottom-sheet.model"
33

44
let I: BottomSheetModel
55

6-
const ANIMATION_DURATION = 500
7-
86
test.describe("bottom-sheet", () => {
97
test.beforeEach(async ({ page }) => {
108
I = new BottomSheetModel(page)
@@ -22,11 +20,13 @@ test.describe("bottom-sheet", () => {
2220
await I.seeBackdrop()
2321
})
2422

25-
test("should close when backdrop is clicked", async () => {
23+
test("should close when clicked outside", async () => {
2624
await I.clickTrigger()
2725
await I.seeContent()
26+
await I.waitForOpenState()
27+
28+
await I.clickOutsideSheet()
2829

29-
await I.clickBackdrop()
3030
await I.dontSeeContent()
3131
await I.dontSeeBackdrop()
3232
})
@@ -39,21 +39,19 @@ test.describe("bottom-sheet", () => {
3939
await I.seeTriggerIsFocused()
4040
})
4141

42-
test("should close when dragged down past swipeVelocityThreshold", async ({ page }) => {
42+
test("should close when dragged down past swipeVelocityThreshold", async () => {
4343
await I.clickTrigger()
4444
await I.seeContent()
45+
await I.waitForOpenState()
4546

46-
await page.waitForTimeout(ANIMATION_DURATION)
47-
48-
await I.dragGrabber("down", 100, 100)
47+
await I.dragGrabber("down", 200, 100)
4948
await I.dontSeeContent()
5049
})
5150

52-
test("should close when dragged down past closeThreshold", async ({ page }) => {
51+
test("should close when dragged down past closeThreshold", async () => {
5352
await I.clickTrigger()
5453
await I.seeContent()
55-
56-
await page.waitForTimeout(ANIMATION_DURATION)
54+
await I.waitForOpenState()
5755

5856
const initialHeight = await I.getContentVisibleHeight()
5957
const dragDistance = Math.floor(initialHeight * 0.3)
@@ -62,21 +60,19 @@ test.describe("bottom-sheet", () => {
6260
await I.dontSeeContent()
6361
})
6462

65-
test("should stay open when dragged down slightly", async ({ page }) => {
63+
test("should stay open when dragged down slightly", async () => {
6664
await I.clickTrigger()
6765
await I.seeContent()
68-
69-
await page.waitForTimeout(ANIMATION_DURATION)
66+
await I.waitForOpenState()
7067

7168
await I.dragGrabber("down", 100)
7269
await I.seeContent()
7370
})
7471

75-
test("should no effect when dragged up", async ({ page }) => {
72+
test("should no effect when dragged up", async () => {
7673
await I.clickTrigger()
7774
await I.seeContent()
78-
79-
await page.waitForTimeout(ANIMATION_DURATION)
75+
await I.waitForOpenState()
8076

8177
const initialHeight = await I.getContentVisibleHeight()
8278
await I.dragGrabber("up", 150)
@@ -102,12 +98,12 @@ test.describe("bottom-sheet", () => {
10298
test("should not allow dragging from no-drag area", async ({ page }) => {
10399
await I.clickTrigger()
104100
await I.seeContent()
105-
106-
await page.waitForTimeout(ANIMATION_DURATION)
101+
await I.waitForOpenState()
107102

108103
const initialHeight = await I.getContentVisibleHeight()
109104

110105
await I.dragNoDragArea("down", 100, 500, false)
106+
await I.waitForSnapComplete()
111107
const heightAfterNoDragAreaDrag = await I.getContentVisibleHeight()
112108

113109
expect(initialHeight - heightAfterNoDragAreaDrag).toBe(0)
@@ -126,11 +122,10 @@ test.describe("bottom-sheet [draggable=false]", () => {
126122
await I.goto("/bottom-sheet-draggable-false")
127123
})
128124

129-
test("sheet content should not be draggable", async ({ page }) => {
125+
test("sheet content should not be draggable", async () => {
130126
await I.clickTrigger()
131127
await I.seeContent()
132-
133-
await page.waitForTimeout(ANIMATION_DURATION)
128+
await I.waitForOpenState()
134129

135130
const initialHeight = await I.getContentVisibleHeight()
136131

@@ -150,33 +145,31 @@ test.describe("bottom-sheet [snapPoints]", () => {
150145
await I.goto("/bottom-sheet-snap-points")
151146
})
152147

153-
test("should snap to defined positions", async ({ page }) => {
148+
test("should snap to defined positions", async () => {
154149
await I.clickTrigger()
155150
await I.seeContent()
156-
157-
await page.waitForTimeout(ANIMATION_DURATION)
151+
await I.waitForOpenState()
158152

159153
const initialHeight = await I.getContentVisibleHeight()
160-
const middleHeight = initialHeight * 0.5
161154
const lowerHeight = initialHeight * 0.25
162155

163-
// Drag down to middle position (50%)
164-
await I.dragGrabber("down", initialHeight / 2)
165-
await page.waitForTimeout(ANIMATION_DURATION)
156+
// Drag down significantly to trigger snap to 250px fixed snap point
157+
await I.dragGrabber("down", 300)
158+
await I.waitForSnapComplete()
166159

167160
let currentHeight = await I.getContentVisibleHeight()
168161

169-
// Should snap to middle (50%)
170-
expect(currentHeight).toBe(middleHeight)
162+
// Should snap to 250px fixed snap point
163+
expect(currentHeight).toBe(250)
171164

172-
// Drag down more to snap to lower position (25%)
173-
await I.dragGrabber("down", currentHeight / 2)
174-
await page.waitForTimeout(ANIMATION_DURATION)
165+
// Drag down to snap to 25% position (drag less to avoid closing)
166+
await I.dragGrabber("down", 60)
167+
await I.waitForSnapComplete()
175168

176169
currentHeight = await I.getContentVisibleHeight()
177170

178-
// Should be at a lower snap point
179-
expect(currentHeight).toBe(lowerHeight)
171+
// Should be at 25% snap point (allow small rounding differences)
172+
expect(currentHeight).toBeCloseTo(lowerHeight, 0)
180173
})
181174
})
182175

@@ -186,44 +179,50 @@ test.describe("bottom-sheet [defaultActiveSnapPoint]", () => {
186179
await I.goto("/bottom-sheet-default-active-snap-point")
187180
})
188181

189-
test("should open at default snap point and drag to 50% and 100%", async ({ page }) => {
182+
test("should open at default snap point and drag to 250px and 100%", async () => {
190183
await I.clickTrigger()
191184
await I.seeContent()
185+
await I.waitForOpenState()
186+
187+
let currentHeight = await I.getContentVisibleHeight()
192188

193-
await page.waitForTimeout(ANIMATION_DURATION)
189+
// Calculate expected heights based on actual content height
190+
// First, drag to 100% to get the full height
191+
await I.dragGrabber("up", 600)
192+
await I.waitForSnapComplete()
194193

195-
const fullHeight = 500
196-
const middleHeight = fullHeight * 0.5
194+
const fullHeight = await I.getContentVisibleHeight()
197195
const lowerHeight = fullHeight * 0.25
198196

199-
let currentHeight = await I.getContentVisibleHeight()
197+
// Close and reopen to test default snap point
198+
await I.pressKey("Escape")
199+
await I.dontSeeContent()
200+
201+
await I.clickTrigger()
202+
await I.seeContent()
203+
await I.waitForOpenState()
204+
205+
currentHeight = await I.getContentVisibleHeight()
200206

201207
// Should open at default snap point (25%)
202-
expect(currentHeight).toBe(lowerHeight)
208+
expect(currentHeight).toBeCloseTo(lowerHeight, 0)
203209

204-
// Drag up to reach middle position (50%)
205-
await I.dragGrabber("up", 175)
206-
await page.waitForTimeout(ANIMATION_DURATION)
210+
// Drag up to reach 250px snap point
211+
await I.dragGrabber("up", 100)
212+
await I.waitForSnapComplete()
207213

208214
currentHeight = await I.getContentVisibleHeight()
209215

210-
// Should have snapped to middle position (50%)
211-
expect(currentHeight).toBe(middleHeight)
216+
// Should have snapped to 250px fixed snap point
217+
expect(currentHeight).toBe(250)
212218

213219
// Drag up more to reach full height (100%)
214-
await I.dragGrabber("up", 250)
215-
await page.waitForTimeout(ANIMATION_DURATION)
220+
await I.dragGrabber("up", 500)
221+
await I.waitForSnapComplete()
216222

217223
currentHeight = await I.getContentVisibleHeight()
218224

219225
// Should be at maximum height (100% snap point)
220226
expect(currentHeight).toBe(fullHeight)
221-
222-
// Try dragging up more - should not increase further as it's at max
223-
await I.dragGrabber("up", 100)
224-
await page.waitForTimeout(ANIMATION_DURATION)
225-
226-
currentHeight = await I.getContentVisibleHeight()
227-
expect(currentHeight).toBe(fullHeight)
228227
})
229228
})

e2e/models/bottom-sheet.model.ts

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ export class BottomSheetModel extends Model {
4040
return this.page.locator("[data-no-drag]")
4141
}
4242

43+
private get scrollable() {
44+
return this.page.locator(".scrollable")
45+
}
46+
4347
clickTrigger(opts: { delay?: number } = {}) {
4448
return this.trigger.click(opts)
4549
}
@@ -85,25 +89,53 @@ export class BottomSheetModel extends Model {
8589
}
8690

8791
async getContentVisibleHeight() {
92+
const isVisible = await this.content.isVisible()
93+
if (!isVisible) return 0
94+
8895
const initialHeight = await this.content.evaluate((el) => el.clientHeight)
8996

9097
const translateY = await this.content.evaluate((el) =>
9198
getComputedStyle(el).getPropertyValue("--bottom-sheet-translate"),
9299
)
93100

94-
return initialHeight - parseInt(translateY, 10)
101+
const parsedTranslateY = parseInt(translateY, 10)
102+
return initialHeight - (isNaN(parsedTranslateY) ? 0 : parsedTranslateY)
103+
}
104+
105+
async getContentFullHeight() {
106+
const isVisible = await this.content.isVisible()
107+
if (!isVisible) return 0
108+
109+
return this.content.evaluate((el) => el.clientHeight)
95110
}
96111

97112
scrollContent(distance: number) {
98-
const scrollable = this.page.locator(".scrollable")
99-
return scrollable.evaluate((el, dist) => {
113+
return this.scrollable.evaluate((el, dist) => {
100114
el.scrollTop += dist
101115
}, distance)
102116
}
103117

104118
async isScrollableAtTop() {
105-
const scrollable = this.page.locator(".scrollable")
106-
const scrollTop = await scrollable.evaluate((el) => el.scrollTop)
119+
const scrollTop = await this.scrollable.evaluate((el) => el.scrollTop)
107120
return scrollTop === 0
108121
}
122+
123+
clickOutsideSheet() {
124+
return this.page.locator("main").click({ position: { x: 5, y: 5 } })
125+
}
126+
127+
async waitForOpenState() {
128+
// Wait for element to be visible and animations to complete
129+
await expect(this.content).toBeVisible()
130+
await this.content.evaluate((el) => Promise.all(el.getAnimations().map((animation) => animation.finished)))
131+
}
132+
133+
waitForClosedState() {
134+
return expect(this.content).toHaveAttribute("data-state", "closed")
135+
}
136+
137+
async waitForSnapComplete() {
138+
// Wait for snap animation/transition to complete after drag
139+
await this.content.evaluate((el) => Promise.all([...el.getAnimations()].map((animation) => animation.finished)))
140+
}
109141
}

0 commit comments

Comments
 (0)