Skip to content

Commit d11a9c9

Browse files
committed
chore: add vitest, migrate tests
1 parent 8b638d6 commit d11a9c9

13 files changed

Lines changed: 1391 additions & 1566 deletions

File tree

packages/client/package.json

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"author": "Coinbase, Inc.",
2424
"license": "Apache-2.0",
2525
"scripts": {
26-
"test": "jest",
26+
"test": "vitest",
2727
"test:coverage": "yarn test:unit && open coverage/lcov-report/index.html",
2828
"prebuild": "rm -rf ./dist && node -p \"'export const LIB_VERSION = \\'' + require('./package.json').version + '\\';'\" > src/version.ts",
2929
"build": "tsc -p ./tsconfig.build.json && tsc-alias",
@@ -53,15 +53,12 @@
5353
"@babel/preset-typescript": "^7.22.5",
5454
"@peculiar/webcrypto": "^1.4.3",
5555
"@react-native-async-storage/async-storage": "^1.24.0",
56-
"@testing-library/jest-dom": "^5.17.0",
5756
"@testing-library/react": "14.3.1",
58-
"@types/jest": "^27.5.2",
5957
"@types/node": "^14.18.54",
6058
"@types/react": "^18.0.25",
6159
"@types/react-native": "^0.70.6",
6260
"@typescript-eslint/eslint-plugin": "^6.2.0",
6361
"@typescript-eslint/parser": "^6.2.0",
64-
"babel-jest": "^27.5.1",
6562
"eslint": "^8.45.0",
6663
"eslint-config-prettier": "^8.8.0",
6764
"eslint-plugin-prettier": "^5.0.0",
@@ -71,12 +68,9 @@
7168
"eslint-plugin-simple-import-sort": "^10.0.0",
7269
"eslint-plugin-unused-imports": "^3.0.0",
7370
"expo-web-browser": "^13.0.3",
74-
"jest": "^27.5.1",
75-
"jest-chrome": "^0.7.2",
76-
"jest-websocket-mock": "^2.4.0",
71+
"jsdom": "^26.0.0",
7772
"nodemon": "^3.1.0",
7873
"prettier": "^3.0.0",
79-
"ts-jest": "^27.1.5",
8074
"ts-node": "^10.9.1",
8175
"tsc-alias": "^1.8.8",
8276
"tslib": "^2.6.0",

packages/client/src/MWPClient.test.ts

Lines changed: 44 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { beforeEach, beforeAll, afterAll, describe, expect, it, vi } from 'vitest';
12
import { postRequestToWallet } from './components/communication/postRequestToWallet';
23
import { KeyManager } from './components/key/KeyManager';
34
import { MWPClient } from './MWPClient';
@@ -16,30 +17,30 @@ import { ScopedAsyncStorage } from ':core/storage/ScopedAsyncStorage';
1617
import { fetchRPCRequest } from ':core/util/utils';
1718
import { Wallets } from ':core/wallet';
1819

19-
jest.mock(':core/util/utils', () => {
20-
const actual = jest.requireActual(':core/util/utils');
20+
vi.mock(':core/util/utils', async () => {
21+
const actual = await vi.importActual(':core/util/utils');
2122
return {
2223
...actual,
23-
fetchRPCRequest: jest.fn(),
24+
fetchRPCRequest: vi.fn(),
2425
};
2526
});
2627

27-
jest.mock('./components/communication/postRequestToWallet');
28+
vi.mock('./components/communication/postRequestToWallet');
2829

29-
jest.mock('expo-web-browser', () => ({
30-
openAuthSessionAsync: jest.fn(),
31-
dismissBrowser: jest.fn(),
30+
vi.mock('expo-web-browser', () => ({
31+
openAuthSessionAsync: vi.fn(),
32+
dismissBrowser: vi.fn(),
3233
}));
3334

34-
jest.mock('./components/key/KeyManager');
35-
const storageStoreSpy = jest.spyOn(ScopedAsyncStorage.prototype, 'storeObject');
36-
const storageClearSpy = jest.spyOn(ScopedAsyncStorage.prototype, 'clear');
35+
vi.mock('./components/key/KeyManager');
36+
const storageStoreSpy = vi.spyOn(ScopedAsyncStorage.prototype, 'storeObject');
37+
const storageClearSpy = vi.spyOn(ScopedAsyncStorage.prototype, 'clear');
3738

38-
jest.mock(':core/cipher/cipher', () => ({
39-
decryptContent: jest.fn(),
40-
encryptContent: jest.fn(),
41-
exportKeyToHexString: jest.fn(),
42-
importKeyFromHexString: jest.fn(),
39+
vi.mock(':core/cipher/cipher', () => ({
40+
decryptContent: vi.fn(),
41+
encryptContent: vi.fn(),
42+
exportKeyToHexString: vi.fn(),
43+
importKeyFromHexString: vi.fn(),
4344
}));
4445

4546
const mockCryptoKey = {} as CryptoKey;
@@ -64,7 +65,7 @@ const mockWallet = Wallets.CoinbaseSmartWallet;
6465
describe('MWPClient', () => {
6566
let client: MWPClient;
6667
let mockMetadata: AppMetadata;
67-
let mockKeyManager: jest.Mocked<KeyManager>;
68+
let mockKeyManager: ReturnType<typeof vi.mocked<KeyManager>>;
6869

6970
beforeEach(async () => {
7071
mockMetadata = {
@@ -73,18 +74,18 @@ describe('MWPClient', () => {
7374
customScheme: 'myapp://',
7475
};
7576

76-
(postRequestToWallet as jest.Mock).mockResolvedValue(mockSuccessResponse);
77+
(postRequestToWallet as ReturnType<typeof vi.fn>).mockResolvedValue(mockSuccessResponse);
7778

7879
mockKeyManager = new KeyManager({
7980
wallet: mockWallet,
80-
}) as jest.Mocked<KeyManager>;
81-
(KeyManager as jest.Mock).mockImplementation(() => mockKeyManager);
81+
}) as ReturnType<typeof vi.mocked<KeyManager>>;
82+
(KeyManager as ReturnType<typeof vi.fn>).mockImplementation(() => mockKeyManager);
8283
storageStoreSpy.mockReset();
8384

84-
(importKeyFromHexString as jest.Mock).mockResolvedValue(mockCryptoKey);
85-
(exportKeyToHexString as jest.Mock).mockResolvedValueOnce('0xPublicKey');
85+
(importKeyFromHexString as ReturnType<typeof vi.fn>).mockResolvedValue(mockCryptoKey);
86+
(exportKeyToHexString as ReturnType<typeof vi.fn>).mockResolvedValueOnce('0xPublicKey');
8687
mockKeyManager.getSharedSecret.mockResolvedValue(mockCryptoKey);
87-
(encryptContent as jest.Mock).mockResolvedValueOnce(encryptedData);
88+
(encryptContent as ReturnType<typeof vi.fn>).mockResolvedValueOnce(encryptedData);
8889

8990
client = await MWPClient.createInstance({
9091
metadata: mockMetadata,
@@ -106,8 +107,21 @@ describe('MWPClient', () => {
106107
});
107108

108109
describe('handshake', () => {
110+
it('should throw an error if failure in response.content', async () => {
111+
const mockResponse: RPCResponseMessage = {
112+
id: '1-2-3-4-5',
113+
requestId: '1-2-3-4-5-6',
114+
sender: '0xPublicKey',
115+
content: { failure: mockError },
116+
timestamp: new Date(),
117+
};
118+
(postRequestToWallet as ReturnType<typeof vi.fn>).mockResolvedValue(mockResponse);
119+
120+
await expect(client.handshake()).rejects.toThrowError(mockError);
121+
});
122+
109123
it('should perform a successful handshake', async () => {
110-
(decryptContent as jest.Mock).mockResolvedValueOnce({
124+
(decryptContent as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
111125
result: {
112126
value: ['0xAddress'],
113127
},
@@ -130,26 +144,13 @@ describe('MWPClient', () => {
130144
expect(storageStoreSpy).toHaveBeenCalledWith('walletCapabilities', mockCapabilities);
131145
expect(storageStoreSpy).toHaveBeenCalledWith('accounts', ['0xAddress']);
132146

133-
expect(client.request({ method: 'eth_requestAccounts' })).resolves.toEqual(['0xAddress']);
134-
});
135-
136-
it('should throw an error if failure in response.content', async () => {
137-
const mockResponse: RPCResponseMessage = {
138-
id: '1-2-3-4-5',
139-
requestId: '1-2-3-4-5',
140-
sender: '0xPublicKey',
141-
content: { failure: mockError },
142-
timestamp: new Date(),
143-
};
144-
(postRequestToWallet as jest.Mock).mockResolvedValue(mockResponse);
145-
146-
await expect(client.handshake()).rejects.toThrowError(mockError);
147+
await expect(client.request({ method: 'eth_requestAccounts' })).resolves.toEqual(['0xAddress']);
147148
});
148149
});
149150

150151
describe('request', () => {
151152
beforeAll(() => {
152-
jest.spyOn(ScopedAsyncStorage.prototype, 'loadObject').mockImplementation(async (key) => {
153+
vi.spyOn(ScopedAsyncStorage.prototype, 'loadObject').mockImplementation(async (key) => {
153154
switch (key) {
154155
case 'accounts':
155156
return ['0xAddress'];
@@ -162,7 +163,7 @@ describe('MWPClient', () => {
162163
});
163164

164165
afterAll(() => {
165-
jest.spyOn(ScopedAsyncStorage.prototype, 'loadObject').mockRestore();
166+
vi.mocked(ScopedAsyncStorage.prototype.loadObject).mockRestore();
166167
});
167168

168169
it('should perform a successful request', async () => {
@@ -171,7 +172,7 @@ describe('MWPClient', () => {
171172
params: ['0xMessage', '0xAddress'],
172173
};
173174

174-
(decryptContent as jest.Mock).mockResolvedValueOnce({
175+
(decryptContent as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
175176
result: {
176177
value: '0xSignature',
177178
},
@@ -212,7 +213,7 @@ describe('MWPClient', () => {
212213
params: [],
213214
};
214215

215-
(decryptContent as jest.Mock).mockResolvedValueOnce({
216+
(decryptContent as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
216217
result: {
217218
value: '0xSignature',
218219
},
@@ -252,7 +253,7 @@ describe('MWPClient', () => {
252253
params: ['0xMessage', '0xAddress'],
253254
};
254255

255-
(decryptContent as jest.Mock).mockResolvedValueOnce({
256+
(decryptContent as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
256257
result: {
257258
error: mockError,
258259
},
@@ -267,7 +268,7 @@ describe('MWPClient', () => {
267268
params: [{ chainId: '0x1' }],
268269
};
269270

270-
(decryptContent as jest.Mock).mockResolvedValueOnce({
271+
(decryptContent as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
271272
result: {
272273
value: null,
273274
},

packages/client/src/components/communication/postRequestToWallet.test.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
1+
import { describe, it, expect, beforeEach, vi } from 'vitest';
12
import * as WebBrowser from 'expo-web-browser';
23

34
import { postRequestToWallet } from './postRequestToWallet';
45
import { decodeResponseURLParams, encodeRequestURLParams } from './utils/encoding';
56
import { RPCRequestMessage, RPCResponseMessage } from ':core/message';
67
import { Wallet } from ':core/wallet';
78

8-
jest.mock('expo-web-browser', () => ({
9-
openAuthSessionAsync: jest.fn(),
10-
dismissBrowser: jest.fn(),
9+
vi.mock('expo-web-browser', () => ({
10+
openAuthSessionAsync: vi.fn(),
11+
dismissBrowser: vi.fn(),
1112
}));
1213

13-
jest.mock('./utils/encoding', () => ({
14-
...jest.requireActual('./utils/encoding'),
15-
decodeResponseURLParams: jest.fn(),
14+
vi.mock('./utils/encoding', () => ({
15+
decodeResponseURLParams: vi.fn(),
16+
encodeRequestURLParams: vi.fn(),
1617
}));
1718

1819
const mockAppCustomScheme = 'myapp://';
@@ -48,17 +49,18 @@ describe('postRequestToWallet', () => {
4849

4950
beforeEach(() => {
5051
requestUrl = new URL(mockWalletScheme);
52+
(encodeRequestURLParams as ReturnType<typeof vi.fn>).mockReturnValue('mocked-search-params');
5153
requestUrl.search = encodeRequestURLParams(mockRequest);
52-
jest.clearAllMocks();
54+
vi.clearAllMocks();
5355
});
5456

5557
it('should successfully post request to a web-based wallet', async () => {
5658
const webWallet: Wallet = { type: 'web', scheme: mockWalletScheme } as Wallet;
57-
(WebBrowser.openAuthSessionAsync as jest.Mock).mockResolvedValue({
59+
(WebBrowser.openAuthSessionAsync as ReturnType<typeof vi.fn>).mockResolvedValue({
5860
type: 'success',
5961
url: 'https://example.com/response',
6062
});
61-
(decodeResponseURLParams as jest.Mock).mockResolvedValue(mockResponse);
63+
(decodeResponseURLParams as ReturnType<typeof vi.fn>).mockResolvedValue(mockResponse);
6264

6365
const result = await postRequestToWallet(mockRequest, mockAppCustomScheme, webWallet);
6466

@@ -74,7 +76,7 @@ describe('postRequestToWallet', () => {
7476

7577
it('should throw an error if the user cancels the request', async () => {
7678
const webWallet: Wallet = { type: 'web', scheme: mockWalletScheme } as Wallet;
77-
(WebBrowser.openAuthSessionAsync as jest.Mock).mockResolvedValue({
79+
(WebBrowser.openAuthSessionAsync as ReturnType<typeof vi.fn>).mockResolvedValue({
7880
type: 'cancel',
7981
});
8082

@@ -105,7 +107,7 @@ describe('postRequestToWallet', () => {
105107
it('should pass through any errors from WebBrowser', async () => {
106108
const webWallet: Wallet = { type: 'web', scheme: mockWalletScheme } as Wallet;
107109
const mockError = new Error('Communication error');
108-
(WebBrowser.openAuthSessionAsync as jest.Mock).mockRejectedValue(mockError);
110+
(WebBrowser.openAuthSessionAsync as ReturnType<typeof vi.fn>).mockRejectedValue(mockError);
109111

110112
await expect(postRequestToWallet(mockRequest, mockAppCustomScheme, webWallet)).rejects.toThrow(
111113
'User rejected the request'

packages/client/src/core/cipher/cipher.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { describe, expect, it, beforeAll } from 'vitest';
2+
13
import { unzlibSync, zlibSync } from 'fflate';
24

35
import {

packages/client/src/core/type/util.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { describe, expect, test } from 'vitest';
12
import { HexString } from '.';
23
import {
34
bigIntStringFromBigInt,
@@ -190,7 +191,7 @@ describe('util', () => {
190191
document.head.innerHTML = `
191192
<link rel="shortcut icon" sizes="16x16 24x24" href="/favicon.ico">
192193
`;
193-
expect(getFavicon()).toEqual('http://localhost/favicon.ico');
194+
expect(getFavicon()).toEqual('http://localhost:3000/favicon.ico');
194195
});
195196
});
196197
});

packages/client/src/core/util/utils.test.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,40 @@
1+
import { describe, expect, it, vi } from 'vitest';
12
import { LIB_VERSION } from '../../version';
23
import { checkErrorForInvalidRequestArgs, fetchRPCRequest } from './utils';
34
import { standardErrors } from ':core/error';
45

56
// @ts-expect-error-next-line
67
const invalidArgsError = (args) =>
7-
standardErrors.rpc.invalidRequest({
8+
standardErrors.rpc.invalidParams({
89
message: 'Expected a single, non-array, object argument.',
910
data: args,
1011
});
1112
// @ts-expect-error-next-line
1213
const invalidMethodError = (args) =>
13-
standardErrors.rpc.invalidRequest({
14+
standardErrors.rpc.invalidParams({
1415
message: "'args.method' must be a non-empty string.",
1516
data: args,
1617
});
1718
// @ts-expect-error-next-line
1819
const invalidParamsError = (args) =>
19-
standardErrors.rpc.invalidRequest({
20+
standardErrors.rpc.invalidParams({
2021
message: "'args.params' must be an object or array if provided.",
2122
data: args,
2223
});
2324

2425
const mockUUID = '123e4567-e89b-12d3-a456-426614174000';
25-
jest.spyOn(crypto, 'randomUUID').mockReturnValue(mockUUID);
26+
vi.spyOn(crypto, 'randomUUID').mockReturnValue(mockUUID);
2627

2728
describe('Utils', () => {
2829
describe('fetchRPCRequest', () => {
2930
function mockFetchResponse(response: unknown) {
30-
global.fetch = jest.fn().mockResolvedValue({
31-
json: jest.fn().mockResolvedValue(response),
31+
global.fetch = vi.fn().mockResolvedValue({
32+
json: vi.fn().mockResolvedValue(response),
3233
});
3334
}
3435

3536
it('should make a POST request with correct parameters', async () => {
36-
const mockResponse = { json: jest.fn().mockResolvedValue({ result: '0x1' }) };
37+
const mockResponse = { json: vi.fn().mockResolvedValue({ result: '0x1' }) };
3738
mockFetchResponse({ id: 1, result: mockResponse, error: null });
3839

3940
const mockRpcUrl = 'https://example.com/rpc';

0 commit comments

Comments
 (0)