Skip to content

Instantly share code, notes, and snippets.

@rami-ruhayel-vgw
Last active March 27, 2026 12:31
Show Gist options
  • Select an option

  • Save rami-ruhayel-vgw/73f9a1fba6e7b9197d58c3b1a1f38895 to your computer and use it in GitHub Desktop.

Select an option

Save rami-ruhayel-vgw/73f9a1fba6e7b9197d58c3b1a1f38895 to your computer and use it in GitHub Desktop.
GeoComply E2E Test Plan: static pages, login flow, failure redirects, debug panels, post-login monitoring (POK-26687)

GeoComply E2E Test Plan (POK-26687)

Review Status

Plan reviewed by automated QA expert agent. Key changes incorporated:

Must fix (done):

  • Split GeoErrorPage into EnableLocationPage and RestrictedLocationPage page objects
  • Fixed GeoPromptOverlay.dismiss selector (was the checkbox, not a button)
  • Added location_lost reason to Slice 3 failure redirect tests
  • Enumerated all restricted-location variants explicitly in Slice 1

Should fix (done):

  • Split ticket #4 into 4a (pre-login) and 4b (post-login)
  • Added data-testid prerequisite note for post-login debug panel
  • Added "read config from debug panel" helper for environment-agnostic threshold tests
  • Added JWT fallback test (viewer_country_region override) to Slice 3
  • Added cookie-overrides-config priority test to Slice 2

Accepted as-is:

  • Dropped runAcrossViewports framework (YAGNI, use inline viewport assertions)
  • Firefox project scoped to Slice 1 only (static pages)
  • Skipped deterministic canary hash test as E2E (keep as unit test)
  • Added loading state test between prompt dismiss and lobby render

Scope

End-to-end test coverage for the GeoComply feature: static error pages, location prompt, login verification flow (success + failure paths), post-login monitoring (via debug panel simulation), and the debug panels themselves.

Browser / Viewport Matrix

All tests run on both configured Playwright projects (Desktop Chrome, Mobile Safari/iPhone 12). The static page viewport tests additionally cover the landscape breakpoint on smaller devices.

Supported browsers (for reference - Playwright covers the major rendering engines):

  • Chromium: Chrome, Edge, Brave, Samsung Internet
  • WebKit: Safari (macOS, iOS, iPad)
  • Firefox: Firefox (desktop)

Current Playwright projects: chromium (Desktop Chrome 1280x720) and Mobile Safari (iPhone 12 390x844).

Reusable Infrastructure (Slice 0)

Build on the existing e2e infrastructure. New code should follow established patterns: page objects like LoginAndRegistrationPage and PokerLobbyPage, services in src/services/, fixtures in src/fixtures.ts.

0a. Extend geoSpoofCookies helper (src/services/geoSpoofCookies.ts)

The existing helper sets 4 cookies (subdivision, status, canary percent, email pattern). Extend the GeoSpoofOptions interface to support the full cookie API:

New option Cookie Purpose
reason GEOCOMPLY_SPOOF_REASON Failure reason (permission_denied, timeout, etc.)
promptEnabled GEO_LOCATION_PROMPT_ENABLED Control location prompt visibility
simulationEnabled GEO_SIMULATION_ENABLED Enable simulation mode for post-login tests

Backward compatible - existing callers (including LoginAndRegistrationPage.setGeoSpoofCookies()) unaffected. New cookies only added to the array when the option is explicitly provided.

0a.1. Make LoginAndRegistrationPage.navigate() accept spoof options

Currently setGeoSpoofCookies() calls geoSpoofCookies(domain) with defaults. Change to accept optional GeoSpoofOptions so tests can customize:

async navigate(geoOptions?: GeoSpoofOptions): Promise<void> {
    await this.setGeoSpoofCookies(geoOptions)
    // ... existing goto logic
}

This lets geo tests configure failure modes before login without needing separate cookie setup. The loginPage fixture continues to work unchanged (no options = defaults = success spoof).

0b. GeoPromptOverlay page object

Wraps the location prompt DOM elements:

selectors:
  overlay:         '#geo-location-prompt'
  title:           '.geo-prompt-title'
  body:            '.geo-prompt-body'
  continueBtn:     '#geo-location-prompt-continue'
  dontShowCheckbox: '#geo-location-prompt-dismiss'  (checkbox input, NOT a button)
  privacyLink:     '.geo-prompt-link'

