/**
 * Copyright 2017 Google Inc. All rights reserved.
 * Modifications copyright (c) Microsoft Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { contextTest as it, expect } from '../config/browserTest';
function getPermission(page, name) {
    return page.evaluate(name => navigator.permissions.query({ name }).then(result => result.state), name);
}
it.describe('permissions', () => {
    it.fixme(({ browserName, isWindows }) => browserName === 'webkit' && isWindows, 'Permissions API is disabled on Windows WebKit');
    it('should be prompt by default', async ({ page, server }) => {
        await page.goto(server.EMPTY_PAGE);
        expect(await getPermission(page, 'geolocation')).toBe('prompt');
    });
    it('should deny permission when not listed', async ({ page, context, server, browserName, isBidi, isFrozenWebkit }) => {
        it.skip(isFrozenWebkit);
        await page.goto(server.EMPTY_PAGE);
        await context.grantPermissions([], { origin: server.EMPTY_PAGE });
        if (browserName === 'webkit') {
            expect(await getPermission(page, 'geolocation')).toBe('prompt');
            // Since https://github.com/WebKit/WebKit/pull/45470 WebKit only returns actual
            // permission value, if the API has been accessed.
            await page.evaluate(() => navigator.geolocation.getCurrentPosition(() => { }));
            expect(await getPermission(page, 'geolocation')).toBe('denied');
        }
        else if (isBidi) {
            expect(await getPermission(page, 'geolocation')).toBe('prompt');
        }
        else {
            expect(await getPermission(page, 'geolocation')).toBe('denied');
        }
    });
    it('should fail when bad permission is given', async ({ page, context, server, isBidi }) => {
        await page.goto(server.EMPTY_PAGE);
        let error;
        await context.grantPermissions(['foo'], { origin: server.EMPTY_PAGE }).catch(e => error = e);
        if (isBidi)
            expect(error.message).toContain('Protocol error (permissions.setPermission): invalid argument');
        else
            expect(error.message).toContain('Unknown permission: foo');
    });
    it('should grant geolocation permission when origin is listed', async ({ page, context, server }) => {
        await page.goto(server.EMPTY_PAGE);
        await context.grantPermissions(['geolocation'], { origin: server.EMPTY_PAGE });
        expect(await getPermission(page, 'geolocation')).toBe('granted');
    });
    it('should prompt for geolocation permission when origin is not listed', async ({ page, context, server }) => {
        await page.goto(server.EMPTY_PAGE);
        await context.grantPermissions(['geolocation'], { origin: server.EMPTY_PAGE });
        await page.goto(server.CROSS_PROCESS_PREFIX + '/empty.html');
        expect(await getPermission(page, 'geolocation')).toBe('prompt');
    });
    it('should grant notifications permission when listed', async ({ page, context, server }) => {
        await page.goto(server.EMPTY_PAGE);
        await context.grantPermissions(['notifications'], { origin: server.EMPTY_PAGE });
        expect(await getPermission(page, 'notifications')).toBe('granted');
    });
    it('should accumulate when adding', async ({ page, context, server }) => {
        await page.goto(server.EMPTY_PAGE);
        await context.grantPermissions(['geolocation']);
        await context.grantPermissions(['notifications']);
        expect(await getPermission(page, 'geolocation')).toBe('granted');
        expect(await getPermission(page, 'notifications')).toBe('granted');
    });
    it('should clear permissions', async ({ page, context, server }) => {
        await page.goto(server.EMPTY_PAGE);
        await context.grantPermissions(['geolocation']);
        await context.clearPermissions();
        await context.grantPermissions(['notifications']);
        expect(await getPermission(page, 'geolocation')).not.toBe('granted');
        expect(await getPermission(page, 'notifications')).toBe('granted');
    });
    it('should grant permission when listed for all domains', async ({ page, context, server }) => {
        await page.goto(server.EMPTY_PAGE);
        await context.grantPermissions(['geolocation']);
        expect(await getPermission(page, 'geolocation')).toBe('granted');
    });
    it('should grant permission when creating context', async ({ server, browser }) => {
        const context = await browser.newContext({ permissions: ['geolocation'] });
        const page = await context.newPage();
        await page.goto(server.EMPTY_PAGE);
        expect(await getPermission(page, 'geolocation')).toBe('granted');
        await context.close();
    });
    it('should reset permissions', async ({ page, context, server }) => {
        await page.goto(server.EMPTY_PAGE);
        await context.grantPermissions(['geolocation'], { origin: server.EMPTY_PAGE });
        expect(await getPermission(page, 'geolocation')).toBe('granted');
        await context.clearPermissions();
        expect(await getPermission(page, 'geolocation')).toBe('prompt');
    });
    it('should trigger permission onchange', async ({ page, context, server, browserName, isBidi }) => {
        it.fail(browserName === 'webkit');
        await page.goto(server.EMPTY_PAGE);
        await page.evaluate(() => {
            window['events'] = [];
            return navigator.permissions.query({ name: 'geolocation' }).then(function (result) {
                window['events'].push(result.state);
                result.onchange = function () {
                    window['events'].push(result.state);
                };
            });
        });
        const expectedEvents = ['prompt'];
        expect(await page.evaluate(() => window['events'])).toEqual(expectedEvents);
        await context.grantPermissions([], { origin: server.EMPTY_PAGE });
        if (!isBidi)
            expectedEvents.push('denied');
        expect(await page.evaluate(() => window['events'])).toEqual(expectedEvents);
        await context.grantPermissions(['geolocation'], { origin: server.EMPTY_PAGE });
        expectedEvents.push('granted');
        expect(await page.evaluate(() => window['events'])).toEqual(expectedEvents);
        await context.clearPermissions();
        expectedEvents.push('prompt');
        expect(await page.evaluate(() => window['events'])).toEqual(expectedEvents);
    });
    it('should isolate permissions between browser contexts', async ({ server, browser, browserName, isBidi, isFrozenWebkit }) => {
        it.skip(isFrozenWebkit);
        const context = await browser.newContext();
        const page = await context.newPage();
        await page.goto(server.EMPTY_PAGE);
        const otherContext = await browser.newContext();
        const otherPage = await otherContext.newPage();
        await otherPage.goto(server.EMPTY_PAGE);
        expect(await getPermission(page, 'geolocation')).toBe('prompt');
        expect(await getPermission(otherPage, 'geolocation')).toBe('prompt');
        await context.grantPermissions([], { origin: server.EMPTY_PAGE });
        await otherContext.grantPermissions(['geolocation'], { origin: server.EMPTY_PAGE });
        if (browserName === 'webkit') {
            expect(await getPermission(page, 'geolocation')).toBe('prompt');
            // Since https://github.com/WebKit/WebKit/pull/45470 WebKit only returns actual
            // permission value, if the API has been accessed.
            await page.evaluate(() => navigator.geolocation.getCurrentPosition(() => { }));
            expect(await getPermission(page, 'geolocation')).toBe('denied');
        }
        else if (isBidi) {
            expect(await getPermission(page, 'geolocation')).toBe('prompt');
        }
        else {
            expect(await getPermission(page, 'geolocation')).toBe('denied');
        }
        expect(await getPermission(otherPage, 'geolocation')).toBe('granted');
        await context.clearPermissions();
        if (browserName === 'webkit') {
            // Since https://github.com/WebKit/WebKit/pull/45470 WebKit returns the cached
            // permission value, if the geolocation API has been accessed.
            // TODO: We can probably reset the cached state in the Web Process when resetting
            // permissions.
            expect(await getPermission(page, 'geolocation')).toBe('denied');
            // Geolocation API in the new page in the same context has not been accessed yet,
            // so the permission status should be prompt.
            const page2 = await context.newPage();
            await page2.goto(server.EMPTY_PAGE);
            expect(await getPermission(page2, 'geolocation')).toBe('prompt');
            await page2.close();
        }
        else {
            expect(await getPermission(page, 'geolocation')).toBe('prompt');
        }
        expect(await getPermission(otherPage, 'geolocation')).toBe('granted');
        await otherContext.close();
        await context.close();
    });
});
it('should support clipboard read', async ({ page, context, server, browserName, isWindows, isLinux, headless, isHeadlessShell }) => {
    it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/27475' });
    it.fail(browserName === 'firefox', 'No such permissions (requires flag) in Firefox');
    it.fixme(browserName === 'webkit' && isWindows, 'WebPasteboardProxy::allPasteboardItemInfo not implemented for Windows.');
    it.fixme(browserName === 'webkit' && isLinux && headless, 'WebPasteboardProxy::allPasteboardItemInfo not implemented for WPE.');
    await page.goto(server.EMPTY_PAGE);
    // There is no 'clipboard-read' permission in WebKit Web API.
    if (browserName !== 'webkit')
        expect(await getPermission(page, 'clipboard-read')).toBe('prompt');
    if (isHeadlessShell) {
        // Chromium (but not headless-shell) shows a dialog and does not resolve the promise.
        const error = await page.evaluate(() => navigator.clipboard.readText()).catch(e => e);
        expect(error.toString()).toContain('denied');
    }
    await context.grantPermissions(['clipboard-read']);
    if (browserName !== 'webkit')
        expect(await getPermission(page, 'clipboard-read')).toBe('granted');
    // There is no 'clipboard-write' permission in WebKit Web API.
    if (browserName === 'chromium')
        await context.grantPermissions(['clipboard-write']);
    await page.evaluate(() => navigator.clipboard.writeText('test content'));
    expect(await page.evaluate(() => navigator.clipboard.readText())).toBe('test content');
});
it('storage access', {
    annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/31227' }
}, async ({ page, context, server, browserName }) => {
    it.skip(browserName !== 'chromium', 'chromium-only api');
    await context.grantPermissions(['storage-access']);
    expect(await getPermission(page, 'storage-access')).toBe('granted');
    server.setRoute('/set-cookie.html', (req, res) => {
        res.setHeader('Set-Cookie', 'name=value; Path=/; SameSite=Strict; Secure');
        res.end();
    });
    server.setRoute('/my-frame.html', (req, res) => {
        res.setHeader('Content-type', 'text/html');
        res.end(`<iframe src="${server.CROSS_PROCESS_PREFIX + '/empty.html'}"></iframe>`);
    });
    // Navigate once to the domain as top level.
    await page.goto(server.CROSS_PROCESS_PREFIX + '/set-cookie.html');
    await page.goto(server.PREFIX + '/my-frame.html');
    const frame = page.frames()[1];
    expect(await getPermission(frame, 'storage-access')).toBe('granted');
    const access = await frame.evaluate(() => document.requestStorageAccess().then(() => true, () => false));
    expect(access).toBe(true);
    expect(await frame.evaluate(() => document.hasStorageAccess())).toBe(true);
});
it.describe(() => {
    // Secure context
    it.use({ ignoreHTTPSErrors: true, });
    it('should be able to use the local-fonts API', async ({ page, context, httpsServer, browserName, channel, headless }) => {
        it.skip(browserName !== 'chromium', 'chromium-only api');
        it.fixme(!!channel && channel.startsWith('msedge'), 'always times out in edge');
        it.fixme(!headless, 'times out in headed');
        it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/36113' });
        await page.goto(httpsServer.EMPTY_PAGE);
        expect(await getPermission(page, 'local-fonts')).toBe('prompt');
        await context.grantPermissions(['local-fonts']);
        expect(await getPermission(page, 'local-fonts')).toBe('granted');
        expect(await page.evaluate(async () => (await window.queryLocalFonts()).length > 0)).toBe(true);
    });
});
it('local network request is allowed from public origin', {
    annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/37861' }
}, async ({ page, context, server, browserName, channel, browserMajorVersion }) => {
    it.skip(browserName === 'webkit');
    it.skip(browserName === 'chromium' && browserMajorVersion < 145, 'local-network-access permission support has changed between versions');
    if (browserName === 'chromium')
        await context.grantPermissions(['local-network-access']);
    const serverRequests = [];
    server.setRoute('/cors', (req, res) => {
        serverRequests.push(`${req.method} ${req.url}`);
        if (req.method === 'OPTIONS') {
            res.writeHead(204, {
                'Access-Control-Allow-Origin': '*',
                'Access-Control-Allow-Methods': 'GET, POST, PUT, OPTIONS',
                'Access-Control-Allow-Headers': '*',
            });
            res.end();
            return;
        }
        res.writeHead(200, { 'Content-type': 'text/plain', 'Access-Control-Allow-Origin': '*' });
        res.end('Hello there!');
    });
    const clientRequests = [];
    // Has to be a public origin.
    await page.goto('https://demo.playwright.dev/todomvc/');
    page.on('request', request => {
        clientRequests.push(`${request.method()} ${request.url()}`);
    });
    const response = await page.evaluate(async (url) => {
        const response = await fetch(url, {
            method: 'POST',
            body: '',
            headers: {
                'Content-Type': 'application/json',
                'X-Custom-Header': 'test-value'
            }
        });
        return await response.text();
    }, server.CROSS_PROCESS_PREFIX + '/cors').catch(e => e.message);
    expect(response).toBe('Hello there!');
    expect(serverRequests).toEqual([
        'OPTIONS /cors',
        'POST /cors',
    ]);
    expect(clientRequests).toEqual([
        `POST ${server.CROSS_PROCESS_PREFIX}/cors`,
    ]);
});
it('can request screen-wake-lock', {
    annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/39115' }
}, async ({ page, context }) => {
    await context.grantPermissions(['screen-wake-lock']);
    await page.route('**/*', route => route.fulfill({ status: 200, body: '<div>Hello there!</div>', contentType: 'text/html' }));
    await page.goto('https://example.com');
    await page.evaluate(() => navigator.wakeLock.request('screen'));
});
//# sourceMappingURL=permissions.spec.js.map