Files
hyperframes/packages/studio/tests/e2e/helpers.sh
Miguel Ángel fb2e21090f feat(studio): GSAP tween editing in Design panel (#1102)
* feat(studio): GSAP tween editing in Design panel

Add a GSAP animation editor to the studio Design panel: select an element,
view and edit its tweens (properties, easing, timing), add/delete animations,
and drag custom bezier speed curves — all persisted back to the composition
HTML. Gated behind VITE_STUDIO_ENABLE_GSAP_PANEL.

Parsing of existing GSAP source now uses a recast + Babel AST parser instead of
regex, giving scope resolution, stable tween IDs, and round-trip preservation of
extras and unresolved raw values.

recast compiles to CommonJS that calls require("fs"), which breaks browser and
Vite SSR bundles. To contain it, @hyperframes/core is split into an isomorphic
layer and a Node-only AST layer:

- gsapSerialize.ts holds the recast-free helpers (serialization, keyframe
  conversion, validation, shared types). htmlParser.ts is now fully isomorphic.
- parseGsapScript and the script-mutation helpers live in gsapParser.ts,
  reachable only via the @hyperframes/core/gsap-parser subpath, loaded
  server-side by the studio-api mutation routes and the linter via dynamic
  import (recast stays external under SSR).
- The barrel and the gsap-constants subpath are recast-free, so studio browser
  bundles never trace recast.

Adds AST parser unit + stress coverage and e2e helpers for the panel.

* fix(lint): await async lintHyperframeHtml in all callers

lintHyperframeHtml became async (gsap rules use dynamic import)
but lintProject and check-hyperframe-static weren't awaiting it,
causing typecheck failures and runtime crashes in CI.

Also wire LintRule type in gsap rules to fix fallow unused-type
finding, and suppress render.ts exported-for-tests symbols.
2026-05-28 19:16:34 -04:00

89 lines
2.6 KiB
Bash

#!/bin/bash
# E2E test helpers for agent-browser that work reliably with React components.
# Uses JS-based clicks (element.click()) instead of pointer events to avoid
# stale ref issues after iframe reloads.
# Click a button by its exact text content
click_button() {
local text="$1"
agent-browser eval --stdin <<EVALEOF
(function() {
var btns = document.querySelectorAll('button');
for (var i = 0; i < btns.length; i++) {
if (btns[i].textContent.trim() === '${text}') {
btns[i].click();
return 'clicked: ${text}';
}
}
return 'not found: ${text}';
})()
EVALEOF
}
# Click a button whose text contains a substring
click_button_contains() {
local text="$1"
agent-browser eval --stdin <<EVALEOF
(function() {
var btns = document.querySelectorAll('button');
for (var i = 0; i < btns.length; i++) {
if (btns[i].textContent.includes('${text}')) {
btns[i].click();
return 'clicked: ' + btns[i].textContent.trim().substring(0, 60);
}
}
return 'not found: ${text}';
})()
EVALEOF
}
# Set an input value by label text and commit via Enter
set_input() {
local label="$1"
local value="$2"
agent-browser eval --stdin <<EVALEOF
(function() {
var labels = document.querySelectorAll('label, span');
for (var i = 0; i < labels.length; i++) {
if (labels[i].textContent.trim() === '${label}') {
var input = labels[i].closest('[class]')?.querySelector('input');
if (!input) continue;
var nativeSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
nativeSetter.call(input, '${value}');
input.dispatchEvent(new Event('input', {bubbles: true}));
input.dispatchEvent(new KeyboardEvent('keydown', {key: 'Enter', code: 'Enter', bubbles: true}));
return 'set ${label} = ${value}';
}
}
return 'not found: ${label}';
})()
EVALEOF
}
# Select from a combobox/select by label and option value
select_option() {
local label="$1"
local value="$2"
agent-browser eval --stdin <<EVALEOF
(function() {
var selects = document.querySelectorAll('select');
for (var i = 0; i < selects.length; i++) {
var lbl = selects[i].closest('[class]')?.querySelector('label, span');
if (lbl && lbl.textContent.trim() === '${label}') {
selects[i].value = '${value}';
selects[i].dispatchEvent(new Event('change', {bubbles: true}));
return 'selected ${label} = ${value}';
}
}
return 'not found: ${label}';
})()
EVALEOF
}
# Wait for text to appear in the page
wait_for_text() {
local text="$1"
local timeout="${2:-10000}"
agent-browser wait --text "${text}" --timeout "${timeout}" 2>/dev/null || echo "timeout waiting for: ${text}"
}