How should someone test a button that evokes `showSaveFilePicker` using Cypress? - cypress

I'm trying to test a web text editor that saves and opens files from the local system. I'm using Cypress v11.2.0 with Chrome v107.
The file operations use the File System Access API through the browser-fs-access library.
I'm unable to test any of the file operations like save, for example. When the underline system function showSaveFilePicker is called, the test throws an error.
This is the test code:
it("'new' creates and links to an empty file", () => {
cy.visit("/");
cy.get("#new").click();
});
Here is the error image:
The operation is working fine in the app.
My question is: how should someone test a button that evokes showSaveFilePicker using Cypress?

It will work with plugin library cypress-real-events
import 'cypress-real-events'
it("'new' creates and links to an empty file", () => {
cy.visit('https://googlechromelabs.github.io/browser-fs-access/demo/');
cy.contains("button", 'Save Image File')
.realClick();
});
Stubbing
Although, the problem is what to do next? The test can't interact with the live popup.
I guess stub the call as per example here Window confirm popup.
But that doesn't need cypress-real-events, since the dialog is not actually called.
it("'new' creates and links to an empty file", () => {
cy.visit('https://googlechromelabs.github.io/browser-fs-access/demo/');
cy.window().then((win) =>
cy.stub(win, 'showSaveFilePicker').as('showSaveFilePicker').returns(true),
)
cy.contains("button", 'Save Image File')
.click();
cy.get('#showSaveFilePicker')
.should('have.been.calledOnce')
.invoke('restore')
});

Related

How to get the URL of a type 'submit' button during Cypress test?

Below is a submit button on the page I am trying to test.
When you click this button, a pop-up window is displayed. The URL of this pop-up is https://login.microsoftonline.com/........etc.
This sign in uses SSO, but we are having difficulty bypassing the sign-in process using requests.
So we are instead trying to capture the URL of the pop-up during the test.
I have seen examples where people retrieve the href attribute of a button. However, as you can see above, there is no href on this button.
I've searched the HTML for a form element too, but can't find that.
I'm just wondering, is there a way I can get the URL of the pop-up window that clicking the above button generates?
To catch the URL, try adding an intercept before the click
cy.intercept('POST', '*').as('submit')
cy.get('button').click()
cy.wait('#submit').then(interception => {
console.log(interception.request.url)
})
Note this is debugging code only to help find the URL. Don't use it in a long-term test.
Additional notes:
I'm assuming 'POST' as it's most common for submit, but may need 'GET' instead.
using '*' will catch anything, so you may catch so stray requests from the page load with the first cy.wait('#submit'). If so, just add more cy.wait('#submit') or a long cy.wait() before the click.
The new tab is likely to be trigger via javascript. If it is using [window.open][1] the you can stub it to open in the same ta
cy.window().then(win => {
cy.stub(win, 'open').callsFake((url, target) => {
expect(target).to.be.undefined
// call the original `win.open` method
// but pass the `_self` argument
return win.open.wrappedMethod.call(win, url, '_self')
}).as('open')
})
cy.get('a').click()
cy.get('#open').should('have.been.calledOnceWithExactly', 'url')
})
[1]: https://glebbahmutov.com/blog/cypress-tips-and-tricks/#deal-with-windowopen

Cypress test runner not rendering Blockly categories

I have a React web app which uses Blockly that I'm currently trying to write automated tests for using the Cypress framework.
Cypress works pretty well for the basic process of signing on, but starts behaving inconsistently once Blockly is supposed to load.
About half the time, the entire Blockly portion of the app doesn't show up at all in the Cypress viewport. Sometimes this shows up, sometimes it doesn't, and I'm unsure what causes it or how to really reproduce it, it seems to be random.
Here is how it looks when it loads properly
Here is how it looks when it doesn't load properly
At first, I thought that the reason it didn't work is because the resources for Blockly hadn't loaded, and Cypress was trying to access resources that didn't exist.
To work around this, I added a delay, using cy.wait(). I tried anywhere from 1s-10s, but the delay doesn't seem to affect anything, no matter how long the delay is, it doesn't seem to impact if the Blockly portion of the app loads properly or not.
Here is the code for the portion of the Cypress test file used:
it('Sign in with created profile', () => {
cy.visit('localhost:3000/');
cy.get('input[name="email"]')
.type('test123#test.com').should('have.value', 'test123#test.com');
cy.get('input[name="password"]')
.type('testtest').should('have.value', 'testtest');
cy.get('button[type="submit"]').click();
});
it('Open created project', () => {
cy.get('div[class="project-container"]').contains('test project').click();
});
it('Drop 1+1 block into grid', () => { //2s delay
cy.wait(2000).then((prom) => {
cy.get('div[class="blocklyTreeRow"]').contains('Math').click({ force: true });
});
});
It works perfectly, until just after the 'Open created project' part of the test is run, then it's a hit or miss if the Blockly part of the app shows up. Refer to the images above for possible scenarios that happen.
Please check you are not trying to automate iframe because cypress do not support iframe
Iframe opened Question :
https://github.com/cypress-io/cypress/issues/136
Else :
Try to use Aliased.
// Wait for the route aliased as 'getAccount' to respond
// without changing or stubbing its response
cy.server()
cy.route('/accounts/*').as('getAccount')
cy.visit('/accounts/123')
cy.wait('#getAccount').then((xhr) => {
// we can now access the low level xhr
// that contains the request body,
// response body, status, etc
})
More documentation available here :
https://docs.cypress.io/api/commands/wait.html#Alias

