/**
 * 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 { expect, playwrightTest as baseTest } from '../config/browserTest';
import { remote, utils } from '../../packages/playwright-core/lib/coreBundle';
const { PlaywrightServer } = remote;
import { Backend } from '../config/debugControllerBackend';
import { roundBox } from '../config/utils';
const { createGuid } = utils;
const test = baseTest.extend({
    wsEndpoint: async ({ headless }, use) => {
        if (headless)
            process.env.PW_DEBUG_CONTROLLER_HEADLESS = '1';
        const server = new PlaywrightServer({ mode: 'extension', path: '/' + createGuid(), maxConnections: Number.MAX_VALUE, enableSocksProxy: false });
        const wsEndpoint = await server.listen();
        await use(wsEndpoint);
        await server.close();
    },
    backend: async ({ wsEndpoint }, use) => {
        const backend = new Backend();
        await backend.connect(wsEndpoint);
        await backend.initialize();
        await use(backend.channel);
        await backend.close();
    },
    connectedBrowserFactory: async ({ wsEndpoint, browserType }, use) => {
        const browsers = [];
        await use(async () => {
            const browser = await browserType.connect(wsEndpoint, {
                headers: {
                    'x-playwright-launch-options': JSON.stringify(browserType._playwright._defaultLaunchOptions),
                },
            });
            browsers.push(browser);
            let context;
            browser.newContextForReuse = async () => {
                if (context)
                    await browser._disconnectFromReusedContext('reusedContext');
                context = await browser._newContextForReuse();
                return context;
            };
            return browser;
        });
        for (const browser of browsers)
            await browser.close();
    },
    connectedBrowser: async ({ connectedBrowserFactory }, use) => {
        await use(await connectedBrowserFactory());
    },
});
test.slow(true, 'All controller tests are slow');
test.skip(({ mode }) => mode.startsWith('service') || mode === 'driver');
// Force a separate worker to avoid registered selector engines from other tests.
// See https://github.com/microsoft/playwright/pull/37103.
test.use({ launchOptions: [async ({ launchOptions }, use) => use(launchOptions), { scope: 'worker' }] });
test('should pick element', async ({ backend, connectedBrowser }) => {
    const events = [];
    backend.on('inspectRequested', event => events.push(event));
    await backend.setRecorderMode({ mode: 'inspecting' });
    const context = await connectedBrowser.newContextForReuse();
    const [page] = context.pages();
    await page.setContent('<button>Submit</button>');
    await page.getByRole('button').click();
    await page.getByRole('button').click();
    expect(events).toEqual([
        {
            ariaSnapshot: '- button "Submit"',
            selector: 'internal:role=button[name=\"Submit\"i]',
            locator: 'getByRole(\'button\', { name: \'Submit\' })',
        }, {
            ariaSnapshot: '- button "Submit"',
            selector: 'internal:role=button[name=\"Submit\"i]',
            locator: 'getByRole(\'button\', { name: \'Submit\' })',
        },
    ]);
    // No events after mode disabled
    await backend.setRecorderMode({ mode: 'none' });
    await page.locator('body').click();
    expect(events).toHaveLength(2);
});
test('should report pages', async ({ backend, connectedBrowser }) => {
    const events = [];
    backend.on('stateChanged', event => events.push(event));
    await backend.setReportStateChanged({ enabled: true });
    const context = await connectedBrowser.newContextForReuse();
    const page1 = await context.newPage();
    const page2 = await context.newPage();
    await page1.close();
    await page2.close();
    await backend.setReportStateChanged({ enabled: false });
    const page3 = await context.newPage();
    await page3.close();
    expect(events).toEqual([
        {
            pageCount: 1,
        }, {
            pageCount: 2,
        }, {
            pageCount: 1,
        }, {
            pageCount: 0,
        }
    ]);
});
test('should reset for reuse', async ({ backend, connectedBrowser }) => {
    const context = await connectedBrowser.newContextForReuse();
    const page1 = await context.newPage();
    const page2 = await context.newPage();
    await page1.goto('data:text/plain,Hello world');
    await page2.goto('data:text/plain,Hello world');
    const context2 = await connectedBrowser.newContextForReuse();
    expect(context2.pages().length).toBe(1);
    expect(context2.pages()[0]).not.toBe(page1);
    expect(await context2.pages()[0].evaluate(() => window.location.href)).toBe('about:blank');
    // Note: ideally, `page1` would be unaccessible, because it was disposed.
    // However, we currently do not check that, and since it keeps the same guid, sending
    // messages to the server keeps working.
    expect(await page1.evaluate(() => window.location.href)).toBe('about:blank');
    expect(await page2.evaluate(() => window.location.href).catch(e => e.message)).toContain('Target page, context or browser has been closed');
});
test('should highlight all', async ({ backend, connectedBrowser }) => {
    const context = await connectedBrowser.newContextForReuse();
    const page1 = await context.newPage();
    const page2 = await context.newPage();
    await page1.goto('data:text/html,<button>Submit</button>');
    await page2.goto('data:text/html,<button>Submit</button>');
    await backend.highlight({ selector: 'button' });
    await expect(page1.getByText('locator(\'button\')')).toBeVisible();
    await expect(page2.getByText('locator(\'button\')')).toBeVisible();
    await backend.hideHighlight();
    await expect(page1.getByText('locator(\'button\')')).toBeHidden({ timeout: 1000000 });
    await expect(page2.getByText('locator(\'button\')')).toBeHidden();
});
test('should record', async ({ backend, connectedBrowser }) => {
    const events = [];
    backend.on('sourceChanged', event => events.push(event));
    await backend.setRecorderMode({ mode: 'recording' });
    const context = await connectedBrowser.newContextForReuse();
    const [page] = context.pages();
    await page.setContent('<button>Submit</button>');
    await page.getByRole('button').click();
    await expect.poll(() => events[events.length - 1]).toEqual({
        header: `import { test, expect } from '@playwright/test';

test('test', async ({ page }) => {`,
        footer: `});`,
        actions: [
            `  await page.goto('about:blank');`,
            `  await page.getByRole('button', { name: 'Submit' }).click();`,
        ],
        text: `import { test, expect } from '@playwright/test';

test('test', async ({ page }) => {
  await page.goto('about:blank');
  await page.getByRole('button', { name: 'Submit' }).click();
});`
    });
    // No events after mode disabled
    await backend.setRecorderMode({ mode: 'none' });
    const length = events.length;
    await page.getByRole('button').click();
    expect(events).toHaveLength(length);
});
test('should record custom data-testid', async ({ backend, connectedBrowser }) => {
    // This test emulates "record at cursor" functionality
    // with custom test id attribute in the config.
    const events = [];
    backend.on('sourceChanged', event => events.push(event));
    // 1. "Show browser" (or "run test").
    const context = await connectedBrowser.newContextForReuse();
    const page = await context.newPage();
    await page.setContent(`<div data-custom-id='one'>One</div>`);
    // 2. "Record at cursor".
    await backend.setRecorderMode({ mode: 'recording', testIdAttributeName: 'data-custom-id' });
    // 3. Record a click action.
    await page.locator('div').click();
    // 4. Expect "getByTestId" locator.
    await expect.poll(() => events[events.length - 1]).toEqual({
        header: `import { test, expect } from '@playwright/test';

test('test', async ({ page }) => {`,
        footer: `});`,
        actions: [
            `  await page.getByTestId('one').click();`,
        ],
        text: `import { test, expect } from '@playwright/test';

test('test', async ({ page }) => {
  await page.getByTestId('one').click();
});`
    });
});
test('should reset routes before reuse', async ({ server, connectedBrowserFactory }) => {
    const browser1 = await connectedBrowserFactory();
    const context1 = await browser1.newContextForReuse();
    await context1.route(server.PREFIX + '/title.html', route => route.fulfill({ body: '<title>Hello</title>', contentType: 'text/html' }));
    const page1 = await context1.newPage();
    await page1.route(server.PREFIX + '/consolelog.html', route => route.fulfill({ body: '<title>World</title>', contentType: 'text/html' }));
    await page1.goto(server.PREFIX + '/title.html');
    await expect(page1).toHaveTitle('Hello');
    await page1.goto(server.PREFIX + '/consolelog.html');
    await expect(page1).toHaveTitle('World');
    await browser1.close();
    const browser2 = await connectedBrowserFactory();
    const context2 = await browser2.newContextForReuse();
    const page2 = await context2.newPage();
    await page2.goto(server.PREFIX + '/title.html');
    await expect(page2).toHaveTitle('Woof-Woof');
    await page2.goto(server.PREFIX + '/consolelog.html');
    await expect(page2).toHaveTitle('console.log test');
    await browser2.close();
});
test('should highlight inside iframe', async ({ backend, connectedBrowser }, testInfo) => {
    testInfo.annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/33146' });
    const context = await connectedBrowser.newContextForReuse();
    const page = await context.newPage();
    await page.goto(`data:text/html,<div>bar</div><iframe srcdoc="<div>bar</div>"/>`);
    await page.frameLocator('iframe').getByText('bar').highlight();
    const highlight = page.frameLocator('iframe').locator('x-pw-highlight');
    await expect(highlight).not.toHaveCount(0);
    await backend.hideHighlight();
    await expect(highlight).toHaveCount(0);
    await backend.highlight({ selector: `frameLocator('iframe').getByText('bar')` });
    await expect(highlight).not.toHaveCount(0);
    await backend.highlight({ selector: `frameLocator('iframe').frameLocator('iframe').getByText('bar')` });
    await expect(highlight).toHaveCount(0);
    await backend.highlight({ selector: `getByText('bar')` });
    await expect(highlight).toHaveCount(1);
    await expect(page.locator('x-pw-highlight')).toHaveCount(1);
});
test('should highlight aria template', async ({ backend, connectedBrowser }, testInfo) => {
    const context = await connectedBrowser.newContextForReuse();
    const page = await context.newPage();
    await page.goto(`data:text/html,<button>Submit</button>`);
    const button = page.getByRole('button');
    const highlight = page.locator('x-pw-highlight');
    await backend.highlight({ ariaTemplate: `- button "Submit2"` });
    await expect(highlight).toHaveCount(0);
    await backend.highlight({ ariaTemplate: `- button "Submit"` });
    const box1 = roundBox(await button.boundingBox());
    const box2 = roundBox(await highlight.boundingBox());
    expect(box1).toEqual(box2);
});
test('should report error in aria template', async ({ backend }) => {
    const error = await backend.highlight({ ariaTemplate: `- button "Submit` }).catch(e => e);
    expect(error.message).toContain('Unterminated string:');
});
//# sourceMappingURL=debug-controller.spec.js.map