cypress
cypress copied to clipboard
Any way to force CSS media queries to detect mobile
First of all THANK YOU for excellent tool. We (front end developers) have been waiting years for this tool.
There is just one small issue. Using cy.viewport('type-of-mobile-phone') makes testing iframe smaller, but CSS media queries and window.screen.width, height remains the same (since it resolves actual size of screen.
Is there any possible way how to fix this? I was doing some research, and only idea I have is to implement somehow Google Dev Tools protocol, that is able to force Chrome to fake anything.
https://chromedevtools.github.io/devtools-protocol/
Related comment on devtools protocol: https://github.com/cypress-io/cypress/issues/311#issuecomment-339824191
That part of the debugger protocol would only work for Chrome and is not cross browser compatible. If we exposed that, it would either have to be restricted to Chrome only.
Can you provide me an example of CSS media queries not working? Those should be bound to the window, not the screen.
I understand that the screen API's don't account for the iframe - but to work around this is fairly trivial, you create wrapper functions around those values and use cy.stub to force them to return what it is you want returned. Then your application reacts as if the screen had those dimensions.
Having some code in regards to what you're doing with screen would also be helpful.
Media query is
@media only screen and ( max-device-width: 736px ) {
...
}
and it is recommended detection of mobile phone. I think cypress works as expected, since media queries are bound to device, not screen.
Yeah I can't think of a way around this other than to hide the Cypress UI and then change the width and height of the actual browser window. It's actually possible to do - those API's are exposed to us - but probably not worth the effort.
No problem will find a way
Just now I have tested Facebook, Gmail and Twitter and all of them use media queries based on device-width not a browser window, and by this they decide if they will use mobile or desktop layout. Therefore I think, that forcing cy.viewport to fake device width would be nice addition. I know that this task is very, very, very complicated but trust me, that can be useful as hell. Even when limited to Chrome.
Agreed. This is possible to do and we will do this - even if its just for Chrome.
This belongs in the same category as "native events", which is something we can implement. @chrisbreiding is scheduled to start working on cross browser support in December and that's when we'll switch everything over.
We can do this by using the underlying debugger protocol as opposed to the extensions which is how we currently automate chrome. Once we do that, we'll be able to fire any kind of native event, but also expose and even lower level API that would enable you to take advantage of anything that the debugger protocol offers.
If you're curious these other issues talk more detail about the switchover:
- https://github.com/cypress-io/cypress/issues/832
- https://github.com/cypress-io/cypress/issues/311#issuecomment-339824191
- https://github.com/cypress-io/cypress/issues/310
Thanx a lot
Any updates on this? I'm currently running into issues trying to properly spoof mobile devices and its breaking my tests.
Hi @thebluick, we still have this on our roadmap, but no defined deadline or work done for this issue at the moment.
With the default 1000px viewport, window.matchMedia('(max-width: 511px)') returns matches: true, which is clearly wrong. (You can put any width there - it will always match.) In the console after the tests run, it works as expected.
max-device-width also doesn't seem to relate to the viewport setting and is also deprecated
https://developer.mozilla.org/en-US/docs/Web/CSS/@media/device-width
The larger issue I am having dealing with this is getting some sort of weird hybrid where the window size is 1280x720 but the rendering is showing the mobile/responsive view. This is breaking tests since we have a different layout in mobile. Is there no way to preserve viewport size and/or reset it manually?
A bit of a crude solution that worked for me was swapping min-device-width for min-width at runtime during the test. It's a bit of a hack and not for all use-cases, but it works.
Cypress.Commands.add('swapDeviceWidth', () => {
cy.document().then(doc=>{
let replaced = 0
Array.from(doc.styleSheets).forEach(sheet => {
try {
Array.from(sheet.cssRules).forEach((rule, index) => {
const {cssText} = rule
const regexQuery = /(\(\s*)(min|max)-device-(width|height)(\s*:)/
const hasDeviceWidth = cssText.match(regexQuery)
if (hasDeviceWidth) {
const newRule = cssText.replace(regexQuery, '$1$2-$3$4')
sheet.removeRule(index)
sheet.insertRule(newRule, index)
replaced++
}
})
}catch(err){/* prevent InvalidAccessError on external sources*/}
})
cy.log(`Replaced ${replaced} -device- rules`)
})
})
This is not just about resolution, there's also these things to detect touch devices:
@media only screen and (hover: none) and (pointer: coarse)
In this issue on the Material-UI library and this Stackoverflow question it is discovered that Cypress tests on headless chrome with Material UI's DatePicker component fail, if they use type() and clear() on the DatePicker.
The reason behind this is that Material UI renders the MobileDatePicker component, since the query @media (pointer: fine) doesn't match (similar to the query of @waterplea). 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).
As far as I know, there is no way for Cypress to force such a media query to match, so this is a feature that would be nice.
Any updates on this? Would love to be able to set pointer media query in addition to viewport size in the cypress config.
Issue is also the Material Date picker as mentioned by @pganster
+1 having the ability to set pointer/ other MediaQuery params is much needed to automate mobile use cases. Please share if there are any workarounds. Thanks!
MUI X pickers detects mobile based on touch, and the lack of feature for this prevents us from visual testing these components.
Running into the same with the latest MUI X pickers too. If I find a solution will update here accordingly.
For those running into this issue, I found a "fix"/work-around. MUI X date pickers have a prop desktopModeMediaQuery as detailed here:
https://mui.com/x/api/date-pickers/date-picker/
It has a default value of '@media (pointer: fine)' which results in the issue pertaining to this thread. My fix is to make this dependent on screen size rather then pointer: fine so cypress viewport changes can effectively render the two different versions accurately. Really I think the fix should be a way to mock pointer: file on Cypress but I had no luck in doing that in a clean way.
My specific solution was to provide a default prop to my MUI theme with the given media query:
MuiDatePicker: {
defaultProps: {
desktopModeMediaQuery: `(min-width: ${breakpoints.md}px)`,
},
},
```
This issue has not had any activity in 180 days. Cypress evolves quickly and the reported behavior should be tested on the latest version of Cypress to verify the behavior is still occurring. It will be closed in 14 days if no updates are provided.
This issue has been closed due to inactivity.
This issue shouldn't be closed, because it's still actual.
This issue has not had any activity in 180 days. Cypress evolves quickly and the reported behavior should be tested on the latest version of Cypress to verify the behavior is still occurring. It will be closed in 14 days if no updates are provided.