Unit Test NgRx effect with fromEvent stream - ngrx

How do you unit test an NgRx Effect that listens to a window event?
I know how the Unit Test is setup with the actions stream as this is well documented, but I could not find an example to test this with event listeners.
Here is the effect I would like to unit test:
openKeyboard$ = createEffect(() => {
return fromEvent(window, 'ionKeyboardDidShow').pipe(mapTo(KeyboardActions.keyboardOpened()));
});
The unit test description would look something like that:
describe('openKeyboard$', () => {
it('dispatches keyboardOpened action on ionKeyboardDidShow window event', () => {
// how to test this?
});
});
Thanks for your help.

I kind of found a solution that works by just dispatching the window event but I am not really sure if this is an elegant one
describe('openKeyboard$', () => {
it('dispatches keyboardOpened action on ionKeyboardDidShow window event', (done) => {
effects.openKeyboard$.subscribe((res) => {
expect(res).toEqual(KeyboardActions.keyboardOpened());
done();
});
const eventMock = new Event('ionKeyboardDidShow');
window.dispatchEvent(eventMock);
});
});

Related

Event Editable: When edit a specific event, other events on the same group unexpectedly edited same as that specific event

I am trying the editable, drag and expand event on my FullCalendar.
First of all, I am using React.
To describe the problem:
If I have this 2 events on my calendar with same group:
before drag and drop
Event1 is Workshop#1pm, Event 2 is Date#5pm
When I drag and drop Workshop to 12 pm, the same will goes to Date and it will located at 4pm, at the same time.
after drag and drop
Same thing happen with changing duration.
I only want single event to be affected with the gesture, not all event on its group.
So far, I tried to read the documentation thoroughly but I could not find any settings related to it. I also tried to search forums but I never found similar problem.
I am suspecting it has something to do with my complex style of populating calendar with event.
constructor(props) {
super(props);
this.state = {
myEventSource: [],
}
// function the fetch event from google API
loadEvents = async () => {
await fetch(fetchCommand)
.then(res => res.json())
.then((res) => {
// making the loop
res.result.forEach(result => {
// when get result, it will compose the events object to be
// stored in this.state.myEventSource
var tempEvent = [];
result[0].eventsInfo.forEach(event => {
var evt = {
id: event.id,
groupId: result[0].userName,
title: event.summary,
allDay: event.start.date!=null?true:false,
start: event.start.dateTime!=null?event.start.dateTime?.toString():event.start.date?.toString(),
end: event.end.dateTime!=null?event.end.dateTime?.toString():event.end.date?.toString(),
}
tempEvent.push(evt);
});
this.TempEventSource[result[0].userName] = tempEvent;
});
});
...
this.setState({ myEventSource: this.updateCalendarOnTabChange(this.state.tabIndex), firstLoad: true });
}
render() {
return(
<FullCalendar
plugins={[ timeGridPlugin, dayGridPlugin, interactionPlugin]} //
editable={true}
...
eventSources={this.state.myEventSource}
/>
)
}

How to accept a window confirm fired by an iframe with Cypress

I'm having some problems with Cypress when I need to accept a window confirm popup that is fired from a iframe. Cypress it's not very friendly with iframes, but I managed to make it work until I've found that need.
So here's what I've tried (based on this):
cy.get("[title='Some title']").then(($iframe) => {
const $body = $iframe.contents().find("body");
const $win = $iframe[0].contentWindow;
cy.stub($win, "confirm").as("windowConfirm");
cy.wrap($body)
.contains("Delete")
.click() // this fires the confirm popup
.should(function () {
expect(this.windowConfirm).to.be.calledWith(
`Continue deletion?`
);
});
});
It actually asserts the text inside the popup, but never accepts it.
I've tried different methods I've found (i.e. using a.on("window:confirm", () => true) but I've got no results.
Thank you!
Just add your truthy function to the stub
cy.stub($win, 'confirm', () => true)
.as('windowConfirm')
Prints CONFIRMED to the console.
it('confirms in iframe', () => {
cy.visit('../app/iframe-confirm-popup.html')
cy.get('iframe').then(($iframe) => {
const $body = $iframe.contents().find('body')
const $win = $iframe[0].contentWindow
cy.stub($win, 'confirm', () => true)
.as('windowConfirm')
cy.stub($win.console, 'log').as('consoleLog')
cy.wrap($body)
.find('input').click().should(function () {
expect(this.windowConfirm).to.be.calledWith('Are you sure you want to submit your application?')
expect(this.consoleLog).to.be.calledWith('CONFIRMED') // passes
})
})
})

Frappe: cur_frm.add_custom_button() does not add a Custom-Button

I'm creating custom-buttons in a Client Script. This code works:
// Buttons do appear, everything is fine
frappe.ui.form.on('Article', {
refresh(frm) {
frm.add_custom_button("Hello", () => {
msgprint("Hello");
}, "Greet");
frm.add_custom_button("Ciao", () => {
msgprint("Ciao");
}, "Greet");
}
Then I thought about creating the buttons outside the events with cur_frm, which doesn't work. Why is this so?
// Buttons don't appear
cur_frm.add_custom_button("Hello", () => {
msgprint("Hello");
}, "Greet");
cur_frm.add_custom_button("Ciao", () => {
msgprint("Ciao");
}, "Greet");
cur_frm is deprecated API. Why can't you use frm from one of the JS event methods?

Firebase function not running/logging

I have a firebase cloud function and for some reason it is not running or logging even with just console.log("hello world") inside. This is confusing me, I think the issue could be because of promises, but even so I think it should work with just a console.log().
I call the function like this:
const addJobFunction = firestore.functions().httpsCallable("addJob");
addJobFunction({companyName: comp[0].data.Name, jobTitle: this.state.jobTitle,
jobLink: this.state.jobLink, companyKey: this.state.company});
and the function looks like:
exports.addJob = functions.https.onCall(async (data, context) => {
console.log("hello world");
db.collection("jobs")
.add({
company: data.companyName,
title: data.jobTitle,
link: data.jobLink,
data: [],
});
});
The result in my logs whether the database add is there or not (I.e just a console.log) is this.
Turns out I needed event.preventDefault() in my form submit function.
Works like this:
submitJob = (event) => {
event.preventDefault();
console.log(this.state.company);
let comp = this.state.companies.filter((company) => {
return company.key === this.state.company;
});
const addJobFunction = firestore.functions().httpsCallable("addJob");
addJobFunction({
companyName: comp[0].data.Name,
jobTitle: this.state.jobTitle,
jobLink: this.state.jobLink,
companyKey: this.state.company,
});
this.setState({
jobTitle: '',
jobLink: '',
})
};

Angular2 - http call Code coverage

My components.ts is,
getHomePageData() : void{
this.homeservice.getHomePageData()
.subscribe(
data => {
//console.log("response status ################### "+data.status);
//console.log("getUserData response ************ \n"+JSON.stringify(data));
this.defaultFacilityId = data.response.defaultFacilityId;
this.defaultFacilityName = data.response.defaultFacilityName;
this.enterpriseId = data.response.enterpriseId;
this.enterpriseName = data.response.enterpriseName;
this.facilityList = data.response.facilityList;
this.userName = data.response.userName;
this.showDefaultPopoup();
},
error => {
console.error(error);
//this.errorMessage="Technical error - Contact Support team !" ;
}
);
}
So my component.spec.ts is ,
it('getHomePageData with SUCCESS - getHomePageData()', () => {
backend.connections.subscribe((connection: MockConnection) => {
//expect(connection.request.url).toEqual('http://localhost:8080/MSMTestWebApp/UDM/UdmService/Home/');
expect(connection.request.url).toEqual('http://192.168.61.158:9080/GetUserData');
expect(connection.request.method).toEqual(RequestMethod.Get);
expect(connection.request.headers.get('Content-Type')).toEqual('application/json');
let options = new ResponseOptions({
body:
{
"request": { "url": "/getUserData" },
"response": {
"defaultFacilityName":"3M Health Information Systems",
"enterpriseId":"11.0",
"enterpriseName":"HSA Enterprise",
"defaultFacilityId": "55303.0",
"userName":"Anand"
},
"error": ""
},
status : 200
});
connection.mockRespond(new Response(options));
});
backend.connections.subscribe((data) => {
//expect(data.response.facilityId).toEqual("55303.0");
//expect(subject.handleError).toHaveBeenCalled();
})
service.getHomePageData().subscribe((data) => {
//expect(videos.length).toBe(4);
expect(data.response.defaultFacilityId).toEqual("55303.0");
component.defaultFacilityId = data.response.defaultFacilityId;
component.defaultFacilityName = data.response.defaultFacilityName;
component.enterpriseId = data.response.enterpriseId;
component.enterpriseName = data.response.enterpriseName;
component.userName = data.response.userName;
console.log("$$$$$$$$$$$$$$$$**********$$$$$$$$$$$$$$$$$$$$$");
});
});
When i try to run test case. It got passed. But while I look into the code coverage, it doesn't cover the code shown in red below
Please help to get the full code coverage. Thanks.
In the test you've shown here you don't seem to be calling getHomePageData() from your component
Try building your test like this:
import { fakeAsync, tick } from '#angular/core/testing';
...
it('getHomePageData with SUCCESS - getHomePageData()', fakeAsync(() => {
backend.connections.subscribe((connection: MockConnection) => {
//expect(connection.request.url).toEqual('http://localhost:8080/MSMTestWebApp/UDM/UdmService/Home/');
expect(connection.request.url).toEqual('http://192.168.61.158:9080/GetUserData');
expect(connection.request.method).toEqual(RequestMethod.Get);
expect(connection.request.headers.get('Content-Type')).toEqual('application/json');
let options = new ResponseOptions({
body:
{
"request": { "url": "/getUserData" },
"response": {
"defaultFacilityName":"3M Health Information Systems",
"enterpriseId":"11.0",
"enterpriseName":"HSA Enterprise",
"defaultFacilityId": "55303.0",
"userName":"Anand"
},
"error": ""
},
status : 200
});
connection.mockRespond(new Response(options));
});
// If this function is not automatically called in the component initialisation
component.getHomePageData();
tick();
//you can call expects on your component's properties now
expect(component.defaultFacilityId).toEqual("55303.0");
});
FakeAsync allows you to write tests in a more linear style so you no longer have to subscribe to the service function to write your expectations.
In a FakeAsync test function you can call tick() after a call where an asynchronous operation takes place to simulate a passage of time and then continue with the flow of your code.
You can read more about this here: https://angular.io/docs/ts/latest/testing/#!#fake-async
EDIT - Error Case
To test the error logic you can call mockError or set up an error response using mockRespond on your connection:
it('getHomePageData with ERROR- getHomePageData()', fakeAsync(() => {
backend.connections.subscribe((connection: MockConnection) => {
if (connection.request.url === 'http://192.168.61.158:9080/GetUserData') {
// mockError option
connection.mockError(new Error('Some error'));
// mockRespond option
connection.mockRespond(new Response(new ResponseOptions({
status: 404,
statusText: 'URL not Found',
})));
}
component.getHomePageData();
tick();
//you can call expects now
expect(connection.request.url).toEqual('http://192.168.61.158:9080/GetUserData');
expect(connection.request.method).toEqual(RequestMethod.Get);
expect(connection.request.headers.get('Content-Type')).toEqual('application/json');
expect('you can test your error logic here');
});
What we're doing inside the subscription is making sure that anytime the GetUserData endpoint is called within this test method it will return an error.
Because we test errors and successes separately in the success test there's no need to add the error related settings in the request options.
Are you using JSON data? Then you should probably use map() before using .subscribe().
.map((res:Response) => res.json())
Try organizing your code like this:
ngOnInit() {
this.getHomePageData();
}
getHomePageData() {
this.http.get('your.json')
.map((res:Response) => res.json())
.subscribe(
data => {
this.YourData = data
},
err => console.error(err),
() => console.log('ok')
);
}
Hope it helps,
Cheers

Resources