Skip to content

Refactor useChatWebhook hook for improved WebSocket connection management and error handling - #208

Merged
kiranharidas187 merged 6 commits into
ELEVATE-Project:release-1.0.4from
VishnuKrishnathu:feature/ip-socket
Dec 9, 2025
Merged

Refactor useChatWebhook hook for improved WebSocket connection management and error handling#208
kiranharidas187 merged 6 commits into
ELEVATE-Project:release-1.0.4from
VishnuKrishnathu:feature/ip-socket

Conversation

@VishnuKrishnathu

@VishnuKrishnathu VishnuKrishnathu commented Dec 8, 2025

Copy link
Copy Markdown

and error handling

Summary by CodeRabbit

  • New Features

    • Automatic WebSocket reconnection with message queuing: Chat connection now automatically reconnects when interrupted, queuing messages during connection attempts for a seamless experience.
    • Enhanced chat session management with improved history tracking and persistence.
  • Tests

    • Added comprehensive end-to-end test coverage across all chat flows to ensure consistent reliability and quality.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Dec 8, 2025

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This PR enhances WebSocket lifecycle management with reconnection logic and message queueing in useChatWebhook, exposes getChatHistory from the chat store, and integrates these improvements into the voice chat component. It also establishes comprehensive test infrastructure including Playwright E2E tests, page objects, fixtures, and helper utilities for multiple conversation flows. Configuration files are updated and jsconfig.json is removed.

Changes

Cohort / File(s) Summary
WebSocket & Hook Infrastructure
src/hooks/useChatWebhook.js, src/hooks/useSmartChatStorage.js, src/store/slices/chatData/state.js
Added robust WebSocket lifecycle with reconnection logic, message queueing, and autoConnect option to useChatWebhook. Exposed getChatHistory getter from chat store and extended useSmartChatStorage return tuple to include it.
Voice Chat Integration
src/pages/ShikshalokamVoiceChat/voice-chat.js
Integrated new hook capabilities with WebSocket close/error/reconnection handlers, manual connection control, and authentication flow that reads chat history before sending initial payload.
Configuration
.gitignore, jsconfig.json (removed), tsconfig.json
Added Playwright artifact patterns to .gitignore; removed jsconfig.json; added comprehensive TypeScript configuration with ES2022 target, strict mode, and Playwright test types.
Test Configuration & Constants
tests/config/test-constants.ts, tests/constant/site_routes.ts, tests/constant/guest-chat.ts, tests/constant/improvement-story-chat.ts, tests/constant/ptm-chat.ts, tests/constant/ylc-chat.ts
Centralized test configuration with timeouts, selectors, fixtures, API endpoints, and environment settings. Added route and conversation constants for guest, improvement-story, PTM, and YLC flows.
Test Fixtures & Data
tests/fixtures/browser.fixture.ts, tests/fixtures/test-data.ts, tests/fixtures/index.ts, tests/fixtures/images/README.md
Created browser fixture with CDP debug support, comprehensive test data structures with flow configs and scenario catalogs, fixture aggregation index, and image fixture documentation.
Test Helpers
tests/helpers/image.helper.ts, tests/helpers/story.helper.ts, tests/helpers/websocket.helper.ts
Added utility classes for image handling (existence, validation, upload), story analysis (metadata, content validation, quality checks), and WebSocket testing (message interception, connection state).
Page Objects
tests/pages/base.page.ts, tests/pages/flow-selection.page.ts, tests/pages/language-selection.page.ts, tests/pages/chat-interface.page.ts, tests/pages/chat-interface-ptm.ts, tests/pages/story-view.page.ts
Established comprehensive Playwright page object layer with base utilities (navigation, waits, clicks, text retrieval) and specialized page objects for flow/language selection, chat interface, PTM variant, and story view interactions.
E2E Test Specs
tests/e2e/flows/capture-discussion/happy-path.spec.ts, tests/e2e/flows/improvement-story/happy-path.spec.ts, tests/e2e/flows/ptm/happy-path.spec.ts, tests/e2e/flows/ylc/happy-path.spec.ts
Added happy-path E2E test suites for guest chat, improvement-story, PTM, and YLC flows covering language selection, flow navigation, chat interaction, image upload/removal, story editing, and report download workflows.

Sequence Diagram

sequenceDiagram
    participant React Hook as useChatWebhook
    participant Queue as Message Queue
    participant WebSocket as WebSocket Connection
    participant App as Voice Chat App
    
    rect rgb(200, 220, 255)
    note over React Hook,App: Initial Connection & Auth Flow
    App->>React Hook: Call sendMessage (first user message)
    React Hook->>Queue: Queue message (socket CONNECTING)
    React Hook->>WebSocket: connect() if not connected
    WebSocket->>WebSocket: Initialize WebSocket
    end
    
    rect rgb(220, 250, 220)
    note over React Hook,App: Connection Established
    WebSocket-->>React Hook: onopen event
    React Hook->>Queue: Flush queued messages
    React Hook->>App: Call onOpen callback
    App->>App: Read chat history via getChatHistory
    App->>WebSocket: Send auth payload (if first message)
    end
    
    rect rgb(255, 240, 200)
    note over React Hook,WebSocket: Reconnection Flow (on error/close)
    WebSocket-->>React Hook: onerror/onclose event
    React Hook->>React Hook: Increment reconnectCount
    alt Attempts Remaining
        React Hook->>React Hook: Wait reconnectInterval
        React Hook->>WebSocket: Retry connect()
    else Attempts Exhausted
        React Hook->>App: Call onFinalReconnectAttempt
        App->>App: Show confirmation popup
        App->>App: Navigate/ResetChat
    end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Areas requiring extra attention:

  • src/hooks/useChatWebhook.js: Intricate reconnection state machine with queue management, timeout handling, and lifecycle coordination—verify edge cases (rapid reconnects, message ordering, cleanup on unmount).
  • src/pages/ShikshalokamVoiceChat/voice-chat.js: New authentication flow that depends on getChatHistory and manual connection control; validate integration with existing state and payload structure.
  • tests/helpers/websocket.helper.ts: WebSocket interception via page evaluation requires careful validation that message capture doesn't interfere with real WebSocket behavior.
  • tests/pages/chat-interface.page.ts: Comprehensive page object with many selectors and interaction paths; verify selector consistency across actual UI.

Possibly related PRs

Suggested reviewers

  • Vinod-V3

Poem

🐰 Hop hop, a WebSocket spring!
Messages queue, then take wing,
Reconnect with grace and might,
Tests now dance in Playwright's light!
Chat flows flow from start to end,
Let this pull request be thy friend! 🎪

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the primary change: refactoring the useChatWebhook hook for improved WebSocket connection management and error handling, which is the main focus of the PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

