/*
 * @jest-environment jsdom
 */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import { jest } from "@jest/globals";
jest.unstable_mockModule("./getRandomChainId.js", () => {
    let nextChainId = "test";
    return {
        _setNextChainId(chainId) {
            nextChainId = chainId;
        },
        getRandomChainId: () => nextChainId,
    };
});
let ExtensionProvider;
let mockedGetRandomChainId;
beforeAll(async () => {
    ;
    ({ ExtensionProvider } = await import("./ExtensionProvider"));
    mockedGetRandomChainId = (await import("./getRandomChainId.js"));
});
const waitForMessageToBePosted = () => {
    // window.postMessge is async so we must do a short setTimeout to yield to
    // the event loop
    return new Promise((resolve) => setTimeout(resolve, 10, null));
};
const sendMessage = (msg) => {
    window.postMessage(msg, "*");
};
const westendSpec = JSON.stringify({ name: "Westend", id: "westend2" });
const rococoSpec = JSON.stringify({ name: "Rococo", id: "rococo" });
const emulateConnect = (ep, chainId = "test") => {
    const p = ep.connect();
    sendMessage({
        origin: "substrate-connect-extension",
        chainId,
        type: "chain-ready",
    });
    return p;
};
let handler = jest.fn();
beforeEach(() => {
    handler = jest.fn();
    window.addEventListener("message", handler);
});
afterEach(() => {
    window.removeEventListener("message", handler);
});
test("connected and sends correct spec message", async () => {
    const ep = new ExtensionProvider(westendSpec);
    const emitted = jest.fn();
    ep.on("connected", emitted);
    await emulateConnect(ep);
    await waitForMessageToBePosted();
    const expectedMessage = {
        origin: "substrate-connect-client",
        type: "add-chain",
        chainSpec: '{"name":"Westend","id":"westend2"}',
        potentialRelayChainIds: [],
    };
    expect(handler).toHaveBeenCalledTimes(2);
    const { data } = handler.mock.calls[0][0];
    expect(data).toMatchObject(expectedMessage);
});
test("connected multiple chains and sends correct spec message", async () => {
    const ep1 = new ExtensionProvider(westendSpec);
    const ep2 = new ExtensionProvider(rococoSpec);
    const emitted1 = jest.fn();
    const emitted2 = jest.fn();
    ep1.on("connected", emitted1);
    ep2.on("connected", emitted2);
    await emulateConnect(ep1);
    await waitForMessageToBePosted();
    await emulateConnect(ep2);
    await waitForMessageToBePosted();
    const expectedMessage1 = {
        origin: "substrate-connect-client",
        type: "add-chain",
        chainSpec: '{"name":"Westend","id":"westend2"}',
        potentialRelayChainIds: [],
    };
    const expectedMessage2 = {
        origin: "substrate-connect-client",
        type: "add-chain",
        chainSpec: '{"name":"Rococo","id":"rococo"}',
        potentialRelayChainIds: [],
    };
    expect(handler).toHaveBeenCalledTimes(4);
    const data1 = handler.mock.calls[0][0];
    const data2 = handler.mock.calls[2][0];
    expect(data1.data).toMatchObject(expectedMessage1);
    expect(data2.data).toMatchObject(expectedMessage2);
});
test("connected parachain sends correct spec message", async () => {
    const ep = new ExtensionProvider(westendSpec);
    const emitted = jest.fn();
    ep.on("connected", emitted);
    await emulateConnect(ep);
    await waitForMessageToBePosted();
    const expectedMessage = {
        origin: "substrate-connect-client",
        type: "add-chain",
        chainSpec: '{"name":"Westend","id":"westend2"}',
        potentialRelayChainIds: [],
    };
    expect(handler).toHaveBeenCalledTimes(2);
    const { data } = handler.mock.calls[0][0];
    expect(data).toMatchObject(expectedMessage);
});
test("disconnect sends disconnect message and emits disconnected", async () => {
    const ep = new ExtensionProvider(westendSpec);
    const emitted = jest.fn();
    await emulateConnect(ep);
    ep.on("disconnected", emitted);
    void ep.disconnect();
    await waitForMessageToBePosted();
    expect(ep.isConnected).toBe(false);
    expect(emitted).toHaveBeenCalledTimes(1);
});
test("disconnects and emits an error when it receives an error message", async () => {
    mockedGetRandomChainId._setNextChainId("foo");
    const ep = new ExtensionProvider(westendSpec);
    const emitted = jest.fn();
    await emulateConnect(ep, "foo");
    ep.on("error", emitted);
    await waitForMessageToBePosted();
    sendMessage({
        origin: "substrate-connect-extension",
        chainId: "foo",
        type: "error",
        errorMessage: "disconnected",
    });
    await waitForMessageToBePosted();
    expect(emitted).toHaveBeenCalled();
    expect(ep.isConnected).toBe(false);
});
test("emits error when it receives an error message", async () => {
    mockedGetRandomChainId._setNextChainId("foo");
    const ep = new ExtensionProvider(westendSpec);
    await emulateConnect(ep, "foo");
    await waitForMessageToBePosted();
    const errorMessage = {
        origin: "substrate-connect-extension",
        chainId: "foo",
        type: "error",
        errorMessage: "Boom!",
    };
    const errorHandler = jest.fn();
    ep.on("error", errorHandler);
    sendMessage(errorMessage);
    await waitForMessageToBePosted();
    expect(errorHandler).toHaveBeenCalled();
    const error = errorHandler.mock.calls[0][0];
    expect(error.message).toEqual(errorMessage.errorMessage);
});
test("it routes incoming messages to the correct Provider", async () => {
    var _a;
    mockedGetRandomChainId._setNextChainId("foo1");
    const ep1 = new ExtensionProvider(westendSpec);
    await emulateConnect(ep1, "foo1");
    mockedGetRandomChainId._setNextChainId("foo2");
    const ep2 = new ExtensionProvider(westendSpec);
    await emulateConnect(ep2, "foo2");
    await waitForMessageToBePosted();
    let extensionProvider1Response = undefined;
    let extensionProvider2Response = undefined;
    ep1
        .send("requestSomeData", [])
        .then((response) => {
        extensionProvider1Response = response;
    })
        .catch(() => {
        extensionProvider1Response = "Error";
    });
    await waitForMessageToBePosted();
    ep2
        .send("requestOtherData", [])
        .then((response) => {
        extensionProvider2Response = response;
    })
        .catch(() => {
        extensionProvider2Response = "Error";
    });
    await waitForMessageToBePosted();
    const latestRequest = handler.mock.calls[handler.mock.calls.length - 1][0];
    const latestRequestRpcId = JSON.parse((_a = latestRequest === null || latestRequest === void 0 ? void 0 : latestRequest.data.jsonRpcMessage) !== null && _a !== void 0 ? _a : "{}").id;
    const latestChainId = latestRequest === null || latestRequest === void 0 ? void 0 : latestRequest.data.chainId;
    sendMessage({
        origin: "substrate-connect-extension",
        chainId: latestChainId,
        type: "rpc",
        jsonRpcMessage: JSON.stringify({
            id: latestRequestRpcId,
            jsonrpc: "2.0",
            result: "hi ExtensionProvider2!",
        }),
    });
    await waitForMessageToBePosted();
    expect(extensionProvider2Response).toBe("hi ExtensionProvider2!");
    expect(extensionProvider1Response).toBe(undefined);
});
//# sourceMappingURL=ExtensionProvider.test.js.map