Skip to content

Commit

Permalink
test: approvals messages and service tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mateuszjasiuk committed Feb 12, 2024
1 parent 6535315 commit 796e918
Show file tree
Hide file tree
Showing 5 changed files with 335 additions and 7 deletions.
2 changes: 1 addition & 1 deletion apps/extension/src/background/approvals/handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ describe.only("approvals handler", () => {
jest.clearAllMocks();
});

it("it call proper handlers", () => {
test("handlers switch", () => {
const service: jest.Mocked<ApprovalsService> = createMockInstance(
ApprovalsService as any
);
Expand Down
128 changes: 128 additions & 0 deletions apps/extension/src/background/approvals/messages.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { TxType } from "@namada/shared";
import { ROUTE } from "./constants";
import {
ConnectInterfaceResponseMsg,
MessageType,
RejectSignatureMsg,
RejectTxMsg,
RevokeConnectionMsg,
SubmitApprovedSignatureMsg,
SubmitApprovedTxMsg,
} from "./messages";

jest.mock("webextension-polyfill", () => ({}));

describe("approvals messages", () => {
test("valid RejectTxMsg", () => {
const msg = new RejectTxMsg("msgId");

expect(msg.type()).toBe(MessageType.RejectTx);
expect(msg.route()).toBe(ROUTE);
expect(msg.validate()).toBeUndefined();
});

test("invalid RejectTxMsg", () => {
const msg = new RejectTxMsg("msgId");
(msg as any).msgId = undefined;

expect(() => msg.validate()).toThrow();
});

test("valid SubmitApprovedTxMsg", () => {
const msg = new SubmitApprovedTxMsg(TxType.Bond, "msgId");

expect(msg.type()).toBe(MessageType.SubmitApprovedTx);
expect(msg.route()).toBe(ROUTE);
expect(msg.validate()).toBeUndefined();
});

test("invalid SubmitApprovedTxMsg", () => {
const msg = new SubmitApprovedTxMsg(TxType.Bond, "msgId");
(msg as any).msgId = undefined;

expect(() => msg.validate()).toThrow();

const msg2 = new SubmitApprovedTxMsg(TxType.Bond, "msgId");
(msg2 as any).txType = undefined;

expect(() => msg2.validate()).toThrow();
});

test("valid RejectSignatureMsg", () => {
const msg = new RejectSignatureMsg("msgId");

expect(msg.type()).toBe(MessageType.RejectSignature);
expect(msg.route()).toBe(ROUTE);
expect(msg.validate()).toBeUndefined();
});

test("invalid RejectSignatureMsg", () => {
const msg = new RejectSignatureMsg("msgId");
(msg as any).msgId = undefined;

expect(() => msg.validate()).toThrow();
});

test("valid SubmitApprovedSignatureMsg", () => {
const msg = new SubmitApprovedSignatureMsg("msgId", "signer");

expect(msg.type()).toBe(MessageType.SubmitApprovedSignature);
expect(msg.route()).toBe(ROUTE);
expect(msg.validate()).toBeUndefined();
});

test("invalid SubmitApprovedSignatureMsg", () => {
const msg = new SubmitApprovedSignatureMsg("msgId", "signer");
(msg as any).msgId = undefined;

expect(() => msg.validate()).toThrow();

const msg2 = new SubmitApprovedSignatureMsg("msgId", "signer");
(msg2 as any).signer = undefined;

expect(() => msg2.validate()).toThrow();
});

test("valid ConnectInterfaceResponseMsg", () => {
const msg = new ConnectInterfaceResponseMsg(0, "interface", true);

expect(msg.type()).toBe(MessageType.ConnectInterfaceResponse);
expect(msg.route()).toBe(ROUTE);
expect(msg.validate()).toBeUndefined();
});

test("invalid ConnectInterfaceResponseMsg", () => {
const msg = new ConnectInterfaceResponseMsg(0, "interface", true);

(msg as any).interfaceTabId = undefined;

expect(() => msg.validate()).toThrow();

const msg2 = new ConnectInterfaceResponseMsg(0, "interface", true);
(msg2 as any).interfaceOrigin = undefined;

expect(() => msg2.validate()).toThrow();

const msg3 = new ConnectInterfaceResponseMsg(0, "interface", true);
(msg3 as any).allowConnection = undefined;

expect(() => msg3.validate()).toThrow();
});

test("valid RevokeConnectionMsg", () => {
const msg = new RevokeConnectionMsg("");

expect(msg.type()).toBe(MessageType.RevokeConnection);
expect(msg.route()).toBe(ROUTE);
expect(msg.validate()).toBeUndefined();
});

test("invalid RevokeConnectionMsg", () => {
const msg = new RevokeConnectionMsg("");

(msg as any).originToRevoke = undefined;

expect(() => msg.validate()).toThrow();
});
});
10 changes: 7 additions & 3 deletions apps/extension/src/background/approvals/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ROUTE } from "./constants";

import { validateProps } from "utils";

enum MessageType {
export enum MessageType {
SubmitApprovedTx = "submit-approved-tx",
RejectTx = "reject-tx",
SubmitApprovedSignature = "submit-approved-signature",
Expand Down Expand Up @@ -127,13 +127,17 @@ export class ConnectInterfaceResponseMsg extends Message<void> {
}

validate(): void {
if (!this.interfaceTabId) {
if (typeof this.interfaceTabId === "undefined") {
throw new Error("interfaceTabId not set");
}

if (!this.interfaceOrigin) {
throw new Error("interfaceOrigin not set");
}

if (typeof this.allowConnection === "undefined") {
throw new Error("allowConnection not set");
}
}

route(): string {
Expand All @@ -155,7 +159,7 @@ export class RevokeConnectionMsg extends Message<void> {
}

validate(): void {
if (!this.originToRevoke) {
if (typeof this.originToRevoke === "undefined") {
throw new Error("originToRevoke not set");
}
}
Expand Down
188 changes: 188 additions & 0 deletions apps/extension/src/background/approvals/service.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { KeyRingService, TabStore } from "background/keyring";
import { LedgerService } from "background/ledger";
import { VaultService } from "background/vault";
import createMockInstance from "jest-create-mock-instance";
import { KVStoreMock } from "test/init";
import { ApprovalsService } from "./service";
import { ApprovedOriginsStore, TxStore } from "./types";

jest.mock("webextension-polyfill", () => ({
runtime: {
getURL: () => "url",
},
}));

describe.only("approvals service", () => {
let service: ApprovalsService;
let keyRingService: jest.Mocked<KeyRingService>;
let dataStore: KVStoreMock<string>;

beforeEach(() => {
jest.clearAllMocks();

const txStore = new KVStoreMock<TxStore>("TxStore");
dataStore = new KVStoreMock<string>("DataStore");
const connectedTabsStore = new KVStoreMock<TabStore[]>("TabStore");
const approvedOriginsStore = new KVStoreMock<ApprovedOriginsStore>(
"ApprovedOriginsStore"
);
keyRingService = createMockInstance(KeyRingService as any);
const ledgerService: jest.Mocked<LedgerService> = createMockInstance(
LedgerService as any
);
const vaultService: jest.Mocked<VaultService> = createMockInstance(
VaultService as any
);

service = new ApprovalsService(
txStore,
dataStore,
connectedTabsStore,
approvedOriginsStore,
keyRingService,
ledgerService,
vaultService
);
});

describe("approveSignature", () => {
it("should add popupTabId to resolverMap", async () => {
const tabId = 1;
const sigResponse = {
hash: "hash",
signature: "sig",
};

jest.spyOn(service as any, "getPopupTabId").mockResolvedValue(tabId);
const signaturePromise = service.approveSignature("signer", "data");

await new Promise((resolve) =>
setTimeout(() => {
resolve(true);
})
);

(service as any).resolverMap[tabId].resolve(sigResponse);
const signature = await signaturePromise;

expect(signature).toEqual(sigResponse);
});

it("should throw an error when popupTabId is not present", async () => {
jest.spyOn(service as any, "getPopupTabId").mockResolvedValue(undefined);

expect(service.approveSignature("signer", "data")).rejects.toBeDefined();
});

it("should throw an error when popupTabId is already in the map", async () => {
const tabId = 1;
const sigResponse = {
hash: "hash",
signature: "sig",
};
jest.spyOn(service as any, "getPopupTabId").mockResolvedValue(tabId);
(service as any).resolverMap[tabId] = sigResponse;

expect(service.approveSignature("signer", "data")).rejects.toBeDefined();
});
});

describe("submitSignature", () => {
it("should add popupTabId to resolverMap", async () => {
const tabId = 1;
const sigResponse = {
hash: "hash",
signature: "sig",
};

jest.spyOn(service as any, "getPopupTabId").mockResolvedValue(tabId);
jest.spyOn(dataStore, "get").mockResolvedValueOnce("data");
jest
.spyOn(keyRingService, "signArbitrary")
.mockResolvedValue(sigResponse);
const signer = "signer";
const signaturePromise = service.approveSignature(signer, "data");

await new Promise((resolve) =>
setTimeout(() => {
resolve(true);
})
);
await service.submitSignature(tabId, "msgId", signer);

expect(await signaturePromise).toEqual(sigResponse);
});

it("should throw an error when resolvers are not present", async () => {
const tabId = 1;
const signer = "signer";
jest.spyOn(dataStore, "get").mockResolvedValueOnce("data");

expect(
service.submitSignature(tabId, "msgId", signer)
).rejects.toBeDefined();
});

it("should throw an error when data is not present", async () => {
const tabId = 1;
const signer = "signer";
const sigResponse = {
hash: "hash",
signature: "sig",
};
(service as any).resolverMap[tabId] = sigResponse;
jest.spyOn(dataStore, "get").mockResolvedValueOnce(undefined);

expect(
service.submitSignature(tabId, "msgId", signer)
).rejects.toBeDefined();
});

it("should reject promise if can't sign", async () => {
const tabId = 1;

jest.spyOn(service as any, "getPopupTabId").mockResolvedValue(tabId);
jest.spyOn(dataStore, "get").mockResolvedValueOnce("data");
jest
.spyOn(keyRingService, "signArbitrary")
.mockRejectedValue("Can't sign");
const signer = "signer";

await new Promise((resolve) =>
setTimeout(() => {
resolve(true);
})
);

expect(
service.submitSignature(tabId, "msgId", signer)
).rejects.toBeDefined();
});
});

describe("submitSignature", () => {
it("should reject resolver", async () => {
const tabId = 1;

jest.spyOn(service as any, "getPopupTabId").mockResolvedValue(tabId);
const signer = "signer";
const signaturePromise = service.approveSignature(signer, "data");

await new Promise((resolve) =>
setTimeout(() => {
resolve(true);
})
);
await service.rejectSignature(tabId, "msgId");

expect(signaturePromise).rejects.toEqual(undefined);
});

it("should throw an error if resolver is not found", async () => {
const tabId = 1;

expect(service.rejectSignature(tabId, "msgId")).rejects.toBeDefined();
});
});
});
Loading

0 comments on commit 796e918

Please sign in to comment.