Skip to content

Commit

Permalink
Dapp kit UI testing (#83)
Browse files Browse the repository at this point in the history
* chore: adding tests for core dapp-kit

* chore: revert eslint config

* chore: revert eslint config

* chore: update GH actions

* chore: add dapp kit UI tests

* chore: move to dev deps

* fix: remove useless Id

* fix: not using internal connex libs
  • Loading branch information
darrenvechain authored Nov 21, 2023
1 parent d41f892 commit 5f59d5e
Show file tree
Hide file tree
Showing 27 changed files with 468 additions and 48 deletions.
6 changes: 6 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules/*
dist/*
web-dev-server.config.js
tsup.config.ts
**/test/**
vite.config.ts
2 changes: 2 additions & 0 deletions packages/dapp-kit-ui/.eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ node_modules/*
dist/*
web-dev-server.config.js
tsup.config.ts
test
vite.config.ts
3 changes: 1 addition & 2 deletions packages/dapp-kit-ui/.gitignore
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
/node_modules/
/lib/
/test/
custom-elements.json
# top level source
my-element.js
my-element.js.map
my-element.d.ts
my-element.d.ts.map
# only generated for size check
my-element.bundled.js
my-element.bundled.js
7 changes: 6 additions & 1 deletion packages/dapp-kit-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"format": "prettier \"**/*.{cjs,html,js,json,md,ts}\" --ignore-path ./.eslintignore --write",
"lint": "tsc --noEmit && eslint src --ext .js,.jsx,.ts,.tsx",
"purge": "yarn clean && rm -rf node_modules",
"test": "vitest run --coverage",
"watch": "tsup --watch"
},
"dependencies": {
Expand All @@ -37,10 +38,14 @@
"@typescript-eslint/eslint-plugin": "^5.25.0",
"@typescript-eslint/parser": "^5.25.0",
"@vechain/repo-config": "https://github.com/vechainfoundation/repo-config#v0.0.1",
"@vitest/coverage-v8": "^0.34.6",
"eslint": "^8.15.0",
"parcel": "^2.10.2",
"prettier": "^2.6.2",
"tsup": "^7.2.0",
"typescript": "~5.2.0"
"typechain": "^8.3.2",
"typescript": "~5.2.0",
"vite": "^4.5.0",
"vitest": "^0.34.6"
}
}
1 change: 1 addition & 0 deletions packages/dapp-kit-ui/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import './vwk-connect-button';
import './vwk-connect-button-with-modal';
import './vwk-source-card';
import './vwk-fonts';
import './vwk-wallet-connect-qrcode';

export * from './base';
export * from './vwk-connect-modal';
Expand Down
2 changes: 2 additions & 0 deletions packages/dapp-kit-ui/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import './components';

export * from './client';
export * from './assets';
export * from './components';
Expand Down
57 changes: 57 additions & 0 deletions packages/dapp-kit-ui/test/connect-buton-with-modal.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { beforeEach, describe, expect, it } from 'vitest';

import {
ConnectButton,
ConnectButtonWithModal,
ConnectModal,
DAppKit,
SourceInfo,
} from '../src';
import { elementQueries } from './helpers/elemnt-queries';
import { WalletSource } from '@vechainfoundation/dapp-kit/src';

describe('connect-button-with-modal', () => {
beforeEach(() => {
DAppKit.configure({ nodeUrl: 'https://mainnet.vechain.org/' });
});

it('Should callback with source when user clicks a wallet', async () => {
const element: ConnectButtonWithModal = window.document.createElement(
'vwk-connect-button-with-modal',
);

let selectedSource: WalletSource | undefined;

element.onSourceClick = (source?: SourceInfo) => {
selectedSource = source?.id;
};

window.document.body.appendChild(element);

const connectButton =
(await elementQueries.getConnectButton()) as ConnectButton;
const connectModal =
(await elementQueries.getConnectModal()) as ConnectModal;

expect(connectModal).toBeDefined();
expect(connectButton).toBeDefined();

expect(connectModal.open).toBe(false);

connectButton.shadowRoot?.querySelector('button')?.click();

await new Promise((resolve) => setTimeout(resolve, 1000));

expect(connectModal.open).toBe(true);

const sourceCards = await elementQueries.getAllSourceCards();

expect(sourceCards.length).toBeGreaterThan(0);

sourceCards[0]?.shadowRoot?.querySelector('div')?.click();

await new Promise((resolve) => setTimeout(resolve, 1000));

expect(selectedSource).toBeDefined();
});
});
69 changes: 69 additions & 0 deletions packages/dapp-kit-ui/test/helpers/elemnt-queries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { ConnectButton, ConnectModal, SourceCard } from '../../src';

