Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 18 additions & 8 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,13 +160,23 @@ Implication for feature work:

The app merge gate (`e2e.yml` / `e2e-tests.yml`) runs `BACKEND=local` (docker Electrum/LND). Staging (`e2e-staging.yml`) and migration (`e2e_migration.yml`) run `BACKEND=regtest` against stag0.

| Tags | Where |
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `@transfer_2` | Local only (LND channel, no Blocktank) |
| `@transfer_1`, `@transfer_max` | Staging via `@transfer_staging` (keep `@transfer_1` / `@transfer_max` / `@transfer`). `@transfer_1` is not in app `e2e-staging.yml` yet — add the transfer shard once it is 3× green. |
| `@multi_address_2` | Staging via `@multi_address_staging` (keep `@multi_address_2` for other greps). Staging workflow greps `@multi_address_staging` only. |
| `@pubky` / `@paykit` / `@pubky_profile` | Staging pubky shard via `@pubky_staging` (public-payments + profile). Keep `@pubky` / `@paykit` / `@pubky_profile` for other greps. |
| `@hardware_wallet` | iOS local (connect/receive/on-chain); Android full path on staging. Do **not** add `@hardware_wallet_staging` — local merge-gate still greps `@hardware_wallet`. |
| `@migration_*` | Migration workflow (nightly, dispatch, `release-*` PRs) |
Capability tags (`@settings`, `@boost`, `@send`, …) stay on titles so Android local can keep grepping them. iOS queue tags are disjoint from `@staging` and from `*_staging` (mocha grep is a regex substring).

| Tag | Android local | iOS Mini (`e2e-tests.yml`) | Staging (`e2e-staging.yml`) |
|---|---|---|---|
| `@ios_gate` | ignored | merge gate grep | no |
| `@ios_nightly` | ignored (still run via `@settings` etc.) | no | extra iOS shard (`ios_nightly_ui`), GitHub mac, not Mini |
| `@transfer_2` | yes | `@ios_gate` | no (LND, no Blocktank) |
| `@transfer_1`, `@transfer_max` | no | no | `@transfer_staging` (keep `@transfer_1` / `@transfer_max` / `@transfer`). `@transfer_1` is not in app `e2e-staging.yml` yet — add the transfer shard once it is 3× green. |
| `@multi_address_2` | no | no | `@multi_address_staging` only |
| `@pubky` / `@paykit` / `@pubky_profile` | no | no | `@pubky_staging` (keep capability tags for other greps) |
| `@boost`, `@multi_address_3` | yes | `@ios_gate` (needs exclusive miner) | no |
| `@send_2`, `@send_3`, `@lightning`, `@lnurl`, `@onboarding`, `@backup`, `@onchain_1`, `@onchain_2`, `@receive`, `@multi_address_4` | yes | `@ios_gate` | no |
| `@settings`, `@numberpad`, `@widgets`, `@security`, `@send_1`, `@multi_address_1` | yes | `@ios_nightly` | iOS nightly shard |
| `@onchain_3` | yes (`@onchain`) | no | no |
| `@hardware_wallet` | no (staging only) | `@ios_gate` | Android staging greps `@hardware_wallet`; do **not** add `@hardware_wallet_staging`. iOS Mini greps `@ios_gate` on this describe. No Trezor on GitHub mac. |
| `@migration_*` | migration workflow (nightly, dispatch, `release-*` PRs) | same | no |

Put `@ios_gate` / `@ios_nightly` on `describe` when the whole file is one iOS queue; on `ciIt` when siblings split (`@send_1` vs `@send_2`, `@multi_address_1` vs `_3`).

