Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chained API that doesn't change scope #43

Open
joshski opened this issue Jul 20, 2016 · 2 comments
Open

Chained API that doesn't change scope #43

joshski opened this issue Jul 20, 2016 · 2 comments

Comments

@joshski
Copy link
Member

joshski commented Jul 20, 2016

The current API gently encourages tight coupling to the structure of your HTML. I want to introduce a chained API which goes the other way.

The idea of moving away from the structure is my preference for being more tightly coupled to the user experience (which bits of text to click) rather than the implementation (whether that text appears on buttons or links, which css classes those elements have) and a distaste for being overly DRY in tests.

I'll rework the example from the top of the readme to illustrate what I have in mind (incidentally this example needs work, because it doesn't do any assertions, when browser-monkey is described as an "assertion library"! But anyway, it's good for this discussion):

var adminPanel = browser.component({
  searchUsers: function () {
    return this.find('.search');
  },
  userResult: function (name) {
    // find a user in the results by their name
    return this.find('.results .user', {text: name});
  }
  userEditor: function () {
    // return the user editor, scoped to the .user-editor div.
    return this.find('.user-editor').component({
      name: function () { this.find('.name'); },
      email: function () { this.find('.email'); },
      save: function () { this.find('.save'); }
    });
  }
});

it('can search for, edit and save a user', function () {
  return adminPanel.searchUsers().typeIn('bar').then(function () {
    return adminPanel.userResult('Barry').click();
  }).then(function () {
    var userEditor = adminPanel.userEditor();
    return Promise.all([
      userEditor.name().typeIn('Barry Jones'),
      userEditor.email().typeIn('[email protected]')
    ]).then(function () {
      return userEditor.save().click();
    });
  }).then(function () {
    // verify that the user was saved
    // use mock-xhr-router!
  });
});

Now, if we use more semantic finders and no components, we could theoretically rephrase all of the above as:

it('can search for, edit and save a user', function () {
  return browser
    .typeInto('Search for users', 'bar')
    .click('Barry')
    .thenUnder('Edit User', function(userEditor) {
      return userEditor
        .typeInto('Name', 'Barry Jones')
        .typeInto('Email', '[email protected]')
        .click('Save');
    })
    .then(function() {
      // verify that the user was saved
      // use mock-xhr-router!
    });
});

The key thing to consider in this example is that thenUnder is an alternative to find. Whereas find changes the scope in the same chain, thenUnder would start a new scope, in an entirely new chain passed to a callback. If we never change the scope in a single chain, then we can lose a lot of promise boilerplate in common cases, i.e:

browser.click('Happy').then(=> browser.click('Days'))

// becomes equivalent to:

browser.click('Happy').click('Days')

To achieve this, we'd have to return promises that were also links in the chained API. Is that too weird?

I'm happy to do this if there's a broad agreement it's a good idea. I don't use components, and this would kind of break the component API. So it could be introduced as an alternative API, or it could replace the existing API. What do you think?

@joshski
Copy link
Member Author

joshski commented Jul 24, 2016

I think this too-many-thens problem can be solved in a general way, so I made this:

https://github.com/featurist/promise-builder

With this, we can transform the browser monkey API to the style above, relatively easily:

http://requirebin.com/?gist=2fa7c16da25a55f5e824959c5ad2fbc5

@dereke
Copy link
Member

dereke commented Apr 3, 2017

I am guessing we are going to close this now?

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

No branches or pull requests

2 participants