最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to simulate user typing in form - Stack Overflow

programmeradmin4浏览0评论

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, 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"
    }
  })
}),

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., 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"
    }
  })
}),

Share Improve this question edited Sep 22, 2021 at 14:21 Pietro Nadalini asked Sep 26, 2020 at 1:18 Pietro NadaliniPietro Nadalini 1,8003 gold badges16 silver badges34 bronze badges 3
  • 1 This might help stackoverflow./questions/47617616/… – sagar1025 Commented Sep 26, 2020 at 1:25
  • The field likely expects to catch key events in order to give the credit card number fancy formatting. You'd either need to simulate those key events, or you would need to populate value and then trigger the correct site-provided function to get the site to synchronize the value and the view. – Ouroborus Commented Sep 26, 2020 at 6:58
  • @Ouroborus, do you know how I can do that? I have tried using this stackoverflow./a/12187302/9801177 but I don't think its registering a key – Pietro Nadalini Commented Sep 26, 2020 at 15:30
Add a ment  | 

1 Answer 1

Reset to default 11

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, posed: 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);
发布评论

评论列表(0)

  1. 暂无评论