@ -7,12 +7,12 @@
|
||||
*/
|
||||
|
||||
import {DOCUMENT, isPlatformBrowser, ɵgetDOM as getDOM} from '@angular/common';
|
||||
import {APP_INITIALIZER, CUSTOM_ELEMENTS_SCHEMA, Compiler, Component, Directive, ErrorHandler, Inject, Injector, Input, LOCALE_ID, NgModule, OnDestroy, PLATFORM_ID, PLATFORM_INITIALIZER, Pipe, Provider, Sanitizer, StaticProvider, Type, VERSION, createPlatformFactory} from '@angular/core';
|
||||
import {APP_INITIALIZER, Compiler, Component, createPlatformFactory, CUSTOM_ELEMENTS_SCHEMA, Directive, ErrorHandler, Inject, Injector, Input, LOCALE_ID, NgModule, OnDestroy, Pipe, PLATFORM_ID, PLATFORM_INITIALIZER, Provider, Sanitizer, StaticProvider, Type, VERSION} from '@angular/core';
|
||||
import {ApplicationRef, destroyPlatform} from '@angular/core/src/application_ref';
|
||||
import {Console} from '@angular/core/src/console';
|
||||
import {ComponentRef} from '@angular/core/src/linker/component_factory';
|
||||
import {Testability, TestabilityRegistry} from '@angular/core/src/testability/testability';
|
||||
import {AsyncTestCompleter, Log, afterEach, beforeEach, beforeEachProviders, describe, inject, it} from '@angular/core/testing/src/testing_internal';
|
||||
import {afterEach, AsyncTestCompleter, beforeEach, beforeEachProviders, describe, inject, it, Log} from '@angular/core/testing/src/testing_internal';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
@ -25,7 +25,9 @@ class NonExistentComp {
|
||||
@Component({selector: 'hello-app', template: '{{greeting}} world!'})
|
||||
class HelloRootCmp {
|
||||
greeting: string;
|
||||
constructor() { this.greeting = 'hello'; }
|
||||
constructor() {
|
||||
this.greeting = 'hello';
|
||||
}
|
||||
}
|
||||
|
||||
@Component({selector: 'hello-app', template: 'before: <ng-content></ng-content> after: done'})
|
||||
@ -36,7 +38,9 @@ class HelloRootCmpContent {
|
||||
@Component({selector: 'hello-app-2', template: '{{greeting}} world, again!'})
|
||||
class HelloRootCmp2 {
|
||||
greeting: string;
|
||||
constructor() { this.greeting = 'hello'; }
|
||||
constructor() {
|
||||
this.greeting = 'hello';
|
||||
}
|
||||
}
|
||||
|
||||
@Component({selector: 'hello-app', template: ''})
|
||||
@ -52,7 +56,9 @@ class HelloRootCmp3 {
|
||||
class HelloRootCmp4 {
|
||||
appRef: any /** TODO #9100 */;
|
||||
|
||||
constructor(@Inject(ApplicationRef) appRef: ApplicationRef) { this.appRef = appRef; }
|
||||
constructor(@Inject(ApplicationRef) appRef: ApplicationRef) {
|
||||
this.appRef = appRef;
|
||||
}
|
||||
}
|
||||
|
||||
@Component({selector: 'hello-app'})
|
||||
@ -66,9 +72,13 @@ class HelloRootDirectiveIsNotCmp {
|
||||
@Component({selector: 'hello-app', template: ''})
|
||||
class HelloOnDestroyTickCmp implements OnDestroy {
|
||||
appRef: ApplicationRef;
|
||||
constructor(@Inject(ApplicationRef) appRef: ApplicationRef) { this.appRef = appRef; }
|
||||
constructor(@Inject(ApplicationRef) appRef: ApplicationRef) {
|
||||
this.appRef = appRef;
|
||||
}
|
||||
|
||||
ngOnDestroy(): void { this.appRef.tick(); }
|
||||
ngOnDestroy(): void {
|
||||
this.appRef.tick();
|
||||
}
|
||||
}
|
||||
|
||||
@Component({selector: 'hello-app', templateUrl: './sometemplate.html'})
|
||||
@ -79,13 +89,14 @@ class HelloUrlCmp {
|
||||
@Directive({selector: '[someDir]', host: {'[title]': 'someDir'}})
|
||||
class SomeDirective {
|
||||
// TODO(issue/24571): remove '!'.
|
||||
@Input()
|
||||
someDir !: string;
|
||||
@Input() someDir!: string;
|
||||
}
|
||||
|
||||
@Pipe({name: 'somePipe'})
|
||||
class SomePipe {
|
||||
transform(value: string): any { return `transformed ${value}`; }
|
||||
transform(value: string): any {
|
||||
return `transformed ${value}`;
|
||||
}
|
||||
}
|
||||
|
||||
@Component({selector: 'hello-app', template: `<div [someDir]="'someValue' | somePipe"></div>`})
|
||||
@ -99,7 +110,9 @@ class HelloCmpUsingCustomElement {
|
||||
|
||||
class MockConsole {
|
||||
res: any[][] = [];
|
||||
error(...s: any[]): void { this.res.push(s); }
|
||||
error(...s: any[]): void {
|
||||
this.res.push(s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -107,7 +120,9 @@ class DummyConsole implements Console {
|
||||
public warnings: string[] = [];
|
||||
|
||||
log(message: string) {}
|
||||
warn(message: string) { this.warnings.push(message); }
|
||||
warn(message: string) {
|
||||
this.warnings.push(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -135,7 +150,9 @@ function bootstrap(
|
||||
if (isNode) return;
|
||||
let compilerConsole: DummyConsole;
|
||||
|
||||
beforeEachProviders(() => { return [Log]; });
|
||||
beforeEachProviders(() => {
|
||||
return [Log];
|
||||
});
|
||||
|
||||
beforeEach(inject([DOCUMENT], (doc: any) => {
|
||||
destroyPlatform();
|
||||
@ -419,7 +436,6 @@ function bootstrap(
|
||||
|
||||
it('should remove styles when transitioning from a server render',
|
||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
||||
|
||||
@Component({
|
||||
selector: 'root',
|
||||
template: 'root',
|
||||
@ -449,8 +465,9 @@ function bootstrap(
|
||||
platform.bootstrapModule(TestModule).then(() => {
|
||||
const styles: HTMLElement[] =
|
||||
Array.prototype.slice.apply(document.getElementsByTagName('style') || []);
|
||||
styles.forEach(
|
||||
style => { expect(style.getAttribute('ng-transition')).not.toBe('my-app'); });
|
||||
styles.forEach(style => {
|
||||
expect(style.getAttribute('ng-transition')).not.toBe('my-app');
|
||||
});
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
@ -487,7 +504,9 @@ function bootstrap(
|
||||
})
|
||||
class CompA {
|
||||
title: string = '';
|
||||
ngDoCheck() { log.push('CompA:ngDoCheck'); }
|
||||
ngDoCheck() {
|
||||
log.push('CompA:ngDoCheck');
|
||||
}
|
||||
onClick() {
|
||||
this.title = 'CompA';
|
||||
log.push('CompA:onClick');
|
||||
@ -500,7 +519,9 @@ function bootstrap(
|
||||
})
|
||||
class CompB {
|
||||
title: string = '';
|
||||
ngDoCheck() { log.push('CompB:ngDoCheck'); }
|
||||
ngDoCheck() {
|
||||
log.push('CompB:ngDoCheck');
|
||||
}
|
||||
onClick() {
|
||||
this.title = 'CompB';
|
||||
log.push('CompB:onClick');
|
||||
|
@ -30,14 +30,14 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
afterEach(() => getDOM().remove(defaultMeta));
|
||||
|
||||
it('should return meta tag matching selector', () => {
|
||||
const actual: HTMLMetaElement = metaService.getTag('property="fb:app_id"') !;
|
||||
const actual: HTMLMetaElement = metaService.getTag('property="fb:app_id"')!;
|
||||
expect(actual).not.toBeNull();
|
||||
expect(actual.getAttribute('content')).toEqual('123456789');
|
||||
});
|
||||
|
||||
it('should return all meta tags matching selector', () => {
|
||||
const tag1 = metaService.addTag({name: 'author', content: 'page author'}) !;
|
||||
const tag2 = metaService.addTag({name: 'author', content: 'another page author'}) !;
|
||||
const tag1 = metaService.addTag({name: 'author', content: 'page author'})!;
|
||||
const tag2 = metaService.addTag({name: 'author', content: 'another page author'})!;
|
||||
|
||||
const actual: HTMLMetaElement[] = metaService.getTags('name=author');
|
||||
expect(actual.length).toEqual(2);
|
||||
@ -50,7 +50,7 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
});
|
||||
|
||||
it('should return null if meta tag does not exist', () => {
|
||||
const actual: HTMLMetaElement = metaService.getTag('fake=fake') !;
|
||||
const actual: HTMLMetaElement = metaService.getTag('fake=fake')!;
|
||||
expect(actual).toBeNull();
|
||||
});
|
||||
|
||||
@ -73,7 +73,7 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
|
||||
metaService.addTags([{name: 'keywords', content: 'meta test'}]);
|
||||
|
||||
const meta = metaService.getTag(selector) !;
|
||||
const meta = metaService.getTag(selector)!;
|
||||
expect(meta).not.toBeNull();
|
||||
|
||||
metaService.removeTagElement(meta);
|
||||
@ -87,7 +87,7 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
|
||||
const actual = metaService.getTag(selector);
|
||||
expect(actual).not.toBeNull();
|
||||
expect(actual !.getAttribute('content')).toEqual('4321');
|
||||
expect(actual!.getAttribute('content')).toEqual('4321');
|
||||
});
|
||||
|
||||
it('should extract selector from the tag definition', () => {
|
||||
@ -96,7 +96,7 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
|
||||
const actual = metaService.getTag(selector);
|
||||
expect(actual).not.toBeNull();
|
||||
expect(actual !.getAttribute('content')).toEqual('666');
|
||||
expect(actual!.getAttribute('content')).toEqual('666');
|
||||
});
|
||||
|
||||
it('should create meta tag if it does not exist', () => {
|
||||
@ -104,7 +104,7 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
|
||||
metaService.updateTag({name: 'twitter:title', content: 'Content Title'}, selector);
|
||||
|
||||
const actual = metaService.getTag(selector) !;
|
||||
const actual = metaService.getTag(selector)!;
|
||||
expect(actual).not.toBeNull();
|
||||
expect(actual.getAttribute('content')).toEqual('Content Title');
|
||||
|
||||
@ -118,7 +118,7 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
|
||||
metaService.addTag({name: 'og:title', content: 'Content Title'});
|
||||
|
||||
const actual = metaService.getTag(selector) !;
|
||||
const actual = metaService.getTag(selector)!;
|
||||
expect(actual).not.toBeNull();
|
||||
expect(actual.getAttribute('content')).toEqual('Content Title');
|
||||
|
||||
@ -136,8 +136,8 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
{name: 'twitter:title', content: 'Content Title'},
|
||||
{property: 'og:title', content: 'Content Title'}
|
||||
]);
|
||||
const twitterMeta = metaService.getTag(nameSelector) !;
|
||||
const fbMeta = metaService.getTag(propertySelector) !;
|
||||
const twitterMeta = metaService.getTag(nameSelector)!;
|
||||
const fbMeta = metaService.getTag(propertySelector)!;
|
||||
expect(twitterMeta).not.toBeNull();
|
||||
expect(fbMeta).not.toBeNull();
|
||||
|
||||
@ -160,7 +160,7 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
const selector = 'property="fb:app_id"';
|
||||
expect(metaService.getTags(selector).length).toEqual(1);
|
||||
|
||||
const meta = metaService.addTag({property: 'fb:app_id', content: '666'}) !;
|
||||
const meta = metaService.addTag({property: 'fb:app_id', content: '666'})!;
|
||||
|
||||
expect(metaService.getTags(selector).length).toEqual(2);
|
||||
|
||||
@ -172,18 +172,16 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
const selector = 'property="fb:app_id"';
|
||||
expect(metaService.getTags(selector).length).toEqual(1);
|
||||
|
||||
const meta = metaService.addTag({property: 'fb:app_id', content: '123456789'}, true) !;
|
||||
const meta = metaService.addTag({property: 'fb:app_id', content: '123456789'}, true)!;
|
||||
|
||||
expect(metaService.getTags(selector).length).toEqual(2);
|
||||
|
||||
// clean up
|
||||
metaService.removeTagElement(meta);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('integration test', () => {
|
||||
|
||||
@Injectable()
|
||||
class DependsOnMeta {
|
||||
constructor(public meta: Meta) {}
|
||||
|
@ -24,10 +24,13 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
titleService = new Title(doc);
|
||||
});
|
||||
|
||||
afterEach(() => { doc.title = initialTitle; });
|
||||
afterEach(() => {
|
||||
doc.title = initialTitle;
|
||||
});
|
||||
|
||||
it('should allow reading initial title',
|
||||
() => { expect(titleService.getTitle()).toEqual(initialTitle); });
|
||||
it('should allow reading initial title', () => {
|
||||
expect(titleService.getTitle()).toEqual(initialTitle);
|
||||
});
|
||||
|
||||
it('should set a title on the injected document', () => {
|
||||
titleService.setTitle('test title');
|
||||
@ -36,13 +39,12 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
});
|
||||
|
||||
it('should reset title to empty string if title not provided', () => {
|
||||
titleService.setTitle(null !);
|
||||
titleService.setTitle(null!);
|
||||
expect(doc.title).toEqual('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('integration test', () => {
|
||||
|
||||
@Injectable()
|
||||
class DependsOnTitle {
|
||||
constructor(public title: Title) {}
|
||||
@ -55,7 +57,8 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
});
|
||||
});
|
||||
|
||||
it('should inject Title service when using BrowserModule',
|
||||
() => { expect(TestBed.inject(DependsOnTitle).title).toBeAnInstanceOf(Title); });
|
||||
it('should inject Title service when using BrowserModule', () => {
|
||||
expect(TestBed.inject(DependsOnTitle).title).toBeAnInstanceOf(Title);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -11,7 +11,9 @@ import {ApplicationRef} from '@angular/core/src/application_ref';
|
||||
import {SpyObject} from '@angular/core/testing/src/testing_internal';
|
||||
|
||||
export class SpyApplicationRef extends SpyObject {
|
||||
constructor() { super(ApplicationRef); }
|
||||
constructor() {
|
||||
super(ApplicationRef);
|
||||
}
|
||||
}
|
||||
|
||||
export class SpyComponentRef extends SpyObject {
|
||||
|
@ -8,18 +8,25 @@
|
||||
|
||||
import {disableDebugTools, enableDebugTools} from '@angular/platform-browser';
|
||||
|
||||
import {SpyComponentRef, callNgProfilerTimeChangeDetection} from './spies';
|
||||
import {callNgProfilerTimeChangeDetection, SpyComponentRef} from './spies';
|
||||
|
||||
{
|
||||
describe('profiler', () => {
|
||||
if (isNode) return;
|
||||
beforeEach(() => { enableDebugTools((<any>new SpyComponentRef())); });
|
||||
beforeEach(() => {
|
||||
enableDebugTools((<any>new SpyComponentRef()));
|
||||
});
|
||||
|
||||
afterEach(() => { disableDebugTools(); });
|
||||
afterEach(() => {
|
||||
disableDebugTools();
|
||||
});
|
||||
|
||||
it('should time change detection', () => { callNgProfilerTimeChangeDetection(); });
|
||||
it('should time change detection', () => {
|
||||
callNgProfilerTimeChangeDetection();
|
||||
});
|
||||
|
||||
it('should time change detection with recording',
|
||||
() => { callNgProfilerTimeChangeDetection({'record': true}); });
|
||||
it('should time change detection with recording', () => {
|
||||
callNgProfilerTimeChangeDetection({'record': true});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -9,124 +9,126 @@
|
||||
import {DOCUMENT} from '@angular/common';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {BrowserModule, BrowserTransferStateModule, TransferState} from '@angular/platform-browser';
|
||||
import {StateKey, escapeHtml, makeStateKey, unescapeHtml} from '@angular/platform-browser/src/browser/transfer_state';
|
||||
import {escapeHtml, makeStateKey, StateKey, unescapeHtml} from '@angular/platform-browser/src/browser/transfer_state';
|
||||
|
||||
(function() {
|
||||
function removeScriptTag(doc: Document, id: string) {
|
||||
const existing = doc.getElementById(id);
|
||||
if (existing) {
|
||||
doc.body.removeChild(existing);
|
||||
}
|
||||
function removeScriptTag(doc: Document, id: string) {
|
||||
const existing = doc.getElementById(id);
|
||||
if (existing) {
|
||||
doc.body.removeChild(existing);
|
||||
}
|
||||
}
|
||||
|
||||
function addScriptTag(doc: Document, appId: string, data: {}) {
|
||||
const script = doc.createElement('script');
|
||||
const id = appId + '-state';
|
||||
script.id = id;
|
||||
script.setAttribute('type', 'application/json');
|
||||
script.textContent = escapeHtml(JSON.stringify(data));
|
||||
function addScriptTag(doc: Document, appId: string, data: {}) {
|
||||
const script = doc.createElement('script');
|
||||
const id = appId + '-state';
|
||||
script.id = id;
|
||||
script.setAttribute('type', 'application/json');
|
||||
script.textContent = escapeHtml(JSON.stringify(data));
|
||||
|
||||
// Remove any stale script tags.
|
||||
removeScriptTag(doc, id);
|
||||
// Remove any stale script tags.
|
||||
removeScriptTag(doc, id);
|
||||
|
||||
doc.body.appendChild(script);
|
||||
}
|
||||
doc.body.appendChild(script);
|
||||
}
|
||||
|
||||
describe('TransferState', () => {
|
||||
const APP_ID = 'test-app';
|
||||
let doc: Document;
|
||||
describe('TransferState', () => {
|
||||
const APP_ID = 'test-app';
|
||||
let doc: Document;
|
||||
|
||||
const TEST_KEY = makeStateKey<number>('test');
|
||||
const DELAYED_KEY = makeStateKey<string>('delayed');
|
||||
const TEST_KEY = makeStateKey<number>('test');
|
||||
const DELAYED_KEY = makeStateKey<string>('delayed');
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
BrowserModule.withServerTransition({appId: APP_ID}),
|
||||
BrowserTransferStateModule,
|
||||
]
|
||||
});
|
||||
doc = TestBed.inject(DOCUMENT);
|
||||
});
|
||||
|
||||
afterEach(() => { removeScriptTag(doc, APP_ID + '-state'); });
|
||||
|
||||
it('is initialized from script tag', () => {
|
||||
addScriptTag(doc, APP_ID, {test: 10});
|
||||
const transferState: TransferState = TestBed.inject(TransferState);
|
||||
expect(transferState.get(TEST_KEY, 0)).toBe(10);
|
||||
});
|
||||
|
||||
it('is initialized to empty state if script tag not found', () => {
|
||||
const transferState: TransferState = TestBed.inject(TransferState);
|
||||
expect(transferState.get(TEST_KEY, 0)).toBe(0);
|
||||
});
|
||||
|
||||
it('supports adding new keys using set', () => {
|
||||
const transferState: TransferState = TestBed.inject(TransferState);
|
||||
transferState.set(TEST_KEY, 20);
|
||||
expect(transferState.get(TEST_KEY, 0)).toBe(20);
|
||||
expect(transferState.hasKey(TEST_KEY)).toBe(true);
|
||||
});
|
||||
|
||||
it('supports setting and accessing value \'0\' via get', () => {
|
||||
const transferState: TransferState = TestBed.inject(TransferState);
|
||||
transferState.set(TEST_KEY, 0);
|
||||
expect(transferState.get(TEST_KEY, 20)).toBe(0);
|
||||
expect(transferState.hasKey(TEST_KEY)).toBe(true);
|
||||
});
|
||||
|
||||
it('supports setting and accessing value \'false\' via get', () => {
|
||||
const transferState: TransferState = TestBed.inject(TransferState);
|
||||
transferState.set(TEST_KEY, false);
|
||||
expect(transferState.get(TEST_KEY, true)).toBe(false);
|
||||
expect(transferState.hasKey(TEST_KEY)).toBe(true);
|
||||
});
|
||||
|
||||
it('supports setting and accessing value \'null\' via get', () => {
|
||||
const transferState: TransferState = TestBed.inject(TransferState);
|
||||
transferState.set(TEST_KEY, null);
|
||||
expect(transferState.get(TEST_KEY, 20 as any)).toBe(null);
|
||||
expect(transferState.hasKey(TEST_KEY)).toBe(true);
|
||||
});
|
||||
|
||||
it('supports removing keys', () => {
|
||||
const transferState: TransferState = TestBed.inject(TransferState);
|
||||
transferState.set(TEST_KEY, 20);
|
||||
transferState.remove(TEST_KEY);
|
||||
expect(transferState.get(TEST_KEY, 0)).toBe(0);
|
||||
expect(transferState.hasKey(TEST_KEY)).toBe(false);
|
||||
});
|
||||
|
||||
it('supports serialization using toJson()', () => {
|
||||
const transferState: TransferState = TestBed.inject(TransferState);
|
||||
transferState.set(TEST_KEY, 20);
|
||||
expect(transferState.toJson()).toBe('{"test":20}');
|
||||
});
|
||||
|
||||
it('calls onSerialize callbacks when calling toJson()', () => {
|
||||
const transferState: TransferState = TestBed.inject(TransferState);
|
||||
transferState.set(TEST_KEY, 20);
|
||||
|
||||
let value = 'initial';
|
||||
transferState.onSerialize(DELAYED_KEY, () => value);
|
||||
value = 'changed';
|
||||
|
||||
expect(transferState.toJson()).toBe('{"test":20,"delayed":"changed"}');
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
BrowserModule.withServerTransition({appId: APP_ID}),
|
||||
BrowserTransferStateModule,
|
||||
]
|
||||
});
|
||||
doc = TestBed.inject(DOCUMENT);
|
||||
});
|
||||
|
||||
describe('escape/unescape', () => {
|
||||
it('works with all escaped characters', () => {
|
||||
const testString = '</script><script>alert(\'Hello&\' + "World");';
|
||||
const testObj = {testString};
|
||||
const escaped = escapeHtml(JSON.stringify(testObj));
|
||||
expect(escaped).toBe(
|
||||
'{&q;testString&q;:&q;&l;/script&g;&l;script&g;' +
|
||||
'alert(&s;Hello&a;&s; + \\&q;World\\&q;);&q;}');
|
||||
|
||||
const unescapedObj = JSON.parse(unescapeHtml(escaped));
|
||||
expect(unescapedObj['testString']).toBe(testString);
|
||||
});
|
||||
afterEach(() => {
|
||||
removeScriptTag(doc, APP_ID + '-state');
|
||||
});
|
||||
|
||||
it('is initialized from script tag', () => {
|
||||
addScriptTag(doc, APP_ID, {test: 10});
|
||||
const transferState: TransferState = TestBed.inject(TransferState);
|
||||
expect(transferState.get(TEST_KEY, 0)).toBe(10);
|
||||
});
|
||||
|
||||
it('is initialized to empty state if script tag not found', () => {
|
||||
const transferState: TransferState = TestBed.inject(TransferState);
|
||||
expect(transferState.get(TEST_KEY, 0)).toBe(0);
|
||||
});
|
||||
|
||||
it('supports adding new keys using set', () => {
|
||||
const transferState: TransferState = TestBed.inject(TransferState);
|
||||
transferState.set(TEST_KEY, 20);
|
||||
expect(transferState.get(TEST_KEY, 0)).toBe(20);
|
||||
expect(transferState.hasKey(TEST_KEY)).toBe(true);
|
||||
});
|
||||
|
||||
it('supports setting and accessing value \'0\' via get', () => {
|
||||
const transferState: TransferState = TestBed.inject(TransferState);
|
||||
transferState.set(TEST_KEY, 0);
|
||||
expect(transferState.get(TEST_KEY, 20)).toBe(0);
|
||||
expect(transferState.hasKey(TEST_KEY)).toBe(true);
|
||||
});
|
||||
|
||||
it('supports setting and accessing value \'false\' via get', () => {
|
||||
const transferState: TransferState = TestBed.inject(TransferState);
|
||||
transferState.set(TEST_KEY, false);
|
||||
expect(transferState.get(TEST_KEY, true)).toBe(false);
|
||||
expect(transferState.hasKey(TEST_KEY)).toBe(true);
|
||||
});
|
||||
|
||||
it('supports setting and accessing value \'null\' via get', () => {
|
||||
const transferState: TransferState = TestBed.inject(TransferState);
|
||||
transferState.set(TEST_KEY, null);
|
||||
expect(transferState.get(TEST_KEY, 20 as any)).toBe(null);
|
||||
expect(transferState.hasKey(TEST_KEY)).toBe(true);
|
||||
});
|
||||
|
||||
it('supports removing keys', () => {
|
||||
const transferState: TransferState = TestBed.inject(TransferState);
|
||||
transferState.set(TEST_KEY, 20);
|
||||
transferState.remove(TEST_KEY);
|
||||
expect(transferState.get(TEST_KEY, 0)).toBe(0);
|
||||
expect(transferState.hasKey(TEST_KEY)).toBe(false);
|
||||
});
|
||||
|
||||
it('supports serialization using toJson()', () => {
|
||||
const transferState: TransferState = TestBed.inject(TransferState);
|
||||
transferState.set(TEST_KEY, 20);
|
||||
expect(transferState.toJson()).toBe('{"test":20}');
|
||||
});
|
||||
|
||||
it('calls onSerialize callbacks when calling toJson()', () => {
|
||||
const transferState: TransferState = TestBed.inject(TransferState);
|
||||
transferState.set(TEST_KEY, 20);
|
||||
|
||||
let value = 'initial';
|
||||
transferState.onSerialize(DELAYED_KEY, () => value);
|
||||
value = 'changed';
|
||||
|
||||
expect(transferState.toJson()).toBe('{"test":20,"delayed":"changed"}');
|
||||
});
|
||||
});
|
||||
|
||||
describe('escape/unescape', () => {
|
||||
it('works with all escaped characters', () => {
|
||||
const testString = '</script><script>alert(\'Hello&\' + "World");';
|
||||
const testObj = {testString};
|
||||
const escaped = escapeHtml(JSON.stringify(testObj));
|
||||
expect(escaped).toBe(
|
||||
'{&q;testString&q;:&q;&l;/script&g;&l;script&g;' +
|
||||
'alert(&s;Hello&a;&s; + \\&q;World\\&q;);&q;}');
|
||||
|
||||
const unescapedObj = JSON.parse(unescapeHtml(escaped));
|
||||
expect(unescapedObj['testString']).toBe(testString);
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
@ -11,7 +11,6 @@ import {BrowserDetection} from '../testing/src/browser_util';
|
||||
|
||||
{
|
||||
describe('BrowserDetection', () => {
|
||||
|
||||
const browsers = [
|
||||
{
|
||||
name: 'Chrome',
|
||||
@ -224,7 +223,7 @@ import {BrowserDetection} from '../testing/src/browser_util';
|
||||
];
|
||||
|
||||
browsers.forEach((browser: {[key: string]: any}) => {
|
||||
it(`should detect ${browser[ 'name']}`, () => {
|
||||
it(`should detect ${browser['name']}`, () => {
|
||||
const bd = new BrowserDetection(<string>browser['ua']);
|
||||
expect(bd.isFirefox).toBe(browser['isFirefox']);
|
||||
expect(bd.isAndroid).toBe(browser['isAndroid']);
|
||||
|
@ -14,361 +14,393 @@ import {EventManager, EventManagerPlugin} from '@angular/platform-browser/src/do
|
||||
import {createMouseEvent, el} from '../../../testing/src/browser_util';
|
||||
|
||||
(function() {
|
||||
if (isNode) return;
|
||||
let domEventPlugin: DomEventsPlugin;
|
||||
let doc: any;
|
||||
let zone: NgZone;
|
||||
if (isNode) return;
|
||||
let domEventPlugin: DomEventsPlugin;
|
||||
let doc: any;
|
||||
let zone: NgZone;
|
||||
|
||||
describe('EventManager', () => {
|
||||
beforeEach(() => {
|
||||
doc = getDOM().supportsDOMEvents() ? document : getDOM().createHtmlDocument();
|
||||
zone = new NgZone({});
|
||||
domEventPlugin = new DomEventsPlugin(doc);
|
||||
describe('EventManager', () => {
|
||||
beforeEach(() => {
|
||||
doc = getDOM().supportsDOMEvents() ? document : getDOM().createHtmlDocument();
|
||||
zone = new NgZone({});
|
||||
domEventPlugin = new DomEventsPlugin(doc);
|
||||
});
|
||||
|
||||
it('should delegate event bindings to plugins that are passed in from the most generic one to the most specific one',
|
||||
() => {
|
||||
const element = el('<div></div>');
|
||||
const handler = (e: any /** TODO #9100 */) => e;
|
||||
const plugin = new FakeEventManagerPlugin(doc, ['click']);
|
||||
const manager = new EventManager([domEventPlugin, plugin], new FakeNgZone());
|
||||
manager.addEventListener(element, 'click', handler);
|
||||
expect(plugin.eventHandler['click']).toBe(handler);
|
||||
});
|
||||
|
||||
it('should delegate event bindings to the first plugin supporting the event', () => {
|
||||
const element = el('<div></div>');
|
||||
const clickHandler = (e: any /** TODO #9100 */) => e;
|
||||
const dblClickHandler = (e: any /** TODO #9100 */) => e;
|
||||
const plugin1 = new FakeEventManagerPlugin(doc, ['dblclick']);
|
||||
const plugin2 = new FakeEventManagerPlugin(doc, ['click', 'dblclick']);
|
||||
const manager = new EventManager([plugin2, plugin1], new FakeNgZone());
|
||||
manager.addEventListener(element, 'click', clickHandler);
|
||||
manager.addEventListener(element, 'dblclick', dblClickHandler);
|
||||
expect(plugin2.eventHandler['click']).toBe(clickHandler);
|
||||
expect(plugin1.eventHandler['dblclick']).toBe(dblClickHandler);
|
||||
});
|
||||
|
||||
it('should throw when no plugin can handle the event', () => {
|
||||
const element = el('<div></div>');
|
||||
const plugin = new FakeEventManagerPlugin(doc, ['dblclick']);
|
||||
const manager = new EventManager([plugin], new FakeNgZone());
|
||||
expect(() => manager.addEventListener(element, 'click', null!))
|
||||
.toThrowError('No event manager plugin found for event click');
|
||||
});
|
||||
|
||||
it('events are caught when fired from a child', () => {
|
||||
const element = el('<div><div></div></div>');
|
||||
// Workaround for https://bugs.webkit.org/show_bug.cgi?id=122755
|
||||
doc.body.appendChild(element);
|
||||
|
||||
const child = element.firstChild as Element;
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvent: any /** TODO #9100 */ = null;
|
||||
const handler = (e: any /** TODO #9100 */) => {
|
||||
receivedEvent = e;
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
manager.addEventListener(element, 'click', handler);
|
||||
getDOM().dispatchEvent(child, dispatchedEvent);
|
||||
|
||||
expect(receivedEvent).toBe(dispatchedEvent);
|
||||
});
|
||||
|
||||
it('should add and remove global event listeners', () => {
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvent: any /** TODO #9100 */ = null;
|
||||
const handler = (e: any /** TODO #9100 */) => {
|
||||
receivedEvent = e;
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
|
||||
const remover = manager.addGlobalEventListener('document', 'click', handler);
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(dispatchedEvent);
|
||||
|
||||
receivedEvent = null;
|
||||
remover();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(null);
|
||||
});
|
||||
|
||||
it('should keep zone when addEventListener', () => {
|
||||
const Zone = (window as any)['Zone'];
|
||||
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvent: any /** TODO #9100 */ = null;
|
||||
let receivedZone: any = null;
|
||||
const handler = (e: any /** TODO #9100 */) => {
|
||||
receivedEvent = e;
|
||||
receivedZone = Zone.current;
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
|
||||
let remover: any = null;
|
||||
Zone.root.run(() => {
|
||||
remover = manager.addEventListener(element, 'click', handler);
|
||||
});
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(dispatchedEvent);
|
||||
expect(receivedZone.name).toBe(Zone.root.name);
|
||||
|
||||
it('should delegate event bindings to plugins that are passed in from the most generic one to the most specific one',
|
||||
() => {
|
||||
const element = el('<div></div>');
|
||||
const handler = (e: any /** TODO #9100 */) => e;
|
||||
const plugin = new FakeEventManagerPlugin(doc, ['click']);
|
||||
const manager = new EventManager([domEventPlugin, plugin], new FakeNgZone());
|
||||
manager.addEventListener(element, 'click', handler);
|
||||
expect(plugin.eventHandler['click']).toBe(handler);
|
||||
});
|
||||
receivedEvent = null;
|
||||
remover && remover();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(null);
|
||||
});
|
||||
|
||||
it('should delegate event bindings to the first plugin supporting the event', () => {
|
||||
const element = el('<div></div>');
|
||||
const clickHandler = (e: any /** TODO #9100 */) => e;
|
||||
const dblClickHandler = (e: any /** TODO #9100 */) => e;
|
||||
const plugin1 = new FakeEventManagerPlugin(doc, ['dblclick']);
|
||||
const plugin2 = new FakeEventManagerPlugin(doc, ['click', 'dblclick']);
|
||||
const manager = new EventManager([plugin2, plugin1], new FakeNgZone());
|
||||
manager.addEventListener(element, 'click', clickHandler);
|
||||
manager.addEventListener(element, 'dblclick', dblClickHandler);
|
||||
expect(plugin2.eventHandler['click']).toBe(clickHandler);
|
||||
expect(plugin1.eventHandler['dblclick']).toBe(dblClickHandler);
|
||||
it('should keep zone when addEventListener multiple times', () => {
|
||||
const Zone = (window as any)['Zone'];
|
||||
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvents: any[] /** TODO #9100 */ = [];
|
||||
let receivedZones: any[] = [];
|
||||
const handler1 = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
};
|
||||
const handler2 = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
|
||||
let remover1: any = null;
|
||||
let remover2: any = null;
|
||||
Zone.root.run(() => {
|
||||
remover1 = manager.addEventListener(element, 'click', handler1);
|
||||
});
|
||||
|
||||
it('should throw when no plugin can handle the event', () => {
|
||||
const element = el('<div></div>');
|
||||
const plugin = new FakeEventManagerPlugin(doc, ['dblclick']);
|
||||
const manager = new EventManager([plugin], new FakeNgZone());
|
||||
expect(() => manager.addEventListener(element, 'click', null !))
|
||||
.toThrowError('No event manager plugin found for event click');
|
||||
Zone.root.fork({name: 'test'}).run(() => {
|
||||
remover2 = manager.addEventListener(element, 'click', handler2);
|
||||
});
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([dispatchedEvent, dispatchedEvent]);
|
||||
expect(receivedZones).toEqual([Zone.root.name, 'test']);
|
||||
|
||||
it('events are caught when fired from a child', () => {
|
||||
const element = el('<div><div></div></div>');
|
||||
// Workaround for https://bugs.webkit.org/show_bug.cgi?id=122755
|
||||
doc.body.appendChild(element);
|
||||
receivedEvents = [];
|
||||
remover1 && remover1();
|
||||
remover2 && remover2();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([]);
|
||||
});
|
||||
|
||||
const child = element.firstChild as Element;
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvent: any /** TODO #9100 */ = null;
|
||||
const handler = (e: any /** TODO #9100 */) => { receivedEvent = e; };
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
manager.addEventListener(element, 'click', handler);
|
||||
getDOM().dispatchEvent(child, dispatchedEvent);
|
||||
it('should support event.stopImmediatePropagation', () => {
|
||||
const Zone = (window as any)['Zone'];
|
||||
|
||||
expect(receivedEvent).toBe(dispatchedEvent);
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvents: any[] /** TODO #9100 */ = [];
|
||||
let receivedZones: any[] = [];
|
||||
const handler1 = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
e.stopImmediatePropagation();
|
||||
};
|
||||
const handler2 = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
|
||||
let remover1: any = null;
|
||||
let remover2: any = null;
|
||||
Zone.root.run(() => {
|
||||
remover1 = manager.addEventListener(element, 'click', handler1);
|
||||
});
|
||||
|
||||
it('should add and remove global event listeners', () => {
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvent: any /** TODO #9100 */ = null;
|
||||
const handler = (e: any /** TODO #9100 */) => { receivedEvent = e; };
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
|
||||
const remover = manager.addGlobalEventListener('document', 'click', handler);
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(dispatchedEvent);
|
||||
|
||||
receivedEvent = null;
|
||||
remover();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(null);
|
||||
Zone.root.fork({name: 'test'}).run(() => {
|
||||
remover2 = manager.addEventListener(element, 'click', handler2);
|
||||
});
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([dispatchedEvent]);
|
||||
expect(receivedZones).toEqual([Zone.root.name]);
|
||||
|
||||
it('should keep zone when addEventListener', () => {
|
||||
const Zone = (window as any)['Zone'];
|
||||
receivedEvents = [];
|
||||
remover1 && remover1();
|
||||
remover2 && remover2();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([]);
|
||||
});
|
||||
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvent: any /** TODO #9100 */ = null;
|
||||
let receivedZone: any = null;
|
||||
const handler = (e: any /** TODO #9100 */) => {
|
||||
receivedEvent = e;
|
||||
receivedZone = Zone.current;
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
it('should handle event correctly when one handler remove itself ', () => {
|
||||
const Zone = (window as any)['Zone'];
|
||||
|
||||
let remover: any = null;
|
||||
Zone.root.run(() => { remover = manager.addEventListener(element, 'click', handler); });
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(dispatchedEvent);
|
||||
expect(receivedZone.name).toBe(Zone.root.name);
|
||||
|
||||
receivedEvent = null;
|
||||
remover && remover();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(null);
|
||||
});
|
||||
|
||||
it('should keep zone when addEventListener multiple times', () => {
|
||||
const Zone = (window as any)['Zone'];
|
||||
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvents: any[] /** TODO #9100 */ = [];
|
||||
let receivedZones: any[] = [];
|
||||
const handler1 = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
};
|
||||
const handler2 = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
|
||||
let remover1: any = null;
|
||||
let remover2: any = null;
|
||||
Zone.root.run(() => { remover1 = manager.addEventListener(element, 'click', handler1); });
|
||||
Zone.root.fork({name: 'test'}).run(() => {
|
||||
remover2 = manager.addEventListener(element, 'click', handler2);
|
||||
});
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([dispatchedEvent, dispatchedEvent]);
|
||||
expect(receivedZones).toEqual([Zone.root.name, 'test']);
|
||||
|
||||
receivedEvents = [];
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvents: any[] /** TODO #9100 */ = [];
|
||||
let receivedZones: any[] = [];
|
||||
let remover1: any = null;
|
||||
let remover2: any = null;
|
||||
const handler1 = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
remover1 && remover1();
|
||||
remover2 && remover2();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([]);
|
||||
};
|
||||
const handler2 = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
|
||||
Zone.root.run(() => {
|
||||
remover1 = manager.addEventListener(element, 'click', handler1);
|
||||
});
|
||||
|
||||
it('should support event.stopImmediatePropagation', () => {
|
||||
const Zone = (window as any)['Zone'];
|
||||
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvents: any[] /** TODO #9100 */ = [];
|
||||
let receivedZones: any[] = [];
|
||||
const handler1 = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
e.stopImmediatePropagation();
|
||||
};
|
||||
const handler2 = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
|
||||
let remover1: any = null;
|
||||
let remover2: any = null;
|
||||
Zone.root.run(() => { remover1 = manager.addEventListener(element, 'click', handler1); });
|
||||
Zone.root.fork({name: 'test'}).run(() => {
|
||||
remover2 = manager.addEventListener(element, 'click', handler2);
|
||||
});
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([dispatchedEvent]);
|
||||
expect(receivedZones).toEqual([Zone.root.name]);
|
||||
|
||||
receivedEvents = [];
|
||||
remover1 && remover1();
|
||||
remover2 && remover2();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([]);
|
||||
Zone.root.fork({name: 'test'}).run(() => {
|
||||
remover2 = manager.addEventListener(element, 'click', handler2);
|
||||
});
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([dispatchedEvent, dispatchedEvent]);
|
||||
expect(receivedZones).toEqual([Zone.root.name, 'test']);
|
||||
|
||||
it('should handle event correctly when one handler remove itself ', () => {
|
||||
const Zone = (window as any)['Zone'];
|
||||
receivedEvents = [];
|
||||
remover1 && remover1();
|
||||
remover2 && remover2();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([]);
|
||||
});
|
||||
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvents: any[] /** TODO #9100 */ = [];
|
||||
let receivedZones: any[] = [];
|
||||
let remover1: any = null;
|
||||
let remover2: any = null;
|
||||
const handler1 = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
remover1 && remover1();
|
||||
};
|
||||
const handler2 = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
it('should only add same callback once when addEventListener', () => {
|
||||
const Zone = (window as any)['Zone'];
|
||||
|
||||
Zone.root.run(() => { remover1 = manager.addEventListener(element, 'click', handler1); });
|
||||
Zone.root.fork({name: 'test'}).run(() => {
|
||||
remover2 = manager.addEventListener(element, 'click', handler2);
|
||||
});
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([dispatchedEvent, dispatchedEvent]);
|
||||
expect(receivedZones).toEqual([Zone.root.name, 'test']);
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvents: any[] /** TODO #9100 */ = [];
|
||||
let receivedZones: any[] = [];
|
||||
const handler = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
|
||||
receivedEvents = [];
|
||||
remover1 && remover1();
|
||||
remover2 && remover2();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([]);
|
||||
let remover1: any = null;
|
||||
let remover2: any = null;
|
||||
Zone.root.run(() => {
|
||||
remover1 = manager.addEventListener(element, 'click', handler);
|
||||
});
|
||||
|
||||
it('should only add same callback once when addEventListener', () => {
|
||||
const Zone = (window as any)['Zone'];
|
||||
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvents: any[] /** TODO #9100 */ = [];
|
||||
let receivedZones: any[] = [];
|
||||
const handler = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
|
||||
let remover1: any = null;
|
||||
let remover2: any = null;
|
||||
Zone.root.run(() => { remover1 = manager.addEventListener(element, 'click', handler); });
|
||||
Zone.root.fork({name: 'test'}).run(() => {
|
||||
remover2 = manager.addEventListener(element, 'click', handler);
|
||||
});
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([dispatchedEvent]);
|
||||
expect(receivedZones).toEqual([Zone.root.name]);
|
||||
|
||||
receivedEvents = [];
|
||||
remover1 && remover1();
|
||||
remover2 && remover2();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([]);
|
||||
Zone.root.fork({name: 'test'}).run(() => {
|
||||
remover2 = manager.addEventListener(element, 'click', handler);
|
||||
});
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([dispatchedEvent]);
|
||||
expect(receivedZones).toEqual([Zone.root.name]);
|
||||
|
||||
it('should be able to remove event listener which was added inside of ngZone', () => {
|
||||
const Zone = (window as any)['Zone'];
|
||||
receivedEvents = [];
|
||||
remover1 && remover1();
|
||||
remover2 && remover2();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([]);
|
||||
});
|
||||
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvents: any[] /** TODO #9100 */ = [];
|
||||
let receivedZones: any[] = [];
|
||||
const handler1 = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
};
|
||||
const handler2 = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
it('should be able to remove event listener which was added inside of ngZone', () => {
|
||||
const Zone = (window as any)['Zone'];
|
||||
|
||||
let remover1: any = null;
|
||||
let remover2: any = null;
|
||||
// handler1 is added in root zone
|
||||
Zone.root.run(() => { remover1 = manager.addEventListener(element, 'click', handler1); });
|
||||
// handler2 is added in 'angular' zone
|
||||
Zone.root.fork({name: 'fakeAngularZone', properties: {isAngularZone: true}}).run(() => {
|
||||
remover2 = manager.addEventListener(element, 'click', handler2);
|
||||
});
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([dispatchedEvent, dispatchedEvent]);
|
||||
expect(receivedZones).toEqual([Zone.root.name, 'fakeAngularZone']);
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvents: any[] /** TODO #9100 */ = [];
|
||||
let receivedZones: any[] = [];
|
||||
const handler1 = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
};
|
||||
const handler2 = (e: any /** TODO #9100 */) => {
|
||||
receivedEvents.push(e);
|
||||
receivedZones.push(Zone.current.name);
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
|
||||
receivedEvents = [];
|
||||
remover1 && remover1();
|
||||
remover2 && remover2();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
// handler1 and handler2 are added in different zone
|
||||
// one is angular zone, the other is not
|
||||
// should still be able to remove them correctly
|
||||
expect(receivedEvents).toEqual([]);
|
||||
let remover1: any = null;
|
||||
let remover2: any = null;
|
||||
// handler1 is added in root zone
|
||||
Zone.root.run(() => {
|
||||
remover1 = manager.addEventListener(element, 'click', handler1);
|
||||
});
|
||||
|
||||
it('should run blackListedEvents handler outside of ngZone', () => {
|
||||
const Zone = (window as any)['Zone'];
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('scroll');
|
||||
let receivedEvent: any /** TODO #9100 */ = null;
|
||||
let receivedZone: any = null;
|
||||
const handler = (e: any /** TODO #9100 */) => {
|
||||
receivedEvent = e;
|
||||
receivedZone = Zone.current;
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
|
||||
let remover = manager.addEventListener(element, 'scroll', handler);
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(dispatchedEvent);
|
||||
expect(receivedZone.name).not.toEqual('angular');
|
||||
|
||||
receivedEvent = null;
|
||||
remover && remover();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(null);
|
||||
// handler2 is added in 'angular' zone
|
||||
Zone.root.fork({name: 'fakeAngularZone', properties: {isAngularZone: true}}).run(() => {
|
||||
remover2 = manager.addEventListener(element, 'click', handler2);
|
||||
});
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvents).toEqual([dispatchedEvent, dispatchedEvent]);
|
||||
expect(receivedZones).toEqual([Zone.root.name, 'fakeAngularZone']);
|
||||
|
||||
it('should only trigger one Change detection when bubbling', (done: DoneFn) => {
|
||||
doc = getDOM().supportsDOMEvents() ? document : getDOM().createHtmlDocument();
|
||||
zone = new NgZone({shouldCoalesceEventChangeDetection: true});
|
||||
domEventPlugin = new DomEventsPlugin(doc);
|
||||
const element = el('<div></div>');
|
||||
const child = el('<div></div>');
|
||||
element.appendChild(child);
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvents: any = [];
|
||||
let stables: any = [];
|
||||
const handler = (e: any) => { receivedEvents.push(e); };
|
||||
const manager = new EventManager([domEventPlugin], zone);
|
||||
let removerChild: any;
|
||||
let removerParent: any;
|
||||
receivedEvents = [];
|
||||
remover1 && remover1();
|
||||
remover2 && remover2();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
// handler1 and handler2 are added in different zone
|
||||
// one is angular zone, the other is not
|
||||
// should still be able to remove them correctly
|
||||
expect(receivedEvents).toEqual([]);
|
||||
});
|
||||
|
||||
zone.run(() => {
|
||||
removerChild = manager.addEventListener(child, 'click', handler);
|
||||
removerParent = manager.addEventListener(element, 'click', handler);
|
||||
});
|
||||
zone.onStable.subscribe((isStable: any) => { stables.push(isStable); });
|
||||
getDOM().dispatchEvent(child, dispatchedEvent);
|
||||
requestAnimationFrame(() => {
|
||||
expect(receivedEvents.length).toBe(2);
|
||||
expect(stables.length).toBe(1);
|
||||
it('should run blackListedEvents handler outside of ngZone', () => {
|
||||
const Zone = (window as any)['Zone'];
|
||||
const element = el('<div><div></div></div>');
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('scroll');
|
||||
let receivedEvent: any /** TODO #9100 */ = null;
|
||||
let receivedZone: any = null;
|
||||
const handler = (e: any /** TODO #9100 */) => {
|
||||
receivedEvent = e;
|
||||
receivedZone = Zone.current;
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], new FakeNgZone());
|
||||
|
||||
removerChild && removerChild();
|
||||
removerParent && removerParent();
|
||||
done();
|
||||
});
|
||||
let remover = manager.addEventListener(element, 'scroll', handler);
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(dispatchedEvent);
|
||||
expect(receivedZone.name).not.toEqual('angular');
|
||||
|
||||
receivedEvent = null;
|
||||
remover && remover();
|
||||
getDOM().dispatchEvent(element, dispatchedEvent);
|
||||
expect(receivedEvent).toBe(null);
|
||||
});
|
||||
|
||||
it('should only trigger one Change detection when bubbling', (done: DoneFn) => {
|
||||
doc = getDOM().supportsDOMEvents() ? document : getDOM().createHtmlDocument();
|
||||
zone = new NgZone({shouldCoalesceEventChangeDetection: true});
|
||||
domEventPlugin = new DomEventsPlugin(doc);
|
||||
const element = el('<div></div>');
|
||||
const child = el('<div></div>');
|
||||
element.appendChild(child);
|
||||
doc.body.appendChild(element);
|
||||
const dispatchedEvent = createMouseEvent('click');
|
||||
let receivedEvents: any = [];
|
||||
let stables: any = [];
|
||||
const handler = (e: any) => {
|
||||
receivedEvents.push(e);
|
||||
};
|
||||
const manager = new EventManager([domEventPlugin], zone);
|
||||
let removerChild: any;
|
||||
let removerParent: any;
|
||||
|
||||
zone.run(() => {
|
||||
removerChild = manager.addEventListener(child, 'click', handler);
|
||||
removerParent = manager.addEventListener(element, 'click', handler);
|
||||
});
|
||||
zone.onStable.subscribe((isStable: any) => {
|
||||
stables.push(isStable);
|
||||
});
|
||||
getDOM().dispatchEvent(child, dispatchedEvent);
|
||||
requestAnimationFrame(() => {
|
||||
expect(receivedEvents.length).toBe(2);
|
||||
expect(stables.length).toBe(1);
|
||||
|
||||
removerChild && removerChild();
|
||||
removerParent && removerParent();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
||||
/** @internal */
|
||||
class FakeEventManagerPlugin extends EventManagerPlugin {
|
||||
eventHandler: {[event: string]: Function} = {};
|
||||
|
||||
constructor(doc: any, public supportedEvents: string[]) { super(doc); }
|
||||
constructor(doc: any, public supportedEvents: string[]) {
|
||||
super(doc);
|
||||
}
|
||||
|
||||
supports(eventName: string): boolean { return this.supportedEvents.indexOf(eventName) > -1; }
|
||||
supports(eventName: string): boolean {
|
||||
return this.supportedEvents.indexOf(eventName) > -1;
|
||||
}
|
||||
|
||||
addEventListener(element: any, eventName: string, handler: Function) {
|
||||
this.eventHandler[eventName] = handler;
|
||||
return () => { delete this.eventHandler[eventName]; };
|
||||
return () => {
|
||||
delete this.eventHandler[eventName];
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class FakeNgZone extends NgZone {
|
||||
constructor() { super({enableLongStackTrace: false, shouldCoalesceEventChangeDetection: true}); }
|
||||
run<T>(fn: (...args: any[]) => T, applyThis?: any, applyArgs?: any[]): T { return fn(); }
|
||||
runOutsideAngular(fn: Function) { return fn(); }
|
||||
constructor() {
|
||||
super({enableLongStackTrace: false, shouldCoalesceEventChangeDetection: true});
|
||||
}
|
||||
run<T>(fn: (...args: any[]) => T, applyThis?: any, applyArgs?: any[]): T {
|
||||
return fn();
|
||||
}
|
||||
runOutsideAngular(fn: Function) {
|
||||
return fn();
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Component, EventEmitter, Injector, Input, NgModule, Output, Renderer2, ViewEncapsulation, destroyPlatform} from '@angular/core';
|
||||
import {Component, destroyPlatform, EventEmitter, Injector, Input, NgModule, Output, Renderer2, ViewEncapsulation} from '@angular/core';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {browserDetection} from '@angular/platform-browser/testing/src/browser_util';
|
||||
@ -15,14 +15,15 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
|
||||
if (browserDetection.supportsShadowDom) {
|
||||
describe('ShadowDOM Support', () => {
|
||||
|
||||
let testContainer: HTMLDivElement;
|
||||
|
||||
beforeEach(() => { TestBed.configureTestingModule({imports: [TestModule]}); });
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({imports: [TestModule]});
|
||||
});
|
||||
|
||||
it('should attach and use a shadowRoot when ViewEncapsulation.Native is set', () => {
|
||||
const compEl = TestBed.createComponent(ShadowComponent).nativeElement;
|
||||
expect(compEl.shadowRoot !.textContent).toEqual('Hello World');
|
||||
expect(compEl.shadowRoot!.textContent).toEqual('Hello World');
|
||||
});
|
||||
|
||||
it('should use the shadow root to encapsulate styles', () => {
|
||||
@ -40,10 +41,10 @@ if (browserDetection.supportsShadowDom) {
|
||||
const el = TestBed.createComponent(ShadowSlotComponent).nativeElement;
|
||||
const projectedContent = document.createTextNode('Hello Slot!');
|
||||
el.appendChild(projectedContent);
|
||||
const slot = el.shadowRoot !.querySelector('slot');
|
||||
const slot = el.shadowRoot!.querySelector('slot');
|
||||
|
||||
expect(slot !.assignedNodes().length).toBe(1);
|
||||
expect(slot !.assignedNodes()[0].textContent).toBe('Hello Slot!');
|
||||
expect(slot!.assignedNodes().length).toBe(1);
|
||||
expect(slot!.assignedNodes()[0].textContent).toBe('Hello Slot!');
|
||||
});
|
||||
|
||||
it('should allow the usage of named <slot> elements', () => {
|
||||
@ -65,16 +66,16 @@ if (browserDetection.supportsShadowDom) {
|
||||
el.appendChild(articleContent);
|
||||
el.appendChild(articleSubcontent);
|
||||
|
||||
const headerSlot = el.shadowRoot !.querySelector('slot[name=header]') as HTMLSlotElement;
|
||||
const articleSlot = el.shadowRoot !.querySelector('slot[name=article]') as HTMLSlotElement;
|
||||
const headerSlot = el.shadowRoot!.querySelector('slot[name=header]') as HTMLSlotElement;
|
||||
const articleSlot = el.shadowRoot!.querySelector('slot[name=article]') as HTMLSlotElement;
|
||||
|
||||
expect(headerSlot !.assignedNodes().length).toBe(1);
|
||||
expect(headerSlot !.assignedNodes()[0].textContent).toBe('Header Text!');
|
||||
expect(headerSlot!.assignedNodes().length).toBe(1);
|
||||
expect(headerSlot!.assignedNodes()[0].textContent).toBe('Header Text!');
|
||||
expect(headerContent.assignedSlot).toBe(headerSlot);
|
||||
|
||||
expect(articleSlot !.assignedNodes().length).toBe(2);
|
||||
expect(articleSlot !.assignedNodes()[0].textContent).toBe('Article Text!');
|
||||
expect(articleSlot !.assignedNodes()[1].textContent).toBe('Article Subtext!');
|
||||
expect(articleSlot!.assignedNodes().length).toBe(2);
|
||||
expect(articleSlot!.assignedNodes()[0].textContent).toBe('Article Text!');
|
||||
expect(articleSlot!.assignedNodes()[1].textContent).toBe('Article Subtext!');
|
||||
expect(articleContent.assignedSlot).toBe(articleSlot);
|
||||
expect(articleSubcontent.assignedSlot).toBe(articleSlot);
|
||||
});
|
||||
|
@ -7,8 +7,8 @@
|
||||
*/
|
||||
|
||||
import {CompilerConfig, ResourceLoader} from '@angular/compiler';
|
||||
import {CUSTOM_ELEMENTS_SCHEMA, Compiler, Component, ComponentFactoryResolver, Directive, Inject, Injectable, InjectionToken, Injector, Input, NgModule, Optional, Pipe, SkipSelf, ɵstringify as stringify} from '@angular/core';
|
||||
import {TestBed, async, fakeAsync, getTestBed, inject, tick, withModule} from '@angular/core/testing';
|
||||
import {Compiler, Component, ComponentFactoryResolver, CUSTOM_ELEMENTS_SCHEMA, Directive, Inject, Injectable, InjectionToken, Injector, Input, NgModule, Optional, Pipe, SkipSelf, ɵstringify as stringify} from '@angular/core';
|
||||
import {async, fakeAsync, getTestBed, inject, TestBed, tick, withModule} from '@angular/core/testing';
|
||||
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
import {ivyEnabled, modifiedInIvy, obsoleteInIvy, onlyInIvy} from '@angular/private/testing';
|
||||
|
||||
@ -18,7 +18,9 @@ import {ivyEnabled, modifiedInIvy, obsoleteInIvy, onlyInIvy} from '@angular/priv
|
||||
@Injectable()
|
||||
class ChildComp {
|
||||
childBinding: string;
|
||||
constructor() { this.childBinding = 'Child'; }
|
||||
constructor() {
|
||||
this.childBinding = 'Child';
|
||||
}
|
||||
}
|
||||
|
||||
@Component({selector: 'child-comp', template: `<span>Mock</span>`})
|
||||
@ -52,12 +54,16 @@ class ChildChildComp {
|
||||
@Injectable()
|
||||
class ChildWithChildComp {
|
||||
childBinding: string;
|
||||
constructor() { this.childBinding = 'Child'; }
|
||||
constructor() {
|
||||
this.childBinding = 'Child';
|
||||
}
|
||||
}
|
||||
|
||||
class FancyService {
|
||||
value: string = 'real value';
|
||||
getAsyncValue() { return Promise.resolve('async value'); }
|
||||
getAsyncValue() {
|
||||
return Promise.resolve('async value');
|
||||
}
|
||||
getTimeoutValue() {
|
||||
return new Promise<string>((resolve, reject) => setTimeout(() => resolve('timeout value'), 10));
|
||||
}
|
||||
@ -88,13 +94,14 @@ class TestViewProvidersComp {
|
||||
@Directive({selector: '[someDir]', host: {'[title]': 'someDir'}})
|
||||
class SomeDirective {
|
||||
// TODO(issue/24571): remove '!'.
|
||||
@Input()
|
||||
someDir !: string;
|
||||
@Input() someDir!: string;
|
||||
}
|
||||
|
||||
@Pipe({name: 'somePipe'})
|
||||
class SomePipe {
|
||||
transform(value: string) { return `transformed ${value}`; }
|
||||
transform(value: string) {
|
||||
return `transformed ${value}`;
|
||||
}
|
||||
}
|
||||
|
||||
@Component({selector: 'comp', template: `<div [someDir]="'someValue' | somePipe"></div>`})
|
||||
@ -120,11 +127,17 @@ const bTok = new InjectionToken<string>('b');
|
||||
describe('using the async helper with context passing', () => {
|
||||
type TestContext = {actuallyDone: boolean};
|
||||
|
||||
beforeEach(function(this: TestContext) { this.actuallyDone = false; });
|
||||
beforeEach(function(this: TestContext) {
|
||||
this.actuallyDone = false;
|
||||
});
|
||||
|
||||
afterEach(function(this: TestContext) { expect(this.actuallyDone).toEqual(true); });
|
||||
afterEach(function(this: TestContext) {
|
||||
expect(this.actuallyDone).toEqual(true);
|
||||
});
|
||||
|
||||
it('should run normal tests', function(this: TestContext) { this.actuallyDone = true; });
|
||||
it('should run normal tests', function(this: TestContext) {
|
||||
this.actuallyDone = true;
|
||||
});
|
||||
|
||||
it('should run normal async tests', function(this: TestContext, done) {
|
||||
setTimeout(() => {
|
||||
@ -133,8 +146,9 @@ const bTok = new InjectionToken<string>('b');
|
||||
}, 0);
|
||||
});
|
||||
|
||||
it('should run async tests with tasks',
|
||||
async(function(this: TestContext) { setTimeout(() => this.actuallyDone = true, 0); }));
|
||||
it('should run async tests with tasks', async(function(this: TestContext) {
|
||||
setTimeout(() => this.actuallyDone = true, 0);
|
||||
}));
|
||||
|
||||
it('should run async tests with promises', async(function(this: TestContext) {
|
||||
const p = new Promise((resolve, reject) => setTimeout(resolve, 10));
|
||||
@ -149,18 +163,26 @@ const bTok = new InjectionToken<string>('b');
|
||||
|
||||
type TestContext = {contextModified: boolean};
|
||||
|
||||
beforeEach(function(this: TestContext) { this.contextModified = false; });
|
||||
beforeEach(function(this: TestContext) {
|
||||
this.contextModified = false;
|
||||
});
|
||||
|
||||
afterEach(function(this: TestContext) { expect(this.contextModified).toEqual(true); });
|
||||
afterEach(function(this: TestContext) {
|
||||
expect(this.contextModified).toEqual(true);
|
||||
});
|
||||
|
||||
it('should pass context to inject helper',
|
||||
inject([], function(this: TestContext) { this.contextModified = true; }));
|
||||
it('should pass context to inject helper', inject([], function(this: TestContext) {
|
||||
this.contextModified = true;
|
||||
}));
|
||||
|
||||
it('should pass context to fakeAsync helper',
|
||||
fakeAsync(function(this: TestContext) { this.contextModified = true; }));
|
||||
it('should pass context to fakeAsync helper', fakeAsync(function(this: TestContext) {
|
||||
this.contextModified = true;
|
||||
}));
|
||||
|
||||
it('should pass context to withModule helper - simple',
|
||||
withModule(moduleConfig, function(this: TestContext) { this.contextModified = true; }));
|
||||
withModule(moduleConfig, function(this: TestContext) {
|
||||
this.contextModified = true;
|
||||
}));
|
||||
|
||||
it('should pass context to withModule helper - advanced',
|
||||
withModule(moduleConfig)
|
||||
@ -199,7 +221,7 @@ const bTok = new InjectionToken<string>('b');
|
||||
|
||||
it('should allow the use of fakeAsync',
|
||||
fakeAsync(inject([FancyService], (service: FancyService) => {
|
||||
let value: string = undefined !;
|
||||
let value: string = undefined!;
|
||||
service.getAsyncValue().then((val) => value = val);
|
||||
tick();
|
||||
expect(value).toEqual('async value');
|
||||
@ -329,7 +351,9 @@ const bTok = new InjectionToken<string>('b');
|
||||
describe('overwriting metadata', () => {
|
||||
@Pipe({name: 'undefined'})
|
||||
class SomePipe {
|
||||
transform(value: string): string { return `transformed ${value}`; }
|
||||
transform(value: string): string {
|
||||
return `transformed ${value}`;
|
||||
}
|
||||
}
|
||||
|
||||
@Directive({selector: '[undefined]'})
|
||||
@ -418,7 +442,6 @@ const bTok = new InjectionToken<string>('b');
|
||||
});
|
||||
|
||||
describe('overriding providers', () => {
|
||||
|
||||
describe('in core', () => {
|
||||
it('ComponentFactoryResolver', () => {
|
||||
const componentFactoryMock =
|
||||
@ -429,7 +452,6 @@ const bTok = new InjectionToken<string>('b');
|
||||
});
|
||||
|
||||
describe('in NgModules', () => {
|
||||
|
||||
it('should support useValue', () => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
@ -501,7 +523,9 @@ const bTok = new InjectionToken<string>('b');
|
||||
|
||||
@NgModule()
|
||||
class SomeModule {
|
||||
constructor() { someModule = this; }
|
||||
constructor() {
|
||||
someModule = this;
|
||||
}
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
@ -731,11 +755,12 @@ const bTok = new InjectionToken<string>('b');
|
||||
|
||||
@Directive({selector: '[test]'})
|
||||
class TestDir {
|
||||
constructor() { testDir = this; }
|
||||
constructor() {
|
||||
testDir = this;
|
||||
}
|
||||
|
||||
// TODO(issue/24571): remove '!'.
|
||||
@Input('test')
|
||||
test !: string;
|
||||
@Input('test') test!: string;
|
||||
}
|
||||
|
||||
TestBed.overrideTemplateUsingTestingModule(
|
||||
@ -746,7 +771,7 @@ const bTok = new InjectionToken<string>('b');
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement).toHaveText('Hello world!');
|
||||
expect(testDir).toBeAnInstanceOf(TestDir);
|
||||
expect(testDir !.test).toBe('some prop');
|
||||
expect(testDir!.test).toBe('some prop');
|
||||
});
|
||||
|
||||
it('should throw if the TestBed is already created', () => {
|
||||
@ -776,9 +801,7 @@ const bTok = new InjectionToken<string>('b');
|
||||
});
|
||||
|
||||
describe('setting up the compiler', () => {
|
||||
|
||||
describe('providers', () => {
|
||||
|
||||
it('should use set up providers', fakeAsync(() => {
|
||||
// Keeping this component inside the test is needed to make sure it's not resolved
|
||||
// prior to this test, thus having ɵcmp and a reference in resource
|
||||
@ -869,8 +892,9 @@ const bTok = new InjectionToken<string>('b');
|
||||
const itPromise = patchJasmineIt();
|
||||
const barError = new Error('bar');
|
||||
|
||||
it('throws an async error',
|
||||
async(inject([], () => setTimeout(() => { throw barError; }, 0))));
|
||||
it('throws an async error', async(inject([], () => setTimeout(() => {
|
||||
throw barError;
|
||||
}, 0))));
|
||||
|
||||
itPromise.then(() => done.fail('Expected test to fail, but it did not'), (err) => {
|
||||
expect(err).toEqual(barError);
|
||||
@ -883,7 +907,7 @@ const bTok = new InjectionToken<string>('b');
|
||||
const itPromise = patchJasmineIt();
|
||||
|
||||
it('should fail with an error from a promise', async(inject([], () => {
|
||||
let reject: (error: any) => void = undefined !;
|
||||
let reject: (error: any) => void = undefined!;
|
||||
const promise = new Promise((_, rej) => reject = rej);
|
||||
const p = promise.then(() => expect(1).toEqual(2));
|
||||
|
||||
@ -919,21 +943,23 @@ const bTok = new InjectionToken<string>('b');
|
||||
}
|
||||
|
||||
expect(
|
||||
() => it(
|
||||
'should fail', withModule(
|
||||
{declarations: [InlineCompWithUrlTemplate]},
|
||||
() => TestBed.createComponent(InlineCompWithUrlTemplate))))
|
||||
() =>
|
||||
it('should fail',
|
||||
withModule(
|
||||
{declarations: [InlineCompWithUrlTemplate]},
|
||||
() => TestBed.createComponent(InlineCompWithUrlTemplate))))
|
||||
.toThrowError(
|
||||
ivyEnabled ?
|
||||
`Component 'InlineCompWithUrlTemplate' is not resolved:
|
||||
- templateUrl: /base/angular/packages/platform-browser/test/static_assets/test.html
|
||||
Did you run and wait for 'resolveComponentResources()'?` :
|
||||
`This test module uses the component ${stringify(InlineCompWithUrlTemplate)} which is using a "templateUrl" or "styleUrls", but they were never compiled. ` +
|
||||
`This test module uses the component ${
|
||||
stringify(
|
||||
InlineCompWithUrlTemplate)} which is using a "templateUrl" or "styleUrls", but they were never compiled. ` +
|
||||
`Please call "TestBed.compileComponents" before your test.`);
|
||||
|
||||
restoreJasmineIt();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
@ -972,7 +998,6 @@ Did you run and wait for 'resolveComponentResources()'?` :
|
||||
});
|
||||
|
||||
describe('creating components', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [
|
||||
@ -1008,7 +1033,6 @@ Did you run and wait for 'resolveComponentResources()'?` :
|
||||
const componentFixture = TestBed.createComponent(ChildComp);
|
||||
componentFixture.detectChanges();
|
||||
expect(componentFixture.nativeElement).toHaveText('Mock');
|
||||
|
||||
}));
|
||||
|
||||
it('should override a provider', async(() => {
|
||||
|
Reference in New Issue
Block a user