…stants, and page objects for improved test organization and maintainability. Enhance .gitignore to exclude Playwright reports and environment files.
…nnect functionality, final reconnect attempt callback, and message queuing for WebSocket connections. Update ShikshalokamVoiceChat component to utilize new features and improve WebSocket management.
…ated messages and updating dependency array in useEffect for better state management.
@VishnuKrishnathu

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Dec 9, 2025

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 9

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/pages/ShikshalokamVoiceChat/voice-chat.js (1)

642-667: Potential race condition: authentication sent before WebSocket connection is established.

connectToWebSocket() is called but sendSocketMessage() for authentication is called immediately after without awaiting the connection. If the connection isn't established yet, the auth message may be queued or lost depending on the hook implementation.

Additionally, this authentication logic duplicates what's in onWebSocketOpen, leading to potential double authentication.

Consider one of these approaches:

  1. Send authentication only in onWebSocketOpen callback (which fires when connection is ready)
  2. Or ensure the hook queues messages until connected

Looking at the useChatWebhook docstring provided, it appears messages are queued while connecting, but verify this handles the authentication message correctly. The duplication with onWebSocketOpen (lines 210-232) should be resolved to have a single source of truth for authentication.

 const chat_history = handleMessagesForUser(textMessage)
 if (chat_history.filter(chat => chat.source === "user").length == 1) {
   connectToWebSocket()
-  sendSocketMessage({
-    type: "authenticate",
-    sessionid: sessionId,
-    profileid: profileToUse,
-    projectid: projectIdStore || searchParams.get("projectId") || "",
-    taskid: searchParams.get("taskId") || taskId,
-    access_token: accessToken,
-    route: chatLanguage,
-    bot_route: getSessionRoute(),
-    flow_name: storageFlow,
-    address: {
-      ipCity,
-      ipState,
-      ipZipCode,
-    },
-  })
+  // Authentication will be handled in onWebSocketOpen callback
 }
🧹 Nitpick comments (37)
tests/constant/ylc-chat.ts (1)

1-21: Conversation data is valid but looks placeholder-like

Using repeated "Hello World" values is fine for now, but consider replacing with more realistic, varied utterances once the flow stabilizes so tests better reflect real usage and are easier to understand.

tsconfig.json (1)

1-24: TS config is reasonable; double‑check JS/alias needs

The config looks generally sane for Playwright + frontend (ES2022, node moduleResolution, types: ["node", "@playwright/test"], baseUrl: "src"). If you plan to:

  • Import JS files from TS tests, or
  • Rely on the commented path aliases,

you may later want to enable allowJs and/or uncomment the paths section to keep editor tooling and builds aligned.

tests/config/test-constants.ts (1)

1-211: Centralized test constants look coherent and consistent

The structure of TIMEOUTS, SELECTORS, FIXTURE_PATHS, ENV, and others is clear and will help keep e2e tests DRY. Default timeouts and paths line up with the new Playwright ignores (downloads/, screenshots/, videos/), so this should integrate cleanly.

Only optional future tweaks:

  • If you ever need non‑HTTP BASE_URLs, consider validating/normalizing it in one place.
  • Consider tying API_ENDPOINTS.WEBSOCKET to whatever URL shape useChatWebhook ultimately expects (e.g., prefixing with BASE_URL) in a helper, not necessarily here.

No blocking issues from this file.

tests/constant/guest-chat.ts (1)

1-14: Guest chat content is fine; consider fixing minor typo

The conversation data looks realistic and appropriate for e2e flows. There’s a small spelling issue in:

  • "Total particpants are 32, ..."

Consider correcting "particpants""participants" to keep test data tidy, especially if it’s ever surfaced in screenshots or demos.

tests/constant/ptm-chat.ts (1)

1-9: PTM conversation constant is OK but very placeholder‑ish

The repeated "Hello World" values will work for basic flow coverage. When the PTM flow stabilizes, consider updating this array to more representative PTM dialog so failures are easier to diagnose from logs/screenshots.

tests/e2e/flows/ptm/happy-path.spec.ts (1)

1-2: Remove commented import or document the reason.

The commented fixture import suggests either incomplete migration or uncertainty about the correct import path. If the direct Playwright import on Line 2 is correct, remove the commented line to avoid confusion.

-// import { test, expect } from '../../../fixtures';
 import { test, expect } from "@playwright/test"
tests/pages/chat-interface-ptm.ts (2)

14-16: Consider more resilient test selectors.

The locators rely on generic CSS classes (ul.div11.pb-6) and third-party library classes (.swal2-confirm.swal2-styled). These selectors can be brittle:

  • Generic class names like div11 and pb-6 (Tailwind utility) may change with UI refactoring
  • SweetAlert2 classes could change with library updates

Consider adding data-testid attributes to the application code for more stable, semantic selectors.


4-4: Class naming suggests PTM-specific but reused for YLC flow.

The class is named ChatInterfacePtm but is also used in the YLC happy-path test (see tests/e2e/flows/ylc/happy-path.spec.ts line 29: chatInterfaceYlcPage = new ChatInterfacePtm(page)). If the functionality is shared, consider renaming to a more generic name like ChatInterfaceForm or ChatInterfaceWithConfirm, or create separate classes if PTM and YLC have distinct behaviors.

tests/e2e/flows/ylc/happy-path.spec.ts (4)

1-2: Remove commented imports.

Similar to the PTM test, this file has a commented fixture import. Remove it to avoid confusion about the correct import path.

-// import { test, expect } from '../../../fixtures';
 import { test, expect } from "@playwright/test"

5-5: Remove unused commented import.

The commented import for GUEST_CHAT_CONVERSATION_EN is not used in this test. Remove it to keep the code clean.

-// import { GUEST_CHAT_CONVERSATION_EN } from 'tests/constant/guest-chat';
 import { SITE_ROUTES } from "../../../constant/site_routes"

17-17: Fix variable naming mismatch.

The variable chatInterfaceYlcPage is instantiated from ChatInterfacePtm class, creating confusion about whether this is YLC-specific or shared functionality. Either rename the variable to reflect the actual class or use a YLC-specific class if the behaviors differ.

-  let chatInterfaceYlcPage: ChatInterfacePtm
+  let chatInterfaceFormPage: ChatInterfacePtm  // Or create ChatInterfaceYlc if behaviors differ

59-59: Inconsistent wait time compared to PTM test.

This test uses a 10-second wait (line 59), while the PTM test uses 5 seconds for the same operation. Consider standardizing wait times across similar test flows or document why YLC requires longer waits.

tests/e2e/flows/improvement-story/happy-path.spec.ts (3)

1-2: Consider using the custom fixture instead of direct Playwright import.

The commented-out import from ../../../fixtures suggests the custom browser fixture was intended. Using the fixture would enable CDP debugging support when CHROME_DEBUG_PORT is set. If the fixture isn't needed, remove the commented line.

-// import { test, expect } from '../../../fixtures';
-import { test, expect } from "@playwright/test"
+import { test, expect } from "../../../fixtures"

