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

Callback context is inconsistent #133

Closed
trentmwillis opened this issue Dec 11, 2015 · 7 comments
Closed

Callback context is inconsistent #133

trentmwillis opened this issue Dec 11, 2015 · 7 comments

Comments

@trentmwillis
Copy link
Member

Currently when callbacks for a test module are contextualized, they get bound to the test module rather than the test context. This causes inconsistent behavior, since setup/teardown get invoked with the test context.

Practically, this means that if you do something such as:

moduleFor('component:foo-bar', {
  integration: true,

  setup() {
    this.set('title', 'first title'); // works as expected
  },

  changeTitle() {
    this.set('title', 'second title'); // doesn't work
  }
});

test('it renders', function(assert) {
  this.changeTitle();
});

changeTitle won't work properly, instead you have to do:

changeTitle() {
  this.context.set('title', 'second title');
}

This is inconsistent and not intuitive. Can we change it such that all callbacks are invoked with the test context? This might limit access to some test module properties, but I feel most of those shouldn't be getting accessed anyway.

@rwjblue
Copy link
Member

rwjblue commented Dec 11, 2015

Generally, I agree with you that the context should be the same for all of the callbacks. Unfortunately, this is a breaking change and I am not sure how exactly we would go about deprecating the current behavior.

@dgeb - Thoughts?

@mmun
Copy link
Member

mmun commented Dec 11, 2015

I also agree. Having consistent context on all the methods is important for preserving the QUnit mental model.

@trentmwillis
Copy link
Member Author

@rwjblue true, definitely breaking. Could we do something like proxy attributes from the test module onto the context? Would probably get ugly though.

@rwjblue
Copy link
Member

rwjblue commented Dec 11, 2015

Yes, @mmun and I were chatting this through in slack and I came up with the following snippet, that should work in a backwards compatible way:

buildDeprecatedContext(module, context) {
  let keysForDeprecation = Object.keys(module);

  if (keysForDeprecation.length === 0) {
    return; // do not call Object.create if we don't need to
  }

  let wrappedContext = Object.create(context);

  for (let index = 0, length = keysForDeprecation.length; index++; index < length) {
    let key = keys[index];

    Object.defineProperty(wrappedContext, key, {
      get: function() {
        Ember.deprecate('ffffuuuuuu, fix it!');
        return module[key];
      }
    });
  });
},

And call that from contextualizeCallbacks (or something like that).

We would need tests for:

  • accessing the TestModule properties on this with a deprecation
  • accessing the test context as this without deprecation

@trentmwillis - Think you would like to tackle this?

@trentmwillis
Copy link
Member Author

I'd definitely be willing to work on this. One remaining question, how should we handle the situation where a user has defined something on the context that conflicts with the module? I'm thinking let the module "win" (as happens in your snippet), but wasn't sure if there is a better approach for that edge case.

@rwjblue
Copy link
Member

rwjblue commented Dec 12, 2015

Yes, module should win with a more specific deprecation

@Turbo87
Copy link
Member

Turbo87 commented Aug 18, 2016

@rwjblue seems this has been resolved by #136

@rwjblue rwjblue closed this as completed Aug 18, 2016
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

4 participants