Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test(portal-e2e): implement testrail #356

Merged
merged 22 commits into from
Mar 13, 2025

Conversation

HasithDeAlwis
Copy link
Collaborator

@HasithDeAlwis HasithDeAlwis commented Mar 13, 2025

Checklist

  • I've thoroughly read the latest contribution guidelines.
  • I've rebased my branch onto main before creating this PR.
  • I've added tests to cover my changes (if applicable).
  • I've verified that all new and existing tests have passed locally for mobile, tablet, and desktop screen sizes.
  • My commit messages follow guidelines
  • My change requires documentation updates.
  • I've updated the documentation accordingly.
  • My code follows existing patterns of this project and/or improves upon them.

Summary by CodeRabbit

  • New Features

    • Introduced a navigation dock offering quick access to core sections.
    • Streamlined the login flow with updated OAuth redirection, now displaying only a LinkedIn option.
    • Enhanced the registration process with prerequisite checks and tailored redirection.
    • Improved feedback via real-time notifications during profile updates and logout.
    • Refined access with role-specific redirection.
    • Added a user deletion command for administrative tasks.
    • Implemented a new function to automate the login process.
  • Style

    • Updated form labels for clarity (e.g., "Resume Link (PDF Required)").
    • Enabled clickable legal terms and dynamic button state indicators.
    • Refreshed social links for better engagement.

Copy link

coderabbitai bot commented Mar 13, 2025

Walkthrough

This pull request introduces a new deletion command and associated script while updating several test suites and UI components. The changes include modifications to OAuth rendering, Playwright configuration, and E2E test flows with revised login and registration actions. Updates are also made to routing, logout, and dashboard links, and adjustments to form submission and toast notifications in the portal. Additional enhancements improve accessibility, client-only rendering in layout, and introduce a new HackerDock component.

Changes

File(s) Change Summary
apps/axiom/project.json
apps/axiom/src/delete-user.ts
Added new "delete:user" target; introduced a new script to delete a user based on an environment-provided email via the Payload API.
apps/axiom/src/components/AfterLogin/index.tsx Commented out OAuth buttons for GitHub, Discord, and Google, leaving only the LinkedIn button active.
apps/portal-e2e/playwright.config.ts Updated baseURL to conditionally use environment URLs; explicitly set fullyParallel to false.
apps/portal-e2e/src/...
(multiple files: index.spec.ts, src/login/hacker/abilities.ts, src/profile/hacker/abilities.ts, src/registration/hacker/abilities.ts, src/profile/hacker/index.spec.ts, src/registration/hacker/index.spec.ts)
Removed encapsulated login functions; integrated login steps in tests; added new test functions for creating profiles and hackathon registration; commented out legacy test suites.
apps/portal-e2e/src/registration/questions.ts Updated aria labels and renamed a text area for improved UI clarity.
apps/portal/app/routes/api.auth.tsx
apps/portal/app/routes/login.tsx
apps/portal/app/routes/registration.tsx
apps/portal/app/routes/logout.tsx
Modified AuthRedirect to show a greeting; streamlined session handling in the loader; added a new OAuth redirection action; overhauled logout to use a fetch request with error handling and cookie clearance.
apps/portal/vite.config.ts Changed the Remix plugin configuration by setting v3_lazyRouteDiscovery to false.
libs/cms/auth/config.ts Updated redirect logic in successRedirect to return '/admin' for specific users.
libs/portal-e2e/abilities/index.ts
libs/portal-e2e/questions/index.ts
Added a new startLoggedIn function to automate login and introduced a constant LOGIN for test questions.
libs/portal/features/legal/ui/terms.tsx
libs/portal/features/profile/ui/questions.tsx
libs/portal/features/profile/hooks/use-profile-schema.ts
Enhanced checkbox interactivity and updated validation/error messages and label texts for profile components.
libs/portal/features/login/ui/call-to-action.tsx
libs/portal/features/registration/ui/registration.tsx
libs/portal/pages/profile/index.tsx
libs/portal/pages/registration/index.tsx
libs/portal/ui/dashboard/social-links/social-links.tsx
Adjusted form submission methods, updated toast notifications, refined button styling, and changed Discord link URL.
libs/portal/ui/hackerdock/hackerdock.client.tsx
libs/portal/ui/hackerdock/index.tsx
Introduced a new HackerDock component with conditional rendering of navigation links and updated its export reference.
libs/portal/ui/layout.tsx Modified the layout to use ClientOnly for client-specific rendering and made the isCompleteProfile flag optional.
apps/portal/app/routes/logout.tsx Updated logout loader to fetch from /api/users/logout and handle errors appropriately.

Sequence Diagram(s)

sequenceDiagram
    participant CLI as Command Line
    participant Script as deleteUser Script
    participant API as Payload API

    CLI->>Script: Run "delete:user" command
    Script->>API: Fetch user by email (from env variable)
    alt User Found
        API-->>Script: Return user data
        Script->>API: Request to delete user by ID
        Script-->>CLI: Log "User deleted"
    else User Not Found
        API-->>Script: No user found
        Script-->>CLI: Log "User does not exist"
    end
Loading
sequenceDiagram
    participant Browser as Browser
    participant Server as Logout Loader
    participant API as Logout API

    Browser->>Server: Request /logout with Cookie
    Server->>API: POST to /api/users/logout (with Cookie)
    alt Response OK
        API-->>Server: Success response
    else Response Fail
        API-->>Server: Error response
        Server->>Server: Log error
    end
    Server->>Browser: Redirect to /login with cleared cookie
Loading

Suggested labels

📦dependencies, released

Poem

In the code where changes align,
A deletion command now joins the line.
OAuth buttons rest, while tests are refined,
UI tweaks and logout flows are redesigned.
With HackerDock sailing at the bottom so fine 🚀,
Our code blossoms like a well-crafted rhyme!

Warning

There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

Progress: resolved 0, reused 0, downloaded 1, added 0
 ERR_PNPM_LINKED_PKG_DIR_NOT_FOUND  Could not install from "/tmp/eslint/infra/sdks/netlify" as it does not exist.

This error happened while installing a direct dependency of /tmp/eslint

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@HasithDeAlwis HasithDeAlwis changed the title Hasith/test/portal e2e/333 implement testrail test(portal-e2e): implement testrail Mar 13, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 11

🔭 Outside diff range comments (4)
apps/portal/app/routes/api.auth.tsx (2)

12-19: 🛠️ Refactor suggestion

Revisit commented WIP implementation

The code contains a commented "WIP" section that likely represents the intended final implementation. Consider implementing the proper solution that sets the X-Client-Origin header as indicated in the comments.

  try {
-    return redirect(`${baseUrl}/api/users/oauth/linkedin`)
+    const response = redirect(`${baseUrl}/api/users/oauth/linkedin`)
+    response.headers.set('X-Client-Origin', 'portal')
+    return response
-    // WIP SHOULD BE DOING THE BELOW
-    // cannot make a get request if you are doing a redirect
-    /* const response = redirect(`${baseUrl}/api/users/oauth/linkedin`)
-* response.headers.set('X-Client-Origin', 'portal')
-* return response */

20-55: 🧹 Nitpick (assertive)

Clean up commented-out code

There's a large block of commented-out code that appears to be an older implementation. If it's no longer needed, consider removing it to improve code maintainability. If it contains logic that should be implemented later, add a more specific TODO comment with details about what needs to be done.

libs/portal/features/profile/hooks/use-profile-schema.ts (1)

81-89: 🧹 Nitpick (assertive)

Consider expanding Google Drive link regex

The current regex for validating Google Drive links handles basic patterns but might not account for all valid formats. Google Drive links can have various formats including shortened links, shared folders, or different document types. Consider expanding the validation to handle these cases or provide more specific error messages.

apps/portal/app/routes/registration.tsx (1)

32-35: 🛠️ Refactor suggestion

Apply consistent credentials handling to forms fetch

You've added credentials: 'include' to the /api/users/me fetch but not to the form submissions fetch below. For consistency and to ensure proper authentication, consider adding the same credentials option to this fetch call as well.

  const forms = await fetch(`${API_URL}/api/form-submissions?where[submittedBy][equals]=${user.id}`, {
    method: 'GET',
+   credentials: 'include',
    headers: { Cookie: cookie || '' },
  })
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c72a654 and c89bddb.

📒 Files selected for processing (29)
  • apps/axiom/project.json (1 hunks)
  • apps/axiom/src/components/AfterLogin/index.tsx (1 hunks)
  • apps/axiom/src/delete-user.ts (1 hunks)
  • apps/portal-e2e/playwright.config.ts (1 hunks)
  • apps/portal-e2e/src/index.spec.ts (3 hunks)
  • apps/portal-e2e/src/login/hacker/abilities.ts (2 hunks)
  • apps/portal-e2e/src/profile/hacker/abilities.ts (2 hunks)
  • apps/portal-e2e/src/profile/hacker/index.spec.ts (1 hunks)
  • apps/portal-e2e/src/registration/hacker/abilities.ts (1 hunks)
  • apps/portal-e2e/src/registration/hacker/index.spec.ts (1 hunks)
  • apps/portal-e2e/src/registration/questions.ts (2 hunks)
  • apps/portal/app/routes/api.auth.tsx (1 hunks)
  • apps/portal/app/routes/login.tsx (2 hunks)
  • apps/portal/app/routes/registration.tsx (1 hunks)
  • apps/portal/vite.config.ts (1 hunks)
  • libs/cms/auth/config.ts (1 hunks)
  • libs/portal-e2e/abilities/index.ts (1 hunks)
  • libs/portal-e2e/questions/index.ts (1 hunks)
  • libs/portal/features/legal/ui/terms.tsx (2 hunks)
  • libs/portal/features/login/ui/call-to-action.tsx (1 hunks)
  • libs/portal/features/profile/hooks/use-profile-schema.ts (1 hunks)
  • libs/portal/features/profile/ui/questions.tsx (2 hunks)
  • libs/portal/features/registration/ui/registration.tsx (1 hunks)
  • libs/portal/pages/profile/index.tsx (2 hunks)
  • libs/portal/pages/registration/index.tsx (2 hunks)
  • libs/portal/ui/dashboard/social-links/social-links.tsx (1 hunks)
  • libs/portal/ui/hackerdock/hackerdock.client.tsx (0 hunks)
  • libs/portal/ui/hackerdock/index.tsx (1 hunks)
  • libs/portal/ui/layout.tsx (2 hunks)
💤 Files with no reviewable changes (1)
  • libs/portal/ui/hackerdock/hackerdock.client.tsx
🧰 Additional context used
🪛 Biome (1.9.4)
libs/portal/features/legal/ui/terms.tsx

[error] 116-120: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)