const performQueryWithTimeout = async <T>(
timeout: number,
query: () => T | undefined | null,
): Promise<T | undefined | null> => {
const startTime = Date.now();

let element = query();

while (!element && Date.now() - startTime < timeout) {
await new Promise((resolve) => setTimeout(resolve, 10));
element = query();
}

return element;
};

const getConnectButton = (
timeout = 2000,
): Promise<ConnectButton | undefined | null> => {
return performQueryWithTimeout(timeout, () =>
window.document.body
.querySelector('vwk-connect-button-with-modal')
?.shadowRoot?.querySelector('vwk-connect-button'),
);
};

const getConnectModal = (): Promise<ConnectModal | undefined | null> => {
return performQueryWithTimeout(2000, () =>
window.document.body
.querySelector('vwk-connect-button-with-modal')
?.shadowRoot?.querySelector('vwk-connect-modal'),
);
};
const getAllSourceCards = async (): Promise<SourceCard[]> => {
const res = await performQueryWithTimeout(2000, () =>
window.document.body
.querySelector('vwk-connect-button-with-modal')
?.shadowRoot?.querySelector('vwk-connect-modal')
?.shadowRoot?.querySelector('vwk-base-modal')
?.querySelectorAll('vwk-source-card'),
);

const sourceCards: SourceCard[] = [];

res?.forEach((sourceCard) => {
sourceCards.push(sourceCard);
});

return sourceCards;
};

const getWalletConnectQrCode = () => {
return performQueryWithTimeout(2000, () =>
window.document.body
.querySelector('vwk-connect-button-with-modal')
?.shadowRoot?.querySelector('vwk-connect-modal')
?.shadowRoot?.querySelector('vwk-base-modal')
?.querySelector('vwk-wallet-connect-qrcode'),
);
};

export const elementQueries = {
getConnectButton,
getConnectModal,
getAllSourceCards,
getWalletConnectQrCode,
};
51 changes: 51 additions & 0 deletions packages/dapp-kit-ui/test/qr-code.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { describe, expect, it } from 'vitest';
import {
ConnectButton,
ConnectButtonWithModal,
DAppKit,
dispatchCustomEvent,
WalletConnectQrCode,
} from '../src';
import { elementQueries } from './helpers/elemnt-queries';

const sampleUri =
'wc:59f6594baa77ca343197f60436e5a188708b045e323aa4d6ce93722772e18deb@2?relay-protocol=irn&symKey=0422890abbd3baf75cefad89e822b01071cd906705d6c9282596de866376a824';

describe('qr-code-modal', () => {
beforeEach(() => {
DAppKit.configure({
nodeUrl: 'https://mainnet.vechain.org/',
walletConnectOptions: {
projectId: '123',
metadata: {
name: 'VeChain',
description: 'VeChain',
icons: ['https://vechain.org/images/logo.svg'],
url: 'https://vechain.org',
},
},
});
});

it('should display QR code', async () => {
const element: ConnectButtonWithModal = window.document.createElement(
'vwk-connect-button-with-modal',
);

window.document.body.appendChild(element);

const connectButton =
(await elementQueries.getConnectButton()) as ConnectButton;

connectButton.shadowRoot?.querySelector('button')?.click();

dispatchCustomEvent('vwk-open-wc-modal', { uri: sampleUri });

const qrCode =
(await elementQueries.getWalletConnectQrCode()) as WalletConnectQrCode;

expect(qrCode).toBeDefined();

expect(qrCode.walletConnectQRcode).toBe(sampleUri);
});
});
17 changes: 17 additions & 0 deletions packages/dapp-kit-ui/test/setup/setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { vi } from 'vitest';

