Skip to content

Commit 93b0458

Browse files
committed
tests: add playwright tests to verify control and stage behavior
1 parent 95e3146 commit 93b0458

File tree

1 file changed

+171
-0
lines changed

1 file changed

+171
-0
lines changed
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
// @ts-check
2+
import { expect, test } from '@playwright/test'
3+
4+
test.describe('Drag Control to Stage', () => {
5+
test.beforeEach(async ({ page }) => {
6+
await page.goto('/')
7+
// Wait for the editor to load
8+
await expect(page.locator('.formeo-editor')).toBeVisible()
9+
// Wait for controls to be fully initialized
10+
await page.waitForTimeout(500)
11+
})
12+
13+
test('should add a control to stage via click', async ({ page }) => {
14+
// Get the control button
15+
const textInputControl = page.getByRole('button', { name: 'Text Input' })
16+
17+
await expect(textInputControl).toBeVisible()
18+
19+
// Count fields before click
20+
const fieldsBefore = await page.locator('.formeo-field').count()
21+
22+
// Click to add (alternative to drag)
23+
await textInputControl.click()
24+
25+
// Wait for the field to be added
26+
await page.waitForTimeout(300)
27+
28+
// Verify a field was added to the stage
29+
const fieldsAfter = await page.locator('.formeo-field').count()
30+
expect(fieldsAfter).toBeGreaterThan(fieldsBefore)
31+
})
32+
33+
test('should keep control in sidebar after adding to stage', async ({ page }) => {
34+
// Get the control button
35+
const textInputControl = page.getByRole('button', { name: 'Text Input' })
36+
37+
await expect(textInputControl).toBeVisible()
38+
39+
// Add control to stage
40+
await textInputControl.click()
41+
42+
// Wait for animation to complete
43+
await page.waitForTimeout(300)
44+
45+
// Verify the control is still in the sidebar
46+
await expect(textInputControl).toBeVisible()
47+
await expect(textInputControl).toBeEnabled()
48+
})
49+
50+
test('should not cause layout shift when dragging control', async ({ page }) => {
51+
// Get the control groups container
52+
const controlGroups = page.locator('.control-groups')
53+
const textInputControl = page.getByRole('button', { name: 'Text Input' })
54+
const stage = page.locator('.formeo-stage')
55+
56+
await expect(controlGroups).toBeVisible()
57+
await expect(stage).toBeVisible()
58+
59+
// Get initial bounding box of control groups
60+
const initialBounds = await controlGroups.boundingBox()
61+
62+
// Start dragging
63+
await textInputControl.hover()
64+
await page.mouse.down()
65+
66+
// Move towards stage
67+
const stageBounds = await stage.boundingBox()
68+
if (stageBounds && initialBounds) {
69+
await page.mouse.move(stageBounds.x + stageBounds.width / 2, stageBounds.y + stageBounds.height / 2)
70+
71+
// Check that control groups didn't shift significantly during drag
72+
const duringDragBounds = await controlGroups.boundingBox()
73+
if (duringDragBounds) {
74+
// Allow small tolerance for any animation
75+
expect(Math.abs(duringDragBounds.width - initialBounds.width)).toBeLessThan(5)
76+
expect(Math.abs(duringDragBounds.height - initialBounds.height)).toBeLessThan(50)
77+
}
78+
}
79+
80+
// Complete the drop
81+
await page.mouse.up()
82+
83+
// Wait for animation to complete
84+
await page.waitForTimeout(300)
85+
86+
// Verify final bounds are similar to initial
87+
const finalBounds = await controlGroups.boundingBox()
88+
if (finalBounds && initialBounds) {
89+
expect(Math.abs(finalBounds.width - initialBounds.width)).toBeLessThan(5)
90+
}
91+
})
92+
93+
test('should be able to add multiple controls to stage', async ({ page }) => {
94+
// Add multiple different controls via click
95+
const controls = ['Text Input', 'Email', 'Number']
96+
97+
for (const controlName of controls) {
98+
const control = page.getByRole('button', { name: controlName })
99+
await expect(control).toBeVisible()
100+
await control.click()
101+
await page.waitForTimeout(200)
102+
}
103+
104+
// Verify all fields were added
105+
const fields = await page.locator('.formeo-field').count()
106+
expect(fields).toBeGreaterThanOrEqual(controls.length)
107+
})
108+
109+
test('should maintain control functionality after multiple uses', async ({ page }) => {
110+
const textInputControl = page.getByRole('button', { name: 'Text Input' })
111+
112+
// Add first time
113+
await textInputControl.click()
114+
await page.waitForTimeout(300)
115+
116+
const fieldsAfterFirst = await page.locator('.formeo-field').count()
117+
118+
// Add second time - control should still work
119+
await textInputControl.click()
120+
await page.waitForTimeout(300)
121+
122+
const fieldsAfterSecond = await page.locator('.formeo-field').count()
123+
124+
// Should have added another field
125+
expect(fieldsAfterSecond).toBeGreaterThan(fieldsAfterFirst)
126+
})
127+
128+
test('should set overflow hidden during drag to prevent scrollbar flash', async ({ page }) => {
129+
// This test verifies the fix for scrollbar flashing
130+
const textInputControl = page.getByRole('button', { name: 'Text Input' })
131+
const stage = page.locator('.formeo-stage')
132+
133+
await expect(textInputControl).toBeVisible()
134+
await expect(stage).toBeVisible()
135+
136+
// Get stage bounds for drag target
137+
const stageBounds = await stage.boundingBox()
138+
139+
// Start dragging with manual mouse actions
140+
const controlBounds = await textInputControl.boundingBox()
141+
if (controlBounds && stageBounds) {
142+
// Move to control center and start drag
143+
await page.mouse.move(controlBounds.x + controlBounds.width / 2, controlBounds.y + controlBounds.height / 2)
144+
await page.mouse.down()
145+
146+
// Move slightly to trigger the drag
147+
await page.mouse.move(
148+
controlBounds.x + controlBounds.width / 2 + 10,
149+
controlBounds.y + controlBounds.height / 2 + 10
150+
)
151+
152+
// Wait a moment for onStart to fire
153+
await page.waitForTimeout(100)
154+
155+
// Check that overflow is set to hidden during drag
156+
const overflowDuringDrag = await page.evaluate(() => document.documentElement.style.overflow)
157+
expect(overflowDuringDrag).toBe('hidden')
158+
159+
// Complete the drag to stage
160+
await page.mouse.move(stageBounds.x + stageBounds.width / 2, stageBounds.y + stageBounds.height / 2)
161+
await page.mouse.up()
162+
163+
// Wait for drag to complete
164+
await page.waitForTimeout(300)
165+
166+
// Overflow should be restored after drag
167+
const overflowAfterDrag = await page.evaluate(() => document.documentElement.style.overflow)
168+
expect(overflowAfterDrag).not.toBe('hidden')
169+
}
170+
})
171+
})

0 commit comments

Comments
 (0)