71-77: Hardcoded 10-second wait may cause flaky or slow tests.

The fixed 10-second wait doesn't adapt to actual response times. Consider using waitForChatContainerCount or similar polling-based waits for all iterations. Also, the formula 2 * i + 3 is not self-documenting.

       for (let i = 0; i < IMPROVEMENT_STORY_CHAT_CONVERSATION_EN.length; i++) {
         await chatInterfacePage.sendMessage(IMPROVEMENT_STORY_CHAT_CONVERSATION_EN[i])
-        await chatInterfacePage.wait(10000)
-        if (i != GUEST_CHAT_CONVERSATION_EN.length - 1) {
-          await chatInterfacePage.waitForChatContainerCount(2 * i + 3, 20000)
+        // Each message creates 2 containers (user + bot), starting from 3 initial
+        const expectedContainers = 2 * (i + 1) + 1
+        if (i !== IMPROVEMENT_STORY_CHAT_CONVERSATION_EN.length - 1) {
+          await chatInterfacePage.waitForChatContainerCount(expectedContainers, 30000)
         }
       }

106-108: Empty test placeholder should be skipped or removed.

This test provides no coverage and could mislead coverage metrics. Mark it as skipped with a TODO or remove it until implemented.

-  test("should complete full flow with story generation and download using SSO", async () => {
-    await test.step("Redirect to Home Page from SSO Route", async () => {})
-  })
+  test.skip("should complete full flow with story generation and download using SSO", async () => {
+    // TODO: Implement SSO redirect flow test
+  })
tests/helpers/story.helper.ts (1)

121-126: Sentence extraction is naive regarding abbreviations.

The regex [.!?]+ will incorrectly split on abbreviations like "Dr.", "Mr.", "e.g.". For test validation purposes this may be acceptable, but worth noting if precise sentence counts are important.

tests/e2e/flows/capture-discussion/happy-path.spec.ts (3)

1-6: Significant code duplication with improvement-story/happy-path.spec.ts.

This test file shares ~90% of its structure with the improvement-story spec. Consider extracting common test steps into a shared helper or using Playwright's test parameterization to reduce maintenance burden.


71-77: Same hardcoded 10-second wait issue as noted in improvement-story spec.

Apply the same fix to use adaptive waits instead of fixed delays.


106-108: Empty SSO test should be skipped.

Same issue as improvement-story spec - mark as test.skip until implemented.

tests/pages/story-view.page.ts (1)

90-101: Path resolution is appropriate, but no file existence check.

The path resolution logic handles relative paths well. However, if the file doesn't exist, setInputFiles will fail with a less descriptive error. Consider adding a pre-check for better error messages in test failures.

tests/pages/language-selection.page.ts (1)

135-149: Consider replacing hardcoded waits with condition-based waiting.

The 500ms wait() calls are test smells that can lead to flaky tests. Consider waiting for a specific condition (e.g., button becoming enabled or a visual state change) instead.

 async completeLanguageSelection(languageName: string): Promise<void> {
   await this.selectLanguageByName(languageName);
-  await this.wait(500); // Brief wait for UI state update
+  // Wait for continue button to be enabled after selection
+  await this.page.waitForFunction(
+    () => !(document.querySelector('[data-testid="continue-button"]') as HTMLButtonElement)?.disabled,
+    { timeout: 5000 }
+  );
   await this.clickContinue();
 }

 async completeLanguageSelectionByIndex(index: number): Promise<void> {
   await this.selectLanguageByIndex(index);
-  await this.wait(500); // Brief wait for UI state update
+  await this.page.waitForFunction(
+    () => !(document.querySelector('[data-testid="continue-button"]') as HTMLButtonElement)?.disabled,
+    { timeout: 5000 }
+  );
   await this.clickContinue();
 }
tests/pages/flow-selection.page.ts (3)

25-32: Brittle CSS class selectors will break on styling changes.

The complex CSS class selectors for flowCards, languageContainer, and flowContinueButton are fragile. Prefer data-testid attributes for test stability.

-    this.flowCards = page.locator("span.flex.items-center.gap-3.px-3.justify-center.sm\\:py-4.py-3.rounded-2xl.cursor-pointer.w-full")
+    this.flowCards = page.locator('[data-testid="flow-card"]')
     this.continueButton = page.locator('[data-testid="continue-button"]')
-    this.imageContainer = page.locator(".custom-login-image").first()
-    this.languageContainer = page.locator("div.div14-lang")
-    this.flowContinueButton = page.locator("button.mt-0.px-16.py-2.rounded-xl.text-white.text-lg.font-medium.flex.items-center")
+    this.imageContainer = page.locator('[data-testid="login-image"]')
+    this.languageContainer = page.locator('[data-testid="language-container"]')
+    this.flowContinueButton = page.locator('[data-testid="flow-continue-button"]')

Coordinate with the frontend team to add these data-testid attributes to the corresponding elements.


42-45: Remove commented-out code.

The commented line should be removed to keep the codebase clean.

 async getLanguageCount(): Promise<number> {
-  // await this.waitForElement(this.languageContainer.first());
   return this.languageContainer.count()
 }

136-140: Replace hardcoded wait with condition-based waiting.

Same concern as in LanguageSelectionPage - the 500ms wait is a test smell.

tests/pages/chat-interface.page.ts (2)

35-52: Prefer data-testid attributes over complex CSS class selectors.

Several locators use fragile CSS class selectors that will break on styling changes. Consider adding data-testid attributes to the application code for test stability.

The following locators should use data-testid attributes:

  • chatContainer (line 36)
  • messageInput (line 37)
  • sendButton (line 38)
  • termsAndConditionsContainer (line 45)
  • termsAndConditionsButton (line 46)
  • uploadedImage (line 49)
  • reportButton (line 50)
  • editorSaveButton (line 51)

180-192: Silent error handling may hide timing issues.

The empty catch block swallows any error from the loading indicator wait, making test failures harder to diagnose. Consider logging the reason for falling back.

 async waitForBotResponse(timeout: number = 30000): Promise<void> {
   // Wait for loading indicator to appear and disappear
   try {
     await this.waitForElement(this.loadingIndicator, 5000);
     await this.waitForElementHidden(this.loadingIndicator, timeout);
   } catch {
     // If loading indicator doesn't appear, just wait for new message
+    console.debug('Loading indicator not found, waiting for bot message directly');
     await this.wait(1000);
   }
   
   // Wait for new bot message
   await this.waitForElement(this.botMessages.last(), timeout);
 }
src/pages/ShikshalokamVoiceChat/voice-chat.js (3)

202-208: Avoid logging sensitive data and use structured logging instead.

Console.log statements with event data could inadvertently log sensitive WebSocket payloads. Consider using a proper logging utility with appropriate log levels.

 const onWebSocketClose = useCallback(event => {
-  console.log("closed", event)
+  // Consider using a logging utility with debug level
 }, [])

 const onWebSocketError = useCallback(error => {
-  console.log("error", error)
+  // Consider using a logging utility with error level
 }, [])

828-831: Remove commented-out dead code.

Commented-out useEffect should be removed to maintain code cleanliness.

-// useEffect(() => {
-//   const chat_history = chatHistory.filter(chat => chat.source === "user").length > 1
-// }, [isFreshConnection, chatHistory])

1282-1291: Remove debug console.log statements before merging.

These debug logging statements should be removed or converted to conditional debug logging for production code.

-  console.log(
-    "unnarated messages",
-    sentences.filter(sent => !sent.isNarrated)
-  )
-  console.log({ strandStep, stateMachineLength })
   if (sentences.filter(sent => !sent.isNarrated).length > 0) return
tests/helpers/image.helper.ts (2)

41-48: getImageSize throws on non-existent files without explicit handling.

Unlike verifyImageExists, this method will throw if the file doesn't exist. Consider adding error handling or documenting this behavior in JSDoc.

 /**
  * Get image file size in bytes
  * @param imagePath - Path to the image file
  * @returns File size in bytes
+ * @throws Error if file does not exist
  */
 getImageSize(imagePath: string): number {
+  if (!this.verifyImageExists(imagePath)) {
+    throw new Error(`Image file not found: ${imagePath}`);
+  }
   const absolutePath = path.isAbsolute(imagePath) 
     ? imagePath 
     : path.resolve(process.cwd(), imagePath);
   
   const stats = fs.statSync(absolutePath);
   return stats.size;
 }

228-244: Add safety checks before deleting files in cleanupDownloads.

The method deletes all files in the specified directory. Consider adding safeguards to prevent accidental deletion of important files.

 cleanupDownloads(downloadDir: string = 'downloads'): void {
   const dir = path.resolve(process.cwd(), downloadDir);
   
+  // Safety check: only clean known test download directories
+  if (!dir.includes('downloads') && !dir.includes('test')) {
+    console.warn(`Refusing to clean directory that doesn't appear to be a test directory: ${dir}`);
+    return;
+  }
+
   if (fs.existsSync(dir)) {
     const files = fs.readdirSync(dir);
     files.forEach(file => {
       const filePath = path.join(dir, file);
-      if (fs.statSync(filePath).isFile()) {
+      // Only delete files, not subdirectories, and skip hidden files
+      if (fs.statSync(filePath).isFile() && !file.startsWith('.')) {
         fs.unlinkSync(filePath);
       }
     });
   }
 }
tests/helpers/websocket.helper.ts (4)

18-29: Remove unused messages state or wire it up

this.messages is initialized and reset (constructor, startMonitoring, clearMessages) but never actually read; all callers go through window.__wsMessages via getMessages. This is dead state and can confuse future maintainers.

You can either remove the field and the related assignments, or update getMessages to keep this.messages in sync and read from it instead of directly from the page.

-  private messages: WebSocketMessage[];
   private isMonitoring: boolean;
@@
   constructor(page: Page) {
     this.page = page;
-    this.messages = [];
     this.isMonitoring = false;
   }
@@
   async startMonitoring(): Promise<void> {
@@
-    this.isMonitoring = true;
-    this.messages = [];
+    this.isMonitoring = true;
@@
   async clearMessages(): Promise<void> {
     await this.page.evaluate(() => {
       (window as any).__wsMessages = [];
     });
-    this.messages = [];
   }

Also applies to: 221-226


42-55: Avoid clearing __wsMessages on every new WebSocket instance

Inside the overridden WebSocket constructor you reset window.__wsMessages = [] every time a new WebSocket is created. If the app reconnects or opens multiple sockets, previously captured messages are silently discarded, which can make debugging flaky flows harder.

Consider initializing __wsMessages once outside the constructor (or only when not already defined) and let explicit calls to clearMessages() control when history is reset.

-    await this.page.addInitScript(() => {
-      // Store original WebSocket
-      const OriginalWebSocket = window.WebSocket;
-
-      // Override WebSocket constructor
-      (window as any).WebSocket = function(url: string, protocols?: string | string[]) {
-        const ws = new OriginalWebSocket(url, protocols);
-        
-        // Store websocket reference for testing
-        (window as any).__wsInstance = ws;
-        (window as any).__wsMessages = [];
+    await this.page.addInitScript(() => {
+      // Store original WebSocket
+      const OriginalWebSocket = window.WebSocket;
+
+      // Initialize message store once
+      (window as any).__wsMessages = (window as any).__wsMessages || [];
+
+      // Override WebSocket constructor
+      (window as any).WebSocket = function (url: string, protocols?: string | string[]) {
+        const ws = new OriginalWebSocket(url, protocols);
+
+        // Store websocket reference for testing
+        (window as any).__wsInstance = ws;
@@
-        return ws;
-      };
+        return ws;
+      };
     });

174-197: Single-connection assumption in __wsInstance helpers

isConnected / getConnectionState work off a single window.__wsInstance, which is always set to the most recently constructed WebSocket. If the app ever uses multiple sockets concurrently, these helpers will not reflect earlier ones.

If multi-socket support becomes relevant, consider tracking an array of connections (with IDs or URLs) instead of a single __wsInstance, or at least document that these methods are specific to the last-created socket.


250-255: Clarify or implement stopMonitoring behavior

stopMonitoring() only flips isMonitoring; it does not:

  • restore the original window.WebSocket constructor, or
  • stop further messages being pushed into window.__wsMessages.

Given that other methods (getMessages, waitForMessage, etc.) don’t consult isMonitoring, calling stopMonitoring() has no real effect today.

Either wire stopMonitoring() to actually unpatch/disable capture, or drop the method to avoid implying behavior that isn’t there.

-  /**
-   * Stop monitoring WebSocket connections
-   */
-  stopMonitoring(): void {
-    this.isMonitoring = false;
-  }
+  /**
+   * Stop monitoring WebSocket connections.
+   * Note: currently this only flips the flag and does not restore the original WebSocket.
+   * Implement unpatching here if you need to truly disable capture.
+   */
+  stopMonitoring(): void {
+    this.isMonitoring = false;
+  }
tests/pages/base.page.ts (1)

36-44: Align waitForElement JSDoc with its actual signature

The comment says “Wait for a specific element to be visible” and documents only selector and timeout, but the method also exposes a state parameter with defaults, making it a general wait helper (attached/detached/visible/hidden).

To avoid confusion for callers, either:

  • update the JSDoc to describe the state parameter and the more general behavior, or
  • remove the state argument and keep this as a strict “visible-only” helper.
-  /**
-   * Wait for a specific element to be visible
-   * @param selector - CSS selector or locator
-   * @param timeout - Optional timeout in milliseconds
-   */
+  /**
+   * Wait for a specific element state.
+   * @param selector - CSS selector or locator
+   * @param timeout - Optional timeout in milliseconds
+   * @param state - Desired state ("attached" | "detached" | "visible" | "hidden"), defaults to "visible"
+   */
   async waitForElement(selector: string | Locator, timeout: number = 10000, state: "attached" | "detached" | "visible" | "hidden" | undefined = "visible"): Promise<void> {
tests/fixtures/test-data.ts (1)

303-318: Consider making randomness deterministic for test runs

getRandomResponse and generateRandomUserData rely on Math.random(), which makes tests that use them non-deterministic and occasionally harder to debug/reproduce.

If these helpers are used in assertions (rather than just setup noise), consider:

  • injecting a seeded PRNG from the tests, or
  • allowing tests to pass in specific values instead of picking randomly.

That keeps fixtures flexible while preserving repeatability.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7b476bc and 41b27c9.

⛔ Files ignored due to path filters (1)
  • tests/static/sample_image.png is excluded by !**/*.png
📒 Files selected for processing (30)
  • .gitignore (1 hunks)
  • jsconfig.json (0 hunks)
  • src/hooks/useChatWebhook.js (1 hunks)
  • src/hooks/useSmartChatStorage.js (1 hunks)
  • src/pages/ShikshalokamVoiceChat/voice-chat.js (7 hunks)
  • src/store/slices/chatData/state.js (1 hunks)
  • tests/config/test-constants.ts (1 hunks)
  • tests/constant/guest-chat.ts (1 hunks)
  • tests/constant/improvement-story-chat.ts (1 hunks)
  • tests/constant/ptm-chat.ts (1 hunks)
  • tests/constant/site_routes.ts (1 hunks)
  • tests/constant/ylc-chat.ts (1 hunks)
  • tests/e2e/flows/capture-discussion/happy-path.spec.ts (1 hunks)
  • tests/e2e/flows/improvement-story/happy-path.spec.ts (1 hunks)
  • tests/e2e/flows/ptm/happy-path.spec.ts (1 hunks)
  • tests/e2e/flows/ylc/happy-path.spec.ts (1 hunks)
  • tests/fixtures/browser.fixture.ts (1 hunks)
  • tests/fixtures/images/README.md (1 hunks)
  • tests/fixtures/index.ts (1 hunks)
  • tests/fixtures/test-data.ts (1 hunks)
  • tests/helpers/image.helper.ts (1 hunks)
  • tests/helpers/story.helper.ts (1 hunks)
  • tests/helpers/websocket.helper.ts (1 hunks)
  • tests/pages/base.page.ts (1 hunks)
  • tests/pages/chat-interface-ptm.ts (1 hunks)
  • tests/pages/chat-interface.page.ts (1 hunks)
  • tests/pages/flow-selection.page.ts (1 hunks)
  • tests/pages/language-selection.page.ts (1 hunks)
  • tests/pages/story-view.page.ts (1 hunks)
  • tsconfig.json (1 hunks)
💤 Files with no reviewable changes (1)
  • jsconfig.json
🧰 Additional context used
🧬 Code graph analysis (11)
tests/pages/chat-interface-ptm.ts (1)
tests/pages/base.page.ts (1)
  • BasePage (7-205)
tests/e2e/flows/capture-discussion/happy-path.spec.ts (5)
tests/fixtures/browser.fixture.ts (2)
  • test (29-67)
  • expect (69-69)
tests/pages/flow-selection.page.ts (1)
  • FlowSelectionPage (9-141)
tests/pages/chat-interface.page.ts (1)
  • ChatInterfacePage (9-347)
tests/constant/site_routes.ts (1)
  • SITE_ROUTES (1-9)
tests/constant/guest-chat.ts (1)
  • GUEST_CHAT_CONVERSATION_EN (1-14)
tests/pages/story-view.page.ts (1)
tests/pages/base.page.ts (1)
  • BasePage (7-205)
tests/pages/language-selection.page.ts (1)
tests/pages/base.page.ts (1)
  • BasePage (7-205)
tests/pages/chat-interface.page.ts (2)
tests/pages/base.page.ts (1)
  • BasePage (7-205)
server.js (1)
  • path (2-2)
tests/pages/flow-selection.page.ts (2)
tests/pages/base.page.ts (1)
  • BasePage (7-205)
tests/constant/site_routes.ts (1)
  • SITE_ROUTES (1-9)
tests/e2e/flows/improvement-story/happy-path.spec.ts (4)
tests/pages/flow-selection.page.ts (1)
  • FlowSelectionPage (9-141)
tests/pages/chat-interface.page.ts (1)
  • ChatInterfacePage (9-347)
tests/constant/site_routes.ts (1)
  • SITE_ROUTES (1-9)
tests/constant/improvement-story-chat.ts (1)
  • IMPROVEMENT_STORY_CHAT_CONVERSATION_EN (1-16)
tests/e2e/flows/ylc/happy-path.spec.ts (4)
tests/pages/flow-selection.page.ts (1)
  • FlowSelectionPage (9-141)
tests/pages/chat-interface.page.ts (1)
  • ChatInterfacePage (9-347)
tests/constant/site_routes.ts (1)
  • SITE_ROUTES (1-9)
tests/constant/ylc-chat.ts (1)
  • YLC_CHAT_CONVERSATION_EN (1-21)
src/pages/ShikshalokamVoiceChat/voice-chat.js (3)
src/hooks/useSmartChatStorage.js (2)
  • chatHistory (4-4)
  • useSmartChatStorage (3-12)
src/services/storage_service.js (1)
  • clearFromStorage (109-122)
src/hooks/useChatWebhook.js (2)
  • useChatWebhook (3-119)
  • useChatWebhook (3-119)
src/hooks/useSmartChatStorage.js (1)
src/pages/ShikshalokamVoiceChat/voice-chat.js (3)
  • chatHistory (136-136)
  • useChatStorage (177-177)
  • useChatStorage (181-181)
src/hooks/useChatWebhook.js (2)
src/utils/index.js (1)
  • url (5-5)
src/pages/ShikshalokamVoiceChat/voice-chat.js (2)
  • onFinalReconnectAttempt (191-200)
  • error (81-81)
🪛 Biome (2.1.2)
tests/fixtures/browser.fixture.ts

[error] 35-35: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

🔇 Additional comments (20)
.gitignore (1)

25-30: Playwright artifacts and .env ignore look good

Ignoring .env and Playwright output directories (downloads/, test-results/, playwright-report/) is appropriate and keeps the repo clean. No changes needed.

src/store/slices/chatData/state.js (1)

29-29: getChatHistory addition matches existing slice patterns

The new getChatHistory mirrors other getters in this slice (getIntroMessage, getFlow, etc.) and should be safe to consume from hooks like useSmartChatStorage. Looks good.

src/hooks/useChatWebhook.js (1)

44-62: Fix sendMessage null-check/return value and guard reconnection on unmount/disconnect

Unable to access the repository to verify the code as described. The review comment identifies two significant issues—a potential null-dereference in sendMessage (lines 77–85) and unguarded reconnection logic after unmount or explicit disconnect (lines 44–62, 68–75, 98–104)—with concrete diffs provided. Manual verification against the actual codebase is required to confirm whether these issues exist in the current version and whether the proposed fixes are complete and correct.

tests/fixtures/images/README.md (1)

1-46: LGTM! Well-documented test fixtures.

The README provides clear guidance on test image usage, generation methods, and technical requirements. The documentation aligns well with the broader test infrastructure introduced in this PR.

tests/fixtures/index.ts (1)

1-21: LGTM! Clean fixture organization.

The central export point provides a clear single import location for test fixtures and utilities, with helpful documentation for usage patterns.

tests/constant/site_routes.ts (1)

1-9: LGTM! Clean route constant organization.

The route constants provide a centralized, maintainable way to reference application paths across test suites.

tests/e2e/flows/ptm/happy-path.spec.ts (1)

7-7: Verify PTM test conversation data quality.

The constant PTM_CHAT_CONVERSATION_EN imported from tests/constant/ptm-chat.ts should be examined to ensure it contains realistic test data. If the conversation data consists only of placeholder strings, consider enhancing it with varied, realistic user inputs and edge cases to better exercise the PTM conversation flow during testing.

tests/e2e/flows/ylc/happy-path.spec.ts (2)

8-8: Verify YLC test conversation data quality.

The YLC_CHAT_CONVERSATION_EN constant should contain realistic test inputs that adequately cover the YLC conversation flow, similar to how test data for other conversation flows should be structured. Inspect tests/constant/ylc-chat.ts to confirm the constant includes appropriate test coverage rather than placeholder data.


68-68: Verify test image file exists.

The test references sample_image.png from a static folder. Ensure this file exists at the expected path relative to the test file.

src/hooks/useSmartChatStorage.js (1)

11-11: Breaking change: Verify all consumers handle the new return signature.

The return tuple has been extended from 3 to 4 elements by adding getChatHistory. Any existing code that destructures this hook with only 3 elements will still work (JavaScript ignores extra elements), but consumers expecting exactly 3 elements or using array indices might need updates.

#!/bin/bash
# Description: Find all usages of useSmartChatStorage to verify they handle the new 4-element return

# Search for all imports and usage of useSmartChatStorage
rg -n "useSmartChatStorage" --type=js --type=jsx -C 3
tests/fixtures/browser.fixture.ts (1)

42-57: Context reuse may affect test isolation.

Reusing an existing context means state (cookies, storage) persists between tests when debugging via CDP. This is intentional for debugging but worth noting in comments for clarity.

tests/helpers/story.helper.ts (2)

6-13: Well-defined interface for story metadata.

The StoryMetadata interface captures all relevant story properties. The optional createdAt field appropriately handles cases where creation timestamp may not be available.


161-179: Polling implementation looks good.

The polling approach with configurable timeout and minimum word threshold is appropriate for waiting on async story generation. The 1-second interval balances responsiveness with resource efficiency.

tests/pages/story-view.page.ts (2)

9-42: Well-structured page object with consistent data-testid selectors.

Good use of data-testid attributes for element selection, which provides maintainable and reliable selectors. The locator initialization follows the established pattern from other page objects.


174-181: Correct reverse iteration to avoid index shifting.

Removing images from last to first prevents index shifting issues during sequential removal. Good defensive implementation.

tests/pages/language-selection.page.ts (1)

1-27: Well-structured page object with good locator organization.

The class correctly extends BasePage and initializes locators in the constructor. Using data-testid attributes for locators is a best practice for test stability.

tests/pages/chat-interface.page.ts (1)

66-72: LGTM: File download and upload handling are well implemented.

The download and upload methods correctly handle file events and path construction.

Also applies to: 86-91

src/pages/ShikshalokamVoiceChat/voice-chat.js (1)

272-291: LGTM: WebSocket hook configuration with manual connection control.

The configuration with autoConnect: false and explicit callbacks provides good control over the WebSocket lifecycle. The destructured properties (sendMessage, connect, isFreshConnection) are well-named.

tests/helpers/image.helper.ts (2)

88-125: Creative approach to generating test images via browser canvas.

Using Playwright's page context to generate images ensures the test environment can create valid image data. Note that this requires the page to be navigated to a valid document first.


1-34: Well-designed utility methods for image validation in tests.

The helper provides comprehensive utilities for verifying image existence, extensions, DOM presence, and sources. Good separation of filesystem and DOM-based operations.

Also applies to: 67-79, 133-208

Comment on lines +191 to +200
const onFinalReconnectAttempt = useCallback(() => {
showConfirmationPopup(() => {
if (accessToken) {
clearFromStorage()
navigate(-1)
} else {
ResetChat()
}
})
}, [])

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Missing dependencies in useCallback for onFinalReconnectAttempt.

The callback references accessToken, navigate, and ResetChat but has an empty dependency array. This could cause stale closures.

 const onFinalReconnectAttempt = useCallback(() => {
   showConfirmationPopup(() => {
     if (accessToken) {
       clearFromStorage()
       navigate(-1)
     } else {
       ResetChat()
     }
   })
-}, [])
+}, [accessToken, navigate, showConfirmationPopup])

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/pages/ShikshalokamVoiceChat/voice-chat.js around lines 191 to 200, the
useCallback for onFinalReconnectAttempt has an empty dependency array but reads
accessToken, navigate, and ResetChat, which can create stale closures; update
the dependency array to include accessToken, navigate, and ResetChat (or wrap
ResetChat/navigate in stable callbacks if needed) so the callback is recreated
when those values change, and ensure any lint rules are satisfied.

Comment on lines +1 to +16
export const IMPROVEMENT_STORY_CHAT_CONVERSATION_EN = [
"Vishnu Krishnathu",
"Yes",
"PT Teacher at ST Thomas School",
"St Thomas High School",
"Village name is Kalyan in District Thane, in state Maharashtra, India",
"Children do not play any sports",
"No sports period in school",
"I wrote a letter to management and convinced all the teachers to have a sports period thrice a weak for children from all classes",
"No",
"No challenges faced",
"3 months",
"Pt sir Kunal helped me with convincing other teachers in school",
"No",
"No"
] No newline at end of file

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Replace realistic PII with clearly synthetic test data.

The test conversation includes what appears to be real personal information (name "Vishnu Krishnathu", specific school "ST Thomas School"/"St Thomas High School", and location "Kalyan in District Thane, Maharashtra, India"). Even in test code, using realistic PII can create privacy concerns and potential GDPR/compliance issues if the data resembles real individuals or institutions.

Use clearly fictional data instead:

 export const IMPROVEMENT_STORY_CHAT_CONVERSATION_EN = [
-    "Vishnu Krishnathu",
+    "Test User",
     "Yes",
-    "PT Teacher at ST Thomas School",
-    "St Thomas High School",
-    "Village name is Kalyan in District Thane, in state Maharashtra, India",
+    "PT Teacher at Test School",
+    "Test High School",
+    "Test Village in Test District, Test State, Test Country",
     "Children do not play any sports",
📝 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 const IMPROVEMENT_STORY_CHAT_CONVERSATION_EN = [
"Vishnu Krishnathu",
"Yes",
"PT Teacher at ST Thomas School",
"St Thomas High School",
"Village name is Kalyan in District Thane, in state Maharashtra, India",
"Children do not play any sports",
"No sports period in school",
"I wrote a letter to management and convinced all the teachers to have a sports period thrice a weak for children from all classes",
"No",
"No challenges faced",
"3 months",
"Pt sir Kunal helped me with convincing other teachers in school",
"No",
"No"
]
export const IMPROVEMENT_STORY_CHAT_CONVERSATION_EN = [
"Test User",
"Yes",
"PT Teacher at Test School",
"Test High School",
"Test Village in Test District, Test State, Test Country",
"Children do not play any sports",
"No sports period in school",
"I wrote a letter to management and convinced all the teachers to have a sports period thrice a weak for children from all classes",
"No",
"No challenges faced",
"3 months",
"Pt sir Kunal helped me with convincing other teachers in school",
"No",
"No"
]
🤖 Prompt for AI Agents
In tests/constant/improvement-story-chat.ts around lines 1-16, the conversation
array contains realistic PII (real name, school and location); replace those
entries with clearly synthetic test data. Change the name, school names, and
location string to obviously fictional values (e.g., "Test User", "Sample
Primary School", "Fictional Village, Fictional District, Fictional State") and
any other person references (e.g., "Pt sir Kunal") to synthetic placeholders so
the whole array contains no real-identifying information but preserves the same
semantic structure for tests.

Comment thread tests/e2e/flows/ptm/happy-path.spec.ts Outdated
for (let i = 0; i < PTM_CHAT_CONVERSATION_EN.length; i++) {
await chatInterfacePage.sendMessage(PTM_CHAT_CONVERSATION_EN[i])
await chatInterfacePage.wait(5000)
if (i != PTM_CHAT_CONVERSATION_EN.length - 1) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Use strict equality operator.

The condition uses non-strict equality (!=) instead of strict equality (!==), which can lead to unexpected type coercion bugs.

-        if (i != PTM_CHAT_CONVERSATION_EN.length - 1) {
+        if (i !== PTM_CHAT_CONVERSATION_EN.length - 1) {
📝 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 (i != PTM_CHAT_CONVERSATION_EN.length - 1) {
if (i !== PTM_CHAT_CONVERSATION_EN.length - 1) {
🤖 Prompt for AI Agents
In tests/e2e/flows/ptm/happy-path.spec.ts around line 60, the condition uses
non-strict inequality (i != PTM_CHAT_CONVERSATION_EN.length - 1); change it to
strict inequality (i !== PTM_CHAT_CONVERSATION_EN.length - 1) to prevent
type-coercion issues and ensure correct boolean evaluation.

Comment thread tests/e2e/flows/ylc/happy-path.spec.ts Outdated
for (let i = 0; i < YLC_CHAT_CONVERSATION_EN.length; i++) {
await chatInterfacePage.sendMessage(YLC_CHAT_CONVERSATION_EN[i])
await chatInterfacePage.wait(10000)
if (i != YLC_CHAT_CONVERSATION_EN.length - 1) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Use strict equality operator.

Use strict equality (!==) instead of loose equality (!=) to avoid type coercion issues.

-        if (i != YLC_CHAT_CONVERSATION_EN.length - 1) {
+        if (i !== YLC_CHAT_CONVERSATION_EN.length - 1) {
📝 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 (i != YLC_CHAT_CONVERSATION_EN.length - 1) {
if (i !== YLC_CHAT_CONVERSATION_EN.length - 1) {
🤖 Prompt for AI Agents
In tests/e2e/flows/ylc/happy-path.spec.ts around line 60, the condition uses the
loose inequality operator (`!=`); replace it with the strict inequality operator
(`!==`) to prevent type coercion issues—update the conditional to use `!==` and
run the test/linter to confirm no other occurrences remain.

Comment thread tests/fixtures/browser.fixture.ts Outdated
Comment on lines +35 to +40
browser: async ({ }, use) => {
// Connect to existing browser via CDP
const browser = await chromium.connectOverCDP(`http://localhost:${debugPort}`);
await use(browser);
// Don't close the browser as it's externally managed
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix empty object pattern flagged by static analysis.

The empty destructuring { } triggers a linting error. Use _ to indicate intentionally unused fixtures.

-      browser: async ({ }, use) => {
+      browser: async ({}, use) => {

Or if you need to explicitly show no dependencies:

-      browser: async ({ }, use) => {
+      browser: async (_, use) => {
📝 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
browser: async ({ }, use) => {
// Connect to existing browser via CDP
const browser = await chromium.connectOverCDP(`http://localhost:${debugPort}`);
await use(browser);
// Don't close the browser as it's externally managed
},
browser: async ({}, use) => {
// Connect to existing browser via CDP
const browser = await chromium.connectOverCDP(`http://localhost:${debugPort}`);
await use(browser);
// Don't close the browser as it's externally managed
},
🧰 Tools
🪛 Biome (2.1.2)

[error] 35-35: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

🤖 Prompt for AI Agents
In tests/fixtures/browser.fixture.ts around lines 35-40, the async fixture
parameter currently uses an empty destructuring "{ }", which triggers
lint/static-analysis errors; replace the empty pattern with an unused
placeholder name such as "_" or "_context" (optionally with an explicit type
like "_: any" or "_: unknown" if TypeScript types are required) so the signature
becomes e.g. "browser: async (_ , use) => { ... }", keeping the rest of the
function unchanged.

Comment on lines +142 to +147
async waitForReceivedMessageContaining(text: string, timeout: number = 30000): Promise<WebSocketMessage> {
return this.waitForMessage(
(msg) => msg.type === 'received' && msg.data.includes(text),
timeout
);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Guard against non-string data in waitForReceivedMessageContaining

msg.data.includes(text) assumes data is a string. In WebSocket APIs it can also be Blob/ArrayBuffer/views, which would throw here if used in future tests.

A small coercion keeps this helper safe without changing semantics for current string-based usage:

   async waitForReceivedMessageContaining(text: string, timeout: number = 30000): Promise<WebSocketMessage> {
     return this.waitForMessage(
-      (msg) => msg.type === 'received' && msg.data.includes(text),
+      (msg) =>
+        msg.type === 'received' &&
+        String(msg.data).includes(text),
       timeout
     );
   }
🤖 Prompt for AI Agents
In tests/helpers/websocket.helper.ts around lines 142–147, the predicate uses
msg.data.includes(text) which will throw if data isn’t a string
(Blob/ArrayBuffer/etc.); change it to coerce data to a string before checking,
e.g. replace msg.data.includes(text) with String(msg.data).includes(text) (or
assign const dataStr = String(msg.data) and use dataStr.includes(text)) so
non-string payloads are safely handled while preserving current string behavior.

Comment thread tests/pages/chat-interface.page.ts Outdated
Comment on lines +78 to +80
async openEditory(): Promise<void> {
await this.clickElement(this.reportButton.nth(1));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix typo in method name: openEditory should be openEditor.

-async openEditory(): Promise<void> {
+async openEditor(): Promise<void> {
   await this.clickElement(this.reportButton.nth(1));
 }
📝 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
async openEditory(): Promise<void> {
await this.clickElement(this.reportButton.nth(1));
}
async openEditor(): Promise<void> {
await this.clickElement(this.reportButton.nth(1));
}
🤖 Prompt for AI Agents
In tests/pages/chat-interface.page.ts around lines 78 to 80, the method name
openEditory is misspelled; rename the method to openEditor and update its
declaration to async openEditor(): Promise<void> { await
this.clickElement(this.reportButton.nth(1)); } then search and replace all
usages/imports/exports of openEditory across the codebase (tests and helpers) to
use openEditor to avoid reference breaks; keep the method signature and behavior
unchanged.

Comment on lines +111 to +118
/**
* Check if continue button is enabled
* @returns True if enabled, false otherwise
*/
async isContinueButtonEnabled(): Promise<boolean> {
const isDisabled = await this.continueButton.isDisabled()
return !isDisabled
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Locator mismatch: isContinueButtonEnabled checks a different button than clickContinue.

isContinueButtonEnabled() uses continueButton while clickContinue() uses flowContinueButton. This inconsistency will cause the enabled check to not reflect the actual button clicked.

 async isContinueButtonEnabled(): Promise<boolean> {
-  const isDisabled = await this.continueButton.isDisabled()
+  const isDisabled = await this.flowContinueButton.isDisabled()
   return !isDisabled
 }
📝 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
/**
* Check if continue button is enabled
* @returns True if enabled, false otherwise
*/
async isContinueButtonEnabled(): Promise<boolean> {
const isDisabled = await this.continueButton.isDisabled()
return !isDisabled
}
/**
* Check if continue button is enabled
* @returns True if enabled, false otherwise
*/
async isContinueButtonEnabled(): Promise<boolean> {
const isDisabled = await this.flowContinueButton.isDisabled()
return !isDisabled
}
🤖 Prompt for AI Agents
In tests/pages/flow-selection.page.ts around lines 111 to 118,
isContinueButtonEnabled currently checks this.continueButton while clickContinue
uses this.flowContinueButton, causing a mismatch; update isContinueButtonEnabled
to use the same locator as clickContinue (this.flowContinueButton) so the
enabled check reflects the actual button being clicked and return !await
this.flowContinueButton.isDisabled().

Comment on lines +214 to +228
async downloadStory(): Promise<void> {
await this.waitForElement(this.downloadButton);

// Set up download promise before clicking
const downloadPromise = this.page.waitForEvent('download', { timeout: 30000 });

await this.clickElement(this.downloadButton);

// Wait for download to start
const download = await downloadPromise;

// Optionally save the download
const downloadPath = path.join(process.cwd(), 'downloads', await download.suggestedFilename());
await download.saveAs(downloadPath);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for downloads directory creation and .gitignore entries
echo "=== Searching for mkdir/mkdirSync related to downloads ==="
rg -n "mkdir.*downloads|downloads.*mkdir" --type ts --type js --type json

echo ""
echo "=== Checking .gitignore for downloads ==="
if [ -f .gitignore ]; then
  rg "downloads" .gitignore
else
  echo ".gitignore not found"
fi

echo ""
echo "=== Searching for downloads directory references ==="
rg -n "downloads" --type ts -B 2 -A 2 | head -50

echo ""
echo "=== Looking for test setup/fixture files ==="
find . -type f \( -name "*.setup.ts" -o -name "*.fixture.ts" -o -name "*.before.ts" -o -name "playwright.config.ts" \) 2>/dev/null

Repository: ELEVATE-Project/mohini-app-frontend

Length of output: 214


🌐 Web query:

Playwright download.saveAs() directory creation behavior

💡 Result:

Short answer: download.saveAs(...) does not create missing parent directories — it copies the downloaded file to the exact path you provide and will error if the target directory doesn't exist. See Playwright's download.saveAs docs for the API and treat the path as a normal filesystem path. [1]

Workaround: create the parent directory first (e.g. Node.js):

  • fs.mkdirSync(path.dirname(targetPath), { recursive: true });
  • await download.saveAs(targetPath);

Example:
const fs = require('fs');
const path = require('path');

fs.mkdirSync(path.dirname(targetPath), { recursive: true });
await download.saveAs(targetPath);

References:

  • Playwright download.saveAs documentation. [1]
  • Node.js fs.mkdir / fs.mkdirSync (recursive option). [2]

Directory creation required before saving downloads.

The downloads directory must be created before calling saveAs(), as Playwright does not auto-create parent directories. Add fs.mkdirSync(path.dirname(downloadPath), { recursive: true }) before the saveAs() call, otherwise the test will fail at runtime.

🤖 Prompt for AI Agents
In tests/pages/story-view.page.ts around lines 214 to 228, the download saving
code assumes the downloads directory exists which causes saveAs() to fail;
before calling download.saveAs(...) create the parent directory (e.g. use
fs.mkdirSync(path.dirname(downloadPath), { recursive: true }) or equivalent
async mkdir) so the directory exists, then proceed to call saveAs to persist the
file.

… consistency by updating comparison operators. Refactor ChatInterfacePage for cleaner syntax and maintainability.
Comment thread src/hooks/useChatWebhook.js Outdated

ws.current.onopen = event => {
setIsConnected(true)
if (socketQueue.current.length > 0) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

just add socketQueue.current.length for true condition

@@ -133,7 +133,7 @@ const ShikshalokamVoiceBasedChat = ({ type = "", variant = "" }) => {
// const introMessageRef = useRef(null);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

remove shikshalokam, mohini etc names

clearFromStorage()
navigate(-1)
} else {
ResetChat()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

follow camelcase

}, [])

const onWebSocketOpen = useCallback(() => {
if (!ipFetched) return

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

recheck

[chatHistory]
)

// useEffect(() => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

rm

…and consistency. Refactor useChatWebhook and ShikshalokamVoiceChat components for better code readability and maintainability by renaming methods and optimizing WebSocket connection logic.
@kiranharidas187
kiranharidas187 merged commit 6283923 into ELEVATE-Project:release-1.0.4 Dec 9, 2025
1 check 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.

2 participants