Unable to select item in cypress inside a frame - javascript

I have managed to log into a laboratory results system but I can't progress any further. My long term intention is to grab lab results for local incorporation into a medical record.
const getIframeBody = () => {
// get the iframe > document > body
// and retry until the body element is not empty
return cy
.get('frame[id="EclairMainFrame"]')
.its('0.contentDocument.body').should('not.be.empty')
// wraps "body" DOM element to allow
// chaining more Cypress commands, like ".find(...)"
// https://on.cypress.io/wrap
.then(cy.wrap)
}
describe('Medlab Test', () => {
it('Visits Eclair', () => {
cy.visit('https://cdr.medlabcentral.co.nz/Eclair/mvc')
cy.get('.login-field').eq(0).type('userid')
cy.get('.login-field').eq(1).type('passphrase{enter}')
cy.location('pathname').should('eq', '/Eclair/ClinicalWorkstation.aspx')
getIframeBody().find('.search-form-form-textbox')
})
})
This gets me logged in, but Cypress fails to find the input field to enter the Patient ID. I see the following error message:
Timed out retrying after 6000ms: Expected to find element:
.search-form-form-textbox, but never found it. Queried from element: <body>
The DOM at this point for that input field shows:
<input class="search-form-form-textbox Mandatory" id="PatAliasId" name="PatAliasId" type="text" value="" tabindex="4">
I've tried cy.get on the class cy.get('.search-form-form-textbox'), on the id cy.get('#PatAliasId'), and on class attribute cy.get('name=["PatAliasId"]') but all these attempts time out at 6 seconds.
What's the correct syntax for finding a dom element inside a frame?

