Skip to content

feat(examples): add comprehensive showcase example with tests#252

Open
Copilot wants to merge 3 commits intomainfrom
copilot/add-sample-web-application
Open

feat(examples): add comprehensive showcase example with tests#252
Copilot wants to merge 3 commits intomainfrom
copilot/add-sample-web-application

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 3, 2026

Affected Package(s)

  • @forward-software/react-auth (lib)
  • @forward-software/react-auth-google (packages/google-signin)
  • Examples
  • CI/CD / Repository configuration

Related Issue(s)

Follow-up issues for integration hiccups discovered during development will be opened separately.

Motivation

No existing example demonstrates the full API surface of @forward-software/react-auth, and none have tests. This adds a showcase example app that exercises every key library feature using a mock backend — zero external dependencies beyond React and the auth library itself — and ships with a Vitest test suite.

Description of Changes

  • examples/showcase/ — new Vite + React 19 example app running on port 3003
  • src/mock-auth-client.tsMockAuthClient implementing all 11 lifecycle hooks (onInit, onPostInit, onPreLogin, onLogin, onPostLogin, onPreRefresh, onRefresh, onPostRefresh, onPreLogout, onLogout, onPostLogout) with localStorage token persistence, shape validation, configurable network-delay simulation, and credential validation. onInit now wraps JSON.parse in a try/catch so corrupted localStorage is cleared and null returned cleanly instead of crashing the provider.
  • Components demonstrating:
    • createAuth() and AuthProvider with LoadingComponent / ErrorComponent
    • useAuthClient hook
    • useSyncExternalStore(subscribe, getSnapshot) for reactive auth state (not shown in any existing example)
    • Event system (on / off) via a real-time EventLog panel subscribing to all 11 auth events
    • Login error handling with an intentional-failure "Try Invalid Credentials" button
    • Token refresh with expiry display and logout in an AuthenticatedView
  • 31 Vitest tests across 5 files:
    • test/mock-auth-client.spec.ts — 17 unit tests for the full lifecycle
    • test/components/AuthStatus.spec.tsx — 4 tests
    • test/components/LoginForm.spec.tsx — 3 tests
    • test/components/AuthenticatedView.spec.tsx — 4 tests
    • test/components/EventLog.spec.tsx — 3 tests
  • README.md with features table, setup/run/test instructions, project structure, valid credentials, and local development notes
  • Standalone lockfileexamples/showcase/pnpm-lock.yaml committed alongside the app; root pnpm-lock.yaml regenerated so examples/showcase is no longer tracked as a workspace member, consistent with all other examples being standalone
  • test/test-utils.tsx — fixed React.FCFC import (was referencing undefined React namespace under the automatic JSX runtime)
  • vitest.config.ts — added react/react-dom resolve aliases to deduplicate React when lib source is resolved directly, preventing duplicate-React hook errors in tests

Breaking Changes

None

How to Test

  1. CI Checks: Verify all automated tests and build steps pass.
  2. Local Verification:
    # From repo root
    pnpm install
    
    # Install showcase deps (standalone, outside workspace)
    cd examples/showcase && pnpm install
    
    # Run 31 tests
    pnpm test
    
    # Verify production build
    pnpm build
    
    # Start dev server at http://localhost:3003
    # Login with username: user / password: password
    pnpm dev

Checklist

  • My code follows the project's style guidelines
  • I have added or updated tests to cover the changes
  • I have updated relevant documentation
  • All tests are passing locally
  • CI checks are passing
  • I have reviewed my own code and lock file changes
  • I have checked for any potential security implications
  • I have verified the changes work as expected
  • My commit messages follow Conventional Commits format

Notes for Reviewers

Five integration hiccups were discovered during development of this showcase and will be tracked as separate issues:

  1. No documented convention for how examples reference the core lib — existing examples pin a published version string (2.0.3), but local development benefits from aliasing to lib source.
  2. useSyncExternalStore pattern is undocumented for consumersEnhancedAuthClient exposes subscribe/getSnapshot but no existing example or README mentions this. Without it, components only re-render via useAsyncCallback loading-state changes, which is fragile for multi-component layouts.
  3. TypeScript 6 breaks bare CSS imports in older examples — requires declare module '*.css'; only refresh-token has a vite-env.d.ts today.
  4. useAsyncCallback in examples/base swallows rejections silently — missing try/catch means setLoading(false) never runs if the callback rejects, leaving the UI in a permanent loading state.
  5. onRefresh signature in lib test/test-utils.tsx omits the required first parameter — declared as onRefresh(_minValidity?) instead of onRefresh(currentTokens, _minValidity?), which misleads anyone reading tests to learn the API contract.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new examples/showcase Vite + React app intended to demonstrate the full @forward-software/react-auth API surface using a mock auth client, along with a Vitest test suite to validate the example’s behavior.