methods:
  waitForVisible()
  clickContinue()
  checkDontShowAgain()   // checks the checkbox, does NOT dismiss
  isVisible(): boolean

0c. GeoDebugPanel page object (post-login)

Wraps the post-login simulation panel:

selectors (data-testid):
  simToggle:        'sim-toggle'
  simResultSelect:  'sim-result-select'
  simDispatch:      'sim-dispatch'
  locationTrigger:  'location-dropdown-trigger'
  locationOption:   'location-option-{value}'
  canaryBadge:      'canary-status-badge'
  currentGeo:       'current-geo'
  restrictionPill:  'current-restriction-pill'
  eventLog:         'event-log'
  logEntry:         'log-entry'

methods:
  activateSimulation()
  deactivateSimulation()
  simulateSuccess(subdivision: string)
  simulateFailure(reason: GeoFailureReason)
  getCanaryStatus(): string
  getCurrentGeo(): string
  getRestrictionStatus(): string
  waitForLogEntry(text: string)

0d. GeoPreLoginPanel page object

Wraps the pre-login debug panel (?geo_debug mode):

selectors (DOM IDs):
  root:             '#geo-debug'
  canaryPercent:    '#geo-debug-canary-percent'
  promptToggle:     '#geo-debug-prompt-toggle'
  simulationToggle: '#geo-debug-simulation-toggle'
  spoofStatus:      '#geo-debug-spoof-status'
  spoofLocation:    '#geo-debug-location-trigger'
  spoofReason:      '#geo-debug-spoof-reason'
  launchButton:     '#geo-debug-launch'
  clearResult:      '#geo-debug-clear-result'
  authPill:         '.geo-debug-auth-pill'
  stateInspector:   '#geo-debug-dev-panel'

methods:
  setCanaryPercent(n: number)
  setSpoofSuccess(subdivision: string)
  setSpoofFailure(reason: string)
  enablePrompt()
  enableSimulation()
  launch()
  isAuthenticated(): boolean

0e. EnableLocationPage page object

Wraps the /user/enable-location server-rendered page:

selectors:
  logo:       '.geo-logo'
  title:      'h2'
  body:       '.geo-container p'
  faqLink:    'a[href*="help.globalpoker"]'
  retryBtn:   '.geo-retry-button'

methods:
  waitForLoaded()
  getTitle(): string
  getBody(): string
  clickRetry()

0e.2. RestrictedLocationPage page object

Wraps the /user/restricted-location server-rendered page (two variants):

selectors:
  logo:       '.geo-logo'          (signed-out variant)
  blockIcon:  '.geo-block-icon'    (blocked-at-login variant)
  title:      'h2'
  body:       '.geo-container p'
  termsLink:  'a[href*="terms-conditions"]'  (blocked-at-login only)
  actionBtn:  '.geo-retry-button'

methods:
  waitForLoaded()
  getTitle(): string
  getBody(): string
  isBlockedAtLoginVariant(): boolean  (checks for .geo-block-icon presence)
  clickAction()

0f. readConfigDefaults(page) helper

Navigate to /?geo_debug, read threshold values from the pre-login panel input placeholders. Returns config values the environment uses so tests are environment-agnostic:

returns: {
  failedThreshold: number    // from #geo-debug-failed-threshold placeholder
  restrictedThreshold: number
  allowedThreshold: number
}

Used by Slice 5 monitoring tests to dispatch the exact number of events needed for sign-out.

0g. Production code prerequisite: data-testid attributes

The post-login debug panel components (SimulationPanel.tsx, LocationDropdown.tsx, EventLog.tsx, ConfigOverridePanel.tsx, GeoLocationDebugTabView.tsx) use data-testid attributes. Verify these exist in production code. If any are missing, add them as part of ticket #0.


Slice 1: Static Error Pages (@pool:none)

No authentication needed. Fast, no flakiness. Tests the server-rendered HTML pages.

Tests

