Browser Permissions Users Refuse
Test geolocation, clipboard, camera, and notifications when the user says no. A fixture that grants them all hides that path.
This post is part of the Playwright Essentials series. If you missed the previous post, read Part 12 — Which Browsers Actually Earn a Test Run first.
Introduction — The Suite Always Says Yes
The base fixture grants geolocation, clipboard, and notifications because one test needed a map. Every later test inherits the grant. The user who taps Block is a user you no longer have.
Permissions are part of the product. Refusal is the common branch.
Default to Denied
Leave the context alone. Grant a permission only inside the test that needs the allow path.
test('explains a denied location', async ({ page }) => {
await page.goto('/stores');
await expect(page.getByRole('status')).toHaveText('Location is off. Search by city.');
});
test('centres the map when location is allowed', async ({ context, page }) => {
await context.grantPermissions(['geolocation']);
await context.setGeolocation({ latitude: 52.23, longitude: 21.01 });
await page.goto('/stores');
await expect(page.getByRole('heading', { name: 'Stores near you' })).toBeVisible();
});
grantPermissions is per context. A grant in beforeEach is how the deny test disappears.
The same split applies to camera, microphone, clipboard-read, and notifications. One allow test, one deny test, for each feature that changes the screen when the answer is no.
What the Deny Path Must Do
- tell the user the feature is unavailable, in the page, not only in the browser prompt
- offer another way through: type a city, upload a file, copy a code by hand
- not throw an unhandled rejection that blanks the view
You cannot reliably assert the browser’s own prompt text across engines. Assert your UI after the permission is already denied. Playwright starts denied unless you grant. That is the setup you want.
WebKit Is Not Chromium Here
Safari is stricter about which permissions automation can set, and about clipboard and camera in particular. If the feature matters on iPhone, the deny test belongs in the @webkit slice from part 12. If grantPermissions is unsupported for that name, keep the deny test and test the allow path by hand on a device. Do not skip both.
Do Not “Fix” Refusal by Asking Again in a Loop
A test that reloads until a permission sticks is documenting a dark pattern. The product gets one prompt. After that, the in-page explanation is the behaviour.
Conclusion
Grant a permission in the test that studies the allow path. Leave every other test denied. Assert the screen you built for the user who said no.
Action for this week: Find one feature that calls geolocation, clipboard, or the camera. Add the deny test first. Move any global grant into the single allow test.
Next in the series: Part 14 — Files Users Actually Send.