Skip to content

Release: develop -> main - #1390

Merged
TaprootFreak merged 13 commits into
mainfrom
develop
Aug 20, 2026
Merged

Release: develop -> main#1390
TaprootFreak merged 13 commits into
mainfrom
develop

Conversation

@github-actions

Copy link
Copy Markdown

Automatic Release PR

This PR was automatically created after changes were pushed to develop.

Commits: 1 new commit(s)

Checklist

  • Review all changes
  • Verify CI passes
  • Approve and merge when ready for production

* Scope develop PR tests and e2e, and honour ci:full

Jest uses --findRelatedTests on changed src and functions files.
The former head_ref job skip is gone. Docs-only e2e PRs with safe
paths bring up no stack. The ci:full label forces full tests and e2e.

* Align docs with scoped e2e and listen for base retargets

CONTRIBUTING, the e2e README and test-architecture describe
mode=none and ci:full. The workflows also run on edited so a
retarget onto main re-evaluates the full-run rule.

* Spell out remaining CI-scope exceptions in the docs

Markdown format check stays full. E2E has no partial mode; docs-only
skip applies only to safe-path documentation that does not touch e2e-stack.

* docs: name workflow_dispatch and unsafe paths as e2e full triggers

* Align e2e full-run trigger lists and fix Markdown formatting

The three docs now name the same e2e full triggers as the workflow.
Prettier accepts the layer table in docs/test-architecture.md.

* Treat setupTests as infra and skip e2e prep on docs-only

src/setupTests.ts is loaded by Jest for every suite, so a change there
must force the full test run. Docs-only e2e jobs no longer check out the
API or type-check the harness.
TaprootFreak and others added 7 commits August 13, 2026 20:36
…1392)

* Reject pull requests into main that are not from develop

GitHub cannot restrict the source branch natively. This required check
allows only this repository's develop branch to target main.

* Fail closed when pull_request head metadata is empty

Empty strings pass set -u. Without this check a missing repo name
plus head ref develop would accept the pull request.
* Collapse the two IBAN switch controls into one cycle button

The payment-details IBAN row showed a collection-account SWAP toggle and a
provider BANK toggle side by side whenever both alternatives existed.
Customers only need one control: a single SWAP button now walks personal
→ collection (when offered) → the other personal-IBAN provider (when
offered). Collection stays a local display change; a provider step still
requests a fresh quote.

* Keep the IBAN cycle helper private to the payment component

The provider callback now lives on the discriminated switch target, so
the unreachable exported fail-closed throw is gone. Tests cover the
cycle only through PaymentInformationContent.

* Guard the buy payment details against a second IBAN switch

The full-stack /buy and /buy/info flows already reach Payment Information.
They now also assert that at most one IBAN switch button is rendered, so
the two-control regression cannot land again even when this stack does
not seed a personal-IBAN provider.

* Refresh provider-toggle baselines for the single SWAP control

The Frick and Yapeal payment-details screenshots now show one SWAP
button instead of the previous SWAP plus bank icons. Collection-only
baselines are unchanged.
* test: cover the CAMT.053 statement builder at 100%

Add a unit spec for credit/debit layout, address fields, XML escaping,
IBAN normalisation and amount formatting.

* test: tighten CAMT.053 builder assertions after review

Restore the crypto global after each case, assert the entry direction
inside Ntry, lock IBAN slots on each side, and cover a debit address.

* test: assert CAMT.053 direction, dates and amount copies

Pin TxDtls direction counts, the account-header IBAN, BookgDt versus
ValDt, and the three amount interpolations.

* test: pin CAMT.053 amount slots to Ntry, TxAmt and balances

Assert the formatted amount inside TxAmt and keep two zero-value
opening and closing balances.
* feat(realunit): let staff deactivate buy quotes from the quotes UI

SUPPORT can open /realunit/quotes and deactivate a buy quote. Confirm
payment stays hidden for SUPPORT and for already deactivated quotes.

