From af1125c8e9ee953d0b0c8b7071583ebb095c7348 Mon Sep 17 00:00:00 2001 From: Tim Voronov Date: Sun, 1 Sep 2019 16:09:35 -0400 Subject: [PATCH] Added INPUT_CLEAR function (#366) * Added INPUT_CLEAR function * Fixed linting issue * Fixed formatting --- .../doc/input/input.fql} | 0 e2e/tests/dynamic/element/clear/clear.fql | 12 + .../element/clear/clear_by_selector.fql | 14 + .../element/input/input.fql} | 0 .../element/input/input_by_selector.fql | 12 + pkg/drivers/cdp/document.go | 4 - pkg/drivers/cdp/element.go | 48 +- pkg/drivers/cdp/input/keyboard.go | 69 +- pkg/drivers/cdp/input/layout.go | 1352 +++++++++++++++++ pkg/drivers/cdp/input/manager.go | 116 +- pkg/drivers/cdp/input/mouse.go | 20 +- pkg/drivers/http/document.go | 4 - pkg/drivers/http/element.go | 12 + pkg/drivers/value.go | 8 +- pkg/stdlib/html/clear.go | 33 + pkg/stdlib/html/input.go | 86 +- pkg/stdlib/html/lib.go | 1 + 17 files changed, 1704 insertions(+), 87 deletions(-) rename e2e/tests/{doc_input_text_d.fql => dynamic/doc/input/input.fql} (100%) create mode 100644 e2e/tests/dynamic/element/clear/clear.fql create mode 100644 e2e/tests/dynamic/element/clear/clear_by_selector.fql rename e2e/tests/{el_input_text_d.fql => dynamic/element/input/input.fql} (100%) create mode 100644 e2e/tests/dynamic/element/input/input_by_selector.fql create mode 100644 pkg/drivers/cdp/input/layout.go create mode 100644 pkg/stdlib/html/clear.go diff --git a/e2e/tests/doc_input_text_d.fql b/e2e/tests/dynamic/doc/input/input.fql similarity index 100% rename from e2e/tests/doc_input_text_d.fql rename to e2e/tests/dynamic/doc/input/input.fql diff --git a/e2e/tests/dynamic/element/clear/clear.fql b/e2e/tests/dynamic/element/clear/clear.fql new file mode 100644 index 00000000..eccb714c --- /dev/null +++ b/e2e/tests/dynamic/element/clear/clear.fql @@ -0,0 +1,12 @@ +LET url = @dynamic + "?redirect=/forms" +LET doc = DOCUMENT(url, true) + +WAIT_ELEMENT(doc, "form") + +LET input = ELEMENT(doc, "#text_input") + +INPUT(input, "Foo", 100) + +INPUT_CLEAR(input) + +RETURN EXPECT("", INNER_TEXT(doc, "#text_output")) \ No newline at end of file diff --git a/e2e/tests/dynamic/element/clear/clear_by_selector.fql b/e2e/tests/dynamic/element/clear/clear_by_selector.fql new file mode 100644 index 00000000..94d27d0a --- /dev/null +++ b/e2e/tests/dynamic/element/clear/clear_by_selector.fql @@ -0,0 +1,14 @@ +LET url = @dynamic + "?redirect=/forms" +LET doc = DOCUMENT(url, true) + +WAIT_ELEMENT(doc, "form") + +LET form = ELEMENT(doc, "#page-form") + +INPUT(form, "#text_input", "foo") +INPUT_CLEAR(form, "#text_input") + +LET input = ELEMENT(doc, "#text_input") +LET output = ELEMENT(doc, "#text_output") + +RETURN EXPECT("", output.innerText) \ No newline at end of file diff --git a/e2e/tests/el_input_text_d.fql b/e2e/tests/dynamic/element/input/input.fql similarity index 100% rename from e2e/tests/el_input_text_d.fql rename to e2e/tests/dynamic/element/input/input.fql diff --git a/e2e/tests/dynamic/element/input/input_by_selector.fql b/e2e/tests/dynamic/element/input/input_by_selector.fql new file mode 100644 index 00000000..0c95cd79 --- /dev/null +++ b/e2e/tests/dynamic/element/input/input_by_selector.fql @@ -0,0 +1,12 @@ +LET url = @dynamic + "?redirect=/forms" +LET doc = DOCUMENT(url, true) + +WAIT_ELEMENT(doc, "form") + +LET form = ELEMENT(doc, "#page-form") + +INPUT(form, "#text_input", "foo") + +LET output = ELEMENT(doc, "#text_output") + +RETURN EXPECT(output.innerText, "foo") \ No newline at end of file diff --git a/pkg/drivers/cdp/document.go b/pkg/drivers/cdp/document.go index 82d59f5c..6386d5e7 100644 --- a/pkg/drivers/cdp/document.go +++ b/pkg/drivers/cdp/document.go @@ -325,10 +325,6 @@ func (doc *HTMLDocument) ClickBySelectorAll(ctx context.Context, selector values return doc.element.ClickBySelectorAll(ctx, selector) } -func (doc *HTMLDocument) InputBySelector(ctx context.Context, selector values.String, value core.Value, delay values.Int) error { - return doc.input.TypeBySelector(ctx, doc.element.id.nodeID, selector, value, delay) -} - func (doc *HTMLDocument) SelectBySelector(ctx context.Context, selector values.String, value *values.Array) (*values.Array, error) { return doc.input.SelectBySelector(ctx, doc.element.id.nodeID, selector, value) } diff --git a/pkg/drivers/cdp/element.go b/pkg/drivers/cdp/element.go index 997bbbbc..6548a55b 100644 --- a/pkg/drivers/cdp/element.go +++ b/pkg/drivers/cdp/element.go @@ -1068,7 +1068,27 @@ func (el *HTMLElement) Input(ctx context.Context, value core.Value, delay values return core.Error(core.ErrInvalidOperation, "element is not an element.") } - return el.input.Type(ctx, el.id.objectID, value, delay) + return el.input.Type(ctx, el.id.objectID, input.TypeParams{ + Text: value, + Clear: false, + Delay: delay, + }) +} + +func (el *HTMLElement) InputBySelector(ctx context.Context, selector values.String, value core.Value, delay values.Int) error { + return el.input.TypeBySelector(ctx, el.id.nodeID, selector, input.TypeParams{ + Text: value, + Clear: false, + Delay: delay, + }) +} + +func (el *HTMLElement) Clear(ctx context.Context) error { + return el.input.Clear(ctx, el.id.objectID) +} + +func (el *HTMLElement) ClearBySelector(ctx context.Context, selector values.String) error { + return el.input.ClearBySelector(ctx, el.id.nodeID, selector) } func (el *HTMLElement) Select(ctx context.Context, value *values.Array) (*values.Array, error) { @@ -1215,6 +1235,10 @@ func (el *HTMLElement) handleAttrModified(ctx context.Context, message interface return } + if el.IsDetached() { + return + } + el.attributes.Mutate(ctx, func(v core.Value, err error) { if err != nil { el.logError(err).Msg("failed to update element") @@ -1255,6 +1279,10 @@ func (el *HTMLElement) handleAttrRemoved(ctx context.Context, message interface{ return } + if el.IsDetached() { + return + } + el.attributes.Mutate(ctx, func(v core.Value, err error) { if err != nil { el.logError(err).Msg("failed to update element") @@ -1287,6 +1315,13 @@ func (el *HTMLElement) handleChildrenCountChanged(ctx context.Context, message i return } + if el.IsDetached() { + return + } + + el.mu.Lock() + defer el.mu.Unlock() + node, err := el.client.DOM.DescribeNode( ctx, dom.NewDescribeNodeArgs().SetObjectID(el.id.objectID), @@ -1298,9 +1333,6 @@ func (el *HTMLElement) handleChildrenCountChanged(ctx context.Context, message i return } - el.mu.Lock() - defer el.mu.Unlock() - el.children = createChildrenArray(node.Node.Children) } @@ -1319,6 +1351,10 @@ func (el *HTMLElement) handleChildInserted(ctx context.Context, message interfac prevID := reply.PreviousNodeID nextID := reply.Node.NodeID + if el.IsDetached() { + return + } + el.mu.Lock() defer el.mu.Unlock() @@ -1375,6 +1411,10 @@ func (el *HTMLElement) handleChildRemoved(ctx context.Context, message interface targetIDx := -1 targetID := reply.NodeID + if el.IsDetached() { + return + } + el.mu.Lock() defer el.mu.Unlock() diff --git a/pkg/drivers/cdp/input/keyboard.go b/pkg/drivers/cdp/input/keyboard.go index 3e41951c..2dc96f91 100644 --- a/pkg/drivers/cdp/input/keyboard.go +++ b/pkg/drivers/cdp/input/keyboard.go @@ -2,15 +2,45 @@ package input import ( "context" + "github.com/pkg/errors" "time" "github.com/mafredri/cdp" "github.com/mafredri/cdp/protocol/input" ) -type Keyboard struct { - client *cdp.Client -} +const DefaultDelay = 25 + +type ( + KeyboardModifier int + + KeyboardLocation int + + KeyboardKey struct { + KeyCode int + Key string + Code string + Modifier KeyboardModifier + Location KeyboardLocation + } + + Keyboard struct { + client *cdp.Client + } +) + +const ( + KeyboardModifierNone KeyboardModifier = 0 + KeyboardModifierAlt KeyboardModifier = 1 + KeyboardModifierCtrl KeyboardModifier = 2 + KeyboardModifierCmd KeyboardModifier = 4 + KeyboardModifierShift KeyboardModifier = 8 + + // 1=Left, 2=Right + KeyboardLocationNone KeyboardLocation = 0 + KeyboardLocationLeft KeyboardLocation = 1 + KeyboardLocationRight KeyboardLocation = 2 +) func NewKeyboard(client *cdp.Client) *Keyboard { return &Keyboard{client} @@ -40,7 +70,7 @@ func (k *Keyboard) Type(ctx context.Context, text string, delay int) error { return err } - releaseDelay := randomDuration(delay) + releaseDelay := randomDuration(delay) * time.Millisecond time.Sleep(releaseDelay) if err := k.Up(ctx, ch); err != nil { @@ -50,3 +80,34 @@ func (k *Keyboard) Type(ctx context.Context, text string, delay int) error { return nil } + +func (k *Keyboard) Press(ctx context.Context, name string) error { + key, found := usKeyboardLayout[name] + + if !found { + return errors.New("invalid key") + } + + err := k.client.Input.DispatchKeyEvent( + ctx, + input.NewDispatchKeyEventArgs("keyDown"). + SetCode(key.Code). + SetKey(key.Key). + SetWindowsVirtualKeyCode(key.KeyCode), + ) + + if err != nil { + return err + } + + releaseDelay := randomDuration(DefaultDelay) + time.Sleep(releaseDelay) + + return k.client.Input.DispatchKeyEvent( + ctx, + input.NewDispatchKeyEventArgs("keyUp"). + SetCode(key.Code). + SetKey(key.Key). + SetWindowsVirtualKeyCode(key.KeyCode), + ) +} diff --git a/pkg/drivers/cdp/input/layout.go b/pkg/drivers/cdp/input/layout.go new file mode 100644 index 00000000..a0800859 --- /dev/null +++ b/pkg/drivers/cdp/input/layout.go @@ -0,0 +1,1352 @@ +package input + +var usKeyboardLayout = map[string]KeyboardKey{ + "0": { + KeyCode: 48, + Key: "0", + Code: "Digit0", + }, + "1": { + KeyCode: 49, + Key: "1", + Code: "Digit1", + }, + "2": { + KeyCode: 50, + Key: "2", + Code: "Digit2", + }, + "3": { + KeyCode: 51, + Key: "3", + Code: "Digit3", + }, + "4": { + KeyCode: 52, + Key: "4", + Code: "Digit4", + }, + "5": { + KeyCode: 53, + Key: "5", + Code: "Digit5", + }, + "6": { + KeyCode: 54, + Key: "6", + Code: "Digit6", + }, + "7": { + KeyCode: 55, + Key: "7", + Code: "Digit7", + }, + "8": { + KeyCode: 56, + Key: "8", + Code: "Digit8", + }, + "9": { + KeyCode: 57, + Key: "9", + Code: "Digit9", + }, + "Power": { + Key: "Power", + Code: "Power", + }, + "Eject": { + Key: "Eject", + Code: "Eject", + }, + "Abort": { + KeyCode: 3, + Code: "Abort", + Key: "Cancel", + }, + "Help": { + KeyCode: 6, + Code: "Help", + Key: "Help", + }, + "Backspace": { + KeyCode: 8, + Code: "Backspace", + Key: "Backspace", + }, + "Tab": { + KeyCode: 9, + Code: "Tab", + Key: "Tab", + }, + "Numpad5": { + KeyCode: 12, + Key: "Clear", + Code: "Numpad5", + Modifier: KeyboardModifierShift, + Location: 3, + }, + "NumpadEnter": { + KeyCode: 13, + Code: "NumpadEnter", + Key: "Enter", + Location: 3, + }, + "Enter": { + KeyCode: 13, + Code: "Enter", + Key: "Enter", + }, + `\r`: { + KeyCode: 13, + Code: "Enter", + Key: "Enter", + }, + `\n`: { + KeyCode: 13, + Code: "Enter", + Key: "Enter", + }, + "ShiftLeft": { + KeyCode: 16, + Code: "ShiftLeft", + Key: "Shift", + Location: 1, + }, + "ShiftRight": { + KeyCode: 16, + Code: "ShiftRight", + Key: "Shift", + Location: 2, + }, + "ControlLeft": { + KeyCode: 17, + Code: "ControlLeft", + Key: "Control", + Location: 1, + }, + "ControlRight": { + KeyCode: 17, + Code: "ControlRight", + Key: "Control", + Location: 2, + }, + "AltLeft": { + KeyCode: 18, + Code: "AltLeft", + Key: "Alt", + Location: 1, + }, + "AltRight": { + KeyCode: 18, + Code: "AltRight", + Key: "Alt", + Location: 2, + }, + "Pause": { + KeyCode: 19, + Code: "Pause", + Key: "Pause", + }, + "CapsLock": { + KeyCode: 20, + Code: "CapsLock", + Key: "CapsLock", + }, + "Escape": { + KeyCode: 27, + Code: "Escape", + Key: "Escape", + }, + "Convert": { + KeyCode: 28, + Code: "Convert", + Key: "Convert", + }, + "NonConvert": { + KeyCode: 29, + Code: "NonConvert", + Key: "NonConvert", + }, + "Space": { + KeyCode: 32, + Code: "Space", + Key: " ", + }, + "Numpad9": { + KeyCode: 33, + Key: "PageUp", + Code: "Numpad9", + Modifier: KeyboardModifierShift, + Location: 3, + }, + "PageUp": { + KeyCode: 33, + Code: "PageUp", + Key: "PageUp", + }, + "Numpad3": { + KeyCode: 34, + Key: "PageDown", + Code: "Numpad3", + Modifier: KeyboardModifierShift, + Location: 3, + }, + "PageDown": { + KeyCode: 34, + Code: "PageDown", + Key: "PageDown", + }, + "End": { + KeyCode: 35, + Code: "End", + Key: "End", + }, + "Numpad1": { + KeyCode: 35, + Key: "End", + Code: "Numpad1", + Modifier: KeyboardModifierShift, + Location: 3, + }, + "Home": { + KeyCode: 36, + Code: "Home", + Key: "Home", + }, + "Numpad7": { + KeyCode: 36, + Key: "Home", + Code: "Numpad7", + Modifier: KeyboardModifierShift, + Location: 3, + }, + "ArrowLeft": { + KeyCode: 37, + Code: "ArrowLeft", + Key: "ArrowLeft", + }, + "Numpad4": { + KeyCode: 37, + Key: "ArrowLeft", + Code: "Numpad4", + Modifier: KeyboardModifierShift, + Location: 3, + }, + "Numpad8": { + KeyCode: 38, + Key: "ArrowUp", + Code: "Numpad8", + Modifier: KeyboardModifierShift, + Location: 3, + }, + "ArrowUp": { + KeyCode: 38, + Code: "ArrowUp", + Key: "ArrowUp", + }, + "ArrowRight": { + KeyCode: 39, + Code: "ArrowRight", + Key: "ArrowRight", + }, + "Numpad6": { + KeyCode: 39, + Key: "ArrowRight", + Code: "Numpad6", + Modifier: KeyboardModifierShift, + Location: 3, + }, + "Numpad2": { + KeyCode: 40, + Key: "ArrowDown", + Code: "Numpad2", + Modifier: KeyboardModifierShift, + Location: 3, + }, + "ArrowDown": { + KeyCode: 40, + Code: "ArrowDown", + Key: "ArrowDown", + }, + "Select": { + KeyCode: 41, + Code: "Select", + Key: "Select", + }, + "Open": { + KeyCode: 43, + Code: "Open", + Key: "Execute", + }, + "PrintScreen": { + KeyCode: 44, + Code: "PrintScreen", + Key: "PrintScreen", + }, + "Insert": { + KeyCode: 45, + Code: "Insert", + Key: "Insert", + }, + "Numpad0": { + KeyCode: 45, + // "shiftKeyCode": 96, + Key: "Insert", + Code: "Numpad0", + Modifier: KeyboardModifierShift, + Location: 3, + }, + "Delete": { + KeyCode: 46, + Code: "Delete", + Key: "Delete", + }, + "NumpadDecimal": { + KeyCode: 46, + // "shiftKeyCode": 110, + Code: "NumpadDecimal", + Key: "\u0000", + Modifier: KeyboardModifierShift, + Location: 3, + }, + "Digit0": { + KeyCode: 48, + Code: "Digit0", + Modifier: KeyboardModifierShift, + Key: "0", + }, + "Digit1": { + KeyCode: 49, + Code: "Digit1", + Modifier: KeyboardModifierShift, + Key: "1", + }, + "Digit2": { + KeyCode: 50, + Code: "Digit2", + Modifier: KeyboardModifierShift, + Key: "2", + }, + "Digit3": { + KeyCode: 51, + Code: "Digit3", + Modifier: KeyboardModifierShift, + Key: "3", + }, + "Digit4": { + KeyCode: 52, + Code: "Digit4", + Modifier: KeyboardModifierShift, + Key: "4", + }, + "Digit5": { + KeyCode: 53, + Code: "Digit5", + Modifier: KeyboardModifierShift, + Key: "5", + }, + "Digit6": { + KeyCode: 54, + Code: "Digit6", + Modifier: KeyboardModifierShift, + Key: "6", + }, + "Digit7": { + KeyCode: 55, + Code: "Digit7", + Modifier: KeyboardModifierShift, + Key: "7", + }, + "Digit8": { + KeyCode: 56, + Code: "Digit8", + Modifier: KeyboardModifierShift, + Key: "8", + }, + "Digit9": { + KeyCode: 57, + Code: "Digit9", + Modifier: KeyboardModifierShift, + Key: "9", + }, + "KeyA": { + KeyCode: 65, + Code: "KeyA", + Modifier: KeyboardModifierShift, + Key: "a", + }, + "KeyB": { + KeyCode: 66, + Code: "KeyB", + Modifier: KeyboardModifierShift, + Key: "b", + }, + "KeyC": { + KeyCode: 67, + Code: "KeyC", + Modifier: KeyboardModifierShift, + Key: "c", + }, + "KeyD": { + KeyCode: 68, + Code: "KeyD", + Modifier: KeyboardModifierShift, + Key: "d", + }, + "KeyE": { + KeyCode: 69, + Code: "KeyE", + Modifier: KeyboardModifierShift, + Key: "e", + }, + "KeyF": { + KeyCode: 70, + Code: "KeyF", + Modifier: KeyboardModifierShift, + Key: "f", + }, + "KeyG": { + KeyCode: 71, + Code: "KeyG", + Modifier: KeyboardModifierShift, + Key: "g", + }, + "KeyH": { + KeyCode: 72, + Code: "KeyH", + Modifier: KeyboardModifierShift, + Key: "h", + }, + "KeyI": { + KeyCode: 73, + Code: "KeyI", + Modifier: KeyboardModifierShift, + Key: "i", + }, + "KeyJ": { + KeyCode: 74, + Code: "KeyJ", + Modifier: KeyboardModifierShift, + Key: "j", + }, + "KeyK": { + KeyCode: 75, + Code: "KeyK", + Modifier: KeyboardModifierShift, + Key: "k", + }, + "KeyL": { + KeyCode: 76, + Code: "KeyL", + Modifier: KeyboardModifierShift, + Key: "l", + }, + "KeyM": { + KeyCode: 77, + Code: "KeyM", + Modifier: KeyboardModifierShift, + Key: "m", + }, + "KeyN": { + KeyCode: 78, + Code: "KeyN", + Modifier: KeyboardModifierShift, + Key: "n", + }, + "KeyO": { + KeyCode: 79, + Code: "KeyO", + Modifier: KeyboardModifierShift, + Key: "o", + }, + "KeyP": { + KeyCode: 80, + Code: "KeyP", + Modifier: KeyboardModifierShift, + Key: "p", + }, + "KeyQ": { + KeyCode: 81, + Code: "KeyQ", + Modifier: KeyboardModifierShift, + Key: "q", + }, + "KeyR": { + KeyCode: 82, + Code: "KeyR", + Modifier: KeyboardModifierShift, + Key: "r", + }, + "KeyS": { + KeyCode: 83, + Code: "KeyS", + Modifier: KeyboardModifierShift, + Key: "s", + }, + "KeyT": { + KeyCode: 84, + Code: "KeyT", + Modifier: KeyboardModifierShift, + Key: "t", + }, + "KeyU": { + KeyCode: 85, + Code: "KeyU", + Modifier: KeyboardModifierShift, + Key: "u", + }, + "KeyV": { + KeyCode: 86, + Code: "KeyV", + Modifier: KeyboardModifierShift, + Key: "v", + }, + "KeyW": { + KeyCode: 87, + Code: "KeyW", + Modifier: KeyboardModifierShift, + Key: "w", + }, + "KeyX": { + KeyCode: 88, + Code: "KeyX", + Modifier: KeyboardModifierShift, + Key: "x", + }, + "KeyY": { + KeyCode: 89, + Code: "KeyY", + Modifier: KeyboardModifierShift, + Key: "y", + }, + "KeyZ": { + KeyCode: 90, + Code: "KeyZ", + Modifier: KeyboardModifierShift, + Key: "z", + }, + "MetaLeft": { + KeyCode: 91, + Code: "MetaLeft", + Key: "Meta", + Location: 1, + }, + "MetaRight": { + KeyCode: 92, + Code: "MetaRight", + Key: "Meta", + Location: 2, + }, + "ContextMenu": { + KeyCode: 93, + Code: "ContextMenu", + Key: "ContextMenu", + }, + "NumpadMultiply": { + KeyCode: 106, + Code: "NumpadMultiply", + Key: "*", + Location: 3, + }, + "NumpadAdd": { + KeyCode: 107, + Code: "NumpadAdd", + Key: "+", + Location: 3, + }, + "NumpadSubtract": { + KeyCode: 109, + Code: "NumpadSubtract", + Key: "-", + Location: 3, + }, + "NumpadDivide": { + KeyCode: 111, + Code: "NumpadDivide", + Key: "/", + Location: 3, + }, + "F1": { + KeyCode: 112, + Code: "F1", + Key: "F1", + }, + "F2": { + KeyCode: 113, + Code: "F2", + Key: "F2", + }, + "F3": { + KeyCode: 114, + Code: "F3", + Key: "F3", + }, + "F4": { + KeyCode: 115, + Code: "F4", + Key: "F4", + }, + "F5": { + KeyCode: 116, + Code: "F5", + Key: "F5", + }, + "F6": { + KeyCode: 117, + Code: "F6", + Key: "F6", + }, + "F7": { + KeyCode: 118, + Code: "F7", + Key: "F7", + }, + "F8": { + KeyCode: 119, + Code: "F8", + Key: "F8", + }, + "F9": { + KeyCode: 120, + Code: "F9", + Key: "F9", + }, + "F10": { + KeyCode: 121, + Code: "F10", + Key: "F10", + }, + "F11": { + KeyCode: 122, + Code: "F11", + Key: "F11", + }, + "F12": { + KeyCode: 123, + Code: "F12", + Key: "F12", + }, + "F13": { + KeyCode: 124, + Code: "F13", + Key: "F13", + }, + "F14": { + KeyCode: 125, + Code: "F14", + Key: "F14", + }, + "F15": { + KeyCode: 126, + Code: "F15", + Key: "F15", + }, + "F16": { + KeyCode: 127, + Code: "F16", + Key: "F16", + }, + "F17": { + KeyCode: 128, + Code: "F17", + Key: "F17", + }, + "F18": { + KeyCode: 129, + Code: "F18", + Key: "F18", + }, + "F19": { + KeyCode: 130, + Code: "F19", + Key: "F19", + }, + "F20": { + KeyCode: 131, + Code: "F20", + Key: "F20", + }, + "F21": { + KeyCode: 132, + Code: "F21", + Key: "F21", + }, + "F22": { + KeyCode: 133, + Code: "F22", + Key: "F22", + }, + "F23": { + KeyCode: 134, + Code: "F23", + Key: "F23", + }, + "F24": { + KeyCode: 135, + Code: "F24", + Key: "F24", + }, + "NumLock": { + KeyCode: 144, + Code: "NumLock", + Key: "NumLock", + }, + "ScrollLock": { + KeyCode: 145, + Code: "ScrollLock", + Key: "ScrollLock", + }, + "AudioVolumeMute": { + KeyCode: 173, + Code: "AudioVolumeMute", + Key: "AudioVolumeMute", + }, + "AudioVolumeDown": { + KeyCode: 174, + Code: "AudioVolumeDown", + Key: "AudioVolumeDown", + }, + "AudioVolumeUp": { + KeyCode: 175, + Code: "AudioVolumeUp", + Key: "AudioVolumeUp", + }, + "MediaTrackNext": { + KeyCode: 176, + Code: "MediaTrackNext", + Key: "MediaTrackNext", + }, + "MediaTrackPrevious": { + KeyCode: 177, + Code: "MediaTrackPrevious", + Key: "MediaTrackPrevious", + }, + "MediaStop": { + KeyCode: 178, + Code: "MediaStop", + Key: "MediaStop", + }, + "MediaPlayPause": { + KeyCode: 179, + Code: "MediaPlayPause", + Key: "MediaPlayPause", + }, + "Semicolon": { + KeyCode: 186, + Code: "Semicolon", + Key: ";", + }, + "Equal": { + KeyCode: 187, + Code: "Equal", + Key: "=", + }, + "NumpadEqual": { + KeyCode: 187, + Code: "NumpadEqual", + Key: "=", + Location: 3, + }, + "Comma": { + KeyCode: 188, + Code: "Comma", + Key: ",", + }, + "Minus": { + KeyCode: 189, + Code: "Minus", + Key: "-", + }, + "Period": { + KeyCode: 190, + Code: "Period", + Key: ".", + }, + "Slash": { + KeyCode: 191, + Code: "Slash", + Key: "/", + }, + "Backquote": { + KeyCode: 192, + Code: "Backquote", + Key: "`", + }, + "BracketLeft": { + KeyCode: 219, + Code: "BracketLeft", + Key: "[", + }, + "Backslash": { + KeyCode: 220, + Code: "Backslash", + Key: "\\", + }, + "BracketRight": { + KeyCode: 221, + Code: "BracketRight", + Key: "]", + }, + "Quote": { + KeyCode: 222, + Code: "Quote", + Key: "\"", + }, + "AltGraph": { + KeyCode: 225, + Code: "AltGraph", + Key: "AltGraph", + }, + "Props": { + KeyCode: 247, + Code: "Props", + Key: "CrSel", + }, + "Cancel": { + KeyCode: 3, + Key: "Cancel", + Code: "Abort", + }, + "Clear": { + KeyCode: 12, + Key: "Clear", + Code: "Numpad5", + Location: 3, + }, + "Shift": { + KeyCode: 16, + Key: "Shift", + Code: "ShiftLeft", + Location: 1, + }, + "Control": { + KeyCode: 17, + Key: "Control", + Code: "ControlLeft", + Location: 1, + }, + "Alt": { + KeyCode: 18, + Key: "Alt", + Code: "AltLeft", + Location: 1, + }, + "Accept": { + KeyCode: 30, + Key: "Accept", + }, + "ModeChange": { + KeyCode: 31, + Key: "ModeChange", + }, + " ": { + KeyCode: 32, + Key: " ", + Code: "Space", + }, + "Print": { + KeyCode: 42, + Key: "Print", + }, + "Execute": { + KeyCode: 43, + Key: "Execute", + Code: "Open", + }, + "": { + KeyCode: 46, + Key: "\u0000", + Code: "NumpadDecimal", + Location: 3, + }, + "a": { + KeyCode: 65, + Key: "a", + Code: "KeyA", + }, + "b": { + KeyCode: 66, + Key: "b", + Code: "KeyB", + }, + "c": { + KeyCode: 67, + Key: "c", + Code: "KeyC", + }, + "d": { + KeyCode: 68, + Key: "d", + Code: "KeyD", + }, + "e": { + KeyCode: 69, + Key: "e", + Code: "KeyE", + }, + "f": { + KeyCode: 70, + Key: "f", + Code: "KeyF", + }, + "g": { + KeyCode: 71, + Key: "g", + Code: "KeyG", + }, + "h": { + KeyCode: 72, + Key: "h", + Code: "KeyH", + }, + "i": { + KeyCode: 73, + Key: "i", + Code: "KeyI", + }, + "j": { + KeyCode: 74, + Key: "j", + Code: "KeyJ", + }, + "k": { + KeyCode: 75, + Key: "k", + Code: "KeyK", + }, + "l": { + KeyCode: 76, + Key: "l", + Code: "KeyL", + }, + "m": { + KeyCode: 77, + Key: "m", + Code: "KeyM", + }, + "n": { + KeyCode: 78, + Key: "n", + Code: "KeyN", + }, + "o": { + KeyCode: 79, + Key: "o", + Code: "KeyO", + }, + "p": { + KeyCode: 80, + Key: "p", + Code: "KeyP", + }, + "q": { + KeyCode: 81, + Key: "q", + Code: "KeyQ", + }, + "r": { + KeyCode: 82, + Key: "r", + Code: "KeyR", + }, + "s": { + KeyCode: 83, + Key: "s", + Code: "KeyS", + }, + "t": { + KeyCode: 84, + Key: "t", + Code: "KeyT", + }, + "u": { + KeyCode: 85, + Key: "u", + Code: "KeyU", + }, + "v": { + KeyCode: 86, + Key: "v", + Code: "KeyV", + }, + "w": { + KeyCode: 87, + Key: "w", + Code: "KeyW", + }, + "x": { + KeyCode: 88, + Key: "x", + Code: "KeyX", + }, + "y": { + KeyCode: 89, + Key: "y", + Code: "KeyY", + }, + "z": { + KeyCode: 90, + Key: "z", + Code: "KeyZ", + }, + "Meta": { + KeyCode: 91, + Key: "Meta", + Code: "MetaLeft", + Location: 1, + }, + "*": { + KeyCode: 106, + Key: "*", + Code: "NumpadMultiply", + Location: 3, + }, + "+": { + KeyCode: 107, + Key: "+", + Code: "NumpadAdd", + Location: 3, + }, + "-": { + KeyCode: 109, + Key: "-", + Code: "NumpadSubtract", + Location: 3, + }, + "/": { + KeyCode: 111, + Key: "/", + Code: "NumpadDivide", + Location: 3, + }, + ";": { + KeyCode: 186, + Key: ";", + Code: "Semicolon", + }, + "=": { + KeyCode: 187, + Key: "=", + Code: "Equal", + }, + ",": { + KeyCode: 188, + Key: ",", + Code: "Comma", + }, + ".": { + KeyCode: 190, + Key: ".", + Code: "Period", + }, + "`": { + KeyCode: 192, + Key: "`", + Code: "Backquote", + }, + "[": { + KeyCode: 219, + Key: "[", + Code: "BracketLeft", + }, + `\`: { + KeyCode: 220, + Key: "\\", + Code: "Backslash", + }, + "]": { + KeyCode: 221, + Key: "]", + Code: "BracketRight", + }, + `"`: { + KeyCode: 222, + Key: "\"", + Code: "Quote", + }, + "Attn": { + KeyCode: 246, + Key: "Attn", + }, + "CrSel": { + KeyCode: 247, + Key: "CrSel", + Code: "Props", + }, + "ExSel": { + KeyCode: 248, + Key: "ExSel", + }, + "EraseEof": { + KeyCode: 249, + Key: "EraseEof", + }, + "Play": { + KeyCode: 250, + Key: "Play", + }, + "ZoomOut": { + KeyCode: 251, + Key: "ZoomOut", + }, + ")": { + KeyCode: 48, + Key: ")", + Code: "Digit0", + }, + "!": { + KeyCode: 49, + Key: "!", + Code: "Digit1", + }, + "@": { + KeyCode: 50, + Key: "@", + Code: "Digit2", + }, + "#": { + KeyCode: 51, + Key: "#", + Code: "Digit3", + }, + "$": { + KeyCode: 52, + Key: "$", + Code: "Digit4", + }, + "%": { + KeyCode: 53, + Key: "%", + Code: "Digit5", + }, + "^": { + KeyCode: 54, + Key: "^", + Code: "Digit6", + }, + "&": { + KeyCode: 55, + Key: "&", + Code: "Digit7", + }, + "(": { + KeyCode: 57, + Key: "\\(", + Code: "Digit9", + }, + "A": { + KeyCode: 65, + Key: "A", + Code: "KeyA", + }, + "B": { + KeyCode: 66, + Key: "B", + Code: "KeyB", + }, + "C": { + KeyCode: 67, + Key: "C", + Code: "KeyC", + }, + "D": { + KeyCode: 68, + Key: "D", + Code: "KeyD", + }, + "E": { + KeyCode: 69, + Key: "E", + Code: "KeyE", + }, + "F": { + KeyCode: 70, + Key: "F", + Code: "KeyF", + }, + "G": { + KeyCode: 71, + Key: "G", + Code: "KeyG", + }, + "H": { + KeyCode: 72, + Key: "H", + Code: "KeyH", + }, + "I": { + KeyCode: 73, + Key: "I", + Code: "KeyI", + }, + "J": { + KeyCode: 74, + Key: "J", + Code: "KeyJ", + }, + "K": { + KeyCode: 75, + Key: "K", + Code: "KeyK", + }, + "L": { + KeyCode: 76, + Key: "L", + Code: "KeyL", + }, + "M": { + KeyCode: 77, + Key: "M", + Code: "KeyM", + }, + "N": { + KeyCode: 78, + Key: "N", + Code: "KeyN", + }, + "O": { + KeyCode: 79, + Key: "O", + Code: "KeyO", + }, + "P": { + KeyCode: 80, + Key: "P", + Code: "KeyP", + }, + "Q": { + KeyCode: 81, + Key: "Q", + Code: "KeyQ", + }, + "R": { + KeyCode: 82, + Key: "R", + Code: "KeyR", + }, + "S": { + KeyCode: 83, + Key: "S", + Code: "KeyS", + }, + "T": { + KeyCode: 84, + Key: "T", + Code: "KeyT", + }, + "U": { + KeyCode: 85, + Key: "U", + Code: "KeyU", + }, + "V": { + KeyCode: 86, + Key: "V", + Code: "KeyV", + }, + "W": { + KeyCode: 87, + Key: "W", + Code: "KeyW", + }, + "X": { + KeyCode: 88, + Key: "X", + Code: "KeyX", + }, + "Y": { + KeyCode: 89, + Key: "Y", + Code: "KeyY", + }, + "Z": { + KeyCode: 90, + Key: "Z", + Code: "KeyZ", + }, + ":": { + KeyCode: 186, + Key: ":", + Code: "Semicolon", + }, + "<": { + KeyCode: 188, + Key: "\\<", + Code: "Comma", + }, + "_": { + KeyCode: 189, + Key: "_", + Code: "Minus", + }, + ">": { + KeyCode: 190, + Key: ">", + Code: "Period", + }, + "?": { + KeyCode: 191, + Key: "?", + Code: "Slash", + }, + "~": { + KeyCode: 192, + Key: "~", + Code: "Backquote", + }, + "{": { + KeyCode: 219, + Key: "{", + Code: "BracketLeft", + }, + "|": { + KeyCode: 220, + Key: "|", + Code: "Backslash", + }, + "}": { + KeyCode: 221, + Key: "}", + Code: "BracketRight", + }, + "SoftLeft": { + Key: "SoftLeft", + Code: "SoftLeft", + Location: 4, + }, + "SoftRight": { + Key: "SoftRight", + Code: "SoftRight", + Location: 4, + }, + "Camera": { + KeyCode: 44, + Key: "Camera", + Code: "Camera", + Location: 4, + }, + "Call": { + Key: "Call", + Code: "Call", + Location: 4, + }, + "EndCall": { + KeyCode: 95, + Key: "EndCall", + Code: "EndCall", + Location: 4, + }, + "VolumeDown": { + KeyCode: 182, + Key: "VolumeDown", + Code: "VolumeDown", + Location: 4, + }, + "VolumeUp": { + KeyCode: 183, + Key: "VolumeUp", + Code: "VolumeUp", + Location: 4, + }, +} diff --git a/pkg/drivers/cdp/input/manager.go b/pkg/drivers/cdp/input/manager.go index 5c53ecd1..731b5ae4 100644 --- a/pkg/drivers/cdp/input/manager.go +++ b/pkg/drivers/cdp/input/manager.go @@ -14,12 +14,20 @@ import ( "github.com/MontFerret/ferret/pkg/runtime/values" ) -type Manager struct { - client *cdp.Client - exec *eval.ExecutionContext - keyboard *Keyboard - mouse *Mouse -} +type ( + TypeParams struct { + Text core.Value + Clear values.Boolean + Delay values.Int + } + + Manager struct { + client *cdp.Client + exec *eval.ExecutionContext + keyboard *Keyboard + mouse *Mouse + } +) func NewManager( client *cdp.Client, @@ -213,7 +221,7 @@ func (m *Manager) ClickBySelectorAll(ctx context.Context, parentNodeID dom.NodeI return nil } -func (m *Manager) Type(ctx context.Context, objectID runtime.RemoteObjectID, text core.Value, delay values.Int) error { +func (m *Manager) Type(ctx context.Context, objectID runtime.RemoteObjectID, params TypeParams) error { err := m.ScrollIntoView(ctx, objectID) if err != nil { @@ -226,15 +234,27 @@ func (m *Manager) Type(ctx context.Context, objectID runtime.RemoteObjectID, tex return err } - _, min := core.NumberBoundaries(float64(delay)) + if params.Clear { + points, err := GetClickablePointByObjectID(ctx, m.client, objectID) + + if err != nil { + return err + } + + if err := m.ClearByXY(ctx, points); err != nil { + return err + } + } + + _, min := core.NumberBoundaries(float64(params.Delay)) beforeTypeDelay := time.Duration(min) time.Sleep(beforeTypeDelay * time.Millisecond) - return m.keyboard.Type(ctx, text.String(), int(delay)) + return m.keyboard.Type(ctx, params.Text.String(), int(params.Delay)) } -func (m *Manager) TypeBySelector(ctx context.Context, parentNodeID dom.NodeID, selector values.String, text core.Value, delay values.Int) error { +func (m *Manager) TypeBySelector(ctx context.Context, parentNodeID dom.NodeID, selector values.String, params TypeParams) error { err := m.ScrollIntoViewBySelector(ctx, selector) if err != nil { @@ -253,12 +273,84 @@ func (m *Manager) TypeBySelector(ctx context.Context, parentNodeID dom.NodeID, s return err } - _, min := core.NumberBoundaries(float64(delay)) + if params.Clear { + points, err := GetClickablePointByNodeID(ctx, m.client, found.NodeID) + + if err != nil { + return err + } + + if err := m.ClearByXY(ctx, points); err != nil { + return err + } + } + + _, min := core.NumberBoundaries(float64(params.Delay)) beforeTypeDelay := time.Duration(min) time.Sleep(beforeTypeDelay * time.Millisecond) - return m.keyboard.Type(ctx, text.String(), int(delay)) + return m.keyboard.Type(ctx, params.Text.String(), int(params.Delay)) +} + +func (m *Manager) Clear(ctx context.Context, objectID runtime.RemoteObjectID) error { + err := m.ScrollIntoView(ctx, objectID) + + if err != nil { + return err + } + + points, err := GetClickablePointByObjectID(ctx, m.client, objectID) + + if err != nil { + return err + } + + err = m.client.DOM.Focus(ctx, dom.NewFocusArgs().SetObjectID(objectID)) + + if err != nil { + return err + } + + return m.ClearByXY(ctx, points) +} + +func (m *Manager) ClearBySelector(ctx context.Context, parentNodeID dom.NodeID, selector values.String) error { + err := m.ScrollIntoViewBySelector(ctx, selector) + + if err != nil { + return err + } + + found, err := m.client.DOM.QuerySelector(ctx, dom.NewQuerySelectorArgs(parentNodeID, selector.String())) + + if err != nil { + return err + } + + points, err := GetClickablePointByNodeID(ctx, m.client, found.NodeID) + + if err != nil { + return err + } + + err = m.client.DOM.Focus(ctx, dom.NewFocusArgs().SetNodeID(found.NodeID)) + + if err != nil { + return err + } + + return m.ClearByXY(ctx, points) +} + +func (m *Manager) ClearByXY(ctx context.Context, points Quad) error { + err := m.mouse.ClickWithCount(ctx, points.X, points.Y, 3, 5) + + if err != nil { + return err + } + + return m.keyboard.Press(ctx, "Backspace") } func (m *Manager) Select(ctx context.Context, objectID runtime.RemoteObjectID, value *values.Array) (*values.Array, error) { diff --git a/pkg/drivers/cdp/input/mouse.go b/pkg/drivers/cdp/input/mouse.go index f41fbcbb..a1dbe1b7 100644 --- a/pkg/drivers/cdp/input/mouse.go +++ b/pkg/drivers/cdp/input/mouse.go @@ -19,11 +19,15 @@ func NewMouse(client *cdp.Client) *Mouse { } func (m *Mouse) Click(ctx context.Context, x, y float64, delay int) error { + return m.ClickWithCount(ctx, x, y, 1, delay) +} + +func (m *Mouse) ClickWithCount(ctx context.Context, x, y float64, count, delay int) error { if err := m.Move(ctx, x, y); err != nil { return err } - if err := m.Down(ctx, "left"); err != nil { + if err := m.DownWithCount(ctx, "left", count); err != nil { return err } @@ -31,23 +35,31 @@ func (m *Mouse) Click(ctx context.Context, x, y float64, delay int) error { time.Sleep(releaseDelay * time.Millisecond) - return m.Up(ctx, "left") + return m.UpWithCount(ctx, "left", count) } func (m *Mouse) Down(ctx context.Context, button string) error { + return m.DownWithCount(ctx, button, 1) +} + +func (m *Mouse) DownWithCount(ctx context.Context, button string, count int) error { return m.client.Input.DispatchMouseEvent( ctx, input.NewDispatchMouseEventArgs("mousePressed", m.x, m.y). - SetClickCount(1). + SetClickCount(count). SetButton(button), ) } func (m *Mouse) Up(ctx context.Context, button string) error { + return m.UpWithCount(ctx, button, 1) +} + +func (m *Mouse) UpWithCount(ctx context.Context, button string, count int) error { return m.client.Input.DispatchMouseEvent( ctx, input.NewDispatchMouseEventArgs("mouseReleased", m.x, m.y). - SetClickCount(1). + SetClickCount(count). SetButton(button), ) } diff --git a/pkg/drivers/http/document.go b/pkg/drivers/http/document.go index 49f5e52f..9f8a2208 100644 --- a/pkg/drivers/http/document.go +++ b/pkg/drivers/http/document.go @@ -215,10 +215,6 @@ func (doc *HTMLDocument) ClickBySelectorAll(_ context.Context, _ values.String) return core.ErrNotSupported } -func (doc *HTMLDocument) InputBySelector(_ context.Context, _ values.String, _ core.Value, _ values.Int) error { - return core.ErrNotSupported -} - func (doc *HTMLDocument) SelectBySelector(_ context.Context, _ values.String, _ *values.Array) (*values.Array, error) { return nil, core.ErrNotSupported } diff --git a/pkg/drivers/http/element.go b/pkg/drivers/http/element.go index f9b04f8d..dd7401fc 100644 --- a/pkg/drivers/http/element.go +++ b/pkg/drivers/http/element.go @@ -501,10 +501,22 @@ func (el *HTMLElement) ClickBySelectorAll(_ context.Context, _ values.String) er return core.ErrNotSupported } +func (el *HTMLElement) Clear(_ context.Context) error { + return core.ErrNotSupported +} + +func (el *HTMLElement) ClearBySelector(_ context.Context, _ values.String) error { + return core.ErrNotSupported +} + func (el *HTMLElement) Input(_ context.Context, _ core.Value, _ values.Int) error { return core.ErrNotSupported } +func (el *HTMLElement) InputBySelector(_ context.Context, _ values.String, _ core.Value, _ values.Int) error { + return core.ErrNotSupported +} + func (el *HTMLElement) Select(_ context.Context, _ *values.Array) (*values.Array, error) { return nil, core.ErrNotSupported } diff --git a/pkg/drivers/value.go b/pkg/drivers/value.go index d29eb417..5bf998ab 100644 --- a/pkg/drivers/value.go +++ b/pkg/drivers/value.go @@ -99,8 +99,14 @@ type ( Click(ctx context.Context) error + Clear(ctx context.Context) error + + ClearBySelector(ctx context.Context, selector values.String) error + Input(ctx context.Context, value core.Value, delay values.Int) error + InputBySelector(ctx context.Context, selector values.String, value core.Value, delay values.Int) error + Select(ctx context.Context, value *values.Array) (*values.Array, error) ScrollIntoView(ctx context.Context) error @@ -131,8 +137,6 @@ type ( GetChildDocuments(ctx context.Context) (*values.Array, error) - InputBySelector(ctx context.Context, selector values.String, value core.Value, delay values.Int) error - SelectBySelector(ctx context.Context, selector values.String, value *values.Array) (*values.Array, error) ScrollTop(ctx context.Context) error diff --git a/pkg/stdlib/html/clear.go b/pkg/stdlib/html/clear.go new file mode 100644 index 00000000..96384fce --- /dev/null +++ b/pkg/stdlib/html/clear.go @@ -0,0 +1,33 @@ +package html + +import ( + "context" + + "github.com/MontFerret/ferret/pkg/drivers" + "github.com/MontFerret/ferret/pkg/runtime/core" + "github.com/MontFerret/ferret/pkg/runtime/values" +) + +// InputClear clears a value from an underlying input element. +// @param source (HTMLPage | HTMLDocument | HTMLElement) - Event target. +// @param selector (String, options) - Selector. +func InputClear(ctx context.Context, args ...core.Value) (core.Value, error) { + err := core.ValidateArgs(args, 1, 2) + + if err != nil { + return values.None, err + } + + el, err := drivers.ToElement(args[0]) + + if err != nil { + return values.None, err + } + + // CLEAR(el) + if len(args) == 1 { + return values.None, el.Clear(ctx) + } + + return values.None, el.ClearBySelector(ctx, values.ToString(args[1])) +} diff --git a/pkg/stdlib/html/input.go b/pkg/stdlib/html/input.go index 950b17c6..50b4c880 100644 --- a/pkg/stdlib/html/input.go +++ b/pkg/stdlib/html/input.go @@ -2,7 +2,6 @@ package html import ( "context" - "github.com/MontFerret/ferret/pkg/drivers" "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/values" @@ -10,93 +9,74 @@ import ( ) // Input types a value to an underlying input element. -// @param source (Open | GetElement) - Event target. +// @param source (HTMLPage | HTMLDocument | HTMLElement) - Event target. // @param valueOrSelector (String) - Selector or a value. // @param value (String) - Target value. -// @param delay (Int, optional) - Waits delay milliseconds between keystrokes +// @param delay (Int, optional) - Target value. // @returns (Boolean) - Returns true if an element was found. func Input(ctx context.Context, args ...core.Value) (core.Value, error) { err := core.ValidateArgs(args, 2, 4) if err != nil { - return values.None, err + return values.False, err } - arg1 := args[0] - err = core.ValidateType(arg1, drivers.HTMLPageType, drivers.HTMLDocumentType, drivers.HTMLElementType) + el, err := drivers.ToElement(args[0]) if err != nil { return values.False, err } - if arg1.Type() == drivers.HTMLPageType || arg1.Type() == drivers.HTMLDocumentType { - doc, err := drivers.ToDocument(arg1) - - if err != nil { - return values.False, err - } - - // selector - arg2 := args[1] - err = core.ValidateType(arg2, types.String) + delay := values.NewInt(25) - if err != nil { - return values.False, err - } + // INPUT(el, value) + if len(args) == 2 { + return values.True, el.Input(ctx, args[1], delay) + } - selector := values.ToString(arg2) - delay := values.Int(0) + var selector values.String + var value core.Value - if len(args) == 4 { - arg4 := args[3] + // INPUT(el, valueOrSelector, valueOrOpts) + if len(args) == 3 { + switch v := args[2].(type) { + // INPUT(el, value, delay) + case values.Int, values.Float: + value = args[1] + delay = values.ToInt(v) - err = core.ValidateType(arg4, types.Int) + return values.True, el.Input(ctx, value, delay) + default: + // INPUT(el, selector, value) + err := core.ValidateType(args[1], types.String) if err != nil { return values.False, err } - delay = values.ToInt(arg4) + selector = values.ToString(args[1]) + value = args[2] } - - exists, err := doc.ExistsBySelector(ctx, selector) + } else { + // INPUT(el, selector, value, delay) + err := core.ValidateType(args[3], types.Int) if err != nil { return values.False, err } - if !exists { - return values.False, nil - } - - return values.True, doc.InputBySelector(ctx, selector, args[2], delay) + delay = values.ToInt(args[3]) } - el, err := drivers.ToElement(arg1) + exists, err := el.ExistsBySelector(ctx, selector) if err != nil { - return values.None, err - } - - delay := values.Int(0) - - if len(args) == 3 { - arg3 := args[2] - - err = core.ValidateType(arg3, types.Int) - - if err != nil { - return values.False, err - } - - delay = arg3.(values.Int) + return values.False, err } - err = el.Input(ctx, args[1], delay) - - if err != nil { - return values.False, err + if !exists { + return values.False, nil } - return values.True, nil + return values.True, el.InputBySelector(ctx, selector, value, delay) } diff --git a/pkg/stdlib/html/lib.go b/pkg/stdlib/html/lib.go index 9139b7be..a57c694e 100644 --- a/pkg/stdlib/html/lib.go +++ b/pkg/stdlib/html/lib.go @@ -37,6 +37,7 @@ func RegisterLib(ns core.Namespace) error { "INNER_TEXT_SET": SetInnerText, "INNER_TEXT_ALL": GetInnerTextAll, "INPUT": Input, + "INPUT_CLEAR": InputClear, "MOUSE": MouseMoveXY, "NAVIGATE": Navigate, "NAVIGATE_BACK": NavigateBack,