Add frame-aware locate for cross-origin iframe steps
Selectors were only resolved against the top document, so steps targeting the Lucid WooCommerce checkout (rendered in a lucidtrading.com iframe under the dash.lucidtrading.com app) never matched — e.g. input#coupon_code_field. Add an optional `frame` on click/type/waitFor naming the <iframe> element. The extension measures the iframe in the top frame (pageFrameOffset), finds the element across child frames (pageLocate `relative` mode), and composes the two into desktop coordinates; the Python side is unchanged since the result keeps the same shape. Without `frame`, every path behaves as before. Point the Lucid checkout steps at the frame and harden the coupon selectors (the exact field id is still unconfirmed against the live iframe). Extension 0.13.0, runner 0.19.0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
016f121f40
commit
66c99c5499
+21
-8
@@ -15,8 +15,14 @@ export type AutomationStep =
|
||||
// failing the run — for things that only sometimes appear, like a cookie
|
||||
// banner or a confirmation modal. Only absence is tolerated: an element that
|
||||
// is present but covered or off-screen still fails.
|
||||
| { action: 'click'; selector: string; index?: number; skipIfNotFound?: boolean; urlPattern?: string; label?: string }
|
||||
| { action: 'type'; selector: string; text: string; index?: number; clear?: boolean; skipIfNotFound?: boolean; urlPattern?: string; label?: string }
|
||||
// `frame` targets an element inside a cross-origin <iframe> (e.g. the
|
||||
// WooCommerce checkout modal). Its value is a selector for the <iframe>
|
||||
// element in the top document; the step's own `selector` is then resolved
|
||||
// inside that frame and its coordinates offset back to the page. Without it a
|
||||
// selector only ever matches the top document. Needs extension 0.13.0+ and
|
||||
// runner 0.19.0+.
|
||||
| { action: 'click'; selector: string; index?: number; skipIfNotFound?: boolean; urlPattern?: string; frame?: string; label?: string }
|
||||
| { action: 'type'; selector: string; text: string; index?: number; clear?: boolean; skipIfNotFound?: boolean; urlPattern?: string; frame?: string; label?: string }
|
||||
| { action: 'wait'; seconds: number; label?: string }
|
||||
// Point the firm's tab at a page. Omit `url` to use the firm's own. Skipped
|
||||
// when the tab is already there, so it doesn't reload and lose page state.
|
||||
@@ -32,7 +38,7 @@ export type AutomationStep =
|
||||
// content-visibility, or collapsed to zero size all end the wait. It says
|
||||
// nothing about being scrolled off-screen or covered by an overlay: those
|
||||
// are still on the page. Needs extension 0.12.0+ and runner 0.18.0+.
|
||||
| { action: 'waitFor'; selector: string; index?: number; absent?: boolean; hidden?: boolean; timeoutSeconds?: number; label?: string }
|
||||
| { action: 'waitFor'; selector: string; index?: number; absent?: boolean; hidden?: boolean; timeoutSeconds?: number; frame?: string; label?: string }
|
||||
// Scroll until the page stops adding elements matching `selector`, for lists
|
||||
// that load progressively. `containerSelector` names the scrolling element
|
||||
// when the automatic guess is wrong — these lists usually scroll inside a div
|
||||
@@ -271,11 +277,18 @@ export const FIRMS: Firm[] = [
|
||||
{ action: 'click', selector: '.slide:nth-child(2) .cta-btn', label: 'Open' },
|
||||
{ action: 'click', selector: '.platform-btn:first-child', label: 'CQG' },
|
||||
|
||||
{ action: 'click', selector: 'input#coupon_code_field', label: 'Click on coupon code'},
|
||||
{ action: 'type', selector: 'input#coupon_code_field', text: 'THEPROPFARM'},
|
||||
{ action: 'click', selector: 'input#coupon_code_field + button'},
|
||||
{ action: 'click', selector: '.validate-required:not(.woocommerce-validated)', label: 'Agree to terms' },
|
||||
{ action: 'click', selector: '.validate-required:not(.woocommerce-validated)', label: 'Agree to terms 2' },
|
||||
// The checkout renders in a WooCommerce iframe on
|
||||
// lucidtrading.com (parent app is dash.lucidtrading.com), so
|
||||
// every step here targets the frame. The coupon field id
|
||||
// varies between WooCommerce's default (#coupon_code /
|
||||
// name="coupon_code") and this template's custom id; list
|
||||
// both so one of them matches. Apply is WooCommerce's
|
||||
// named submit button, not a positional sibling.
|
||||
{ action: 'click', selector: 'input#coupon_code, input[name="coupon_code"], input#coupon_code_field', frame: '#woocommerceModal iframe', label: 'Focus coupon field' },
|
||||
{ action: 'type', selector: 'input#coupon_code, input[name="coupon_code"], input#coupon_code_field', frame: '#woocommerceModal iframe', text: 'THEPROPFARM', label: 'Enter coupon' },
|
||||
{ action: 'click', selector: 'button[name="apply_coupon"], input[name="apply_coupon"]', frame: '#woocommerceModal iframe', label: 'Apply coupon' },
|
||||
{ action: 'click', selector: '.validate-required:not(.woocommerce-validated)', frame: '#woocommerceModal iframe', label: 'Agree to terms' },
|
||||
{ action: 'click', selector: '.validate-required:not(.woocommerce-validated)', frame: '#woocommerceModal iframe', label: 'Agree to terms 2' },
|
||||
|
||||
{ action: 'waitFor', selector: '#woocommerceModal', absent: true, hidden: true, timeoutSeconds: 30, label: 'Wait for the modal to close' },
|
||||
|
||||
|
||||
Reference in New Issue
Block a user