Controlling Browser Permissions in Cypress End-to-End Tests
I am excited to release a new open source package cypress-browser-permissions. 🎉 You can view it on GitHub at kamranayub/cypress-browser-permissions.
This package solves a real need when testing more sophisticated applications when using Cypress, the end-to-end testing framework. It helps control the permission level of various browser features such as:
- Desktop Notifications
- Geolocation
- Images
- Camera
- Microphone
- etc.
How to Use It
To get started, you'll need to install the package and you'll need Cypress installed already.
npm i cypress cypress-browser-permissions --save-dev
If this is your first time installing Cypress, you'll need to run it once to generate a project structure:
npx cypress open
Then, you need to initialize the plugin to hook it into Cypress' plugin pipeline. In cypress/plugins/index.js
, modify it as follows:
+ const { cypressBrowserPermissionsPlugin } = require('cypress-browser-permissions')
/**
* @type {Cypress.PluginConfig}
*/
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
+ config = cypressBrowserPermissionsPlugin(on, config);
+ return config;
};
Now you will have the ability to control various permissions for Chrome, Edge, and Firefox using Cypress environment variables.
For example, if you want to just set permissions for your project you can do so in cypress.json
:
{
"env": {
"browserPermissions": {
"notifications": "allow",
"geolocation": "allow"
}
}
}
The plugin will read the permission settings and apply them when launching the browser. It will also reset between launches since modifying the browser profile is persisted across sessions.
You can read more about supported permissions and values in the README.
Writing an End-to-End Notification Test
So let's try it out! Once I finish my Testing Progressive Web Apps Pluralsight course, it will come with an open source sample app. In the meantime, we can write a basic test to see if permissions are working. This same test is included in the repo.
First, we have an HTML file that uses window.Notification
to display a desktop notification:
cypress/html/notification.html
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cypress Notification Test</title>
</head>
<body>
<script type="text/javascript">
const n = new window.Notification('test', { body: 'This is a test!' })
n.addEventListener('show', (e) => {
window.__CypressNotificationShown = e;
})
</script>
</body>
</html>
You can learn more about how the Notification API works but what we are doing is immediately triggering a notification. Once the browser shows the toast, it triggers the show
event on the Notification
instance. Since Cypress is awesome and we can hook directly into the window
object, we set a callback value globally that we can then inspect/wait for in our test.
If you have a blank Cypress project you do not even need a server as Cypress will automatically host the root of the project when there is no other configuration.
Save the notification.html
file under cypress/html
and then we can visit that page in the test.
We can create a test suite in cypress/integration
:
cypress/integration/notification.test.js
import { isPermissionAllowed } from 'cypress-browser-permissions';
describe("notifications", () => {
it("should be enabled", () => {
expect(isPermissionAllowed("notifications")).to.be.true;
})
// Only test notification showing in "headed" browsers, which also
// works in CI :tada:
Cypress.browser.isHeaded && it("should display desktop notification", () => {
// Visit the page we created previously
cy.visit('/cypress/html/notification.html')
// Wait for the window callback to populate with the event data
cy.window().its('__CypressNotificationShown').should('exist');
})
})
Now we can run our tests:
npx cypress open
That's all! If browserPermissions.notifications
is set to allow
then our test should pass:
And a notification will be shown!
How It Works
In Cypress, you have control over the launch preferences for browsers, so the magic lies in what preferences to pass to each browser.
This topic is not heavily documented as evidenced by this open issue in the Cypress repo I came across while researching this. It has been open since 2018 with no one mentioning the ability to control launch preferences.
Thanks to BrowserStack for documenting some of these permissions as well as these StackOverflow posts:
- Selenium + Python Allow Firefox Notifications
- How to allow or deny notification geo-location microphone camera pop up
I was able to piece together the information needed to tackle this with a Cypress plugin. Since each browser family uses different preferences, I thought it would be best to abstract it.
What's Next?
My hope is that this package is actually short-lived and the Cypress team can incorporate these permission settings into the core of the product, since it's such an important feature especially when testing new, modern APIs.
There will be a full sample of using Cypress with this plugin (as well as other black magicks such as bypassing service workers and more!) in my Testing Progressive Web Apps course soon on Pluralsight. It should be released in August, you can follow me there to get notified when it releases. The sample app will be open source on GitHub so you'll be able to reference it 👍