Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dapp kit UI testing #83

Merged
merged 11 commits into from
Nov 21, 2023
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
Loading