[error] 139-139: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)

🔇 Additional comments (39)
libs/portal/ui/hackerdock/index.tsx (1)

1-1: Update to client-side component import looks good.

This change aligns with modern React frameworks' client/server component separation pattern. The .client suffix is a good convention that clearly indicates this component should only run on the client side.

libs/portal/ui/layout.tsx (3)

5-5: Good addition of ClientOnly import.

Adding the ClientOnly utility from remix-utils is appropriate for components that need client-only rendering.


8-8: Function signature improvement with optional parameter.

Making isCompleteProfile optional with a default value improves the API. This is a good TypeScript pattern.


23-28: Proper implementation of client-only rendering.

Wrapping HackerDock in ClientOnly ensures it only renders in the browser. The callback pattern with fallback=null correctly handles server-side rendering.

This change correctly addresses issues that would occur if HackerDock uses browser-only APIs.

libs/portal-e2e/questions/index.ts (2)

1-1: Clean and Accurate Import Statement

The import of button from the shared test module is correctly implemented and clearly indicates dependence on a common test utility.


3-3: Clear Definition of the LOGIN Constant

Defining LOGIN using button.withText('LOG IN') is straightforward and consistent with project conventions.

libs/portal/ui/dashboard/social-links/social-links.tsx (1)

29-35: Discord URL Update:
You've correctly updated the href for the Discord link to https://discord.gg/VnbWdAe8kA. Please verify that this URL meets the latest requirements and update any related documentation if necessary.

apps/portal/vite.config.ts (1)

23-23:

✅ Verification successful

Verify impact of disabling lazy route discovery

Changing v3_lazyRouteDiscovery from true to false will load all routes at build time rather than lazily. This may increase initial bundle size but improve navigation performance. Ensure this change is intentional and doesn't negatively impact the application's performance or loading times.


🏁 Script executed:

#!/bin/bash
# Analyze the routes structure to understand the impact
echo "Checking Remix route files count:"
find apps/portal/app/routes -type f | grep -v "\.test\." | wc -l

echo "\nChecking for potential route structure complexity:"
find apps/portal/app/routes -type f | grep -v "\.test\." | sort

Length of output: 641


Impact of Eager Route Loading Confirmed

  • In apps/portal/vite.config.ts (line 23), setting v3_lazyRouteDiscovery to false will load all routes at build time.
  • Analysis of the routes folder shows 9 route files, indicating that the increased bundle size should be minimal.
  • This eager loading is expected to improve navigation performance; please verify that this trade-off aligns with current performance benchmarks.
apps/portal/app/routes/registration.tsx (1)

16-20:

❓ Verification inconclusive

Ensure consistency in fetch credential handling

You've added credentials: 'include' to enable cookies for cross-origin requests, which is good. However, check that all other API calls in the application consistently handle credentials, especially those related to authentication flows.


🏁 Script executed:

#!/bin/bash
# Find all fetch calls in the portal app to check for credentials handling
echo "Fetch calls without credentials option:"
grep -r "fetch(" --include="*.tsx" --include="*.ts" apps/portal | grep -v "credentials" | grep -B 2 -A 2 "fetch"

echo "\nFetch calls with credentials option:"
grep -r "fetch(" --include="*.tsx" --include="*.ts" apps/portal | grep "credentials" | grep -B 2 -A 2 "fetch"

Length of output: 1387


Action Required: Verify Consistency in Credential Handling Across All API Calls

You've added credentials: 'include' in apps/portal/app/routes/registration.tsx for the /api/users/me call, which is a step in the right direction for ensuring cookies are sent with cross-origin requests. However, an initial search across the portal codebase indicates that several fetch calls—in files such as _index.tsx, dashboard.tsx, login.tsx, and profile.tsx—do not visibly include a credentials option. Note that our previous automated search might miss multi-line credential configurations (for example, when the credentials property is defined on a separate line from the fetch( invocation).

Please verify that:

  • Intended Behavior: All API calls that rely on authentication or need to send cookies use credentials: 'include' (or another appropriate setting), and that the omission in some cases isn’t deliberate.
  • Multi-line Definitions: Review instances where the credential handling might be defined over multiple lines to ensure they’re not falsely flagged as missing this configuration.
  • Consistency: Update the fetch calls in files like apps/portal/app/routes/_index.tsx, dashboard.tsx, login.tsx, and profile.tsx if they are supposed to mirror the behavior established in registration.

Manual review is recommended to confirm the consistency across fetch calls.

libs/portal/features/login/ui/call-to-action.tsx (1)

27-27: Added cursor-pointer class to improve button UX

Good enhancement to provide visual feedback that the button is clickable.

libs/portal/pages/registration/index.tsx (1)

24-24:

✅ Verification successful

Removed hardcoded submittedBy value of '6'

Good change to remove the hardcoded submittedBy field with value '6'.

However, verify that:

  1. The backend no longer requires this field
  2. User attribution is still correctly tracked

🏁 Script executed:

#!/bin/bash
# Check if the postForm function or backend API still expects submittedBy
echo "Checking postForm implementation for submittedBy parameter..."
grep -r "postForm" --include="*.ts" --include="*.tsx" libs/portal

Length of output: 623


Verification Complete: Dynamic user attribution confirmed.

The change to remove the hardcoded "submittedBy" value and instead pass user.id is consistent with the backend's expectations, as confirmed by the definition of postForm in libs/portal/shared/features/form/api/index.ts (which expects a userId parameter). No further modifications are needed.

apps/portal-e2e/src/login/hacker/abilities.ts (2)

8-10: Improvement: Environment variables for sensitive data.

Good move replacing hardcoded credentials with environment variables. This aligns with security best practices and makes the tests configurable.


35-37: Credentials update looks good.

The function now properly uses the environment variables instead of hardcoded values.

libs/portal/features/profile/ui/questions.tsx (2)

222-222: Better label for resume link field.

Updating the label to clarify PDF requirement helps users understand the expected format.


460-460: Improved cursor styling based on button state.

Good UX improvement to provide visual feedback on the disabled state.

apps/axiom/src/components/AfterLogin/index.tsx (1)

29-46: OAuth buttons commented out - intentional?

You've commented out GitHub, Discord, and Google login options, leaving only LinkedIn. Is this intentional or part of a phased rollout?

If this is intended to be permanent, consider removing the code instead of commenting it out to keep the codebase clean. If it's temporary (for testing with just LinkedIn), add a TODO comment explaining when these will be re-enabled.

libs/portal/features/registration/ui/registration.tsx (1)

108-111: Enhanced button state feedback

Good enhancement to provide visual feedback through CSS classes that match the disabled state logic. This improves UX by clearly indicating when the button is not interactive.

libs/cms/auth/config.ts (1)

9-17: Improved redirect logic with explicit paths

The redirect logic is now more explicit with clear paths for admin users vs regular users. The added else block makes the code more readable and ensures proper flow control.

libs/portal-e2e/abilities/index.ts (1)

1-24: Good addition of reusable login function for E2E tests

This utility function provides a consistent way to handle authentication in E2E tests, following good DRY principles. The task sequence is logical and handles the login flow well.

Consider adding error handling for cases where elements might not be found or timeouts occur to make the utility more robust.

apps/portal-e2e/src/profile/hacker/index.spec.ts (1)

1-37:

❓ Verification inconclusive

Verify if commented tests are intentionally disabled