* test(realunit): handbook quotes variants and Support deactivate e2e

Add the visual quotes spec and metadata entry, and make the Support
e2e-stack case click Deactivate through to completion.

* docs(handbook): describe RealUnit quote deactivate variants in German

Handbook metadata descriptions are German; keep the product title.

* test(e2e): fill required columns when seeding a WaitingForPayment buy quote

TypeORM synchronize rejects the insert without routeId, sourceId,
payment methods, rates and isValid.

* test(e2e): seed loc REALU on Sepolia and click Confirm exactly

The deactivate flow must look up the Sepolia Token REALU row so
getAdminQuotes returns the seeded quote. Overlay Confirm uses an
exact name match so it does not collide with Confirm Payment Received.

* test(e2e): pin handbook quote screenshots to English

lang=en keeps selectors and baselines stable regardless of the
admin account language.

* test(e2e): commit RealUnit quote handbook baselines

Encode the session JWT in the quote screenshot gotos so the token
survives the query string, and add the four chromium-darwin baselines
for list, active detail, deactivate overlay, and deactivated detail.

* test(e2e): add Support-only quote deactivate handbook variant

Cover the missing-session confirm-payment branch and snapshot the
Support detail view that shows Deactivate without Confirm Payment.

* fix(realunit): serialize quote confirm and deactivate actions

Keep a single pending overlay so staff cannot confirm and deactivate
the same quote at once. Cover the quote DTO helper and require
deactivatedAt in the stack deactivate tests.

* fix(ci): check out the private API with a deploy key

The default GITHUB_TOKEN of this public repository cannot fetch
DFXswiss/api, so Checkout API failed as "repository not found" and
skipped the suite. Use the read-only deploy key in E2E_API_CHECKOUT_KEY.

* fix(ci): do not persist the API deploy key after checkout

Later job steps only need the working tree. Leaving the key in
api-repo git config would let them reach the private API repo.

* fix(realunit): return to the quotes list after deactivate

navigate(-1) leaves a deep-linked detail page on about:blank.
Staff after confirm or deactivate go to /realunit/quotes.
* Describe adding a wallet address on /account-merge

The confirmation page no longer says two accounts are being merged.
It matches the confirmation mail: a wallet address is added to the
existing account.

* Keep Full-stack E2E green when the API deploy key is missing

Fork pull requests do not receive E2E_API_CHECKOUT_KEY. Detect the
empty secret so the job still runs and skips the private checkout
instead of failing as repository not found.

---------

Co-authored-by: TaprootFreakAI <315477232+TaprootFreakAI@users.noreply.github.com>
…1409)

The support form no longer collects email. After verification the
customer returns via the stored origin; cancel and merge-OK drop
that path so it cannot come back on a later visit.