vi.mock('@walletconnect/modal');

Object.defineProperty(window, 'matchMedia', {
writable: true,
value: vi.fn().mockImplementation((query) => ({
matches: false,
media: query,
onchange: null,
addListener: vi.fn(), // deprecated
removeListener: vi.fn(), // deprecated
addEventListener: vi.fn(),
removeEventListener: vi.fn(),
dispatchEvent: vi.fn(),
})),
});
29 changes: 29 additions & 0 deletions packages/dapp-kit-ui/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/// <reference types="vitest" />
import { defineConfig } from 'vitest/config';
import { resolve } from 'node:path'; // eslint-disable-next-line import/no-default-export

// eslint-disable-next-line import/no-default-export
export default defineConfig({
test: {
include: ['test/**/*.test.ts'],
environment: 'jsdom',
reporters: 'dot',
setupFiles: [resolve(__dirname, 'test/setup/setup.ts')],
coverage: {
reporter: [
'text',
'json',
'html',
'lcov',
'json-summary',
'text-summary',
'text',
],
lines: 80,
statements: 80,
functions: 60,
branches: 80,
},
globals: true,
},
});
6 changes: 6 additions & 0 deletions packages/dapp-kit/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules/*
dist/*
web-dev-server.config.js
tsup.config.ts
test
vite.config.ts
File renamed without changes.
1 change: 1 addition & 0 deletions packages/dapp-kit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"name": "@vechainfoundation/dapp-kit",
"version": "0.0.0",
"private": false,
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"scripts": {
Expand Down
45 changes: 31 additions & 14 deletions packages/dapp-kit/src/connex.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,31 @@
import { createNoVendor, LazyDriver } from '@vechain/connex/esm/driver';
import { newThor } from '@vechain/connex-framework/dist/thor';
import type { DriverNoVendor } from '@vechain/connex-driver';
import { newVendor } from '@vechain/connex-framework';
import { DriverNoVendor, SimpleNet } from '@vechain/connex-driver';
import { Framework } from '@vechain/connex-framework';
import { blake2b256 } from 'thor-devkit';
import type { ConnexOptions } from './types';
import { normalizeGenesisBlock } from './genesis';
import { WalletManager } from './wallet-manager';

const cache: Record<string, DriverNoVendor | undefined> = {};

const createThorDriver = (
node: string,
genesis: Connex.Thor.Block,
): DriverNoVendor => {
const key = blake2b256(
JSON.stringify({
node,
genesis,
}),
).toString('hex');

let driver = cache[key];
if (!driver) {
driver = new DriverNoVendor(new SimpleNet(node), genesis);
cache[key] = driver;
}
return driver;
};

class MultiWalletConnex {
public readonly thor: Connex.Thor;
public readonly vendor: Connex.Vendor;
Expand All @@ -16,20 +36,17 @@ class MultiWalletConnex {

const genesisBlock = normalizeGenesisBlock(genesis);

const thorOnlyDriver: DriverNoVendor = createNoVendor(
nodeUrl,
genesisBlock,
);
const driver = createThorDriver(nodeUrl, genesisBlock);

const walletManager = new WalletManager(options);
const lazyDriver = new LazyDriver(Promise.resolve(walletManager));
lazyDriver.setNoVendor(thorOnlyDriver);

const thor = newThor(lazyDriver);
const vendor = newVendor(lazyDriver);
driver.signTx = walletManager.signTx.bind(walletManager);
driver.signCert = walletManager.signCert.bind(walletManager);

const framework = new Framework(driver);

this.thor = thor;
this.vendor = vendor;
this.thor = framework.thor;
this.vendor = framework.vendor;
this.wallet = walletManager;
}
}
Expand Down
Loading

0 comments on commit 5f59d5e

Please sign in to comment.