Custom child command in cypress doesn't perform click

Background:
I'm writing test automation for a React web application, using Cypress. In the application I have a dialog box in which there are elements I need to click. When I try to click any of these elements normally, Cypress gives me an error that the element in not visible because its content is being clipped by one of its parent elements, which has a CSS property of overflow: 'hidden', 'scroll' or 'auto'. Because these DOM elements are generated by some 3rd party React components, I cannot change this, and the only way I can work-around it is to use {force:true} in the click command.
The problem:
Because I have few of these elements and in order to keep the DRY principle, I wanted to create a custom child command named forceClick that simply wraps subject.click({force:true}). However, for some reason, when I do that, Cypress does not perform the click command at all!
Note: For debugging purposes I added a cy.log command to the custom command as well, and strangely enough, I see that this log command is executed and only the click command doesn't.
Here's the code:
Cypress.Commands.add('forceClick', {prevSubject:'element'}, subject => {
cy.log('forceClick was called!');
subject.click({force:true})});
And inside my test I have the following line:
cy.get("[data-test='panel-VALUES']").forceClick();
Note that if I change it to the following line, it works as expected:
cy.get("[data-test='panel-VALUES']").click({force:true});
Any idea why the click command isn't executed by the forceClick custom command?
You are almost there, you just missed that you have to wrap the subject if you want to work with it.
Cypress.Commands.add('forceClick', {prevSubject: 'element'}, (subject, options) => {
// wrap the existing subject and do something with it
cy.wrap(subject).click({force:true})
})
I never saw a solution with subject.click({force:true}), I'm not saying it won't work, but I just never saw it before. What works anyway is this:
Custom command:
Cypress.Commands.add('forceClick', {prevSubject:'element'}, subject => {
cy.log('forceClick was called!');
cy.get(subject)
.click({force:true})});
}
Test step:
cy.forceClick('[data-test="panel-VALUES"]');
If you only use the forceClick you could even shorten it further to this:
Custom command:
Cypress.Commands.add('forceClick', {prevSubject:'element'}, subject => {
cy.log('forceClick was called!');
cy.get(`[data-test=${subject}]`)
.click({force:true})});
}
Test step:
cy.forceClick('panel-VALUES');

How to verify element displays in new window after clicking a link on the main window

I am using Cypress to click a link on the Homepage which opens the respective page in the new window. I am not able to identify any element on this page. I am doing this to verify that the click opens the correct page.
I saw the link: Access a new window - cypress.io which didn't help much to answer the problem.
Please suggest if there is some way to test this.
I have tried few things like:
cy.window().contains('.div.trItem')
cy.window().its('.trValue).should('eq','SomeHeading')
cy.url().should('include', '/theLink1.html/')
Expected:
- Clicking link open the correct page in new window
- Identify URL in new window includes some text
- Certain text displays on the new window
First of all, you can't access to another tab or window with Cypress. Consider to separate your test cases. For example, in one test you could check that a element contains href attribute with expected url and target attribute with _blank.
Like this:
it('contains valid a element', () => {
cy.visit('https://example.cypress.io/')
cy.contains('Cypress.io').should('have.attr', 'href', 'https://www.cypress.io').should('have.attr', 'target', '_blank')
})
And in second test check that your other page contains expected text.

Programmatically invoking a button with CKEditor 4

Hello CKEditor experts,
Can I use a javascript-code (in-page) to invoke a button and dialog of the CKEditor?
I am trying to bring back the usage of the "anchor" button into our CryptPad collaborative suite. To do so, I wish to write an integration test that invokes the "anchor" button then check that the exported content indeed includes the expected <a name="..."> element. Our tests are actually scripts running inside the page (and invoked by selenium). What function could I invoke, as part of the JS page, to invoke that button or invoke exactly the same content addition as the invocation of the button does?
thanks in advance.
Usually buttons, have defined commands. If you don't know what command is bound to button you want to invoke, then you can find it:
var editor = CKEDITOR.insances[ instanceName ];
console.log( editor.ui.get( 'Anchor' ).command ) // 'anchor'
editor.execCommand( 'anchor' ) // Dialog opens
Once we know our command, testing code would like like:
editor.on( 'dialogShow', function( evt ) {
evt.data // Dialog instance
// All code goes here
} );
editor.execCommand( 'anchor' );
Visit docs for more detailed informations on dialog methods, which might help you with proper testing.
https://docs.ckeditor.com/ckeditor4/latest/api/CKEDITOR_dialog.html

Resources