Co-authored-by: TaprootFreakAI <315477232+TaprootFreakAI@users.noreply.github.com>
TaprootFreak
TaprootFreak previously approved these changes Aug 18, 2026
…pup (#1411)

* Open the invoice PDF from /tx without a post-await popup

Reserve a tab on the Open invoice click so iOS Safari can show the
PDF after the invoice PUT. Hide the button unless the row is a
completed Buy in CHF or EUR.

* Lock Open invoice with e2e and a jsdom-safe PDF stub

Add full-stack tests that fail if the invoice tab is opened after the
PUT, if the button shows on pending or sell rows, or if an API error
is swallowed. Stub URL.createObjectURL on jsdom the same way the
export tests already do.

* Reserve a tab for Open receipt and buy-QR PDF Invoice

Same click-then-PUT/GET pattern as Open invoice, so iOS Safari can
show the PDF after the request. Fixes the leftover list receipt and
buy-QR buttons.

* Cover stale buy-QR success with a live reserved preview

A mode change while the invoice request is in flight must close the
reserved tab and must not assign a blob URL.

* Give the pending-buy invoice row its own buy route

createTransaction would otherwise POST /v1/buy again for the same
user and get HTTP 409 Buy route already exists.

* Cover the Open receipt error path at the unit layer

The reserved-tab close on a rejected receipt request is unit-testable,
same as Open invoice. Also lock the live-preview success assignment.

---------

Co-authored-by: TaprootFreakAI <315477232+TaprootFreakAI@users.noreply.github.com>
TaprootFreakAI and others added 4 commits August 18, 2026 13:45
…pdowns (#1410)

* Use the logged-in staff verified name instead of clerk dropdowns

Staff already have a mandatory verifiedName. Self-identification
selects on compliance and support forms now send that name and no
longer ask the clerk to pick themselves from a list.

* Fix stale staff name after account change and declare coverage

Clear the verified name while another account is loading, and stop
mirroring Freigabe processedBy in local state. Add save-disabled
tests, translations, and the e2e identity stub declaration.

* Match My tickets by verified name or mapped clerk

Assigned clerk initials and the name written on send can differ.
The overview now treats either identity as mine and shows loading
or error instead of a false empty state.

* Reset mapped clerk identity when the staff account changes

The My tickets mapping must not keep a previous account's clerk
name across a session switch.

* Drop unused clerks dependency from issue loaders

The clerk list no longer seeds the message author, so reloading
the issue whenever clerks arrive was leftover work.

* Reuse the staff-name copy for send errors and load failures

Issue send guards now share STAFF_NAME_MISSING, and the overview
load error uses the same translated message as the rest of staff UI.

* Load staff identity from the clerk endpoint, not the user dump

The read-only name still comes from the logged-in account. Prefer
GET support/issue/clerk (or the RealUnit twin) and only fall back to
the user-data payload when that call is empty or missing.

* Note why a failed clerk lookup falls back to userData

* Align staff-identity layout, wrap a long line, and mock GET clerk

* Move the missing-name hint out of the message compose row

* Add before/after screenshots of the staff-identity UI change

Review images of Editor, message author, assignment, and the missing-name hint.

* Ignore Enter while the staff author name is still loading

The Send button is already disabled in that state. Enter in the compose
box was calling send anyway and showing a sticky missing-name error.

* Key the staff-name cache by account and role

The loader picks support vs RealUnit from the session role. Caching
only on account reused the first endpoint after a role change.

* Show the current staff-identity screens instead of before/after pairs

Review images of the live controls as they look after the change:
read-only author, read-only Editor, and the missing-name hint.

* Keep only the two staff-identity screenshots

Drop the error-state mock and the now-suffix names. The remaining
images are the support issue screen and the compliance editor.

---------

Co-authored-by: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com>
Co-authored-by: TaprootFreakAI <315477232+TaprootFreakAI@users.noreply.github.com>
…ge (#1407)

* Open assign, refund and support on the public TX status page

Buttons on /tx/T… no longer redirect to login. Assign and refund use
UID guest endpoints; the support form accepts a tx query param so a
ticket can be filed without a session.

* Keep the tx query param after the URL is cleaned

Snapshot tx at mount so clearing the query string cannot re-enable
the login guard or wipe the prefilled transaction. Guest refund
renders without a numeric transaction id.

* Hide logged-in refund dropdowns on the guest path

Guest refunds always use free-text IBAN and address fields so leftover
bank-account context after a previous session cannot open the dropdown.

* Keep public TX mail links working when a session is already open

Assign, refund and support on a T/Q status URL always use the guest
capability path so a logged-in session cannot block or widen the action.

* Drop unused within import from the refund tests

ESLint treats the leftover import as a warning and CI fails at max-warnings 0.

* Wire the guest refund mock in the list/txinfo suite

T/Q refund now always calls getRefund. The list suite still stubbed that
as a bare jest.fn, so the form never left the spinner.

* Refresh status checks for the feature-branch pull request

The previous head still carried a Full-stack E2E run from the closed
develop-targeted fork PR. This branch is not develop, so that workflow
does not apply here.

* Do not fail full-stack E2E when the API checkout key is missing

Fork pull requests do not receive repository secrets. Without the API checkout key the job dies as repository-not-found. Treat a missing key like a documentation-only change: mode=none, job still runs.

* Drop unreachable session refund UI from the public TX refund form

The refund route only mounts for T/Q UIDs, so the logged-in dropdowns
and session refund APIs could never run. Always use the guest form, and
expect the full-stack refund test to land on /tx/{uid}.

* Drop leftover uid gates on the refund form and cover public assign

TransactionRefund only mounts for T/Q, so a second isUid check was
dead. The full-stack suite now opens /tx/{uid}/assign and expects the
guest assign screen, not the list.

* Restore user and session mocks in the tx query-param suite

The mail-gate tests clear all mocks. The tx suite must put useUserContext
back so the screen can destructure user after #1409.

* Use the mail action secret on guest assign and refund URLs

The unmatched-deposit mail stays one link: /tx/{uid}/{secret}.
Guest assign and refund call the secret APIs; status without a secret
does not offer those actions.

* Restore JWT refund on the logged-in TX list path

* Add handbook screenshots for the mail action-secret TX flow

* Drop the unused JWT helper from the guest TX visual spec

---------

Co-authored-by: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com>
Co-authored-by: TaprootFreakAI <315477232+TaprootFreakAI@users.noreply.github.com>
The Nest monolith was renamed from DFXswiss/api. README, docs, comments,
and the E2E checkout must use the current GitHub path.

Co-authored-by: TaprootFreakAI <315477232+TaprootFreakAI@users.noreply.github.com>
* Match the assign screen title by text, not by heading role

The guest assign test added in #1407 asserts the screen title with
getByRole('heading'), which never matches: the title comes from
useLayoutOptions and renders in the app bar as a plain element. The
captured Playwright trace of the failing run shows it as
`generic [ref=e10]: Assign transaction`, with no heading role anywhere on
the page. The other title assertions in this file already use getByText
for exactly that reason.

The feature itself works — the same trace shows the guest form rendered,
the single buy target preselected and the submit button present, so this
was only ever a wrong locator.

getByText matches twice here, because the submit button carries the same
accessible name (`button "Assign transaction" [ref=e30]`); the app bar
precedes the form in the DOM, so first() takes the title. The negative
assertion on the next line stays role-based: 'Your Transactions' is a
real in-page heading, as the passing list tests at lines 48, 110 and 179
show, so it keeps its meaning.

This blocks the DFXswiss/backend release, where it is the last failing
check.

* Spell out why first() is safe on the exact text locator

* Cover the logged-in refund route the registry already claims

Fixing the assign locator let the [coverage-gate] project run for the
first time on this branch — it is skipped while any earlier spec fails,
which is why #5090 never reported it. It then failed:

  Routes claimed but never opened (1) — the claiming suite must navigate
  there:  - /tx/:id/refund

#1407 added /tx/:id/refund to App.tsx and claimed it in
specs/registry/transactions.ts, but every refund test navigates the
guest variant /tx/:id/:secret/refund. The screen opens on either input —
`isRefund = ... && (hasActionSecret || isLoggedIn)` — so the logged-in
half was untested and the claimed route never visited.

route-coverage.spec.ts says not to weaken or remove a claim to keep the
gate green, so this adds the missing navigation as real coverage: open
the route with a session and no secret, and assert the refund form
renders.

* Describe the exact-text matching rule accurately

Codex conformance review: the comment explained first() via "the smallest
element whose own text nodes match". That is the legacy text= engine's
model and is not what makes ancestors safe here. Exact matching resolves
to the smallest element whose text is exactly the string, and a wrapping
container is never the smallest match — that is the reason, and the
comment now says it.
@TaprootFreak
TaprootFreak merged commit db8db79 into main Aug 20, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants