fix(aio): correctly intercept links with LinkDirective

This commit is contained in:
Peter Bacon Darwin 2017-03-05 19:46:59 +00:00 committed by Igor Minar
parent fe962f6de7
commit 5815983178
2 changed files with 110 additions and 8 deletions

View File

@ -1,7 +1,93 @@
import { async, inject, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { Component } from '@angular/core';
import { LocationService } from 'app/shared/location.service';
import { MockLocationService } from 'testing/location.service';
import { LinkDirective } from './link.directive';
xdescribe('LinkDirective', () => {
it('should attach to all anchor elements', () => {});
it('should bind a property to the "href" attribute', () => {});
it('should intercept clicks on the element and call `location.go()`', () => {});
describe('LinkDirective', () => {
@Component({
template: '<a href="{{ url }}">Test Link</a>'
})
class TestComponent {
url: string;
}
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
LinkDirective,
TestComponent
],
providers: [
{ provide: LocationService, useFactory: () => new MockLocationService('initial/url') }
]
})
.compileComponents();
}));
it('should attach to all anchor elements', () => {
const fixture = TestBed.createComponent(TestComponent);
const directiveElement = fixture.debugElement.query(By.directive(LinkDirective));
expect(directiveElement.name).toEqual('a');
});
it('should bind a property to the "href" attribute', () => {
const fixture = TestBed.createComponent(TestComponent);
const directiveElement = fixture.debugElement.query(By.directive(LinkDirective));
fixture.componentInstance.url = 'test/url';
fixture.detectChanges();
expect(directiveElement.properties['href']).toEqual('test/url');
});
it('should set the "target" attribute to "_blank" if the href is absolute, otherwise "_self"', () => {
const fixture = TestBed.createComponent(TestComponent);
const directiveElement = fixture.debugElement.query(By.directive(LinkDirective));
fixture.componentInstance.url = 'http://test/url';
fixture.detectChanges();
expect(directiveElement.properties['target']).toEqual('_blank');
fixture.componentInstance.url = 'https://test/url';
fixture.detectChanges();
expect(directiveElement.properties['target']).toEqual('_blank');
fixture.componentInstance.url = 'ftp://test/url';
fixture.detectChanges();
expect(directiveElement.properties['target']).toEqual('_blank');
fixture.componentInstance.url = '//test/url';
fixture.detectChanges();
expect(directiveElement.properties['target']).toEqual('_blank');
fixture.componentInstance.url = 'test/url';
fixture.detectChanges();
expect(directiveElement.properties['target']).toEqual('_self');
fixture.componentInstance.url = '/test/url';
fixture.detectChanges();
expect(directiveElement.properties['target']).toEqual('_self');
});
it('should intercept clicks for local urls and call `location.go()`', inject([LocationService], (location: LocationService) => {
const fixture = TestBed.createComponent(TestComponent);
const directiveElement = fixture.debugElement.query(By.directive(LinkDirective));
fixture.componentInstance.url = 'some/local/url';
fixture.detectChanges();
location.go = jasmine.createSpy('Location.go');
directiveElement.triggerEventHandler('click', null);
expect(location.go).toHaveBeenCalledWith('some/local/url');
}));
it('should not intercept clicks for absolute urls', inject([LocationService], (location: LocationService) => {
const fixture = TestBed.createComponent(TestComponent);
const directiveElement = fixture.debugElement.query(By.directive(LinkDirective));
fixture.componentInstance.url = 'https://some/absolute/url';
fixture.detectChanges();
location.go = jasmine.createSpy('Location.go');
directiveElement.triggerEventHandler('click', null);
expect(location.go).not.toHaveBeenCalled();
}));
});

View File

@ -1,10 +1,10 @@
import { Directive, HostListener, HostBinding, Input } from '@angular/core';
import { Directive, HostListener, HostBinding, Input, OnChanges } from '@angular/core';
import { LocationService } from 'app/shared/location.service';
@Directive({
/* tslint:disable-next-line:directive-selector */
selector: 'a[href]'
})
export class LinkDirective {
export class LinkDirective implements OnChanges {
// We need both these decorators to ensure that we can access
// the href programmatically, and that it appears as a real
@ -13,11 +13,27 @@ export class LinkDirective {
@HostBinding()
href: string;
@HostBinding()
target: string;
@HostListener('click', ['$event'])
onClick($event) {
if (this.isAbsolute(this.href)) {
return true;
} else {
this.location.go(this.href);
return false;
}
}
private isAbsolute(url) {
return /^[a-z]+:\/\/|\/\//i.test(url);
}
constructor(private location: LocationService) { }
ngOnChanges() {
this.target = this.isAbsolute(this.href) ? '_blank' : '_self';
}
}