How to simulate user typing in form

Viewed 577

I'm trying to make a chrome extension that fills out a form in a specific page. (You can think of it like LastPass filling the user and passwords)

Currently I'm trying to fill out a form for a credit card with Javascript, but the website just gets stucked loading when you submit the form if you insert the credit card or other information through Javascript.

I have currently tried adding the card with this document.querySelector("#cardNumber").value="5454545454545454"; and I have tried doing .focus() or .click() on that input, even adding the value digit by digit, but it doesn't seem to trigger the website events that save the credit card correctly.

So, what I'm currently trying to figure out is if there's any way I can simulate the user adding the form so the website events get triggered. (The website is Mercadolibre.com, but I don't know if that helps in any way).

Here's a snippet of the website's code that gets executed when the card number changes.

App.module("Checkout.Payments.Views", function(e, t, n, i, o) {
  var s = {
    cardNumber: "number",
    ownerName: "name",
    expirationDate: "expiration",
    securityCode: "security",
    brand: "brand"
  };
  e.CardContainer = i.ItemView.extend({
    getTemplate: function() {
      return t.Utils.getTemplate(t.Components.templates.card, '[data-js="card"]')
    },
    className: "new-card__container--view",
    ui: {
      card: ".ui-card"
    },
    initialize: function() {
      var e = this;
      this.on("refresh", this.onCardRefresh),
        this.on("rotate", this.onRotate),
        this.on("brandSet", this.onBrandSet),
        this.on("showSecurityHint", this.onShowSecurityHint),
        this.modelEvents = {},
        this.model.keys().forEach(function(t) {
          "binHelper" !== t && (e.modelEvents["change:" + t] = function() {
            return e.onCardDataChanged({
              key: t,
              rotate: "securityCode" === t
            })
          })
        }),
        this.bindEntityEvents(this.model, this.modelEvents),
        this.brandSet = !1
    },
    onBrandSet: function() {
      this.brandSet = !0
    },
    onShow: function() {
      this.cardComponent = new CardComponent,
        o(this.cardComponent.cardElements.name).attr("data-title", this.model.get("ownerNamePlaceholder")),
        this.trigger("refresh")
    },
    onCardRefresh: function() {
      var e = this;
      this.model.keys().forEach(function(t) {
        e.model.trigger("change:" + t, {
          rotate: !1
        })
      })
    },
    onCardDataChanged: function(e) {
      var t = e.key + "Changed",
        n = t.replace(/\w{1}/, function(e) {
          return e.toUpperCase()
        }),
        i = "on" + n;
      this.triggerMethod(this[i] instanceof Function ? t : "otherCardDataChanged", e.key)
    },
    onCardNumberChanged: function(e) {
      var t = this.model.get(e);
      this.cardComponent[s[e]] = this.model.get(e),
        t.length < 6 && (this.model.set("brand", ""),
          this.model.set("bin", ""),
          this.brandSet = !1)
    },
    onCardOwnerNameChanged: function(e) {
      var t = this.model.get(e) || this.model.get("ownerNamePlaceholder");
      this.cardComponent[s[e]] = t
    },
    onOtherCardDataChanged: function(e) {
      this.cardComponent[s[e]] = this.model.get(e),
        "" !== this.model.get("brand") && this.trigger("brandSet")
    },
    onRotate: function(e) {
      "front" === e ? (this.cardComponent.rotateFront(),
        this.cardComponent.blur = "securityFront") : "back" === e && this.cardComponent.rotateBack()
    },
    onShowSecurityHint: function() {
      this.cardComponent.focus = "securityFront"
    }
  })
}),

1 Answers

The solution for this issue is sending events that get triggered when the user is typing manually. For example the events (blur, change, and input).

I added the events as constants like so:

const EVENT_OPTIONS = {bubbles: true, cancelable: false, composed: true};
const EVENTS = {
    BLUR: new Event("blur", EVENT_OPTIONS),
    CHANGE: new Event("change", EVENT_OPTIONS),
    INPUT: new Event("input", EVENT_OPTIONS),
};

Afterwards, depending on the website, you might only need to add some of them or all like this:

const inputElement = document.querySelector("#cardNumber");
inputElement.value = "5454545454545454";
inputElement.dispatchEvent(EVENTS.INPUT);

In other websites, you can simulate the events better sending the CHANGE event and then the BLUR. And for other websites that use React, you might need to use React's _valueTracker like so:

const inputElement = document.querySelector("#cardNumber");
inputElement.value = "5454545454545454";
const tracker = inputElement._valueTracker;
tracker && tracker.setValue("5454545454545454");
inputElement.dispatchEvent(EVENTS.INPUT);
inputElement.dispatchEvent(EVENTS.BLUR);
Related