Test Page What it validates
enable-location renders default copy /user/enable-location Title "Location access is required", default body text, FAQ link, Retry button
enable-location renders per-reason body /user/enable-location?reason={each} Each of 6 reasons produces correct body text
enable-location Retry links to / /user/enable-location Button href is "/"
enable-location FAQ links to troubleshooting /user/enable-location FAQ href is help.globalpoker.com troubleshooting article
restricted-location blocked-at-login (default) /user/restricted-location geo-block-icon image, "App not available in your location", Terms link, "Return home" button
restricted-location: entered_restricted_market /user/restricted-location?reason=entered_restricted_market GP logo, "You were signed out", reason body, "Log in" button
restricted-location: market_restriction_changed /user/restricted-location?reason=market_restriction_changed GP logo, "You were signed out", reason body, "Log in" button
restricted-location: restriction_cleared /user/restricted-location?reason=restriction_cleared GP logo, "You were signed out", reason body, "Log in" button
All pages render action button in viewport (landscape) All URLs assertElementInViewport('.geo-retry-button') across device viewports

Tags: @pool:none (no auth needed, can run in any environment including prod)


Slice 2: Geo-Comply Happy Path (@pool:bot @no-prod)

Authenticated flow with spoofed success. Validates the golden path: canary group -> prompt -> dismiss -> verify -> lobby.

Tests

Test Cookies What it validates
Control group bypasses geo, reaches lobby canaryPercent: 0 No prompt, no verification, lobby loads
Canary group sees location prompt canaryPercent: 100, promptEnabled: true Prompt overlay appears after login
Dismissing prompt proceeds to verification Same Click Continue, prompt disappears, lobby loads (spoof success)
"Don't show again" checkbox prevents re-show Same + check dismiss checkbox Second login: no prompt, straight to lobby
Successful verification stores result in sessionStorage canaryPercent: 100 sessionStorage['geo-comply-result'] contains Success result
Lobby loaded event fires for both groups Both canaryPercent: 0 and 100 geo.lobby.loaded element or lobby content visible
Cookie overrides config canary percent canaryPercent: 0 cookie when env default is non-zero No geo-gate runs, straight to lobby
Loading state visible between prompt dismiss and lobby canaryPercent: 100, promptEnabled: true After Continue click, #loadingView visible before lobby renders

Tags: @pool:bot @no-prod (uses spoof infrastructure)


Slice 3: Failure Redirects (@pool:bot @no-prod)

Authenticated flow with spoofed failures. Validates that each failure mode redirects to the correct error page.

Tests

Test Spoof config Expected redirect
permission_denied -> enable-location status: Failed, reason: permission_denied /user/enable-location?reason=permission_denied
timeout -> enable-location status: Failed, reason: timeout /user/enable-location?reason=timeout
sdk_load_failed -> enable-location status: Failed, reason: sdk_load_failed /user/enable-location?reason=sdk_load_failed
token_failed -> enable-location status: Failed, reason: token_failed /user/enable-location?reason=token_failed
verification_failed -> enable-location status: Failed, reason: verification_failed /user/enable-location?reason=verification_failed
location_lost -> enable-location status: Failed, reason: location_lost /user/enable-location?reason=location_lost
Restricted market -> restricted-location status: Success, subdivision: <blocked market> /user/restricted-location (via Auth0 logout)
JWT fallback: restricted residential region canaryPercent: 0 + OVERRIDE_VIEWER_COUNTRY_REGION=<restricted> Residential market restriction behavior without geo-gate

Note: The restricted market test depends on which markets are in BLOCKED_MARKETS config for the target environment. Use the readConfigDefaults() helper or the pre-login debug panel to determine which subdivision triggers Phase 3 in CI. Don't hardcode.

Tags: @pool:bot @no-prod


Slice 4: Debug Panels (@pool:bot @no-prod)

4a. Pre-login panel

Test URL What it validates
Panel renders when geo_debug param present /?geo_debug #geo-debug root visible, all sections rendered
Auth status shows correctly (logged out) /?geo_debug (fresh context) Auth pill shows "Logged out"
Auth status shows correctly (logged in) /?geo_debug (after login) Auth pill shows "Logged in"
Canary percent input updates cookie /?geo_debug Set value, check cookie via page.context().cookies()
Spoof status dropdown works /?geo_debug Select Success/Failed, verify cookie
Location dropdown shows subdivisions /?geo_debug (status=Success) Click trigger, dropdown list appears with options
Failure reason dropdown shows options /?geo_debug (status=Failed) All 5 failure reasons listed
Launch button navigates to app /?geo_debug Clicking Launch removes geo_debug param, app loads
State inspector shows cookie values /?geo_debug Toggle dev panel, verify table rows match set cookies

