Skip to content

Commit f052a26

Browse files
authored
Merge pull request #120 from synonymdev/test/cjit-mainnet
add CJIT order mainnet test
2 parents 0cfa95e + f398833 commit f052a26

4 files changed

Lines changed: 267 additions & 12 deletions

File tree

test/specs/mainnet.cjit.e2e.ts

Lines changed: 0 additions & 10 deletions
This file was deleted.
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
import {
2+
elementById,
3+
enterAmount,
4+
elementsById,
5+
restoreWallet,
6+
sleep,
7+
tap,
8+
} from '../../helpers/actions';
9+
import { ciIt } from '../../helpers/suite';
10+
11+
const channelOrderSeed = process.env.CHANNEL_ORDER_SEED ?? process.env.CJIT_SEED;
12+
const transferAmountSats = Number.parseInt(process.env.CHANNEL_ORDER_AMOUNT_SATS ?? '20000', 10);
13+
const minimumFeeSats = Number.parseInt(process.env.CHANNEL_ORDER_MIN_FEE_SATS ?? '100', 10);
14+
const minimumReceivingCapacitySats = Number.parseInt(process.env.CHANNEL_ORDER_MIN_RECEIVING_SATS ?? '100000', 10);
15+
16+
function parseSats(value: string): number {
17+
const digits = value.replace(/[^\d]/g, '');
18+
return Number.parseInt(digits, 10);
19+
}
20+
21+
async function maybeTap(testId: string, timeout = 4000): Promise<boolean> {
22+
const element = elementById(testId);
23+
try {
24+
await element.waitForDisplayed({ timeout });
25+
} catch {
26+
return false;
27+
}
28+
await tap(testId);
29+
return true;
30+
}
31+
32+
async function tapSpendingAmountContinueWithRetry(retries = 3): Promise<void> {
33+
for (let attempt = 0; attempt < retries; attempt += 1) {
34+
await tap('SpendingAmountContinue');
35+
const moreButton = elementById('SpendingConfirmMore');
36+
try {
37+
await moreButton.waitForDisplayed({ timeout: 5000 });
38+
return;
39+
} catch {
40+
await sleep(1000);
41+
}
42+
}
43+
44+
throw new Error('Unable to reach transfer confirm screen after tapping SpendingAmountContinue');
45+
}
46+
47+
async function getMoneyTextValues(minCount: number): Promise<number[]> {
48+
if (!driver.isAndroid) {
49+
throw new Error('Mainnet channel-order smoke is currently supported on Android only');
50+
}
51+
52+
await browser.waitUntil(
53+
async () => {
54+
const values = await elementsById('MoneyText');
55+
return (await values.length) >= minCount;
56+
},
57+
{
58+
timeout: 15_000,
59+
interval: 300,
60+
timeoutMsg: `Timed out waiting for at least ${minCount} MoneyText values`,
61+
},
62+
);
63+
64+
const moneyValues = await elementsById('MoneyText');
65+
const parsedValues: number[] = [];
66+
67+
for (const valueEl of moneyValues) {
68+
const valueText = await valueEl.getText();
69+
const sats = parseSats(valueText);
70+
if (Number.isInteger(sats)) {
71+
parsedValues.push(sats);
72+
}
73+
}
74+
75+
return parsedValues;
76+
}
77+
78+
describe('@channel_order_mainnet - Channel order smoke', () => {
79+
let walletSeed = '';
80+
81+
before(() => {
82+
if (!channelOrderSeed) {
83+
throw new Error('Missing CHANNEL_ORDER_SEED (or CJIT_SEED fallback) env var');
84+
}
85+
walletSeed = channelOrderSeed;
86+
if (!Number.isInteger(transferAmountSats) || transferAmountSats <= 0) {
87+
throw new Error(`Invalid CHANNEL_ORDER_AMOUNT_SATS value: ${process.env.CHANNEL_ORDER_AMOUNT_SATS}`);
88+
}
89+
if (!Number.isInteger(minimumFeeSats) || minimumFeeSats <= 0) {
90+
throw new Error(`Invalid CHANNEL_ORDER_MIN_FEE_SATS value: ${process.env.CHANNEL_ORDER_MIN_FEE_SATS}`);
91+
}
92+
if (!Number.isInteger(minimumReceivingCapacitySats) || minimumReceivingCapacitySats <= 0) {
93+
throw new Error(
94+
`Invalid CHANNEL_ORDER_MIN_RECEIVING_SATS value: ${process.env.CHANNEL_ORDER_MIN_RECEIVING_SATS}`,
95+
);
96+
}
97+
});
98+
99+
ciIt('@channel_order_1 - Can validate channel order pricing and liquidity', async () => {
100+
await restoreWallet(walletSeed, {
101+
expectBackupSheet: false,
102+
reinstall: false,
103+
expectAndroidAlert: false,
104+
});
105+
106+
await tap('ActivitySavings');
107+
await tap('TransferToSpending');
108+
await maybeTap('SpendingIntro-button');
109+
110+
await enterAmount(transferAmountSats);
111+
await tapSpendingAmountContinueWithRetry();
112+
113+
const confirmValues = await getMoneyTextValues(4);
114+
const [networkFeeSats, serviceFeeSats, toSpendingAmountSats, totalSats] = confirmValues;
115+
116+
if (!(networkFeeSats > minimumFeeSats)) {
117+
throw new Error(`Network fee ${networkFeeSats} should be greater than ${minimumFeeSats}`);
118+
}
119+
120+
if (!(serviceFeeSats > minimumFeeSats)) {
121+
throw new Error(`Service fee ${serviceFeeSats} should be greater than ${minimumFeeSats}`);
122+
}
123+
124+
if (toSpendingAmountSats !== transferAmountSats) {
125+
throw new Error(`To spending amount ${toSpendingAmountSats} should equal ${transferAmountSats}`);
126+
}
127+
128+
if (!(totalSats > transferAmountSats)) {
129+
throw new Error(`Total ${totalSats} should be greater than ${transferAmountSats}`);
130+
}
131+
132+
await tap('SpendingConfirmMore');
133+
134+
const liquidityValues = await getMoneyTextValues(2);
135+
const [spendingLiquiditySats, receivingLiquiditySats] = liquidityValues;
136+
137+
if (spendingLiquiditySats !== transferAmountSats) {
138+
throw new Error(`Spending liquidity ${spendingLiquiditySats} should equal ${transferAmountSats}`);
139+
}
140+
141+
if (!(receivingLiquiditySats > minimumReceivingCapacitySats)) {
142+
throw new Error(
143+
`Receiving liquidity ${receivingLiquiditySats} should be greater than ${minimumReceivingCapacitySats}`,
144+
);
145+
}
146+
});
147+
});

