Skip to content

Commit

Permalink
Migrate client from jest to vitest (#1041)
Browse files Browse the repository at this point in the history
* Migrate client from jest to vitest

* Add workaround to spy on exported function

* Reset timers after all

* Update changelog

* Use non-local domain (seems necessary within GitHub Action container)

* Clean up `vi.useFakeTimers()` after usage

* Use simple getObj() helper over `deepFreeze` + `structuredClone`
  • Loading branch information
webpro authored Oct 18, 2023
1 parent 0c958ba commit 6703177
Show file tree
Hide file tree
Showing 23 changed files with 618 additions and 627 deletions.
5 changes: 5 additions & 0 deletions .changeset/wild-moles-beg.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@kadena/client': patch
---

Migrate packages from Jest to Vitest
5 changes: 0 additions & 5 deletions packages/libs/client/jest.config.js

This file was deleted.

10 changes: 0 additions & 10 deletions packages/libs/client/jest.integration.config.js

This file was deleted.

10 changes: 5 additions & 5 deletions packages/libs/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
"pactjs:generate:contract": "pactjs contract-generate --file contracts/coin.contract.pact",
"pactjs:retrieve:contract": "pactjs retrieve-contract --out contracts/coin.contract.pact --module coin",
"start": "ts-node --transpile-only src/index.ts",
"test": "jest",
"test:integration": "jest --silent -c ./jest.integration.config.js"
"test": "vitest",
"test:integration": "vitest run -c ./vitest.integration.config.ts"
},
"dependencies": {
"@kadena/chainweb-node-client": "workspace:*",
Expand All @@ -54,15 +54,15 @@
"@microsoft/api-extractor": "^7.37.0",
"@rushstack/eslint-config": "~3.3.0",
"@types/debug": "~4.1.7",
"@types/jest": "^29.5.3",
"@types/node": "^18.17.14",
"@walletconnect/types": "~2.8.1",
"eslint": "^8.45.0",
"jest": "^29.7.0",
"msw": "^1.3.2",
"prettier": "~3.0.0",
"prettier-plugin-packagejson": "^2.4.5",
"ts-node": "~10.8.2",
"typescript": "5.2.2"
"typescript": "5.2.2",
"vitest": "^0.34.6"
},
"publishConfig": {
"provenance": true
Expand Down
41 changes: 31 additions & 10 deletions packages/libs/client/src/client/api/tests/runPact.test.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,44 @@
jest.mock('@kadena/chainweb-node-client', () => ({
__esModule: true,
...jest.requireActual('@kadena/chainweb-node-client'),
local: jest.fn(),
}));

import type * as ChainWebNodeClient from '@kadena/chainweb-node-client';
import { local } from '@kadena/chainweb-node-client';

import { runPact } from '../runPact';

jest.useFakeTimers().setSystemTime(new Date('2023-07-31'));
import { rest } from 'msw';
import { setupServer } from 'msw/node';

// Hack to spy on exported function
vi.mock('@kadena/chainweb-node-client', async (importOriginal) => {
const mod: typeof ChainWebNodeClient = await importOriginal();
const local = vi.fn().mockImplementation(mod.local);
return { ...mod, local };
});

const server = setupServer();
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

describe('runPact', () => {
beforeAll(() => {
vi.useFakeTimers().setSystemTime(new Date('2023-07-31'));
});

afterAll(() => {
vi.useRealTimers();
});

it('create a complete pact command from the input and send it to the chain', async () => {
const response = 'local-response';
(local as jest.Mock).mockResolvedValue(response);
const mockResponse = {};

server.resetHandlers(
rest.post('http://blockchain/api/v1/local', (req, res, ctx) =>
res.once(ctx.status(200), ctx.json(mockResponse)),
),
);

const result = await runPact('http://blockchain', '(+ 1 1)');

expect(result).toBe(response);
expect(result).toStrictEqual(mockResponse);

expect(local).toBeCalledWith(
{
Expand Down
60 changes: 34 additions & 26 deletions packages/libs/client/src/client/api/tests/spv.test.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
jest.mock('@kadena/chainweb-node-client', () => ({
__esModule: true,
...jest.requireActual('@kadena/chainweb-node-client'),
spv: jest.fn(),
}));

import { spv } from '@kadena/chainweb-node-client';

import { withCounter } from '../../utils/utils';
import { getSpv, pollSpv } from '../spv';

import { rest } from 'msw';
import { setupServer } from 'msw/node';

const server = setupServer();
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

const post = (
path: string,
response: string | Record<string, unknown>,
status = 200,
): ReturnType<typeof rest.post> =>
rest.post(path, (req, res, ctx) =>
res.once(
ctx.status(status),
typeof response === 'string' ? ctx.text(response) : ctx.json(response),
),
);

describe('getSpv', () => {
it('calls /spv endpoint to generate spv for a request and a target chain', async () => {
const response = 'spv-proof';

(spv as jest.Mock).mockResolvedValue(response);
server.resetHandlers(post('http://test-blockchain-host.com/spv', response));

const hostUrl = 'http://test-blockchain-host.com';

Expand All @@ -23,14 +34,16 @@ describe('getSpv', () => {
const result = await getSpv(hostUrl, requestKey, targetChainId);

expect(result).toBe(response);

expect(spv).toBeCalledWith({ requestKey, targetChainId }, hostUrl);
});

it('throws exception if spv function does not return string', async () => {
const response = { key: 'any' };

(spv as jest.Mock).mockResolvedValue(response);
server.resetHandlers(
post(
'http://test-blockchain-host.com/spv',
'PROOF_IS_NOT_AVAILABLE',
500,
),
);

const hostUrl = 'http://test-blockchain-host.com';

Expand All @@ -40,22 +53,19 @@ describe('getSpv', () => {
await expect(() =>
getSpv(hostUrl, requestKey, targetChainId),
).rejects.toThrowError(new Error('PROOF_IS_NOT_AVAILABLE'));

expect(spv).toBeCalledWith({ requestKey, targetChainId }, hostUrl);
});
});

describe('pollSpv', () => {
it('calls /spv endpoint several times to generate spv for a request and a target chain', async () => {
const response = 'spv-proof';

(spv as jest.Mock).mockImplementation(
withCounter(async (counter) => {
if (counter < 5) {
return Promise.reject('not found');
}
return Promise.resolve(response);
}),
server.resetHandlers(
post('http://test-blockchain-host.com/spv', 'not found', 404),
post('http://test-blockchain-host.com/spv', 'not found', 404),
post('http://test-blockchain-host.com/spv', 'not found', 404),
post('http://test-blockchain-host.com/spv', 'not found', 404),
post('http://test-blockchain-host.com/spv', response),
);

const hostUrl = 'http://test-blockchain-host.com';
Expand All @@ -67,8 +77,6 @@ describe('pollSpv', () => {
interval: 10,
});

expect(spv).toBeCalledTimes(5);

expect(result).toBe(response);
});
});
81 changes: 43 additions & 38 deletions packages/libs/client/src/client/api/tests/status.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,27 @@
jest.mock('@kadena/chainweb-node-client', () => ({
__esModule: true,
...jest.requireActual('@kadena/chainweb-node-client'),
poll: jest.fn(),
}));

import { poll } from '@kadena/chainweb-node-client';

import { sleep, withCounter } from '../../utils/utils';
import { pollStatus } from '../status';

import { rest } from 'msw';
import { setupServer } from 'msw/node';

const server = setupServer();
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

const post = (
path: string,
response: string | Record<string, unknown>,
status = 200,
delay?: number,
): ReturnType<typeof rest.post> =>
rest.post(path, (req, res, ctx) =>
res.once(
ctx.status(status),
ctx.delay(delay ?? 0),
typeof response === 'string' ? ctx.text(response) : ctx.json(response),
),
);

describe('pollStatus', () => {
it('calls the /poll endpoint several times till it gets the status of all request keys', async () => {
const responses = [
Expand All @@ -18,11 +31,14 @@ describe('pollStatus', () => {
{ 'key-2': { reqKey: 'key-2' } },
];

(poll as jest.Mock).mockImplementation(
withCounter((counter) => responses[counter - 1] ?? {}),
server.resetHandlers(
post('http://test-blockchain-host.com/api/v1/poll', responses[0]),
post('http://test-blockchain-host.com/api/v1/poll', responses[1]),
post('http://test-blockchain-host.com/api/v1/poll', responses[2]),
post('http://test-blockchain-host.com/api/v1/poll', responses[3]),
);

const hostUrl = "http://test-blockchain-host.com'";
const hostUrl = 'http://test-blockchain-host.com';

const requestKeys = ['key-1', 'key-2'];

Expand All @@ -34,32 +50,20 @@ describe('pollStatus', () => {
'key-1': { reqKey: 'key-1' },
'key-2': { reqKey: 'key-2' },
});

expect(poll).toHaveBeenCalledTimes(4);
});

it('throws TIME_OUT_REJECT if the task get longer that in timeout option', async () => {
const responses = [
{},
{ 'key-1': { reqKey: 'key-1' } },
{},
{ 'key-2': { reqKey: 'key-2' } },
];

(poll as jest.Mock).mockImplementation(
withCounter(async (counter) => {
await sleep(501);
return responses[counter - 1] ?? {};
}),
it('throws TIME_OUT_REJECT if the task get longer than set in timeout option', async () => {
server.resetHandlers(
post('http://test-blockchain-host.com/api/v1/poll', {}, 200, 75),
);

const hostUrl = "http://test-blockchain-host.com'";
const hostUrl = 'http://test-blockchain-host.com';

const requestKeys = ['key-1', 'key-2'];

const promise = pollStatus(hostUrl, requestKeys, {
interval: 10,
timeout: 500,
timeout: 50,
});

await expect(promise).rejects.toEqual(new Error('TIME_OUT_REJECT'));
Expand All @@ -73,13 +77,16 @@ describe('pollStatus', () => {
{ 'key-2': { reqKey: 'key-2' } },
];

(poll as jest.Mock).mockImplementation(
withCounter((counter) => responses[counter - 1] ?? {}),
server.resetHandlers(
post('http://test-blockchain-host.com/api/v1/poll', responses[0]),
post('http://test-blockchain-host.com/api/v1/poll', responses[1]),
post('http://test-blockchain-host.com/api/v1/poll', responses[2]),
post('http://test-blockchain-host.com/api/v1/poll', responses[3]),
);

const onPoll = jest.fn();
const onPoll = vi.fn();

const hostUrl = "http://test-blockchain-host.com'";
const hostUrl = 'http://test-blockchain-host.com';

const requestKeys = ['key-1', 'key-2'];

Expand Down Expand Up @@ -110,11 +117,11 @@ describe('pollStatus', () => {
{ 'key-1': { reqKey: 'key-1' }, 'key-2': { reqKey: 'key-2' } },
];

(poll as jest.Mock).mockImplementation(
withCounter((counter) => responses[counter - 1] ?? {}),
server.resetHandlers(
post('http://test-blockchain-host.com/api/v1/poll', responses[0]),
);

const hostUrl = "http://test-blockchain-host.com'";
const hostUrl = 'http://test-blockchain-host.com';

const requestKeys = ['key-1', 'key-2'];

Expand All @@ -124,7 +131,5 @@ describe('pollStatus', () => {
'key-1': { reqKey: 'key-1' },
'key-2': { reqKey: 'key-2' },
});

expect(poll).toHaveBeenCalledTimes(1);
});
});
Loading

0 comments on commit 6703177

Please sign in to comment.