To stub or not to stub the router service in integration tests

Let’s imagine a component uses the router service currentRouteName property to decide what to display in its template.

To tests this, I would write an integration test where I would stub the router service and provide it with a dummy currentRouteName value.

But in a recent comment on a related topic https://github.com/ember-cli/ember-cli-qunit/issues/203#issuecomment-506735392, @rwjblue suggested that we should not stub the router service.

If we don’t stub the router service, then what is the right way to write this integration test?

Thx for the insight

Ju

It might be helpful if you shared a basic gist of the component and test here? I’m happy to try to answer, but its a bit too abstract at the moment…

We have a similar use-case but @rwjblue is right, the description is very abstract. In our case we have a component which uses the router service to transition to another page if an error occurs.

In the test, we didn’t want to do the actual transition. In the component test, we only want to assure that the component calls transitionTo with the correct parameters.

So in our case we mocked the router and put a spy on the transitionTo method of the mocked object.

Maybe there is a smarter way but it works for us and we do not need to care about all the stuff which would be triggered by a transitionTo.

Sorry for the abstract description. Here is a less abstract example:

// component.js
import Component from "@ember/component";
import { service } from '@ember-decorators/service';

export default class MyComponent extends Component {
  @service router;
}

{{!-- template.hbs --}}
<p>
  This component might be rendered in many different routes ;
</p>

{{#if (eq this.router.currentRouteName "my-special-route")}}
  <p data-test-special-route-only-content>
    but I want to show this only on a particular route
  </p>
{{/if}}

When testing MyComponent, this.router.currentRouteName needs to be set, I this is how I do it:

// component-test.js
import { module, test } from "qunit";
import { setupRenderingTest } from "ember-qunit";
import { render } from "@ember/test-helpers";
import hbs from "htmlbars-inline-precompile";
import Service from '@ember/service';

module("Integration | Component | <MyComponent />", function( hooks ) {
  setupRenderingTest(hooks);

  module('when rendering on any route', function(hooks) {
    hooks.beforeEach(function() {
      const routerStub = Service.extend({currentRouteName: 'dummy'},);
      this.owner.register('service:router', routerStub);
    });

    test("its", async function(assert) {
      await render(hbs`<MyComponent />`);
      assert
        .dom("[data-test-special-route-only-content]")
        .doesNotExist();
    });
  });

  module('when rendering on the special route', function(hooks) {
    hooks.beforeEach(function() {
      const routerStub = Service.extend({currentRouteName: 'my-special-route'},);
      this.owner.register('service:router', routerStub);
    });

    test("its", async function(assert) {
      await render(hbs`<MyComponent />`);
      assert
        .dom("[data-test-special-route-only-content]")
        .exists();
    });
  });
});

If stubbing the router service is a bad practice, I would like to know what is the alternative testing strategy.

Thx

We have a tab component which uses the router service to determine the current route so we can set the tab as “active”. Right now, I’m not able to write an integration test for it, so I’ve ended up using an acceptance test for it.

In a nutshell, this is what I’m trying to do:

<UiTabs as |Tabs|>
  <Tabs.tab @href="/foo">
    Tab One
  </Tabs.tab>
  <Tabs.tab @href="/bar">
    Tab Two
  </Tabs.tab>
  <Tabs.tab @href="/baz">
    Tab Three
  </Tabs.tab>
</UiTabs>