Files
meshcore-analyzer/test-channel-issue-1101.js
T
Kpa-clawbot 4cd51a41e7 fix(channels): strip Share modal — remove redundant URL copy + duplicated key field (#1101) (#1103)
## Summary

Strips the Share Channel modal (shipped in #1090) down to its
essentials. Removes redundant affordances that the QR already provides.

## What changed

**Removed from the Share modal:**
- The URL text printed inside the QR box (the QR encodes the URL)
- The inline Copy Key button inside the QR box (overlapped the image)
- The `meshcore://` URL input field below the QR
- The Copy URL button next to the URL field

**Result — the modal now contains exactly:**
- Title `Share: <Channel Name>`
- QR code (just the QR `<img>`, nothing else in that box)
- Hex Key field with a single Copy button BELOW the QR
- Privacy warning
- ✕ close button (top right)

## Implementation

- `public/channels.js` — drop the `meshcore://` URL field-group from
share modal markup; `openShareModal()` no longer looks up `#chShareUrl`
or builds a URL into a field; pass `{ qrOnly: true }` when calling
`ChannelQR.generate` so the QR box renders ONLY the QR image.
- `public/channel-qr.js` — `generate(name, secret, target, opts)` now
accepts `opts.qrOnly` which short-circuits before appending the inline
URL line + Copy Key button. Default behaviour (no opts) unchanged, so
the Add-Channel "Generate & Show QR" flow is untouched.

## Tests (TDD: red → green)

- New: `test-channel-issue-1101.js` (static grep) — asserts the URL
field is gone from markup, `openShareModal` no longer references it, and
`ChannelQR.generate` honours `qrOnly`.
- Updated: `test-channel-issue-1087.js` and
`test-channel-issue-1087-e2e.js` — those previously asserted the URL
field's presence (which is exactly what #1101 removes); they now assert
ONLY the hex key field exists, AND that `#chShareQr` contains exactly
one `<img>` and no `.channel-qr-url` / `.channel-qr-copy` children.
- Wired into `.github/workflows/deploy.yml` `node-test` job.

Commit history shows red (test commit `c0c254a`) → green (fix commit
`6315a19`) per AGENTS.md TDD requirement.

E2E assertion added: test-channel-issue-1087-e2e.js:184

## Acceptance criteria

- [x] Share modal contains only: QR, "Copy Key" button, privacy warning
- [x] No "Copy URL" affordance anywhere in the modal
- [x] No duplicated hex key field below
- [x] E2E test asserts the absence of the removed elements

Fixes #1101

---------

Co-authored-by: meshcore-bot <bot@meshcore.local>
Co-authored-by: clawbot <clawbot@users.noreply.github.com>
2026-05-05 11:19:10 -07:00

95 lines
4.1 KiB
JavaScript

/**
* #1101 — Strip Share modal: remove redundant URL copy + duplicated key field.
*
* Acceptance criteria:
* - Share modal contains only: QR (just the QR image, nothing else
* in that box), Hex Key field with single Copy button BELOW the QR,
* privacy warning, Close ✕ button.
* - No "Copy URL" affordance ANYWHERE in the modal.
* - No duplicated meshcore:// URL field below the QR.
* - The QR box (#chShareQr) must contain ONLY the QR image — no URL
* text, no Copy Key button overlapping it.
*/
'use strict';
const fs = require('fs');
const path = require('path');
let passed = 0, failed = 0;
function assert(cond, msg) {
if (cond) { passed++; console.log(' ✓ ' + msg); }
else { failed++; console.error(' ✗ ' + msg); }
}
const channelsSrc = fs.readFileSync(path.join(__dirname, 'public', 'channels.js'), 'utf8');
const qrSrc = fs.readFileSync(path.join(__dirname, 'public', 'channel-qr.js'), 'utf8');
console.log('\n=== #1101: Share modal markup ===');
// Locate the share modal markup block.
const shareModalIdx = channelsSrc.indexOf('id="chShareModal"');
assert(shareModalIdx > 0, 'share modal markup located');
// Tighten block isolation: scan forward for the share modal's own
// closing tag (the outer overlay div is indented 6 spaces, so its
// matching close is the first "\n </div>" we hit after the
// opener). Falls back to the old ch-main heuristic if that pattern
// disappears for any reason.
let shareEnd = channelsSrc.indexOf('\n </div>', shareModalIdx);
if (shareEnd < 0) {
shareEnd = channelsSrc.indexOf('<div class="ch-main"', shareModalIdx);
}
const shareModalBlock = channelsSrc.substring(shareModalIdx, shareEnd);
assert(shareModalBlock.length > 0 && shareModalBlock.length < 4000,
'share modal block isolated');
// Hex key field MUST still be present (single source of truth).
assert(/id="chShareKey"/.test(shareModalBlock),
'share modal still exposes the hex key field with a Copy button');
// meshcore:// URL field MUST be removed.
assert(!/id="chShareUrl"/.test(shareModalBlock),
'share modal does NOT render a #chShareUrl input field');
assert(!/data-share-field="url"/.test(shareModalBlock),
'share modal does NOT render any [data-share-field="url"] element');
assert(!/data-share-copy="url"/.test(shareModalBlock),
'share modal does NOT render any [data-share-copy="url"] button');
assert(!/meshcore:\/\/ URL/.test(shareModalBlock),
'share modal does NOT show a "meshcore:// URL" label');
// Privacy warning + close button still required.
assert(/ch-modal-warn/.test(shareModalBlock),
'share modal still includes the privacy warning');
assert(/id="chShareModalClose"/.test(shareModalBlock),
'share modal still has the ✕ close button');
console.log('\n=== #1101: openShareModal() body ===');
// openShareModal must no longer reference chShareUrl or build URL into a field.
const openIdx = channelsSrc.indexOf('function openShareModal(');
assert(openIdx > 0, 'openShareModal located');
const openEnd = channelsSrc.indexOf('function ', openIdx + 30);
const openBlock = channelsSrc.substring(openIdx, openEnd);
assert(!/getElementById\('chShareUrl'\)/.test(openBlock),
'openShareModal does NOT look up #chShareUrl');
assert(!/urlField\.value\s*=/.test(openBlock),
'openShareModal does NOT assign to urlField.value');
console.log('\n=== #1101: ChannelQR.generate() supports qrOnly ===');
// ChannelQR.generate must accept an opts.qrOnly flag so the Share
// modal's QR box can render JUST the QR image — no URL line, no
// inline Copy Key button. (The Share modal has its own dedicated
// hex key field + Copy button BELOW the QR.)
assert(/function generate\([^)]*opts[^)]*\)/.test(qrSrc),
'ChannelQR.generate accepts an opts argument');
assert(/qrOnly/.test(qrSrc),
'ChannelQR.generate honours opts.qrOnly');
// Share modal call site must pass qrOnly:true.
assert(/ChannelQR\.generate\([^)]*qrOnly[^)]*\)/.test(channelsSrc) ||
/ChannelQR\.generate\([\s\S]{0,200}qrOnly\s*:\s*true/.test(channelsSrc),
'openShareModal passes { qrOnly: true } to ChannelQR.generate');
console.log('\n=== Results: ' + passed + ' passed, ' + failed + ' failed ===');
process.exit(failed > 0 ? 1 : 0);