fix(WebWorker): remove the platform-browser dependency on compiler
This commit is contained in:
@ -1 +1,4 @@
|
||||
export * from './platform_browser_dynamic';
|
||||
export * from './src/platform_browser_dynamic';
|
||||
|
||||
export * from './src/worker_render';
|
||||
export * from './src/worker_app';
|
||||
|
@ -1,4 +1,7 @@
|
||||
import {__platform_browser_private__ as _} from '@angular/platform-browser';
|
||||
|
||||
export type DomAdapter = _.DomAdapter;
|
||||
export function getDOM(): _.DomAdapter{return _.getDOM()};
|
||||
export function getDOM(): _.DomAdapter {
|
||||
return _.getDOM()
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,20 @@
|
||||
import {
|
||||
reflector,
|
||||
ReflectiveInjector,
|
||||
coreLoadAndBootstrap,
|
||||
Type,
|
||||
ComponentRef
|
||||
} from '@angular/core';
|
||||
|
||||
import {COMPILER_PROVIDERS, XHR} from '@angular/compiler';
|
||||
import {CachedXHR} from './src/xhr/xhr_cache';
|
||||
import {Provider, Type, ComponentRef} from '@angular/core';
|
||||
import {isPresent} from './src/facade/lang';
|
||||
import {XHRImpl} from './src/xhr/xhr_impl';
|
||||
import {BROWSER_APP_COMMON_PROVIDERS, browserPlatform} from '@angular/platform-browser';
|
||||
import {reflector, ReflectiveInjector, coreLoadAndBootstrap} from '@angular/core';
|
||||
import {getDOM} from './platform_browser_private';
|
||||
import {ReflectionCapabilities} from './core_private';
|
||||
import {CachedXHR} from '../src/xhr/xhr_cache';
|
||||
import {isPresent} from '../src/facade/lang';
|
||||
import {XHRImpl} from '../src/xhr/xhr_impl';
|
||||
import {
|
||||
browserPlatform,
|
||||
BROWSER_APP_COMMON_PROVIDERS,
|
||||
} from '@angular/platform-browser';
|
||||
import {ReflectionCapabilities} from '../core_private';
|
||||
|
||||
export const CACHED_TEMPLATE_PROVIDER: Array<any /*Type | Provider | any[]*/> =
|
||||
/*@ts2dart_const*/[{provide: XHR, useClass: CachedXHR}];
|
||||
@ -21,8 +29,6 @@ export const BROWSER_APP_DYNAMIC_PROVIDERS: Array<any /*Type | Provider | any[]*
|
||||
{provide: XHR, useClass: XHRImpl},
|
||||
];
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Bootstrapping for Angular applications.
|
||||
*
|
@ -0,0 +1,5 @@
|
||||
/**
|
||||
* All channels used by angular's WebWorker components are listed here.
|
||||
* You should not use these channels in your application code.
|
||||
*/
|
||||
export const XHR_CHANNEL = "ng-XHR";
|
@ -0,0 +1,23 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {PRIMITIVE, ServiceMessageBrokerFactory} from '@angular/platform-browser';
|
||||
import {XHR_CHANNEL} from '../shared/messaging_api';
|
||||
import {XHR} from '@angular/compiler';
|
||||
import {FunctionWrapper} from '../../facade/lang';
|
||||
|
||||
/**
|
||||
* XHR requests triggered on the worker side are executed on the UI side.
|
||||
*
|
||||
* This is only strictly required for Dart where the isolates do not have access to XHRs.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
@Injectable()
|
||||
export class MessageBasedXHRImpl {
|
||||
constructor(private _brokerFactory: ServiceMessageBrokerFactory, private _xhr: XHR) {}
|
||||
|
||||
start(): void {
|
||||
var broker = this._brokerFactory.createMessageBroker(XHR_CHANNEL);
|
||||
broker.registerMethod("get", [PRIMITIVE], FunctionWrapper.bind(this._xhr.get, this._xhr),
|
||||
PRIMITIVE);
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {XHR} from '@angular/compiler';
|
||||
import {
|
||||
FnArg,
|
||||
UiArguments,
|
||||
ClientMessageBroker,
|
||||
ClientMessageBrokerFactory
|
||||
} from '@angular/platform-browser';
|
||||
import {XHR_CHANNEL} from '../shared/messaging_api';
|
||||
|
||||
/**
|
||||
* Implementation of compiler/xhr that relays XHR requests to the UI side where they are sent
|
||||
* and the result is proxied back to the worker.
|
||||
*
|
||||
* This is only strictly required for Dart where isolates do not have access to the XHRs.
|
||||
*/
|
||||
@Injectable()
|
||||
export class WebWorkerXHRImpl extends XHR {
|
||||
private _messageBroker: ClientMessageBroker;
|
||||
|
||||
constructor(messageBrokerFactory: ClientMessageBrokerFactory) {
|
||||
super();
|
||||
this._messageBroker = messageBrokerFactory.createMessageBroker(XHR_CHANNEL);
|
||||
}
|
||||
|
||||
get(url: string): Promise<string> {
|
||||
var fnArgs: FnArg[] = [new FnArg(url, null)];
|
||||
var args: UiArguments = new UiArguments("get", fnArgs);
|
||||
return this._messageBroker.runOnService(args, String);
|
||||
}
|
||||
}
|
28
modules/@angular/platform-browser-dynamic/src/worker_app.ts
Normal file
28
modules/@angular/platform-browser-dynamic/src/worker_app.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import {WORKER_APP_APPLICATION_PROVIDERS, workerAppPlatform} from '@angular/platform-browser';
|
||||
import {COMPILER_PROVIDERS, XHR} from '@angular/compiler';
|
||||
import {WebWorkerXHRImpl} from './web_workers/worker/xhr_impl';
|
||||
import {isPresent} from './facade/lang';
|
||||
|
||||
import {
|
||||
PlatformRef,
|
||||
Type,
|
||||
ComponentRef,
|
||||
ReflectiveInjector,
|
||||
coreLoadAndBootstrap,
|
||||
} from '@angular/core';
|
||||
|
||||
export const WORKER_APP_DYNAMIC_APPLICATION_PROVIDERS: Array<any /*Type | Provider | any[]*/> = [
|
||||
WORKER_APP_APPLICATION_PROVIDERS,
|
||||
COMPILER_PROVIDERS,
|
||||
WebWorkerXHRImpl,
|
||||
/* @ts2dart_Provider */ {provide: XHR, useExisting: WebWorkerXHRImpl}
|
||||
];
|
||||
|
||||
export function bootstrapApp(
|
||||
appComponentType: Type,
|
||||
customProviders?: Array<any /*Type | Provider | any[]*/>): Promise<ComponentRef<any>> {
|
||||
var appInjector = ReflectiveInjector.resolveAndCreate(
|
||||
[WORKER_APP_DYNAMIC_APPLICATION_PROVIDERS, isPresent(customProviders) ? customProviders : []],
|
||||
workerAppPlatform().injector);
|
||||
return coreLoadAndBootstrap(appInjector, appComponentType);
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
import {XHR} from "@angular/compiler";
|
||||
import {XHRImpl} from "./xhr/xhr_impl";
|
||||
import {MessageBasedXHRImpl} from "./web_workers/ui/xhr_impl";
|
||||
import {
|
||||
WORKER_RENDER_APPLICATION_PROVIDERS,
|
||||
WORKER_RENDER_STARTABLE_MESSAGING_SERVICE
|
||||
} from '@angular/platform-browser';
|
||||
import {
|
||||
ApplicationRef,
|
||||
PlatformRef,
|
||||
ReflectiveInjector,
|
||||
} from '@angular/core';
|
||||
import {workerRenderPlatform, WORKER_SCRIPT} from '@angular/platform-browser';
|
||||
import {isPresent} from './facade/lang';
|
||||
import {PromiseWrapper} from './facade/async';
|
||||
|
||||
export const WORKER_RENDER_DYNAMIC_APPLICATION_PROVIDERS: Array<any /*Type | Provider | any[]*/> = [
|
||||
WORKER_RENDER_APPLICATION_PROVIDERS,
|
||||
/* @ts2dart_Provider */ {provide: XHR, useClass: XHRImpl},
|
||||
MessageBasedXHRImpl,
|
||||
/* @ts2dart_Provider */ {provide: WORKER_RENDER_STARTABLE_MESSAGING_SERVICE, useExisting: MessageBasedXHRImpl, multi: true},
|
||||
];
|
||||
|
||||
export function bootstrapRender(
|
||||
workerScriptUri: string,
|
||||
customProviders?: Array<any /*Type | Provider | any[]*/>): Promise<ApplicationRef> {
|
||||
var app = ReflectiveInjector.resolveAndCreate(
|
||||
[
|
||||
WORKER_RENDER_DYNAMIC_APPLICATION_PROVIDERS,
|
||||
/* @ts2dart_Provider */ {provide: WORKER_SCRIPT, useValue: workerScriptUri},
|
||||
isPresent(customProviders) ? customProviders : []
|
||||
],
|
||||
workerRenderPlatform().injector);
|
||||
// Return a promise so that we keep the same semantics as Dart,
|
||||
// and we might want to wait for the app side to come up
|
||||
// in the future...
|
||||
return PromiseWrapper.resolve(app.get(ApplicationRef));
|
||||
}
|
@ -0,0 +1 @@
|
||||
<span>from external template</span>
|
@ -0,0 +1,7 @@
|
||||
library angular2.test.testing.testing_browser_pec;
|
||||
|
||||
/**
|
||||
* This is intentionally left blank. The public test lib is only for TS/JS
|
||||
* apps.
|
||||
*/
|
||||
main() {}
|
@ -0,0 +1,194 @@
|
||||
import {
|
||||
it,
|
||||
iit,
|
||||
xit,
|
||||
describe,
|
||||
ddescribe,
|
||||
xdescribe,
|
||||
expect,
|
||||
beforeEach,
|
||||
beforeEachProviders,
|
||||
inject,
|
||||
} from '@angular/core/testing';
|
||||
import {
|
||||
async,
|
||||
fakeAsync,
|
||||
flushMicrotasks,
|
||||
Log,
|
||||
tick,
|
||||
} from '@angular/core/testing';
|
||||
|
||||
import {ROUTER_FAKE_PROVIDERS} from '@angular/router/testing';
|
||||
import {ROUTER_DIRECTIVES, Routes, Route} from '@angular/router';
|
||||
|
||||
|
||||
import {Component, bind} from '@angular/core';
|
||||
import {PromiseWrapper} from '../src/facade/promise';
|
||||
import {XHR} from '@angular/compiler';
|
||||
import {XHRImpl} from '../../platform-browser-dynamic/src/xhr/xhr_impl';
|
||||
import {TestComponentBuilder} from '@angular/compiler/testing';
|
||||
|
||||
// Components for the tests.
|
||||
class FancyService {
|
||||
value: string = 'real value';
|
||||
getAsyncValue() { return Promise.resolve('async value'); }
|
||||
getTimeoutValue() {
|
||||
return new Promise((resolve, reject) => { setTimeout(() => {resolve('timeout value')}, 10); })
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'external-template-comp',
|
||||
templateUrl: '/base/modules/@angular/platform-browser/test/static_assets/test.html'
|
||||
})
|
||||
class ExternalTemplateComp {
|
||||
}
|
||||
|
||||
@Component({selector: 'bad-template-comp', templateUrl: 'non-existant.html'})
|
||||
class BadTemplateUrl {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'test-router-cmp',
|
||||
template: `<a [routerLink]="['One']">one</a> <a [routerLink]="['Two']">two</a><router-outlet></router-outlet>`,
|
||||
directives: [ROUTER_DIRECTIVES]
|
||||
})
|
||||
@Routes([
|
||||
new Route({path: '/One', component: BadTemplateUrl}),
|
||||
new Route({path: '/Two', component: ExternalTemplateComp}),
|
||||
])
|
||||
class TestRouterComponent {
|
||||
}
|
||||
|
||||
// Tests for angular2/testing bundle specific to the browser environment.
|
||||
// For general tests, see test/testing/testing_public_spec.ts.
|
||||
export function main() {
|
||||
describe('test APIs for the browser', () => {
|
||||
describe('angular2 jasmine matchers', () => {
|
||||
describe('toHaveCssClass', () => {
|
||||
it('should assert that the CSS class is present', () => {
|
||||
var el = document.createElement('div');
|
||||
el.classList.add('matias');
|
||||
expect(el).toHaveCssClass('matias');
|
||||
});
|
||||
|
||||
it('should assert that the CSS class is not present', () => {
|
||||
var el = document.createElement('div');
|
||||
el.classList.add('matias');
|
||||
expect(el).not.toHaveCssClass('fatias');
|
||||
});
|
||||
});
|
||||
|
||||
describe('toHaveCssStyle', () => {
|
||||
it('should assert that the CSS style is present', () => {
|
||||
var el = document.createElement('div');
|
||||
expect(el).not.toHaveCssStyle('width');
|
||||
|
||||
el.style.setProperty('width', '100px');
|
||||
expect(el).toHaveCssStyle('width');
|
||||
});
|
||||
|
||||
it('should assert that the styles are matched against the element', () => {
|
||||
var el = document.createElement('div');
|
||||
expect(el).not.toHaveCssStyle({width: '100px', height: '555px'});
|
||||
|
||||
el.style.setProperty('width', '100px');
|
||||
expect(el).toHaveCssStyle({width: '100px'});
|
||||
expect(el).not.toHaveCssStyle({width: '100px', height: '555px'});
|
||||
|
||||
el.style.setProperty('height', '555px');
|
||||
expect(el).toHaveCssStyle({height: '555px'});
|
||||
expect(el).toHaveCssStyle({width: '100px', height: '555px'});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('using the async helper', () => {
|
||||
var actuallyDone: boolean;
|
||||
|
||||
beforeEach(() => { actuallyDone = false; });
|
||||
|
||||
afterEach(() => { expect(actuallyDone).toEqual(true); });
|
||||
|
||||
it('should run async tests with XHRs', async(() => {
|
||||
var xhr = new XHRImpl();
|
||||
xhr.get('/base/modules/@angular/platform-browser/test/static_assets/test.html')
|
||||
.then(() => { actuallyDone = true; });
|
||||
}),
|
||||
10000); // Long timeout here because this test makes an actual XHR.
|
||||
});
|
||||
|
||||
describe('using the test injector with the inject helper', () => {
|
||||
describe('setting up Providers', () => {
|
||||
beforeEachProviders(() => [bind(FancyService).toValue(new FancyService())]);
|
||||
|
||||
it('provides a real XHR instance',
|
||||
inject([XHR], (xhr) => { expect(xhr).toBeAnInstanceOf(XHRImpl); }));
|
||||
|
||||
it('should allow the use of fakeAsync', fakeAsync(inject([FancyService], (service) => {
|
||||
var value;
|
||||
service.getAsyncValue().then(function(val) { value = val; });
|
||||
tick();
|
||||
expect(value).toEqual('async value');
|
||||
})));
|
||||
});
|
||||
});
|
||||
|
||||
describe('errors', () => {
|
||||
var originalJasmineIt: any;
|
||||
|
||||
var patchJasmineIt = () => {
|
||||
var deferred = PromiseWrapper.completer();
|
||||
originalJasmineIt = jasmine.getEnv().it;
|
||||
jasmine.getEnv().it = (description: string, fn) => {
|
||||
var done = () => { deferred.resolve() };
|
||||
(<any>done).fail = (err) => { deferred.reject(err) };
|
||||
fn(done);
|
||||
return null;
|
||||
};
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
var restoreJasmineIt = () => { jasmine.getEnv().it = originalJasmineIt; };
|
||||
|
||||
it('should fail when an XHR fails', (done) => {
|
||||
var itPromise = patchJasmineIt();
|
||||
|
||||
it('should fail with an error from a promise',
|
||||
async(inject([TestComponentBuilder],
|
||||
(tcb) => { return tcb.createAsync(BadTemplateUrl); })));
|
||||
|
||||
itPromise.then(() => { done.fail('Expected test to fail, but it did not'); }, (err) => {
|
||||
expect(err).toEqual('Uncaught (in promise): Failed to load non-existant.html');
|
||||
done();
|
||||
});
|
||||
restoreJasmineIt();
|
||||
}, 10000);
|
||||
});
|
||||
|
||||
describe('test component builder', function() {
|
||||
it('should allow an external templateUrl',
|
||||
async(inject([TestComponentBuilder],
|
||||
(tcb: TestComponentBuilder) => {
|
||||
|
||||
tcb.createAsync(ExternalTemplateComp)
|
||||
.then((componentFixture) => {
|
||||
componentFixture.detectChanges();
|
||||
expect(componentFixture.debugElement.nativeElement)
|
||||
.toHaveText('from external template\n');
|
||||
});
|
||||
})),
|
||||
10000); // Long timeout here because this test makes an actual XHR, and is slow on Edge.
|
||||
});
|
||||
});
|
||||
|
||||
describe('apps with router components', () => {
|
||||
beforeEachProviders(() => [ROUTER_FAKE_PROVIDERS]);
|
||||
|
||||
it('should build without a problem',
|
||||
async(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
||||
tcb.createAsync(TestRouterComponent)
|
||||
.then((fixture) => { expect(fixture.nativeElement).toHaveText('one two'); });
|
||||
})));
|
||||
});
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
import {inject, describe, it, expect} from '@angular/core/testing/testing_internal';
|
||||
import {AsyncTestCompleter} from '@angular/core/testing/testing_internal';
|
||||
|
||||
import {SpyMessageBroker} from '@angular/platform-browser/test/web_workers/worker/spies';
|
||||
import {WebWorkerXHRImpl} from '@angular/platform-browser-dynamic/src/web_workers/worker/xhr_impl';
|
||||
import {PromiseWrapper} from '../../../src/facade/async';
|
||||
import {
|
||||
MockMessageBrokerFactory,
|
||||
expectBrokerCall
|
||||
} from '@angular/platform-browser/test/web_workers/shared/web_worker_test_util';
|
||||
|
||||
export function main() {
|
||||
describe("WebWorkerXHRImpl", () => {
|
||||
it("should pass requests through the broker and return the response",
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
const URL = "http://www.example.com/test";
|
||||
const RESPONSE = "Example response text";
|
||||
|
||||
var messageBroker = new SpyMessageBroker();
|
||||
expectBrokerCall(messageBroker, "get", [URL],
|
||||
(_) => { return PromiseWrapper.wrap(() => { return RESPONSE; }); });
|
||||
var xhrImpl = new WebWorkerXHRImpl(new MockMessageBrokerFactory(<any>messageBroker));
|
||||
xhrImpl.get(URL).then((response) => {
|
||||
expect(response).toEqual(RESPONSE);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
});
|
||||
}
|
@ -1 +1,2 @@
|
||||
export * from './testing/browser';
|
||||
export * from './testing/dom_test_component_renderer';
|
@ -3,7 +3,14 @@ import {
|
||||
ADDITIONAL_TEST_BROWSER_PROVIDERS
|
||||
} from '@angular/platform-browser/testing';
|
||||
import {BROWSER_APP_DYNAMIC_PROVIDERS} from '../index';
|
||||
|
||||
import {DirectiveResolver, ViewResolver} from '@angular/compiler';
|
||||
import {
|
||||
MockDirectiveResolver,
|
||||
MockViewResolver,
|
||||
TestComponentRenderer,
|
||||
TestComponentBuilder
|
||||
} from '@angular/compiler/testing';
|
||||
import {DOMTestComponentRenderer} from './dom_test_component_renderer';
|
||||
|
||||
/**
|
||||
* Default platform providers for testing.
|
||||
@ -11,8 +18,20 @@ import {BROWSER_APP_DYNAMIC_PROVIDERS} from '../index';
|
||||
export const TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS: Array<any /*Type | Provider | any[]*/> =
|
||||
/*@ts2dart_const*/[TEST_BROWSER_STATIC_PLATFORM_PROVIDERS];
|
||||
|
||||
|
||||
export const ADDITIONAL_DYNAMIC_TEST_BROWSER_PROVIDERS = [
|
||||
/*@ts2dart_Provider*/ {provide: DirectiveResolver, useClass: MockDirectiveResolver},
|
||||
/*@ts2dart_Provider*/ {provide: ViewResolver, useClass: MockViewResolver},
|
||||
TestComponentBuilder,
|
||||
/*@ts2dart_Provider*/ {provide: TestComponentRenderer, useClass: DOMTestComponentRenderer},
|
||||
];
|
||||
|
||||
/**
|
||||
* Default application providers for testing.
|
||||
*/
|
||||
export const TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS: Array<any /*Type | Provider | any[]*/> =
|
||||
/*@ts2dart_const*/[BROWSER_APP_DYNAMIC_PROVIDERS, ADDITIONAL_TEST_BROWSER_PROVIDERS];
|
||||
/*@ts2dart_const*/[
|
||||
BROWSER_APP_DYNAMIC_PROVIDERS,
|
||||
ADDITIONAL_TEST_BROWSER_PROVIDERS,
|
||||
ADDITIONAL_DYNAMIC_TEST_BROWSER_PROVIDERS
|
||||
];
|
||||
|
@ -0,0 +1,24 @@
|
||||
import {Inject, Injectable} from '@angular/core';
|
||||
import {DOCUMENT} from '@angular/platform-browser';
|
||||
import {getDOM} from '../platform_browser_private';
|
||||
import {TestComponentRenderer} from '@angular/compiler/testing';
|
||||
import {el} from '@angular/platform-browser/testing';
|
||||
|
||||
/**
|
||||
* A DOM based implementation of the TestComponentRenderer.
|
||||
*/
|
||||
@Injectable()
|
||||
export class DOMTestComponentRenderer extends TestComponentRenderer {
|
||||
constructor(@Inject(DOCUMENT) private _doc) { super(); }
|
||||
|
||||
insertRootElement(rootElId: string) {
|
||||
let rootEl = el(`<div id="${rootElId}"></div>`);
|
||||
|
||||
// TODO(juliemr): can/should this be optional?
|
||||
let oldRoots = getDOM().querySelectorAll(this._doc, '[id^=root]');
|
||||
for (let i = 0; i < oldRoots.length; i++) {
|
||||
getDOM().remove(oldRoots[i]);
|
||||
}
|
||||
getDOM().appendChild(this._doc.body, rootEl);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user