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
})
})
})
Related
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 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);
});
});
I am struggling with implementing soft assertions in my Cypress test.
I need to convert all the assertions to soft assertions. The problem I encounter is that I cannot locate the element in the jsonAssertion. For example cy.get('span[class="h4"]') is the element and I need to assert that it contains some text. How can this be done with jsonAssertion.softAssert()?
This is my test:
describe('Load Validation Test', function(){
const jsonAssertion = require("soft-assert")
it('Load Validation Test', function(){
let url = Cypress.config().baseUrl
cy.visit(url+'activityTaskManagement')
cy.get('span[class="h4"]').should('contain.text','Manage Activities')
cy.get('button[ng-click="vm.addActivityTask();"]').should('be.visible')
cy.get('button[ng-click="vm.addActivityTaskBulk();"]').should('be.visible')
cy.get('input[placeholder="Activity Name"]').should('be.visible')
cy.get('div table[class="table table-striped b-t b-light table-nowrap"]').should('be.visible')
})
})
For soft-assert, see How can i use soft assertion in Cypress
As custom commands,
const jsonAssertion = require("soft-assert")
Cypress.Commands.add('softAssert', (actual, expected, message) => {
jsonAssertion.softAssert(actual, expected, message)
if (jsonAssertion.jsonDiffArray.length) {
jsonAssertion.jsonDiffArray.forEach(diff => {
const log = Cypress.log({
name: 'Soft assertion error',
displayName: 'softAssert',
message: diff.error.message
})
})
}
});
Cypress.Commands.add('softAssertAll', () => jsonAssertion.softAssertAll())
In the test
cy.get('span[class="h4"]').then($el=> {
const actual = $el.text()
cy.softAssert(actual, 'Manage Activities')
})
There's also package that proxies expect
const { proxy, flush } = require("#alfonso-presa/soft-assert");
const { expect } = require("chai");
const softExpect = proxy(expect);
cy.get('span[class="h4"]')
.invoke('text')
.should(actual => {
softExpect(actual).to.eq('Manage Activities')
})
flush() // Now fail the test if above fails
})
If you just want to assert that the element span[class="h4"] has some text you can do:
cy.get('span[class="h4"]').should('include.text','Manage Activities')
Using soft assert you can do something like this:
const jsonAssertion = require('soft-assert')
describe('Load Validation Test', function () {
it('Load Validation Test', function () {
let url = Cypress.config().baseUrl
cy.visit(url + 'activityTaskManagement')
cy.get('span[class="h4"]')
.invoke(text)
.then((text) => {
jsonAssertion.softContains(
text,
'Manage Activities',
'Some custom message'
)
})
cy.get('button[ng-click="vm.addActivityTask();"]').should('be.visible')
cy.get('button[ng-click="vm.addActivityTaskBulk();"]').should('be.visible')
cy.get('input[placeholder="Activity Name"]').should('be.visible')
cy.get(
'div table[class="table table-striped b-t b-light table-nowrap"]'
).should('be.visible')
})
})
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: '',
})
};
Works
Template.Hello.onRendered(function() {
this.autorun(() => {
console.log('sup');
});
});
Doesn't work.
Template.Hello.onRendered(() => {
this.autorun(() => {
console.log('sup');
});
});
The error is TypeError: _this.autorun is not a function.
Any ideas why using arrow notation gives us this error?
Arrow functions use lexical binding of this which means that this will be whatever it was when the function was created. This means that you unfortunately can't use it when creating functions on objects that use object properties such as the template.
A small example is something like:
o = {};
o.fn = () => console.log(this);
o.fn(); // not 'o'
o.fn = function () { console.log(this); }
o.fn(); // 'o'
.autorun is a method of the template so the functional binding of this is required.
There are times when the lexical binding of arrow functions are useful such as in the callback to autorun. In that case, you want this to remain the same as the outer scope. Otherwise you would have to bind it:
Template.Hello.onRendered(() => {
this.autorun(() => {
console.log(this); // the template
});
this.autorun(function () {
console.log(this); // the template
}.bind(this));
this.autorun(function () {
console.log(this); // the callback function
});
});