"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BrowserTester = void 0;
const expect_1 = require("./expect");
const spy_1 = require("./spy");
class BrowserTester {
    html = '';
    url = '';
    width;
    height;
    iframe;
    tests = [];
    expects = new expect_1.Expect();
    beforeAllCallbacks = [];
    afterAllCallbacks = [];
    beforeEachCallbacks = [];
    afterEachCallbacks = [];
    constructor({ html = '', url = '', width, height, }) {
        this.html = html;
        this.url = url;
        if (width) {
            this.width = width;
        }
        if (height) {
            this.height = height;
        }
    }
    spyOn(obj, key) {
        return new spy_1.Spy(obj, key);
    }
    setBrowserSize(width, height) {
        if (width) {
            this.iframe.width = `${width}px`;
        }
        if (height) {
            this.iframe.height = `${height}px`;
        }
    }
    beforeAll(callback) {
        this.beforeAllCallbacks.push(callback);
    }
    afterAll(callback) {
        this.afterAllCallbacks.push(callback);
    }
    beforeEach(callback) {
        this.beforeEachCallbacks.push(callback);
    }
    afterEach(callback) {
        this.afterEachCallbacks.push(callback);
    }
    test(description, callback) {
        this.tests.push({
            description,
            callback,
        });
    }
    it(description, callback) {
        this.tests.push({
            description,
            callback,
        });
    }
    expect(...args) {
        // @ts-ignore
        return this.expects.expect(...args);
    }
    clearTests() {
        this.tests = [];
    }
    evaluate(code, args = {}) {
        const func = new Function('test', 'it', 'expect', 'beforeEach', 'afterEach', 'beforeAll', 'afterAll', 'setBrowserSize', 'spyOn', ...Object.keys(args), code);
        func(this.test.bind(this), this.it.bind(this), this.expect.bind(this), this.beforeEach.bind(this), this.afterEach.bind(this), this.beforeAll.bind(this), this.afterAll.bind(this), this.setBrowserSize.bind(this), this.spyOn, ...Object.values(args));
    }
    run() {
        return new Promise((resolve) => {
            let url = this.url;
            if (!url) {
                const blob = new Blob([this.html], { type: "text/html" });
                url = URL.createObjectURL(blob);
            }
            const iframe = document.createElement('iframe');
            const body = document.querySelector('body');
            this.iframe = iframe;
            iframe.style.opacity = '0';
            iframe.style.pointerEvents = 'none';
            iframe.src = url;
            if (this.width && this.height) {
                iframe.width = `${this.width}px`;
                iframe.height = `${this.height}px`;
            }
            const iframeCallback = async () => {
                iframe.removeEventListener('load', iframeCallback);
                const results = [];
                for (const b of this.beforeAllCallbacks) {
                    await b(iframe.contentWindow, iframe.contentDocument);
                }
                for (const t of this.tests) {
                    for (const b of this.beforeEachCallbacks) {
                        await b(iframe.contentWindow, iframe.contentDocument);
                    }
                    const { description } = t;
                    try {
                        await t.callback(iframe.contentWindow, iframe.contentDocument, iframe);
                        results.push({
                            description,
                            result: this.expects.isAllPassed()
                        });
                    }
                    catch (e) {
                        results.push({
                            description,
                            result: false,
                            error: e,
                        });
                    }
                    this.expects.clean();
                    for (const a of this.afterEachCallbacks) {
                        await a(iframe.contentWindow, iframe.contentDocument);
                    }
                }
                for (const a of this.afterAllCallbacks) {
                    await a(iframe.contentWindow, iframe.contentDocument);
                }
                iframe.removeEventListener('load', iframeCallback);
                URL.revokeObjectURL(url);
                iframe.remove();
                resolve(results);
            };
            iframe.addEventListener('load', iframeCallback);
            body.appendChild(iframe);
        });
    }
}
exports.BrowserTester = BrowserTester;
