-
Notifications
You must be signed in to change notification settings - Fork 2.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Web Sockets #4300
Comments
Yes indeed web sockets are the issue. I had to abandon protractor in my testing as a main framework because of ws protocol. |
Very interesting; could one of you produce a small test repo that reproduces this issue? We can then use that to explore some solutions here. Thanks! |
@NickTomlin , I managed to reproduce the bug in one of my current projects hosted on github. I just had to create a separate branch called |
I had to call |
I have a very similar problem. My tests are not failing but after each page load the test waits for about 30 seconds before it proceeds (seems to be a timeout). See my issue #4316 When I remove Firebase everything is fine. |
The question is how to solve this if you can not remove firebase from the project. |
In my project I solved it by disabling the synchronization. But this has a drawback: I had to insert some sleeps to wait "manually" for the page to get ready. Especially with Angular Material which I use in my project as it uses lots of animations. And there I often have to wait until the animation has finished. But for me this is not a big problem. |
Curious if anyone has had any luck with this? I like @ZuSe's suggestion though. |
For me worked this workaround:
|
I've never used Firebase, so I'm not sure how this could be implemented in this particular case, but I thought I'd post my findings anyway as it might give some pointers as to a possible solution. I've had similar issues with other web sockets based services and the way I got around it was by using NgZone to initialize the web socket outside of Angular. Basically, the idea is as follows : @Injectable()
export class SomeService {
constructor(
private ngZone: NgZone
) {
this.ngZone.runOutsideAngular(() => {
let foo = initWebSocket(...); // Whatever call may set up the web sockets based service, run it outside Angular
foo.listen('event', e => {
this.ngZone.run(() => {
handleEvent(e); // Run callbacks from the web sockets service inside Angular
});
});
});
}
} Using this solution has allowed me to properly run protractor tests with web sockets related to Pusher. Hope it can help. |
…vables - protractor seems to have problems with WebSockets. Therefore, we inject `AngularFireAuth` outside `Angular` but reattach needed observables ( back into a `NgZone` - Sources: - angular/protractor#4300 (comment) - https://stackoverflow.com/questions/42461852/angular-2-inject-service-manually?rq=1 - kamilkisiela/apollo-angular#320 (comment) - currently sign in user can be `undefined` at sign-out - import `AngularFireAuthModule` & `AngularFireDatabaseModule` - set `allScriptsTimeout` back to its default value of `11000`
I've tried @glebihan's approach by using I tried to explicit 'reattach' the subscription to Angular's change detection with the approach from kamilkisiela/apollo-angular#320 (comment) without any success. For public constructor(
injector: Injector,
zone: NgZone,
) {
zone.runOutsideAngular(() => {
this.afAuth = injector.get(AngularFireAuth);
});
} For public constructor(
injector: Injector,
zone: NgZone,
) {
zone.runOutsideAngular(() => {
this.db = injector.get(AngularFireDatabase);
});
this.items = this.db
.list<Item>('/items')
.valueChanges();
} |
@PhilippeMorier What I would try for your AngularFireDatabase example is the following. First declare public constructor(
injector: Injector,
zone: NgZone,
) {
zone.runOutsideAngular(() => {
this.db = injector.get(AngularFireDatabase);
this.db.list<Item>('/items').valueChanges().subscribe(i => {
this.ngZone.run(() => {
this.items.next(i);
});
});
});
} |
Any updates on this issue? this.zone.runOutsideAngular(() => {
this.started = this.connection
.start()
.then(_ => {
console.log('[signaler] started');
this.isStarted = true;
this.connection.on(
'notify',
(messageType: string, signal: Signal) => {
signal.messageType = messageType;
this.zone.runGuarded(() => this.signalsSubject$.next(signal));
}
);
})
.catch();
}); |
@pavelpykhtin this is my solution (with help from StackOverflow, of course), to have the app and the tests work like expected. The service-consumer don't have to handle with zones, it's all done inside the service. import { Injectable, NgZone } from "@angular/core";
import { Observable, Observer, TeardownLogic, SchedulerLike, Subscription, asapScheduler, from, of as observableOf } from "rxjs";
import { switchMap, observeOn } from "rxjs/operators";
import * as signalR from "@aspnet/signalr";
export class TheResponse {
}
class LeaveZoneScheduler implements SchedulerLike {
constructor(
private zone: NgZone,
private scheduler: SchedulerLike,
) {
}
schedule(...args: any[]): Subscription {
return this.zone.runOutsideAngular(() =>
this.scheduler.schedule.apply(this.scheduler, args)
);
}
now(): number {
return this.scheduler.now();
}
}
export function leaveZone(zone: NgZone, scheduler: SchedulerLike): SchedulerLike {
return new LeaveZoneScheduler(zone, scheduler);
}
class EnterZoneScheduler implements SchedulerLike {
constructor(
private zone: NgZone,
private scheduler: SchedulerLike,
) {
}
schedule(...args: any[]): Subscription {
return this.zone.run(() =>
this.scheduler.schedule.apply(this.scheduler, args)
);
}
now(): number {
return this.scheduler.now();
}
}
export function enterZone(zone: NgZone, scheduler: SchedulerLike): SchedulerLike {
return new EnterZoneScheduler(zone, scheduler);
}
@Injectable()
export class TheHubService {
private static _hubConnection: signalR.HubConnection = null;
private static _huburl: string = "/api/The/Hub";
constructor(private _zone: NgZone) {
}
private static async waitForHubConnectionAsync(): Promise<signalR.HubConnection> {
if (TheHubService._hubConnection === null) {
TheHubService._hubConnection = new signalR.HubConnectionBuilder()
.withUrl(TheHubService._huburl)
.build();
await TheHubService._hubConnection
.start()
.catch((err: any) => {
console.error("error:", err);
});
}
let retry: number = 100; // 100 * 100ms = 10s
while ((retry > 0) && (TheHubService._hubConnection.state !== signalR.HubConnectionState.Connected)) {
await new Promise<void>(resolve => setTimeout(resolve, 100));
retry--;
}
if (TheHubService._hubConnection.state !== signalR.HubConnectionState.Connected) {
throw new Error("can't connect to the hub.");
}
return TheHubService._hubConnection;
}
getTheResponse(): Observable<TheResponse> {
return observableOf(true, leaveZone(this._zone, asapScheduler))
.pipe(
switchMap((_) => from(TheHubService.waitForHubConnectionAsync())),
switchMap((connection: signalR.HubConnection) => Observable.create((observer: Observer<TheResponse>): TeardownLogic => {
const streamResult: signalR.IStreamResult<TheResponse> = connection.stream("GetTheResponse");
const subscription = streamResult.subscribe(observer);
return () => subscription.dispose();
}) as Observable<TheResponse>),
observeOn(enterZone(this._zone, asapScheduler)),
);
}
} |
I've been investigating a similar issue with our Protractor tests and setting up our websocket outside of the Angular zone didn't change anything, so after following the steps in https://stackoverflow.com/questions/48627074/how-to-track-which-async-tasks-protractor-is-waiting-on to add task tracking to zone-evergreen.js I found that the culprit was Pace calling setTimeout in a loop. While running the test in non headless mode, entering Pace.stop() in the browser's console (while the test was hanging, having set an longer timeout before hand) would always make the test complete immediately in a success. https://github.com/HubSpot/pace/blob/master/pace.coffee shows that the default value for trackWebSockets is true. Changing that config fixed the issue and all of our tests are now completing successfully! Here is the patch that you can apply by executing
|
Can't run Protractor test on Angular2+ apps using Firrebase.
Following up from angular/angularfire#779
Bug report
v7.3.0
5.1.2
4.1.2
chrome
MacOS Sierra 10.12.4
Just including either
AngularFireAuth
orAngularFireDatabase
in an Angular4AppTestComponent
triggers the error.https://onlineboard.sonnywebdesign.com/
The text was updated successfully, but these errors were encountered: