/**
 * 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.
 */
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
    var useValue = arguments.length > 2;
    for (var i = 0; i < initializers.length; i++) {
        value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
    }
    return useValue ? value : void 0;
};
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
    function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
    var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
    var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
    var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
    var _, done = false;
    for (var i = decorators.length - 1; i >= 0; i--) {
        var context = {};
        for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
        for (var p in contextIn.access) context.access[p] = contextIn.access[p];
        context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
        var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
        if (kind === "accessor") {
            if (result === void 0) continue;
            if (result === null || typeof result !== "object") throw new TypeError("Object expected");
            if (_ = accept(result.get)) descriptor.get = _;
            if (_ = accept(result.set)) descriptor.set = _;
            if (_ = accept(result.init)) initializers.unshift(_);
        }
        else if (_ = accept(result)) {
            if (kind === "field") initializers.unshift(_);
            else descriptor[key] = _;
        }
    }
    if (target) Object.defineProperty(target, contextIn.name, descriptor);
    done = true;
};
import { contextTest } from '../../config/browserTest';
import { step } from '../../config/baseTest';
import * as path from 'path';
import fs from 'fs';
import { expect } from '@playwright/test';
export { expect } from '@playwright/test';
const codegenLang2Id = new Map([
    ['JSON', 'jsonl'],
    ['JavaScript', 'javascript'],
    ['Java', 'java'],
    ['Java JUnit', 'java-junit'],
    ['Python', 'python'],
    ['Python Async', 'python-async'],
    ['Pytest', 'python-pytest'],
    ['C#', 'csharp'],
    ['C# NUnit', 'csharp-nunit'],
    ['C# MSTest', 'csharp-mstest'],
    ['C# xUnit', 'csharp-xunit'],
    ['Playwright Test', 'playwright-test'],
]);
const codegenLangId2lang = new Map([...codegenLang2Id.entries()].map(([lang, langId]) => [langId, lang]));
import { inprocess } from '../../../packages/playwright-core/lib/coreBundle';
// Use a separate Playwright instance for automating the inspector so that
// contexts created here do not get tracked by the test runner's tracing.
const playwrightToAutomateInspector = inprocess.createInProcessPlaywright();
export const test = contextTest.extend({
    recorderPageGetter: async ({ context, toImpl, mode, headless }, run, testInfo) => {
        testInfo.skip(mode !== 'default');
        testInfo.skip(!headless, 'real mouse moves mess up with recording');
        await run(async () => {
            while (!toImpl(context).recorderAppForTest)
                await new Promise(f => setTimeout(f, 100));
            const wsEndpoint = toImpl(context).recorderAppForTest.wsEndpointForTest;
            const browser = await playwrightToAutomateInspector.chromium.connectOverCDP({ wsEndpoint });
            const c = browser.contexts()[0];
            return c.pages()[0] || await c.waitForEvent('page');
        });
    },
    closeRecorder: async ({ context, toImpl }, run) => {
        await run(async () => {
            await toImpl(context).recorderAppForTest.close();
        });
    },
    runCLI: async ({ childProcess, browserName, channel, headless, mode, launchOptions }, run, testInfo) => {
        testInfo.slow();
        testInfo.skip(mode.startsWith('service'));
        let cli;
        await run(cliArgs => {
            const outputFile = testInfo.outputPath('codegen.output');
            cli = new CLIMock(childProcess, {
                outputFile,
                browserName,
                channel,
                headless,
                args: cliArgs,
                executablePath: launchOptions.executablePath,
            });
            return cli;
        });
        await cli?.exit();
    },
    openRecorder: async ({ context, recorderPageGetter }, use) => {
        await use(async (options) => {
            await context._enableRecorder({
                mode: 'recording',
                omitCallTracking: true,
                ...options
            });
            const page = await context.newPage();
            return { page, recorder: new Recorder(page, await recorderPageGetter()) };
        });
    },
});
export class Recorder {
    page;
    _highlightCallback;
    _highlightInstalled;
    _actionReporterInstalled;
    _actionPerformedCallback;
    recorderPage;
    _sources = new Map();
    constructor(page, recorderPage) {
        this.page = page;
        this.recorderPage = recorderPage;
        this._highlightCallback = () => { };
        this._highlightInstalled = false;
        this._actionReporterInstalled = false;
        this._actionPerformedCallback = () => { };
    }
    async setContentAndWait(content, url = 'about:blank', frameCount = 1) {
        await this.setPageContentAndWait(this.page, content, url, frameCount);
    }
    async setPageContentAndWait(page, content, url = 'about:blank', frameCount = 1) {
        let callback;
        const result = new Promise(f => callback = f);
        let msgCount = 0;
        const listener = msg => {
            if (msg.text() === 'Recorder script ready for test') {
                ++msgCount;
                if (msgCount === frameCount) {
                    page.off('console', listener);
                    callback();
                }
            }
        };
        page.on('console', listener);
        await page.goto(url);
        await Promise.all([
            result,
            page.setContent(content)
        ]);
    }
    async waitForOutput(file, text) {
        return await test.step('waitForOutput', async () => {
            if (!codegenLang2Id.has(file))
                throw new Error(`Unknown language: ${file}`);
            await expect.poll(() => this.recorderPage.evaluate(languageId => {
                const sources = (window.playwrightSourcesEchoForTest || []);
                return sources.find(s => s.id === languageId)?.text || '';
            }, codegenLang2Id.get(file)), { timeout: 0 }).toContain(text);
            const sources = await this.recorderPage.evaluate(() => window.playwrightSourcesEchoForTest || []);
            for (const source of sources) {
                if (!codegenLangId2lang.has(source.id))
                    throw new Error(`Unknown language: ${source.id}`);
                this._sources.set(codegenLangId2lang.get(source.id), source);
            }
            return this._sources;
        }, { box: true });
    }
    sources() {
        return this._sources;
    }
    async text(file) {
        const sources = await this.recorderPage.evaluate(() => window.playwrightSourcesEchoForTest || []);
        for (const source of sources) {
            if (codegenLangId2lang.get(source.id) === file)
                return source.text;
        }
        return '';
    }
    async waitForHighlight(action) {
        return await test.step('waitForHighlight', async () => {
            await this.page.$$eval('x-pw-highlight', els => els.forEach(e => e.remove()));
            await this.page.$$eval('x-pw-tooltip', els => els.forEach(e => e.remove()));
            await action();
            await this.page.locator('x-pw-highlight').waitFor();
            await this.page.locator('x-pw-tooltip').waitFor();
            await expect(this.page.locator('x-pw-tooltip')).not.toHaveText('');
            await expect(this.page.locator('x-pw-tooltip')).not.toHaveText(`locator('body')`);
            return this.page.locator('x-pw-tooltip').textContent();
        }, { box: true });
    }
    async waitForHighlightNoTooltip(action) {
        await this.page.$$eval('x-pw-highlight', els => els.forEach(e => e.remove()));
        await action();
        await this.page.locator('x-pw-highlight').waitFor();
        return '';
    }
    async waitForActionPerformed() {
        let callback;
        const listener = async (msg) => {
            const prefix = 'Action performed for test: ';
            if (msg.text().startsWith(prefix)) {
                this.page.off('console', listener);
                const arg = JSON.parse(msg.text().substr(prefix.length));
                callback(arg);
            }
        };
        this.page.on('console', listener);
        return new Promise(f => callback = f);
    }
    async hoverOverElement(selector, options) {
        return (options?.omitTooltip ? this.waitForHighlightNoTooltip : this.waitForHighlight).call(this, async () => {
            const box = await this.page.locator(selector).first().boundingBox();
            const offset = options?.position || { x: box.width / 2, y: box.height / 2 };
            await this.page.mouse.move(box.x + offset.x, box.y + offset.y);
        });
    }
    async trustedMove(selector) {
        const locator = typeof selector === 'string' ? this.page.locator(selector).first() : selector;
        const box = await locator.boundingBox();
        await this.page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);
    }
    async trustedClick(options) {
        await this.page.mouse.down(options);
        await this.page.mouse.up(options);
    }
    async trustedPress(text) {
        await this.page.keyboard.press(text);
    }
    async trustedDblclick() {
        await this.page.mouse.down();
        await this.page.mouse.up();
        await this.page.mouse.down({ clickCount: 2 });
        await this.page.mouse.up();
    }
    async focusElement(selector) {
        return this.waitForHighlight(() => this.page.focus(selector));
    }
}
let CLIMock = (() => {
    let _instanceExtraInitializers = [];
    let _waitFor_decorators;
    let _exit_decorators;
    return class CLIMock {
        static {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
            _waitFor_decorators = [step];
            _exit_decorators = [step];
            __esDecorate(this, null, _waitFor_decorators, { kind: "method", name: "waitFor", static: false, private: false, access: { has: obj => "waitFor" in obj, get: obj => obj.waitFor }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _exit_decorators, { kind: "method", name: "exit", static: false, private: false, access: { has: obj => "exit" in obj, get: obj => obj.exit }, metadata: _metadata }, null, _instanceExtraInitializers);
            if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        }
        _process = __runInitializers(this, _instanceExtraInitializers);
        _outputFile;
        _exitPromise;
        constructor(childProcess, options) {
            this._outputFile = options.outputFile;
            const nodeArgs = [
                'node',
                path.join(__dirname, '..', '..', '..', 'packages', 'playwright-core', 'cli.js'),
                'codegen',
                ...options.args,
                `--browser=${options.browserName}`,
                `--output=${this._outputFile}`,
            ];
            if (options.channel)
                nodeArgs.push(`--channel=${options.channel}`);
            this._process = childProcess({
                command: nodeArgs,
                env: {
                    PWTEST_CLI_IS_UNDER_TEST: '1',
                    PWTEST_CLI_HEADLESS: options.headless ? '1' : undefined,
                    PWTEST_CLI_EXECUTABLE_PATH: options.executablePath,
                    DEBUG: (process.env.DEBUG ?? '') + ',pw:browser*',
                },
            });
        }
        async waitFor(text) {
            await expect.poll(() => this.text(), { timeout: 30000 }).toContain(text);
        }
        async exit() {
            if (!this._exitPromise) {
                this._process.write('exit\n');
                this._exitPromise = this._process.cleanExit();
            }
            await this._exitPromise;
        }
        sigint() {
            const result = this._process.kill('SIGINT');
            this._exitPromise = this._process.exited.then(() => undefined); // Avoid double closing.
            return result;
        }
        async text() {
            try {
                return await fs.promises.readFile(this._outputFile, 'utf-8');
            }
            catch {
                return '';
            }
        }
    };
})();
//# sourceMappingURL=inspectorTest.js.map