Commenting out entire test files reduces test coverage and can lead to regression issues. If this is part of the TestRail implementation, please clarify the plan for these tests:

  1. Are they being replaced by equivalent tests in another location?
  2. Is this a temporary measure during migration?
  3. Is there a tracking issue for re-enabling these tests?

Without tests for profile creation scenarios, you may miss regressions in this functionality.


🏁 Script executed:

#!/bin/bash
# Check if other test files have been commented out as well
echo "Checking for other commented test files..."
rg -l "^// describe" --type ts apps/portal-e2e/src/

Length of output: 285


Action: Confirm the Intent and Plan for Disabled Tests

It appears that disabled tests via commented code are present in multiple files:

  • apps/portal-e2e/src/profile/hacker/index.spec.ts
  • apps/portal-e2e/src/registration/hacker/index.spec.ts
  • apps/portal-e2e/src/index.spec.ts

Please clarify:

  • Are these tests being replaced by equivalent tests elsewhere?
  • Is disabling them a temporary step during a migration (e.g., as part of your TestRail implementation)?
  • Is there a tracking issue or timeline for re-enabling these tests?

Since the profile creation scenarios are currently untested, addressing this is essential to avoid regressions.

apps/portal/app/routes/login.tsx (1)

25-27:

✅ Verification successful

Logic simplified for redirection when user exists

The redirection logic has been simplified to just check for user existence and redirect directly. This makes the code cleaner, but there's a potential risk that the session-based auth is no longer being managed properly.


🏁 Script executed:

#!/bin/bash
# Checking for session management implementation elsewhere
rg -A 3 "getSession|commitSession" --type=tsx --type=ts

Length of output: 85


Below is an updated shell script to re-verify that session management (e.g. via getSession or commitSession) is implemented elsewhere. The previous command failed due to the tsx file type flag. This script uses explicit globs to include both *.ts and *.tsx files:

Once you run this script and review the output, we can confirm whether the redirection logic (i.e., the simple check for user existence in apps/portal/app/routes/login.tsx at lines 25–27) inadvertently skips important session management. Please provide the output for further verification.


🏁 Script executed:

#!/bin/bash
# Re-verify session management by searching for getSession and commitSession across *.ts and *.tsx files using explicit file globs.
rg -g "*.{ts,tsx}" -A 3 "getSession|commitSession"

Length of output: 1028


Verified session management is properly implemented across the codebase.

The simplified redirection in apps/portal/app/routes/login.tsx (lines 25–27) now solely checks for user existence to redirect, which is acceptable given the following:

  • Session management utilities (getSession, commitSession, destroySession) are implemented in apps/portal/app/sessions.ts.
  • These utilities are actively used in routes such as apps/portal/app/routes/api.auth.tsx to manage session cookies.

No immediate issues were detected with simplifying the login redirection, provided that session handling remains consistently managed elsewhere in the code. Please verify that the login flow correctly initializes sessions where needed.

apps/portal-e2e/playwright.config.ts (1)

15-16: Explicit disabling of parallel test execution

Setting fullyParallel to false ensures consistent test execution behavior regardless of environment, which can help with test reliability. This is especially useful for TestRail integration where test cases might have ordering dependencies.

libs/portal/pages/profile/index.tsx (5)

6-6: Added toast notification dependency

Good addition. Using a toast library for user feedback is more intuitive than relying solely on response objects.


15-17: Improved user feedback with better naming and loading state

Using past tense for the action and adding a loading toast improves the user experience.


24-28: Success toast notification

The toast success notification provides clear feedback to users on successful profile operations.


29-29: Consistent response message

Using the same message in the toast and the Response object is a good practice for consistency.


37-41:

❓ Verification inconclusive

Error feedback with toast

Good error handling with toast notification. However, there's an inconsistency in how errors are handled across the application.


🏁 Script executed:

#!/bin/bash
# Check for error toast pattern consistency
rg -A 5 "toast\.error" --type tsx --type ts

Length of output: 73


Error Toast Consistency Verification

The toast error handler implementation within the file looks solid, but we need to double-check consistency across the codebase. The initial rg command failed because the file type tsx wasn’t recognized. Please run the revised script below to manually verify that instances of toast.error are being used consistently:

#!/bin/bash
# Search for error toast usage in TypeScript and TSX files.
rg -A 5 "toast\.error" -g "*.tsx" -g "*.ts"

Once you've verified that the usage is consistent across the codebase, we can proceed accordingly.

apps/portal-e2e/src/registration/hacker/abilities.ts (2)

3-5: Good addition of Navigate and startLoggedIn imports.
These imports correctly align with the new login and navigation flow.


7-13: Verify usage of the destructured actor param.
Inside registerForHackathon({ actor }), you call actorCalled('Hacker') but never reference actor. Confirm this is intentional or switch to using the passed-in actor to avoid confusion.

apps/portal-e2e/src/registration/questions.ts (2)

5-19: Aria label changes improve clarity.
The updated labels are more descriptive.


28-28: Renaming textArea to ‘first-time-hacker’ is consistent.
This naming is clearer and aligns well with the question’s intent.

apps/portal-e2e/src/profile/hacker/abilities.ts (3)

1-4: New imports appear correct.
Importing startLoggedIn and updated Serenity/JS modules is valid for the new login flow.


8-11: Well-structured login and navigation steps.
The destructured actor usage and the startLoggedIn() invocation streamline the flow into the profile page.


66-66: Confirm final route logic.
Switching from /dashboard to /registration alters the post-profile workflow. Double-check this aligns with user expectations.

apps/portal-e2e/src/index.spec.ts (5)

5-7: Imported necessary abilities for extended test coverage

Good addition of required imports to support new test cases for profile creation and hackathon registration.


34-35: Navigation flow updated correctly for the login test

The updated flow now aligns with the application's expected behavior, redirecting to '/terms' after login rather than '/dashboard'.


42-42: Explicit navigation to '/terms' ensures test independence

Good practice to explicitly navigate to '/terms' rather than relying on previous test state, making this test more reliable and independently executable.


75-75: XPath selectors provide more precise element targeting

Switching from CSS to XPath selectors for checkbox text content is more robust, especially for elements with complex text content.

Also applies to: 80-80


1-568:

❓ Verification inconclusive

Verify environment variables are properly configured in CI

The test depends on environment variables LOCAL_DEV_EMAIL_ADDRESS and LOCAL_DEV_PASSWORD. Ensure these are configured in your CI environment for TestRail integration.


🏁 Script executed:

#!/bin/bash
# Check for environment variable configuration in GitHub Actions workflow files
grep -r "LOCAL_DEV_EMAIL_ADDRESS\|LOCAL_DEV_PASSWORD" .github/workflows/

Length of output: 74


Ensure CI pipelines properly expose required environment variables for TestRail integration

Please manually verify that the environment variables LOCAL_DEV_EMAIL_ADDRESS and LOCAL_DEV_PASSWORD are correctly configured in your CI environment. Our initial grep in the GitHub Actions workflow files didn’t return any configuration details, so confirm that these are set through repository secrets or another appropriate mechanism to ensure they’re available at runtime.

🧰 Tools
🪛 Biome (1.9.4)

[error] 12-18: Do not export from a test file.

(lint/suspicious/noExportsInTest)

Comment on lines 63 to +68
export default function AuthRedirect() {
return null
return (
<>
HELL0 world ;)
</>
)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove debug output from AuthRedirect component

The component is returning "HELL0 world ;)" text which appears to be a temporary debug statement. This should be removed before deployment to production.

export default function AuthRedirect() {
-  return (
-    <>
-    HELL0 world ;)
-    </>
-  )
+  return null
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export default function AuthRedirect() {
return null
return (
<>
HELL0 world ;)
</>
)
export default function AuthRedirect() {
return null
}