To work with frames in Cypress you have to install a cypress plugin with the following command, then you can interact with elements inside the frame
npm install -D cypress-iframe
Reference URL
Cypress Frames
If you have done the above already, then load the frame first to find the required element
cy.frameLoaded(#frameId)
cy.iframe.find('#PatAliasId').type('abc')

In previous version of cypress, don't have any support for the iFrame. But in latest version cypress provided the support for iFrames.
Do work on cypress , we need to install cypress-iframe by using the below commands.
npm install -D cypress-iframe
Use this below code:
describe('Medlab Test', () => {
it('Visits Eclair', () => {
cy.visit('https://cdr.medlabcentral.co.nz/Eclair/mvc')
cy.frameLoaded('#frameId')
cy.iframe.find('#PatAliasId').type('Enter Your Input')
})
})

Related

How to click in a select element with several options with Cypress?

I have a problem in clicking in a select element using cypress.
This is the element to click:
And i receive this error.
cy.click() cannot be called on a <select> element. Use the cy.select() command instead to change the value.
This is my code:
cy.get('[name^=shopveg]').click()
After searching some people advise using the trigger command.
Changed the code to:
cy.get('[name^=shopveg]').trigger('click')
The step pass in the cypress execution but the click was not executed.
As the message says, .select() is the command to use
cy.get('[name^=shopveg]').select('Bananas')
That's because <select> behavior is implemented by a web component (see slot tag), not javascript, so there's no click handler available.
Given the select looks like a "special" implementation, i.e a web component with slots, you may need to click it open to see the option values (lazy loading).
If so, try with cypress-real-events plugin
Install
npm install cypress-real-events
// or
yarn add cypress-real-events
In /cypress/suport/e2e.js
import "cypress-real-events";
Test
cy.get('[name^=shopveg]')
.should('have.value', '1') // confirm initial value
.realClick() // click open
cy.contains('option', 'Batatas') // this option exists
cy.contains('option', 'Arroz') // this option exists
cy.contains('option', 'Bananas') // this option exists
// etc
cy.get('[name^=shopveg]')
.select('Bananas') // select new option
.should('have.value', '3') // confirm new value
To validate the values in the select menu, you can iterate through them with cy.each().
const options = [ "Batatas", "Arroz", "Bananas", "Tomates", "Macaz" ];
cy.get('[name^=shopveg]').find('option').each(($el, index) => {
cy.wrap($el).should('have.text', options[index]);
});
As #Grainger answered, you can then use cy.select() to pick a value.

Cypress - element is detached from the DOM error

I tested our (nearly all of the components are created by DevExtreme) web application but I have a strange re-rendering problem.
I posted a picture of the error message. As you can see the "element exists" and "element is visible" assertions both pass. The next action command click, type, clear sometimes gives me this error.
I watched the network but there are no suspicious API requests.
How can I fix it?
cy.get("div.c-title.pe-2.me-2.active")
.parent()
.find("[name='Property Unsafe']")
.parent()
.find(".dx-item-content")
.contains("Yes")
.scrollIntoView()
.should("be.visible")
.should("be.exist")
.click();
You can see which components are I working on it. (I get similar errors frequently from every components not just dropdown or text input)
Hello, the issue is still the same. Not working.
As you can see the latest updates here: I used Cypress.dom.isAttached($el) I re-queried until the element was attached into dom with Cypress recurse library. Still the result same.
recurse(
() =>
cy.get(
"#txtErrormeter_number > .dx-texteditor-container > .dx-texteditor-input-container > .dx-texteditor-input"
),
($el) => Cypress.dom.isAttached($el),
{
debugLog: true,
log: true,
limit: 50, // max number of iterations
timeout: 10000, // time limit in ms
delay: 250, // delay before next iteration, ms
}
).then(() => {
cy.get(
"#txtErrormeter_number > .dx-texteditor-container > .dx-texteditor-input-container > .dx-texteditor-input"
).then(($el) => {
if (Cypress.dom.isAttached($el)) {
cy.log("aattacchheeed");
cy.wrap($el)
.clear({ force: true })
.type(variables.meterId, { force: true });
} else {
cy.log("NOOOOOOTTTTTTTTTT aattacchheeed");
}
});
});
The Cypress log is saying you have a .click() two lines above the scrollIntoView(), but it is not in the posted test code.
You should split the long command after that first click, it is most likely causing the re-render.
Whatever you selected above click #1 should be selected again after it.
I can't tell what the context is, only a mention of DevExtreme. If you provide more information about the control (select, input, dropdown) it would be more useful.
Also the correct check for attachment is isAttached() not visible or exist.
.then(($el) => {
expect(Cypress.dom.isAttached($el).to.eq(true)
})

Cypress testing a Material-UI datepicker is not working on Github actions

We have a strange behavior when running our cypress tests in a github action. MUI datepicker the datepicker is in readonly mode and we can't enter any date (it's fine in other environments).
Error in Cypress
CypressError: Timed out retrying after 4000ms: cy.clear() failed because this element is readonly:
<input aria-invalid="false" readonly="" type="text" aria-readonly="true" aria-label="Choose date" class="MuiOutlinedInput-input MuiInputBase-input css-1x5jdmq" value="">
Visually looks the date picker does not have any button (something is going on) :
The console logs show no error or warning
On other environments, windows/linux, the tests work fine, even though we launch the test in headless mode (all desktops with a UI). The MUI datepicker looks as nice as in MUI documentation (link).
Github action looks like :
on:
workflow_dispatch:
defaults:
run:
working-directory: ic3-test
jobs:
build:
runs-on: ubuntu-latest
container: cypress/included:8.6.0
steps:
- uses: actions/checkout#v2
- uses: actions/setup-node#v2
with:
node-version: '16'
- name: Install dependencies
run: npm install
working-directory: ic3-test
- name: Cypress run with env
uses: cypress-io/github-action#v2
with:
# headless: true
browser: chrome
record: true
working-directory: ic3-test
The Cypress line that generates the error :
cy.getWidget(widgetId). // this is getting a div with wid = widgetId , works fine
.find("input.MuiInputBase-input")
.clear()
.type(date). // date is a string
Some hints are welcomed
We had the same error when running cypress test in azure devops pipelines. And I think its the same reason, looking at your screenshot of the date picker without any button.
The input which was giving us the error was #mui/lab/DatePicker.
We found that this component is rendering as #mui/lab/MobileDatePicker when we ran the cypress tests in azure devops pipelines. It's explained here: docs.
That version not accept direct text input, but opens a dialog to pick/input date, therefore cypress test fails when trying to type into the input.
Our solution was to use #mui/lab/DesktopDatePicker directly.
The reason behind this is that Material UI renders the MobileDatePicker component, since the query #media (pointer: fine) doesn't match on the headless Chrome used by our Github Actions Workflow. The mobile component only has readonly inputs, therefore it can't be cleared or typed into with .type() and .clear() (as opposed to the DesktopDatePicker component, which has typable and clearable inputs).
Since we don't want to remove the MobileDatePicker component, we've created a custom command so it checks if the mobile date picker is currently being rendered. If on mobile, the test opens the date picker, clicks on the edit button, so the mobile input view is opened.
And in that input view, the input field is not readonly anymore. Using that command, no matter if desktop or mobile, the input field can be cleared and typed into.
Cypress.Commands.add(
'chooseDatePicker',
(selector: string, value: string) => {
cy.get('body')
.then(($body) => {
const mobilePickerSelector = `${selector} input[readonly]`;
const isMobile = $body.find(mobilePickerSelector).length > 0;
if (isMobile) {
// The MobileDatePicker component has readonly inputs and needs to
// be opened and clicked on edit so its inputs can be edited
cy.get(mobilePickerSelector)
.click();
cy.get('[role="dialog"] [aria-label="calendar view is open, go to text input view"]')
.click();
cy.get(`[role="dialog"] ${selector}`)
.find('input')
.clear()
.type(value);
cy.contains('[role="dialog"] button', 'OK')
.click();
} else {
cy.get(selector)
.find('input')
.clear()
.type(value);
}
});
},
);
// Usage:
const datePickerValue = '2021-01-03';
cy.chooseDatePicker('[data-testid="my-datepicker"]', datePickerValue);
Since I haven't seen all the code, I will try to comment as specific as I can, I would like you to review few topics.
1- Examine the properties in the transformed code. Make sure a Property such as helperText={null} is should not set.
2- You might need to install polyfills. For instance for the popper.js (transitive dependency). Although MUI claims that it is (polly) not needed. Technology is advancing every day and there may be changes that they cannot catch.
3- Be sure working right mode. Even test it with Jest. Such window.matchMedia.
Cypress.Commands.add('setDateField', ({ date, label }) => {
//open the datepicker dialog if is mobile
cy.contains(label).siblings('div').click()
cy.get('body').then(($body) => {
if ($body.find('[role=dialog]').length) {
cy.get('[data-testid=PenIcon]').click()
cy.get('[role=dialog]').contains(label).type(date)
cy.get('[role=dialog]').contains('Confirmar').click()
return
}
cy.contains(label).siblings('div').type(date)
})
})

unable to access html element using cypress

I am trying to test the login functionalities using cypress, but for some reason I am unable to access the input text-box.
It shows Timed out retrying after 4000ms: Expected to find element: runner container, but never found it.
describe("User authentication", () => {
beforeEach(() => {
cy.visit("https://lmflf.com");
});
it("it takes to the correct page", () => {
cy.get('[data-field=password]')
});
});
I could see a shadow DOM in your webpage and in that case you have to use .shadow()(Cypress Docs). Your code would look something like:
cy.get('view-login').shadow().find('input[data-field="username"]').type('username', {force: true})
cy.get('view-login').shadow().find('input[data-field="password"]').type('password', {force: true})
cy.get('view-login').shadow().find('input[value="personal"]').click()
cy.get('view-login').shadow().find('.ViewLogin__button').click()

Is there any way to hide a log in cypress?

I'd like to know if there's a way to not show a log in Cypress, for example.
If I make a test to log into any application, when it types the password:
cy.get(#id).type(password)
and the test is executed, the password value appears in the log.
Is there any way of stopping this?
as per docs, this should work:
cy.get("#id").type( password, { log: false });
If you want to hide the command log sidebar altogether then set the ENV CYPRESS_NO_COMMAND_LOG to 1 before running Cypress this way:
CYPRESS_NO_COMMAND_LOG=1 cypress run
Documentation
It works for the Cypress v10.9.0
With some older versions (8.7.0, 9.6.0) it may not work.
CYPRESS_NO_COMMAND_LOG=1 leaves faulty empty space
fix: respect CYPRESS_NO_COMMAND_LOG in env
We can hide the details of each step inside cy.getIframeBody code by disabling internal commands' logging.
Cypress.Commands.add('getIframeBody', () => {
// get the iframe > document > body
// and retry until the body element is not empty
cy.log('getIframeBody')
return cy
.get('iframe[data-cy="the-frame"]', { log: false })
.its('0.contentDocument.body', { log: false }).should('not.be.empty')
// wraps "body" DOM element to allow
// chaining more Cypress commands, like ".find(...)"
// https://on.cypress.io/wrap
.then((body) => cy.wrap(body, { log: false }))
})

Categories