Skip to content

Commit

Permalink
[chore] Additional Tests (#512)
Browse files Browse the repository at this point in the history
* Create Spinner.test.tsx

* Create ScopedLocalStorage.test.ts

* WalletSDKUI tests

* Update ScopedLocalStorage.test.ts

* aes256gcm tests

* Update ScopedLocalStorage.test.ts
  • Loading branch information
erin-at-work authored May 10, 2022
1 parent 61fe01d commit 9614ef4
Show file tree
Hide file tree
Showing 9 changed files with 337 additions and 6 deletions.
14 changes: 8 additions & 6 deletions jest.setup.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import "@testing-library/jest-dom";

import webcrypto from "crypto";
import { Crypto } from "@peculiar/webcrypto";
import { TextDecoder, TextEncoder } from "util";

Object.defineProperty(global.self, "crypto", {
value: {
getRandomValues: (arr: Uint8Array) => webcrypto.randomBytes(arr.length),
},
});
global.crypto = new Crypto();

global.TextEncoder = TextEncoder;

// @ts-expect-error Use util TextDecoder
global.TextDecoder = TextDecoder;
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"@babel/plugin-transform-react-jsx": "^7.17.3",
"@babel/preset-env": "^7.16.11",
"@babel/preset-typescript": "^7.16.7",
"@peculiar/webcrypto": "^1.3.3",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/preact": "^2.0.1",
"@types/bn.js": "^4.11.6",
Expand Down
34 changes: 34 additions & 0 deletions src/components/Spinner.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { render } from "@testing-library/preact";
import { h } from "preact";

import { Spinner } from "./Spinner";

const renderSpinner = (props: { size?: number; color?: string }) =>
render(<Spinner {...props} />);

describe("Spinner", () => {
test("renders default", () => {
renderSpinner({});

const svgStyle = document.querySelector("svg")?.style;
const svgCircle = document.querySelector("circle")?.style;

expect(svgStyle?.width).toEqual("64px");
expect(svgStyle?.height).toEqual("64px");
expect(svgCircle?.stroke).toEqual("#000");
});

test("renders overrides", () => {
renderSpinner({
size: 200,
color: "red",
});

const svgStyle = document.querySelector("svg")?.style;
const svgCircle = document.querySelector("circle")?.style;

expect(svgStyle?.width).toEqual("200px");
expect(svgStyle?.height).toEqual("200px");
expect(svgCircle?.stroke).toEqual("red");
});
});
38 changes: 38 additions & 0 deletions src/lib/ScopedLocalStorage.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { ScopedLocalStorage } from "./ScopedLocalStorage";

describe("ScopedLocalStorage", () => {
describe("public methods", () => {
afterEach(() => localStorage.clear());

const scopedLocalStorage = new ScopedLocalStorage("-testing");
test("@setItem", () => {
scopedLocalStorage.setItem("foo", "bar");

expect(localStorage.getItem("-testing:foo")).toEqual("bar");
expect(localStorage.length).toEqual(1);
});

test("@getItem", () => {
scopedLocalStorage.setItem("foo", "bar");
const getVal = scopedLocalStorage.getItem("foo");

expect(getVal).toEqual("bar");
});

test("@removeItem", () => {
scopedLocalStorage.removeItem("foo");

expect(localStorage.length).toEqual(0);
});

test("@clear", () => {
scopedLocalStorage.setItem("foo1", "bar1");
scopedLocalStorage.setItem("foo2", "bar2");
scopedLocalStorage.setItem("foo3", "bar3");
expect(localStorage.length).toEqual(3);

scopedLocalStorage.clear();
expect(localStorage.length).toEqual(0);
});
});
});
121 changes: 121 additions & 0 deletions src/provider/WalletSDKUI.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import { render } from "@testing-library/preact";
import { Session } from "inspector";
import { Observable } from "rxjs";

import { LinkFlow } from "../components/LinkFlow";
import { Snackbar } from "../components/Snackbar";
import { WalletSDKUI } from "./WalletSDKUI";

describe("WalletSDKUI", () => {
const walletSDKUI = new WalletSDKUI({
darkMode: false,
version: "1.2.1",
// @ts-expect-error mock session
session: new Session(),
linkAPIUrl: "http://link-url.com",
connected$: new Observable(),
});

render("<div />");

test("@attach", () => {
walletSDKUI.attach();

expect(walletSDKUI).toMatchObject({
attached: true,
});

const containerClass = document.getElementsByClassName("-cbwsdk-css-reset");
expect(containerClass.length).toEqual(1);
});

test("@showConnecting: isUnlinkedErrorState - false", () => {
const snackbarMock = jest
.spyOn(Snackbar.prototype, "presentItem")
.mockImplementation(() => () => {});

const onResetConnection = () => {};
const onCancel = () => {};
walletSDKUI.showConnecting({
onResetConnection,
onCancel,
});

expect(snackbarMock).toHaveBeenCalledWith({
message: "Confirm on phone",
menuItems: [
{
isRed: true,
info: "Cancel transaction",
svgWidth: "11",
svgHeight: "11",
path: "M10.3711 1.52346L9.21775 0.370117L5.37109 4.21022L1.52444 0.370117L0.371094 1.52346L4.2112 5.37012L0.371094 9.21677L1.52444 10.3701L5.37109 6.53001L9.21775 10.3701L10.3711 9.21677L6.53099 5.37012L10.3711 1.52346Z",
defaultFillRule: "inherit",
defaultClipRule: "inherit",
onClick: onCancel,
},
{
isRed: false,
info: "Reset connection",
svgWidth: "10",
svgHeight: "11",
path: "M5.00008 0.96875C6.73133 0.96875 8.23758 1.94375 9.00008 3.375L10.0001 2.375V5.5H9.53133H7.96883H6.87508L7.80633 4.56875C7.41258 3.3875 6.31258 2.53125 5.00008 2.53125C3.76258 2.53125 2.70633 3.2875 2.25633 4.36875L0.812576 3.76875C1.50008 2.125 3.11258 0.96875 5.00008 0.96875ZM2.19375 6.43125C2.5875 7.6125 3.6875 8.46875 5 8.46875C6.2375 8.46875 7.29375 7.7125 7.74375 6.63125L9.1875 7.23125C8.5 8.875 6.8875 10.0312 5 10.0312C3.26875 10.0312 1.7625 9.05625 1 7.625L0 8.625V5.5H0.46875H2.03125H3.125L2.19375 6.43125Z",
defaultFillRule: "evenodd",
defaultClipRule: "evenodd",
onClick: onResetConnection,
},
],
});
});

test("@showConnecting: isUnlinkedErrorState - true", () => {
const snackbarMock = jest.spyOn(Snackbar.prototype, "presentItem");

const onResetConnection = () => {};
const onCancel = () => {};
walletSDKUI.showConnecting({
isUnlinkedErrorState: true,
onResetConnection,
onCancel,
});

expect(snackbarMock).toHaveBeenCalledWith({
autoExpand: true,
message: "Connection lost",
menuItems: [
{
isRed: false,
info: "Reset connection",
svgWidth: "10",
svgHeight: "11",
path: "M5.00008 0.96875C6.73133 0.96875 8.23758 1.94375 9.00008 3.375L10.0001 2.375V5.5H9.53133H7.96883H6.87508L7.80633 4.56875C7.41258 3.3875 6.31258 2.53125 5.00008 2.53125C3.76258 2.53125 2.70633 3.2875 2.25633 4.36875L0.812576 3.76875C1.50008 2.125 3.11258 0.96875 5.00008 0.96875ZM2.19375 6.43125C2.5875 7.6125 3.6875 8.46875 5 8.46875C6.2375 8.46875 7.29375 7.7125 7.74375 6.63125L9.1875 7.23125C8.5 8.875 6.8875 10.0312 5 10.0312C3.26875 10.0312 1.7625 9.05625 1 7.625L0 8.625V5.5H0.46875H2.03125H3.125L2.19375 6.43125Z",
defaultFillRule: "evenodd",
defaultClipRule: "evenodd",
onClick: onResetConnection,
},
],
});
});

test("@setConnectDisabled", () => {
const linkFlowMock = jest.spyOn(LinkFlow.prototype, "setConnectDisabled");
walletSDKUI.setConnectDisabled(true);

expect(linkFlowMock).toBeCalledWith(true);
});

test("@requestEthereumAccounts", () => {
const linkFlowMock = jest.spyOn(LinkFlow.prototype, "open");
const onCancel = () => {};
walletSDKUI.requestEthereumAccounts({ onCancel });

expect(linkFlowMock).toBeCalledWith({ onCancel });
});

test("@hideEthereumAccounts", () => {
const linkFlowMock = jest.spyOn(LinkFlow.prototype, "close");
walletSDKUI.hideRequestEthereumAccounts();

expect(linkFlowMock).toBeCalled();
});
});
13 changes: 13 additions & 0 deletions src/provider/WalletSDKUI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export class WalletSDKUI implements WalletUI {
this.linkFlow.setConnectDisabled(connectDisabled);
}

/* istanbul ignore next */
addEthereumChain(_options: {
onCancel: (error?: Error) => void;
onApprove: () => void;
Expand All @@ -73,6 +74,7 @@ export class WalletSDKUI implements WalletUI {
// no-op
}

/* istanbul ignore next */
watchAsset(_options: {
onCancel: (error?: Error) => void;
onApprove: () => void;
Expand All @@ -85,6 +87,7 @@ export class WalletSDKUI implements WalletUI {
// no-op
}

/* istanbul ignore next */
switchEthereumChain(_options: {
onCancel: (error?: Error) => void;
onApprove: () => void;
Expand All @@ -103,6 +106,7 @@ export class WalletSDKUI implements WalletUI {
this.linkFlow.close();
}

/* istanbul ignore next */
signEthereumMessage(_: {
request: SignEthereumMessageRequest;
onSuccess: (response: SignEthereumMessageResponse) => void;
Expand All @@ -111,6 +115,7 @@ export class WalletSDKUI implements WalletUI {
// No-op
}

/* istanbul ignore next */
signEthereumTransaction(_: {
request: SignEthereumTransactionRequest;
onSuccess: (response: SignEthereumTransactionResponse) => void;
Expand All @@ -119,6 +124,7 @@ export class WalletSDKUI implements WalletUI {
// No-op
}

/* istanbul ignore next */
submitEthereumTransaction(_: {
request: SubmitEthereumTransactionRequest;
onSuccess: (response: SubmitEthereumTransactionResponse) => void;
Expand All @@ -127,6 +133,7 @@ export class WalletSDKUI implements WalletUI {
// No-op
}

/* istanbul ignore next */
ethereumAddressFromSignedMessage(_: {
request: EthereumAddressFromSignedMessageRequest;
onSuccess: (response: EthereumAddressFromSignedMessageResponse) => void;
Expand Down Expand Up @@ -188,26 +195,32 @@ export class WalletSDKUI implements WalletUI {
return this.snackbar.presentItem(snackbarProps);
}

/* istanbul ignore next */
reloadUI(): void {
document.location.reload();
}

/* istanbul ignore next */
inlineAccountsResponse(): boolean {
return false;
}

/* istanbul ignore next */
inlineAddEthereumChain(_chainId: string): boolean {
return false;
}

/* istanbul ignore next */
inlineWatchAsset(): boolean {
return false;
}

/* istanbul ignore next */
inlineSwitchEthereumChain(): boolean {
return false;
}

/* istanbul ignore next */
isStandalone(): boolean {
return false;
}
Expand Down
61 changes: 61 additions & 0 deletions src/relay/aes256gcm.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { randomBytesHex } from "../util";
import { decrypt, encrypt } from "./aes256gcm";

const secret =
"c356fe708ea7bbf7b1cc9ff9813c32772b6e0d16332da4c031ba9ea88be9b5ed";

describe("aes256gcm", () => {
test("encrypt/decrypt", async () => {
const randSecret = randomBytesHex(32);
const encrypted = await encrypt("plain text string", randSecret);

expect(encrypted.length).toEqual(90);

// decrypted output matches original input
decrypt(encrypted, randSecret).subscribe({
next: decrypted => {
expect(decrypted).toBe("plain text string");
},
});
});

test("decrypt", () => {
const cipherText =
"06593325a922a928913b5c6ea26f848c4545bcea4e26c4f5ee745316ff22b2780aeccc565730514b2820a94b03f5f89fe7542a35bbdd87a1d52a4352f49482781113db09266c668696778e0a94bc9f866f1e92e7262fd0bb811838284cc64cbc4552b33e9c6fb2582cea4f49471d6d46a16a5c8ac83ee8483ed4dc01f1fde3bfd7a2f173715e0a8d09dd4907483f096a845bff698831ea277c1ca4223d3f6073174cb35119d0a795c1a9cb4f32ee1dcc254d8931";
const sampleDataResult = {
type: "WEB3_RESPONSE",
id: "791fe0ec3dc3de49",
response: {
method: "requestEthereumAccounts",
result: ["0xdf0635793e91d4f8e7426dbd9ed08471186f428d"],
},
};

decrypt(cipherText, secret).subscribe({
next: value => {
expect(sampleDataResult).toEqual(value);
},
});
});

test("errors", async () => {
await expect(encrypt("plain text string", "123456")).rejects.toThrowError(
"secret must be 256 bits",
);

expect(() => decrypt("plain stext string", "123456")).toThrowError(
"secret must be 256 bits",
);

await expect(
decrypt("text", secret).subscribe(
() => {
fail("expected error");
},
error => {
expect(error).toBe("expected error");
},
),
);
});
});
2 changes: 2 additions & 0 deletions src/relay/aes256gcm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ export async function encrypt(
* @param cipherText hex string representation of bytes in the order: initialization vector (iv),
* auth tag, encrypted plaintext. IV is 12 bytes. Auth tag is 16 bytes.
* @param secret hex string representation of 32-byte secret
*
* TODO: Update rxjs for promises
*/
export function decrypt(
cipherText: string,
Expand Down
Loading

0 comments on commit 9614ef4

Please sign in to comment.