Skip to content

Commit 4a29dfe

Browse files
PoC test
1 parent dd1a57b commit 4a29dfe

File tree

1 file changed

+138
-0
lines changed

1 file changed

+138
-0
lines changed

injected/integration-test/web-compat.spec.js

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,144 @@ test.describe('Permissions API', () => {
277277
});
278278
});
279279

280+
test.describe('Permissions API - when present', () => {
281+
function checkForPermissions() {
282+
return !!window.navigator.permissions;
283+
}
284+
285+
test.describe('disabled feature', () => {
286+
test('should not modify existing permissions API', async ({ page }) => {
287+
await gotoAndWait(page, '/blank.html', { site: { enabledFeatures: [] } });
288+
const hasPermissions = await page.evaluate(checkForPermissions);
289+
expect(hasPermissions).toEqual(true);
290+
291+
// Test that the original API behavior is preserved
292+
const originalQuery = await page.evaluate(() => {
293+
return window.navigator.permissions.query;
294+
});
295+
expect(typeof originalQuery).toBe('function');
296+
});
297+
});
298+
299+
test.describe('enabled feature', () => {
300+
/**
301+
* @param {import("@playwright/test").Page} page
302+
*/
303+
async function before(page) {
304+
await gotoAndWait(page, '/blank.html', {
305+
site: {
306+
enabledFeatures: ['webCompat'],
307+
},
308+
featureSettings: {
309+
webCompat: {
310+
permissionsPresent: {
311+
state: 'enabled',
312+
},
313+
permissions: {
314+
state: 'enabled',
315+
supportedPermissions: {
316+
geolocation: {},
317+
push: {
318+
name: 'notifications',
319+
},
320+
camera: {
321+
name: 'video_capture',
322+
native: true,
323+
},
324+
},
325+
},
326+
},
327+
},
328+
});
329+
}
330+
331+
/**
332+
* @param {import("@playwright/test").Page} page
333+
* @param {any} name
334+
* @return {Promise<{result: any, message: *}>}
335+
*/
336+
async function checkPermission(page, name) {
337+
const payload = `window.navigator.permissions.query(${JSON.stringify({ name })})`;
338+
const result = await page.evaluate(payload).catch((e) => {
339+
return { threw: e };
340+
});
341+
const message = await page.evaluate(() => {
342+
return globalThis.shareReq;
343+
});
344+
return { result, message };
345+
}
346+
347+
test('should preserve existing permissions API', async ({ page }) => {
348+
await before(page);
349+
const hasPermissions = await page.evaluate(checkForPermissions);
350+
expect(hasPermissions).toEqual(true);
351+
});
352+
353+
test('should fall through to original API for non-native permissions', async ({ page }) => {
354+
await before(page);
355+
const { result } = await checkPermission(page, 'geolocation');
356+
// Should use original API behavior, not our custom implementation
357+
expect(result).toBeDefined();
358+
// The result should be a native PermissionStatus, not our custom one
359+
expect(result.constructor.name).toBe('PermissionStatus');
360+
});
361+
362+
test('should fall through to original API for unsupported permissions', async ({ page }) => {
363+
await before(page);
364+
const { result } = await checkPermission(page, 'notexistent');
365+
// Should use original API behavior for validation
366+
expect(result.threw).not.toBeUndefined();
367+
});
368+
369+
test('should intercept native permissions and return custom result', async ({ page }) => {
370+
await before(page);
371+
// Fake result from native
372+
await page.evaluate(() => {
373+
globalThis.cssMessaging.impl.request = (req) => {
374+
globalThis.shareReq = req;
375+
return Promise.resolve({ state: 'granted' });
376+
};
377+
});
378+
const { result, message } = await checkPermission(page, 'camera');
379+
expect(result).toMatchObject({ name: 'video_capture', state: 'granted' });
380+
expect(message).toMatchObject({ featureName: 'webCompat', method: 'permissionsQuery', params: { name: 'camera' } });
381+
});
382+
383+
test('should fall through to original API when native messaging fails', async ({ page }) => {
384+
await before(page);
385+
await page.evaluate(() => {
386+
globalThis.cssMessaging.impl.request = (message) => {
387+
globalThis.shareReq = message;
388+
return Promise.reject(new Error('something wrong'));
389+
};
390+
});
391+
const { result, message } = await checkPermission(page, 'camera');
392+
// Should fall through to original API when messaging fails
393+
expect(result).toBeDefined();
394+
expect(message).toMatchObject({ featureName: 'webCompat', method: 'permissionsQuery', params: { name: 'camera' } });
395+
});
396+
397+
test('should fall through to original API for invalid arguments', async ({ page }) => {
398+
await before(page);
399+
const { result } = await checkPermission(page, null);
400+
// Should use original API validation
401+
expect(result.threw).not.toBeUndefined();
402+
});
403+
404+
test('should use configured name override for native permissions', async ({ page }) => {
405+
await before(page);
406+
await page.evaluate(() => {
407+
globalThis.cssMessaging.impl.request = (req) => {
408+
globalThis.shareReq = req;
409+
return Promise.resolve({ state: 'denied' });
410+
};
411+
});
412+
const { result } = await checkPermission(page, 'push');
413+
expect(result).toMatchObject({ name: 'notifications', state: 'denied' });
414+
});
415+
});
416+
});
417+
280418
test.describe('ScreenOrientation API', () => {
281419
test.describe('disabled feature', () => {
282420
/**

0 commit comments

Comments
 (0)