@@ -84,7 +84,7 @@ export function useProfileSchema(
link,
),
{
message: 'Invalid Google Drive link.',
message: 'Invalid Google Drive link',
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Maintain consistency in error message punctuation

The error message for the Google Drive link validation has had its period removed. For consistency, check if other error messages in this schema follow the same pattern (with or without ending punctuation) and ensure they all follow the same standard.

#!/bin/bash
# Check for consistency in error message punctuation
echo "Error messages with periods:"
grep -r "message: '[^']*\.'" libs/portal/features/profile/hooks/

echo "\nError messages without periods:"
grep -r "message: '[^']*[^.]'" libs/portal/features/profile/hooks/

@@ -20,11 +20,11 @@ export function LoginCallToAction() {
</h2>
</header>

<Form method="get" action="/api/auth">
<Form method="post" >
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Changed form method from "get" to "post" and removed action attribute

This change indicates a shift in the authentication flow. Ensure the receiving endpoint is correctly set up to handle POST requests. With Remix router's conventions, the POST will be handled by the action function in the nearest route.

Comment on lines +1 to +34
// import { actorCalled, Task } from '@serenity-js/core'
// import { beforeEach, describe, it } from '@serenity-js/playwright-test'
// import { BrowseTheWeb, Navigate } from '@serenity-js/web'
// import { registerForHackathon, registerForHackathonMissingFields } from './abilities'

export function startLoggedInNoProfile() {
return Task.where(
'#actor starts logged out',
Navigate.to('/registration'),
)
}
// const EMAIL_ADDRESS = process.env.LOCAL_DEV_EMAIL_ADDRESS
// const PASSWORD = process.env.LOCAL_DEV_PASSWORD

describe('when the hacker', () => {
beforeEach(async ({ actor }) => {
await actorCalled('Hacker')
.whoCan(BrowseTheWeb.as(actor))
.attemptsTo(startLoggedInNoProfile())
})
// export function startLoggedInNoProfile() {
// return Task.where(
// '#actor starts logged out',
// Navigate.to('/registration'),
// )
// }

describe('is logged in', () => {
describe('has profile', () => {
it('should be able to regsiter', async () => {
await registerForHackathon()
})
// describe('when the hacker', () => {
// beforeEach(async ({ actor }) => {
// await actorCalled('Hacker')
// .whoCan(BrowseTheWeb.as(actor))
// .attemptsTo(startLoggedInNoProfile())
// })

it('should not be able to regsiter with missing fields', async () => {
await registerForHackathonMissingFields()
})
})
})
})
// describe('is logged in', () => {
// describe('has profile', () => {
// it('should be able to regsiter', async () => {
// await registerForHackathon()
// })

// it('should not be able to regsiter with missing fields', async () => {
// await registerForHackathonMissingFields()
// })
// })
// })
// })
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Commented out entire test file - potential test coverage gap

The entire test file has been commented out, which removes test coverage for the registration flow. If this is part of migrating tests to TestRail, please document this transition in the code comments.

Consider adding a comment at the top of the file explaining:

  • Why these tests are disabled
  • Where the equivalent test cases now live in TestRail
  • Whether these tests will be removed entirely in a future PR

🏁 Script executed:

#!/bin/bash
# Check if there are any other test files covering registration functionality
echo "Checking for other test files covering registration functionality..."
find apps/portal-e2e/src -type f -name "*.spec.ts" | grep -v "index.spec.ts" | grep -i "registration"

Length of output: 246


Action: Document Disabled Registration Tests

The entire test file is currently commented out, which creates a potential coverage gap for the registration flow. I couldn’t locate any alternative test files within the repository to cover these scenarios, so please confirm whether these tests have been migrated to TestRail. If so, add a header comment in apps/portal-e2e/src/registration/hacker/index.spec.ts that details:

  • Why these tests are disabled
  • Where the equivalent test cases now reside in TestRail
  • Whether these tests will be removed entirely in an upcoming PR

Comment on lines +138 to 143
"delete:user": {
"command": "cross-env NODE_OPTIONS=--no-deprecation payload run src/delete-user.ts",
"options": {
"cwd": "apps/axiom"
}
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Added new "delete:user" command target

Good addition for testing purposes. This target will help with cleaning up test users during automated testing.

Consider adding:

  1. Documentation for this command in your README
  2. Safeguards to prevent accidental deletion of production users

Comment on lines +35 to +42
export const action: LoaderFunction = async () => {
const baseUrl
= process.env.NODE_ENV === 'development'
? 'http://localhost:8000'
: 'https://axiom.cuhacking.ca'

return redirect(`${baseUrl}/api/users/oauth/linkedin`)
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

New action function for LinkedIn OAuth

The new action function provides a clean way to handle LinkedIn OAuth redirection, but there's a code duplication issue with the baseUrl construction. The same logic exists in both loader and action functions.

Consider extracting the baseUrl logic into a shared utility function:

+function getBaseUrl() {
+  return process.env.NODE_ENV === 'development'
+    ? 'http://localhost:8000'
+    : 'https://axiom.cuhacking.ca'
+}

export const loader: LoaderFunction = async ({ request }) => {
  const cookie = request.headers.get('Cookie')
-  const baseUrl
-  = process.env.NODE_ENV === 'development'
-    ? 'http://localhost:8000'
-    : 'https://axiom.cuhacking.ca'
+  const baseUrl = getBaseUrl()

  try {
    // ...
  }
}

export const action: LoaderFunction = async () => {
-  const baseUrl
-    = process.env.NODE_ENV === 'development'
-      ? 'http://localhost:8000'
-      : 'https://axiom.cuhacking.ca'
+  const baseUrl = getBaseUrl()

  return redirect(`${baseUrl}/api/users/oauth/linkedin`)
}

@@ -8,11 +8,12 @@ import { defineConfig, devices } from '@playwright/test'

const __filename = fileURLToPath(import.meta.url)

const baseURL = process.env.CUHACKING_2025_PORTAL_LOCAL_URL
const baseURL = process.env.CI ? process.env.CUHACKING_2025_PORTAL_LOCAL_URL : process.env.CUHACKING_2025_PORTAL_PUBLIC_URL
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Environment-dependent baseURL

The baseURL is now conditionally set based on the CI environment, which is good for flexibility. However, there's no fallback value if the environment variables are undefined, which could cause tests to fail silently.

Add fallback values:

-const baseURL = process.env.CI ? process.env.CUHACKING_2025_PORTAL_LOCAL_URL : process.env.CUHACKING_2025_PORTAL_PUBLIC_URL
+const baseURL = process.env.CI 
+  ? process.env.CUHACKING_2025_PORTAL_LOCAL_URL || 'http://localhost:5173' 
+  : process.env.CUHACKING_2025_PORTAL_PUBLIC_URL || 'http://localhost:5173'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const baseURL = process.env.CI ? process.env.CUHACKING_2025_PORTAL_LOCAL_URL : process.env.CUHACKING_2025_PORTAL_PUBLIC_URL
const baseURL = process.env.CI
? process.env.CUHACKING_2025_PORTAL_LOCAL_URL || 'http://localhost:5173'
: process.env.CUHACKING_2025_PORTAL_PUBLIC_URL || 'http://localhost:5173'

Comment on lines +139 to +144
<div onClick={() => handleCheckboxChange(`${value}2`)}>
<Typography variant="paragraph-base" className="text-left">
{buttonContent2}
<span className="text-red-500">*</span>
</Typography>
</div>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Checkbox label needs keyboard accessibility

Similar to the previous issue, this click handler also lacks keyboard accessibility.

-<div onClick={() => handleCheckboxChange(`${value}2`)}>
+<div 
+  onClick={() => handleCheckboxChange(`${value}2`)}
+  onKeyDown={(e) => {
+    if ((e.key === 'Enter' || e.key === ' ') && scrollEndReached[value]) {
+      e.preventDefault();
+      handleCheckboxChange(`${value}2`);
+    }
+  }}
+  tabIndex={scrollEndReached[value] ? 0 : -1}
+  role="button"
+  aria-disabled={!scrollEndReached[value]}
+>
  <Typography variant="paragraph-base" className="text-left">
    {buttonContent2}
    <span className="text-red-500">*</span>
  </Typography>
</div>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div onClick={() => handleCheckboxChange(`${value}2`)}>
<Typography variant="paragraph-base" className="text-left">
{buttonContent2}
<span className="text-red-500">*</span>
</Typography>
</div>
<div
onClick={() => handleCheckboxChange(`${value}2`)}
onKeyDown={(e) => {
if ((e.key === 'Enter' || e.key === ' ') && scrollEndReached[value]) {
e.preventDefault();
handleCheckboxChange(`${value}2`);
}
}}
tabIndex={scrollEndReached[value] ? 0 : -1}
role="button"
aria-disabled={!scrollEndReached[value]}
>
<Typography variant="paragraph-base" className="text-left">
{buttonContent2}
<span className="text-red-500">*</span>
</Typography>
</div>
🧰 Tools
🪛 Biome (1.9.4)

[error] 139-139: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)

Comment on lines +115 to 126

<div onClick={() => {
if (scrollEndReached[value]) {
handleCheckboxChange(`${value}1`)
}
}}>
<Typography variant="paragraph-base" className="text-left">
{buttonContent}
<span className="text-red-500">*</span>
</Typography>
</div>
</div>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Added click handler to terms checkbox label, but missing keyboard accessibility

The added onClick handler improves usability by making the label clickable, but it lacks keyboard accessibility support which is flagged by the static analysis.

Add keyboard event handling:

-<div onClick={() => {
+<div 
+  onClick={() => {
   if (scrollEndReached[value]) {
    handleCheckboxChange(`${value}1`)
   }
-  }}>
+  }}
+  onKeyDown={(e) => {
+    if ((e.key === 'Enter' || e.key === ' ') && scrollEndReached[value]) {
+      e.preventDefault();
+      handleCheckboxChange(`${value}1`);
+    }
+  }}
+  tabIndex={scrollEndReached[value] ? 0 : -1}
+  role="button"
+  aria-disabled={!scrollEndReached[value]}
+>
  <Typography variant="paragraph-base" className="text-left">
    {buttonContent}
    <span className="text-red-500">*</span>
  </Typography>
</div>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div onClick={() => {
if (scrollEndReached[value]) {
handleCheckboxChange(`${value}1`)
}
}}>
<Typography variant="paragraph-base" className="text-left">
{buttonContent}
<span className="text-red-500">*</span>
</Typography>
</div>
</div>
<div
onClick={() => {
if (scrollEndReached[value]) {
handleCheckboxChange(`${value}1`)
}
}}
onKeyDown={(e) => {
if ((e.key === 'Enter' || e.key === ' ') && scrollEndReached[value]) {
e.preventDefault();
handleCheckboxChange(`${value}1`);
}
}}
tabIndex={scrollEndReached[value] ? 0 : -1}
role="button"
aria-disabled={!scrollEndReached[value]}
>
<Typography variant="paragraph-base" className="text-left">
{buttonContent}
<span className="text-red-500">*</span>
</Typography>
</div>
</div>
🧰 Tools
🪛 Biome (1.9.4)

[error] 116-120: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 10

🔭 Outside diff range comments (1)
apps/portal/app/routes/registration.tsx (1)

7-53: 🧹 Nitpick (assertive)

Consider refactoring loader function for better maintainability.

The loader function is growing in complexity with multiple redirects and conditions. Consider extracting the user validation logic into a separate function for improved readability and maintainability.

// Example refactored approach
function validateUserRegistrationState(user: any) {
  if (!user) {
    return { isValid: false, reason: 'not_authenticated' }
  }
  if (!user.agreedToTerms) {
    return { isValid: false, reason: 'terms_not_agreed' }
  }
  if (!user.emergencyContactFullName) {
    return { isValid: false, reason: 'missing_emergency_contact' }
  }
  return { isValid: true }
}

export const loader: LoaderFunction = async ({ request }) => {
  // Setup and fetch user as before
  
  try {
    // ... existing code to fetch user
    
    const validation = validateUserRegistrationState(user)
    if (!validation.isValid) {
      return redirect(`/?error=${validation.reason}`)
    }
    
    // Continue with form submissions check
  } catch {
    return redirect('/')
  }
}
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c89bddb and f958b7b.

📒 Files selected for processing (3)
  • apps/portal/app/routes/logout.tsx (1 hunks)
  • apps/portal/app/routes/registration.tsx (2 hunks)
  • libs/portal/ui/hackerdock/hackerdock.client.tsx (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: test
🔇 Additional comments (2)
apps/portal/app/routes/registration.tsx (1)

17-18: Adding credentials:include enhances authentication flow.

The addition of credentials: 'include' is important to ensure cookies are sent with cross-origin requests. This complements the existing manual Cookie header assignment, working together to maintain proper authentication state.

apps/portal/app/routes/logout.tsx (1)

5-10: Code structure change looks good.

The updated loader function now correctly accepts the request parameter, allowing access to the cookie headers. The endpoint URL change from /admin/logout to /api/users/logout aligns with API restructuring.

Comment on lines +32 to +34
if (!user.agreedToTerms) {
return redirect('/')
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

New user validation enhances registration flow.

This check ensures users complete all required steps in the correct order by redirecting those who haven't agreed to terms. Consider adding a query parameter to the redirect to inform the user why they're being redirected for a better user experience.

- return redirect('/')
+ return redirect('/?missingStep=terms')
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!user.agreedToTerms) {
return redirect('/')
}
if (!user.agreedToTerms) {
return redirect('/?missingStep=terms')
}

Comment on lines +36 to +38
if (!user.emergencyContactFullName) {
return redirect('/')
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Appropriate validation for emergency contact.

This check properly ensures users provide emergency contact information before proceeding with registration. Similar to the above comment, consider adding context to the redirect for improved UX.

- return redirect('/')
+ return redirect('/?missingStep=emergencyContact')
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!user.emergencyContactFullName) {
return redirect('/')
}
if (!user.emergencyContactFullName) {
return redirect('/?missingStep=emergencyContact')
}

Comment on lines +12 to +29
try {
const res = await fetch(adminURL, {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'Cookie': cookie || '',
},
})

if (!res.ok) {
console.error('ERROR - Could not log user out')
throw new Error('Failed to log out user')
}
}
catch (error) {
console.error('ERROR - An error occurred during logout', error)
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Error handling implementation is good but consider improving error management.

The try-catch implementation for the fetch request is appropriate, but the current implementation swallows errors after logging them. Since you're not re-throwing after catching, the function will proceed to redirect regardless of whether the logout was successful.

This might be intentional (to ensure users are always redirected to login), but consider adding comments explaining this design decision.

Comment on lines 31 to 38
const response = redirect('/login', {
headers: {
"Set-Cookie":
"payload-token=; path=/"
}
})
return response
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Cookie clearing implementation could be more robust.

While the current implementation will clear the cookie, consider using a more complete cookie clearing approach:

  const response = redirect('/login', {
    headers: {
      "Set-Cookie":
-     "payload-token=; path=/"
+     "payload-token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly; SameSite=Lax"
    }
  })

This ensures better cross-browser compatibility and security by:

  1. Setting an expired date
  2. Adding HttpOnly flag to prevent JavaScript access
  3. Including SameSite attribute for CSRF protection
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const response = redirect('/login', {
headers: {
"Set-Cookie":
"payload-token=; path=/"
}
})
return response
const response = redirect('/login', {
headers: {
"Set-Cookie":
"payload-token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly; SameSite=Lax"
}
})
return response

label: 'Home',
disabled: false,
href: '/dashboard',
icon: <Logo link="/dashboard" />,
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Consider removing redundant link prop in Logo component.

The Logo component already has a link prop pointing to /dashboard, but it's used within a Link component that already routes to /dashboard.

-          icon: <Logo link="/dashboard" />,
+          icon: <Logo />,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
icon: <Logo link="/dashboard" />,
icon: <Logo />,

Comment on lines +75 to +78
className={cn(
'',
link.disabled && 'opacity-25 pointer-events-none cursor-not-allowed',
)}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Remove empty string className and consider using a more descriptive approach for disabled links.

The empty string in the className concatenation is unnecessary. Additionally, for better accessibility, consider using aria-disabled for disabled links.

                    className={cn(
-                      '',
                      link.disabled && 'opacity-25 pointer-events-none cursor-not-allowed',
                    )}
+                    aria-disabled={link.disabled}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
className={cn(
'',
link.disabled && 'opacity-25 pointer-events-none cursor-not-allowed',
)}
className={cn(
link.disabled && 'opacity-25 pointer-events-none cursor-not-allowed',
)}
aria-disabled={link.disabled}

];

return (
<div className="fixed w-screen bottom-4 flex flex-col items-center justify-center z-10000">
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Consider using more standard z-index values.

The z-index values z-10000 and z-10001 (line 83) are extremely high and could potentially cause conflicts with other UI elements. Consider using a more standard z-index scale.

-    <div className="fixed w-screen bottom-4 flex flex-col items-center justify-center z-10000">
+    <div className="fixed w-screen bottom-4 flex flex-col items-center justify-center z-50">

You should also update the z-index on line 83 accordingly:

-                <TooltipContent className="z-10001">
+                <TooltipContent className="z-51">
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div className="fixed w-screen bottom-4 flex flex-col items-center justify-center z-10000">
// Context from libs/portal/ui/hackerdock/hackerdock.client.tsx
<div className="fixed w-screen bottom-4 flex flex-col items-center justify-center z-50">
{/* other content */}
</div>
{/* ...other parts of the component... */}
<TooltipContent className="z-51">
{/* tooltip content */}
</TooltipContent>
{/* ...rest of the file... */}

@HasithDeAlwis HasithDeAlwis force-pushed the hasith/test/portal-e2e/333-implement-testrail branch from 6d14d2a to 4525463 Compare March 13, 2025 06:15
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f958b7b and 4525463.

📒 Files selected for processing (1)
  • libs/db/collections/models/Users.ts (1 hunks)

Comment on lines 261 to 267
auth: {
cookies: {
domain: process.env.NODE_ENV === 'development' ? 'localhost' : '.cuhacking.ca',
sameSite: 'None',
secure: true
},
// cookies: {
// domain: process.env.NODE_ENV === 'development' ? 'localhost' : '.cuhacking.ca',
// sameSite: 'None',
// secure: true
// },
disableLocalStrategy: {
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

❓ Verification inconclusive

Clarify and Document the Cookie Settings Change

The cookie configuration has been commented out within the auth object. Please confirm that this change is intentional, and if so, add a brief comment explaining why these settings are disabled so future maintainers understand the context.


Clarify Cookie Configuration Reasoning

In libs/db/collections/models/Users.ts (lines 261-267), the cookie settings within the auth object are commented out. Please confirm that this change is intentional and add an inline comment explaining the rationale behind disabling these settings. This will help future maintainers understand the context.

@HasithDeAlwis HasithDeAlwis force-pushed the hasith/test/portal-e2e/333-implement-testrail branch 2 times, most recently from d522bb1 to 397db6f Compare March 13, 2025 06:42
@HasithDeAlwis HasithDeAlwis force-pushed the hasith/test/portal-e2e/333-implement-testrail branch from 397db6f to f89551c Compare March 13, 2025 06:58
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

♻️ Duplicate comments (5)
libs/portal/features/legal/ui/terms.tsx (2)

115-126: ⚠️ Potential issue

Missing keyboard accessibility in checkbox label click handler.

The div with the onClick handler lacks keyboard event support, making it inaccessible to keyboard users.

Add keyboard event handling as previously suggested:

-<div onClick={() => {
+<div 
+  onClick={() => {
   if (scrollEndReached[value]) {
    handleCheckboxChange(`${value}1`)
   }
-  }}>
+  }}
+  onKeyDown={(e) => {
+    if ((e.key === 'Enter' || e.key === ' ') && scrollEndReached[value]) {
+      e.preventDefault();
+      handleCheckboxChange(`${value}1`);
+    }
+  }}
+  tabIndex={scrollEndReached[value] ? 0 : -1}
+  role="button"
+  aria-disabled={!scrollEndReached[value]}
+>
  <Typography variant="paragraph-base" className="text-left">
    {buttonContent}
    <span className="text-red-500">*</span>
  </Typography>
</div>
🧰 Tools
🪛 Biome (1.9.4)

[error] 116-120: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)


139-144: ⚠️ Potential issue

Missing keyboard accessibility in second checkbox label click handler.

This click handler also lacks keyboard accessibility, making it inaccessible to keyboard users.

Add keyboard event handling:

-<div onClick={() => handleCheckboxChange(`${value}2`)}>
+<div 
+  onClick={() => handleCheckboxChange(`${value}2`)}
+  onKeyDown={(e) => {
+    if ((e.key === 'Enter' || e.key === ' ') && scrollEndReached[value]) {
+      e.preventDefault();
+      handleCheckboxChange(`${value}2`);
+    }
+  }}
+  tabIndex={scrollEndReached[value] ? 0 : -1}
+  role="button"
+  aria-disabled={!scrollEndReached[value]}
+>
  <Typography variant="paragraph-base" className="text-left">
    {buttonContent2}
    <span className="text-red-500">*</span>
  </Typography>
</div>
🧰 Tools
🪛 Biome (1.9.4)

[error] 139-139: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)

apps/portal/app/routes/logout.tsx (2)

12-29: 🧹 Nitpick (assertive)

Silent error handling during logout.

The try-catch implementation logs errors but doesn't prevent redirection to the login page, even if logout fails.

Add a comment explaining this design decision if intentional:

try {
  // ... existing code
}
catch (error) {
  console.error('ERROR - An error occurred during logout', error)
+  // Always redirect to login page even if logout fails
+  // This ensures users can't get stuck in a logged-in state with invalid credentials
}

31-38: 🧹 Nitpick (assertive)

Cookie clearing implementation could be more robust.

The current cookie clearing lacks security attributes like HttpOnly and SameSite.

Enhance cookie security:

const response = redirect('/login', {
  headers: {
    'Set-Cookie':
-    `payload-token=; path=/; domain=${domain}`,
+    `payload-token=; path=/; domain=${domain}; expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly; SameSite=Lax`,
  },
})
apps/portal-e2e/src/index.spec.ts (1)

87-89: 🧹 Nitpick (assertive)

Add final result assertion in test

Suggest verifying a successful profile creation within the test itself for better clarity.

 it('should be able to create profile', async ({ actor }) => {
   await createProfile({ actor })
+  // e.g. verify final route, or confirm success message
 })
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 397db6f and f89551c.

📒 Files selected for processing (20)
  • apps/axiom/src/components/AfterLogin/index.tsx (1 hunks)
  • apps/portal-e2e/playwright.config.ts (1 hunks)
  • apps/portal-e2e/src/index.spec.ts (3 hunks)
  • apps/portal-e2e/src/profile/hacker/abilities.ts (2 hunks)
  • apps/portal-e2e/src/profile/hacker/index.spec.ts (1 hunks)
  • apps/portal-e2e/src/registration/hacker/abilities.ts (1 hunks)
  • apps/portal-e2e/src/registration/hacker/index.spec.ts (1 hunks)
  • apps/portal-e2e/src/registration/questions.ts (2 hunks)
  • apps/portal/app/routes/logout.tsx (1 hunks)
  • apps/portal/app/routes/registration.tsx (2 hunks)
  • libs/portal-e2e/abilities/index.ts (1 hunks)
  • libs/portal-e2e/questions/index.ts (1 hunks)
  • libs/portal/features/legal/ui/terms.tsx (2 hunks)
  • libs/portal/features/login/ui/call-to-action.tsx (1 hunks)
  • libs/portal/features/profile/hooks/use-profile-schema.ts (1 hunks)
  • libs/portal/features/profile/ui/questions.tsx (2 hunks)
  • libs/portal/features/registration/ui/registration.tsx (1 hunks)
  • libs/portal/pages/profile/index.tsx (2 hunks)
  • libs/portal/ui/dashboard/social-links/social-links.tsx (1 hunks)
  • libs/portal/ui/hackerdock/hackerdock.client.tsx (1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
libs/portal/features/legal/ui/terms.tsx

[error] 116-120: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)


[error] 139-139: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: build (22.13.1)
  • GitHub Check: test
🔇 Additional comments (31)
libs/portal/ui/dashboard/social-links/social-links.tsx (1)

32-32: Discord invite link updated

The Discord invite link has been updated from the previous value to a new one. Ensure this is the correct new invite link for the community.

libs/portal/features/login/ui/call-to-action.tsx (2)

23-23: Method changed to post for form submission

Changing from "get" to "post" is appropriate for authentication flows. In Remix, this will trigger the action function in the nearest route. Verify your route has the proper action handler set up.


27-27: Good UX enhancement with cursor-pointer

Adding the cursor-pointer class improves user experience by providing visual feedback that the button is interactive.

apps/axiom/src/components/AfterLogin/index.tsx (1)

29-46: Confirm if limiting to LinkedIn auth only is intentional

You've commented out GitHub, Discord, and Google OAuth options, leaving only LinkedIn active. This aligns with the LinkedIn-only login form changes in the other file, but reduces authentication options for users.

Is this an intentional simplification of the auth flow for the TestRail implementation, or will these options be re-enabled in a future PR?

libs/portal/ui/hackerdock/hackerdock.client.tsx (6)

14-16: Add documentation to clarify what the status prop represents.

The status boolean prop isn't self-explanatory. Add JSDoc comments to clarify what this status represents (e.g., whether it indicates user authentication, registration status, etc.).

 interface HackerDockProps {
+  /** Indicates whether the user is authenticated/registered */
   status: boolean
 }

38-40: Improve handling of disabled links.

Disabled links still have href properties that point to /, which is redundant. For disabled links, consider using # or removing the href attribute entirely.

         {
           label: 'Sponsors',
           disabled: true,
-          href: '/',
+          href: '#',
           icon: <img className="size-6" src={handshake} alt="Team Icon" />,
         },
         {
           label: 'Challenges',
           disabled: true,
-          href: '/',
+          href: '#',
           icon: <img className="size-6" src={mountain} alt="Challenges Icon" />,
         },
         {
           label: 'Calendar',
           disabled: true,
-          href: '/',
+          href: '#',
           icon: <img className="size-6" src={map} alt="Map Icon" />,
         },

Also applies to: 49-52, 55-58


46-46: Remove redundant link prop in Logo component.

The Logo component has a link prop pointing to /dashboard, but it's already within a Link component that routes to /dashboard.

-          icon: <Logo link="/dashboard" />,
+          icon: <Logo />,

65-65: Use more standard z-index values.

The z-index values z-10000 and z-10001 are extremely high and could potentially cause conflicts with other UI elements.

-    <div className="fixed w-screen bottom-4 flex flex-col items-center justify-center z-10000">
+    <div className="fixed w-screen bottom-4 flex flex-col items-center justify-center z-50">

-                <TooltipContent className="z-10001">
+                <TooltipContent className="z-51">

Also applies to: 83-83


75-78: Improve className usage and accessibility for disabled links.

The empty string in the className concatenation is unnecessary. For better accessibility, consider using aria-disabled for disabled links.

                    className={cn(
-                      '',
                      link.disabled && 'opacity-25 pointer-events-none cursor-not-allowed',
                    )}
+                    aria-disabled={link.disabled}

65-65: Add data-testid attributes for E2E testing.

Since this PR is focused on implementing TestRail for E2E tests, adding data-testid attributes would help with testing this component.

-    <div className="fixed w-screen bottom-4 flex flex-col items-center justify-center z-10000">
+    <div className="fixed w-screen bottom-4 flex flex-col items-center justify-center z-10000" data-testid="hacker-dock">

                  <Link
                    to={link.href}
                    aria-label={link.label}
+                   data-testid={`dock-link-${link.label.toLowerCase()}`}
                    className={cn(

Also applies to: 72-79

libs/portal-e2e/questions/index.ts (1)

1-3: Looks good - adding login test utility

Clean implementation of a test utility for selecting the login button. This will help standardize button selection across E2E tests.

libs/portal/features/profile/hooks/use-profile-schema.ts (1)

87-87: Error message period removed for consistency

The removal of the period from the error message aligns with the formatting of other error messages in this file (like 'Required', 'Invalid email', 'Invalid URL').

libs/portal/features/profile/ui/questions.tsx (2)

222-222: Improved field label with format requirements

Changing "Resume Link" to "Resume Link (PDF Required)" enhances clarity about the expected file format. This provides better up-front guidance to users.


460-460: Enhanced button accessibility with proper cursor states

Adding cursor style based on disabled state improves the UI feedback. This properly indicates when interaction is not possible.

apps/portal-e2e/src/registration/hacker/index.spec.ts (1)

1-34: Action: Document Disabled Registration Tests

The entire test file is currently commented out, which creates a potential coverage gap for the registration flow. I couldn't locate any alternative test files within the repository to cover these scenarios, so please confirm whether these tests have been migrated to TestRail. If so, add a header comment in apps/portal-e2e/src/registration/hacker/index.spec.ts that details:

  • Why these tests are disabled
  • Where the equivalent test cases now reside in TestRail
  • Whether these tests will be removed entirely in an upcoming PR
apps/portal/app/routes/registration.tsx (3)

17-18: Good addition of credentials for cross-origin authentication

The credentials: 'include' ensures cookies are properly sent with cross-origin requests, which is necessary for maintaining authentication state.


32-34: New user validation enhances registration flow.

This check ensures users complete all required steps in the correct order by redirecting those who haven't agreed to terms. Consider adding a query parameter to the redirect to inform the user why they're being redirected for a better user experience.

- return redirect('/')
+ return redirect('/?missingStep=terms')

36-38: Appropriate validation for emergency contact.

This check properly ensures users provide emergency contact information before proceeding with registration. Similar to the above comment, consider adding context to the redirect for improved UX.

- return redirect('/')
+ return redirect('/?missingStep=emergencyContact')
libs/portal/features/registration/ui/registration.tsx (1)

109-111: Improved visual feedback for button states

The dynamic className addition enhances UX by visually indicating when the form button is disabled. This aligns with the button's functional state controlled by the disabled attribute.

apps/portal-e2e/playwright.config.ts (2)

11-11: Inverted CI environment condition for baseURL.

The condition has been inverted from the previous implementation. Before, it used LOCAL_URL in CI and PUBLIC_URL otherwise. Now it's using LOCAL_URL when NOT in CI.

Verify this is intentional. If accidental, correct the condition:

-const baseURL = !process.env.CI ? process.env.CUHACKING_2025_PORTAL_LOCAL_URL : process.env.CUHACKING_2025_PORTAL_PUBLIC_URL
+const baseURL = process.env.CI ? process.env.CUHACKING_2025_PORTAL_PUBLIC_URL : process.env.CUHACKING_2025_PORTAL_LOCAL_URL

Also, add fallback URLs:

-const baseURL = !process.env.CI ? process.env.CUHACKING_2025_PORTAL_LOCAL_URL : process.env.CUHACKING_2025_PORTAL_PUBLIC_URL
+const baseURL = !process.env.CI 
+  ? process.env.CUHACKING_2025_PORTAL_LOCAL_URL || 'http://localhost:5173' 
+  : process.env.CUHACKING_2025_PORTAL_PUBLIC_URL || 'https://portal.cuhacking.ca'

15-16: Test parallelization explicitly disabled.

You've commented out dynamic parallelization based on CI and explicitly set fullyParallel: false. This will prevent tests from running in parallel in all environments, which could slow down test execution.

Is this intentional due to test interference issues? If so, consider adding a comment explaining why:

// fullyParallel: !process.env.CI,
-fullyParallel: false,
+// Disabling parallel test execution to prevent test interference issues with TestRail
+fullyParallel: false,
libs/portal/pages/profile/index.tsx (1)

6-40: Well-implemented toast notifications for form feedback.

Good addition of toast feedback for loading, success, and error states. This improves user experience by providing clear status indicators during profile operations.

apps/portal-e2e/src/index.spec.ts (3)

5-7: Imports appear correct

No issues with the import references.


34-35: Confirm post-login redirect handling

After signing in, we navigate to '/' and wait for an URL ending with /terms. Verify that the app indeed redirects from '/' to /terms and that no race conditions occur if the page load takes longer.


42-42: Potential redundancy in navigation

Navigate.to('/terms') might overlap with any existing redirect logic if the user is already directed to /terms after logging in. Confirm that this additional navigation is intended.

apps/portal-e2e/src/registration/hacker/abilities.ts (1)

3-5: No issues in imports

These references look correct.

apps/portal-e2e/src/profile/hacker/abilities.ts (3)

1-4: Imports are aligned

No concerns with the new imports or usage.


8-11: Ensure profile route is correct

startLoggedIn() followed by Navigate.to('/profile') appears valid. Confirm it aligns with your desired user flow.


66-66: Validate redirected path

Now the final route check ends with /registration instead of /dashboard. Confirm that’s intentional.

apps/portal-e2e/src/registration/questions.ts (2)

5-5: Improved aria labels for better accessibility.

The updated aria labels are more descriptive and follow a consistent kebab-case pattern, which aligns with accessibility best practices. Make sure these match the exact labels used in the actual UI components for reliable test selectors.

Also applies to: 12-12, 19-19


28-28:

✅ Verification successful

Verify field name change compatibility.

The text area name has been changed from 'adviceForFirstTimers' to 'first-time-hacker'. While this follows the kebab-case convention used in other changes, ensure this name matches exactly what's used in the form implementation to prevent test failures.


🏁 Script executed:

#!/bin/bash
# Search for the corresponding form field in the codebase
echo "Checking for first-time-hacker field usage in the codebase:"
rg -l "first-time-hacker" --type tsx --type jsx

Length of output: 204


Field Name Update: Verify Compatibility
The text area field now uses 'first-time-hacker' instead of 'adviceForFirstTimers' to follow the kebab-case convention. Please manually confirm that the form implementation is updated accordingly and that no stale references to the old field name remain, which could lead to test failures.

  • Ensure the form component is using 'first-time-hacker'.
  • Check for any lingering mentions of 'adviceForFirstTimers' and update them if necessary.

🏁 Script executed:

#!/bin/bash
# Check usage of the "first-time-hacker" field across source files (ts, tsx, js, and jsx)
echo "Checking for 'first-time-hacker' field usage across source files:"
rg -l "first-time-hacker" --glob "*.{ts,tsx,js,jsx}"

Length of output: 488


Field Name Compatibility Verified

The updated text area field now correctly uses 'first-time-hacker'. Our search confirms its usage across the codebase in:

  • libs/portal/features/registration/ui/registration.tsx
  • libs/portal/features/registration/hooks/use-registration-schema.ts
  • apps/portal-e2e/src/registration/questions.ts

Please double-check that there are no remaining references to the old field name 'adviceForFirstTimers' elsewhere in the application to avoid potential test failures.

Comment on lines +1 to +37
// import { startLoggedIn } from '@cuhacking/portal-e2e/abilities'
// import { actorCalled } from '@serenity-js/core'
// import { beforeEach, describe, it } from '@serenity-js/playwright-test'
// import { BrowseTheWeb, Navigate } from '@serenity-js/web'
// import { createInvalidProfile, createProfile, createProfileNoSchool } from './abilities'

export function startLoggedInNoProfile() {
return Task.where(
'#actor starts logged out',
Navigate.to('/profile'),
)
}
// describe('when the hacker', () => {
// beforeEach(async ({ actor }) => {
// actorCalled('Hacker')
// .whoCan(BrowseTheWeb.as(actor))
// .attemptsTo(startLoggedIn(), Navigate.to('/profile'))
// })

describe('when the hacker', () => {
beforeEach(async ({ actor }) => {
actorCalled('Hacker')
.whoCan(BrowseTheWeb.as(actor))
.attemptsTo(startLoggedInNoProfile(),
)
})
describe('is logged in', () => {
describe('has agreed to all terms and conditions', () => {
// ==============================
// ========= NO PROFILE =========
// ==============================
describe('has no profile', () => {
describe('is a student', () => {
it('should be able to create profile', async () => {
await createProfile()
})
// describe('is logged in', () => {
// describe('has agreed to all terms and conditions', () => {
// // ==============================
// // ========= NO PROFILE =========
// // ==============================
// describe('has no profile', () => {
// describe('is a student', () => {
// it('should be able to create profile', async () => {
// await createProfile()
// })

it('should not be able to create profile when fields are invalid', async () => {
await createInvalidProfile()
})
})
describe('is not a student', () => {
it('should be able to create profile', async () => {
await createProfileNoSchool()
})
})
})

// ==============================
// ========= HAS PROFILE =========
// ==============================
describe('has profile', () => {
describe('is a student', () => {
it('should be able to update profile', async () => {
// await updateProfile()
})

it('should not be able to create profile when fields are invalid', async () => {
// updateInvalidProfile(),
})
})
describe('is not a student', () => {
it('should be able to create profile', async () => {
// await updateProfileNoSchool()
})
})
})
})
})
})
// it('should not be able to create profile when fields are invalid', async () => {
// await createInvalidProfile()
// })
// })
// describe('is not a student', () => {
// it('should be able to create profile', async () => {
// await createProfileNoSchool()
// })
// })
// })
// })
// })
// })
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Commented-out tests reduce test coverage

Removing these profile tests without replacement reduces the overall test coverage. Is this temporary or intentional? Consider using test.skip() instead of commenting out if these tests need to be temporarily disabled, or document the reason for removal.

If this is part of migrating to TestRail as mentioned in the PR objectives, ensure equivalent test coverage exists in the new system before removing these tests.

Comment on lines +6 to +7
const EMAIL_ADDRESS = process.env.LOCAL_DEV_EMAIL_ADDRESS || ''
const PASSWORD = process.env.LOCAL_DEV_PASSWORD || ''
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Environment variables should have meaningful defaults

Empty string defaults for credentials could lead to silent test failures if environment variables aren't properly configured. Consider using placeholder values that would trigger obvious failures or throw an error if these values aren't provided.

- const EMAIL_ADDRESS = process.env.LOCAL_DEV_EMAIL_ADDRESS || ''
- const PASSWORD = process.env.LOCAL_DEV_PASSWORD || ''
+ const EMAIL_ADDRESS = process.env.LOCAL_DEV_EMAIL_ADDRESS || (() => { throw new Error('LOCAL_DEV_EMAIL_ADDRESS must be set') })()
+ const PASSWORD = process.env.LOCAL_DEV_PASSWORD || (() => { throw new Error('LOCAL_DEV_PASSWORD must be set') })()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const EMAIL_ADDRESS = process.env.LOCAL_DEV_EMAIL_ADDRESS || ''
const PASSWORD = process.env.LOCAL_DEV_PASSWORD || ''
const EMAIL_ADDRESS = process.env.LOCAL_DEV_EMAIL_ADDRESS || (() => { throw new Error('LOCAL_DEV_EMAIL_ADDRESS must be set') })()
const PASSWORD = process.env.LOCAL_DEV_PASSWORD || (() => { throw new Error('LOCAL_DEV_PASSWORD must be set') })()

Comment on lines +9 to +23
export function startLoggedIn() {
return Task.where(
'#actor starts logged in',
Navigate.to('/'),
Click.on(PageElement.located(By.cssContainingText('button', 'LOG IN'))),
Wait.upTo(Duration.ofSeconds(10))
.until(PageElement.located(By.css('#username')), isVisible()),
Enter.theValue(EMAIL_ADDRESS)
.into(PageElement.located(By.css('#username'))),
Enter.theValue(PASSWORD)
.into(PageElement.located(By.css('#password'))),
Click.on(PageElement.located(By.cssContainingText('button', 'Sign in'))),
Wait.until(Page.current().url().href, matches(/\/(dashboard|terms|profile|registration)$/)),
)
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Well-structured login automation for E2E tests

This login implementation is a good abstraction for reuse across test suites. A few suggestions for enhancement:

  1. Consider extracting selectors to constants at the top of the file for easier maintenance
  2. Add more descriptive step names for better test reporting
  3. Add error handling for common login failures
+ // Selectors for login elements
+ const LOGIN_BUTTON = By.cssContainingText('button', 'LOG IN')
+ const USERNAME_FIELD = By.css('#username')
+ const PASSWORD_FIELD = By.css('#password')
+ const SIGN_IN_BUTTON = By.cssContainingText('button', 'Sign in')

export function startLoggedIn() {
  return Task.where(
-   '#actor starts logged in',
+   '#actor logs in with credentials',
    Navigate.to('/'),
-   Click.on(PageElement.located(By.cssContainingText('button', 'LOG IN'))),
+   Click.on(PageElement.located(LOGIN_BUTTON)).describedAs('click login button'),
    Wait.upTo(Duration.ofSeconds(10))
-     .until(PageElement.located(By.css('#username')), isVisible()),
+     .until(PageElement.located(USERNAME_FIELD), isVisible()).describedAs('wait for username field'),
-   Enter.theValue(EMAIL_ADDRESS)
-     .into(PageElement.located(By.css('#username'))),
+   Enter.theValue(EMAIL_ADDRESS)
+     .into(PageElement.located(USERNAME_FIELD)).describedAs('enter email'),
-   Enter.theValue(PASSWORD)
-     .into(PageElement.located(By.css('#password'))),
+   Enter.theValue(PASSWORD)
+     .into(PageElement.located(PASSWORD_FIELD)).describedAs('enter password'),
-   Click.on(PageElement.located(By.cssContainingText('button', 'Sign in'))),
+   Click.on(PageElement.located(SIGN_IN_BUTTON)).describedAs('click sign in'),
    Wait.until(Page.current().url().href, matches(/\/(dashboard|terms|profile|registration)$/)),
  )
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function startLoggedIn() {
return Task.where(
'#actor starts logged in',
Navigate.to('/'),
Click.on(PageElement.located(By.cssContainingText('button', 'LOG IN'))),
Wait.upTo(Duration.ofSeconds(10))
.until(PageElement.located(By.css('#username')), isVisible()),
Enter.theValue(EMAIL_ADDRESS)
.into(PageElement.located(By.css('#username'))),
Enter.theValue(PASSWORD)
.into(PageElement.located(By.css('#password'))),
Click.on(PageElement.located(By.cssContainingText('button', 'Sign in'))),
Wait.until(Page.current().url().href, matches(/\/(dashboard|terms|profile|registration)$/)),
)
}
// Selectors for login elements
const LOGIN_BUTTON = By.cssContainingText('button', 'LOG IN')
const USERNAME_FIELD = By.css('#username')
const PASSWORD_FIELD = By.css('#password')
const SIGN_IN_BUTTON = By.cssContainingText('button', 'Sign in')
export function startLoggedIn() {
return Task.where(
'#actor logs in with credentials',
Navigate.to('/'),
Click.on(PageElement.located(LOGIN_BUTTON)).describedAs('click login button'),
Wait.upTo(Duration.ofSeconds(10))
.until(PageElement.located(USERNAME_FIELD), isVisible()).describedAs('wait for username field'),
Enter.theValue(EMAIL_ADDRESS)
.into(PageElement.located(USERNAME_FIELD)).describedAs('enter email'),
Enter.theValue(PASSWORD)
.into(PageElement.located(PASSWORD_FIELD)).describedAs('enter password'),
Click.on(PageElement.located(SIGN_IN_BUTTON)).describedAs('click sign in'),
Wait.until(Page.current().url().href, matches(/\/(dashboard|terms|profile|registration)$/)),
)
}

Comment on lines +75 to +80
By.xpath('//*[text()=\'I am at least 18 years of age.\']'),
),
),
Wait.until(PageElement.located(By.css('button[role="checkbox"]')), isVisible()),
Click.on(
PageElement.located(
By.css('button[role="checkbox"][aria-checked="false"]'),
By.xpath('//*[text()=\'I have read cuHacking Terms & Conditions\']'),
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Fragile text-based selectors

Using text-based XPath selectors can break if the message changes. Consider using data-test attributes or more stable locators.

Comment on lines +91 to +93
it('should be able to register for the hackathon', async ({ actor }) => {
await registerForHackathon({ actor })
})
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Add assertion for hackathon registration

After registerForHackathon, confirm the user sees a success message or the expected route.

 it('should be able to register for the hackathon', async ({ actor }) => {
   await registerForHackathon({ actor })
+  // e.g. Ensure relevant element or page shows success
 })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
it('should be able to register for the hackathon', async ({ actor }) => {
await registerForHackathon({ actor })
})
it('should be able to register for the hackathon', async ({ actor }) => {
await registerForHackathon({ actor })
// e.g. Ensure relevant element or page shows success
})

Comment on lines +7 to +13
export async function registerForHackathon({ actor }) {
const words = `I would tell a first time hacker that they should be freeeeeee!
Like that one song about being free.
I\'m trying to get to 50 words right now haha. So how was your day?`
await actorCalled('Hacker').attemptsTo(
startLoggedIn(),
Navigate.to('/registration'),
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Use the provided actor argument

Instead of actorCalled('Hacker'), reuse the function parameter { actor }. Keeps logic consistent with createProfile.

-export async function registerForHackathon({ actor }) {
-  await actorCalled('Hacker').attemptsTo(
+export async function registerForHackathon({ actor }) {
+  await actor.attemptsTo(
    startLoggedIn(),
    Navigate.to('/registration'),
    ...
  )
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export async function registerForHackathon({ actor }) {
const words = `I would tell a first time hacker that they should be freeeeeee!
Like that one song about being free.
I\'m trying to get to 50 words right now haha. So how was your day?`
await actorCalled('Hacker').attemptsTo(
startLoggedIn(),
Navigate.to('/registration'),
export async function registerForHackathon({ actor }) {
const words = `I would tell a first time hacker that they should be freeeeeee!
Like that one song about being free.
I'm trying to get to 50 words right now haha. So how was your day?`
await actor.attemptsTo(
startLoggedIn(),
Navigate.to('/registration'),
...
)
}

@MFarabi619 MFarabi619 merged commit af1e71e into main Mar 13, 2025
4 of 5 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.

3 participants