Poke staging with `gh workflow run e2e-staging.yml` on the app repo (does not queue the iOS Mini). Optional Slack post to `#bitkit-staging-nightly` via dispatch `post_to_slack`.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -292,16 +292,17 @@ npm run e2e:android -- --mochaOpts.grep "@onchain|@backup|@onboarding"
npm run e2e:android -- --mochaOpts.grep "@backup" --mochaOpts.invert
```

**Local vs staging (CI):** the app merge gate uses `BACKEND=local` and specific tags (`@transfer_2`, not blob `@transfer`). Staging shards grep dedicated `*_staging` tags:
**Local vs staging (CI):** the app merge gate uses `BACKEND=local`. Android greps capability tags (`@settings`, `@send`, `@boost`, …). iOS Mini greps `@ios_gate`. Staging shards grep dedicated `*_staging` tags, plus iOS-only `@ios_nightly` for UI that Android still runs on local:

| Staging grep | Specs |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `@transfer_staging` | `@transfer_1` and `@transfer_max` (keep those tags plus `@transfer` on the describe). `@transfer_1` is not in app `e2e-staging.yml` yet. |
| `@multi_address_staging` | Staging multi-address (`@multi_address_2` kept for other greps) |
| `@pubky_staging` | Public-payments + pubky-profile (`@pubky` / `@paykit` / `@pubky_profile` kept for other greps) |
| `@hardware_wallet` | Unchanged — do not add `@hardware_wallet_staging` (iOS local merge-gate still greps this) |
| `@ios_nightly` | iOS-only UI shard (`@settings`, `@numberpad`, `@widgets`, `@security`, `@send_1`, `@multi_address_1`). Does not queue the Mini. |
| `@hardware_wallet` | Android staging only — do not add `@hardware_wallet_staging` (iOS Mini greps `@ios_gate` on this describe) |

Bare `@staging` may still be present next to those tags. Migration (`@migration_*`) is a separate nightly / dispatch / `release-*` PR workflow.
Bare `@staging` may still be present next to the `*_staging` tags. Migration (`@migration_*`) is a separate nightly / dispatch / `release-*` PR workflow. See AGENTS.md for the full matrix.

---

Expand Down
2 changes: 1 addition & 1 deletion test/specs/backup.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { ensureLocalFunds } from '../helpers/regtest';
import { openSettings } from '../helpers/navigation';
import { deleteAllDefaultWidgets } from '../helpers/widgets';

describe('@backup - Backup', () => {
describe('@backup @ios_gate - Backup', () => {
let electrum: Awaited<ReturnType<typeof initElectrum>> | undefined;

before(async () => {
Expand Down
2 changes: 1 addition & 1 deletion test/specs/boost.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { reinstallApp } from '../helpers/setup';
import { ciIt } from '../helpers/suite';
import { ensureLocalFunds, getExternalAddress, mineBlocks } from '../helpers/regtest';

describe('@boost - Boost', () => {
describe('@boost @ios_gate - Boost', () => {
let electrum: { waitForSync: any; stop: any };

before(async () => {
Expand Down
2 changes: 1 addition & 1 deletion test/specs/hardware-wallet.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { ensureLocalFunds, getBackend, getExternalAddress } from '../helpers/reg
import { reinstallApp } from '../helpers/setup';
import { ciIt } from '../helpers/suite';

describe('@hardware_wallet - Hardware Wallet', () => {
describe('@hardware_wallet @ios_gate - Hardware Wallet', () => {
const walletLabel = 'E2E Trezor';
const renamedWalletLabel = 'E2E Renamed Trezor';
let electrum: Awaited<ReturnType<typeof initElectrum>> | undefined;
Expand Down
2 changes: 1 addition & 1 deletion test/specs/lightning.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import { ciIt } from '../helpers/suite';
import { ensureLocalFunds, getBitcoinRpc, mineBlocks } from '../helpers/regtest';
import { openSettings } from '../helpers/navigation';

describe('@lightning - Lightning', () => {
describe('@lightning @ios_gate - Lightning', () => {
let electrum: { waitForSync: any; stop: any };
// LND tests only work with BACKEND=local
let rpc: ReturnType<typeof getBitcoinRpc>;
Expand Down
2 changes: 1 addition & 1 deletion test/specs/lnurl.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ function msatsToCeilSatsString(msats: number): string {
return Math.ceil(msats / 1000).toString();
}

describe('@lnurl - LNURL', () => {
describe('@lnurl @ios_gate - LNURL', () => {
let electrum: Awaited<ReturnType<typeof initElectrum>> | undefined;
let lnurlServer: any;
// LND tests only work with BACKEND=local
Expand Down
6 changes: 3 additions & 3 deletions test/specs/multiaddress.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ describe('@multi_address - Multi address', () => {
await electrum?.stop();
});

ciIt('@multi_address_1 - Receive to each address type and send max combined', async () => {
ciIt('@multi_address_1 @ios_nightly - Receive to each address type and send max combined', async () => {
const addressTypes: addressTypePreference[] = ['p2pkh', 'p2sh-p2wpkh', 'p2wpkh', 'p2tr'];
const satsPerAddressType = 100_000;
const { totalFundedSats } = await switchAndFundEachAddressType({
Expand Down Expand Up @@ -174,7 +174,7 @@ describe('@multi_address - Multi address', () => {
);

ciIt(
'@multi_address_3 - Receive to each type, send almost max, verify change to primary, then RBF',
'@multi_address_3 @ios_gate - Receive to each type, send almost max, verify change to primary, then RBF',
async () => {
const addressTypes: addressTypePreference[] = ['p2pkh', 'p2sh-p2wpkh', 'p2wpkh', 'p2tr'];
const satsPerAddressType = 10_000;
Expand Down Expand Up @@ -248,7 +248,7 @@ describe('@multi_address - Multi address', () => {
);

ciIt(
'@multi_address_4 - Receive to each type, open external channel with max, keep Legacy untouched',
'@multi_address_4 @ios_gate - Receive to each type, open external channel with max, keep Legacy untouched',
async () => {
const rpc = getBitcoinRpc();
const addressTypes: addressTypePreference[] = ['p2pkh', 'p2sh-p2wpkh', 'p2wpkh', 'p2tr'];
Expand Down
2 changes: 1 addition & 1 deletion test/specs/numberpad.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { ciIt } from '../helpers/suite';
import { ensureLocalFunds } from '../helpers/regtest';
import { openSettings } from '../helpers/navigation';

describe('@numberpad - NumberPad', () => {
describe('@numberpad @ios_nightly - NumberPad', () => {
let electrum: Awaited<ReturnType<typeof initElectrum>> | undefined;

before(async () => {
Expand Down
2 changes: 1 addition & 1 deletion test/specs/onboarding.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { reinstallApp } from '../helpers/setup';
import { ciIt } from '../helpers/suite';
import { openSettings } from '../helpers/navigation';

describe('@onboarding - Onboarding', () => {
describe('@onboarding @ios_gate - Onboarding', () => {
beforeEach(async () => {
await reinstallApp();
});
Expand Down
4 changes: 2 additions & 2 deletions test/specs/onchain.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ describe('@onchain - Onchain', () => {
await electrum?.stop();
});

ciIt('@onchain_1 - Receive and send some out', async () => {
ciIt('@onchain_1 @ios_gate - Receive and send some out', async () => {
// receive some first
const satsToReceive = 100_000;
await receiveOnchainFunds({ sats: satsToReceive, expectHighBalanceWarning: false });
Expand Down Expand Up @@ -107,7 +107,7 @@ describe('@onchain - Onchain', () => {
// - shows warnings for sending over 100$ or 50% of total
// - avoid creating dust output

ciIt('@onchain_2 - Can receive 2 transactions and send them all at once', async () => {
ciIt('@onchain_2 @ios_gate - Can receive 2 transactions and send them all at once', async () => {
// - can receive to 2 addresses and tag them //
for (let i = 1; i <= 2; i++) {
const address = await getReceiveAddress();
Expand Down
2 changes: 1 addition & 1 deletion test/specs/receive.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
import { reinstallApp } from '../helpers/setup';
import { ciIt } from '../helpers/suite';

describe('@receive - Receive', () => {
describe('@receive @ios_gate - Receive', () => {
before(async () => {
await reinstallApp();
await completeOnboarding();
Expand Down
2 changes: 1 addition & 1 deletion test/specs/security.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { ciIt } from '../helpers/suite';
import { ensureLocalFunds, getExternalAddress } from '../helpers/regtest';
import { openSettings } from '../helpers/navigation';

describe('@security - Security And Privacy', () => {
describe('@security @ios_nightly - Security And Privacy', () => {
let electrum: { waitForSync: any; stop: any };

before(async () => {
Expand Down
15 changes: 6 additions & 9 deletions test/specs/send.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,8 @@ import { openSettings } from '../helpers/navigation';

describe('@send - Send', () => {
let electrum: { waitForSync: any; stop: any };
// LND tests only work with BACKEND=local
let rpc: ReturnType<typeof getBitcoinRpc>;

before(async () => {
rpc = getBitcoinRpc();
await ensureLocalFunds();
electrum = await initElectrum();
});
Expand All @@ -69,7 +66,7 @@ describe('@send - Send', () => {
electrum?.stop();
});

ciIt('@send_1 - Validates payment data in the manual input', async () => {
ciIt('@send_1 @ios_nightly - Validates payment data in the manual input', async () => {
await tap('Send');
await sleep(1000);
await handleAndroidAlert('permission_allow_foreground_only_button');
Expand Down Expand Up @@ -98,7 +95,7 @@ describe('@send - Send', () => {
}

// check validation for address when balance is 0
const address = await rpc.getNewAddress();
const address = await getExternalAddress();
console.info({ address });
try {
await typeRecipientInput(address, { confirmKeyboard: false });
Expand Down Expand Up @@ -184,7 +181,7 @@ describe('@send - Send', () => {
}
});

ciIt('@send_2 - Can receive funds and send to different invoices', async () => {
ciIt('@send_2 @ios_gate - Can receive funds and send to different invoices', async () => {
// Test plan:
// Prepare
// - receive onchain funds
Expand All @@ -201,7 +198,7 @@ describe('@send - Send', () => {

await receiveOnchainFunds();

// send funds to LND node and open a channel
const rpc = getBitcoinRpc();
const { lnd, lndNodeID } = await setupLND(rpc, lndConfig);
await electrum?.waitForSync();

Expand Down Expand Up @@ -554,10 +551,10 @@ describe('@send - Send', () => {
await elementById('Activity-2').waitForDisplayed();
});

ciIt('@send_3 - Can pay regular invoices with msat precision', async () => {
ciIt('@send_3 @ios_gate - Can pay regular invoices with msat precision', async () => {
await receiveOnchainFunds();

// send funds to LND node and open a channel
const rpc = getBitcoinRpc();
const { lnd, lndNodeID } = await setupLND(rpc, lndConfig);
await electrum?.waitForSync();

Expand Down
9 changes: 7 additions & 2 deletions test/specs/settings.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ import {
waitForToast,
ToastId,
} from '../helpers/actions';
import { electrumHost, electrumPort } from '../helpers/constants';
import { electrumHost, electrumPort, getBackend } from '../helpers/constants';
import { launchFreshApp, reinstallApp } from '../helpers/setup';
import { ciIt } from '../helpers/suite';
import { openSettings, openSupport } from '../helpers/navigation';

describe('@settings - Settings', () => {
describe('@settings @ios_nightly - Settings', () => {
before(async () => {
await reinstallApp();
await completeOnboarding();
Expand Down Expand Up @@ -323,6 +323,11 @@ describe('@settings - Settings', () => {
});

ciIt('@settings_10 - Can enter wrong Electrum server and get an error message', async () => {
if (getBackend() !== 'local') {
console.info('→ Skipping Electrum TCP/TLS format checks (BACKEND is not local)');
return;
}

await openSettings('advanced');
await tap('ElectrumConfig');

Expand Down
2 changes: 1 addition & 1 deletion test/specs/transfer.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -725,7 +725,7 @@ describe('@transfer - Transfer', () => {
}
);

ciIt('@transfer_2 - Can open a channel to external node', async () => {
ciIt('@transfer_2 @ios_gate - Can open a channel to external node', async () => {
const rpc = getBitcoinRpc();
await receiveOnchainFunds({ sats: 100_000 });

Expand Down
2 changes: 1 addition & 1 deletion test/specs/widgets.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
type WidgetId,
} from '../helpers/widgets';

describe('@widgets - Widgets', () => {
describe('@widgets @ios_nightly - Widgets', () => {
beforeEach(async () => {
await reinstallApp();
await completeOnboarding();
Expand Down