Skip to content

Feature/apcfss fix - #259

Open
VishnuKrishnathu wants to merge 13 commits into
ELEVATE-Project:release-1.0.6from
VishnuKrishnathu:feature/apcfss-fix
Open

Feature/apcfss fix#259
VishnuKrishnathu wants to merge 13 commits into
ELEVATE-Project:release-1.0.6from
VishnuKrishnathu:feature/apcfss-fix

Conversation

@VishnuKrishnathu

@VishnuKrishnathu VishnuKrishnathu commented Mar 25, 2026

Copy link
Copy Markdown

Summary by CodeRabbit

  • Refactor

    • Improved internal state management for chat and creation flows, enhancing stability and consistency across screens and back-navigation.
  • New Features

    • Added Mitra Chat entry and an Improvement Plan page route for the MIP flow.
  • Bug Fixes

    • Fixed back-navigation fallback to clear client storage and navigate back instead of external redirect.
  • Tests

    • Added comprehensive end-to-end MIP flow tests and page-object utilities.
  • Chores

    • Added environment options to configure authentication method and route.

@coderabbitai

coderabbitai Bot commented Mar 25, 2026

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.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 516246da-ed98-4527-8538-caf4e1523824

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

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Refactors AI-creation pages to use selector hooks and destructured store getters instead of imperative .getState() calls, removes several local state mirrors and unused props, updates navigation fallback to clear storage and navigate back, adds env accessors, and introduces MIP e2e tests and page-object.

Changes

Cohort / File(s) Summary
Store access & state migration
src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/ActionItems.jsx, src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/CommonFlow.jsx, src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/SelectObjective.jsx, src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/TitleGeneration.jsx, src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/WeeksSelection.jsx, src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/objectives/FinalObjectiveSection.jsx
Replaced imperative useAICreationSessionStore.getState() calls with selector hooks and destructured getters/setters. Removed local mirror states (intro/chat/objective state), simplified effects, and removed unused props/imports; updated websocket/chat logic to rely on store-selected values.
Navigation fallback change
src/pages/ShikshalokamVoiceChat/dynamic-voice-chat.js
Changed fallback from window.location.replace("https://www.google.com") to clearing client storage via clearFromStorage() and calling navigate(-1).
Selector hook migration (improvement-plan)
src/pages/ai-creation/pages/improvement-plan/index.jsx
Switched media retrieval from useAICreationSessionStore.getState().getMedia() to useAICreationSessionStore(state => state.media) selector hook.
Environment additions
src/utils/env.ts
Added AUTH_METHOD() and AUTH_ROUTE() accessors to exported env (defaults: "url" and "/api/shikshalokam/read-elevate-profile/").
Test constants & routes
tests/constant/sg-commons-chat.ts, tests/constant/site_routes.ts
Added MIP chat message constants and test route constants MITRA_CHAT and IMPROVEMENT_PLAN.
E2E test & page object
tests/pages/mip-flow.page.ts, tests/e2e/flows/mip-flow/happy-path.spec.ts
Added MIPFlowPage Playwright page-object with comprehensive locators and helpers, and an end-to-end "MIP Flow - Happy Path" test that exercises the full MIP creation journey and asserts arrival on the improvement-plan page.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • Vinod-V3

Poem

🐇 Hopped through hooks and store so bright,
Cleared the crumbs and set navigation right.
Tests now scamper, pages sing,
MIP blossoms—what joy I bring! ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Feature/apcfss fix' is vague and generic. It uses non-descriptive terms that don't convey meaningful information about the changeset's purpose or scope. Provide a more descriptive title that clearly summarizes the main change. For example: 'Refactor store access patterns and add MIP flow e2e tests' or similar that reflects the primary modifications.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@VishnuKrishnathu

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Mar 25, 2026

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: 6

Caution

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

⚠️ Outside diff range comments (3)
src/pages/ai-creation/pages/improvement-plan/index.jsx (1)

12-17: ⚠️ Potential issue | 🟠 Major

Sync the rendered media when the store value changes.

items already subscribes this component to state.media, but the mirrored media state is only refreshed when projectId changes. Any later setMedia(...) leaves FileViewer stale or empty until the route changes.