test/specs/mainnet/cjit.e2e.ts

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import {
2+
completeOnboarding,
3+
elementById,
4+
elementByText,
5+
getTextUnder,
6+
restoreWallet,
7+
sleep,
8+
tap,
9+
} from '../../helpers/actions';
10+
import { reinstallApp } from '../../helpers/setup';
11+
import { ciIt } from '../../helpers/suite';
12+
13+
const cjitSeed = process.env.CJIT_SEED;
14+
const expectedMinimumAmountSats = Number.parseInt(process.env.CJIT_MIN_EXPECTED_SATS ?? '1000', 10);
15+
16+
function parseNumber(value: string): number {
17+
const normalized = value.replace(/\s+/g, '');
18+
const digits = normalized.replace(/[^\d]/g, '');
19+
return Number.parseInt(digits, 10);
20+
}
21+
22+
function parseCjitFees(value: string): { networkFee: number; serviceProviderFee: number } {
23+
const labeledMatch = value.match(
24+
/\$([0-9]+(?:\.[0-9]+)?) network fee and \$([0-9]+(?:\.[0-9]+)?) service provider fee/i,
25+
);
26+
if (labeledMatch) {
27+
return {
28+
networkFee: Number.parseFloat(labeledMatch[1]),
29+
serviceProviderFee: Number.parseFloat(labeledMatch[2]),
30+
};
31+
}
32+
33+
const amountMatches = [...value.matchAll(/\$([0-9]+(?:\.[0-9]+)?)/g)];
34+
if (amountMatches.length >= 2) {
35+
const networkFee = Number.parseFloat(amountMatches[0][1]);
36+
const serviceProviderFee = Number.parseFloat(amountMatches[1][1]);
37+
return {
38+
networkFee,
39+
serviceProviderFee,
40+
};
41+
}
42+
43+
throw new Error(`Could not parse CJIT fees from: "${value}"`);
44+
}
45+
46+
async function waitForNonZeroMinimumAmount(retries = 30): Promise<number> {
47+
for (let attempt = 0; attempt < retries; attempt += 1) {
48+
const minAmountText = await getTextUnder('ReceiveAmountMin');
49+
const minAmountSats = parseNumber(minAmountText);
50+
if (minAmountSats > 0) {
51+
return minAmountSats;
52+
}
53+
await sleep(1000);
54+
}
55+
56+
throw new Error('Timed out waiting for non-zero minimum receive amount');
57+
}
58+
59+
async function setupWallet(): Promise<void> {
60+
if (cjitSeed) {
61+
await restoreWallet(cjitSeed, {
62+
expectBackupSheet: false,
63+
reinstall: false,
64+
expectAndroidAlert: true,
65+
});
66+
return;
67+
}
68+
69+
await completeOnboarding({ isFirstTime: true });
70+
}
71+
72+
describe('@cjit_mainnet - CJIT smoke', () => {
73+
before(async () => {
74+
if (!Number.isInteger(expectedMinimumAmountSats) || expectedMinimumAmountSats <= 0) {
75+
throw new Error(`Invalid CJIT_MIN_EXPECTED_SATS value: ${process.env.CJIT_MIN_EXPECTED_SATS}`);
76+
}
77+
await reinstallApp();
78+
});
79+
80+
ciIt('@cjit_1 - Can create CJIT invoice', async () => {
81+
await setupWallet();
82+
83+
await tap('Receive');
84+
await sleep(2000);
85+
await tap('Tab-spending');
86+
await tap('ShowDetails');
87+
88+
const minAmountSats = await waitForNonZeroMinimumAmount();
89+
if (minAmountSats <= expectedMinimumAmountSats) {
90+
throw new Error(
91+
`Minimum receive amount ${minAmountSats} should be greater than ${expectedMinimumAmountSats}`,
92+
);
93+
}
94+
95+
await tap('ReceiveAmountMin');
96+
await tap('ContinueAmount');
97+
98+
const reviewAmountText = await getTextUnder('-primary');
99+
const reviewAmountSats = parseNumber(reviewAmountText);
100+
if (reviewAmountSats !== minAmountSats) {
101+
throw new Error(`Review amount ${reviewAmountSats} should equal minimum receive amount ${minAmountSats}`);
102+
}
103+
104+
const serviceProviderFeeText = await elementByText('service provider fee', 'contains').getText();
105+
const { networkFee, serviceProviderFee } = parseCjitFees(serviceProviderFeeText);
106+
if (!(networkFee > 0)) {
107+
throw new Error(`Network fee should be greater than 0. Found: "${serviceProviderFeeText}"`);
108+
}
109+
if (!(serviceProviderFee > 0)) {
110+
throw new Error(`Service provider fee should be greater than 0. Found: "${serviceProviderFeeText}"`);
111+
}
112+
113+
await elementByText('Continue').click();
114+
await elementById('QRCode').waitForDisplayed({ timeout: 30_000 });
115+
await sleep(2000);
116+
});
117+
});
118+
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import {
55
enterAddress,
66
restoreWallet,
77
tap,
8-
} from '../helpers/actions';
9-
import { ciIt } from '../helpers/suite';
8+
} from '../../helpers/actions';
9+
import { ciIt } from '../../helpers/suite';
1010

1111
type MainnetLnSuiteConfig = {
1212
suiteTag: string;

0 commit comments

Comments
 (0)