Address review findings: bugs, memory leaks, CSS consolidation#10
Merged
gtandersen merged 2 commits intoJun 9, 2026
Conversation
Original review (geir-signup-screen-review-clean):
- C1: Map getRunboxDomains objects to strings defensively; fix mock shapes
- I1: Clear interval on existing-script error listener
- I2: Add destroyed flag and timer cleanup in ngOnDestroy
- I3: Replace hardcoded hex literals with theme palette tokens
- S1: Remove dead SIGNUP_HCAPTCHA_SITE_KEY env var from gen-env.js
- S3: Clear hCaptchaSiteKey on script failure for accurate error message
- S4: Try/catch around formElement.submit() with state reset
- S5: Nullish-coalescing on getSignupHCaptchaSiteKey response
- S7: Remove dead hidden accountType form field
- S8: Unicode-aware password strength regex (\p{Ll}, \p{Lu})
- S9: Validate account_number query param before binding
- S11: Add afterEach fixture.destroy() and hcaptcha stub cleanup
- S12: Capture hCaptcha render params in Cypress stub
- S13: Two-pass focus selector (Angular-invalid first, native second)
Remediation pass (fix-signup-review-findings):
- N1: Gate submit guard on hCaptchaReady instead of hCaptchaSiteKey
- N2: Remove failed hCaptcha script element on error
- N3: Capture subscriptions and guard async chain on destroyed flag
- N4: Add 15s timeout on script-load polling for ad blocker/CSP scenarios
- N5: Wrap afterEach in try/finally for resilient test cleanup
- Guard destroyed-component state in hcaptcha catch handler (N6) - Resolve paused promise in 'still loading' test to prevent GC leak (N9) - Replace footer gradient hex literals with palette tokens - Consolidate breakpoint padding/width/font-size overrides into clamp() expressions on base rules (35 lines net reduction, 883 -> 844 lines) - Add consolidated review document covering all three review passes
3c97d57
into
gtandersen:geir/signup-screen-review-clean
5 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This branch applies review findings from PR runbox#1849. Two commits cover 23 fixes across 8 files: a critical domain-selector bug, five memory leak and timer bugs, validation and UX improvements, test hardening, and CSS consolidation.
Context
The signup page is a solid piece of work: lazy-loaded standalone module, runtime API config, native form POST to the Perl backend, and an intentional marketing-surface visual identity separate from the in-app Material theme. Three review passes found 23 issues; 19 were fixed in the first commit (
dcb2fe25), 4 more in the refinement commit (86538deb), and 7 items remain deferred.Critical
Domain selector rendered
[object Object]in production.getRunboxDomains()declaredObservable<string[]>but the backend returns{id, name}[]. Tests passed because mocks matched the (incorrect) signature. Fixed by mapping objects to strings at the consumer and correcting all mocks. The service signature fix is deferred (touches every consumer).Memory leaks and timer bugs
setIntervalleak on hCaptcha script error — polling never stopped after a failed script tag. Fixed withclearIntervalin the error listener.setTimeout(0)retry inrenderHCaptcha— survived component destroy, leaked memory. Fixed withdestroyedflag and timer capture/clear inngOnDestroy.ngOnDestroy. Fixed withsubs.add()teardown and post-await guard.destroyedguard in catch handler..catchremoval.Validation and UX
hCaptchaSiteKey(set early) instead ofhCaptchaReady(set after load), giving a misleading error. Fixed guard and disambiguated message.formElement.submit()throwing leftsubmitInProgressstuck. Fixed withtry/catchand state reset.querySelectoralternation. Fixed with two-pass: Angular-invalid first, native-invalid second.\p{Ll}/u,\p{Lu}/u.account_numberforwarded without validation. Added/^[0-9]{0,12}$/check before binding.getSignupHCaptchaSiteKeycould return undefined. Addedres?.result ?? ''.Cleanup
SIGNUP_HCAPTCHA_SITE_KEYenv var removed fromgen-env.js.accountTypehidden form field removed (backend ignores it).$rmm-signup-slate-*,mat.get-color-from-palette($rmm-default-error)).Array.isArrayguard added on domain list (folded into C1 fix).CSS consolidation
The four-step breakpoint ladder (900/720/560/420px) repeated padding, width, and font-size overrides. Consolidated into fluid
clamp()expressions on the base declarations — 35 lines net reduction (883 to 844 lines), no visual change at any viewport.clamp(0.9rem, calc(1.5vw + 0.45rem), 1.75rem)clamp(0.9rem, calc(1.2vw + 0.45rem), 1.5rem)clamp(0.75rem, calc(2vw + 0.4rem), 2rem)clamp(0.92rem, calc(0.4vw + 0.84rem), 1.04rem)clamp(0.92rem, calc(0.4vw + 0.8rem), 1rem)Tests
{id, name}[]with explanatory commentwindow.hcaptchastub added inbeforeEach, cleaned up inafterEachafterEachusestry/finallyfor defensive cleanupwindow.__hcaptchaParams(scaffolding for future callback tests)254 pass, 0 fail, 2 skipped.
Backend verification
API contracts verified against
RMM/perl/source:GET /rest/v1/signup/hcaptcha/site_keyreturns{status, result: '<key>'}(scalar). Endpoint is unauthenticated, which is correct for signup.GET /rest/v1/runbox_domainsreturns{status, results: [{name, id}]}(array). Consumer maps objects to strings.POST /signup/signupreads 20 form fields. Backend does not readtype,accountType, ordomain— deadaccountTypefield removed.Runbox::Core::Utils->check_password) is authoritative; client-side meter is advisory only.phone_number_homesilently blocks signup if filled. Correctly included as hidden field.Architecture notes
The signup page is a marketing surface with its own visual identity. The 13 new SCSS palette tokens in
_rmm-theme-vars.scssare correctly scoped: they produce zero CSS output, are consumed only bysignup.component.scssvia@use, and do not leak into the global stylesheet. The component uses defaultEmulatedview encapsulation, so all styles are scoped to the component host regardless of file size.Deferred follow-ups
rbwebmail.tsreturn type fix%signup-cardSCSS placeholder