QA pass on the member profile gate: stable button ids, completion opens the dashboard tab, local devCode, 47-test E2E suite

Findings fixed: the gate's buttons had no stable ids (fragile to test and maintain), and finishing the
gate left the member on the pitch tab where the profile card and Messages are not visible, so
completion now opens the Position Dashboard tab. /api/public/profile/email-start returns devCode
outside production so the flow is testable locally, matching the InstantAdPay pattern.

qa/profiles-unit.mjs (28 assertions) and qa/gate-e2e.mjs (47 assertions, real sessions, real UI) with
a README. All pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
martbost
2026-09-16 17:40:03 -05:00
parent 2c5fff20f5
commit 2f90e1a97f
7 changed files with 232 additions and 10 deletions
+11 -8
View File
@@ -38,6 +38,7 @@
if (editable) { // editing an existing profile can be abandoned; the first-time gate can not
var x = el('button', 'position:absolute;top:10px;right:12px;z-index:2;width:34px;height:34px;border-radius:50%;border:none;' +
'cursor:pointer;background:rgba(255,255,255,.08);color:#fff;font-size:20px;line-height:1;font-weight:700;', '&times;');
x.id = 'pgClose';
x.setAttribute('aria-label', 'Close');
x.addEventListener('click', close);
card.appendChild(x);
@@ -68,9 +69,10 @@
'background:rgba(255,255,255,.04);color:#fff;font-size:16px;margin-bottom:10px;';
return i;
}
function button(label) {
function button(label, id) {
var b = el('button', 'width:100%;padding:13px 16px;border-radius:11px;border:none;cursor:pointer;font-size:15px;font-weight:700;' +
'background:linear-gradient(180deg,' + GOLD + ',#b8932f);color:#1a1205;', label);
if (id) b.id = id;
return b;
}
function errLine() { return el('p', 'margin:0 0 10px;font-size:13px;color:#ff8b8b;display:none;'); }
@@ -83,7 +85,7 @@
var err = errLine(); card.appendChild(err);
var i = input('pgUser', 'e.g. ' + (state.suggest || 'member' + state.id), (state.profile && state.profile.username) || '');
card.appendChild(i);
var b = button('Save and continue');
var b = button('Save and continue', 'pgUserSave');
card.appendChild(b);
var go = async function () {
err.style.display = 'none'; b.disabled = true; b.textContent = 'Saving…';
@@ -112,14 +114,14 @@
var err = errLine(); card.appendChild(err);
var i = input('pgEmail', 'you@example.com', prefill, 'email');
card.appendChild(i);
var b = button(prefill ? 'Send me the code' : 'Send me a code');
var b = button(prefill ? 'Send me the code' : 'Send me a code', 'pgMailSend');
card.appendChild(b);
var codeWrap = el('div', 'display:none;margin-top:14px;padding-top:14px;border-top:1px solid rgba(255,255,255,.1);');
var sentNote = note('', TEAL); codeWrap.appendChild(sentNote);
var ci = input('pgCode', '6-digit code', '');
ci.inputMode = 'numeric'; ci.maxLength = 6;
codeWrap.appendChild(ci);
var cb = button('Confirm and finish');
var cb = button('Confirm and finish', 'pgCodeConfirm');
codeWrap.appendChild(cb);
var again = el('p', 'margin:10px 0 0;font-size:12.5px;color:#7f93a8;text-align:center;cursor:pointer;', 'Wrong address? Change it and send a new code.');
again.addEventListener('click', function () { codeWrap.style.display = 'none'; b.disabled = false; b.textContent = 'Send me a code'; i.focus(); });
@@ -159,14 +161,15 @@
'<div style="font-size:42px;line-height:1">✅</div>' +
'<h2 style="margin:10px 0 6px;font-size:21px;color:#fff">You are all set, @' + esc(state.profile.username) + '</h2>' +
'<p style="margin:0 0 16px;font-size:13.5px;line-height:1.6;color:#9fb3c8">Your leader can reach you now, and every payout to your wallet sends you a note.</p></div>';
var b = button('Open my dashboard');
b.addEventListener('click', close);
var b = button('Open my dashboard', 'pgDone');
b.addEventListener('click', function () { close(true); });
card.appendChild(b);
setTimeout(close, 2600);
setTimeout(function () { close(true); }, 2600);
}
function close() {
function close(openDash) {
if (back && back.parentNode) back.parentNode.removeChild(back);
back = null;
if (openDash) { try { var b = document.querySelector('.mp-tab[data-tab="dash"]'); if (b) b.click(); } catch (e) {} }
if (resolveDone) { var r = resolveDone; resolveDone = null; r((state && state.profile) || null); }
}
function next() {