-
Notifications
You must be signed in to change notification settings - Fork 11
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
feature: E2E real wallet data using esbuild #193
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
/test-results/ | ||
/playwright-report/ | ||
/blob-report/ | ||
/playwright/.cache/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,7 +23,7 @@ where, | |
- `NEXT_PUBLIC_POINTS_API_URL` specifies the Points API to use for the points | ||
system | ||
- `NEXT_PUBLIC_NETWORK` specifies the BTC network environment | ||
- `NEXT_PUBLIC_DISPLAY_TESTING_MESSAGES` boolean value to indicate whether display | ||
- `NEXT_PUBLIC_DISPLAY_TESTING_MESSAGES` boolean value to indicate whether display | ||
testing network related message. Default to true | ||
|
||
Then, to start a development server: | ||
|
@@ -36,3 +36,26 @@ npm run dev | |
|
||
Instructions for wallet integration can be found in this | ||
[document](./docs/WalletIntegration.md). | ||
|
||
## E2E | ||
The end-to-end (E2E) tests are implemented using Playwright. These tests simulate user interactions with the application to ensure that all functionalities work as expected across different Bitcoin network environments (`mainnet` and `signet`). The tests utilize *some* mocked data to prevent interactions with real Bitcoin networks, ensuring safe and reliable testing. | ||
|
||
### Prerequisites | ||
Before running the E2E tests, ensure that you have completed the following steps: | ||
|
||
- Environment Configuration: Set up the necessary environment variables. | ||
- Install Dependencies: Ensure all dependencies are installed. | ||
|
||
### Environment Configuration | ||
The E2E tests can be run using either the .env.local file or the specific environment files .env.mainnet and .env.signet. These files should contain the following environment variables: | ||
|
||
- `NEXT_PUBLIC_NETWORK`: Specifies the BTC network environment (mainnet or signet). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now that the E2E tests are using fully mocked data, do we still need all the environment setups across different env files? or maybe we can just create a single .env.test under the test directory for running the e2e test? |
||
- `NEXT_PUBLIC_MEMPOOL_API`: Specifies the mempool.space host to use for Bitcoin node queries. | ||
- `NEXT_PUBLIC_DISPLAY_TESTING_MESSAGES`: Boolean value to indicate whether to display testing network-related messages. | ||
- `NEXT_PUBLIC_API_URL`: Specifies the back-end API to use for staking system queries. | ||
|
||
### Commands to run E2E | ||
- `npx playwright install` to install playwright. This is *required* to do after the `npm install` | ||
- Stop the current `dev` server in case you ran it with `npm run dev` | ||
- `npm run test:e2e` to run the test using the network in `.env.local` | ||
- `npm run test:e2e:full` to run the test using the networks in `.env.mainnet` and `.env.signet` |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,20 +1,96 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { expect, test } from "@playwright/test"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { expect, Page, test } from "@playwright/test"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { satoshiToBtc } from "@/utils/btcConversions"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { maxDecimals } from "@/utils/maxDecimals"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { trim } from "@/utils/trim"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
NATIVE_SEGWIT_MAINNET_ADDRESS, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
NATIVE_SEGWIT_SIGNET_ADDRESS, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
TAPROOT_MAINNET_ADDRESS, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
TAPROOT_SIGNET_ADDRESS, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} from "./constants/wallet"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { setupWalletConnection } from "./helper/connect"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { mockNetwork } from "./helper/mockNetwork"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { extractNumericBalance } from "./helper/utils"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { nativeSegwitMainnetBalance } from "./mock/mainnet/wallet/nativeSegwit/utxos"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { taprootMainnetBalance } from "./mock/mainnet/wallet/taproot/utxos"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { nativeSegwitSignetBalance } from "./mock/signet/wallet/nativeSegwit/utxos"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { taprootSignetBalance } from "./mock/signet/wallet/taproot/utxos"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
type Network = "mainnet" | "signet"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
type AddressType = "taproot" | "nativeSegwit"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Duplicated with the types defined in |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Determine the network from environment variable or default to 'mainnet' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const network: Network = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we not use existing |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
(process.env.NEXT_PUBLIC_NETWORK as Network) || "mainnet"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Define the address types to test | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const addressTypes: AddressType[] = ["taproot", "nativeSegwit"]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Mappings for expected addresses based on network and address type | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const expectedAddresses: Record<AddressType, Record<Network, string>> = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
taproot: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
mainnet: TAPROOT_MAINNET_ADDRESS, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
signet: TAPROOT_SIGNET_ADDRESS, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
nativeSegwit: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
mainnet: NATIVE_SEGWIT_MAINNET_ADDRESS, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
signet: NATIVE_SEGWIT_SIGNET_ADDRESS, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Mappings for expected balances based on network and address type | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const expectedBalances: Record<AddressType, Record<Network, number>> = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
taproot: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
mainnet: taprootMainnetBalance, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
signet: taprootSignetBalance, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
nativeSegwit: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
mainnet: nativeSegwitMainnetBalance, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
signet: nativeSegwitSignetBalance, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+32
to
+53
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can move this logic together with current const addresses = {
mainnet: {
taproot: 'address',
nativeSegwit: 'address',
},
signet: {
taproot: 'address',
nativeSegwit: 'address',
}
}[network]; |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Reusable function for checking address | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
async function checkAddress(page: Page, expectedAddress: string) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const address = await page.getByTestId("address").textContent(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
expect(address).toBe(trim(expectedAddress)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Reusable function for checking balance | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
async function checkBalance(page: Page, expectedBalance: number) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const balanceText = await page.getByTestId("balance").textContent(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const balance = maxDecimals(extractNumericBalance(balanceText), 8); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
expect(balance).toBe(satoshiToBtc(expectedBalance)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
test.describe("Balance and address checks after connection", () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
test.beforeEach(async ({ page }) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
await page.goto("/"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
await setupWalletConnection(page); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
test("balance is correct", async ({ page }) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const balance = await page.getByTestId("balance").textContent(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
expect(balance).toBe("0.12345678 BTC"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
test("address is correct", async ({ page }) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const address = await page.getByTestId("address").textContent(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
expect(address).toBe("bc1p...97sd"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Iterate over each address type | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
for (const type of addressTypes) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
test.describe(`${type} address on ${network}`, () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I notice the
then we just do a testCase.forEach to loop through There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jrwbabylonlab why we need test against multiple networks if everything is mocked? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Theoretically, it should be the same. The different network only matters if our code is performing BTC-specific operations. I’m not sure if our simple-staking implementation includes that (it shouldn’t), but it wouldn’t hurt to run it on multiple networks just to be safe. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Mock the network | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
test.beforeEach(async ({ page }) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
await mockNetwork(page, network); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Setup wallet connection before each test | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
test.beforeEach(async ({ page }) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
await setupWalletConnection(page, network, type); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There’s no need to use two separate test.beforeEach calls. It's the same as a single beforeEach |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
test(`should verify the ${type} address and balance on ${network}`, async ({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
page, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const expectedAddress = expectedAddresses[type][network]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const expectedBalance = expectedBalances[type][network]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Perform address check | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
await checkAddress(page, expectedAddress); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Perform balance check | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
await checkBalance(page, expectedBalance); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+82
to
+93
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Test is pretty small, no need in additional wrapper. Weird to see test without
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
// Constants for selectors and texts | ||
|
||
export const BUTTON_TEXT_CONNECT_TO_BTC = "Connect to BTC"; | ||
export const LABEL_TEXT_ACCEPT_TERMS = "I certify that I have read"; | ||
export const LABEL_TEXT_NO_INSCRIPTIONS = "I certify that there are no"; | ||
export const LABEL_TEXT_HW_WALLET = "I acknowledge that Keystone via QR code"; | ||
export const BUTTON_TEXT_BROWSER = "Browser"; | ||
export const INPUT_DURATION_BLOCKS = "Blocks"; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// Don't use real funds with these addresses | ||
export const MNEMONIC = | ||
"baby baby baby baby baby baby baby rocket rocket rocket rocket science"; | ||
|
||
// The following addresses are derived from the above mnemonic | ||
export const TAPROOT_MAINNET_ADDRESS = | ||
"bc1p620x2d0wvycj0y7jmc0lxytk0m64swcx2lp430grtn0klqwugpcsgwalan"; | ||
export const TAPROOT_MAINNET_PK = | ||
"038f561718d7f3ead37bd57e7b68360325db2263acfbbc8cb6b129e768d27aa46d"; | ||
export const TAPROOT_MAINNET_SCRIPT_PUBKEY = | ||
"5120d29e6535ee61312793d2de1ff311767ef5583b0657c358bd035cdf6f81dc4071"; | ||
|
||
export const NATIVE_SEGWIT_MAINNET_ADDRESS = | ||
"bc1q7w09t8gl84c7ksus5nt3r2eg0qexk987hk9n23"; | ||
export const NATIVE_SEGWIT_MAINNET_PK = | ||
"02ed32cf86745ea2c7a13f72b3194a576c249736e0b773e1a9f837767d60a3adcf"; | ||
export const NATIVE_SEGWIT_MAINNET_SCRIPT_PUBKEY = | ||
"0014f39e559d1f3d71eb4390a4d711ab2878326b14fe"; | ||
|
||
export const TAPROOT_SIGNET_ADDRESS = | ||
"tb1pc29r075qcgypvxzaq34680sk3epwv3xrqu4fnkskrqesd65d9yjqun5x5j"; | ||
export const TAPROOT_SIGNET_PK = | ||
"025bf662d62fdfaa781c6ecb6b533d50f5a8a1b6892e9fe5609ccccd07e041b20a"; | ||
export const TAPROOT_SIGNET_SCRIPT_PUBKEY = | ||
"5120c28a37fa80c20816185d046ba3be168e42e644c3072a99da16183306ea8d2924"; | ||
|
||
export const NATIVE_SEGWIT_SIGNET_ADDRESS = | ||
"tb1qrspcmpwh4k05xlflx7fqz5dmgpt06fydfmyzyr"; | ||
export const NATIVE_SEGWIT_SIGNET_PK = | ||
"026b4ebd2b5ec63b8e9260c540921e46e75bbdcc42cf14bc3c0274e8d6a544bda1"; | ||
export const NATIVE_SEGWIT_SIGNET_SCRIPT_PUBKEY = | ||
"00141c038d85d7ad9f437d3f37920151bb4056fd248d"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I run
npm run test:e2e
I see this. Is that expected behaviour?