QA: end-to-end join-flow harness proving the post-registration sign-in, including the refuse regression

qa/harness-server.js boots the real server with chain reads stubbed (COLD=1 reproduces the cached-index
state that left #787 without a profile). qa/join-flow-e2e.mjs drives the real /join-now page with a fake
wallet producing genuine secp256k1 signatures.

Three scenarios pass: signs on a cold index (9) - the gate appears on their own dashboard; refuses to
sign (10) - REGRESSION, the join still completes and redirects with the page usable; signs on a warm
index (9). Full set green: profiles-unit 28, signin-fallback 7, gate-e2e 47, join-flow 9/10/9, plus the
live shared-link check.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
martbost
2026-09-16 19:05:04 -05:00
parent 49a0778a53
commit 0189278aa5
3 changed files with 196 additions and 0 deletions
+42
View File
@@ -0,0 +1,42 @@
// QA harness: boots the real server with the chain reads stubbed, so the join flow
// can be driven end to end without spending POL or waiting on the indexer.
//
// TEST_ADDR=0x.. TEST_ID=9001 COLD=1 PORT=3399 DATA_DIR=... node qa/harness-server.js
//
// COLD=1 reproduces the state that broke #787: the cached index does NOT know the
// brand-new position, so only a live contract read can resolve it.
const path = require('path');
process.chdir(path.join(__dirname, '..'));
const chain = require('../chain.js');
const ADDR = String(process.env.TEST_ADDR || '').toLowerCase();
const ID = Number(process.env.TEST_ID || 9001);
const COLD = process.env.COLD !== '0';
let seeded = !COLD; // warm index = already knows the member
chain.startIndexer = function () { /* no RPC polling in the harness */ };
chain.memberIdByAccount = function (a) {
return (seeded && String(a || '').toLowerCase() === ADDR) ? ID : null;
};
chain.verifyMember = async function (id) {
if (Number(id) !== ID) return { registered: false };
seeded = true; // a live read seeds the index, as the real one does
return { registered: true, id: ID, account: ADDR, referrerId: 21, uplineId: 21, tier: 2, level: 1,
directCount: 0, joinedAt: Math.floor(Date.now() / 1000), tierName: 'Premium', levelName: 'Scintilla' };
};
chain.memberPublic = async function (id) { return Number(id) === ID ? { registered: true, id: ID, level: 1, tier: 2, directCount: 0 } : { registered: false, id }; };
chain.memberLookup = async function (id) { return chain.memberPublic(id); };
chain.isInTeam = function () { return true; };
chain.getPayoutsPublic = function () { return []; };
chain.getIncome = async function () { return []; };
chain.getMatrixTree = async function () { return null; };
chain.getCoachingScan = async function () { return { rows: [] }; };
chain.liveDirects = async function () { return []; };
chain.balanceOf = async function () { return '0'; };
chain.getOwnerUpgradeNeeds = async function () { return null; };
chain.getOrgRouting = async function () { return null; };
chain.getOrgShare = async function () { return null; };
chain.nextOpenPosition = function () { return 21; };
console.log('harness: addr=' + ADDR + ' id=' + ID + ' coldIndex=' + COLD);
require('../server.js');