"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const apollo_link_1 = require("apollo-link");
const apolloLinkContextModule = __importStar(require("apollo-link-context"));
const semver_1 = __importDefault(require("semver"));
const sinon_1 = __importDefault(require("sinon"));
const queries_1 = require("../middleware/queries");
const Polymesh_1 = require("../Polymesh");
const mocks_1 = require("../testUtils/mocks");
const constants_1 = require("../utils/constants");
jest.mock('@polkadot/api', require("../testUtils/mocks/dataSources").mockPolkadotModule('@polkadot/api'));
jest.mock('~/base/Context', require("../testUtils/mocks/dataSources").mockContextModule('~/base/Context'));
jest.mock('apollo-client', require("../testUtils/mocks/dataSources").mockApolloModule('apollo-client'));
jest.mock('~/api/entities/TickerReservation', require("../testUtils/mocks/entities").mockTickerReservationModule('~/api/entities/TickerReservation'));
jest.mock('~/api/entities/Identity', require("../testUtils/mocks/entities").mockIdentityModule('~/api/entities/Identity'));
jest.mock('~/api/entities/Account', require("../testUtils/mocks/entities").mockAccountModule('~/api/entities/Account'));
jest.mock('~/base/Procedure', require("../testUtils/mocks/procedure").mockProcedureModule('~/base/Procedure'));
jest.mock('~/api/entities/Asset', require("../testUtils/mocks/entities").mockAssetModule('~/api/entities/Asset'));
jest.mock('websocket-as-promised', require("../testUtils/mocks/dataSources").mockWebSocketAsPromisedModule());
describe('Polymesh Class', () => {
    beforeAll(() => {
        mocks_1.dsMockUtils.initMocks();
        mocks_1.entityMockUtils.initMocks();
        mocks_1.procedureMockUtils.initMocks();
    });
    afterEach(() => {
        mocks_1.dsMockUtils.reset();
        mocks_1.entityMockUtils.reset();
        mocks_1.procedureMockUtils.reset();
    });
    afterAll(() => {
        mocks_1.dsMockUtils.cleanup();
        mocks_1.procedureMockUtils.cleanup();
    });
    describe('method: create', () => {
        beforeAll(() => {
            sinon_1.default.stub(apolloLinkContextModule, 'setContext').callsFake(cbFunc => {
                return new apollo_link_1.ApolloLink(cbFunc({}, {}));
            });
        });
        test('should instantiate Context and return a Polymesh instance', () => __awaiter(void 0, void 0, void 0, function* () {
            const polymesh = yield Polymesh_1.Polymesh.connect({
                nodeUrl: 'wss://some.url',
            });
            expect(polymesh instanceof Polymesh_1.Polymesh).toBe(true);
        }));
        test('should instantiate Context with a seed and return a Polymesh instance', () => __awaiter(void 0, void 0, void 0, function* () {
            const accountSeed = 'Alice'.padEnd(66, ' ');
            const createStub = mocks_1.dsMockUtils.getContextCreateStub();
            yield Polymesh_1.Polymesh.connect({
                nodeUrl: 'wss://some.url',
                accountSeed,
            });
            sinon_1.default.assert.calledOnce(createStub);
            sinon_1.default.assert.calledWith(createStub, {
                polymeshApi: mocks_1.dsMockUtils.getApiInstance(),
                middlewareApi: null,
                accountSeed,
                accountUri: undefined,
                accountMnemonic: undefined,
                keyring: undefined,
            });
        }));
        test('should instantiate Context with a keyring and return a Polymesh instance', () => __awaiter(void 0, void 0, void 0, function* () {
            const keyring = {};
            const createStub = mocks_1.dsMockUtils.getContextCreateStub();
            yield Polymesh_1.Polymesh.connect({
                nodeUrl: 'wss://some.url',
                keyring,
            });
            sinon_1.default.assert.calledOnce(createStub);
            sinon_1.default.assert.calledWith(createStub, {
                polymeshApi: mocks_1.dsMockUtils.getApiInstance(),
                middlewareApi: null,
                keyring,
                accountSeed: undefined,
                accountUri: undefined,
                accountMnemonic: undefined,
            });
        }));
        test('should instantiate Context with a ui keyring and return a Polymesh instance', () => __awaiter(void 0, void 0, void 0, function* () {
            const keyring = {};
            const createStub = mocks_1.dsMockUtils.getContextCreateStub();
            yield Polymesh_1.Polymesh.connect({
                nodeUrl: 'wss://some.url',
                keyring: { keyring },
            });
            sinon_1.default.assert.calledOnce(createStub);
            sinon_1.default.assert.calledWith(createStub, {
                polymeshApi: mocks_1.dsMockUtils.getApiInstance(),
                middlewareApi: null,
                keyring: { keyring },
                accountSeed: undefined,
                accountUri: undefined,
                accountMnemonic: undefined,
            });
        }));
        test('should instantiate Context with a uri and return a Polymesh instance', () => __awaiter(void 0, void 0, void 0, function* () {
            const accountUri = '//uri';
            const createStub = mocks_1.dsMockUtils.getContextCreateStub();
            yield Polymesh_1.Polymesh.connect({
                nodeUrl: 'wss://some.url',
                accountUri,
            });
            sinon_1.default.assert.calledOnce(createStub);
            sinon_1.default.assert.calledWith(createStub, {
                polymeshApi: mocks_1.dsMockUtils.getApiInstance(),
                middlewareApi: null,
                accountUri,
                accountSeed: undefined,
                accountMnemonic: undefined,
                keyring: undefined,
            });
        }));
        test('should instantiate Context with a mnemonic and return a Polymesh instance', () => __awaiter(void 0, void 0, void 0, function* () {
            const accountMnemonic = 'lorem ipsum dolor sit';
            const createStub = mocks_1.dsMockUtils.getContextCreateStub();
            yield Polymesh_1.Polymesh.connect({
                nodeUrl: 'wss://some.url',
                accountMnemonic,
            });
            sinon_1.default.assert.calledOnce(createStub);
            sinon_1.default.assert.calledWith(createStub, {
                polymeshApi: mocks_1.dsMockUtils.getApiInstance(),
                middlewareApi: null,
                accountMnemonic,
                accountSeed: undefined,
                accountUri: undefined,
                keyring: undefined,
            });
        }));
        test('should instantiate Context with middleware credentials and return a Polymesh instance', () => __awaiter(void 0, void 0, void 0, function* () {
            const accountUri = '//uri';
            const createStub = mocks_1.dsMockUtils.getContextCreateStub();
            const middleware = {
                link: 'someLink',
                key: 'someKey',
            };
            mocks_1.dsMockUtils.createApolloQueryStub(queries_1.heartbeat(), true);
            yield Polymesh_1.Polymesh.connect({
                nodeUrl: 'wss://some.url',
                accountUri,
                middleware,
            });
            sinon_1.default.assert.calledOnce(createStub);
            sinon_1.default.assert.calledWith(createStub, {
                polymeshApi: mocks_1.dsMockUtils.getApiInstance(),
                middlewareApi: mocks_1.dsMockUtils.getMiddlewareApi(),
                accountUri,
                accountSeed: undefined,
                accountMnemonic: undefined,
                keyring: undefined,
            });
        }));
        test('should throw an error if the Polymesh version does not satisfy the supported version range', () => __awaiter(void 0, void 0, void 0, function* () {
            jest.spyOn(semver_1.default, 'satisfies').mockImplementationOnce(() => false);
            let err;
            try {
                yield Polymesh_1.Polymesh.connect({
                    nodeUrl: 'wss://some.url',
                });
            }
            catch (e) {
                err = e;
            }
            expect(err.message).toBe('Unsupported Polymesh version. Please upgrade the SDK');
            expect(err.data.supportedVersionRange).toBe(constants_1.SUPPORTED_VERSION_RANGE);
        }));
        test('should throw an error if the middleware credentials are incorrect', () => __awaiter(void 0, void 0, void 0, function* () {
            const accountUri = '//uri';
            const middleware = {
                link: 'wrong',
                key: 'alsoWrong',
            };
            mocks_1.dsMockUtils.throwOnMiddlewareQuery(new Error('Forbidden'));
            let err;
            try {
                yield Polymesh_1.Polymesh.connect({
                    nodeUrl: 'wss://some.url',
                    accountUri,
                    middleware,
                });
            }
            catch (e) {
                err = e;
            }
            expect(err.message).toBe('Incorrect middleware URL or API key');
            mocks_1.dsMockUtils.throwOnMiddlewareQuery(new Error('Missing Authentication Token'));
            err = undefined;
            try {
                yield Polymesh_1.Polymesh.connect({
                    nodeUrl: 'wss://some.url',
                    accountUri,
                    middleware,
                });
            }
            catch (e) {
                err = e;
            }
            expect(err.message).toBe('Incorrect middleware URL or API key');
            // other errors are caught when performing queries later on
            mocks_1.dsMockUtils.throwOnMiddlewareQuery(new Error('Anything else'));
            err = undefined;
            try {
                yield Polymesh_1.Polymesh.connect({
                    nodeUrl: 'wss://some.url',
                    accountUri,
                    middleware,
                });
            }
            catch (e) {
                err = e;
            }
            expect(err).toBeUndefined();
        }));
        test('should set an optional signer for the polkadot API', () => __awaiter(void 0, void 0, void 0, function* () {
            const accountSeed = 'Alice'.padEnd(66, ' ');
            const createStub = mocks_1.dsMockUtils.getContextCreateStub();
            const signer = 'signer';
            yield Polymesh_1.Polymesh.connect({
                nodeUrl: 'wss://some.url',
                accountSeed,
                signer,
            });
            sinon_1.default.assert.calledOnce(createStub);
            sinon_1.default.assert.calledWith(createStub, {
                polymeshApi: mocks_1.dsMockUtils.getApiInstance(),
                middlewareApi: null,
                accountSeed,
                accountUri: undefined,
                accountMnemonic: undefined,
                keyring: undefined,
            });
            sinon_1.default.assert.calledWith(mocks_1.dsMockUtils.getApiInstance().setSigner, signer);
        }));
        test('should throw if Context fails in the connection process', () => __awaiter(void 0, void 0, void 0, function* () {
            mocks_1.dsMockUtils.throwOnApiCreation();
            const nodeUrl = 'wss://some.url';
            const polymeshApiPromise = Polymesh_1.Polymesh.connect({
                nodeUrl,
            });
            return expect(polymeshApiPromise).rejects.toThrow(`Error while connecting to "${nodeUrl}": "Error"`);
        }));
        test('should throw if Polkadot fails in the connection process', () => __awaiter(void 0, void 0, void 0, function* () {
            mocks_1.dsMockUtils.throwOnApiCreation(new Error());
            const nodeUrl = 'wss://some.url';
            const polymeshApiPromise = Polymesh_1.Polymesh.connect({
                nodeUrl,
            });
            return expect(polymeshApiPromise).rejects.toThrow(`Error while connecting to "${nodeUrl}": "The node couldn’t be reached"`);
        }));
        test('should throw if Context create method fails', () => {
            mocks_1.dsMockUtils.throwOnContextCreation();
            const nodeUrl = 'wss://some.url';
            const polymeshApiPromise = Polymesh_1.Polymesh.connect({
                nodeUrl,
            });
            return expect(polymeshApiPromise).rejects.toThrow(`Error while connecting to "${nodeUrl}": "Error"`);
        });
    });
    describe('method: getCurrentIdentity', () => {
        test('should return the current Identity', () => __awaiter(void 0, void 0, void 0, function* () {
            const polymesh = yield Polymesh_1.Polymesh.connect({
                nodeUrl: 'wss://some.url',
                accountUri: '//uri',
            });
            const context = mocks_1.dsMockUtils.getContextInstance();
            const [result, currentIdentity] = yield Promise.all([
                polymesh.getCurrentIdentity(),
                context.getCurrentIdentity(),
            ]);
            expect(result).toEqual(currentIdentity);
        }));
    });
    describe('method: onConnectionError', () => {
        test('should call the supplied listener when the event is emitted and return an unsubscribe callback', () => __awaiter(void 0, void 0, void 0, function* () {
            const polkadot = mocks_1.dsMockUtils.getApiInstance();
            const polymesh = yield Polymesh_1.Polymesh.connect({
                nodeUrl: 'wss://some.url',
                accountUri: '//uri',
            });
            const callback = sinon_1.default.stub();
            const unsub = polymesh.onConnectionError(callback);
            polkadot.emit('error');
            polkadot.emit('disconnected');
            unsub();
            polkadot.emit('error');
            sinon_1.default.assert.calledOnce(callback);
        }));
    });
    describe('method: onDisconnect', () => {
        test('should call the supplied listener when the event is emitted and return an unsubscribe callback', () => __awaiter(void 0, void 0, void 0, function* () {
            const polkadot = mocks_1.dsMockUtils.getApiInstance();
            const polymesh = yield Polymesh_1.Polymesh.connect({
                nodeUrl: 'wss://some.url',
                accountUri: '//uri',
            });
            const callback = sinon_1.default.stub();
            const unsub = polymesh.onDisconnect(callback);
            polkadot.emit('disconnected');
            polkadot.emit('error');
            unsub();
            polkadot.emit('disconnected');
            sinon_1.default.assert.calledOnce(callback);
        }));
    });
    describe('method: disconnect', () => {
        test('should call the underlying disconnect function', () => __awaiter(void 0, void 0, void 0, function* () {
            const polymesh = yield Polymesh_1.Polymesh.connect({
                nodeUrl: 'wss://some.url',
                accountUri: '//uri',
                middleware: {
                    link: 'someLink',
                    key: 'someKey',
                },
            });
            yield polymesh.disconnect();
            sinon_1.default.assert.calledOnce(mocks_1.dsMockUtils.getContextInstance().disconnect);
        }));
    });
    describe('method: addSigner', () => {
        test('should call the underlying addPair function', () => __awaiter(void 0, void 0, void 0, function* () {
            const pair = {
                address: '5EYCAe5ijAx5xEfZdpCna3grUpY1M9M5vLUH5vpmwV1EnaYR',
                publicKey: 'someKey',
                meta: {},
            };
            mocks_1.dsMockUtils.configureMocks({
                contextOptions: {
                    addPair: pair,
                },
            });
            const polymesh = yield Polymesh_1.Polymesh.connect({
                nodeUrl: 'wss://some.url',
                accountUri: '//uri',
                middleware: {
                    link: 'someLink',
                    key: 'someKey',
                },
            });
            let params = { accountSeed: '0x1' };
            let account = polymesh.addSigner(params);
            expect(account.address).toBe(pair.address);
            params = { accountMnemonic: 'something' };
            account = polymesh.addSigner(params);
            expect(account.address).toBe(pair.address);
            params = { accountUri: '//Something' };
            account = polymesh.addSigner(params);
            expect(account.address).toBe(pair.address);
        }));
    });
    describe('method: setSigner', () => {
        test('should call the underlying setPair function', () => __awaiter(void 0, void 0, void 0, function* () {
            const polymesh = yield Polymesh_1.Polymesh.connect({
                nodeUrl: 'wss://some.url',
                accountUri: '//uri',
                middleware: {
                    link: 'someLink',
                    key: 'someKey',
                },
            });
            const address = 'address';
            polymesh.setSigner(address);
            sinon_1.default.assert.calledWith(mocks_1.dsMockUtils.getContextInstance().setPair, address);
        }));
    });
});
//# sourceMappingURL=Polymesh.js.map