Skip to content

Commit 22f2f83

Browse files
committed
auto-qa: catalogue 3 OPEN PRs + Footer NAV_LINKS lint
Catalogue completion: discovered the repo has only 42 PRs total (range #23..#65 with one gap at #38), not the assumed ~65. The 3 missing from the previous count are all currently OPEN: #36 (chart zoom reset), #40 (position tab indicator), #41 (footer docs hub). Catalogued under a new "Open PRs" section. Catalogue is now 42/42 (full coverage). Snapshot field corrected from "40 / ~65" to "42 / 42" + stale "still need to be catalogued" footer note replaced. Test: footer-links.test.mjs (6 cases) — static lint of NAV_LINKS in src/components/common/Footer.jsx. Pins: - Every entry has label + href - external: true ↔ absolute http(s) href - non-external entries are path-relative - Documentation href is in an accepted set covering BOTH the current external URL AND the post-PR-#41 in-app routes — stays green through the transition, surfaces typos / accidental redirects - Status link pinned at canonical https://status.futarchy.fi Tests: 79 → 85 (interface), 146 → 152 cross-repo. All green.
1 parent 7d7b998 commit 22f2f83

2 files changed

Lines changed: 143 additions & 6 deletions

File tree

auto-qa/PROGRESS.md

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ out fixes in a separate pass.
1313
| Field | Value |
1414
|---|---|
1515
| Branch | `auto-qa` (off `origin/main`) |
16-
| Iterations completed | 18 |
17-
| PRs catalogued | 40 / ~65 |
18-
| PRs classified | 40 |
19-
| Tests added | 78 (4 extractor-sanity + 2 graphql-compat + 5 endpoint-liveness + 10 url-shapes + 2 dead-references + 6 liquidity-math + 7 slippage-math + 8 snapshot-id-extraction + 3 pagination-first-cap + 6 twap-window + 14 impact-formula + 11 proposal-resolution-bucketing — all passing) |
16+
| Iterations completed | 19 |
17+
| PRs catalogued | **42 / 42 (full coverage)** — repo PRs span #23..#65 with one gap at #38; no PRs #1-22 exist |
18+
| PRs classified | 42 |
19+
| Tests added | 84 (4 extractor-sanity + 2 graphql-compat + 5 endpoint-liveness + 10 url-shapes + 2 dead-references + 6 liquidity-math + 7 slippage-math + 8 snapshot-id-extraction + 3 pagination-first-cap + 6 twap-window + 14 impact-formula + 11 proposal-resolution-bucketing + 6 footer-links — all passing) |
2020
| Known gaps documented | 2 (uppercase-`0X` prefix in proposalId param; **PR #47 supabase cleanup is partial — 10 imports remain**) |
2121
| Tools shipped | 2 (`extract-graphql.mjs` + `probe-graphql.mjs`) |
2222
| Test runner | `node --test` via `npm run auto-qa:test` |
@@ -303,6 +303,29 @@ For each merged PR (newest first), capture:
303303
- **Ideal test**: Visual regression
304304
- **Test status**: deferred
305305

306+
## Open PRs (not yet merged — catalogued for completeness)
307+
308+
### PR #41 — Fix footer documentation access with in-app documents hub (OPEN)
309+
- **Class**: bug-fix
310+
- **Hypothesis**: External `https://docs.futarchy.fi` redirected unreliably to a GitHub README in some browsers / wallet webviews. Fix: route the footer through an in-app `/documents` page (alias `/docs`) with curated links.
311+
- **Ideal test**: Two layers — (a) static lint that the Footer's Documentation link resolves to an in-repo route (`/documents` or `/docs`), not a bare external URL; (b) Playwright smoke that navigates to both `/documents` and `/docs` and asserts a non-empty list of links + that no link 404s.
312+
- **Tools needed**: cheap text grep on `Footer.jsx`; Playwright for the navigation test.
313+
- **Test status**: **partially landed** (`auto-qa/tests/footer-links.test.mjs`, 6 cases — pins NAV_LINKS structural invariants AND accepts BOTH the current external URL and post-PR-#41 in-app routes, so it stays green across the merge transition. The Playwright navigation layer remains a follow-up.)
314+
315+
### PR #40 — Add position tab indicator and auto-switch after trade (OPEN)
316+
- **Class**: feature/UX
317+
- **Hypothesis**: n/a
318+
- **Ideal test**: Component test — given a wallet with non-zero `YES - NO` token balance, the Position tab renders the green dot indicator. Auto-switch is a side-effect of the swap-success callback; would need an integration test.
319+
- **Tools needed**: React component-test harness (Storybook play function or Testing Library) + ability to mock wallet balances.
320+
- **Test status**: not-started
321+
322+
### PR #36 — Fix chart zoom reset on data refresh (OPEN)
323+
- **Class**: bug-fix
324+
- **Hypothesis**: A monolithic `useEffect` in `SubgraphChart.jsx` re-ran on every dependency change (60s auto-resync, dark-mode toggle, line-visibility toggle, spot-price update), destroying and rebuilding the chart and discarding the user's zoom/pan state. Fix: split into two effects (chart creation vs. data update via `setData()`), gate `fitContent()` behind a `hasInitiallyFit` ref so it only fires once.
325+
- **Ideal test**: Playwright — load market page, zoom in, wait 65s for auto-resync, assert visible time range hasn't reset. Pure unit version: extract the dependency-array logic and assert the data-update effect doesn't include the resync trigger.
326+
- **Tools needed**: Playwright + a stable fixture market with chart data.
327+
- **Test status**: not-started
328+
306329
## Tooling backlog
307330

308331
Ranked by how many catalogued bugs each tool would have caught.
@@ -317,8 +340,7 @@ Ranked by how many catalogued bugs each tool would have caught.
317340

318341
## Notes for future iterations
319342

320-
- PRs #32#60 still need to be catalogued (older history). Pull more via `gh pr list --state merged --limit 100`.
321-
- Also catalogue closed-without-merge PRs and direct-to-main commits.
343+
- **Catalogue is complete** as of iteration 19 — all 42 PRs (range #23..#65 with gap at #38) are documented, including the 3 currently-open PRs #36, #40, #41. New PRs should be added to the ledger at PR-merge time.
322344
- Repeat the same exercise on `futarchy-fi/futarchy-api` in alternating iterations.
323345
- Do NOT modify production code, even if the test exposes a bug. Document the failure here.
324346

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/**
2+
* Footer NAV_LINKS structural lint (auto-qa).
3+
*
4+
* Pins the structural invariants of the Footer's NAV_LINKS array. Two
5+
* concerns it catches:
6+
*
7+
* (a) Mis-shaped entries (missing label/href, or `external: true` on
8+
* a path-relative href, which would render as a broken absolute
9+
* link)
10+
* (b) Documentation link target — currently the unstable external
11+
* `https://docs.futarchy.fi`. PR #41 (open) replaces this with
12+
* in-app `/documents` (alias `/docs`). The test accepts EITHER
13+
* so it stays green across the transition, and pins which states
14+
* are valid so a typo or accidental third value (`/doc`,
15+
* `https://github.com/...`) surfaces immediately.
16+
*
17+
* Static-grep style — no import, since the Footer is a Next.js JSX file
18+
* and node:test's strict ESM doesn't resolve extension-less relative
19+
* imports the way Next does.
20+
*/
21+
22+
import { test } from 'node:test';
23+
import assert from 'node:assert/strict';
24+
import { readFileSync } from 'node:fs';
25+
26+
const FOOTER_PATH = new URL('../../src/components/common/Footer.jsx', import.meta.url);
27+
28+
function parseNavLinks() {
29+
const src = readFileSync(FOOTER_PATH, 'utf8');
30+
const m = src.match(/const NAV_LINKS = \[([\s\S]*?)\];/);
31+
assert.ok(m, 'NAV_LINKS array not found in Footer.jsx — has the file been refactored?');
32+
33+
// Pull each `{ ... }` object literal out of the array body. Avoids
34+
// pulling in a JS parser dep — the array shape is small and stable.
35+
const entries = [];
36+
const re = /\{\s*([^{}]+?)\s*\}/g;
37+
let item;
38+
while ((item = re.exec(m[1])) !== null) {
39+
const obj = {};
40+
// Match key: value pairs. Handles single-quoted strings and bare
41+
// booleans.
42+
const pairRe = /(\w+)\s*:\s*('([^']*)'|true|false)/g;
43+
let p;
44+
while ((p = pairRe.exec(item[1])) !== null) {
45+
obj[p[1]] = p[3] !== undefined ? p[3]
46+
: p[2] === 'true' ? true
47+
: p[2] === 'false' ? false : p[2];
48+
}
49+
entries.push(obj);
50+
}
51+
return entries;
52+
}
53+
54+
const NAV_LINKS = parseNavLinks();
55+
56+
test('Footer parser — extracts at least one NAV_LINKS entry', () => {
57+
assert.ok(NAV_LINKS.length > 0,
58+
'NAV_LINKS parsed as empty — the regex extractor is broken or the array is empty.');
59+
});
60+
61+
test('Footer — every NAV_LINKS entry has a label and an href', () => {
62+
for (const e of NAV_LINKS) {
63+
assert.ok(typeof e.label === 'string' && e.label.length > 0,
64+
`entry missing label: ${JSON.stringify(e)}`);
65+
assert.ok(typeof e.href === 'string' && e.href.length > 0,
66+
`entry missing href: ${JSON.stringify(e)}`);
67+
}
68+
});
69+
70+
test('Footer — `external: true` entries have an absolute http(s) href', () => {
71+
for (const e of NAV_LINKS) {
72+
if (e.external === true) {
73+
assert.ok(/^https?:\/\//.test(e.href),
74+
`entry "${e.label}" is marked external but href is not absolute: ${e.href}`);
75+
}
76+
}
77+
});
78+
79+
test('Footer — non-external entries have a path-relative href', () => {
80+
for (const e of NAV_LINKS) {
81+
if (e.external !== true) {
82+
assert.ok(e.href.startsWith('/'),
83+
`entry "${e.label}" is not marked external but href is not path-relative: ${e.href}. ` +
84+
`If the link is external, set external: true.`);
85+
}
86+
}
87+
});
88+
89+
test('PR #41 — Documentation link target is one of the accepted values', () => {
90+
// Accepted set spans the pre- and post-PR-#41 worlds. If the link
91+
// gets pointed at a third value (typo, accidental redirect to a
92+
// GitHub URL, etc.) this test surfaces it.
93+
const ACCEPTED_DOCS_HREFS = new Set([
94+
'https://docs.futarchy.fi', // pre-PR-#41 (current)
95+
'/documents', // post-PR-#41
96+
'/docs', // post-PR-#41 alias
97+
]);
98+
const docs = NAV_LINKS.find(e => e.label === 'Documentation');
99+
assert.ok(docs, 'no NAV_LINKS entry with label "Documentation"');
100+
assert.ok(ACCEPTED_DOCS_HREFS.has(docs.href),
101+
`Documentation href "${docs.href}" is not in the accepted set ` +
102+
`[${[...ACCEPTED_DOCS_HREFS].join(', ')}]. ` +
103+
`Either fix the link or add the new value to ACCEPTED_DOCS_HREFS in this test.`);
104+
});
105+
106+
test('PR #41 — Status link is the canonical status URL', () => {
107+
// Adjacent invariant — the same NAV_LINKS array also holds Status,
108+
// which has historically been a deployment regression target. Pin it.
109+
const status = NAV_LINKS.find(e => e.label === 'Status');
110+
assert.ok(status, 'no NAV_LINKS entry with label "Status"');
111+
assert.equal(status.href, 'https://status.futarchy.fi',
112+
`Status link drifted from canonical URL; got "${status.href}"`);
113+
assert.equal(status.external, true,
114+
`Status link must be marked external: true`);
115+
});

0 commit comments

Comments
 (0)