💡 Suggested fix
-  useEffect(() => {
-    const mediaItems = items || [];
-    setMedia(mediaItems);
-  }, [projectId]);
+  useEffect(() => {
+    setMedia(items || []);
+  }, [items]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/ai-creation/pages/improvement-plan/index.jsx` around lines 12 - 17,
The effect currently sets local media state only when projectId changes, causing
FileViewer to go stale; update the useEffect watching items (the value returned
from useAICreationSessionStore) so setMedia(mediaItems) runs whenever items
changes (or remove the mirrored state and use items directly). Locate the
useEffect that references items, setMedia, and projectId and add items to the
dependency array (or refactor to avoid duplicating state) so the rendered media
stays in sync with the store.
src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/CommonFlow.jsx (1)

75-88: ⚠️ Potential issue | 🟠 Major

Invalidate the cached intro when flowType changes.

setCommonFlowIntroMessage(message) now stores a single shared intro value, and this branch only checks whether that value is truthy. If a different common flow is opened before the store is cleared, fetchIntroMessage() and generateNewSession() are skipped and the new flow can start with the previous flow's intro/session.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/CommonFlow.jsx`
around lines 75 - 88, The code caches a single shared intro in
commonFlowIntroMessage so when flowType changes the branch that skips
fetchIntroMessage()/generateNewSession() can reuse the old intro/session; to
fix, invalidate or reset that cached value when flowType changes (e.g., call
setCommonFlowIntroMessage(null) or store intro keyed by flowType) before the if
(commonFlowIntroMessage) check so fetchIntroMessage() and generateNewSession()
run for the new flow; update references to setCommonFlowIntroMessage,
commonFlowIntroMessage, fetchIntroMessage and generateNewSession accordingly.
src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/SelectObjective.jsx (1)

508-513: ⚠️ Potential issue | 🟠 Major

Clear the local selection when switching to the previous objective list.

This handler swaps the rendered list but only resets selectedObjective in the store. selectedIndices and selectedObjectives still point at the old list, so the Next button can stay enabled and handleNextClick() can submit a stale selection from the wrong objective set.

💡 Suggested fix
                             handleAdditionalCTAClick={() => {
                               setObjectiveList(getPrevObjective())
                               setObjectiveSource(getPrevObjectiveSource())
+                              setSelectedIndices([])
+                              setSelectedObjectives([])
                               setPrevObjectiveShown(true)
                               setIsPrevObjectiveShownStore(true)
                               setObjectiveListLoading(true)
                               setSelectedObjectiveStore(null)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/SelectObjective.jsx`
around lines 508 - 513, When switching to the previous objective list you only
clear the store selection via setSelectedObjectiveStore(null) but leave local
selection state (selectedIndices and selectedObjectives) pointing at the old
list; reset those local selections as well so the UI and Next button reflect no
selection. In the same handler that calls setObjectiveList(...),
setObjectiveSource(...), setPrevObjectiveShown(true),
setIsPrevObjectiveShownStore(true), setObjectiveListLoading(true) and
setSelectedObjectiveStore(null), also clear local selection by calling the
setters for selectedIndices and selectedObjectives (e.g., setSelectedIndices([])
and setSelectedObjectives([])) so handleNextClick() cannot submit stale
selections from the previous list.
🧹 Nitpick comments (3)
src/pages/ShikshalokamVoiceChat/dynamic-voice-chat.js (1)

1796-1797: Redundant clearFromStorage() call.

clearFromStorage() is already called at line 1789 (unconditionally in the non-accessToken path). Calling it again here at line 1796 is unnecessary.

🔧 Proposed fix to remove redundant call
     if (rerouteUrl && rerouteUrl !== null && rerouteUrl !== undefined && rerouteUrl !== "") {
       window.location.href = rerouteUrl
     } else {
-      clearFromStorage()
       navigate(-1)
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/ShikshalokamVoiceChat/dynamic-voice-chat.js` around lines 1796 -
1797, Remove the redundant clearFromStorage() call that directly precedes
navigate(-1); clearFromStorage() is already invoked unconditionally earlier in
the non-accessToken branch, so keep the earlier call and delete the second
invocation (leave navigate(-1) intact) to avoid duplicate clearing; look for the
clearFromStorage() call paired with navigate(-1) in dynamic-voice-chat.js and
remove only that extra invocation.
tests/e2e/flows/mip-flow/happy-path.spec.ts (1)

27-37: Clear persisted storage before the first app boot.

Line 32 loads the app before localStorage/sessionStorage are cleared, and Line 46 loads it again. If startup logic reads persisted flags, the first visit can still influence the test before the clean-state navigation happens.

Also applies to: 45-48

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/e2e/flows/mip-flow/happy-path.spec.ts` around lines 27 - 37, Move the
storage-clearing steps to run before the app is first loaded: call
page.context().clearCookies() and run the page.evaluate that clears localStorage
and sessionStorage before instantiating/navigating the app (i.e., before new
MIPFlowPage(page) and before calling mipFlowPage.navigateToMitraChat()). Ensure
the same change is applied to the other setup around lines 45-48 so the first
app boot sees a clean storage state.
tests/pages/mip-flow.page.ts (1)

81-83: Use SITE_ROUTES here instead of duplicating path literals.

This page object hardcodes both the entry path and the final-page check even though tests/constant/site_routes.ts now owns those routes. Pulling from the shared constant keeps navigation and assertions from drifting apart.

♻️ Suggested refactor
 import { Page, Locator } from "@playwright/test"
 import { BasePage } from "./base.page"
+import { SITE_ROUTES } from "../constant/site_routes"
@@
   async navigateToMitraChat(): Promise<void> {
-    await this.navigate("/mohini/mitra-chat")
+    await this.navigate(SITE_ROUTES.MITRA_CHAT)
   }
@@
   async waitForImprovementPlanPage(timeout: number = 120000): Promise<void> {
-    await this.page.waitForURL("**/improvement-plan**", { timeout })
+    await this.page.waitForURL(`**${SITE_ROUTES.IMPROVEMENT_PLAN}**`, { timeout })
   }
@@
   isOnImprovementPlanPage(): boolean {
-    return this.getCurrentUrl().includes("/improvement-plan")
+    return this.getCurrentUrl().includes(SITE_ROUTES.IMPROVEMENT_PLAN)
   }

Also applies to: 338-346

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/pages/mip-flow.page.ts` around lines 81 - 83, The navigateToMitraChat
method hardcodes the route string; replace the literal "/mohini/mitra-chat" with
the shared route constant from SITE_ROUTES (import from
tests/constant/site_routes.ts) so navigation uses SITE_ROUTES.MITRA_CHAT (or the
appropriate exported name). Update any other hardcoded occurrences in this file
(notably the similar block around lines 338-346) to reference the same
SITE_ROUTES constants to keep navigation and assertions consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/CommonFlow.jsx`:
- Around line 158-185: The code reads prevChatHistory/lastMessage once but calls
setCommonFlowChatHistory up to three times, causing later branches to overwrite
earlier updates; instead, inside the if (lastIndex >= 0 && lastMessage?.source
=== 'bot') block create a single updatedLastMessage = { ...lastMessage }, then
if (message?.msg) append to updatedLastMessage.msg, if
(Array.isArray(message?.extra_content?.sources)) set updatedLastMessage.sources,
and if (message?.extra_content?.file_url) set updatedLastMessage.file_url, then
call setCommonFlowChatHistory([...prevChatHistory.slice(0, lastIndex),
updatedLastMessage]) exactly once (use
getCommonFlowChatHistory()/prevChatHistory and lastIndex as currently used).

In
`@src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/SelectObjective.jsx`:
- Around line 87-111: The lazy initializer for visibleCount currently calls
setSelectedIndices and setSelectedObjectives (render-phase side effects);
instead compute initial values first by reading getObjective() and
getSelectedObjective() to derive initialSelectedIndices and
initialSelectedObjectives (handling legacy single-string selection), then pass
those computed values into separate useState calls for selectedIndices and
selectedObjectives, and initialize visibleCount with a pure computed number
(using defaultValueToShow and max selected index) without invoking any setters;
update references to visibleCount, setVisibleCount, setSelectedIndices,
setSelectedObjectives, getObjective, and getSelectedObjective accordingly.

In `@src/utils/env.ts`:
- Line 48: AUTH_ROUTE currently defaults to the literal string "url" due to a
copy/paste error; update the getEnv call for AUTH_ROUTE to use a sensible
default API path (e.g., an empty string "" or a specific path like
"/auth/profile") instead of "url" so that calls using env.AUTH_ROUTE() (via
getEnv and REACT_APP_AUTH_ROUTE) produce a valid endpoint when passed to
apiClient.get(); locate the AUTH_ROUTE definition and replace the default "url"
with the chosen proper default.

In `@tests/pages/mip-flow.page.ts`:
- Around line 170-172: The waitForDefineChallengeLoad helper currently waits for
the shared chat textarea (this.chatBoxTextarea) which is already visible earlier
and doesn't prove the flow advanced; update waitForDefineChallengeLoad (and the
similar helper used around the other occurrence) to wait for a stage-specific
selector or state instead—for example wait for a specific prompt/container
unique to the "define challenge" step (a CSS selector or test-id for that
prompt) or wait for the bot message count to increase (inspect bot message
elements and assert count changed) rather than waiting on this.chatBoxTextarea
so the helper only returns once the UI has actually progressed to the next step.
- Around line 328-330: The method isCreateMIPButtonEnabled currently checks
visibility via isElementVisible (returning true for visible-but-disabled
buttons); change it to check the element's enabled state instead by calling
Playwright's isEnabled on the createMIPButton Locator (or use your existing
helper isElementEnabled if present) so the method accurately returns whether the
button is interactable (ensure you update the implementation of
isCreateMIPButtonEnabled to call createMIPButton.isEnabled() rather than
isElementVisible(createMIPButton)).
- Around line 74-75: getGeneratedTitle is currently using
titleTextarea.inputValue() but titleTextarea can match a <textarea> or a
[contenteditable='true'] element; change getGeneratedTitle to detect which node
was matched (using the locator titleTextarea) and read its text accordingly: if
it's a form control (textarea/input) use inputValue(), otherwise read text via
textContent/innerText or locator.evaluate(node => node.innerText) for
contenteditable elements so the function returns the actual rendered text in
both cases.

---

Outside diff comments:
In `@src/pages/ai-creation/pages/improvement-plan/index.jsx`:
- Around line 12-17: The effect currently sets local media state only when
projectId changes, causing FileViewer to go stale; update the useEffect watching
items (the value returned from useAICreationSessionStore) so
setMedia(mediaItems) runs whenever items changes (or remove the mirrored state
and use items directly). Locate the useEffect that references items, setMedia,
and projectId and add items to the dependency array (or refactor to avoid
duplicating state) so the rendered media stays in sync with the store.

In `@src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/CommonFlow.jsx`:
- Around line 75-88: The code caches a single shared intro in
commonFlowIntroMessage so when flowType changes the branch that skips
fetchIntroMessage()/generateNewSession() can reuse the old intro/session; to
fix, invalidate or reset that cached value when flowType changes (e.g., call
setCommonFlowIntroMessage(null) or store intro keyed by flowType) before the if
(commonFlowIntroMessage) check so fetchIntroMessage() and generateNewSession()
run for the new flow; update references to setCommonFlowIntroMessage,
commonFlowIntroMessage, fetchIntroMessage and generateNewSession accordingly.

In
`@src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/SelectObjective.jsx`:
- Around line 508-513: When switching to the previous objective list you only
clear the store selection via setSelectedObjectiveStore(null) but leave local
selection state (selectedIndices and selectedObjectives) pointing at the old
list; reset those local selections as well so the UI and Next button reflect no
selection. In the same handler that calls setObjectiveList(...),
setObjectiveSource(...), setPrevObjectiveShown(true),
setIsPrevObjectiveShownStore(true), setObjectiveListLoading(true) and
setSelectedObjectiveStore(null), also clear local selection by calling the
setters for selectedIndices and selectedObjectives (e.g., setSelectedIndices([])
and setSelectedObjectives([])) so handleNextClick() cannot submit stale
selections from the previous list.

---

Nitpick comments:
In `@src/pages/ShikshalokamVoiceChat/dynamic-voice-chat.js`:
- Around line 1796-1797: Remove the redundant clearFromStorage() call that
directly precedes navigate(-1); clearFromStorage() is already invoked
unconditionally earlier in the non-accessToken branch, so keep the earlier call
and delete the second invocation (leave navigate(-1) intact) to avoid duplicate
clearing; look for the clearFromStorage() call paired with navigate(-1) in
dynamic-voice-chat.js and remove only that extra invocation.

In `@tests/e2e/flows/mip-flow/happy-path.spec.ts`:
- Around line 27-37: Move the storage-clearing steps to run before the app is
first loaded: call page.context().clearCookies() and run the page.evaluate that
clears localStorage and sessionStorage before instantiating/navigating the app
(i.e., before new MIPFlowPage(page) and before calling
mipFlowPage.navigateToMitraChat()). Ensure the same change is applied to the
other setup around lines 45-48 so the first app boot sees a clean storage state.

In `@tests/pages/mip-flow.page.ts`:
- Around line 81-83: The navigateToMitraChat method hardcodes the route string;
replace the literal "/mohini/mitra-chat" with the shared route constant from
SITE_ROUTES (import from tests/constant/site_routes.ts) so navigation uses
SITE_ROUTES.MITRA_CHAT (or the appropriate exported name). Update any other
hardcoded occurrences in this file (notably the similar block around lines
338-346) to reference the same SITE_ROUTES constants to keep navigation and
assertions consistent.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 638d76a1-9de3-4049-8c4d-6dbefdc3363f

📥 Commits

Reviewing files that changed from the base of the PR and between afa9a16 and f233e56.

📒 Files selected for processing (13)
  • src/pages/ShikshalokamVoiceChat/dynamic-voice-chat.js
  • src/pages/ai-creation/pages/improvement-plan/index.jsx
  • src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/ActionItems.jsx
  • src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/CommonFlow.jsx
  • src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/SelectObjective.jsx
  • src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/TitleGeneration.jsx
  • src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/WeeksSelection.jsx
  • src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/components/objectives/FinalObjectiveSection.jsx
  • src/utils/env.ts
  • tests/constant/sg-commons-chat.ts
  • tests/constant/site_routes.ts
  • tests/e2e/flows/mip-flow/happy-path.spec.ts
  • tests/pages/mip-flow.page.ts

Comment thread src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/SelectObjective.jsx Outdated
Comment thread src/utils/env.ts Outdated
Comment on lines +74 to +75
this.titleTextarea = page.locator("div.secondpage-textbox-container textarea, div.secondpage-textbox-container [contenteditable='true']")
this.createMIPButton = page.locator("button.fifthpage-select-bttn")

@coderabbitai coderabbitai Bot Mar 25, 2026

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

🧩 Analysis chain

🏁 Script executed:

# First, let's check the file exists and view the relevant sections
wc -l tests/pages/mip-flow.page.ts

Repository: ELEVATE-Project/mohini-app-frontend

Length of output: 111


🏁 Script executed:

# View lines 74-75 (selector definition)
sed -n '70,80p' tests/pages/mip-flow.page.ts

Repository: ELEVATE-Project/mohini-app-frontend

Length of output: 470


🏁 Script executed:

# View lines 305-310 (usage context around inputValue)
sed -n '300,310p' tests/pages/mip-flow.page.ts

Repository: ELEVATE-Project/mohini-app-frontend

Length of output: 272


🏁 Script executed:

# Search for the getGeneratedTitle method
grep -n "getGeneratedTitle" tests/pages/mip-flow.page.ts

Repository: ELEVATE-Project/mohini-app-frontend

Length of output: 129


🏁 Script executed:

# Search for all usages of titleTextarea to see if there are other methods interacting with it
grep -n "titleTextarea" tests/pages/mip-flow.page.ts

Repository: ELEVATE-Project/mohini-app-frontend

Length of output: 439


🏁 Script executed:

# Let's also verify Playwright's inputValue() behavior by checking the repository for any documentation or other clues
rg "inputValue" tests/ -A 2 -B 2 --max-count=10

Repository: ELEVATE-Project/mohini-app-frontend

Length of output: 611


🌐 Web query:

Playwright inputValue() contenteditable support compatibility

💡 Result:

Playwright's inputValue method (available on both ElementHandle and Locator) does not support contenteditable elements. It is specifically designed for form input elements like , <textarea>, and , returning input.value for those. Using it on non-input elements like [contenteditable] typically returns an empty string or throws an error. For contenteditable elements, use alternatives such as: - locator.textContent or locator.innerText to get the text content. - locator.inputValue is unreliable and not intended for contenteditable (confirmed by multiple sources including Stack Overflow discussions and third-party docs noting it fails on divs/contenteditable). Official Playwright docs show locator.fill supports contenteditable (via input event dispatch), but inputValue documentation and examples are limited to input/textarea/select. GitHub issues discuss fill/recognition problems with contenteditable but confirm inputValue expects form controls. Compatibility: No native support in current versions (up to 2026); use textContent for reading values. Citations: 1: https://runebook.dev/en/docs/playwright/api/class-elementhandle/element-handle-input-value 2: https://stackoverflow.com/questions/62002041/getting-value-of-input-element-in-playwright 3: https://runebook.dev/en/articles/playwright/api/class-locator/locator-input-value 4: https://playwright.dev/docs/api/class-elementhandle 5: http://playwright.dev/docs/api/class-locator 🏁 Script executed: # Check the fillInput helper method to see how it handles different element types grep -n "fillInput" tests/pages/mip-flow.page.ts -A 5 -B 2 Repository: ELEVATE-Project/mohini-app-frontend Length of output: 610 🏁 Script executed: # Also check if there's a shared base class or utility that handles both element types grep -n "fillInput\|fill" tests/pages/mip-flow.page.ts | head -20 Repository: ELEVATE-Project/mohini-app-frontend Length of output: 194 🏁 Script executed: # Find the fillInput method definition - it's likely in a base class or utility grep -rn "fillInput" tests/ --include="*.ts" -B 2 -A 8 | grep -A 8 "fillInput\s*(" Repository: ELEVATE-Project/mohini-app-frontend Length of output: 3132 🏁 Script executed: # Check if there's a base page class or helpers file find tests -name "*.ts" -type f | head -20 Repository: ELEVATE-Project/mohini-app-frontend Length of output: 765 getGeneratedTitle() is incompatible with the [contenteditable] fallback. titleTextarea can match either <textarea> or [contenteditable='true'], but inputValue() only works for form controls. If the contenteditable variant is rendered, this will fail or return an empty string instead of the actual text value. 🛠️ Suggested fix async getGeneratedTitle(): Promise<string> { - return await this.titleTextarea.inputValue() + const editor = this.titleTextarea.first() + const tagName = await editor.evaluate((node) => node.tagName.toLowerCase()) + + return tagName === "textarea" + ? await editor.inputValue() + : ((await editor.textContent()) ?? "").trim() } 🤖 Prompt for AI Agents Verify each finding against the current code and only fix it if needed. In `@tests/pages/mip-flow.page.ts` around lines 74 - 75, getGeneratedTitle is currently using titleTextarea.inputValue() but titleTextarea can match a <textarea> or a [contenteditable='true'] element; change getGeneratedTitle to detect which node was matched (using the locator titleTextarea) and read its text accordingly: if it's a form control (textarea/input) use inputValue(), otherwise read text via textContent/innerText or locator.evaluate(node => node.innerText) for contenteditable elements so the function returns the actual rendered text in both cases.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

not required

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@pinkman7009, understood! I'll drop this suggestion. Feel free to let me know if you need anything else.

Comment on lines +170 to +172
async waitForDefineChallengeLoad(): Promise<void> {
await this.waitForElement(this.chatBoxTextarea, 60000)
}

@coderabbitai coderabbitai Bot Mar 25, 2026

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

These wait helpers do not prove the flow advanced.

Both methods wait on the shared chat textarea, which is already visible in earlier stages. They can return immediately while the app is still on the previous step, which is why the spec has to rely on fixed sleeps. Wait on a stage-specific prompt/container or a bot-message count change instead.

Also applies to: 280-282

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/pages/mip-flow.page.ts` around lines 170 - 172, The
waitForDefineChallengeLoad helper currently waits for the shared chat textarea
(this.chatBoxTextarea) which is already visible earlier and doesn't prove the
flow advanced; update waitForDefineChallengeLoad (and the similar helper used
around the other occurrence) to wait for a stage-specific selector or state
instead—for example wait for a specific prompt/container unique to the "define
challenge" step (a CSS selector or test-id for that prompt) or wait for the bot
message count to increase (inspect bot message elements and assert count
changed) rather than waiting on this.chatBoxTextarea so the helper only returns
once the UI has actually progressed to the next step.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

not required

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@pinkman7009, understood! I'll defer to your judgment on this one.

(´• ω •`) ʕ•ᴥ•ʔ


🧠 Learnings used
Learnt from: pinkman7009
Repo: ELEVATE-Project/mohini-app-frontend PR: 225
File: src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/InitialSwitch.jsx:79-89
Timestamp: 2026-01-14T02:51:15.737Z
Learning: In the AI creation flow components (InitialSwitch.jsx, CommonFlow.jsx), the pattern of using `pendingMessageRef` with a 100ms `setTimeout` after WebSocket authentication is intentionally used to ensure the authenticate message is sent before any user messages. This is an accepted implementation pattern for these flows.

Comment thread tests/pages/mip-flow.page.ts
@VishnuKrishnathu

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Mar 26, 2026

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: 1

Caution

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

⚠️ Outside diff range comments (1)
src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/CommonFlow.jsx (1)

83-88: ⚠️ Potential issue | 🟡 Minor

Add botRoute to effect dependency array to ensure intro message refreshes when flow type changes.

When flowType changes, botRoute also changes (e.g., LFA → LCF maps to different bot_routes), but if commonFlowIntroMessage is already cached, the effect skips fetching the new intro message for the current flow type. Add botRoute to the dependency array:

}, [flowType, botRoute]);

Alternatively, clear commonFlowIntroMessage when flowType changes to force a fresh fetch for each flow.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/CommonFlow.jsx`
around lines 83 - 88, The effect that checks commonFlowIntroMessage and calls
fetchIntroMessage currently only depends on flowType, which misses updates when
botRoute changes; update the dependency array for the useEffect that references
commonFlowIntroMessage, setIsLoadingIntro, and fetchIntroMessage to include
botRoute (i.e., }, [flowType, botRoute]); alternatively, if you prefer forcing a
reload on flow change, clear commonFlowIntroMessage when flowType changes so
fetchIntroMessage runs for the new botRoute.
🧹 Nitpick comments (3)
tests/pages/mip-flow.page.ts (2)

137-145: Duplicated selector string.

The selector "li.div34" is hardcoded here and also in the chatMessageContainer locator (line 59). If the selector needs to change, both locations must be updated. Consider extracting a constant or deriving the selector string from the locator.

♻️ Suggested refactor
+  private readonly chatMessageSelector = "li.div34"
+
   // Chat messages (both user and bot messages in the chat window)
-  this.chatMessageContainer = page.locator("li.div34")
+  this.chatMessageContainer = page.locator(this.chatMessageSelector)

Then reference this.chatMessageSelector in waitForBotResponse:

   async waitForBotResponse(expectedCount: number, timeout: number = 60000): Promise<void> {
     await this.page.waitForFunction(
       ({ selector, count }) => {
         return document.querySelectorAll(selector).length >= count
       },
-      { selector: "li.div34", count: expectedCount },
+      { selector: this.chatMessageSelector, count: expectedCount },
       { timeout }
     )
   }

Note: If using an instance field inside waitForFunction, you'll need to pass it as a parameter since the function runs in browser context.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/pages/mip-flow.page.ts` around lines 137 - 145, The selector "li.div34"
is duplicated; update waitForBotResponse to use the existing chat message
selector instead of hardcoding by referencing the class/field used for the
locator (e.g., chatMessageContainer or chatMessageSelector). Move the selector
string into a single constant/instance field (e.g., this.chatMessageSelector)
and pass that selector as an argument into page.waitForFunction so the
browser-context function uses the provided selector parameter rather than a
hardcoded literal; ensure waitForBotResponse signature uses the same selector
source to keep a single point of truth.

63-71: Unused locator declarations.

These class members are defined but never used:

  • objectiveNextButton (line 63) — methods create new locators instead
  • actionItemNextButton (line 68) — clickActionItemNext and isActionItemNextEnabled use inline locators with different selectors
  • weeksSelectionBotMessage (line 71) — not referenced anywhere

Either remove these unused declarations or refactor the methods to use them consistently.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/pages/mip-flow.page.ts` around lines 63 - 71, Remove or consolidate the
unused locator fields: objectiveNextButton, actionItemNextButton, and
weeksSelectionBotMessage from the class, or update the methods to use them
consistently; specifically either delete the declarations for
objectiveNextButton and actionItemNextButton and let clickActionItemNext and
isActionItemNextEnabled continue using their inline locators, and remove
weeksSelectionBotMessage if it's unused, OR change clickActionItemNext and
isActionItemNextEnabled to reference the class fields objectiveNextButton and
actionItemNextButton (ensure the selectors match the inline locators currently
used) and replace any other inline instantiations so all locator usage is
consistent.
src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/CommonFlow.jsx (1)

256-256: Consider using getCommonFlowChatHistory() for consistency.

The onWebSocketMessage callback uses getCommonFlowChatHistory() to read fresh state, but here commonFlowChatHistory from the selector is used. While this works correctly for synchronous event handlers, using the getter would maintain a consistent pattern throughout the component.

♻️ Suggested change for consistency
-    setCommonFlowChatHistory([...commonFlowChatHistory, newMessage]);
+    setCommonFlowChatHistory([...getCommonFlowChatHistory(), newMessage]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/CommonFlow.jsx` at
line 256, Replace the direct usage of the selector state variable when appending
a new message and instead call the getter to obtain the freshest history;
specifically, in the code that currently calls
setCommonFlowChatHistory([...commonFlowChatHistory, newMessage]) use
getCommonFlowChatHistory() to read the current array (e.g.
setCommonFlowChatHistory([...getCommonFlowChatHistory(), newMessage])) so it
matches the pattern used in onWebSocketMessage and avoids stale-state issues.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/pages/mip-flow.page.ts`:
- Line 59: The selector for chat messages is incorrect; update the locator
assignment and any related selector objects to match the actual DOM: change the
locator in tests/pages/mip-flow.page.ts where chatMessageContainer is set from
"li.div34" to "div.div35", and likewise update the selector used in the selector
object (previously { selector: "li.div34", ... }) to { selector: "div.div35",
... } so methods like waitForBotResponse and getChatMessageCount correctly
target the individual message elements (refer to chatMessageContainer,
waitForBotResponse, and getChatMessageCount to locate usages).

---

Outside diff comments:
In `@src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/CommonFlow.jsx`:
- Around line 83-88: The effect that checks commonFlowIntroMessage and calls
fetchIntroMessage currently only depends on flowType, which misses updates when
botRoute changes; update the dependency array for the useEffect that references
commonFlowIntroMessage, setIsLoadingIntro, and fetchIntroMessage to include
botRoute (i.e., }, [flowType, botRoute]); alternatively, if you prefer forcing a
reload on flow change, clear commonFlowIntroMessage when flowType changes so
fetchIntroMessage runs for the new botRoute.

---

Nitpick comments:
In `@src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/CommonFlow.jsx`:
- Line 256: Replace the direct usage of the selector state variable when
appending a new message and instead call the getter to obtain the freshest
history; specifically, in the code that currently calls
setCommonFlowChatHistory([...commonFlowChatHistory, newMessage]) use
getCommonFlowChatHistory() to read the current array (e.g.
setCommonFlowChatHistory([...getCommonFlowChatHistory(), newMessage])) so it
matches the pattern used in onWebSocketMessage and avoids stale-state issues.

In `@tests/pages/mip-flow.page.ts`:
- Around line 137-145: The selector "li.div34" is duplicated; update
waitForBotResponse to use the existing chat message selector instead of
hardcoding by referencing the class/field used for the locator (e.g.,
chatMessageContainer or chatMessageSelector). Move the selector string into a
single constant/instance field (e.g., this.chatMessageSelector) and pass that
selector as an argument into page.waitForFunction so the browser-context
function uses the provided selector parameter rather than a hardcoded literal;
ensure waitForBotResponse signature uses the same selector source to keep a
single point of truth.
- Around line 63-71: Remove or consolidate the unused locator fields:
objectiveNextButton, actionItemNextButton, and weeksSelectionBotMessage from the
class, or update the methods to use them consistently; specifically either
delete the declarations for objectiveNextButton and actionItemNextButton and let
clickActionItemNext and isActionItemNextEnabled continue using their inline
locators, and remove weeksSelectionBotMessage if it's unused, OR change
clickActionItemNext and isActionItemNextEnabled to reference the class fields
objectiveNextButton and actionItemNextButton (ensure the selectors match the
inline locators currently used) and replace any other inline instantiations so
all locator usage is consistent.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0f8d68a2-c2e0-4d7c-8fbf-31acd338dc54

📥 Commits

Reviewing files that changed from the base of the PR and between f233e56 and 5d99bee.

📒 Files selected for processing (4)
  • src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/CommonFlow.jsx
  • src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/SelectObjective.jsx
  • src/utils/env.ts
  • tests/pages/mip-flow.page.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/pages/ai-creation/pages/shikshalokam-mitra/mitra-pages/SelectObjective.jsx

Comment thread tests/pages/mip-flow.page.ts Outdated
this.loadingIndicator = page.locator(".login-load-spinner")

// Chat messages (both user and bot messages in the chat window)
this.chatMessageContainer = page.locator("li.div34")

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 the actual CSS class used in chat message rendering
rg -n "div34|div35" --type=js --type=jsx --type=ts --type=tsx -g '!node_modules' -g '!dist' -C 2

# Also check CSS/SCSS files for these class definitions
rg -n "\.div34|\.div35" --type=css --type=scss -g '!node_modules'

Repository: ELEVATE-Project/mohini-app-frontend

Length of output: 135


🏁 Script executed:

# Search for div34 and div35 references without problematic file type flags
rg -n "div34|div35" -C 2

# Also check the specific file to see the context
wc -l tests/pages/mip-flow.page.ts
head -80 tests/pages/mip-flow.page.ts | tail -30

Repository: ELEVATE-Project/mohini-app-frontend

Length of output: 10149


Fix selector mismatch: li.div34 does not match the actual MIP chat component DOM structure.

The test page object uses li.div34 selector (lines 59, 142), but the actual MIP flow component (ChatWindow.jsx) uses <div> elements with these classes:

  • Container: <div className="div34">
  • Individual messages: <div className="div35 label1">

Update selectors to match the actual DOM:

  • Line 59: Change "li.div34" to "div.div35" (to target individual message elements)
  • Line 142: Change { selector: "li.div34", ... } to { selector: "div.div35", ... }

Without this fix, waitForBotResponse and getChatMessageCount will fail with element not found errors.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/pages/mip-flow.page.ts` at line 59, The selector for chat messages is
incorrect; update the locator assignment and any related selector objects to
match the actual DOM: change the locator in tests/pages/mip-flow.page.ts where
chatMessageContainer is set from "li.div34" to "div.div35", and likewise update
the selector used in the selector object (previously { selector: "li.div34", ...
}) to { selector: "div.div35", ... } so methods like waitForBotResponse and
getChatMessageCount correctly target the individual message elements (refer to
chatMessageContainer, waitForBotResponse, and getChatMessageCount to locate
usages).

});
let chat_history = getCommonFlowChatHistory();
if (Array.isArray(chat_history)) {
chat_history = chat_history.filter((chat, index) => !(index == chat_history.length - 1 && chat.source === "user"))

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.

Don't hardcode "user" here, take it from a constant file

const lastIndex = prevChatHistory.length - 1;
const lastMessage = prevChatHistory[lastIndex];

if (lastIndex >= 0 && lastMessage?.source === 'bot') {

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.

take the "bot" from a constant file

} else {
const updatedMessage = {
msg: message?.msg || '',
source: 'bot',

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.

take the hardcoded value from the constant file

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