Skip to content
This repository was archived by the owner on Dec 16, 2023. It is now read-only.

Forms onsubmit handler gets called twice when submitting #1173

Open
juamedgod opened this issue Sep 12, 2018 · 4 comments
Open

Forms onsubmit handler gets called twice when submitting #1173

juamedgod opened this issue Sep 12, 2018 · 4 comments

Comments

@juamedgod
Copy link
Contributor

When defining a form with a onsubmit handler setup, the code gets called twice.

I have prepared a snippet using mocha for ease testing.

Just place the below text under zombie/test/issue.js:

const assert  = require('assert');
const brains  = require('./helpers/brains');
const Browser = require('../src');


describe('Forms Issue', function() {
  const browser = new Browser();
  browser.on('alert', function(message) {
    console.log(`ALERT ${message}`);
  });

  before(function() {
    return brains.ready();
  });
  before(function() {
    brains.post('/testform_submit', function(req, res) {
      res.send(`<html><title>Results</title><body>OK</body></html>`);
    });
    brains.static('/forms/form', `
      <html>
        <head>
          <script>
           var called = 0;
           document.myEvents = [];
           function trackEvent(eventName) {
             called += 1;
             alert("Called " + called + " times, asked to track " + eventName);
             document.myEvents.push(eventName);
           }
          </script>
         </head>
         <body>
           <form id="install_install2" method="post" onsubmit="trackEvent('submit_form');" action="/testform_submit">
             <input type="submit" onclick="trackEvent('clicked');" value="Submit">
           </form>
         </body>
        </html>
       `);
  });
  describe('User visits form', function() {
    let document = null;
    before(function(done) {
      browser.visit('/forms/form', function() {
        document = browser.document;
        done();
      });
    });

    describe('submits form', function() {
      before(function(done) {
        browser.pressButton('Submit', done);
      });

      it('should be successful', function() {
        browser.assert.success();
      });

      it('should report two events', function() {
        console.log(document.myEvents);
        assert.equal(document.myEvents, ['clicked', 'submit_form']);
      });
    });
  });
});

And invoke it with mocha:

$> cd zombie
$> mocha test/issue.js
  Forms Issue
    User visits form
      submits form
ALERT Called 1 times, asked to track clicked
ALERT Called 2 times, asked to track submit_form
ALERT Called 3 times, asked to track submit_form
        ✓ should be successful
[ 'clicked', 'submit_form', 'submit_form' ]
        1) should report two events


  1 passing (349ms)
  1 failing

  1) Forms Issue
       User visits form
         submits form
           should report two events:

      AssertionError: [ 'clicked', 'submit_form', 'submit_form' ] == [ 'clicked', 'submit_form' ]
      + expected - actual

       [
         "clicked"
         "submit_form"
      -  "submit_form"
       ]

It adds some printed messages for debugging, I apologize for the noise :).

The expected result would be to call trackEvent twice, once in the button onclick, and once in the form submit, but the latter gets called two times, as it can be seen in the "alert" messages and from the document.myEvents property that gets populated.

issue.zip

@TheFive
Copy link

TheFive commented Oct 28, 2018

If i do two small changes to your code, it is running

Line 54:

browser.click('Input', done);

And line 60

assert.deepEqual(document.myEvents, ['clicked', 'submit_form']);

I am a little bit confused, because I have change yesterday all my browser.click to browser.pressButton but are still in upgrade to Zombie 6 mode, so your issue looks to be helpful to me.

What I do not understand, is that the pressButton function is just doing a "click"
https://github.com/assaf/zombie/blob/master/src/index.js#L951
and why that doubles the submit event.

@TheFive
Copy link

TheFive commented Oct 28, 2018

I just add a reference to my issue yesterday:
#1180

@TheFive
Copy link

TheFive commented Oct 28, 2018

In my source - couldn't reduce it to such a nice testcase as @juamedgod yet - i have the opposite problem.

browser.pressButton("Input#okbutton") does 1 time submit and browser.click("Input#okbutton") does nothing (even no debug output from Zombie)

@TheFive
Copy link

TheFive commented Oct 28, 2018

I have done some investigation

The submit handler onsubmit is called twice with pressButton and once with click.

The submit (post) without submit handler is done once with pressButton and never with click.

For me this looks like a bug, as the tester should not have any knowledge of the implementation of the submit (and the developer should be free to change from onsubmit handler to a submit button or vice versa).

// See Github Issue 1180
// https://github.com/assaf/zombie/issues/1180


const assert  = require('assert');
const brains  = require('./helpers/brains');
const Browser = require('../src');


describe('Forms Issue', function() {
  const browser = new Browser();
  let submit_1_called = false;
  let submit_2_called = false;
  browser.on('alert', function(message) {
    console.log(`ALERT ${message}`);
  });

  before(function() {
    return brains.ready();
  });
  before(function() {

    brains.post('/testform_submit_1', function(req, res) {
      console.log("Submit 1 Called");
      assert(!submit_1_called);
      submit_1_called = true;
      res.send(`<html><title>Results</title><body>OK</body></html>`);
    });
    brains.post('/testform_submit_2', function(req, res) {
      console.log("Submit 2 Called");
      assert(!submit_2_called);
      submit_2_called = true;
      res.send(`<html><title>Results</title><body>OK</body></html>`);
    });
    brains.static('/forms/form', `
      <html>
        <head>
          <script>
           var called = 0;
           document.myEvents = [];
           function trackEvent(eventName) {
             called += 1;
             alert("Called " + called + " times, asked to track " + eventName);
             document.myEvents.push(eventName);
           }
          </script>
         </head>
         <body>
           <form id="install_install1" method="post" onsubmit="trackEvent('submit_form');" action="/testform_submit_1">
             <input id="i_1" type="submit" onclick="trackEvent('clicked');" value="Submit"\>
           </form>
           <form id="install_install2" method="post"  action="/testform_submit_2">
             <input id="i_2" type="submit"  value="Submit"\>
           </form>
         </body>
        </html>
       `);
  });
  describe('User visits form', function() {
    let document = null;
    beforeEach(function(done) {
      submit_1_called = false;
      submit_2_called = false;
      browser.visit('/forms/form', function() {
        document = browser.document;
        done();
      });
    });

    describe('submits form with pressButton', function() {

      it('should be successful for onsubmit', async function() {
        await browser.pressButton('Input#i_1');
        browser.assert.success();
        console.log(document.myEvents);
        assert.deepEqual(document.myEvents, ['clicked', 'submit_form']);
        // -->> the installed submithandler is called twice (wrong)
      });
      it('should be successful for submitting form', async function() {
        await browser.pressButton('Input#i_2');
        browser.assert.success();
        browser.assert.text("body","OK");
        // -->> everything is fine, no submit handler. 1 time submit is called (OK)
      });
    });
    describe('submits form with click', function() {

      it('should be successful for onsubmit', async function() {
        await browser.click('Input#i_1');
        browser.assert.success();
        console.log(document.myEvents);
        assert.deepEqual(document.myEvents, ['clicked', 'submit_form']);
        // -->> everything is fine, the submithandler is called once. (OK)
      });
      it('should be successful for submitting form', async function() {
        await browser.click('Input#i_2');
        browser.assert.success();
        browser.assert.text("body","OK");
        // -->> no submithandler is called (wrong)
      });
    });
  });
});

I have put the test results as comments to the testfiles. (and used async/await as makes reading of zombie tests much easier).

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants