I have some RXJS code that does something like the following....
this.webSocketSubject = Observable.webSocket(url);
...
get webSocketStream() {
return this.webSocketSubject;
}
// Other Service
this.socketService.webSocketStream.filter(message => {
return message.method === "logout";
}).subscribe( this.onLogout );
Then in my test I try something like this...
socketService.sendMessage = jasmine.createSpy("Send Message Spy").and.callFake(function() {
socketService.webSocketStream.next(
{
method: "logout",
status: "OK"
}
)
});
// Just to confirm but doesn't get called
socketService.webSocketStream.subscribe(message => console.log("Ok it actually got called"))
But the subscribe code never gets called. I looked for other examples of test WS in RxJS but all I see is this and I can't get something similar working locally.
How do I test Observable.websocket in RxJS?
I had to resort to this but I don't like it.
constructor(private socket: Subject<any> = undefined ) {
if(!socket){
this.webSocketSubject = Observable.webSocket(url);
}
else{
this.webSocketSubject = socket;
}
};
Related
I have aproblem when test Apollo.When I try query with apollo and graphql, i want response return error and partical data, so I set property errorPolicy:'all'. But its not work. I don't no why? Help please!
Here my code:
query { animal {
name
age }, school {
name
numberfd } } `
const { loading,data,error} = useQuery(GET_DASHBOARD_DATA, {
errorPolicy:'all',
onCompleted: (res) => {console.log("complete",res)},
onError : (res,data) => {console.log("ERRRR",res,data)},
})
and i want to receive:
{
error:[...], data:[animal:[...]] }
but its only response error.Here is Apollo's doc: https://www.apollographql.com/docs/react/data/error-handling/
onError type is onError?: (error: ApolloError) => void;. You don't have data inside onError callback.
After useQuery you can add:
console.log('data', data)
console.log('error', error)
I faced the same issue with errorPolicy: 'all', I only received the partial result inside onCompleted callback of useQuery, but no errors.
I created an ErrorLink like this:
private createErrorLink = () => {
return new ApolloLink((operation, forward) => {
return forward(operation).map((response) => {
// filter out errors you don't want to display
const errors = filterSomeErrors(response.errors);
if (errors && response?.data) {
response.data.errors = errors;
}
return response;
});
});
};
Now inside my onCompleted callback I get my data as well as errors. You will have to tweak your types a bit, because seems there is no errors field on response.data by default.
Mind that if you use onError from Apollo and return something from the link, it will retry your request containing errors!
I have a BaseDataService class and it has a method for HttpGet requests.
protected Get<TResponse>(
endPoint: string
): Observable<BaseResponse<TResponse>> {
return this.httpClient.get<TResponse>(this.baseUrl + endPoint).pipe(
map(data => {
const response = <BaseResponse<TResponse>>{};
response.Data = data;
response.Errors = [];
response.HasError = false;
return response;
}),
catchError(errors => {
const response = <BaseResponse<TResponse>>{};
response.Errors = [];
response.Errors.push(errors.error);
response.HasError = true;
return of(response);
})
);
}
And I have a LocationDeviceDataService which extends BaseDataService and it has a method for Get LocationDevices
getAll() {
return this.Get<BasePaginatedResponse<LocationDeviceResponse>>(
EndPoints.GET_LOCATIONDEVICES
);
}
And I am calling this method inside event ,
this.events.subscribe("connection-type:wifi", () => {
this.locationDataService.getAll().subscribe(t => {
localStorage.setItem('LOCATION_DEVICES', JSON.stringify(t.Data.items))
});
});
Everything is fine at first call , but when another events (https://ionicframework.com/docs/api/util/Events/)publish for "connection-type:wifi" this.locationDataService.getAll().subscribe returns responses 1x,2x,4x etc. slower.
I am sure for nothing wrong in back-end.
Should unsubscribe or complete subscription ? If I should , I dont have any trigger for that.
Could you please tell me what is wrong in this code ?
I solved my issue.
I think you can not call observable method inside Ionic events so I changed my method to void. Everything is fine for now.
I am making a request using observable. and trying to subcribe the value. But getting error on typescript. any on help me?
I like to do this:
public getCountry(lat,lan):Observable<any>{
return this.http.get(this.googleApi+lat+','+lan+'&sensor=false').subscribe(data => {
return this.genertedData(data);
} );
}
But getting error as follows:
UPDATES
public getCountry(lat,lan):Observable<any>{
return this.http.get(this.googleApi+lat+','+lan+'&sensor=false').map( data => {
data.results.map( array => {
let details = array.address_components.find( obj => obj.types.includes("country") );
this.countryDetails.countryLongName = details.long_name;
this.countryDetails.countryShortName = details.short_name;
})
return this.countryDetails;
})
}
The problem is that your return type states Observable<any>, where as you actually return whatever this.genertedData(data) returns (Hint: Sounds like a typo in your function. Guess it should be called generatedData ?).
Best practice would be to move the http call into a service and subscribe to its returned Observable within your component.
So to speak:
// => service.ts
public getCountryObservable(lat,lan):Observable<any> {
return this.http.get(this.googleApi+lat+','+lan+'&sensor=false');
}
Your component would look something like:
// => component.ts
export class YourComponent {
constructor(public yourService: YourService) {}
getCountry(lat, lan): whateverDataTypeYourGeneratedDataReturns {
this.yourService.getCountryObservable(lat, lan).subscribe((data) => {
this.data = this.generatedData(data);
});
}
}
Since the return type of the function is Observable<any>, I guess it should just return this.http.get(this.googleApi+lat+','+lan+'&sensor=false')
I'm using Angular2 and I have a question about what is the best way to do if I have many observables.
Can I put subscriptions inside each other or put each one in a different method and put the results in class properties?
Example :
ngOnInit() {
this.route.params**.subscribe**(params => {
if (params['id']) {
this.load = true;
this.batchService.getPagesOfCurrentObject(params['id'], "10", "0")
**.subscribe**(result => {
this.stream = result;
if (this.stream.length > 0) {
this.stream.forEach(page => { this.batchService.getPageStreamById
(page.pageId)**.subscribe**(pageStream => {
let base64 = btoa(new Uint8Array(pageStream.data)
.reduce((data, byte)
=> data + String.fromCharCode(byte), ''));
this.pages.push(base64 );
})
return;
});
}
},
error => this.errorService.setError(<any>error),
() => this.load = false
);
}
});
try {
this.customer = this.sharedService.processSelect.subscription.customer;
} catch (err) {
return;
}
}
Having multiple observables is totally fine, this is what reactive programming is about :)
But here your problem is having too much subscribe. Keep in mind that subscribe is a way to create side effect. To have an easy to read code, you should try to use the least possible subscribe.
Your use case is the perfect use case for the mergeMap operator, that allows you to flatten nested observables.
Here what your code would look like
const response$ = this.route.params
.mergeMap(params => {
return this.batchService.getPagesOfCurrentObject(params['id'])
})
.mergeMap(stream => {
return Rx.Observable.merge(stream.map(page => this.batchService.getPageStreamById(page.pageId))
})
.map(pageStream => /* do your stuff with pageStream, base64 ... */)
response$.subscribe(pageStreamData => pages.push(pageStreamData))
See how there is a single subscription that triggers the side-effect that will modify your app's state
Note that I voluntarily simplified the code (removed error handling and checks) for you to get the idea of how to do that.
I hope it will help you thinking in reactive programming :)
I am trying to test if an element is not present on a page.
I have tried using the following method, but I get an error each time:
Method:
expect(element(CastModule.PersonXpath).isDisplayed()).toEqual(false);
Error: Failed: Timed out waiting for Protractor to synchronize with the page after
seconds. Please see https://github.com/angular/protractor/blob/master/docs/f ...
What method do you recommend?
The error should not be related to the checking for the absence of an element. Try the following:
var elm = element(CastModule.PersonXpath);
expect(browser.isElementPresent(elm)).toBe(false);
See also:
In protractor, browser.isElementPresent vs element.isPresent vs element.isElementPresent
Yeah, testing for NOT visible can be sucky. You should be able to use isPresent(), which means in the dom, where isDisplayed() means it's actually visible, which I'm thinking is your issue. Try...
expect(element(CastModule.PersonXpath).isPresent()).toEqual(false);
You may also want to break this out into a method and use an Expected Condition.
The error doesn't look like it's to do with the element being displayed. It looks like it's to do with page synchronization. Try ignoring the sync, then waiting for angular above the expect with:
browser.ignoreSynchronization = true;
browser.waitForAngular();
expect(element(CastModule.PersonXpath).isDisplayed()).toEqual(false);
To check for visibility (in case isDisplayed or isPresent isn't working), just use:
if (!EC.invisibilityOf(ug.personXpath)) {
throw new Error("Partner logo is not displayed");
}
I managed to find out a solution, using the protractor library.
var EC = protractor.ExpectedConditions; browser.wait(EC.invisibilityOf(element(by.xpath(CastModule.PersonXpath))), 5000).then(function() {
if (EC.invisibilityOf(element(by.xpath(x.LanguagesXpath)))) {
console.log("Persons module is not present - as expected for this scenario");
} else {
throw new Error("Element STILL present");
}
});
});
You can also try below code to handle element displayed or not. Below code returns true or false according to the visibility of the element.
browser.wait(() => {
return element(by.className("claasName")).isDisplayed()
.then(
(hasDisplayed) => {
console.log("Has displayed: "+ hasDisplayed);
return hasDisplayed === false;
}
);
}, 5000)
.then(
() => {
return true;
},
() => {
return false;
}
)
To use presence of element use:
var elm = element(CastModule.PersonXpath);
elm.isPresent().then(function (present) {
if (present) {
element(CastModule.PersonXpath).then(function (labels) {
});
} else {
console.log('Element did not found');
}`enter code here`
expect(elem.isNull===undefined).to.be.equal(true);