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

fix: make <Link> inert for setupRenderingTest #127

Merged
merged 1 commit into from
Aug 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions addon/components/link/component.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { assert } from '@ember/debug';
import { action } from '@ember/object';
import { reads } from '@ember/object/computed';
import Transition from '@ember/routing/-private/transition';
Expand Down Expand Up @@ -57,6 +58,17 @@ export default class LinkComponent extends Component<LinkArgs> {
@service
private router!: RouterService;

/**
* Whether the router has been initialized. This will be false in render
* tests.
*
* @see https://github.com/buschtoens/ember-link/issues/126
*/
private get isRouterInitialized() {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return Boolean((this.router as any)._router._routerMicrolib);
}

@reads('router.currentURL')
private currentURL!: string;

Expand Down Expand Up @@ -97,6 +109,7 @@ export default class LinkComponent extends Component<LinkArgs> {
* attribute.
*/
get href(): string {
if (!this.isRouterInitialized) return '';
return this.router.urlFor(...this.routeArgs);
}

Expand All @@ -105,6 +118,7 @@ export default class LinkComponent extends Component<LinkArgs> {
* models and query params.
*/
get isActive(): boolean {
if (!this.isRouterInitialized) return false;
this.currentURL; // eslint-disable-line no-unused-expressions
return this.router.isActive(...this.routeArgs);
}
Expand All @@ -114,6 +128,7 @@ export default class LinkComponent extends Component<LinkArgs> {
* models, but ignoring query params.
*/
get isActiveWithoutQueryParams() {
if (!this.isRouterInitialized) return false;
this.currentURL; // eslint-disable-line no-unused-expressions
return this.router.isActive(
this.args.route,
Expand All @@ -130,6 +145,7 @@ export default class LinkComponent extends Component<LinkArgs> {
* params.
*/
get isActiveWithoutModels() {
if (!this.isRouterInitialized) return false;
this.currentURL; // eslint-disable-line no-unused-expressions
return this.router.isActive(this.args.route);
}
Expand All @@ -139,8 +155,15 @@ export default class LinkComponent extends Component<LinkArgs> {
*/
@action
transitionTo(event?: Event | unknown): Transition {
// Intentionally putting this *before* the assertion to prevent navigating
// away in case of a failed assertion.
this.preventDefault(event);

assert(
'You can only call `transitionTo`, when the router is initialized, e.g. when using `setupApplicationTest`.',
this.isRouterInitialized
);

return this.router.transitionTo(...this.routeArgs);
}

Expand All @@ -150,8 +173,15 @@ export default class LinkComponent extends Component<LinkArgs> {
*/
@action
replaceWith(event?: Event | unknown): Transition {
// Intentionally putting this *before* the assertion to prevent navigating
// away in case of a failed assertion.
this.preventDefault(event);

assert(
'You can only call `replaceWith`, when the router is initialized, e.g. when using `setupApplicationTest`.',
this.isRouterInitialized
);

return this.router.replaceWith(...this.routeArgs);
}

Expand Down
47 changes: 47 additions & 0 deletions tests/helpers/wait-for-error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { waitUntil } from '@ember/test-helpers';

import Ember from 'ember';

import { on, off } from 'rsvp';

/**
* I would be using `ember-qunit-assert-helpers` here, but it does not work with
* async rendering. :(
*
* Adapted from https://github.com/workmanw/ember-qunit-assert-helpers/issues/18#issuecomment-390003905
*/
export default async function waitForError(
callback: () => Promise<unknown>,
options?: Parameters<typeof waitUntil>[1]
) {
const originalEmberListener = Ember.onerror;
const originalWindowListener = window.onerror;

let error: Error | undefined;
Ember.onerror = uncaughtError => {
error = uncaughtError;
};
window.onerror = (
_message,
_source,
_lineNumber,
_columnNumber,
uncaughtError
) => {
error = uncaughtError;
};
on('error', Ember.onerror);

await Promise.all([
waitUntil(() => error, options).finally(() => {
Ember.onerror = originalEmberListener;
window.onerror = originalWindowListener;
off('error', Ember.onerror);
}),
callback()
]);

if (!error) throw new Error('No Error was thrown.');

return error;
}
52 changes: 52 additions & 0 deletions tests/integration/components/link-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { render, click } from '@ember/test-helpers';
import { setupRenderingTest } from 'ember-qunit';
import { module, test } from 'qunit';

import hbs from 'htmlbars-inline-precompile';

import waitForError from 'dummy/tests/helpers/wait-for-error';

module('Integration | Component | link', function(hooks) {
setupRenderingTest(hooks);

// Regression for: https://github.com/buschtoens/ember-link/issues/126
test('it renders', async function(assert) {
await render(hbs`
<Link @route="foo" as |l|>
<a
data-test-link
href={{l.href}}
class={{if l.isActive "is-active"}}
{{on "click" l.transitionTo}}
>
Link
</a>
</Link>
`);

assert.dom('[data-test-link]').hasAttribute('href', '');
assert.dom('[data-test-link]').hasNoClass('is-active');
});

test('triggering a transition has no effect', async function(assert) {
await render(hbs`
<Link @route="foo" as |l|>
<a
data-test-link
href={{l.href}}
class={{if l.isActive "is-active"}}
{{on "click" l.transitionTo}}
>
Link
</a>
</Link>
`);

const error = await waitForError(() => click('[data-test-link]'));
assert.ok(error instanceof Error);
assert.strictEqual(
error.message,
'Assertion Failed: You can only call `transitionTo`, when the router is initialized, e.g. when using `setupApplicationTest`.'
);
});
});