test(sweep): add UI-sweep targets for the new syncing / no-peers / chat-identity states
Capture the states the earlier verification couldn't reach: - overview-syncing: the balance "catching up — funds are safe" strip (P4). - overview-no-peers: the node-status banner's no-peers detail (P2; full-node only — renders as a plain Overview in the Lite sweep binary). - chat-identity-preparing / -unavailable: the chat empty states that used to all say "unlock your wallet" (P3). Setup clears the fabricated demo identity (clearIdentity wipes only the key; the demo message store survives); sweepEnsureDemoChatIdentity() re-fabricates on teardown so later targets keep the populated chat UI. Also make the demo baseline a genuinely synced node (tip_known=true) so the no-peers banner only appears on its own target, and dismiss the lite first-run welcome prompt during the demo so it stops occluding every lite screenshot (snapshotted + restored). Verified: all four new captures render correctly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1677,6 +1677,7 @@ private:
|
||||
std::string sweep_sandbox_;
|
||||
bool sweep_chat_identity_fabricated_ = false; // seedChatDemoData() made the demo chat identity
|
||||
void applyHealthyDemoState(); // reset the connection/encryption flags to the healthy demo values
|
||||
void sweepEnsureDemoChatIdentity(); // re-fabricate a demo chat identity if none (sweep teardown)
|
||||
void writeSweepManifest() const;
|
||||
// Snapshot of the state_ fields the demo installer mutates, restored at sweep end. Kept as a
|
||||
// plain struct because WalletState has reference-alias members and isn't copy-assignable.
|
||||
@@ -1692,6 +1693,7 @@ private:
|
||||
double market_price_usd=0;
|
||||
double market_change_24h=0;
|
||||
WizardPhase wizard_phase = WizardPhase::None; // the demo state dismisses the wizard
|
||||
bool lite_firstrun_dismissed = false; // the demo dismisses the lite welcome prompt
|
||||
} sweep_state_snapshot_;
|
||||
bool sidebar_user_toggled_ = false; // user manually toggled — suppress auto-collapse
|
||||
float sidebar_width_anim_ = 0.0f; // animated width (0 = uninitialized)
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
#include "ui/windows/folder_picker.h"
|
||||
#include "ui/pages/settings_page.h"
|
||||
#include "chat/chat_protocol.h"
|
||||
#include "chat/chat_identity.h" // deriveChatIdentityFromSecret / ChatIdentityStatus (sweep identity)
|
||||
#include "chat/chat_crypto.h" // ChatKeyPair / wipeChatKeyPair
|
||||
#include "util/i18n.h"
|
||||
#include "util/platform.h"
|
||||
#include "util/private_temp_dir.h"
|
||||
@@ -159,11 +161,15 @@ void App::installDemoWalletData()
|
||||
s.market_price_usd = state_.market.price_usd;
|
||||
s.market_change_24h = state_.market.change_24h;
|
||||
s.wizard_phase = wizard_phase_;
|
||||
s.lite_firstrun_dismissed = lite_firstrun_dismissed_;
|
||||
s.valid = true;
|
||||
|
||||
applyHealthyDemoState();
|
||||
state_.sync.blocks = state_.sync.headers = 3124322;
|
||||
state_.sync.verification_progress = 1.0; state_.sync.syncing = false;
|
||||
state_.sync.tip_known = true; // a healthy synced node knows the peer-derived tip (so the no-peers
|
||||
state_.sync.building_witnesses = false; state_.sync.rescanning = false; // banner only shows on its target
|
||||
lite_firstrun_dismissed_ = true; // the demo "has" a wallet — don't overlay the lite welcome prompt
|
||||
// Legacy (pre-seed) wallet so the Settings "Migrate to seed" button glows in the sweep.
|
||||
wallet_seed_status_ = WalletSeedStatus::NoMnemonic;
|
||||
|
||||
@@ -260,6 +266,20 @@ void App::applyHealthyDemoState()
|
||||
wizard_phase_ = WizardPhase::None;
|
||||
}
|
||||
|
||||
// Re-fabricate an identity-only demo chat identity (no messages — the demo store is untouched by
|
||||
// clearIdentity) so a chat-identity sweep target's teardown restores the populated chat UI. Mirrors the
|
||||
// identity half of seedChatDemoData(); never clobbers a real identity (only runs when none is held).
|
||||
void App::sweepEnsureDemoChatIdentity()
|
||||
{
|
||||
if (!chat::hushChatFeatureEnabledAtBuild()) return;
|
||||
if (chat_service_.hasIdentity()) return;
|
||||
chat::ChatKeyPair keys;
|
||||
const std::string demoSecret = generateChatLocalId("demo-chat:", 24); // random, per-run
|
||||
if (chat::deriveChatIdentityFromSecret(demoSecret, keys).status == chat::ChatIdentityStatus::Ready)
|
||||
chat_service_.setIdentity(keys);
|
||||
chat::wipeChatKeyPair(keys);
|
||||
}
|
||||
|
||||
// Refuse a full sweep while any real workflow it would fake is in flight: its surfaces overwrite the
|
||||
// migration, wallet-switch, security-workflow and seed-backup state in memory, and its teardown resets it.
|
||||
const char* App::fullSweepBlockedReason() const
|
||||
@@ -307,6 +327,7 @@ void App::clearDemoWalletData()
|
||||
state_.market.price_history = g_marketHistorySnapshot;
|
||||
g_marketHistorySnapshot.clear();
|
||||
wizard_phase_ = s.wizard_phase; // applyHealthyDemoState() dismissed it
|
||||
lite_firstrun_dismissed_ = s.lite_firstrun_dismissed;
|
||||
s = SweepStateSnapshot{}; // invalidate
|
||||
|
||||
// Sandbox: close what shows it, then delete it (error_code overloads only; at worst temp debris,
|
||||
@@ -703,6 +724,57 @@ void App::buildSweepCatalog()
|
||||
[](App& a) { a.state_.connected = false; a.state_.encryption_state_known = false; },
|
||||
[](App& a) { a.applyHealthyDemoState(); });
|
||||
|
||||
// Restore the healthy synced demo sync-state (applyHealthyDemoState leaves state_.sync alone).
|
||||
auto resetDemoSync = [](App& a) {
|
||||
a.applyHealthyDemoState();
|
||||
a.state_.sync.syncing = false; a.state_.sync.building_witnesses = false;
|
||||
a.state_.sync.rescanning = false; a.state_.sync.verification_progress = 1.0;
|
||||
a.state_.sync.tip_known = true;
|
||||
a.state_.sync.blocks = a.state_.sync.headers = 3124322;
|
||||
};
|
||||
// Balance tab while the node is still catching up (connected, tip known, verifying) → the shared
|
||||
// "catching up — your funds are safe" strip above whichever layout renders (P4).
|
||||
add("overview-syncing", ui::NavPage::Overview,
|
||||
[](App& a) {
|
||||
a.applyHealthyDemoState();
|
||||
a.state_.sync.tip_known = true;
|
||||
a.state_.sync.syncing = true;
|
||||
a.state_.sync.building_witnesses = false;
|
||||
a.state_.sync.rescanning = false;
|
||||
a.state_.sync.verification_progress = 0.62;
|
||||
a.state_.sync.blocks = 1934000; a.state_.sync.headers = 3124322;
|
||||
},
|
||||
resetDemoSync);
|
||||
// Full node connected to the daemon but with zero network peers → the node-status banner's honest
|
||||
// detail (P2). Full-node only: the Lite build has no node, so there this renders as a plain Overview.
|
||||
add("overview-no-peers", ui::NavPage::Overview,
|
||||
[](App& a) {
|
||||
a.applyHealthyDemoState();
|
||||
a.state_.sync.tip_known = false; // no peer-derived tip → NoPeers banner
|
||||
a.state_.sync.syncing = false;
|
||||
a.state_.sync.blocks = 3124322; a.state_.sync.headers = 3124322;
|
||||
a.connection_status_ = "Connected";
|
||||
},
|
||||
resetDemoSync);
|
||||
|
||||
// Chat with no derived identity yet — the states that previously ALL said "unlock your wallet" (P3).
|
||||
// Setup clears the fabricated demo identity (clearIdentity wipes only the key; the demo messages stay
|
||||
// in the store); teardown re-fabricates an identity so the populated chat UI returns for later targets.
|
||||
add("chat-identity-preparing", ui::NavPage::Chat,
|
||||
[](App& a) {
|
||||
a.chat_service_.clearIdentity();
|
||||
a.chat_identity_unavailable_ = false;
|
||||
a.chat_identity_fetch_in_flight_ = false;
|
||||
},
|
||||
[](App& a) { a.chat_identity_unavailable_ = false; a.sweepEnsureDemoChatIdentity(); });
|
||||
add("chat-identity-unavailable", ui::NavPage::Chat,
|
||||
[](App& a) {
|
||||
a.chat_service_.clearIdentity();
|
||||
a.chat_identity_unavailable_ = true; // view-only / legacy wallet with no exportable secret
|
||||
a.chat_identity_fetch_in_flight_ = false;
|
||||
},
|
||||
[](App& a) { a.chat_identity_unavailable_ = false; a.sweepEnsureDemoChatIdentity(); });
|
||||
|
||||
// A mining (transparent) address as the recipient: shown as unpayable, Send disabled.
|
||||
add("send-mining-recipient", ui::NavPage::Send,
|
||||
[](App& a) { ui::SweepSetSendRecipient(&a, "R9NXAVJezHiBnT3ijTpg3JUZre7PxhJWti"); },
|
||||
|
||||
Reference in New Issue
Block a user