Verifying a text on a dialog box with Cypress and Cucumber - cucumber

I'm trying to verify a text message on a dialog box using cypress and cucumber. The test cases are working perfectly fine when it's within "it function". Here is is the sample code :
it ('Verify if the Login is successful', function()
{
cy.visit('loginTest.html')
cy.get('#username').type('shahin')
cy.get('#password').type('tala')
cy.contains('Login').click()
cy.on('window:alert', (str) => {
expect(str).to.equal(`Login Successfully`)
})
})
However when i add the BDD keywords it looks like the function doesn't get evaluated at all. It works for When but not the Then scenario. I think it needs to be handled in Js in a different way. I have uploaded the cypress log as well. Below is the code :
When('I click on the login button', () => {
cy.contains('Login').click()
})
Then('Successful POP up message should be displayed', () => {
cy.on('window:alert', (str) => {
expect(str).to.equal(`Login Successfully`)
})
Cypress Log

The first thing is cy.on('window:alert'... is a passive event listener, it does not do anything until an event is emitted by the app.
This means you need to set it before the event is triggered (e.g Login click),
When('I click on the login button', () => {
cy.on('window:alert', ...something here...) // set up the event listener
cy.contains('Login').click() // action that triggers the event
})
If you do your expect() within the callback of the event listener it mucks up your BDD flow (Then() is redundant).
Use a stub to catch the event, and assert the stub properties inside Then().
let stub // declare outside so it's visible in both When and Then
When('I click on the login button', () => {
stub = cy.stub() // set stub here (must be inside a test)
cy.on('window:alert', stub) // capture call
cy.contains('Login').click()
})
Then('message is displayed', () => {
expect(stub).to.have.been.calledWith('Login Successful')
})
Why does it() work?
Essentially, with it() all the code is within one block vs two blocks for When() Then().
The async commands are queued for later exectution, but the synchronous cy.on() is executed immediately - even though it's the last line it gets executed first.
it('...', () => {
// Queued and executed (slightly) later
cy.visit('loginTest.html')
cy.get('#username').type('shahin')
cy.get('#password').type('tala')
cy.contains('Login').click()
// executed immediately (so actually first line to run)
cy.on('window:alert', (str) => {
expect(str).to.equal(`Login Successfully`)
})
})
The When() and Then() blocks are executed in sequence, so you don't get the same pattern as with it().

Related

Selenium Test Case not getting executed with Jest

I am working on setting up an automation test suite for an application using selenium and jest and it turns out that the console never reaches the inner body of the minimalist test case written below.
describe('When a user Opens Launchpad', () => {
test('It should be able to Navigate to Tasks Application without errors', async () => {
driver.get('http://localhost:4004/fiori.html').then(function () {
const temp = driver.findElement(By.xpath("li[#id='__tile11']"));
temp.then(function (element){
element.getAttribute("innerHTML");
expect(element.getText()).toBe("VT Dashboard");
})
});
}, 200000);
});
I looked online and tried multiple fixes like putting the driver.get() method above all these functions, making the test cases synchronous and using getText() instead of getAttribute() but none of them worked.
I either get an element not found error (The element actually exists when I check it on the chromium browser) or the test case executes successfully without reaching the expect statement in debug mode.
Bottomline is that driver.findElement() returns a promise instead of an element and would be great if I could get an element instead of promise.
Any help or correction here would be greatly appreciated.
If the function is async you should return the promise chain from that function or just use await keyword. So try following:
test('It should be able to Navigate to Tasks Application without errors', async () => {
await driver.get('http://localhost:4004/fiori.html');
const temp = await driver.findElement(By.xpath("li[#id='__tile11']"));
element.getAttribute("innerHTML");
expect(element.getText()).toBe("VT Dashboard");
}, 200000);
or
test('It should be able to Navigate to Tasks Application without errors', async () => {
return driver.get('http://localhost:4004/fiori.html').then(function () {
const temp = driver.findElement(By.xpath("li[#id='__tile11']"));
temp.then(function (element){
element.getAttribute("innerHTML");
expect(element.getText()).toBe("VT Dashboard");
})
});
}, 200000);

Passing data from server to html with Electron/Nodejs

I'm using preload and renderer js to pass data from html to server. I have a main window and I open another window (add window). I take data from add window and pass it to server. I receive the data on server, but I don't know how to send callback with data from server to main window html.
In preload I have:
contextBridge.exposeInMainWorld(
'windowControls',
{
add: (data)=> ipcRenderer.send('item:add',data),
received:(data)=> ipcRenderer.send('item:received',data)
In rendererAddwindow:
var input = document.getElementById("inputItem").value;
windowControls.add(input)
In app.js:
// Catch item:add
ipcMain.on('item:add',(e,item)=>{
console.log('item',item); // Here I can read item
mainWindow.webContents.on('did-finish-load',()=>{
mainWindow.webContents.send('item:received',item)
});
addWindow.close();
})
What should I write in rendererMain to get data as a callback in main window? The main renderer is executed at first run and not when callback is triggered (if I triggered callback with these lines at all).
The did-finish-load event is not what you are looking for. This event is fired once the webpage is loaded, it is emited only once if you stay on the same page.
You have 2 solutions to answer a message received in the main process.
Invoke the message instead of sending it
You should refer to the documentation to learn about invoking the message.
Here is the example from the documentation :
// Renderer process
ipcRenderer.invoke('some-name', someArgument).then((result) => {
// ...
})
// Main process
ipcMain.handle('some-name', async (event, someArgument) => {
const result = await doSomeWork(someArgument)
return result
})
Here is what it should look like in your example :
// Renderer process
ipcRenderer.invoke('item:add', item) // This sends the item to main process and wait for the answer
.then((data) => { // Callback triggered once the result comes back
console.log(data) // Do what you want with the data
})
// Main process
ipcMain.handle('item:add', async (event, item) => {
console.log(item)
return item // Or return whatever you want
})
Send a new message
This is not the best solution since it can become very complexe as the app grows. But you can send a new message from main to renderer :
// app.js file
ipcMain.on('item:add',(e,item)=>{
console.log({item})
if(yourWindow) { // It can throw an error if yourWindow is null or defined
yourWindow.webContents.send('item:received',item)
}
})
In app.js (when data is received from add window input):
// Catch item:add
ipcMain.on('item:add',(e,item)=>{
console.log('item',item); // Here I can read item
mainWindow.send('itemreceived',item)
addWindow.close();
})
In preload.js (outside contextBridge.exposeInMainWorld()):
const { contextBridge, ipcRenderer } = require('electron')
// Set up context bridge between the renderer process and the main process
contextBridge.exposeInMainWorld(
'windowControls',
{
close: () => ipcRenderer.send('windowControls:close'),
maximize: () => ipcRenderer.send('windowControls:maximize'),
minimize: () => ipcRenderer.send('windowControls:minimize'),
add: (data)=> ipcRenderer.send('item:add',data),
}
)
ipcRenderer.on('itemreceived',(event,message)=>{
console.log('item received message',message);
}
Similar example is here: https://gist.github.com/malept/3a8fcdc000fbd803d9a3d2b9f6944612

How to do callback in our component using react jest test cases

How can we do callback on success and failue cases for below lines of code for test coverage using jest
const handleService = () => {
window.domain.service("1321",'',onSuccess, onFailure)
}
const onSuccess = () => {
....update state values
}
const onFailure = () => {
....update state values
}
Something like this:
Spy on window.domain.service to gain access to the calls it receives. This will allow you to access the parameters of those calls which will be "1321",'',onSuccess, onFailure
Assign the function you wish to test to a variable
Invoke the function to execute the code in it (this will get you the coverage)
(Optional) assert that the callback functions behave correctly
Here is a snippet to help demonstrate
it('should run', () => {
// Some setup to create the function on the window, may not be needed if done elsewhere.
// Could be good to do this in a beforeEach and clean up in afterEach to avoid contaminating the window object
window.domain = {
service: () => {},
}
// Spy on the window.domain.service method.
// Provide a mock implementation if you don't want the real one to be called
const serviceSpy = jest.spyOn(window.domain, 'service');
executeYourCode();
// capture the arguments to the call
const [_arg1, _arg2, onSuccess, onFailure] = serviceSpy.mock.calls[0];
// execute the callbacks
onSuccess();
onFailure();
});

Why is the second Jest mock function never being called?

I am mocking navigator functions for simple clipboard functionality. Here is the relevant code:
// FUNCTION
/**
* Adds a click event to the button which will save a string to the navigator clipboard. Checks for
* clipboard permissions before copying.
*/
function loader(): void {
async function copyUrl(): Promise<void> {
const permission = await navigator.permissions.query({ name: "clipboard-write" });
if (permission.state == "granted" || permission.state == "prompt" ) {
await navigator.clipboard.writeText("the url");
} else {
console.error('Permission not supported');
}
}
const button = document.querySelector('button') as HTMLElement;
button.addEventListener('click', async () => {
await copyUrl();
});
}
// TEST
it('works', () => {
// mock navigator functions
Object.assign(navigator, {
permissions: {
query: jest.fn(async () => ({ state: "granted" }))
},
clipboard: {
writeText: jest.fn(async () => {})
}
});
// initialize DOM
document.body.innerHTML = '<button></button>';
loader(); // adds the event listener
// click the button!
const button = document.querySelector('button') as HTMLElement;
button.click();
expect(navigator.permissions.query).toHaveBeenCalledTimes(1);
expect(navigator.clipboard.writeText).toHaveBeenCalledWith('the url');
});
The test fails on expect(navigator.clipboard.writeText).toHaveBeenCalledWith('the url') with:
Expected: "the url" Number of calls: 0
Defeats the purpose of permissions, yes, but for the sake of debugging:
Try adding a clipboard call before permissions call like so?
// FUNCTION
// ...
async function copyUrl(): Promise<void> {
// add this
await navigator.clipboard.writeText('the url');
// keep the rest still
const permission = await navigator.permissions.query({ name: "clipboard-write" });
// ...
}
This fails on the first assertion now, expect(navigator.permissions.query).toHaveBeenCalledTimes(1) with
Expected number of calls: 1 Received number of calls: 0
With the addition above, I also changed the assertions to be:
expect(navigator.clipboard.writeText).toHaveBeenCalledWith('the url');
expect(navigator.clipboard.writeText).toHaveBeenCalledTimes(2);
expect(navigator.permissions.query).toHaveBeenCalledTimes(1);
... which failed on the second assertion because it expected 2 calls but only received 1.
I have been testing in a VSCode devcontainer and tried out the extension firsttris.vscode-jest-runner to debug the test. With breakpoints in the loader function, I'm able to see that every single line executes perfectly with my mockup but still fails at the end of debug.
I even changed the mock navigator.permissions.query function to return { state: 'denied' } instead. Both running and debugging, it did not satisfy the permission check and gave an error to the console as expected but the test still failed at expect(navigator.permissions.query).toHaveBeenCalledTimes(1) (with the added writeText call before it).
It seems to me that after the first call of a mock function, the others just don't work.
Am I missing something? Send help pls lol
EDITS
Using jest.spyOn as in this answer has the same issues.
Using an async test with an expect.assertions(n) assertion still produces the exact same issue.

Ajax testing with Mocha - Nodejs

I tried using Mocha to write tests for one of my application.
I can able to run different scenarios when page reloads.
Consider the below scenario
1) A user enters value in a text field "Username"
2) Clicks "Save" button
3) This will send ajax call to save user name and response might come back in 1 to 2 seconds
4) A message is shown after response is received
How can i implement test for above scenario?
NOTE : I tried the below code, but the browser isn't waiting at all
describe("Ajax test", function(){
before(function(){
return this.browser.field('save').click()
})
it("Tests save username", function(){
this.browser.wait(6000, function() {
//code to check if success message is shown in body
})
})
})
thanks,
Balan
There is a callback you can make in each test case, and you should wait for a response from the server before making this callback.
The pattern should be something like this:
// Test case. Notice the `done` param
it('Should make an async call', function(done){
// Make an async call, with a callback function
async_call(function(){
// Do whatever you need (test some values)
// Then call done
done();
});
});

Resources