Changes:

  • Introduces examples/showcase example app with MockAuthClient, UI components, and styling.
  • Adds Vitest + Testing Library test suite covering mock client lifecycle and core UI flows.
  • Documents setup, usage, and feature mapping in examples/showcase/README.md and wires example dependencies.

Reviewed changes

Copilot reviewed 23 out of 25 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
pnpm-lock.yaml Adds dependency resolution entries for the new showcase example.
examples/showcase/vitest.config.ts Vitest config for jsdom tests + local lib aliasing.
examples/showcase/vite.config.ts Vite dev config (port 3003) + local lib aliasing.
examples/showcase/tsconfig.json TypeScript config for the showcase example (strict, bundler resolution, path alias).
examples/showcase/test/test-utils.tsx Shared test AuthClient + wrapper helpers.
examples/showcase/test/mock-auth-client.spec.ts Unit tests for the mock auth client behavior and lifecycle hooks.
examples/showcase/test/components/LoginForm.spec.tsx Component tests for login flows and error display.
examples/showcase/test/components/EventLog.spec.tsx Component tests for auth event logging UI.
examples/showcase/test/components/AuthStatus.spec.tsx Component tests for reactive auth state badges/token rendering.
examples/showcase/test/components/AuthenticatedView.spec.tsx Component tests for refresh/logout interactions and expiry display.
examples/showcase/src/vite-env.d.ts Vite type refs + CSS module declaration for TS 6 compatibility.
examples/showcase/src/styles.css Styling for the dashboard/cards/badges/event log/loading screens.
examples/showcase/src/mock-auth-client.ts Mock AuthClient implementation with storage persistence + lifecycle hooks.
examples/showcase/src/main.tsx React root bootstrap.
examples/showcase/src/hooks/useAsyncCallback.ts Async action hook with loading + error state.
examples/showcase/src/components/LoginForm.tsx Login UI (valid + intentional invalid credentials) with async handling.
examples/showcase/src/components/EventLog.tsx UI panel subscribing to auth events via on/off.
examples/showcase/src/components/Dashboard.tsx Main layout + conditional authenticated/unauthenticated rendering using useSyncExternalStore.
examples/showcase/src/components/AuthStatus.tsx Auth status badges + token JSON display using useSyncExternalStore.
examples/showcase/src/components/AuthenticatedView.tsx Authenticated UI with refresh/logout actions and token expiry display.
examples/showcase/src/auth.ts createAuth() wiring using MockAuthClient.
examples/showcase/src/App.tsx Root provider usage with loading/error screens.
examples/showcase/README.md Showcase documentation: features, commands, structure, credentials.
examples/showcase/package.json Example dependencies + scripts for dev/build/test.
examples/showcase/index.html Vite HTML entrypoint for the example.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@panz3r
Copy link
Copy Markdown
Member

panz3r commented Apr 3, 2026

@copilot can you take care of the review comments.

Note about the lock-file one, please update it by running pnpm i and verify that the example app is no longer included in it

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 3, 2026

@copilot can you take care of the review comments.

Note about the lock-file one, please update it by running pnpm i and verify that the example app is no longer included in it

Done in 61b7f31. Three things addressed:

  1. Lockfile — ran pnpm i from root; examples/showcase is no longer tracked as a workspace importer in pnpm-lock.yaml. A standalone examples/showcase/pnpm-lock.yaml is committed alongside the app, consistent with how each example manages its own dependencies.

  2. React.FC undefinedtest/test-utils.tsx now imports FC from 'react' directly and uses it without the React. namespace.

  3. JSON.parse without try/catchonInit in mock-auth-client.ts now wraps the parse in a try/catch; corrupted storage is cleared and null is returned, so the provider initialises cleanly instead of crashing.

Also added react/react-dom resolve aliases to vitest.config.ts to prevent duplicate-React hook errors when the lib source is resolved directly via alias — all 31 tests pass.

@panz3r panz3r marked this pull request as ready for review April 4, 2026 01:24
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.

3 participants