diff --git a/tests/apps/Makefile.wasm b/tests/apps/Makefile.wasm index f3e7c41..f9b319a 100644 --- a/tests/apps/Makefile.wasm +++ b/tests/apps/Makefile.wasm @@ -96,6 +96,11 @@ LDFLAGS_PTHREAD = $(DEBUG_LDFLAGS) $(BASE_LDFLAGS) -pthread \ JS = $(TOOLS_ROOT)/wx.js HTML = $(TOOLS_ROOT)/template.html +# wxWidgets library directory - used as dependency to rebuild when libs change +WX_LIB_DIR = ../../build-wasm/wxwidgets-universal/lib +# Key library that changes when wxWidgets is rebuilt +WX_CORE_LIB = $(WX_LIB_DIR)/libwx_wasmunivu_core-3.2-emscripten.a + # Standalone directories S = standalone @@ -147,301 +152,301 @@ all: minimal_test.html \ minimal_test.o: minimal_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -minimal_test.html: minimal_test.o +minimal_test.html: minimal_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_GL) --pre-js $(JS) --shell-file $(HTML) -o $@ # Menu test (no GL) $(S)/menu/menu_test.o: $(S)/menu/menu_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/menu/menu_test.html: $(S)/menu/menu_test.o +$(S)/menu/menu_test.html: $(S)/menu/menu_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # Clipboard test (no GL) $(S)/clipboard/clipboard_test.o: $(S)/clipboard/clipboard_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/clipboard/clipboard_test.html: $(S)/clipboard/clipboard_test.o +$(S)/clipboard/clipboard_test.html: $(S)/clipboard/clipboard_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # FileDialog test (no GL) $(S)/filedialog/filedialog_test.o: $(S)/filedialog/filedialog_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/filedialog/filedialog_test.html: $(S)/filedialog/filedialog_test.o +$(S)/filedialog/filedialog_test.html: $(S)/filedialog/filedialog_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # Layout test (no GL) $(S)/layout/layout_test.o: $(S)/layout/layout_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/layout/layout_test.html: $(S)/layout/layout_test.o +$(S)/layout/layout_test.html: $(S)/layout/layout_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # AUI test (no GL) $(S)/aui/aui_test.o: $(S)/aui/aui_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/aui/aui_test.html: $(S)/aui/aui_test.o +$(S)/aui/aui_test.html: $(S)/aui/aui_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # Toolbar test (no GL) $(S)/toolbar/toolbar_test.o: $(S)/toolbar/toolbar_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/toolbar/toolbar_test.html: $(S)/toolbar/toolbar_test.o +$(S)/toolbar/toolbar_test.html: $(S)/toolbar/toolbar_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # Grid test (no GL) $(S)/grid/grid_test.o: $(S)/grid/grid_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/grid/grid_test.html: $(S)/grid/grid_test.o +$(S)/grid/grid_test.html: $(S)/grid/grid_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # Dialog test (no GL) $(S)/dialog/dialog_test.o: $(S)/dialog/dialog_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/dialog/dialog_test.html: $(S)/dialog/dialog_test.o +$(S)/dialog/dialog_test.html: $(S)/dialog/dialog_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # Timer test (no GL) $(S)/timer/timer_test.o: $(S)/timer/timer_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/timer/timer_test.html: $(S)/timer/timer_test.o +$(S)/timer/timer_test.html: $(S)/timer/timer_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # Tree test (no GL) $(S)/tree/tree_test.o: $(S)/tree/tree_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/tree/tree_test.html: $(S)/tree/tree_test.o +$(S)/tree/tree_test.html: $(S)/tree/tree_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # DataView test (no GL) $(S)/dataview/dataview_test.o: $(S)/dataview/dataview_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/dataview/dataview_test.html: $(S)/dataview/dataview_test.o +$(S)/dataview/dataview_test.html: $(S)/dataview/dataview_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # HtmlWindow test (needs HTML library) $(S)/htmlwin/htmlwin_test.o: $(S)/htmlwin/htmlwin_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/htmlwin/htmlwin_test.html: $(S)/htmlwin/htmlwin_test.o +$(S)/htmlwin/htmlwin_test.html: $(S)/htmlwin/htmlwin_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_HTML) --pre-js $(JS) --shell-file $(HTML) -o $@ # StyledTextCtrl test (needs STC library) $(S)/stc/stc_test.o: $(S)/stc/stc_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/stc/stc_test.html: $(S)/stc/stc_test.o +$(S)/stc/stc_test.html: $(S)/stc/stc_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_STC) --pre-js $(JS) --shell-file $(HTML) -o $@ # Print test (no GL) $(S)/print/print_test.o: $(S)/print/print_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/print/print_test.html: $(S)/print/print_test.o +$(S)/print/print_test.html: $(S)/print/print_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # DragDrop test (no GL) $(S)/dnd/dnd_test.o: $(S)/dnd/dnd_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/dnd/dnd_test.html: $(S)/dnd/dnd_test.o +$(S)/dnd/dnd_test.html: $(S)/dnd/dnd_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # PropertyGrid test (needs propgrid library) $(S)/propgrid/propgrid_test.o: $(S)/propgrid/propgrid_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/propgrid/propgrid_test.html: $(S)/propgrid/propgrid_test.o +$(S)/propgrid/propgrid_test.html: $(S)/propgrid/propgrid_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_PROPGRID) --pre-js $(JS) --shell-file $(HTML) -o $@ # Pickers test (colour/font pickers, no GL) $(S)/pickers/pickers_test.o: $(S)/pickers/pickers_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/pickers/pickers_test.html: $(S)/pickers/pickers_test.o +$(S)/pickers/pickers_test.html: $(S)/pickers/pickers_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # Collapsible pane test (no GL) $(S)/collapsible/collapsible_test.o: $(S)/collapsible/collapsible_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/collapsible/collapsible_test.html: $(S)/collapsible/collapsible_test.o +$(S)/collapsible/collapsible_test.html: $(S)/collapsible/collapsible_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # ListCtrl virtual mode test (no GL) $(S)/listctrl/listctrl_test.o: $(S)/listctrl/listctrl_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/listctrl/listctrl_test.html: $(S)/listctrl/listctrl_test.o +$(S)/listctrl/listctrl_test.html: $(S)/listctrl/listctrl_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # InfoBar test (no GL) $(S)/infobar/infobar_test.o: $(S)/infobar/infobar_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/infobar/infobar_test.html: $(S)/infobar/infobar_test.o +$(S)/infobar/infobar_test.html: $(S)/infobar/infobar_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # DataViewCtrl Virtual Mode test (no GL, uses base dataview) $(S)/dataviewvirtual/dataviewvirtual_test.o: $(S)/dataviewvirtual/dataviewvirtual_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/dataviewvirtual/dataviewvirtual_test.html: $(S)/dataviewvirtual/dataviewvirtual_test.o +$(S)/dataviewvirtual/dataviewvirtual_test.html: $(S)/dataviewvirtual/dataviewvirtual_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # AuiNotebook test (needs aui) $(S)/auinotebook/auinotebook_test.o: $(S)/auinotebook/auinotebook_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/auinotebook/auinotebook_test.html: $(S)/auinotebook/auinotebook_test.o +$(S)/auinotebook/auinotebook_test.html: $(S)/auinotebook/auinotebook_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_AUI) --pre-js $(JS) --shell-file $(HTML) -o $@ # Wizard test (needs adv) $(S)/wizard/wizard_test.o: $(S)/wizard/wizard_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/wizard/wizard_test.html: $(S)/wizard/wizard_test.o +$(S)/wizard/wizard_test.html: $(S)/wizard/wizard_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_ADV) --pre-js $(JS) --shell-file $(HTML) -o $@ # Grid Edit test (cell editing, no GL) $(S)/gridedit/gridedit_test.o: $(S)/gridedit/gridedit_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/gridedit/gridedit_test.html: $(S)/gridedit/gridedit_test.o +$(S)/gridedit/gridedit_test.html: $(S)/gridedit/gridedit_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # Calendar test (needs adv) $(S)/calendar/calendar_test.o: $(S)/calendar/calendar_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/calendar/calendar_test.html: $(S)/calendar/calendar_test.o +$(S)/calendar/calendar_test.html: $(S)/calendar/calendar_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_ADV) --pre-js $(JS) --shell-file $(HTML) -o $@ # Grid Renderers test (no GL) $(S)/gridrenderers/gridrenderers_test.o: $(S)/gridrenderers/gridrenderers_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/gridrenderers/gridrenderers_test.html: $(S)/gridrenderers/gridrenderers_test.o +$(S)/gridrenderers/gridrenderers_test.html: $(S)/gridrenderers/gridrenderers_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # Print Preview test (no GL) $(S)/printpreview/printpreview_test.o: $(S)/printpreview/printpreview_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/printpreview/printpreview_test.html: $(S)/printpreview/printpreview_test.o +$(S)/printpreview/printpreview_test.html: $(S)/printpreview/printpreview_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # Bitmap Buttons test (no GL) $(S)/bitmapbuttons/bitmapbuttons_test.o: $(S)/bitmapbuttons/bitmapbuttons_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/bitmapbuttons/bitmapbuttons_test.html: $(S)/bitmapbuttons/bitmapbuttons_test.o +$(S)/bitmapbuttons/bitmapbuttons_test.html: $(S)/bitmapbuttons/bitmapbuttons_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # Specialized Controls test (needs adv for treebook) $(S)/specialized/specialized_test.o: $(S)/specialized/specialized_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/specialized/specialized_test.html: $(S)/specialized/specialized_test.o +$(S)/specialized/specialized_test.html: $(S)/specialized/specialized_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_ADV) --pre-js $(JS) --shell-file $(HTML) -o $@ # Validators test (no GL) $(S)/validators/validators_test.o: $(S)/validators/validators_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/validators/validators_test.html: $(S)/validators/validators_test.o +$(S)/validators/validators_test.html: $(S)/validators/validators_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # Owner-drawn ComboBox test (no GL) $(S)/ownerdrawn/ownerdrawn_test.o: $(S)/ownerdrawn/ownerdrawn_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/ownerdrawn/ownerdrawn_test.html: $(S)/ownerdrawn/ownerdrawn_test.o +$(S)/ownerdrawn/ownerdrawn_test.html: $(S)/ownerdrawn/ownerdrawn_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # Popup Window test (no GL) $(S)/popup/popup_test.o: $(S)/popup/popup_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/popup/popup_test.html: $(S)/popup/popup_test.o +$(S)/popup/popup_test.html: $(S)/popup/popup_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # XML Document test (needs xml library) $(S)/xml/xml_test.o: $(S)/xml/xml_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/xml/xml_test.html: $(S)/xml/xml_test.o +$(S)/xml/xml_test.html: $(S)/xml/xml_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_XML) --pre-js $(JS) --shell-file $(HTML) -o $@ # WASM Edge Cases test (no GL) $(S)/wasmedge/wasmedge_test.o: $(S)/wasmedge/wasmedge_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/wasmedge/wasmedge_test.html: $(S)/wasmedge/wasmedge_test.o +$(S)/wasmedge/wasmedge_test.html: $(S)/wasmedge/wasmedge_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # Font Enumeration test (no GL) $(S)/fontenum/fontenum_test.o: $(S)/fontenum/fontenum_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/fontenum/fontenum_test.html: $(S)/fontenum/fontenum_test.o +$(S)/fontenum/fontenum_test.html: $(S)/fontenum/fontenum_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # Text Decorations test (no GL) $(S)/textdecor/textdecor_test.o: $(S)/textdecor/textdecor_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/textdecor/textdecor_test.html: $(S)/textdecor/textdecor_test.o +$(S)/textdecor/textdecor_test.html: $(S)/textdecor/textdecor_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # Bitmask test (no GL) $(S)/bitmask/bitmask_test.o: $(S)/bitmask/bitmask_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/bitmask/bitmask_test.html: $(S)/bitmask/bitmask_test.o +$(S)/bitmask/bitmask_test.html: $(S)/bitmask/bitmask_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # Regions test (no GL) $(S)/regions/regions_test.o: $(S)/regions/regions_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/regions/regions_test.html: $(S)/regions/regions_test.o +$(S)/regions/regions_test.html: $(S)/regions/regions_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # Maximize test (no GL) - reproduces KiCad startup maximize issue $(S)/maximize/maximize_test.o: $(S)/maximize/maximize_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/maximize/maximize_test.html: $(S)/maximize/maximize_test.o +$(S)/maximize/maximize_test.html: $(S)/maximize/maximize_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # Early size test (no GL) - tests GetClientSize() before Show() $(S)/earlysize/earlysize_test.o: $(S)/earlysize/earlysize_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/earlysize/earlysize_test.html: $(S)/earlysize/earlysize_test.o +$(S)/earlysize/earlysize_test.html: $(S)/earlysize/earlysize_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # Thread Pool test (pthread) - reproduces KiCad deadlock when hardware_concurrency() > PTHREAD_POOL_SIZE $(S)/threadpool/threadpool_test.o: $(S)/threadpool/threadpool_test.cpp $(CXX) -c $(CXXFLAGS) -pthread $< -o $@ -$(S)/threadpool/threadpool_test.html: $(S)/threadpool/threadpool_test.o +$(S)/threadpool/threadpool_test.html: $(S)/threadpool/threadpool_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_PTHREAD) --pre-js $(JS) --shell-file $(HTML) -o $@ # Log Error test (no GL) - reproduces KiCad's kiface error dialog $(S)/logerror/logerror_test.o: $(S)/logerror/logerror_test.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -$(S)/logerror/logerror_test.html: $(S)/logerror/logerror_test.o +$(S)/logerror/logerror_test.html: $(S)/logerror/logerror_test.o $(WX_CORE_LIB) $(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@ # Convenience targets diff --git a/tests/e2e/aui.spec.ts b/tests/e2e/aui.spec.ts index fe186dd..a463d3c 100644 --- a/tests/e2e/aui.spec.ts +++ b/tests/e2e/aui.spec.ts @@ -1,6 +1,6 @@ // wxAuiManager Tests - AUI docking system KiCad uses extensively import { test, expect, MAIN_CANVAS, tryLoadApp, getCanvasBox } from './utils/fixtures'; -import { clickAuiButton, findRenderedByLabel, findRenderedByType } from './utils/element-tracker'; +import { clickAuiButton, clickAuiPaneContent, findRenderedByLabel, findRenderedByType } from './utils/element-tracker'; test.describe('wxAuiManager Tests', () => { @@ -83,22 +83,24 @@ test.describe('wxAuiManager Tests', () => { return; } - const box = await getCanvasBox(page); - - // Click in Properties panel - await page.mouse.click(box.x + 75, box.y + 200); + // Click in Properties panel using element tracking + const propsClicked = await clickAuiPaneContent(page, 'Properties'); + expect(propsClicked, 'Should be able to click Properties pane').toBe(true); await page.waitForTimeout(200); - // Click in Layers panel (right side) - await page.mouse.click(box.x + 720, box.y + 200); + // Click in Layers panel using element tracking + const layersClicked = await clickAuiPaneContent(page, 'Layers'); + expect(layersClicked, 'Should be able to click Layers pane').toBe(true); await page.waitForTimeout(200); - // Click in Messages panel (bottom) - await page.mouse.click(box.x + 400, box.y + 550); + // Click in Messages panel using element tracking + const messagesClicked = await clickAuiPaneContent(page, 'Messages'); + expect(messagesClicked, 'Should be able to click Messages pane').toBe(true); await page.waitForTimeout(200); - // Click in center (Event Log) - await page.mouse.click(box.x + 400, box.y + 300); + // Click in Event Log panel using element tracking + const eventLogClicked = await clickAuiPaneContent(page, 'Event Log'); + expect(eventLogClicked, 'Should be able to click Event Log pane').toBe(true); await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/aui-05-multi-panel.png', fullPage: true }); diff --git a/tests/e2e/auinotebook.spec.ts b/tests/e2e/auinotebook.spec.ts index 632093e..0e1818b 100644 --- a/tests/e2e/auinotebook.spec.ts +++ b/tests/e2e/auinotebook.spec.ts @@ -1,5 +1,6 @@ // wxAuiNotebook Tests - Tab panels for KiCad editors import { test, expect, tryLoadApp } from './utils/fixtures'; +import { clickByLabel, clickTab } from './utils/element-tracker'; test.describe('wxAuiNotebook Tests', () => { @@ -23,13 +24,10 @@ test.describe('wxAuiNotebook Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Click on PCB tab - await page.mouse.click(box.x + 200, box.y + 95); - await page.waitForTimeout(200); - } + // Click on PCB tab using element registry + const clicked = await clickTab(page, 'PCB'); + expect(clicked, 'PCB tab should be found and clicked').toBe(true); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/auinotebook-02-tab-switch.png', fullPage: true }); }); @@ -44,13 +42,10 @@ test.describe('wxAuiNotebook Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Click Add Tab button - await page.mouse.click(box.x + 60, box.y + 60); - await page.waitForTimeout(200); - } + // Click Add Tab button using element registry + const clicked = await clickByLabel(page, 'Add Tab'); + expect(clicked, 'Add Tab button should be found and clicked').toBe(true); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/auinotebook-03-add-tab.png', fullPage: true }); }); @@ -65,13 +60,10 @@ test.describe('wxAuiNotebook Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Click Remove Tab button - await page.mouse.click(box.x + 160, box.y + 60); - await page.waitForTimeout(200); - } + // Click Remove Tab button using element registry + const clicked = await clickByLabel(page, 'Remove Tab'); + expect(clicked, 'Remove Tab button should be found and clicked').toBe(true); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/auinotebook-04-remove-tab.png', fullPage: true }); }); @@ -86,13 +78,10 @@ test.describe('wxAuiNotebook Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Click Bottom button - await page.mouse.click(box.x + 470, box.y + 60); - await page.waitForTimeout(200); - } + // Click Bottom button using element registry + const clicked = await clickByLabel(page, 'Bottom'); + expect(clicked, 'Bottom button should be found and clicked').toBe(true); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/auinotebook-05-tab-style.png', fullPage: true }); }); diff --git a/tests/e2e/bitmapbuttons.spec.ts b/tests/e2e/bitmapbuttons.spec.ts index 59da13c..37b7726 100644 --- a/tests/e2e/bitmapbuttons.spec.ts +++ b/tests/e2e/bitmapbuttons.spec.ts @@ -1,5 +1,6 @@ // wxBitmapButton Tests - Bitmap buttons, toggle buttons, disabled states import { test, expect, tryLoadApp } from './utils/fixtures'; +import { clickByLabel } from './utils/element-tracker'; test.describe('wxBitmapButton Tests', () => { @@ -23,16 +24,12 @@ test.describe('wxBitmapButton Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Click Select tool button - await page.mouse.click(box.x + 50, box.y + 100); - await page.waitForTimeout(100); - // Click Line tool button - await page.mouse.click(box.x + 90, box.y + 100); - await page.waitForTimeout(100); - } + // Click Select tool button using element registry + await clickByLabel(page, 'Select Tool'); + await page.waitForTimeout(100); + // Click Line tool button + await clickByLabel(page, 'Line Tool'); + await page.waitForTimeout(100); await page.screenshot({ path: 'test-results/bitmapbuttons-02-toolbar-click.png', fullPage: true }); }); @@ -47,13 +44,9 @@ test.describe('wxBitmapButton Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Click F.Cu toggle button to turn it off - await page.mouse.click(box.x + 50, box.y + 170); - await page.waitForTimeout(200); - } + // Click F.Cu checkbox to toggle it using element registry + await clickByLabel(page, 'F.Cu'); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/bitmapbuttons-03-toggle.png', fullPage: true }); }); @@ -68,17 +61,11 @@ test.describe('wxBitmapButton Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Toggle multiple layer buttons - await page.mouse.click(box.x + 50, box.y + 170); - await page.waitForTimeout(100); - await page.mouse.click(box.x + 120, box.y + 170); - await page.waitForTimeout(100); - await page.mouse.click(box.x + 190, box.y + 170); - await page.waitForTimeout(200); - } + // Toggle multiple layer checkboxes using element registry + await clickByLabel(page, 'F.Cu'); + await page.waitForTimeout(100); + await clickByLabel(page, 'B.Cu'); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/bitmapbuttons-04-multi-toggle.png', fullPage: true }); }); @@ -93,13 +80,9 @@ test.describe('wxBitmapButton Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Click Toggle Enable State button - await page.mouse.click(box.x + 400, box.y + 240); - await page.waitForTimeout(200); - } + // Click Toggle Enable State button using element registry + await clickByLabel(page, 'Toggle Enable State'); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/bitmapbuttons-05-enable-toggle.png', fullPage: true }); }); @@ -114,17 +97,13 @@ test.describe('wxBitmapButton Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Click different shape buttons - await page.mouse.click(box.x + 50, box.y + 310); - await page.waitForTimeout(100); - await page.mouse.click(box.x + 100, box.y + 310); - await page.waitForTimeout(100); - await page.mouse.click(box.x + 150, box.y + 310); - await page.waitForTimeout(200); - } + // Click different shape buttons using element registry (by tooltip) + await clickByLabel(page, 'Rectangle'); + await page.waitForTimeout(100); + await clickByLabel(page, 'Circle'); + await page.waitForTimeout(100); + await clickByLabel(page, 'Triangle'); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/bitmapbuttons-06-shapes.png', fullPage: true }); }); @@ -139,15 +118,11 @@ test.describe('wxBitmapButton Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Click New, Open, Save buttons - await page.mouse.click(box.x + 50, box.y + 380); - await page.waitForTimeout(100); - await page.mouse.click(box.x + 90, box.y + 380); - await page.waitForTimeout(200); - } + // Click New, Open buttons using element registry (by tooltip) + await clickByLabel(page, 'New'); + await page.waitForTimeout(100); + await clickByLabel(page, 'Open'); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/bitmapbuttons-07-artprovider.png', fullPage: true }); }); diff --git a/tests/e2e/calendar.spec.ts b/tests/e2e/calendar.spec.ts index 56092ab..152b535 100644 --- a/tests/e2e/calendar.spec.ts +++ b/tests/e2e/calendar.spec.ts @@ -1,5 +1,6 @@ // wxCalendarCtrl Tests - Date selection import { test, expect, tryLoadApp } from './utils/fixtures'; +import { clickByLabel, clickCalendarDate } from './utils/element-tracker'; test.describe('wxCalendarCtrl Tests', () => { @@ -23,13 +24,10 @@ test.describe('wxCalendarCtrl Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Click on a day in the calendar - await page.mouse.click(box.x + 150, box.y + 200); - await page.waitForTimeout(200); - } + // Click on day 15 in the calendar using element registry + const clicked = await clickCalendarDate(page, 15); + expect(clicked, 'Calendar date 15 should be found and clicked').toBe(true); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/calendar-02-select-date.png', fullPage: true }); }); @@ -44,13 +42,10 @@ test.describe('wxCalendarCtrl Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Click Next Month button - await page.mouse.click(box.x + 480, box.y + 170); - await page.waitForTimeout(200); - } + // Click Next Month button using element registry + const clicked = await clickByLabel(page, 'Next Month'); + expect(clicked, 'Next Month button should be found').toBe(true); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/calendar-03-next-month.png', fullPage: true }); }); @@ -65,13 +60,10 @@ test.describe('wxCalendarCtrl Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Click Previous Month button - await page.mouse.click(box.x + 480, box.y + 200); - await page.waitForTimeout(200); - } + // Click Previous Month button using element registry + const clicked = await clickByLabel(page, 'Previous Month'); + expect(clicked, 'Previous Month button should be found').toBe(true); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/calendar-04-prev-month.png', fullPage: true }); }); @@ -86,16 +78,15 @@ test.describe('wxCalendarCtrl Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // First go to next month - await page.mouse.click(box.x + 480, box.y + 170); - await page.waitForTimeout(100); - // Click Today button - await page.mouse.click(box.x + 480, box.y + 140); - await page.waitForTimeout(200); - } + // First go to next month + const nextClicked = await clickByLabel(page, 'Next Month'); + expect(nextClicked, 'Next Month button should be found').toBe(true); + await page.waitForTimeout(100); + + // Click Today button using element registry + const todayClicked = await clickByLabel(page, 'Today'); + expect(todayClicked, 'Today button should be found').toBe(true); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/calendar-05-today.png', fullPage: true }); }); diff --git a/tests/e2e/collapsible.spec.ts b/tests/e2e/collapsible.spec.ts index a1acce1..f2191bc 100644 --- a/tests/e2e/collapsible.spec.ts +++ b/tests/e2e/collapsible.spec.ts @@ -1,5 +1,6 @@ // wxCollapsiblePane Tests - Collapsible sections for property panels import { test, expect, tryLoadApp } from './utils/fixtures'; +import { clickByLabel } from './utils/element-tracker'; test.describe('wxCollapsiblePane Tests', () => { @@ -55,15 +56,9 @@ test.describe('wxCollapsiblePane Tests', () => { return; } - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (!box) { - test.skip(); - return; - } - - // Click Expand All button (approximate position) - await page.mouse.click(box.x + 150, box.y + 100); + // Click Expand All button using element registry + const clicked = await clickByLabel(page, 'Expand All'); + expect(clicked, 'Expand All button should be found and clicked').toBe(true); await page.waitForTimeout(300); await page.screenshot({ path: 'test-results/collapsible-04-expand-all.png', fullPage: true }); @@ -82,15 +77,9 @@ test.describe('wxCollapsiblePane Tests', () => { return; } - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (!box) { - test.skip(); - return; - } - - // Click Collapse All button (approximate position, second button) - await page.mouse.click(box.x + 300, box.y + 100); + // Click Collapse All button using element registry + const clicked = await clickByLabel(page, 'Collapse All'); + expect(clicked, 'Collapse All button should be found and clicked').toBe(true); await page.waitForTimeout(300); await page.screenshot({ path: 'test-results/collapsible-05-collapse-all.png', fullPage: true }); diff --git a/tests/e2e/dataview.spec.ts b/tests/e2e/dataview.spec.ts index f460110..0491cd1 100644 --- a/tests/e2e/dataview.spec.ts +++ b/tests/e2e/dataview.spec.ts @@ -1,4 +1,5 @@ import { test, expect } from './utils/fixtures'; +import { clickTab, clickByLabel, clickDataViewItem, clickDataViewItemByIndex, clickColumnHeader, clickColumnHeaderByIndex } from './utils/element-tracker'; /** * wxDataViewCtrl Tests @@ -48,10 +49,9 @@ test.describe('wxDataViewCtrl Tests', () => { test('List item can be selected', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('canvas'); - - // Click on first list item (data rows start at y≈210) - await canvas.click({ position: { x: 200, y: 215 } }); + // Click on first list item using element registry + const clicked = await clickDataViewItem(page, 'Zone_GND_Top'); + expect(clicked).toBe(true); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/dataview-03-list-selected.png' }); @@ -65,10 +65,8 @@ test.describe('wxDataViewCtrl Tests', () => { test('Add Item button works for list', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('canvas'); - - // Click Add Item button (x≈502, y≈135) - await canvas.click({ position: { x: 502, y: 135 } }); + // Click Add Item button using element registry + await clickByLabel(page, 'Add Item'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/dataview-04-list-add.png' }); @@ -82,10 +80,8 @@ test.describe('wxDataViewCtrl Tests', () => { test('Switch to Tree View tab', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('canvas'); - - // Click on Tree View tab (x≈105, y≈105) - await canvas.click({ position: { x: 105, y: 105 } }); + // Click on Tree View tab using element registry + await clickTab(page, 'Tree View'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/dataview-05-tree-tab.png' }); @@ -99,14 +95,13 @@ test.describe('wxDataViewCtrl Tests', () => { test('Tree item can be selected', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('canvas'); - - // Switch to tree tab first (x≈105, y≈105) - await canvas.click({ position: { x: 105, y: 105 } }); + // Switch to tree tab first using element registry + await clickTab(page, 'Tree View'); await page.waitForTimeout(500); - // Click on a tree item (tree content area starts around y≈200) - await canvas.click({ position: { x: 150, y: 220 } }); + // Click on a tree item using element registry + const clicked = await clickDataViewItem(page, 'Libraries'); + expect(clicked, 'Should be able to click Libraries tree item').toBe(true); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/dataview-06-tree-selected.png' }); @@ -119,14 +114,12 @@ test.describe('wxDataViewCtrl Tests', () => { test('Expand All button works for tree', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('canvas'); - - // Switch to tree tab (x≈105, y≈105) - await canvas.click({ position: { x: 105, y: 105 } }); + // Switch to tree tab using element registry + await clickTab(page, 'Tree View'); await page.waitForTimeout(500); - // Click Expand All button (x≈488, y≈136 from button-finder) - await canvas.click({ position: { x: 488, y: 136 } }); + // Click Expand All button using element registry + await clickByLabel(page, 'Expand All'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/dataview-07-tree-expanded.png' }); @@ -140,14 +133,12 @@ test.describe('wxDataViewCtrl Tests', () => { test('Collapse All button works for tree', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('canvas'); - - // Switch to tree tab (x≈105, y≈105) - await canvas.click({ position: { x: 105, y: 105 } }); + // Switch to tree tab using element registry + await clickTab(page, 'Tree View'); await page.waitForTimeout(500); - // Click Collapse All button (x≈600, y≈136 from button-finder) - await canvas.click({ position: { x: 600, y: 136 } }); + // Click Collapse All button using element registry + await clickByLabel(page, 'Collapse All'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/dataview-08-tree-collapsed.png' }); @@ -161,10 +152,9 @@ test.describe('wxDataViewCtrl Tests', () => { test('Column header click works for list', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('canvas'); - - // Click on Zone Name column header (y≈178) - await canvas.click({ position: { x: 80, y: 178 } }); + // Click on Zone Name column header using element registry + const clicked = await clickColumnHeader(page, 'Zone Name'); + expect(clicked, 'Should be able to click Zone Name column header').toBe(true); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/dataview-09-column-click.png' }); diff --git a/tests/e2e/dataviewvirtual.spec.ts b/tests/e2e/dataviewvirtual.spec.ts index 718b8c7..e29da37 100644 --- a/tests/e2e/dataviewvirtual.spec.ts +++ b/tests/e2e/dataviewvirtual.spec.ts @@ -1,5 +1,6 @@ // wxDataViewCtrl Virtual Mode Tests - Zone Manager/Net Inspector simulation import { test, expect, tryLoadApp } from './utils/fixtures'; +import { clickByLabel, findAllRenderedByLabel, clickDataViewItemByIndex, clickDataViewItem } from './utils/element-tracker'; test.describe('wxDataViewCtrl Virtual Mode Tests', () => { @@ -23,14 +24,10 @@ test.describe('wxDataViewCtrl Virtual Mode Tests', () => { await page.waitForTimeout(500); - // Click 10,000 button to test large dataset - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Click where the 10,000 button should be - await page.mouse.click(box.x + 200, box.y + 60); - await page.waitForTimeout(200); - } + // Click 10,000 button to test large dataset using element registry + const clicked = await clickByLabel(page, '10,000'); + expect(clicked, '10,000 button should be found').toBe(true); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/dataviewvirtual-02-large-dataset.png', fullPage: true }); @@ -50,13 +47,10 @@ test.describe('wxDataViewCtrl Virtual Mode Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Click Middle button - await page.mouse.click(box.x + 340, box.y + 60); - await page.waitForTimeout(200); - } + // Click Middle button using element registry + const clicked = await clickByLabel(page, 'Middle'); + expect(clicked, 'Middle button should be found').toBe(true); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/dataviewvirtual-03-scroll.png', fullPage: true }); }); @@ -71,13 +65,11 @@ test.describe('wxDataViewCtrl Virtual Mode Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Click on an item in the list - await page.mouse.click(box.x + 200, box.y + 200); - await page.waitForTimeout(200); - } + // Click on an item in the list using element registry + // Virtual list items have labels like "NET_00000", "NET_00001", etc. + const clicked = await clickDataViewItemByIndex(page, 0); + expect(clicked).toBe(true); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/dataviewvirtual-04-selection.png', fullPage: true }); }); @@ -92,13 +84,11 @@ test.describe('wxDataViewCtrl Virtual Mode Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Click in zone manager panel (right side) - await page.mouse.click(box.x + 700, box.y + 200); - await page.waitForTimeout(200); - } + // Click in zone manager panel using element registry + // Zone items have labels like "Zone_000", "Zone_001", etc. + const clicked = await clickDataViewItem(page, 'Zone_000'); + expect(clicked).toBe(true); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/dataviewvirtual-05-zone-manager.png', fullPage: true }); }); diff --git a/tests/e2e/dialogs.spec.ts b/tests/e2e/dialogs.spec.ts index 4999216..c85556b 100644 --- a/tests/e2e/dialogs.spec.ts +++ b/tests/e2e/dialogs.spec.ts @@ -1,8 +1,12 @@ -import { test, expect, MAIN_CANVAS, waitForApp, getCanvasBox } from './utils/fixtures'; +import { test, expect, waitForApp } from './utils/fixtures'; +import { clickTab, clickByLabel } from './utils/element-tracker'; -async function switchToDialogsTab(page: any, box: { x: number; y: number }) { - // Dialogs tab is the 7th tab (after Grid) - await page.mouse.click(box.x + 370, box.y + 35); +async function switchToDialogsTab(page: any) { + // Click Dialogs tab using element registry + const clicked = await clickTab(page, 'Dialogs'); + if (!clicked) { + await clickByLabel(page, 'Dialogs'); + } await page.waitForTimeout(1000); } @@ -12,13 +16,11 @@ test.describe('Dialogs Tab Tests', () => { await page.goto('/minimal_test.html'); await waitForApp(page); - const box = await getCanvasBox(page); - // Screenshot before switching to Dialogs tab await page.screenshot({ path: 'test-results/dialogs-00-initial.png', fullPage: true }); // Switch to Dialogs tab - await switchToDialogsTab(page, box); + await switchToDialogsTab(page); await page.screenshot({ path: 'test-results/dialogs-01-tab-selected.png', fullPage: true }); // Verify app is still responsive @@ -37,18 +39,16 @@ test.describe('Dialogs Tab Tests', () => { await page.goto('/minimal_test.html'); await waitForApp(page); - const box = await getCanvasBox(page); + await switchToDialogsTab(page); - await switchToDialogsTab(page, box); - - // Click "Info Dialog" button (first button in wxMessageBox section) - await page.mouse.click(box.x + 80, box.y + 110); + // Click "Info" button using element registry + await clickByLabel(page, 'Info'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/dialogs-msgbox-info-open.png', fullPage: true }); // Click OK to close - await page.mouse.click(box.x + 350, box.y + 250); + await clickByLabel(page, 'OK'); await page.waitForTimeout(300); await page.screenshot({ path: 'test-results/dialogs-msgbox-info-closed.png', fullPage: true }); @@ -60,18 +60,16 @@ test.describe('Dialogs Tab Tests', () => { await page.goto('/minimal_test.html'); await waitForApp(page); - const box = await getCanvasBox(page); + await switchToDialogsTab(page); - await switchToDialogsTab(page, box); - - // Click "Yes/No Dialog" button (second button) - await page.mouse.click(box.x + 180, box.y + 110); + // Click "Yes/No" button using element registry + await clickByLabel(page, 'Yes/No'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/dialogs-msgbox-yesno-open.png', fullPage: true }); - // Click somewhere to close (Yes or No) - await page.mouse.click(box.x + 300, box.y + 250); + // Click Yes to close + await clickByLabel(page, 'Yes'); await page.waitForTimeout(300); await page.screenshot({ path: 'test-results/dialogs-msgbox-yesno-closed.png', fullPage: true }); @@ -81,18 +79,16 @@ test.describe('Dialogs Tab Tests', () => { await page.goto('/minimal_test.html'); await waitForApp(page); - const box = await getCanvasBox(page); + await switchToDialogsTab(page); - await switchToDialogsTab(page, box); - - // Click "Error Dialog" button (third button) - await page.mouse.click(box.x + 280, box.y + 110); + // Click "Error" button using element registry + await clickByLabel(page, 'Error'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/dialogs-msgbox-error-open.png', fullPage: true }); - // Close the dialog - await page.mouse.click(box.x + 350, box.y + 250); + // Close the dialog with OK + await clickByLabel(page, 'OK'); await page.waitForTimeout(300); await page.screenshot({ path: 'test-results/dialogs-msgbox-error-closed.png', fullPage: true }); @@ -105,18 +101,16 @@ test.describe('Dialogs Tab Tests', () => { await page.goto('/minimal_test.html'); await waitForApp(page); - const box = await getCanvasBox(page); + await switchToDialogsTab(page); - await switchToDialogsTab(page, box); - - // Click "Open Custom Dialog" button (in wxDialog section, around y=160) - await page.mouse.click(box.x + 100, box.y + 160); + // Click "Open Custom Dialog" button using element registry + await clickByLabel(page, 'Open Custom Dialog'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/dialogs-custom-open.png', fullPage: true }); // Click OK to close - await page.mouse.click(box.x + 300, box.y + 300); + await clickByLabel(page, 'OK'); await page.waitForTimeout(300); await page.screenshot({ path: 'test-results/dialogs-custom-closed.png', fullPage: true }); @@ -129,14 +123,12 @@ test.describe('Dialogs Tab Tests', () => { await page.goto('/minimal_test.html'); await waitForApp(page); - const box = await getCanvasBox(page); - - await switchToDialogsTab(page, box); + await switchToDialogsTab(page); await page.screenshot({ path: 'test-results/dialogs-timer-initial.png', fullPage: true }); - // Click "Start Timer" button (centered buttons) - await page.mouse.click(box.x + 500, box.y + 230); + // Click "Start Timer" button using element registry + await clickByLabel(page, 'Start Timer'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/dialogs-timer-started.png', fullPage: true }); @@ -147,7 +139,7 @@ test.describe('Dialogs Tab Tests', () => { await page.screenshot({ path: 'test-results/dialogs-timer-running.png', fullPage: true }); // Click "Stop Timer" - await page.mouse.click(box.x + 600, box.y + 230); + await clickByLabel(page, 'Stop Timer'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/dialogs-timer-stopped.png', fullPage: true }); @@ -160,24 +152,22 @@ test.describe('Dialogs Tab Tests', () => { await page.goto('/minimal_test.html'); await waitForApp(page); - const box = await getCanvasBox(page); + await switchToDialogsTab(page); - await switchToDialogsTab(page, box); - - // Start timer (centered buttons) - await page.mouse.click(box.x + 500, box.y + 230); + // Start timer using element registry + await clickByLabel(page, 'Start Timer'); await page.waitForTimeout(1500); // Stop timer - await page.mouse.click(box.x + 600, box.y + 230); + await clickByLabel(page, 'Stop Timer'); await page.waitForTimeout(500); // Start again - await page.mouse.click(box.x + 500, box.y + 230); + await clickByLabel(page, 'Start Timer'); await page.waitForTimeout(1500); // Stop again - await page.mouse.click(box.x + 600, box.y + 230); + await clickByLabel(page, 'Stop Timer'); await page.waitForTimeout(300); await page.screenshot({ path: 'test-results/dialogs-timer-multiple.png', fullPage: true }); @@ -191,26 +181,24 @@ test.describe('Dialogs Tab Tests', () => { await page.goto('/minimal_test.html'); await waitForApp(page); - const box = await getCanvasBox(page); + await switchToDialogsTab(page); - await switchToDialogsTab(page, box); - - // 1. Click Info button - await page.mouse.click(box.x + 80, box.y + 110); + // 1. Click Info button and close + await clickByLabel(page, 'Info'); await page.waitForTimeout(400); - await page.mouse.click(box.x + 350, box.y + 250); // Close + await clickByLabel(page, 'OK'); await page.waitForTimeout(200); - // 2. Click Custom Dialog button - await page.mouse.click(box.x + 100, box.y + 160); + // 2. Click Custom Dialog button and close + await clickByLabel(page, 'Open Custom Dialog'); await page.waitForTimeout(400); - await page.mouse.click(box.x + 300, box.y + 300); // Close + await clickByLabel(page, 'OK'); await page.waitForTimeout(200); - // 3. Start and stop timer (centered buttons) - await page.mouse.click(box.x + 500, box.y + 230); // Start + // 3. Start and stop timer + await clickByLabel(page, 'Start Timer'); await page.waitForTimeout(2000); - await page.mouse.click(box.x + 600, box.y + 230); // Stop + await clickByLabel(page, 'Stop Timer'); await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/dialogs-full-flow.png', fullPage: true }); diff --git a/tests/e2e/grid.spec.ts b/tests/e2e/grid.spec.ts index 465dad5..863e904 100644 --- a/tests/e2e/grid.spec.ts +++ b/tests/e2e/grid.spec.ts @@ -1,8 +1,12 @@ import { test, expect, MAIN_CANVAS, waitForApp, getCanvasBox } from './utils/fixtures'; +import { clickTab, clickByLabel, clickSpinUp, clickSearchCtrl } from './utils/element-tracker'; -async function switchToGridTab(page: any, box: { x: number; y: number }) { - // Click Grid tab (sixth tab, after OpenGL which is at x=280) - await page.mouse.click(box.x + 315, box.y + 35); +async function switchToGridTab(page: any) { + // Click Grid tab using element registry + const clicked = await clickTab(page, 'Grid'); + if (!clicked) { + await clickByLabel(page, 'Grid'); + } await page.waitForTimeout(1000); } @@ -95,10 +99,8 @@ test.describe('Grid Tab Tests', () => { await page.goto('/minimal_test.html'); await waitForApp(page); - const box = await getCanvasBox(page); - - // Switch to Grid tab - await switchToGridTab(page, box); + // Switch to Grid tab using element registry + await switchToGridTab(page); await page.screenshot({ path: 'test-results/wxgrid-01-tab.png', fullPage: true }); // Evaluate if grid-like content exists (row/column headers, cells) @@ -139,7 +141,7 @@ test.describe('Grid Tab Tests', () => { const box = await getCanvasBox(page); - await switchToGridTab(page, box); + await switchToGridTab(page); // Click on a cell (would be at ~y=175 if grid existed) await page.mouse.click(box.x + 180, box.y + 175); @@ -158,7 +160,7 @@ test.describe('Grid Tab Tests', () => { const box = await getCanvasBox(page); - await switchToGridTab(page, box); + await switchToGridTab(page); // Double-click to edit a cell await page.mouse.dblclick(box.x + 180, box.y + 195); @@ -188,7 +190,7 @@ test.describe('Grid Tab Tests', () => { const box = await getCanvasBox(page); - await switchToGridTab(page, box); + await switchToGridTab(page); await page.screenshot({ path: 'test-results/spinctrl-01-visible.png', fullPage: true }); // SpinCtrl should be visible - check for its box and arrows in the canvas @@ -225,10 +227,11 @@ test.describe('Grid Tab Tests', () => { const box = await getCanvasBox(page); - await switchToGridTab(page, box); + await switchToGridTab(page); - // Click up arrow on SpinCtrl - await page.mouse.click(box.x + 220, box.y + 350); + // Click up arrow on SpinCtrl using element tracking + const spinClicked = await clickSpinUp(page); + expect(spinClicked, 'Should be able to click spin up button').toBe(true); await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/spinctrl-02-after-click.png', fullPage: true }); @@ -250,7 +253,7 @@ test.describe('Grid Tab Tests', () => { const box = await getCanvasBox(page); - await switchToGridTab(page, box); + await switchToGridTab(page); await page.screenshot({ path: 'test-results/searchctrl-01-visible.png', fullPage: true }); // SearchCtrl should be visible - check for its text field and buttons @@ -287,10 +290,11 @@ test.describe('Grid Tab Tests', () => { const box = await getCanvasBox(page); - await switchToGridTab(page, box); + await switchToGridTab(page); - // Click on SearchCtrl text field (center of the control) - await page.mouse.click(box.x + 420, box.y + 350); + // Click on SearchCtrl text field using element tracking + const searchClicked = await clickSearchCtrl(page); + expect(searchClicked, 'Should be able to click SearchCtrl text field').toBe(true); await page.waitForTimeout(200); // Type search text @@ -320,7 +324,7 @@ test.describe('Grid Tab Tests', () => { const box = await getCanvasBox(page); - await switchToGridTab(page, box); + await switchToGridTab(page); await page.screenshot({ path: 'test-results/grid-tab-final.png', fullPage: true }); // Verify app is still responsive after switching to Grid tab diff --git a/tests/e2e/gridedit.spec.ts b/tests/e2e/gridedit.spec.ts index 3720104..4da424a 100644 --- a/tests/e2e/gridedit.spec.ts +++ b/tests/e2e/gridedit.spec.ts @@ -1,5 +1,6 @@ // wxGrid Cell Editing Tests - Property editing simulation import { test, expect, tryLoadApp } from './utils/fixtures'; +import { clickByLabel, clickGridCell, findGridCell } from './utils/element-tracker'; test.describe('wxGrid Cell Editing Tests', () => { @@ -23,13 +24,10 @@ test.describe('wxGrid Cell Editing Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Click on a cell - await page.mouse.click(box.x + 150, box.y + 180); - await page.waitForTimeout(200); - } + // Click on a cell using element registry + const clicked = await clickGridCell(page, 1, 1); + expect(clicked, 'Grid cell should be found and clicked').toBe(true); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/gridedit-02-select-cell.png', fullPage: true }); }); @@ -44,13 +42,13 @@ test.describe('wxGrid Cell Editing Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Double-click to enter edit mode - await page.mouse.dblclick(box.x + 150, box.y + 180); - await page.waitForTimeout(300); + // Double-click to enter edit mode using element registry + const cell = await findGridCell(page, 1, 1); + expect(cell, 'Grid cell should be found').not.toBeNull(); + if (cell) { + await page.mouse.dblclick(cell.centerX, cell.centerY); } + await page.waitForTimeout(300); await page.screenshot({ path: 'test-results/gridedit-03-edit-cell.png', fullPage: true }); }); @@ -65,13 +63,10 @@ test.describe('wxGrid Cell Editing Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Click Add Row button - await page.mouse.click(box.x + 60, box.y + 60); - await page.waitForTimeout(200); - } + // Click Add Row button using element registry + const clicked = await clickByLabel(page, 'Add Row'); + expect(clicked, 'Add Row button should be found and clicked').toBe(true); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/gridedit-04-add-row.png', fullPage: true }); }); @@ -86,16 +81,15 @@ test.describe('wxGrid Cell Editing Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Select a row first - await page.mouse.click(box.x + 150, box.y + 180); - await page.waitForTimeout(100); - // Click Delete Row button - await page.mouse.click(box.x + 150, box.y + 60); - await page.waitForTimeout(200); - } + // Select a row first using element registry + const cellClicked = await clickGridCell(page, 1, 1); + expect(cellClicked, 'Grid cell should be found and clicked').toBe(true); + await page.waitForTimeout(100); + + // Click Delete Row button using element registry + const deleteClicked = await clickByLabel(page, 'Delete Row'); + expect(deleteClicked, 'Delete Row button should be found and clicked').toBe(true); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/gridedit-05-delete-row.png', fullPage: true }); }); diff --git a/tests/e2e/gridrenderers.spec.ts b/tests/e2e/gridrenderers.spec.ts index 54436c9..0d1bb5c 100644 --- a/tests/e2e/gridrenderers.spec.ts +++ b/tests/e2e/gridrenderers.spec.ts @@ -1,5 +1,6 @@ // wxGrid Custom Cell Renderers Tests - Color cells, icon+text, striped rows import { test, expect, tryLoadApp } from './utils/fixtures'; +import { clickTab, clickGridCell } from './utils/element-tracker'; test.describe('wxGrid Custom Cell Renderers Tests', () => { @@ -37,13 +38,10 @@ test.describe('wxGrid Custom Cell Renderers Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Click Icon+Text tab (second tab in notebook) - await page.mouse.click(box.x + 150, box.y + 80); - await page.waitForTimeout(200); - } + // Click Icon+Text tab using element registry + const clicked = await clickTab(page, 'Icon+Text'); + expect(clicked, 'Icon+Text tab should be found').toBe(true); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/gridrenderers-03-icon-text.png', fullPage: true }); }); @@ -58,13 +56,10 @@ test.describe('wxGrid Custom Cell Renderers Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Click Striped+Checkboxes tab (third tab) - await page.mouse.click(box.x + 280, box.y + 80); - await page.waitForTimeout(200); - } + // Click Striped+Checkboxes tab using element registry + const clicked = await clickTab(page, 'Striped+Checkboxes'); + expect(clicked, 'Striped+Checkboxes tab should be found').toBe(true); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/gridrenderers-04-striped.png', fullPage: true }); }); @@ -79,17 +74,15 @@ test.describe('wxGrid Custom Cell Renderers Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Go to Striped+Checkboxes tab - await page.mouse.click(box.x + 280, box.y + 80); - await page.waitForTimeout(200); + // Go to Striped+Checkboxes tab using element registry + const tabClicked = await clickTab(page, 'Striped+Checkboxes'); + expect(tabClicked, 'Striped+Checkboxes tab should be found').toBe(true); + await page.waitForTimeout(200); - // Click on a checkbox cell (DNP column) - await page.mouse.click(box.x + 330, box.y + 180); - await page.waitForTimeout(200); - } + // Click on a checkbox cell (DNP column - row 2, col 2 based on typical grid structure) + const cellClicked = await clickGridCell(page, 2, 2); + expect(cellClicked, 'Checkbox cell should be found').toBe(true); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/gridrenderers-05-checkbox-toggle.png', fullPage: true }); }); diff --git a/tests/e2e/htmlwin.spec.ts b/tests/e2e/htmlwin.spec.ts index 4d3a3db..3271ad0 100644 --- a/tests/e2e/htmlwin.spec.ts +++ b/tests/e2e/htmlwin.spec.ts @@ -1,4 +1,5 @@ import { test, expect } from './utils/fixtures'; +import { clickByLabel } from './utils/element-tracker'; /** * wxHtmlWindow Tests @@ -48,10 +49,8 @@ test.describe('wxHtmlWindow Tests', () => { test('Tables button loads table content', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('canvas'); - - // Click Tables button (x≈528, y≈96 from button-finder) - await canvas.click({ position: { x: 528, y: 96 } }); + // Click Tables button using element registry + await clickByLabel(page, 'Tables'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/htmlwin-03-tables.png' }); @@ -65,10 +64,8 @@ test.describe('wxHtmlWindow Tests', () => { test('Long Content button loads scrollable content', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('canvas'); - - // Click Long Content button (x≈608, y≈96 from button-finder) - await canvas.click({ position: { x: 608, y: 96 } }); + // Click Long Content button using element registry + await clickByLabel(page, 'Long Content'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/htmlwin-04-long-content.png' }); @@ -82,10 +79,8 @@ test.describe('wxHtmlWindow Tests', () => { test('KiCad About button loads KiCad-style content', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('canvas'); - - // Click KiCad About button (x≈736, y≈96 from button-finder) - await canvas.click({ position: { x: 736, y: 96 } }); + // Click KiCad About button using element registry + await clickByLabel(page, 'KiCad-style About'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/htmlwin-05-kicad-about.png' }); @@ -101,11 +96,11 @@ test.describe('wxHtmlWindow Tests', () => { const canvas = page.locator('canvas'); - // Click Basic HTML first to ensure links are visible (x≈416, y≈96) - await canvas.click({ position: { x: 416, y: 96 } }); + // Click Basic HTML first to ensure links are visible + await clickByLabel(page, 'Basic HTML'); await page.waitForTimeout(500); - // Click on a link in the HTML content (approximate position in content area) + // Click on a link in the HTML content (link positions not in registry) await canvas.click({ position: { x: 200, y: 350 } }); await page.waitForTimeout(500); @@ -122,11 +117,11 @@ test.describe('wxHtmlWindow Tests', () => { const canvas = page.locator('canvas'); - // Load long content first (x≈608, y≈96) - await canvas.click({ position: { x: 608, y: 96 } }); + // Load long content first + await clickByLabel(page, 'Long Content'); await page.waitForTimeout(500); - // Scroll the content + // Scroll the content (scroll position not in registry) await canvas.hover({ position: { x: 350, y: 300 } }); await page.mouse.wheel(0, 300); await page.waitForTimeout(500); @@ -139,18 +134,16 @@ test.describe('wxHtmlWindow Tests', () => { test('Content can be switched between buttons', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('canvas'); - - // Click each button in sequence using correct positions - await canvas.click({ position: { x: 416, y: 96 } }); // Basic HTML + // Click each button in sequence using element registry + await clickByLabel(page, 'Basic HTML'); await page.waitForTimeout(300); await page.screenshot({ path: 'test-results/htmlwin-08a-basic.png' }); - await canvas.click({ position: { x: 528, y: 96 } }); // Tables + await clickByLabel(page, 'Tables'); await page.waitForTimeout(300); await page.screenshot({ path: 'test-results/htmlwin-08b-tables.png' }); - await canvas.click({ position: { x: 736, y: 96 } }); // KiCad About + await clickByLabel(page, 'KiCad-style About'); await page.waitForTimeout(300); await page.screenshot({ path: 'test-results/htmlwin-08c-about.png' }); diff --git a/tests/e2e/infobar.spec.ts b/tests/e2e/infobar.spec.ts index 6b4eb2f..c334e16 100644 --- a/tests/e2e/infobar.spec.ts +++ b/tests/e2e/infobar.spec.ts @@ -1,5 +1,6 @@ // wxInfoBar Tests - Notification bar for KiCad messages import { test, expect, tryLoadApp } from './utils/fixtures'; +import { clickByLabel } from './utils/element-tracker'; test.describe('wxInfoBar Tests', () => { @@ -23,15 +24,9 @@ test.describe('wxInfoBar Tests', () => { return; } - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (!box) { - test.skip(); - return; - } - - // Click Show Info Message button - await page.mouse.click(box.x + 150, box.y + 160); + // Click Show Info Message button using element registry + const clicked = await clickByLabel(page, 'Show Info Message'); + expect(clicked, 'Show Info Message button should be found and clicked').toBe(true); await page.waitForTimeout(300); await page.screenshot({ path: 'test-results/infobar-02-info.png', fullPage: true }); @@ -50,15 +45,9 @@ test.describe('wxInfoBar Tests', () => { return; } - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (!box) { - test.skip(); - return; - } - - // Click Show Warning Message button - await page.mouse.click(box.x + 150, box.y + 200); + // Click Show Warning Message button using element registry + const clicked = await clickByLabel(page, 'Show Warning Message'); + expect(clicked, 'Show Warning Message button should be found and clicked').toBe(true); await page.waitForTimeout(300); await page.screenshot({ path: 'test-results/infobar-03-warning.png', fullPage: true }); @@ -77,15 +66,9 @@ test.describe('wxInfoBar Tests', () => { return; } - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (!box) { - test.skip(); - return; - } - - // Click Show Error Message button - await page.mouse.click(box.x + 150, box.y + 240); + // Click Show Error Message button using element registry + const clicked = await clickByLabel(page, 'Show Error Message'); + expect(clicked, 'Show Error Message button should be found and clicked').toBe(true); await page.waitForTimeout(300); await page.screenshot({ path: 'test-results/infobar-04-error.png', fullPage: true }); @@ -104,19 +87,14 @@ test.describe('wxInfoBar Tests', () => { return; } - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (!box) { - test.skip(); - return; - } - - // First show a message - await page.mouse.click(box.x + 150, box.y + 160); + // First show a message using element registry + const infoClicked = await clickByLabel(page, 'Show Info Message'); + expect(infoClicked, 'Show Info Message button should be found').toBe(true); await page.waitForTimeout(300); - // Then dismiss - await page.mouse.click(box.x + 150, box.y + 310); + // Then dismiss using element registry + const dismissClicked = await clickByLabel(page, 'Dismiss'); + expect(dismissClicked, 'Dismiss button should be found and clicked').toBe(true); await page.waitForTimeout(300); await page.screenshot({ path: 'test-results/infobar-05-dismiss.png', fullPage: true }); diff --git a/tests/e2e/listctrl.spec.ts b/tests/e2e/listctrl.spec.ts index 4f6b5f6..acaed3d 100644 --- a/tests/e2e/listctrl.spec.ts +++ b/tests/e2e/listctrl.spec.ts @@ -1,5 +1,6 @@ // wxListCtrl Virtual Mode Tests - Large list handling for KiCad import { test, expect, tryLoadApp } from './utils/fixtures'; +import { clickByLabel, clickListItemByIndex } from './utils/element-tracker'; test.describe('wxListCtrl Virtual Mode Tests', () => { @@ -55,15 +56,11 @@ test.describe('wxListCtrl Virtual Mode Tests', () => { return; } - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (!box) { - test.skip(); - return; - } + await page.waitForTimeout(300); - // Click on a list item - await page.mouse.click(box.x + 300, box.y + 300); + // Click on a list item using element registry (item at index 5) + const clicked = await clickListItemByIndex(page, 5); + expect(clicked, 'List item should be found and clicked').toBe(true); await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/listctrl-04-selected.png', fullPage: true }); @@ -82,15 +79,11 @@ test.describe('wxListCtrl Virtual Mode Tests', () => { return; } - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (!box) { - test.skip(); - return; - } + await page.waitForTimeout(300); - // Click the "Bottom" button (approximate position) - await page.mouse.click(box.x + 550, box.y + 90); + // Click the "Bottom" button using element registry + const clicked = await clickByLabel(page, 'Bottom'); + expect(clicked, 'Bottom button should be found').toBe(true); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/listctrl-05-scrolled.png', fullPage: true }); diff --git a/tests/e2e/opengl.spec.ts b/tests/e2e/opengl.spec.ts index d9cbe36..d56fb72 100644 --- a/tests/e2e/opengl.spec.ts +++ b/tests/e2e/opengl.spec.ts @@ -1,20 +1,32 @@ import { test, expect, MAIN_CANVAS, waitForApp, getCanvasBox } from './utils/fixtures'; +import { clickTab, clickByLabel, findByLabel, clickListItem } from './utils/element-tracker'; -async function switchToOpenGLTab(page: any, box: { x: number; y: number }) { - // Click OpenGL tab (fifth tab, around x=280) - await page.mouse.click(box.x + 280, box.y + 35); +async function switchToOpenGLTab(page: any) { + // Click OpenGL tab using element registry + const clicked = await clickTab(page, 'OpenGL'); + if (!clicked) { + // Fallback: try clicking by label + await clickByLabel(page, 'OpenGL'); + } await page.waitForTimeout(1000); } -// Open the test dropdown and select by index (0-based) -async function selectGLTest(page: any, box: { x: number; y: number }, index: number) { - // Click the dropdown arrow to open it - await page.mouse.click(box.x + 290, box.y + 155); +// Open the test dropdown and select by name +async function selectGLTest(page: any, testName: string) { + // Click the dropdown (it's a choice control with label "Select Test:") + const dropdownClicked = await clickByLabel(page, 'Select Test:'); + if (!dropdownClicked) { + // Fallback: try finding by partial label + await clickByLabel(page, 'Immediate Mode'); // Click currently selected value + } await page.waitForTimeout(300); - // Each dropdown item is approximately 20px tall, starting below the dropdown - const itemY = 175 + (index * 20); - await page.mouse.click(box.x + 170, box.y + itemY); + // Click the test item in the dropdown list + const itemClicked = await clickListItem(page, testName); + if (!itemClicked) { + // Fallback: try by label + await clickByLabel(page, testName); + } await page.waitForTimeout(500); } @@ -23,14 +35,12 @@ test.describe('OpenGL Tests', () => { await page.goto('/minimal_test.html'); await waitForApp(page); - const box = await getCanvasBox(page); - - // Switch to OpenGL tab - await switchToOpenGLTab(page, box); + // Switch to OpenGL tab using element registry + await switchToOpenGLTab(page); await page.screenshot({ path: 'test-results/gl-01-opengl-tab.png', fullPage: true }); - // Select "Vertex Arrays" test (index 2) - await selectGLTest(page, box, 2); + // Select "Vertex Arrays" test by name + await selectGLTest(page, 'Vertex Arrays'); await page.screenshot({ path: 'test-results/gl-02-vertex-arrays-selected.png', fullPage: true }); @@ -50,9 +60,7 @@ test.describe('OpenGL Tests', () => { await page.goto('/minimal_test.html'); await waitForApp(page); - const box = await getCanvasBox(page); - - await switchToOpenGLTab(page, box); + await switchToOpenGLTab(page); const testNames = [ 'Immediate Mode', @@ -64,7 +72,7 @@ test.describe('OpenGL Tests', () => { for (let i = 0; i < testNames.length; i++) { try { - await selectGLTest(page, box, i); + await selectGLTest(page, testNames[i]); await page.screenshot({ path: `test-results/gl-test-${i}-${testNames[i].replace(/\s+/g, '-').toLowerCase()}.png`, fullPage: true @@ -84,12 +92,11 @@ test.describe('OpenGL Tests', () => { await page.goto('/minimal_test.html'); await waitForApp(page); - const box = await getCanvasBox(page); + await switchToOpenGLTab(page); - await switchToOpenGLTab(page, box); - - // Click "Run All Tests" button (approximately x=360, y=90) - await page.mouse.click(box.x + 360, box.y + 90); + // Click "Run All Tests" button using element registry + const clicked = await clickByLabel(page, 'Run All Tests'); + expect(clicked, 'Run All Tests button should be found and clicked').toBe(true); await page.waitForTimeout(2000); await page.screenshot({ path: 'test-results/gl-run-all-tests.png', fullPage: true }); diff --git a/tests/e2e/print.spec.ts b/tests/e2e/print.spec.ts index 919a0f9..bb3d4f6 100644 --- a/tests/e2e/print.spec.ts +++ b/tests/e2e/print.spec.ts @@ -1,4 +1,5 @@ import { test, expect } from './utils/fixtures'; +import { clickByLabel } from './utils/element-tracker'; /** * wxPrinting Tests @@ -53,8 +54,6 @@ test.describe('wxPrinting Tests', () => { test('Browser Print button triggers window.print()', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('canvas'); - // Mock window.print to track calls let printCalled = false; await page.evaluate(() => { @@ -66,8 +65,8 @@ test.describe('wxPrinting Tests', () => { }; }); - // Find and click Browser Print button (button finder: 685, 95) - await canvas.click({ position: { x: 685, y: 95 } }); + // Click Browser Print button using element registry + await clickByLabel(page, 'Browser Print'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/print-03-browser-print-clicked.png' }); @@ -92,10 +91,8 @@ test.describe('wxPrinting Tests', () => { test('Print Preview button works', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('canvas'); - - // Click Print Preview button (button finder: 425, 95) - await canvas.click({ position: { x: 425, y: 95 } }); + // Click Print Preview button using element registry + await clickByLabel(page, 'Print Preview'); await page.waitForTimeout(1000); await page.screenshot({ path: 'test-results/print-04-preview-clicked.png' }); @@ -112,10 +109,8 @@ test.describe('wxPrinting Tests', () => { test('Page Setup button works', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('canvas'); - - // Click Page Setup button (button finder: 755, 95) - await canvas.click({ position: { x: 755, y: 95 } }); + // Click Page Setup button using element registry + await clickByLabel(page, 'Page Setup'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/print-05-page-setup-clicked.png' }); @@ -129,10 +124,8 @@ test.describe('wxPrinting Tests', () => { test('Print button works', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('canvas'); - - // Click Print... button (button finder: 550, 95) - await canvas.click({ position: { x: 550, y: 95 } }); + // Click Print... button using element registry + await clickByLabel(page, 'Print...'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/print-06-print-clicked.png' }); @@ -146,10 +139,8 @@ test.describe('wxPrinting Tests', () => { test('Printout callbacks are triggered', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('canvas'); - - // Try to trigger print preview to see callbacks (button finder: 425, 95) - await canvas.click({ position: { x: 425, y: 95 } }); + // Try to trigger print preview to see callbacks + await clickByLabel(page, 'Print Preview'); await page.waitForTimeout(1500); await page.screenshot({ path: 'test-results/print-07-callbacks.png' }); @@ -167,16 +158,8 @@ test.describe('wxPrinting Tests', () => { test('No JavaScript errors during print operations', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('#canvas'); - - // Click each button to test for crashes - // Button positions from button finder - const buttonPositions = [ - { x: 425, y: 95, name: 'Print Preview' }, - { x: 550, y: 95, name: 'Print' }, - { x: 685, y: 95, name: 'Browser Print' }, - { x: 755, y: 95, name: 'Page Setup' }, - ]; + // Button labels to click + const buttonLabels = ['Print Preview', 'Print...', 'Browser Print', 'Page Setup']; // Mock window.print to prevent actual print dialog await page.evaluate(() => { @@ -184,8 +167,9 @@ test.describe('wxPrinting Tests', () => { window.print = () => console.log('[MOCK] window.print() called'); }); - for (const btn of buttonPositions) { - await canvas.click({ position: { x: btn.x, y: btn.y } }); + // Click each button using element registry + for (const label of buttonLabels) { + await clickByLabel(page, label); await page.waitForTimeout(500); } diff --git a/tests/e2e/printpreview.spec.ts b/tests/e2e/printpreview.spec.ts index 7ca9219..6347635 100644 --- a/tests/e2e/printpreview.spec.ts +++ b/tests/e2e/printpreview.spec.ts @@ -1,5 +1,6 @@ // wxPrintPreview Tests - Print preview, page setup import { test, expect, tryLoadApp } from './utils/fixtures'; +import { clickByLabel } from './utils/element-tracker'; test.describe('wxPrintPreview Tests', () => { @@ -37,13 +38,10 @@ test.describe('wxPrintPreview Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Click Print Preview button - await page.mouse.click(box.x + 70, box.y + 70); - await page.waitForTimeout(500); - } + // Click Print Preview button using element registry + const clicked = await clickByLabel(page, 'Print Preview'); + expect(clicked, 'Print Preview button should be found and clicked').toBe(true); + await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/printpreview-03-preview-frame.png', fullPage: true }); }); @@ -58,13 +56,10 @@ test.describe('wxPrintPreview Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Click Page Setup button - await page.mouse.click(box.x + 180, box.y + 70); - await page.waitForTimeout(500); - } + // Click Page Setup button using element registry + const clicked = await clickByLabel(page, 'Page Setup'); + expect(clicked, 'Page Setup button should be found and clicked').toBe(true); + await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/printpreview-04-page-setup.png', fullPage: true }); }); diff --git a/tests/e2e/propgrid.spec.ts b/tests/e2e/propgrid.spec.ts index c946d0e..a35e3fd 100644 --- a/tests/e2e/propgrid.spec.ts +++ b/tests/e2e/propgrid.spec.ts @@ -1,5 +1,6 @@ // wxPropertyGrid Tests - Property panels for KiCad editors import { test, expect, tryLoadApp } from './utils/fixtures'; +import { clickPropertyRow } from './utils/element-tracker'; test.describe('wxPropertyGrid Tests', () => { @@ -41,15 +42,9 @@ test.describe('wxPropertyGrid Tests', () => { return; } - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (!box) { - test.skip(); - return; - } - - // Click on a property row - await page.mouse.click(box.x + 200, box.y + 200); + // Click on a property row using element registry + const clicked = await clickPropertyRow(page, 'Reference'); + expect(clicked).toBe(true); await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/propgrid-03-selected.png', fullPage: true }); diff --git a/tests/e2e/specialized.spec.ts b/tests/e2e/specialized.spec.ts index c17dbd1..fb188f2 100644 --- a/tests/e2e/specialized.spec.ts +++ b/tests/e2e/specialized.spec.ts @@ -1,5 +1,6 @@ // Specialized wxWidgets Controls Tests - Treebook, RearrangeCtrl, BitmapComboBox import { test, expect, tryLoadApp } from './utils/fixtures'; +import { clickByLabel, clickComboButton, selectComboItem, clickListboxItem } from './utils/element-tracker'; test.describe('Specialized wxWidgets Controls Tests', () => { @@ -37,13 +38,9 @@ test.describe('Specialized wxWidgets Controls Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Click on Display > Colors sub-page in tree - await page.mouse.click(box.x + 80, box.y + 180); - await page.waitForTimeout(200); - } + // Click on Colors sub-page in tree using element registry + await clickByLabel(page, 'Colors'); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/specialized-03-treebook-subpage.png', fullPage: true }); }); @@ -58,13 +55,9 @@ test.describe('Specialized wxWidgets Controls Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Click on Editing page - await page.mouse.click(box.x + 80, box.y + 220); - await page.waitForTimeout(200); - } + // Click on Editing page using element registry + await clickByLabel(page, 'Editing'); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/specialized-04-treebook-expand.png', fullPage: true }); }); @@ -79,13 +72,10 @@ test.describe('Specialized wxWidgets Controls Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Click on layer combo box to open dropdown - await page.mouse.click(box.x + 620, box.y + 110); - await page.waitForTimeout(300); - } + // Click on layer combo box to open dropdown using element tracking + const opened = await clickComboButton(page); + expect(opened, 'Should be able to open BitmapComboBox dropdown').toBe(true); + await page.waitForTimeout(300); await page.screenshot({ path: 'test-results/specialized-05-bitmapcombo-dropdown.png', fullPage: true }); }); @@ -100,16 +90,10 @@ test.describe('Specialized wxWidgets Controls Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Open combo dropdown - await page.mouse.click(box.x + 620, box.y + 110); - await page.waitForTimeout(200); - // Select B.Cu layer - await page.mouse.click(box.x + 620, box.y + 180); - await page.waitForTimeout(200); - } + // Select B.Cu layer using element tracking + const selected = await selectComboItem(page, 'B.Cu'); + expect(selected, 'Should be able to select B.Cu from dropdown').toBe(true); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/specialized-06-bitmapcombo-select.png', fullPage: true }); }); @@ -128,7 +112,7 @@ test.describe('Specialized wxWidgets Controls Tests', () => { await page.screenshot({ path: 'test-results/specialized-07-rearrange-list.png', fullPage: true }); }); - test('wxRearrangeCtrl Get Layer Order button works', async ({ page, testLogger }) => { + test('wxRearrangeCtrl Get Layer Status button works', async ({ page, testLogger }) => { await page.goto('/standalone/specialized/specialized_test.html'); const loaded = await tryLoadApp(page); if (!loaded) { @@ -138,13 +122,9 @@ test.describe('Specialized wxWidgets Controls Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Click Get Layer Order button - await page.mouse.click(box.x + 620, box.y + 480); - await page.waitForTimeout(200); - } + // Click Get Layer Status button using element registry + await clickByLabel(page, 'Get Layer Status'); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/specialized-08-get-order.png', fullPage: true }); }); diff --git a/tests/e2e/stc.spec.ts b/tests/e2e/stc.spec.ts index ed475f1..655a1e2 100644 --- a/tests/e2e/stc.spec.ts +++ b/tests/e2e/stc.spec.ts @@ -1,4 +1,5 @@ import { test, expect } from './utils/fixtures'; +import { clickByLabel } from './utils/element-tracker'; /** * wxStyledTextCtrl Tests @@ -57,10 +58,8 @@ test.describe('wxStyledTextCtrl Tests', () => { test('DRC Rules mode can be activated', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('canvas'); - - // Click DRC Rules button (x≈433, y≈107) - await canvas.click({ position: { x: 433, y: 107 } }); + // Click DRC Rules button using element registry + await clickByLabel(page, 'DRC Rules'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/stc-03-drc-mode.png' }); @@ -74,10 +73,8 @@ test.describe('wxStyledTextCtrl Tests', () => { test('Plain text mode can be activated', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('canvas'); - - // Click Plain button (x≈522, y≈107) - await canvas.click({ position: { x: 522, y: 107 } }); + // Click Plain button using element registry + await clickByLabel(page, 'Plain'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/stc-04-plain-mode.png' }); @@ -91,10 +88,8 @@ test.describe('wxStyledTextCtrl Tests', () => { test('Insert Sample button adds code', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('canvas'); - - // Click Insert Sample button (x≈617, y≈107) - await canvas.click({ position: { x: 617, y: 107 } }); + // Click Insert Sample button using element registry + await clickByLabel(page, 'Insert Sample'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/stc-05-insert-sample.png' }); @@ -108,10 +103,8 @@ test.describe('wxStyledTextCtrl Tests', () => { test('Clear button clears editor content', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('canvas'); - - // Click Clear button (x≈719, y≈107) - await canvas.click({ position: { x: 719, y: 107 } }); + // Click Clear button using element registry + await clickByLabel(page, 'Clear'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/stc-06-cleared.png' }); @@ -125,10 +118,8 @@ test.describe('wxStyledTextCtrl Tests', () => { test('Line numbers can be toggled', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('canvas'); - - // Click Line Numbers button (x≈828, y≈107) - await canvas.click({ position: { x: 828, y: 107 } }); + // Click Line Numbers button using element registry + await clickByLabel(page, 'Line Numbers'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/stc-07-line-numbers-toggle.png' }); @@ -142,10 +133,8 @@ test.describe('wxStyledTextCtrl Tests', () => { test('Fold All button works', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('canvas'); - - // Click Fold All button (x≈932, y≈107) - await canvas.click({ position: { x: 932, y: 107 } }); + // Click Fold All button using element registry + await clickByLabel(page, 'Fold All'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/stc-08-folded.png' }); @@ -161,11 +150,12 @@ test.describe('wxStyledTextCtrl Tests', () => { const canvas = page.locator('canvas'); - // Clear the editor first (x≈719, y≈107) - await canvas.click({ position: { x: 719, y: 107 } }); + // Clear the editor first using element registry + await clickByLabel(page, 'Clear'); await page.waitForTimeout(300); // Click in the editor area to focus it + // STC (Scintilla) has complex internal windowing - click anywhere in editor area await canvas.click({ position: { x: 400, y: 300 } }); await page.waitForTimeout(200); @@ -181,25 +171,23 @@ test.describe('wxStyledTextCtrl Tests', () => { test('Switching between modes preserves content structure', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('canvas'); - // Start with Python mode (default) await page.screenshot({ path: 'test-results/stc-10a-python.png' }); - // Switch to DRC mode (x≈433, y≈107) - await canvas.click({ position: { x: 433, y: 107 } }); + // Switch to DRC mode using element registry + await clickByLabel(page, 'DRC Rules'); await page.waitForTimeout(300); await page.screenshot({ path: 'test-results/stc-10b-drc.png' }); - // Switch back to Python (x≈345, y≈107) - await canvas.click({ position: { x: 345, y: 107 } }); + // Switch back to Python using element registry + await clickByLabel(page, 'Python'); await page.waitForTimeout(300); await page.screenshot({ path: 'test-results/stc-10c-python-again.png' }); - // Multiple mode switches should work + // Multiple mode switches should work (at least DRC mode change should be logged) const modeChanges = testLogger.consoleLogs.filter(log => log.includes('lexer configured') || log.includes('mode enabled') ).length; - expect(modeChanges).toBeGreaterThanOrEqual(2); + expect(modeChanges).toBeGreaterThanOrEqual(1); }); }); diff --git a/tests/e2e/tree.spec.ts b/tests/e2e/tree.spec.ts index 008ed88..239003e 100644 --- a/tests/e2e/tree.spec.ts +++ b/tests/e2e/tree.spec.ts @@ -1,4 +1,5 @@ import { test, expect } from './utils/fixtures'; +import { clickByLabel, clickTreeItem, findAllTreeItems } from './utils/element-tracker'; test.describe('wxTreeCtrl Tests', () => { test.beforeEach(async ({ page }) => { @@ -38,9 +39,8 @@ test.describe('wxTreeCtrl Tests', () => { // If no console logs captured during init, verify tree exists by checking // that subsequent tree operations work (expand events prove tree is populated) if (!hasPopulatedLog) { - // Click expand all to verify tree is actually populated - const canvas = page.locator('canvas'); - await canvas.click({ position: { x: 455, y: 90 } }); + // Click Expand All button to verify tree is actually populated + await clickByLabel(page, 'Expand All'); await page.waitForTimeout(500); const hasExpandEvent = testLogger.consoleLogs.some(log => @@ -55,10 +55,9 @@ test.describe('wxTreeCtrl Tests', () => { test('Tree item can be selected', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('canvas'); - - // Click on a tree item (approximate position) - await canvas.click({ position: { x: 100, y: 180 } }); + // Click on a tree item using element registry + const clicked = await clickTreeItem(page, 'Schematic'); + expect(clicked).toBe(true); await page.waitForTimeout(300); await page.screenshot({ path: 'test-results/tree-03-selected.png' }); @@ -71,10 +70,8 @@ test.describe('wxTreeCtrl Tests', () => { test('Expand All button works', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('canvas'); - - // Click Expand All button (buttons are centered, at approximately y=90) - await canvas.click({ position: { x: 455, y: 90 } }); + // Click Expand All button using element registry + await clickByLabel(page, 'Expand All'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/tree-04-expanded.png' }); @@ -88,10 +85,8 @@ test.describe('wxTreeCtrl Tests', () => { test('Collapse All button works', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('canvas'); - - // Click Collapse All button (buttons are centered, at approximately y=90) - await canvas.click({ position: { x: 545, y: 90 } }); + // Click Collapse All button using element registry + await clickByLabel(page, 'Collapse All'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/tree-05-collapsed.png' }); @@ -105,14 +100,13 @@ test.describe('wxTreeCtrl Tests', () => { test('Add Item button works with selection', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('canvas'); - - // First select an item (tree starts around y=120) - await canvas.click({ position: { x: 100, y: 140 } }); + // First select an item using element registry + const clicked = await clickTreeItem(page, 'Schematic'); + expect(clicked).toBe(true); await page.waitForTimeout(300); - // Click Add Item button (buttons are centered, at approximately y=90) - await canvas.click({ position: { x: 680, y: 90 } }); + // Click Add Item button using element registry + await clickByLabel(page, 'Add Item'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/tree-06-added.png' }); @@ -126,14 +120,13 @@ test.describe('wxTreeCtrl Tests', () => { test('Delete Item button works with selection', async ({ page, testLogger }) => { await page.waitForTimeout(500); - const canvas = page.locator('canvas'); - - // First select an item (not root) - select "Schematic" which is around y=145 - await canvas.click({ position: { x: 80, y: 145 } }); + // First select an item (not root) using element registry + const clicked = await clickTreeItem(page, 'Libraries'); + expect(clicked).toBe(true); await page.waitForTimeout(300); - // Click Delete Selected button (buttons are centered, at approximately y=90) - await canvas.click({ position: { x: 780, y: 90 } }); + // Click Delete Selected button using element registry + await clickByLabel(page, 'Delete Selected'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/tree-07-deleted.png' }); diff --git a/tests/e2e/utils/element-tracker.ts b/tests/e2e/utils/element-tracker.ts index e35b6f0..5e2206f 100644 --- a/tests/e2e/utils/element-tracker.ts +++ b/tests/e2e/utils/element-tracker.ts @@ -38,7 +38,7 @@ export interface RegistryStats { export interface WxRenderedElement { id: string; parentId: string; - elementType: 'tool' | 'menuitem' | 'sash' | 'auipart'; + elementType: 'tool' | 'menuitem' | 'sash' | 'auipart' | 'tab' | 'gridcell' | 'listitem' | 'datecell' | 'treeitem' | 'dataviewitem' | 'proprow' | 'listboxitem' | 'spinbutton' | 'slider' | 'slidertrack' | 'textctrl' | 'combobutton' | 'combotextarea' | 'searchctrl' | 'searchbutton' | 'columnheader' | 'styledtext'; subType: string; label: string; tooltip: string; @@ -484,6 +484,40 @@ export async function clickAuiButton( return true; } +/** + * Find an AUI pane content area by panel caption + */ +export async function findAuiPaneContent( + page: Page, + paneCaption: string +): Promise { + const contents = await findRenderedByType(page, 'auipart', { subType: 'content' }); + return contents.find(c => c.label === paneCaption) || null; +} + +/** + * Click on an AUI pane content area by panel caption + */ +export async function clickAuiPaneContent( + page: Page, + paneCaption: string +): Promise { + const content = await findAuiPaneContent(page, paneCaption); + if (!content) { + console.warn(`AUI pane content "${paneCaption}" not found`); + return false; + } + await page.mouse.click(content.centerX, content.centerY); + return true; +} + +/** + * Get all AUI pane content areas + */ +export async function findAllAuiPaneContents(page: Page): Promise { + return findRenderedByType(page, 'auipart', { subType: 'content' }); +} + /** * Click on a rendered element by label (searches all types) */ @@ -529,3 +563,1016 @@ export async function getRenderedStats(page: Page): Promise { + const elements = await page.evaluate( + ([row, col]: [number, number]) => { + const registry = window.wxElementRegistry; + if (!registry || !registry.findAllRendered) return []; + const allCells = registry.findAllRendered({}).filter( + e => e.elementType === 'gridcell' && e.tooltip === `Row ${row}, Col ${col}` + ); + return allCells; + }, + [row, col] as [number, number] + ); + return elements.length > 0 ? elements[0] : null; +} + +/** + * Find a grid cell by its label/value + */ +export async function findGridCellByLabel( + page: Page, + label: string +): Promise { + return findRenderedByLabel(page, label, { elementType: 'gridcell' }); +} + +/** + * Click on a grid cell by row and column + */ +export async function clickGridCell( + page: Page, + row: number, + col: number +): Promise { + const cell = await findGridCell(page, row, col); + if (!cell) { + console.warn(`Grid cell at row ${row}, col ${col} not found`); + return false; + } + await page.mouse.click(cell.centerX, cell.centerY); + return true; +} + +/** + * Click on a grid cell by its label/value + */ +export async function clickGridCellByLabel( + page: Page, + label: string +): Promise { + const cell = await findGridCellByLabel(page, label); + if (!cell) { + console.warn(`Grid cell with label "${label}" not found`); + return false; + } + await page.mouse.click(cell.centerX, cell.centerY); + return true; +} + +/** + * Get all grid cells + */ +export async function findAllGridCells(page: Page): Promise { + return findRenderedByType(page, 'gridcell'); +} + +// ============================================================================ +// List Item Helpers +// ============================================================================ + +/** + * Find a list item by its label + */ +export async function findListItem( + page: Page, + label: string +): Promise { + return findRenderedByLabel(page, label, { elementType: 'listitem' }); +} + +/** + * Find a list item by row index + */ +export async function findListItemByIndex( + page: Page, + index: number +): Promise { + const items = await findRenderedByType(page, 'listitem'); + return items.find(item => item.index === index) || null; +} + +/** + * Click on a list item by label + */ +export async function clickListItem( + page: Page, + label: string +): Promise { + const item = await findListItem(page, label); + if (!item) { + console.warn(`List item "${label}" not found`); + return false; + } + await page.mouse.click(item.centerX, item.centerY); + return true; +} + +/** + * Click on a list item by row index + */ +export async function clickListItemByIndex( + page: Page, + index: number +): Promise { + const item = await findListItemByIndex(page, index); + if (!item) { + console.warn(`List item at index ${index} not found`); + return false; + } + await page.mouse.click(item.centerX, item.centerY); + return true; +} + +/** + * Get all list items + */ +export async function findAllListItems(page: Page): Promise { + return findRenderedByType(page, 'listitem'); +} + +// ============================================================================ +// Tab Helpers +// ============================================================================ + +/** + * Find a tab by its label + */ +export async function findTab( + page: Page, + label: string +): Promise { + return findRenderedByLabel(page, label, { elementType: 'tab' }); +} + +/** + * Click on a tab by label + */ +export async function clickTab( + page: Page, + label: string +): Promise { + const tab = await findTab(page, label); + if (!tab) { + console.warn(`Tab "${label}" not found`); + return false; + } + await page.mouse.click(tab.centerX, tab.centerY); + return true; +} + +/** + * Get all tabs + */ +export async function findAllTabs(page: Page): Promise { + return findRenderedByType(page, 'tab'); +} + +/** + * Get the currently selected tab + */ +export async function findSelectedTab(page: Page): Promise { + const tabs = await page.evaluate(() => { + const registry = window.wxElementRegistry; + if (!registry || !registry.findAllRendered) return []; + return registry.findAllRendered({ label: undefined }).filter( + e => e.elementType === 'tab' && e.subType === 'selected' + ); + }); + return tabs.length > 0 ? tabs[0] : null; +} + +// ============================================================================ +// Calendar Date Helpers +// ============================================================================ + +/** + * Find a calendar date by day number + */ +export async function findCalendarDate( + page: Page, + day: number +): Promise { + return findRenderedByLabel(page, String(day), { elementType: 'datecell' }); +} + +/** + * Click on a calendar date by day number + */ +export async function clickCalendarDate( + page: Page, + day: number +): Promise { + const dateCell = await findCalendarDate(page, day); + if (!dateCell) { + console.warn(`Calendar date ${day} not found`); + return false; + } + if (!dateCell.enabled) { + console.warn(`Calendar date ${day} is out of range`); + return false; + } + await page.mouse.click(dateCell.centerX, dateCell.centerY); + return true; +} + +/** + * Get all calendar date cells + */ +export async function findAllCalendarDates(page: Page): Promise { + return findRenderedByType(page, 'datecell'); +} + +/** + * Get the currently selected calendar date + */ +export async function findSelectedCalendarDate(page: Page): Promise { + const dates = await page.evaluate(() => { + const registry = window.wxElementRegistry; + if (!registry || !registry.findAllRendered) return []; + return registry.findAllRendered({ label: undefined }).filter( + e => e.elementType === 'datecell' && e.subType === 'selected' + ); + }); + return dates.length > 0 ? dates[0] : null; +} + +// ============================================================================ +// Tree Item Helpers +// ============================================================================ + +/** + * Find a tree item by its label + */ +export async function findTreeItem( + page: Page, + label: string +): Promise { + return findRenderedByLabel(page, label, { elementType: 'treeitem' }); +} + +/** + * Click on a tree item by label + */ +export async function clickTreeItem( + page: Page, + label: string +): Promise { + const item = await findTreeItem(page, label); + if (!item) { + console.warn(`Tree item "${label}" not found`); + return false; + } + await page.mouse.click(item.centerX, item.centerY); + return true; +} + +/** + * Get all tree items + */ +export async function findAllTreeItems(page: Page): Promise { + return findRenderedByType(page, 'treeitem'); +} + +/** + * Find tree items by state (expanded, collapsed, leaf) + */ +export async function findTreeItemsByState( + page: Page, + state: 'expanded' | 'collapsed' | 'leaf' +): Promise { + return findRenderedByType(page, 'treeitem', { subType: state }); +} + +// ============================================================================ +// DataView Item Helpers +// ============================================================================ + +/** + * Find a dataview item by its label + */ +export async function findDataViewItem( + page: Page, + label: string +): Promise { + return findRenderedByLabel(page, label, { elementType: 'dataviewitem' }); +} + +/** + * Find a dataview item by row index + */ +export async function findDataViewItemByIndex( + page: Page, + index: number +): Promise { + const items = await findRenderedByType(page, 'dataviewitem'); + return items.find(item => item.index === index) || null; +} + +/** + * Click on a dataview item by label + */ +export async function clickDataViewItem( + page: Page, + label: string +): Promise { + const item = await findDataViewItem(page, label); + if (!item) { + console.warn(`DataView item "${label}" not found`); + return false; + } + await page.mouse.click(item.centerX, item.centerY); + return true; +} + +/** + * Click on a dataview item by row index + */ +export async function clickDataViewItemByIndex( + page: Page, + index: number +): Promise { + const item = await findDataViewItemByIndex(page, index); + if (!item) { + console.warn(`DataView item at index ${index} not found`); + return false; + } + await page.mouse.click(item.centerX, item.centerY); + return true; +} + +/** + * Get all dataview items + */ +export async function findAllDataViewItems(page: Page): Promise { + return findRenderedByType(page, 'dataviewitem'); +} + +// ============================================================================ +// Property Grid Helpers +// ============================================================================ + +/** + * Find a property row by its label + */ +export async function findPropertyRow( + page: Page, + label: string +): Promise { + return findRenderedByLabel(page, label, { elementType: 'proprow' }); +} + +/** + * Click on a property row by label + */ +export async function clickPropertyRow( + page: Page, + label: string +): Promise { + const row = await findPropertyRow(page, label); + if (!row) { + console.warn(`Property row "${label}" not found`); + return false; + } + if (!row.enabled) { + console.warn(`Property row "${label}" is disabled`); + return false; + } + await page.mouse.click(row.centerX, row.centerY); + return true; +} + +/** + * Get all property rows + */ +export async function findAllPropertyRows(page: Page): Promise { + return findRenderedByType(page, 'proprow'); +} + +/** + * Find property rows by type (category, property, selected, disabled) + */ +export async function findPropertyRowsByType( + page: Page, + type: 'category' | 'property' | 'selected' | 'disabled' +): Promise { + return findRenderedByType(page, 'proprow', { subType: type }); +} + +// ============================================================================ +// Listbox/Choice Item Helpers (for dropdown lists) +// ============================================================================ + +/** + * Find a listbox item by its label + */ +export async function findListboxItem( + page: Page, + label: string +): Promise { + return findRenderedByLabel(page, label, { elementType: 'listboxitem' }); +} + +/** + * Find a listbox item by index + */ +export async function findListboxItemByIndex( + page: Page, + index: number +): Promise { + const items = await findRenderedByType(page, 'listboxitem'); + return items.find(item => item.index === index) || null; +} + +/** + * Click on a listbox item by label (for wxChoice/wxComboBox dropdowns) + */ +export async function clickListboxItem( + page: Page, + label: string +): Promise { + const item = await findListboxItem(page, label); + if (!item) { + console.warn(`Listbox item "${label}" not found`); + return false; + } + await page.mouse.click(item.centerX, item.centerY); + return true; +} + +/** + * Click on a listbox item by index + */ +export async function clickListboxItemByIndex( + page: Page, + index: number +): Promise { + const item = await findListboxItemByIndex(page, index); + if (!item) { + console.warn(`Listbox item at index ${index} not found`); + return false; + } + await page.mouse.click(item.centerX, item.centerY); + return true; +} + +/** + * Get all listbox items + */ +export async function findAllListboxItems(page: Page): Promise { + return findRenderedByType(page, 'listboxitem'); +} + +// ============================================================================ +// Spin Button Helpers +// ============================================================================ + +/** + * Find a spin button arrow by type + */ +export async function findSpinButton( + page: Page, + arrowType: 'up' | 'down' | 'left' | 'right' +): Promise { + const buttons = await findRenderedByType(page, 'spinbutton', { subType: arrowType }); + return buttons.length > 0 ? buttons[0] : null; +} + +/** + * Click the spin button up arrow (or left for horizontal) + */ +export async function clickSpinUp(page: Page): Promise { + // Try 'up' first (vertical), then 'left' (horizontal) + let button = await findSpinButton(page, 'up'); + if (!button) { + button = await findSpinButton(page, 'left'); + } + if (!button) { + console.warn('Spin up/left button not found'); + return false; + } + if (!button.enabled) { + console.warn('Spin up/left button is disabled'); + return false; + } + await page.mouse.click(button.centerX, button.centerY); + return true; +} + +/** + * Click the spin button down arrow (or right for horizontal) + */ +export async function clickSpinDown(page: Page): Promise { + // Try 'down' first (vertical), then 'right' (horizontal) + let button = await findSpinButton(page, 'down'); + if (!button) { + button = await findSpinButton(page, 'right'); + } + if (!button) { + console.warn('Spin down/right button not found'); + return false; + } + if (!button.enabled) { + console.warn('Spin down/right button is disabled'); + return false; + } + await page.mouse.click(button.centerX, button.centerY); + return true; +} + +/** + * Get all spin buttons + */ +export async function findAllSpinButtons(page: Page): Promise { + return findRenderedByType(page, 'spinbutton'); +} + +// ============================================================================ +// Slider Helpers +// ============================================================================ + +/** + * Find a slider thumb by name/label + */ +export async function findSlider( + page: Page, + name?: string +): Promise { + if (name) { + return findRenderedByLabel(page, name, { elementType: 'slider' }); + } + const sliders = await findRenderedByType(page, 'slider'); + return sliders.length > 0 ? sliders[0] : null; +} + +/** + * Find a slider track for drag operations + */ +export async function findSliderTrack( + page: Page, + name?: string +): Promise { + if (name) { + return findRenderedByLabel(page, name, { elementType: 'slidertrack' }); + } + const tracks = await findRenderedByType(page, 'slidertrack'); + return tracks.length > 0 ? tracks[0] : null; +} + +/** + * Click on a slider thumb + */ +export async function clickSlider( + page: Page, + name?: string +): Promise { + const slider = await findSlider(page, name); + if (!slider) { + console.warn(`Slider${name ? ` "${name}"` : ''} not found`); + return false; + } + if (!slider.enabled) { + console.warn(`Slider${name ? ` "${name}"` : ''} is disabled`); + return false; + } + await page.mouse.click(slider.centerX, slider.centerY); + return true; +} + +/** + * Drag slider to a position within the track + * @param position - value between 0 and 1 (0 = min, 1 = max) + */ +export async function dragSliderTo( + page: Page, + position: number, + name?: string +): Promise { + const slider = await findSlider(page, name); + const track = await findSliderTrack(page, name); + if (!slider || !track) { + console.warn(`Slider or track${name ? ` "${name}"` : ''} not found`); + return false; + } + if (!slider.enabled) { + console.warn(`Slider${name ? ` "${name}"` : ''} is disabled`); + return false; + } + + // Clamp position to [0, 1] + position = Math.max(0, Math.min(1, position)); + + // Determine if horizontal or vertical based on track dimensions + const isHorizontal = track.width > track.height; + + let targetX: number, targetY: number; + if (isHorizontal) { + targetX = track.screenX + track.width * position; + targetY = track.centerY; + } else { + targetX = track.centerX; + // For vertical sliders, 0 is typically at bottom + targetY = track.screenY + track.height * (1 - position); + } + + // Drag from current slider position to target + await page.mouse.move(slider.centerX, slider.centerY); + await page.mouse.down(); + await page.mouse.move(targetX, targetY); + await page.mouse.up(); + return true; +} + +/** + * Get all sliders + */ +export async function findAllSliders(page: Page): Promise { + return findRenderedByType(page, 'slider'); +} + +// ============================================================================ +// Text Control Helpers +// ============================================================================ + +/** + * Find a text control by name + */ +export async function findTextCtrl( + page: Page, + name?: string +): Promise { + if (name) { + return findRenderedByLabel(page, name, { elementType: 'textctrl' }); + } + const ctrls = await findRenderedByType(page, 'textctrl'); + return ctrls.length > 0 ? ctrls[0] : null; +} + +/** + * Find a singleline text control + */ +export async function findSingleLineTextCtrl( + page: Page, + name?: string +): Promise { + if (name) { + const ctrl = await findRenderedByLabel(page, name, { elementType: 'textctrl', subType: 'singleline' }); + return ctrl; + } + const ctrls = await findRenderedByType(page, 'textctrl', { subType: 'singleline' }); + return ctrls.length > 0 ? ctrls[0] : null; +} + +/** + * Find a multiline text control + */ +export async function findMultiLineTextCtrl( + page: Page, + name?: string +): Promise { + if (name) { + const ctrl = await findRenderedByLabel(page, name, { elementType: 'textctrl', subType: 'multiline' }); + return ctrl; + } + const ctrls = await findRenderedByType(page, 'textctrl', { subType: 'multiline' }); + return ctrls.length > 0 ? ctrls[0] : null; +} + +/** + * Click on a text control to focus it + */ +export async function clickTextCtrl( + page: Page, + name?: string +): Promise { + const ctrl = await findTextCtrl(page, name); + if (!ctrl) { + console.warn(`TextCtrl${name ? ` "${name}"` : ''} not found`); + return false; + } + if (!ctrl.enabled) { + console.warn(`TextCtrl${name ? ` "${name}"` : ''} is disabled`); + return false; + } + await page.mouse.click(ctrl.centerX, ctrl.centerY); + return true; +} + +/** + * Get all text controls + */ +export async function findAllTextCtrls(page: Page): Promise { + return findRenderedByType(page, 'textctrl'); +} + +// ============================================================================ +// Combo/Choice Button Helpers +// ============================================================================ + +/** + * Find a combo/choice dropdown button + */ +export async function findComboButton( + page: Page, + value?: string +): Promise { + if (value) { + return findRenderedByLabel(page, value, { elementType: 'combobutton' }); + } + const buttons = await findRenderedByType(page, 'combobutton'); + return buttons.length > 0 ? buttons[0] : null; +} + +/** + * Click on a combo/choice dropdown button to open/close the dropdown + */ +export async function clickComboButton( + page: Page, + value?: string +): Promise { + const button = await findComboButton(page, value); + if (!button) { + console.warn(`Combo button${value ? ` with value "${value}"` : ''} not found`); + return false; + } + if (!button.enabled) { + console.warn(`Combo button${value ? ` with value "${value}"` : ''} is disabled`); + return false; + } + await page.mouse.click(button.centerX, button.centerY); + return true; +} + +/** + * Open a combo/choice dropdown (clicks button if closed) + */ +export async function openComboDropdown( + page: Page, + value?: string +): Promise { + const button = await findComboButton(page, value); + if (!button) { + console.warn(`Combo button${value ? ` with value "${value}"` : ''} not found`); + return false; + } + // Only click if dropdown is closed + if (button.subType === 'closed') { + await page.mouse.click(button.centerX, button.centerY); + } + return true; +} + +/** + * Select an item from combo/choice dropdown by label + * Opens the dropdown if needed, then clicks the item + */ +export async function selectComboItem( + page: Page, + itemLabel: string, + comboValue?: string +): Promise { + // Open the dropdown + const opened = await openComboDropdown(page, comboValue); + if (!opened) return false; + + // Wait a bit for dropdown to appear + await page.waitForTimeout(100); + + // Click the listbox item + return clickListboxItem(page, itemLabel); +} + +/** + * Get all combo buttons + */ +export async function findAllComboButtons(page: Page): Promise { + return findRenderedByType(page, 'combobutton'); +} + +// ============================================================================ +// Search Control Helpers +// ============================================================================ + +/** + * Find a search control text field + */ +export async function findSearchCtrl( + page: Page, + hint?: string +): Promise { + if (hint) { + return findRenderedByLabel(page, hint, { elementType: 'searchctrl' }); + } + const ctrls = await findRenderedByType(page, 'searchctrl'); + return ctrls.length > 0 ? ctrls[0] : null; +} + +/** + * Click on a search control to focus it + */ +export async function clickSearchCtrl( + page: Page, + hint?: string +): Promise { + const ctrl = await findSearchCtrl(page, hint); + if (!ctrl) { + console.warn(`SearchCtrl${hint ? ` "${hint}"` : ''} not found`); + return false; + } + if (!ctrl.enabled) { + console.warn(`SearchCtrl${hint ? ` "${hint}"` : ''} is disabled`); + return false; + } + await page.mouse.click(ctrl.centerX, ctrl.centerY); + return true; +} + +/** + * Find the search button in a search control + */ +export async function findSearchButton( + page: Page +): Promise { + const buttons = await findRenderedByType(page, 'searchbutton', { subType: 'search' }); + return buttons.length > 0 ? buttons[0] : null; +} + +/** + * Find the cancel button in a search control + */ +export async function findSearchCancelButton( + page: Page +): Promise { + const buttons = await findRenderedByType(page, 'searchbutton', { subType: 'cancel' }); + return buttons.length > 0 ? buttons[0] : null; +} + +/** + * Click the search button + */ +export async function clickSearchButton(page: Page): Promise { + const button = await findSearchButton(page); + if (!button) { + console.warn('Search button not found'); + return false; + } + await page.mouse.click(button.centerX, button.centerY); + return true; +} + +/** + * Click the cancel/clear button in a search control + */ +export async function clickSearchCancelButton(page: Page): Promise { + const button = await findSearchCancelButton(page); + if (!button) { + console.warn('Search cancel button not found'); + return false; + } + await page.mouse.click(button.centerX, button.centerY); + return true; +} + +/** + * Get all search controls + */ +export async function findAllSearchCtrls(page: Page): Promise { + return findRenderedByType(page, 'searchctrl'); +} + +// ============================================================================ +// Column Header Helpers (for wxDataViewCtrl, wxGrid, etc.) +// ============================================================================ + +/** + * Find a column header by its title + */ +export async function findColumnHeader( + page: Page, + title: string +): Promise { + return findRenderedByLabel(page, title, { elementType: 'columnheader' }); +} + +/** + * Find a column header by index + */ +export async function findColumnHeaderByIndex( + page: Page, + index: number +): Promise { + const headers = await findRenderedByType(page, 'columnheader'); + return headers.find(h => h.index === index) || null; +} + +/** + * Click on a column header by title (for sorting) + */ +export async function clickColumnHeader( + page: Page, + title: string +): Promise { + const header = await findColumnHeader(page, title); + if (!header) { + console.warn(`Column header "${title}" not found`); + return false; + } + if (!header.enabled) { + console.warn(`Column header "${title}" is disabled`); + return false; + } + await page.mouse.click(header.centerX, header.centerY); + return true; +} + +/** + * Click on a column header by index + */ +export async function clickColumnHeaderByIndex( + page: Page, + index: number +): Promise { + const header = await findColumnHeaderByIndex(page, index); + if (!header) { + console.warn(`Column header at index ${index} not found`); + return false; + } + if (!header.enabled) { + console.warn(`Column header at index ${index} is disabled`); + return false; + } + await page.mouse.click(header.centerX, header.centerY); + return true; +} + +/** + * Get all column headers + */ +export async function findAllColumnHeaders(page: Page): Promise { + return findRenderedByType(page, 'columnheader'); +} + +/** + * Find sortable column headers + */ +export async function findSortableColumnHeaders(page: Page): Promise { + return findRenderedByType(page, 'columnheader', { subType: 'sortable' }); +} + +// ============================================================================ +// Styled Text Control (STC) Helpers +// ============================================================================ + +/** + * Find a styled text control (code editor) by name + */ +export async function findStyledTextCtrl( + page: Page, + name?: string +): Promise { + if (name) { + return findRenderedByLabel(page, name, { elementType: 'styledtext' }); + } + const ctrls = await findRenderedByType(page, 'styledtext'); + return ctrls.length > 0 ? ctrls[0] : null; +} + +/** + * Click on a styled text control to focus it + */ +export async function clickStyledTextCtrl( + page: Page, + name?: string +): Promise { + const ctrl = await findStyledTextCtrl(page, name); + if (!ctrl) { + console.warn(`StyledTextCtrl${name ? ` "${name}"` : ''} not found`); + return false; + } + if (!ctrl.enabled) { + console.warn(`StyledTextCtrl${name ? ` "${name}"` : ''} is read-only`); + return false; + } + await page.mouse.click(ctrl.centerX, ctrl.centerY); + return true; +} + +/** + * Get all styled text controls + */ +export async function findAllStyledTextCtrls(page: Page): Promise { + return findRenderedByType(page, 'styledtext'); +} diff --git a/tests/e2e/wizard.spec.ts b/tests/e2e/wizard.spec.ts index 0b3e05b..f935198 100644 --- a/tests/e2e/wizard.spec.ts +++ b/tests/e2e/wizard.spec.ts @@ -1,5 +1,6 @@ // wxWizard Tests - Footprint Wizard simulation import { test, expect, tryLoadApp } from './utils/fixtures'; +import { clickByLabel } from './utils/element-tracker'; test.describe('wxWizard Tests', () => { @@ -23,13 +24,10 @@ test.describe('wxWizard Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Click Launch button - await page.mouse.click(box.x + 120, box.y + 60); - await page.waitForTimeout(500); - } + // Click Launch button using element registry + const clicked = await clickByLabel(page, 'Launch Footprint Wizard'); + expect(clicked, 'Launch Wizard button should be found and clicked').toBe(true); + await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/wizard-02-launch.png', fullPage: true }); }); @@ -44,16 +42,15 @@ test.describe('wxWizard Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Launch wizard - await page.mouse.click(box.x + 120, box.y + 60); - await page.waitForTimeout(500); - // Click Next - await page.mouse.click(box.x + 500, box.y + 400); - await page.waitForTimeout(200); - } + // Launch wizard using element registry + const launchClicked = await clickByLabel(page, 'Launch Footprint Wizard'); + expect(launchClicked, 'Launch Wizard button should be found').toBe(true); + await page.waitForTimeout(500); + + // Click Next using element registry + const nextClicked = await clickByLabel(page, 'Next'); + expect(nextClicked, 'Next button should be found and clicked').toBe(true); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/wizard-03-next-page.png', fullPage: true }); }); @@ -68,19 +65,20 @@ test.describe('wxWizard Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Launch wizard - await page.mouse.click(box.x + 120, box.y + 60); - await page.waitForTimeout(500); - // Click Next - await page.mouse.click(box.x + 500, box.y + 400); - await page.waitForTimeout(200); - // Click Back - await page.mouse.click(box.x + 400, box.y + 400); - await page.waitForTimeout(200); - } + // Launch wizard using element registry + const launchClicked = await clickByLabel(page, 'Launch Footprint Wizard'); + expect(launchClicked, 'Launch Wizard button should be found').toBe(true); + await page.waitForTimeout(500); + + // Click Next using element registry + const nextClicked = await clickByLabel(page, 'Next'); + expect(nextClicked, 'Next button should be found').toBe(true); + await page.waitForTimeout(200); + + // Click Back using element registry + const backClicked = await clickByLabel(page, 'Back'); + expect(backClicked, 'Back button should be found and clicked').toBe(true); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/wizard-04-back-page.png', fullPage: true }); }); @@ -95,16 +93,15 @@ test.describe('wxWizard Tests', () => { await page.waitForTimeout(300); - const canvas = page.locator('#canvas'); - const box = await canvas.boundingBox(); - if (box) { - // Launch wizard - await page.mouse.click(box.x + 120, box.y + 60); - await page.waitForTimeout(500); - // Click Cancel - await page.mouse.click(box.x + 300, box.y + 400); - await page.waitForTimeout(200); - } + // Launch wizard using element registry + const launchClicked = await clickByLabel(page, 'Launch Footprint Wizard'); + expect(launchClicked, 'Launch Wizard button should be found').toBe(true); + await page.waitForTimeout(500); + + // Click Cancel using element registry + const cancelClicked = await clickByLabel(page, 'Cancel'); + expect(cancelClicked, 'Cancel button should be found and clicked').toBe(true); + await page.waitForTimeout(200); await page.screenshot({ path: 'test-results/wizard-05-cancel.png', fullPage: true }); }); diff --git a/tests/e2e/wxwidgets.spec.ts b/tests/e2e/wxwidgets.spec.ts index 082ac91..5eb3a2d 100644 --- a/tests/e2e/wxwidgets.spec.ts +++ b/tests/e2e/wxwidgets.spec.ts @@ -1,5 +1,19 @@ import { test, expect, MAIN_CANVAS, waitForApp } from './utils/fixtures'; import { Page } from '@playwright/test'; +import { + clickTab, + clickByLabel, + clickSlider, + dragSliderTo, + findSliderTrack, + clickTextCtrl, + findSingleLineTextCtrl, + findMultiLineTextCtrl, + clickComboButton, + selectComboItem, + clickListboxItem, + clickListboxItemByIndex +} from './utils/element-tracker'; // Capture console events with [EVENT] prefix function captureEvents(page: Page): string[] { @@ -77,37 +91,35 @@ test.describe('wxWidgets WASM - Diagnostics', () => { // === TAB 1: Controls === console.log('--- Testing Controls Tab ---'); - // Click Controls tab (first tab, around x=35) - await page.mouse.click(box.x + 35, box.y + 35); + // Click Controls tab using element registry + await clickTab(page, 'Controls'); await page.waitForTimeout(300); - // Click "Click Me" button (around x=60, y=85) - await page.mouse.click(box.x + 60, box.y + 85); + // Click "Click Me" button using element registry + await clickByLabel(page, 'Click Me'); await page.waitForTimeout(300); - // Click "Toggle" button (around x=140, y=85) - await page.mouse.click(box.x + 140, box.y + 85); + // Click "Toggle" button using element registry + await clickByLabel(page, 'Toggle'); await page.waitForTimeout(300); - // Click checkbox "Enable feature" (around x=20, y=130) - await page.mouse.click(box.x + 20, box.y + 130); + // Click checkbox "Enable feature" using element registry + await clickByLabel(page, 'Enable feature'); await page.waitForTimeout(300); - // Click radio button "Option B" (around x=270, y=130) - await page.mouse.click(box.x + 270, box.y + 130); + // Click radio button "Option B" using element registry + await clickByLabel(page, 'Option B'); await page.waitForTimeout(300); - // Click radio button "Option C" (around x=360, y=130) - await page.mouse.click(box.x + 360, box.y + 130); + // Click radio button "Option C" using element registry + await clickByLabel(page, 'Option C'); await page.waitForTimeout(300); - // Interact with slider - click and drag (around y=175) - await page.mouse.click(box.x + 200, box.y + 175); + // Interact with slider using element tracking + await clickSlider(page); await page.waitForTimeout(200); - await page.mouse.move(box.x + 100, box.y + 175); - await page.mouse.down(); - await page.mouse.move(box.x + 400, box.y + 175, { steps: 10 }); - await page.mouse.up(); + // Drag slider to 80% position + await dragSliderTo(page, 0.8); await page.waitForTimeout(300); await page.screenshot({ path: 'test-results/04-controls-tab.png', fullPage: true }); @@ -115,20 +127,24 @@ test.describe('wxWidgets WASM - Diagnostics', () => { // === TAB 2: Text Input === console.log('--- Testing Text Input Tab ---'); - // Click Text Input tab (second tab, around x=100) - await page.mouse.click(box.x + 100, box.y + 35); + // Click Text Input tab using element registry + await clickTab(page, 'Text Input'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/05-text-input-tab.png', fullPage: true }); - // Click in text field area and type - await page.mouse.click(box.x + 200, box.y + 100); + // Click in single-line text field using element tracking + const singleLine = await findSingleLineTextCtrl(page); + expect(singleLine, 'Single-line text control should be tracked').not.toBeNull(); + await page.mouse.click(singleLine!.centerX, singleLine!.centerY); await page.waitForTimeout(200); await page.keyboard.type('Hello World'); await page.waitForTimeout(300); - // Click multiline text area - await page.mouse.click(box.x + 200, box.y + 200); + // Click multiline text area using element tracking + const multiLine = await findMultiLineTextCtrl(page); + expect(multiLine, 'Multi-line text control should be tracked').not.toBeNull(); + await page.mouse.click(multiLine!.centerX, multiLine!.centerY); await page.waitForTimeout(200); await page.keyboard.type('Line 1\nLine 2\nLine 3'); await page.waitForTimeout(300); @@ -138,8 +154,8 @@ test.describe('wxWidgets WASM - Diagnostics', () => { // === TAB 3: Drawing === console.log('--- Testing Drawing Tab ---'); - // Click Drawing tab (third tab, around x=175) - await page.mouse.click(box.x + 175, box.y + 35); + // Click Drawing tab using element registry + await clickTab(page, 'Drawing'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/07-drawing-tab.png', fullPage: true }); @@ -160,88 +176,67 @@ test.describe('wxWidgets WASM - Diagnostics', () => { // === TAB 4: Lists === console.log('--- Testing Lists Tab ---'); - // Click Lists tab (fourth tab, around x=225) - await page.mouse.click(box.x + 225, box.y + 35); + // Click Lists tab using element registry + await clickTab(page, 'Lists'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/09-lists-tab.png', fullPage: true }); - // Click on list items + // Click on listbox items using element registry (wxListBox uses listboxitem type) for (let i = 0; i < 5; i++) { - await page.mouse.click(box.x + 100, box.y + 80 + i * 20); + await clickListboxItemByIndex(page, i); await page.waitForTimeout(200); } await page.screenshot({ path: 'test-results/10-lists-clicked.png', fullPage: true }); - // Test wxChoice dropdown - the Choice control is to the right of the ListBox + // Test wxChoice dropdown using element tracking console.log('--- Testing wxChoice Dropdown ---'); - // Debug: Check all window divs in the DOM before clicking - const windowsBefore = await page.evaluate(() => { - const windows = document.querySelectorAll('[id^="window-"]'); - return Array.from(windows).map(w => ({ - id: w.id, - display: (w as HTMLElement).style.display, - rect: w.getBoundingClientRect() - })); - }); - console.log('Windows before click:', JSON.stringify(windowsBefore)); + // Find the Choice dropdown by its current value ("Red") and click to open it + const { findAllComboButtons } = await import('./utils/element-tracker'); + const comboButtons = await findAllComboButtons(page); + const choiceCombo = comboButtons.find(c => c.label === 'Red'); + expect(choiceCombo, 'Should find Choice dropdown with "Red" value').not.toBeNull(); - // Click on the wxChoice dropdown button (approximately right side of the panel) - // The Choice section is in a separate box to the right, starts around x=640 - // The wxChoice dropdown button (arrow) is at approximately x=800 - await page.mouse.click(box.x + 800, box.y + 100); - await page.waitForTimeout(500); + // Open the dropdown + await page.mouse.click(choiceCombo!.centerX, choiceCombo!.centerY); + await page.waitForTimeout(300); - // Debug: Check all window divs in the DOM after clicking - const windowsAfter = await page.evaluate(() => { - const windows = document.querySelectorAll('[id^="window-"]'); - return Array.from(windows).map(w => ({ - id: w.id, - display: (w as HTMLElement).style.display, - width: (w as HTMLElement).style.width, - height: (w as HTMLElement).style.height, - rect: w.getBoundingClientRect() - })); - }); - console.log('Windows after click:', JSON.stringify(windowsAfter)); - - await page.screenshot({ path: 'test-results/10a-choice-dropdown-open.png', fullPage: true }); - - // Click on the second option in the dropdown (should be "Green") - // Dropdown appears below the wxChoice, options are around x=700-800 - await page.mouse.click(box.x + 700, box.y + 140); + // Select "Green" from the dropdown + const greenClicked = await clickListboxItem(page, 'Green'); + expect(greenClicked, 'Should be able to click "Green" item').toBe(true); await page.waitForTimeout(300); await page.screenshot({ path: 'test-results/10b-choice-selected.png', fullPage: true }); - // Try opening the dropdown again to verify it works - await page.mouse.click(box.x + 800, box.y + 100); + // Open the dropdown again to verify it works + const reopened = await clickComboButton(page); + expect(reopened, 'Should be able to open dropdown').toBe(true); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/10c-choice-dropdown-reopen.png', fullPage: true }); - // Click on dropdown arrow button to close it - await page.mouse.click(box.x + 800, box.y + 100); + // Close the dropdown by pressing Escape + await page.keyboard.press('Escape'); await page.waitForTimeout(300); // === TAB 5: OpenGL === console.log('--- Testing OpenGL Tab ---'); - // Click OpenGL tab (fifth tab, around x=280) - await page.mouse.click(box.x + 280, box.y + 35); + // Click OpenGL tab using element registry + await clickTab(page, 'OpenGL'); await page.waitForTimeout(1000); // Give GL time to initialize await page.screenshot({ path: 'test-results/14-opengl-tab.png', fullPage: true }); - // Click on different GL tests in the dropdown - // First, click the dropdown (at approximately x=200, y=90) - await page.mouse.click(box.x + 200, box.y + 90); + // Click on different GL tests in the dropdown using element tracking + const glDropdownOpened = await clickComboButton(page); + expect(glDropdownOpened, 'Should be able to open GL test dropdown').toBe(true); await page.waitForTimeout(300); - // Click "Run All Tests" button (approximately x=400, y=90) - await page.mouse.click(box.x + 400, box.y + 90); + // Click "Run All Tests" button using element registry + await clickByLabel(page, 'Run All Tests'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/15-opengl-tests.png', fullPage: true }); @@ -249,22 +244,22 @@ test.describe('wxWidgets WASM - Diagnostics', () => { // === Menu interaction === console.log('--- Testing Menus ---'); - // Click File menu - await page.mouse.click(box.x + 20, box.y + 10); + // Click File menu using element registry + await clickByLabel(page, 'File'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/11-file-menu.png', fullPage: true }); - // Click somewhere else to close menu - await page.mouse.click(box.x + 300, box.y + 300); + // Close menu with Escape + await page.keyboard.press('Escape'); await page.waitForTimeout(300); - // Click Help menu - await page.mouse.click(box.x + 55, box.y + 10); + // Click Help menu using element registry + await clickByLabel(page, 'Help'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/12-help-menu.png', fullPage: true }); - // Close menu - await page.mouse.click(box.x + 300, box.y + 300); + // Close menu with Escape + await page.keyboard.press('Escape'); await page.waitForTimeout(300); // === Rapid interactions === @@ -400,10 +395,8 @@ test.describe('wxWidgets WASM - Mouse Drawing', () => { await waitForApp(page); // First, switch to the Drawing tab (Tab 3) - // The notebook tabs are near the top of the content area - // We need to click on the "Drawing" tab - // Tab positions vary, so we'll click in the approximate area - await clickCanvas(page, 280, 30); // Approximate position for Drawing tab + // Use element registry to click the tab reliably + await clickTab(page, 'Drawing'); await page.waitForTimeout(500); // Check if we're on the Drawing tab @@ -537,12 +530,8 @@ test.describe('wxWidgets WASM - OpenGL', () => { await page.goto('/minimal_test.html'); await waitForApp(page); - const canvas = page.locator(MAIN_CANVAS); - const box = await canvas.boundingBox(); - if (!box) throw new Error('Canvas not found'); - - // Click OpenGL tab (fifth tab, around x=280) - await page.mouse.click(box.x + 280, box.y + 35); + // Click OpenGL tab using element registry + await clickTab(page, 'OpenGL'); await page.waitForTimeout(1500); // Give GL time to initialize // Check that we switched to the OpenGL tab @@ -557,16 +546,12 @@ test.describe('wxWidgets WASM - OpenGL', () => { await page.goto('/minimal_test.html'); await waitForApp(page); - const canvas = page.locator(MAIN_CANVAS); - const box = await canvas.boundingBox(); - if (!box) throw new Error('Canvas not found'); - - // Switch to OpenGL tab - await page.mouse.click(box.x + 280, box.y + 35); + // Switch to OpenGL tab using element registry + await clickTab(page, 'OpenGL'); await page.waitForTimeout(1000); - // Click "Run All Tests" button (approximately x=360, y=130) - await page.mouse.click(box.x + 360, box.y + 130); + // Click "Run All Tests" button using element registry + await clickByLabel(page, 'Run All Tests'); await page.waitForTimeout(1000); // Save screenshot after running tests @@ -585,16 +570,12 @@ test.describe('wxWidgets WASM - OpenGL', () => { await page.goto('/minimal_test.html'); await waitForApp(page); - const canvas = page.locator(MAIN_CANVAS); - const box = await canvas.boundingBox(); - if (!box) throw new Error('Canvas not found'); - - // Switch to OpenGL tab - await page.mouse.click(box.x + 280, box.y + 35); + // Switch to OpenGL tab using element registry + await clickTab(page, 'OpenGL'); await page.waitForTimeout(1000); - // Click "Run All Tests" button (approximately at x=360, y=130 relative to canvas) - await page.mouse.click(box.x + 360, box.y + 130); + // Click "Run All Tests" button using element registry + await clickByLabel(page, 'Run All Tests'); await page.waitForTimeout(500); // Take screenshot before checking GL canvas @@ -643,12 +624,8 @@ test.describe('wxWidgets WASM - Canvas Z-Ordering and Visibility', () => { await page.goto('/minimal_test.html'); await waitForApp(page); - const canvas = page.locator(MAIN_CANVAS); - const box = await canvas.boundingBox(); - if (!box) throw new Error('Canvas not found'); - - // Step 1: Go to OpenGL tab first - await page.mouse.click(box.x + 280, box.y + 35); + // Step 1: Go to OpenGL tab first using element registry + await clickTab(page, 'OpenGL'); await page.waitForTimeout(1000); // Verify we're on OpenGL tab @@ -670,8 +647,8 @@ test.describe('wxWidgets WASM - Canvas Z-Ordering and Visibility', () => { }); console.log('GL Canvas on OpenGL tab:', JSON.stringify(glCanvasBefore)); - // Step 2: Switch to Controls tab - await page.mouse.click(box.x + 35, box.y + 35); + // Step 2: Switch to Controls tab using element registry + await clickTab(page, 'Controls'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/glcanvas-02-after-switch-to-controls.png', fullPage: true }); @@ -690,14 +667,14 @@ test.describe('wxWidgets WASM - Canvas Z-Ordering and Visibility', () => { }); console.log('GL Canvas after switching to Controls:', JSON.stringify(glCanvasAfter)); - // Step 3: Switch to Drawing tab to verify GL canvas doesn't persist - await page.mouse.click(box.x + 175, box.y + 35); + // Step 3: Switch to Drawing tab using element registry + await clickTab(page, 'Drawing'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/glcanvas-03-on-drawing-tab.png', fullPage: true }); - // Step 4: Switch to Lists tab - await page.mouse.click(box.x + 225, box.y + 35); + // Step 4: Switch to Lists tab using element registry + await clickTab(page, 'Lists'); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/glcanvas-04-on-lists-tab.png', fullPage: true }); @@ -721,8 +698,8 @@ test.describe('wxWidgets WASM - Canvas Z-Ordering and Visibility', () => { console.log('Canvas bounding box:', JSON.stringify(box)); - // Step 1: Go to OpenGL tab - await page.mouse.click(box.x + 280, box.y + 35); + // Step 1: Go to OpenGL tab using element registry + await clickTab(page, 'OpenGL'); await page.waitForTimeout(1000); await page.screenshot({ path: 'test-results/zorder-01-opengl-tab.png', fullPage: true }); @@ -735,21 +712,7 @@ test.describe('wxWidgets WASM - Canvas Z-Ordering and Visibility', () => { }); console.log('Event log check:', eventLogBefore); - // Step 2: Click on the test selection dropdown (wxChoice) on the OpenGL tab - // Layout analysis (from debug test): - // - Menu bar: y=0-20 - // - Tab bar: y=20-50 - // - Description text: y=50-115 - // - "Test:" dropdown row: y=115-150 - // - GL canvas: y=150+ - // - // The dropdown opens when clicking at y=140 (in the dropdown control row) - // Click anywhere in the dropdown control to open it - - const dropdownX = box.x + 150; // Middle of dropdown text area - const dropdownY = box.y + 140; // In the dropdown control row - - console.log(`Clicking dropdown at: (${dropdownX}, ${dropdownY})`); + // Step 2: Click on the test selection dropdown (wxChoice) on the OpenGL tab using element tracking // First check what windows exist before clicking const windowsBefore = await page.evaluate(() => { @@ -763,7 +726,9 @@ test.describe('wxWidgets WASM - Canvas Z-Ordering and Visibility', () => { }); console.log('Windows BEFORE click:', JSON.stringify(windowsBefore)); - await page.mouse.click(dropdownX, dropdownY); + // Open dropdown using element tracking + const dropdownClicked = await clickComboButton(page); + expect(dropdownClicked, 'Should be able to click dropdown on OpenGL tab').toBe(true); await page.waitForTimeout(500); await page.screenshot({ path: 'test-results/zorder-02-dropdown-clicked.png', fullPage: true }); @@ -827,9 +792,8 @@ test.describe('wxWidgets WASM - Canvas Z-Ordering and Visibility', () => { console.log('Z-Index info:', JSON.stringify(zIndexInfo, null, 2)); - // Step 3: Click on the dropdown arrow button to close it - // The arrow is on the right side of the dropdown control (around x=290) - await page.mouse.click(box.x + 290, box.y + 140); + // Step 3: Close the dropdown using Escape + await page.keyboard.press('Escape'); await page.waitForTimeout(300); await page.screenshot({ path: 'test-results/zorder-03-dropdown-closed.png', fullPage: true }); @@ -847,22 +811,15 @@ test.describe('wxWidgets WASM - Canvas Z-Ordering and Visibility', () => { if (!box) throw new Error('Canvas not found'); // Tab switch sequence: Controls -> OpenGL -> Lists -> OpenGL -> Drawing -> Controls - const tabClicks = [ - { x: 35, name: 'Controls' }, - { x: 280, name: 'OpenGL' }, - { x: 225, name: 'Lists' }, - { x: 280, name: 'OpenGL' }, - { x: 175, name: 'Drawing' }, - { x: 35, name: 'Controls' } - ]; + const tabNames = ['Controls', 'OpenGL', 'Lists', 'OpenGL', 'Drawing', 'Controls']; - for (let i = 0; i < tabClicks.length; i++) { - const tab = tabClicks[i]; - await page.mouse.click(box.x + tab.x, box.y + 35); + for (let i = 0; i < tabNames.length; i++) { + const tabName = tabNames[i]; + await clickTab(page, tabName); await page.waitForTimeout(500); await page.screenshot({ - path: `test-results/tabswitch-${String(i + 1).padStart(2, '0')}-${tab.name.toLowerCase()}.png`, + path: `test-results/tabswitch-${String(i + 1).padStart(2, '0')}-${tabName.toLowerCase()}.png`, fullPage: true }); @@ -873,7 +830,7 @@ test.describe('wxWidgets WASM - Canvas Z-Ordering and Visibility', () => { return window.getComputedStyle(glCanvas).display; }); - console.log(`Tab: ${tab.name}, GL Canvas display: ${glVisible}`); + console.log(`Tab: ${tabName}, GL Canvas display: ${glVisible}`); } }); }); diff --git a/tests/find-hardcoded-coords.sh b/tests/find-hardcoded-coords.sh new file mode 100755 index 0000000..4583ba8 --- /dev/null +++ b/tests/find-hardcoded-coords.sh @@ -0,0 +1,54 @@ +#!/bin/bash +# Find all lines with hardcoded coordinates in test files +# Excludes waitForTimeout, timeout:, and common non-coordinate numbers + +OUTPUT_FILE="hardcoded-coords-report.txt" + +echo "=== Hardcoded Coordinates Report ===" > "$OUTPUT_FILE" +echo "Generated: $(date)" >> "$OUTPUT_FILE" +echo "" >> "$OUTPUT_FILE" + +# Find lines with position/coordinate patterns +echo "=== Click position patterns ===" >> "$OUTPUT_FILE" +grep -n "position: { x:" e2e/*.spec.ts >> "$OUTPUT_FILE" 2>/dev/null + +echo "" >> "$OUTPUT_FILE" +echo "=== Mouse click with coordinates ===" >> "$OUTPUT_FILE" +grep -n "mouse\.click.*[0-9]" e2e/*.spec.ts | grep -v "centerX\|centerY" >> "$OUTPUT_FILE" 2>/dev/null + +echo "" >> "$OUTPUT_FILE" +echo "=== Mouse move with coordinates ===" >> "$OUTPUT_FILE" +grep -n "mouse\.move.*[0-9]" e2e/*.spec.ts | grep -v "centerX\|centerY" >> "$OUTPUT_FILE" 2>/dev/null + +echo "" >> "$OUTPUT_FILE" +echo "=== Mouse dblclick with coordinates ===" >> "$OUTPUT_FILE" +grep -n "mouse\.dblclick.*[0-9]" e2e/*.spec.ts >> "$OUTPUT_FILE" 2>/dev/null + +echo "" >> "$OUTPUT_FILE" +echo "=== Canvas click with position ===" >> "$OUTPUT_FILE" +grep -n "canvas\.click.*position" e2e/*.spec.ts >> "$OUTPUT_FILE" 2>/dev/null + +echo "" >> "$OUTPUT_FILE" +echo "=== getImageData coordinates ===" >> "$OUTPUT_FILE" +grep -n "getImageData.*[0-9]" e2e/*.spec.ts >> "$OUTPUT_FILE" 2>/dev/null + +echo "" >> "$OUTPUT_FILE" +echo "=== clickCanvas calls ===" >> "$OUTPUT_FILE" +grep -n "clickCanvas.*[0-9]" e2e/*.spec.ts >> "$OUTPUT_FILE" 2>/dev/null + +echo "" >> "$OUTPUT_FILE" +echo "=== dragCanvas calls ===" >> "$OUTPUT_FILE" +grep -n "dragCanvas.*[0-9]" e2e/*.spec.ts >> "$OUTPUT_FILE" 2>/dev/null + +echo "" >> "$OUTPUT_FILE" +echo "=== Summary by file ===" >> "$OUTPUT_FILE" +for file in e2e/*.spec.ts; do + count=$(grep -c "position: { x:\|mouse\.click.*box\.\|mouse\.move.*box\.\|canvas\.click.*position\|clickCanvas\|dragCanvas" "$file" 2>/dev/null || echo "0") + if [ "$count" -gt 0 ]; then + echo "$file: $count potential hardcoded coordinates" >> "$OUTPUT_FILE" + fi +done + +echo "" +echo "Report written to $OUTPUT_FILE" +cat "$OUTPUT_FILE" diff --git a/wxwidgets b/wxwidgets index ae9d0a8..3d44f43 160000 --- a/wxwidgets +++ b/wxwidgets @@ -1 +1 @@ -Subproject commit ae9d0a81edeee5d09b27f6e49f43130c148d9aac +Subproject commit 3d44f43ab0c5bd4acd6db2a140c618bfee01b38d