Tags: @pool:bot @no-prod (needs login for auth status test; @pool:none for logged-out tests)

4b. Post-login panel

Test What it validates
Debug tab accessible from profile menu Navigate to profile -> debug section visible
Canary status badge shows correct state Badge shows "In canary group (100%)"
Login result display shows success After spoofed success login, shows green "Success" badge
Current geo shows spoofed subdivision Shows the subdivision from GEOCOMPLY_SPOOF cookie
Simulation toggle activates/deactivates Click sim-toggle, verify state change
Result type dropdown has all options Success + 5 failure modes listed
Dispatch button sends event Select Success + US-CA, click dispatch, event log entry appears
Event log records dispatched events Multiple dispatches produce chronological log entries
Config override inputs update cookies Change failed threshold, verify cookie value

Tags: @pool:bot @no-prod


Slice 5: Post-Login Monitoring (@pool:bot @no-prod)

Uses the post-login debug panel simulation controls to trigger monitoring callbacks through the real callback handler. Login with spoof success first, then use simulation panel.

Tests

Test Simulation action Expected outcome
Successful location check keeps user logged in Dispatch Success (US-CA) User stays in lobby, event log shows "allowed"
Permission denied -> immediate sign-out Dispatch Failed:permission_denied Redirected to /user/restricted-location?reason=... or enable-location (via Auth0 logout)
Consecutive failures -> sign-out after threshold Dispatch Failed:timeout x3 (default threshold) After 3rd dispatch, user is signed out
Restriction detected -> sign-out Dispatch Success with restricted subdivision Restriction pill updates, user signed out after threshold
Restriction cleared -> sign-out for re-login Login from restricted, then dispatch Success with allowed subdivision User signed out with restriction_cleared reason

Note: These tests need GEO_SIMULATION_ENABLED=true cookie and the simulation panel activated. The test flow:

  1. Login with spoof success (reach lobby)
  2. Navigate to profile -> debug panel
  3. Activate simulation mode (sim-toggle)
  4. Select result type + location
  5. Click dispatch
  6. Assert outcome (stay in lobby or redirect to error page)

Tags: @pool:bot @no-prod


Ticket Breakdown

All under epic POK-26453 (GeoComply Integration), linked to POK-26687 (E2E test story).

# Ticket Type Description Depends on
0 Shared geo e2e infrastructure Task Extend geoSpoofCookies, page objects (GeoPromptOverlay, GeoDebugPanel, GeoPreLoginPanel, EnableLocationPage, RestrictedLocationPage), readConfigDefaults helper, verify data-testid attributes in production code -
1 Static error pages e2e tests Task Slice 1: all enable-location + restricted-location variants, per-reason copy, viewport assertions. Add Firefox project scoped to this slice. #0
2 Geo-comply happy path e2e tests Task Slice 2: control group bypass, canary prompt, dismiss, success -> lobby, cookie-overrides-config, loading state #0
3 Geo-comply failure redirect e2e tests Task Slice 3: all 6 failure reasons + restricted market + JWT fallback #0
4a Pre-login debug panel e2e tests Task Slice 4a: canary input, spoof controls, prompt toggle, simulation toggle, state inspector, launch #0
4b Post-login debug panel e2e tests Task Slice 4b: canary badge, login result, geo state, restriction pill, simulation dispatch, event log, config overrides #0
5 Post-login monitoring e2e tests Task Slice 5: simulation-driven sign-out flows (uses readConfigDefaults for environment-agnostic thresholds) #0, #4b

Implementation Order

#0   Shared infrastructure (page objects, helpers, data-testid audit)
#1   Static error pages (no auth, fastest feedback, add Firefox project)
#2   Happy path (core flow, highest value)
#3   Failure redirects (all error paths + JWT fallback)
#4a  Pre-login debug panel (QA tooling, no dependency on 4b)
#4b  Post-login debug panel (simulation controls)
#5   Post-login monitoring (most complex, depends on 4b for simulation)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment