import { describe, it, expect } from 'vitest' import { render, screen, fireEvent, waitFor } from '@testing-library/react' import { WysiwygBuilderPage } from '@/components/wysiwyg/WysiwygBuilderPage' function getXY(el: HTMLElement) { const style = el.getAttribute('style') || '' const m = { left: /left:\s*(\d+)px/, top: /top:\s*(\d+)px/ } const left = Number((style.match(m.left)?.[1]) || '0') const top = Number((style.match(m.top)?.[1]) || '0') return { left, top } } function getRotate(el: HTMLElement) { const style = el.getAttribute('style') || '' const m = /rotate\(([-\d.]+)deg\)/ const v = Number((style.match(m)?.[1]) || '0') return v } describe('WYSIWYG - group actions drag/resize/rotate with snapping', () => { it('drags two selected objects together with 8px snapping', async () => { render() // add two texts const addText = () => fireEvent.click(screen.getByRole('button', { name: /^Add Text$/i })) addText() addText() const objs = await screen.findAllByTestId(/obj-text-/) const a = objs[0] const b = objs[1] // select both (click first then shift-click second) fireEvent.mouseDown(a, { clientX: 60, clientY: 60 }) fireEvent.mouseUp(a) fireEvent.mouseDown(b, { clientX: 80, clientY: 80, shiftKey: true }) // wait until selection reflects two items await screen.findByText(/선택 2개/) const canvas = screen.getByTestId('wysiwyg-canvas') // drag second (selected) by ~13, expect snap to +16 fireEvent.mouseDown(b, { clientX: 120, clientY: 120 }) fireEvent.mouseMove(canvas, { clientX: 133, clientY: 133 }) fireEvent.mouseUp(canvas) await waitFor(() => { const xyA = getXY(a) const xyB = getXY(b) expect(xyA.left).toBe(76) expect(xyA.top).toBe(76) expect(xyB.left).toBe(76) expect(xyB.top).toBe(76) }) }) it('resizes group from east handle; both widths increase with snapping', async () => { render() const addText = () => fireEvent.click(screen.getByRole('button', { name: /^Add Text$/i })) addText() addText() const objs = await screen.findAllByTestId(/obj-text-/) const a = objs[0] const b = objs[1] // select both fireEvent.mouseDown(a, { clientX: 60, clientY: 60 }) fireEvent.mouseUp(a) fireEvent.mouseDown(b, { clientX: 80, clientY: 80, shiftKey: true }) // drag east handle of second by ~13 -> snap width +16 const idB = (b.getAttribute('data-testid') || '').replace('obj-', '') const handleE = await screen.findByTestId(`resize-handle-e-${idB}`) fireEvent.mouseDown(handleE, { clientX: 180, clientY: 80 }) const canvas = screen.getByTestId('wysiwyg-canvas') fireEvent.mouseMove(canvas, { clientX: 193, clientY: 80 }) fireEvent.mouseUp(canvas) // widths reflected in inline style const styleA = a.getAttribute('style') || '' const styleB = b.getAttribute('style') || '' const wA = Number((styleA.match(/width:\s*(\d+)px/)?.[1]) || '0') const wB = Number((styleB.match(/width:\s*(\d+)px/)?.[1]) || '0') expect(wA).toBeGreaterThanOrEqual(176) // initial 160 -> +16 expect(wB).toBeGreaterThanOrEqual(176) }) it('rotates group with 15deg snapping (no shift)', async () => { render() const addText = () => fireEvent.click(screen.getByRole('button', { name: /^Add Text$/i })) addText() addText() const objs = await screen.findAllByTestId(/obj-text-/) const a = objs[0] const b = objs[1] // select both fireEvent.mouseDown(a) fireEvent.mouseUp(a) fireEvent.mouseDown(b, { shiftKey: true }) fireEvent.mouseUp(b) const idB2 = (b.getAttribute('data-testid') || '').replace('obj-', '') const rotateHandle = await screen.findByTestId(`rotate-handle-${idB2}`) fireEvent.mouseDown(rotateHandle, { clientX: 100, clientY: 10 }) const canvas = screen.getByTestId('wysiwyg-canvas') fireEvent.mouseMove(canvas, { clientX: 130, clientY: 10 }) // +30 -> snap 30 (15 step) fireEvent.mouseUp(canvas) const rA = getRotate(a) const rB = getRotate(b) expect(rA).toBe(30) expect(rB).toBe(30) }) })