Skip to content

Commit

Permalink
test(cat-voices): refactoring playwright
Browse files Browse the repository at this point in the history
  • Loading branch information
emiride committed Oct 31, 2024
1 parent 0bbeb68 commit 3a24ed1
Show file tree
Hide file tree
Showing 21 changed files with 1,067 additions and 260 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,5 @@ test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
extensions/
extensions/
catalyst_voices_packages/catalyst_cardano/catalyst_cardano/wallet-automation/.env

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
VERSION 0.8
IMPORT github.com/input-output-hk/catalyst-ci/earthly/flutter:v3.2.18 AS flutter-ci
IMPORT github.com/input-output-hk/catalyst-ci/earthly/playwright:v3.2.18 AS playwright-ci
IMPORT github.com/input-output-hk/catalyst-ci/earthly/flutter:v3.2.21 AS flutter-ci
IMPORT github.com/input-output-hk/catalyst-ci/earthly/playwright:v3.2.21 AS playwright-ci

deps:
DO playwright-ci+SETUP --workdir=/wallet-automation
Expand All @@ -13,11 +13,11 @@ deps:

src:
FROM +deps
COPY keys.txt .
COPY --dir pages ./pages
COPY --dir tests ./tests
COPY --dir utils ./utils
COPY playwright.config.ts .
COPY global-setup.ts .
COPY wallet-tests.spec.ts .
COPY utils.ts .
COPY test-fixtures.ts .

package-test:
FROM +src
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,8 @@ docker-compose up
```
The app should be running on `localhost:8000`.

6. You can now
6. You can now run tests with the following command:

```sh
npx playwright test
```

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,17 @@
},
"homepage": "https://github.com/input-output-hk/catalyst-voices#readme",
"devDependencies": {
"@playwright/test": "^1.45.3",
"@playwright/test": "^1.48.0",
"@types/node": "^20.14.12"
},
"dependencies": {
"@tomjs/unzip-crx": "^1.1.3",
"@types/node-fetch": "^2.6.11",
"dotenv": "^16.3.1",
"fs-extra": "^11.2.0",
"install": "^0.13.0",
"node-fetch": "^2.6.7",
"playwright": "^1.45.3",
"playwright": "^1.48.0",
"unzip-crx-3": "^0.2.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
import { Page, Locator, expect } from '@playwright/test';
import { BrowserExtensionName } from '../utils/extensions';
import { Modal, ModalName } from './modal';

export interface UTxO {
tx: string;
index: number;
amount: number;
}

export interface WalletCipData {
balance: number;
extensions: string;
networkId: string;
changeAddress: string;
rewardAddresses: string[];
unusedAddresses: string[];
usedAddresses: string[];
utxos: UTxO[];
publicDRepKey: string;
registeredPublicStakeKeys: string;
unregisteredPublicStakeKeys: string[];
}

export class HomePage {

readonly page: Page;
readonly balanceLabel: Locator;
readonly extensionsLabel: Locator;
readonly networkIdLabel: Locator;
readonly changeAddressLabel: Locator;
readonly rewardAddressesLabel: Locator;
readonly unusedAddressesLabel: Locator;
readonly usedAddressesLabel: Locator;
readonly utxosLabel: Locator;
readonly publicDRepKeyLabel: Locator;
readonly registeredPublicStakeKeysLabel: Locator;
readonly unregisteredPublicStakeKeysLabel: Locator;
readonly signDataButton: Locator;
readonly signAndSubmitTxButton: Locator;
readonly signAndSubmitRBACTxButton: Locator;

constructor(page: Page) {
this.page = page;
this.balanceLabel = page.getByText(/^Balance: Ada \(lovelaces\):/);
this.extensionsLabel = page.getByText(/^Extensions:/);
this.networkIdLabel = page.getByText(/^Network ID:/);
this.changeAddressLabel = page.getByText(/^Change address:/);
this.rewardAddressesLabel = page.getByText(/^Reward addresses:/);
this.unusedAddressesLabel = page.getByText(/^Unused addresses:/);
this.usedAddressesLabel = page.getByText(/^Used addresses:/);
this.utxosLabel = page.getByText(/^UTXOs:/);
this.publicDRepKeyLabel = page.getByText(/^Public DRep Key:/);
this.registeredPublicStakeKeysLabel = page.getByText(/^Registered Public Stake Keys:/);
this.unregisteredPublicStakeKeysLabel = page.getByText(/^Unregistered Public Stake Keys:/);
this.signDataButton = page.getByRole('button', { name: 'Sign data' });
this.signAndSubmitTxButton = page.getByRole('button', { name: 'Sign & submit tx' });
this.signAndSubmitRBACTxButton = page.getByRole('button', { name: 'Sign & submit RBAC tx' });
}

async getWalletCipData() {
const walletCipData: WalletCipData = {
balance: 0,
extensions: '',
networkId: '',
changeAddress: '',
rewardAddresses: [],
unusedAddresses: [],
usedAddresses: [],
utxos: [],
publicDRepKey: '',
registeredPublicStakeKeys: '',
unregisteredPublicStakeKeys: [],
};
await this.balanceLabel.waitFor({state: 'visible', timeout: 10000});
walletCipData.balance = await this.getBalance();
walletCipData.extensions = await this.getExtensions();
walletCipData.networkId = await this.getNetworkId();
walletCipData.changeAddress = await this.getChangeAddress();
walletCipData.rewardAddresses = await this.getRewardAddresses();
walletCipData.unusedAddresses = await this.getUnusedAddresses();
walletCipData.usedAddresses = await this.getUsedAddresses();
walletCipData.utxos = await this.getUTXOs();
walletCipData.publicDRepKey = await this.getPublicDRepKey();
walletCipData.registeredPublicStakeKeys = await this.getRegisteredPublicStakeKeys();
walletCipData.unregisteredPublicStakeKeys = await this.getUnregisteredPublicStakeKeys();
return walletCipData;
}

async assertModal(modalName: ModalName) {
const modal = new Modal(this.page, modalName);
await modal.assertModalIsVisible();
}

async getBalance(): Promise<number> {
const isVisible = await this.balanceLabel.isVisible();
if (!isVisible) {
throw new Error('Balance label is not visible');
}
const balanceText = await this.balanceLabel.textContent();
const match = balanceText?.match(/^Balance: Ada \(lovelaces\): (\d+)/);
if (match && match[1]) {
return Number(match[1]);
} else {
throw new Error(`Unable to extract balance from text: ${balanceText}`);
}
}

async getExtensions(): Promise<string> {
const isVisible = await this.extensionsLabel.isVisible();
if (!isVisible) {
throw new Error('Extensions label is not visible');
}
const extensionsText = await this.extensionsLabel.textContent();
const match = extensionsText?.trim().match(/^Extensions:\s*(.+)$/);
if (match && match[1]) {
return match[1].trim();
} else {
throw new Error(`Unable to extract extensions from text: ${extensionsText}`);
}
}

async getNetworkId(): Promise<string> {
const isVisible = await this.networkIdLabel.isVisible();
if (!isVisible) {
throw new Error('Network ID label is not visible');
}
const networkIdText = await this.networkIdLabel.textContent();
const match = networkIdText?.trim().match(/^Network ID:\s*(.+)$/);
if (match && match[1]) {
return match[1].trim();
} else {
throw new Error(`Unable to extract network ID from text: ${networkIdText}`);
}
}

async getChangeAddress(): Promise<string> {
const isVisible = await this.changeAddressLabel.isVisible();
if (!isVisible) {
throw new Error('Change address label is not visible');
}
const changeAddressText = await this.changeAddressLabel.textContent();
const match = changeAddressText?.trim().match(/^Change address:\s*(.+)$/s);
if (match && match[1]) {
return match[1].trim();
} else {
throw new Error(`Unable to extract change address from text: ${changeAddressText}`);
}
}

async getRewardAddresses(): Promise<string[]> {
const isVisible = await this.rewardAddressesLabel.isVisible();
if (!isVisible) {
throw new Error('Reward addresses label is not visible');
}
const rewardAddressesText = await this.rewardAddressesLabel.textContent();
const match = rewardAddressesText?.match(/^Reward addresses:\s*(.+)$/s);
if (match && match[1]) {
const addresses = match[1].trim().split('\n').map(addr => addr.trim()).filter(addr => addr.length > 0);
return addresses;
} else {
throw new Error(`Unable to extract reward addresses from text: ${rewardAddressesText}`);
}
}

async getUnusedAddresses(): Promise<string[]> {
const isVisible = await this.unusedAddressesLabel.isVisible();
if (!isVisible) {
throw new Error('Unused addresses label is not visible');
}
const unusedAddressesText = await this.unusedAddressesLabel.textContent();
const match = unusedAddressesText?.match(/^Unused addresses:\s*(.+)$/s);
if (match && match[1]) {
const addresses = match[1].trim().split('\n').map(addr => addr.trim()).filter(addr => addr.length > 0);
return addresses;
} else {
throw new Error(`Unable to extract unused addresses from text: ${unusedAddressesText}`);
}
}

async getUsedAddresses(): Promise<string[]> {
const isVisible = await this.usedAddressesLabel.isVisible();
if (!isVisible) {
throw new Error('Used addresses label is not visible');
}
const usedAddressesText = await this.usedAddressesLabel.textContent();
const match = usedAddressesText?.match(/^Used addresses:\s*(.+)$/s);
if (match && match[1]) {
const addresses = match[1].trim().split('\n').map(addr => addr.trim()).filter(addr => addr.length > 0);
return addresses;
} else {
throw new Error(`Unable to extract used addresses from text: ${usedAddressesText}`);
}
}

async getUTXOs(): Promise<UTxO[]> {
const isVisible = await this.utxosLabel.isVisible();
if (!isVisible) {
throw new Error('UTXOs label is not visible');
}
const utxosText = await this.utxosLabel.textContent();
const match = utxosText?.match(/^UTXOs:\s*(.+)$/s);
if (match && match[1]) {
const utxosData = match[1].trim();
const utxoEntries = utxosData.split(/\n\n+/).map(entry => entry.trim()).filter(entry => entry.length > 0);
const utxos: UTxO[] = [];
for (const entry of utxoEntries) {
const txMatch = entry.match(/Tx:\s*([a-fA-F0-9]+)/);
const indexMatch = entry.match(/Index:\s*(\d+)/);
const amountMatch = entry.match(/Amount:\s*Ada \(lovelaces\):\s*(\d+)/);
if (txMatch && indexMatch && amountMatch) {
utxos.push({
tx: txMatch[1],
index: Number(indexMatch[1]),
amount: Number(amountMatch[1]),
});
} else {
throw new Error(`Unable to parse UTXO entry: ${entry}`);
}
}
return utxos;
} else {
throw new Error(`Unable to extract UTXOs from text: ${utxosText}`);
}
}

async getPublicDRepKey(): Promise<string> {
const isVisible = await this.publicDRepKeyLabel.isVisible();
if (!isVisible) {
throw new Error('Public DRep Key label is not visible');
}
const publicDRepKeyText = await this.publicDRepKeyLabel.textContent();
const match = publicDRepKeyText?.trim().match(/^Public DRep Key:\s*([a-fA-F0-9]+)$/);
if (match && match[1]) {
return match[1];
} else {
throw new Error(`Unable to extract public DRep key from text: ${publicDRepKeyText}`);
}
}

async getRegisteredPublicStakeKeys(): Promise<string> {
const isVisible = await this.registeredPublicStakeKeysLabel.isVisible();
if (!isVisible) {
throw new Error('Registered Public Stake Keys label is not visible');
}
const stakeKeysText = await this.registeredPublicStakeKeysLabel.textContent();
const match = stakeKeysText?.trim().match(/^Registered Public Stake Keys:\s*([a-fA-F0-9]+)$/);
if (match && match[1]) {
return match[1];
} else {
throw new Error(`Unable to extract registered public stake keys from text: ${stakeKeysText}`);
}
}

async getUnregisteredPublicStakeKeys(): Promise<string[]> {
const isVisible = await this.unregisteredPublicStakeKeysLabel.isVisible();
if (!isVisible) {
throw new Error('Unregistered Public Stake Keys label is not visible');
}
const keysText = await this.unregisteredPublicStakeKeysLabel.textContent();
const match = keysText?.trim().match(/^Unregistered Public Stake Keys:\s*(.*)$/s);
if (match) {
const keysData = match[1].trim();
if (keysData) {
const keys = keysData.split('\n').map(key => key.trim()).filter(key => key.length > 0);
return keys;
} else {
return [];
}
} else {
throw new Error(`Unable to extract unregistered public stake keys from text: ${keysText}`);
}
}

async assertBasicWalletCipData(actualWalletCipData: WalletCipData, extensionName: BrowserExtensionName) {
expect(actualWalletCipData.balance).toBeGreaterThan(500000000);
expect(actualWalletCipData.extensions).toBe(extensionName === BrowserExtensionName.Typhon ? 'cip-30' : 'cip-95');
expect(actualWalletCipData.networkId).not.toBeNaN();
expect(actualWalletCipData.changeAddress).not.toBeNaN();
expect(actualWalletCipData.rewardAddresses.length).toBeGreaterThan(0);
expect(actualWalletCipData.unusedAddresses.length).toBeGreaterThan(0);
expect(actualWalletCipData.usedAddresses.length).toBeGreaterThan(0);
expect(actualWalletCipData.utxos.length).toBeGreaterThan(0);
expect(actualWalletCipData.publicDRepKey).not.toBeNaN();
expect(actualWalletCipData.registeredPublicStakeKeys).not.toBeNaN();

}
}
Loading

0 comments on commit 3a24ed1

Please sign in to comment.