Skip to content

enhance(apps/chat): Add Cypress E2E tests and data-cy attributes for chat app#5007

Draft
rschlaefli wants to merge 1 commit intov3from
claude/add-cypress-tests-T4tHl
Draft

enhance(apps/chat): Add Cypress E2E tests and data-cy attributes for chat app#5007
rschlaefli wants to merge 1 commit intov3from
claude/add-cypress-tests-T4tHl

Conversation

@rschlaefli
Copy link
Copy Markdown
Member

@rschlaefli rschlaefli commented Feb 8, 2026

Summary

This PR adds comprehensive end-to-end testing infrastructure for the chat application by introducing Cypress test files and instrumenting UI components with data-cy attributes for reliable test selectors.

Key Changes

Test Infrastructure

  • New Cypress test files:
    • Y-chatbot-auth-workflow.cy.ts: Tests authentication flow, noLogin page rendering, and access control
    • Z-chatbot-disclaimer-workflow.cy.ts: Tests disclaimer modal display, acceptance/decline flows, and blocked state
    • ZA-chatbot-thread-management-workflow.cy.ts: Tests thread creation, switching, editing, deletion, and sidebar management
  • Updated cypress.config.ts: Added URL_CHAT environment variable pointing to chat app at http://127.0.0.1:3004

UI Instrumentation

Added data-cy attributes throughout the chat application for reliable test selectors:

Authentication & Access:

  • chat-no-login, chat-no-login-title, chat-no-login-link
  • chat-participation-required

Loading & Disclaimer States:

  • chat-loading, chat-disclaimer-declined, chat-show-disclaimer-again
  • chat-disclaimer-modal, chat-disclaimer-content, chat-disclaimer-accept, chat-disclaimer-decline

Chat Interface:

  • chat-header, chat-breadcrumb-name, chat-breadcrumb-thread
  • chat-thread, chat-composer, chat-composer-input, chat-send-button, chat-cancel-button
  • chat-user-message, chat-user-message-content, chat-assistant-message, chat-assistant-message-content
  • chat-edit-message-button, chat-edit-composer, chat-edit-composer-input, chat-edit-send-button, chat-edit-cancel-button
  • chat-copy-message-button, chat-reload-message-button

Thread Management:

  • chat-thread-list, chat-thread-item, chat-thread-select
  • chat-thread-edit-button, chat-thread-delete-button
  • chat-thread-title-input, chat-thread-title-save, chat-thread-title-cancel
  • chat-new-thread-button

Branch Navigation:

  • chat-branch-picker, chat-branch-previous, chat-branch-next, chat-branch-indicator

Settings & Credits:

  • chat-settings-toggle, chat-settings-panel
  • chat-mode-selection, chat-mode-select
  • chat-model-selection, chat-model-select, chat-model-display
  • chat-credits-section, chat-credits-display, chat-credits-empty-message

Welcome State:

  • chat-welcome-message

Implementation Details

  • All test files use API interception to mock backend responses, enabling tests to run without a real backend
  • Tests cover happy paths and edge cases (empty states, declined disclaimers, etc.)
  • Tests follow naming convention with Z prefix to ensure they run after other test suites
  • Attributes are added non-intrusively without affecting styling or functionality

https://claude.ai/code/session_01XaniHBWXbZnTfuEcNsXjWQ

Summary by CodeRabbit

  • Tests

    • Added comprehensive end-to-end test suites covering chat authentication, disclaimer flows, thread management, messaging, and settings.
    • Added test selectors across chat UI to enable more reliable automated testing.
  • Chores

    • Added a chat environment URL to Cypress config for test targeting.

Copilot AI review requested due to automatic review settings February 8, 2026 07:16
@dosubot dosubot bot added the size:XXL This PR changes 1000+ lines, ignoring generated files. label Feb 8, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 8, 2026

📝 Walkthrough

Walkthrough

Adds test selectors (data-cy attributes) across chat UI components, introduces multiple new Cypress end-to-end test suites for auth, disclaimer, threads, messaging, and settings, and adds a chat URL env var to Cypress config.

Changes

Cohort / File(s) Summary
Chat UI — test selectors
apps/chat/src/app/noLogin/page.tsx, apps/chat/src/components/assistant.tsx, apps/chat/src/components/branch-picker.tsx, apps/chat/src/components/disclaimer-modal.tsx, apps/chat/src/components/settings-panel.tsx, apps/chat/src/components/thread-list.tsx, apps/chat/src/components/thread.tsx, apps/chat/src/components/app-sidebar.tsx
Added data-cy attributes to UI elements (containers, buttons, inputs, indicators) for E2E test targeting only; no logic or behavior changes.
Cypress config
cypress/cypress.config.ts
Added URL_CHAT environment variable (http://127.0.0.1:3004) to Cypress env.
Cypress E2E — authentication
cypress/cypress/e2e/Y-chatbot-auth-workflow.cy.ts
New test validating unauthenticated redirect to /noLogin, login link presence, and authenticated access using intercepted APIs and participant token cookie handling.
Cypress E2E — disclaimer
cypress/cypress/e2e/Z-chatbot-disclaimer-workflow.cy.ts
New suite testing disclaimer modal flows (appear/accept/decline/reopen) with mocked disclaimer, post-disclaimer, threads, credits, and metadata endpoints.
Cypress E2E — thread management
cypress/cypress/e2e/ZA-chatbot-thread-management-workflow.cy.ts
New suite covering thread sidebar, creation, selection, inline title editing (save/cancel), deletion, and empty-state handling via API intercepts.
Cypress E2E — messaging
cypress/cypress/e2e/ZB-chatbot-messaging-workflow.cy.ts
New suite validating composer, sending messages, streaming assistant responses (SSE-like), welcome message behavior, and message rendering for empty and pre-populated threads.
Cypress E2E — settings
cypress/cypress/e2e/ZC-chatbot-settings-workflow.cy.ts
New suite testing settings panel toggle, mode/model selection display, credits display (including zero-edge cases), and reasoning-effort UI using mocked endpoints.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

size:XL

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 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 main purpose of the PR: adding Cypress E2E tests and data-cy attributes to the chat app. It is concise, specific, and directly related to all substantial changes in the changeset.

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


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.

@rschlaefli rschlaefli changed the title Add Cypress E2E tests and data-cy attributes for chat app enhance(apps/chat): Add Cypress E2E tests and data-cy attributes for chat app Feb 8, 2026
@dosubot dosubot bot added the enhancement label Feb 8, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds Cypress E2E coverage for the chat application and instruments chat UI components with data-cy attributes to provide stable selectors for those tests.

Changes:

  • Added new Cypress E2E test suites covering auth/noLogin, disclaimer flow, thread management, messaging, and settings.
  • Added data-cy attributes across chat UI components (noLogin, assistant states, disclaimer modal, thread/thread list, settings panel, branch picker).
  • Updated Cypress configuration with URL_CHAT pointing to the chat app.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
cypress/cypress/e2e/Y-chatbot-auth-workflow.cy.ts Adds E2E coverage for unauthenticated redirect and authenticated access.
cypress/cypress/e2e/Z-chatbot-disclaimer-workflow.cy.ts Adds E2E coverage for disclaimer modal accept/decline flows.
cypress/cypress/e2e/ZA-chatbot-thread-management-workflow.cy.ts Adds E2E coverage for thread list CRUD and sidebar behavior (with mocked APIs).
cypress/cypress/e2e/ZB-chatbot-messaging-workflow.cy.ts Adds E2E coverage for messaging UI including a stubbed streaming response.
cypress/cypress/e2e/ZC-chatbot-settings-workflow.cy.ts Adds E2E coverage for settings panel behavior and credits/model UI.
cypress/cypress.config.ts Adds URL_CHAT env var for chat app base URL.
apps/chat/src/app/noLogin/page.tsx Adds data-cy hooks for noLogin page tests.
apps/chat/src/components/assistant.tsx Adds data-cy hooks for loading/blocked/header/breadcrumb states.
apps/chat/src/components/disclaimer-modal.tsx Adds data-cy hooks for disclaimer modal and actions.
apps/chat/src/components/thread.tsx Adds data-cy hooks for thread UI, composer, messages, and action buttons.
apps/chat/src/components/thread-list.tsx Adds data-cy hooks for thread list, items, and inline title editing actions.
apps/chat/src/components/settings-panel.tsx Adds data-cy hooks for settings and credits UI.
apps/chat/src/components/branch-picker.tsx Adds data-cy hooks for branch navigation controls.

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

Comment on lines +6 to +10
* Tests for the chatbot authentication and access control flow.
* Verifies that unauthenticated users are redirected, the noLogin page renders
* correctly, and authenticated users can access or are blocked from the chatbot
* depending on their participation status.
*/
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

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

The suite description mentions that authenticated users can be blocked based on participation status, but there is no test case covering the "participation required"/403 flow. Consider adding a test that stubs the relevant API to return 403 and asserts the blocked UI (e.g., the element with data-cy="chat-participation-required").

Copilot uses AI. Check for mistakes.
Comment on lines 36 to 40
<div
data-cy="chat-settings-toggle"
className="flex cursor-pointer items-center gap-2 border-t p-4 hover:bg-gray-100"
onClick={() => setOpen(!open)}
>
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

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

The settings toggle is implemented as a clickable

with only an onClick handler. This is not keyboard-accessible and lacks proper button semantics (role/tabIndex/key handlers), which is an accessibility issue. Consider changing this to a element (preferred) or adding role="button", tabIndex={0}, and handling Enter/Space keydown to toggle the panel.

Copilot uses AI. Check for mistakes.
Comment on lines +170 to +175
cy.wait('@getDisclaimer')

cy.get('[data-cy="chat-thread-list"]').should('be.visible')
cy.get('[data-cy="chat-thread-item"]').should('have.length', 2)
cy.contains('First conversation').should('be.visible')
cy.contains('Second conversation').should('be.visible')
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

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

These assertions can run before the initial thread list request resolves. Since RuntimeProvider triggers loadThreads/loadCredits/loadModeOptions on mount, this test can become flaky without waiting for the relevant intercepts. Add a cy.wait('@getThreads') (and any other required alias like @getCredits/@GetChatbot) before asserting on rendered thread items.

Copilot uses AI. Check for mistakes.
Comment on lines +312 to +316
cy.wait('@getDisclaimer')

// Click on the existing thread
cy.get('[data-cy="chat-thread-select"]').first().click()
cy.wait('@getThreadMessages')
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

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

This test interacts with the thread list immediately after only waiting for @getDisclaimer. Since threads are loaded asynchronously on mount, the thread list may not be populated yet, making the click/expectations flaky. Add a cy.wait('@getThreads') before selecting the thread (and optionally wait for @getChatbot/@getCredits if the UI depends on them).

Copilot uses AI. Check for mistakes.
Comment on lines +199 to +203
// When model selection is enabled, a Select dropdown should be rendered
// instead of the static model display
cy.get('[data-cy="chat-model-selection"]').should('be.visible')
cy.get('[data-cy="chat-model-display"]').should('not.exist')
})
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

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

This test claims the model selection dropdown is rendered when modelSelection is enabled, but it only asserts that the static model display is absent. To actually verify the intended behavior (and avoid false positives where neither control renders correctly), also assert that the model selection control is present (e.g., the element with data-cy="chat-model-select").

Copilot uses AI. Check for mistakes.
Comment on lines +7 to +8
* Covers the welcome state, sending messages, receiving (stubbed) streaming
* responses, and the message action bar (copy, reload).
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

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

The file header comment says this suite covers the message action bar (copy, reload), but there are currently no tests exercising those controls. Either add coverage for copy/reload or update the header comment to avoid misleading future readers.

Suggested change
* Covers the welcome state, sending messages, receiving (stubbed) streaming
* responses, and the message action bar (copy, reload).
* Covers the welcome state, sending messages, and receiving (stubbed) streaming
* responses.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@apps/chat/src/components/disclaimer-modal.tsx`:
- Around line 82-84: The Modal and Button usage passes data-cy as a plain
attribute which the design-system expects as a data prop object; update the
Modal (title={disclaimer.title}) and the Buttons in this file to replace any
data-cy="..." with data={{ cy: '...' }} so the components receive the data prop
(e.g., change Modal's data-cy and both Button instances' data-cy usages to
data={{ cy: 'your-value' }}).

In `@cypress/cypress/e2e/Y-chatbot-auth-workflow.cy.ts`:
- Around line 84-91: The current cy.getCookie('participant_token') block
silently no-ops when the cookie is absent; change it to explicitly assert/fail
when the cookie is missing so test doesn't continue unauthenticated. After
calling cy.getCookie('participant_token'), check the result and if falsy throw
an error or call an explicit Cypress assertion (e.g., expect/should) with a
clear message like "participant_token missing — cy.loginStudent() failed",
otherwise call cy.setCookie('participant_token', cookie.value, { domain:
'127.0.0.1', path: '/' }); keep the same identifiers (participant_token,
cy.getCookie, cy.setCookie) so the change is localized and fails fast on missing
auth.
🧹 Nitpick comments (5)
cypress/cypress/e2e/Y-chatbot-auth-workflow.cy.ts (1)

81-81: Replace hardcoded cy.wait(1000) with a deterministic wait.

Hardcoded time-based waits are a common source of flakiness in Cypress tests — they may be too short on slow CI runners or unnecessarily slow elsewhere. Prefer waiting on a route alias, a DOM condition, or a cookie assertion.

Suggested approach
     cy.loginStudent()
-    cy.wait(1000)
+    // Wait for the login to complete by checking for the cookie
+    cy.getCookie('participant_token').should('exist')
cypress/cypress/e2e/ZA-chatbot-thread-management-workflow.cy.ts (2)

142-146: Hardcoded cy.wait(500) — same flakiness concern across all test files.

This pattern appears in every beforeEach across all four test suites. Consider replacing it with a deterministic wait (e.g., asserting the cookie or a DOM state) and extracting the login + setup into a shared Cypress command or support utility.


32-139: Extract shared setupChatIntercepts into a reusable utility.

This helper is duplicated (with minor variations) across Y-chatbot-auth-workflow, Z-chatbot-disclaimer-workflow, ZA-chatbot-thread-management-workflow, ZB-chatbot-messaging-workflow, and ZC-chatbot-settings-workflow. A single parameterized helper in cypress/support/ (or a shared fixtures file) would reduce maintenance burden and make it easier to update API shapes consistently.

Example approach

Create cypress/cypress/support/chat-intercepts.ts:

interface ChatInterceptOptions {
  chatbotId: string
  threads?: any[]
  credits?: { current: number; total: number }
  disclaimer?: { disclaimer: any; status: any }
  modelSelection?: boolean
  systemPrompts?: Record<string, { prompt: string; description: string }>
  // ...additional overrides
}

export function setupChatIntercepts(options: ChatInterceptOptions) {
  const { chatbotId, threads = [], credits = { current: 50, total: 100 }, ...rest } = options
  // shared intercept setup...
}

Then import in each test file:

import { setupChatIntercepts } from '../support/chat-intercepts'
cypress/cypress/e2e/Z-chatbot-disclaimer-workflow.cy.ts (2)

22-28: declined field in disclaimerStatus type is unused.

The declined?: boolean property on line 26 is declared but never passed in any test invocation. Either remove it if it's not needed or add test coverage for the declined state to justify its presence.


179-219: Inline intercepts duplicate the helper — consider extending setupChatInterceptsWithDisclaimer.

This test sets up intercepts manually instead of reusing the helper because the helper doesn't support disclaimer: null. A small adjustment to the helper's signature (accepting null for disclaimer data) would eliminate this duplication.

Suggested approach
 function setupChatInterceptsWithDisclaimer(
+  disclaimerData: typeof DISCLAIMER_DATA | null = DISCLAIMER_DATA,
   disclaimerStatus: {
     required: boolean
     accepted: boolean
     declined?: boolean
   } = { required: true, accepted: false }
 ) {
   cy.intercept('GET', `/api/chatbots/${CHATBOT_ID}/disclaimer`, {
     statusCode: 200,
     body: {
-      disclaimer: DISCLAIMER_DATA,
+      disclaimer: disclaimerData,
       status: disclaimerStatus,
     },
   }).as('getDisclaimer')

Then the test simplifies to:

it('No disclaimer modal appears when no disclaimer is required', () => {
  setupChatInterceptsWithDisclaimer(null, { required: false, accepted: false })
  // ...
})

Comment on lines 82 to 84
<Modal
data-cy="chat-disclaimer-modal"
title={disclaimer.title}
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:

fd -t f -e tsx -e ts "design-system" --max-one-result

Repository: uzh-bf/klicker-uzh

Length of output: 313


🏁 Script executed:

find . -type d -name "design-system" | head -5

Repository: uzh-bf/klicker-uzh

Length of output: 44


🏁 Script executed:

git ls-files | grep -i "design-system" | head -20

Repository: uzh-bf/klicker-uzh

Length of output: 44


🏁 Script executed:

cat package.json | grep -A5 "@uzh-bf/design-system" || echo "Not in root package.json"

Repository: uzh-bf/klicker-uzh

Length of output: 86


🏁 Script executed:

find . -name "package.json" -exec grep -l "@uzh-bf/design-system" {} \; | head -10

Repository: uzh-bf/klicker-uzh

Length of output: 388


🏁 Script executed:

rg -l "design-system" --glob "*/package.json" | head -10

Repository: uzh-bf/klicker-uzh

Length of output: 44


🏁 Script executed:

cat apps/chat/package.json | grep -A2 -B2 "design-system"

Repository: uzh-bf/klicker-uzh

Length of output: 238


🏁 Script executed:

# Check if design-system is a local package in the monorepo
ls -la packages/ | grep -i design

Repository: uzh-bf/klicker-uzh

Length of output: 44


🏁 Script executed:

# Search for Modal and Button implementations anywhere in the codebase
rg -l "export.*Modal|export.*Button" --glob "*.tsx" --glob "*.ts" | grep -v node_modules | head -20

Repository: uzh-bf/klicker-uzh

Length of output: 1679


🏁 Script executed:

# Verify the disclaimer-modal.tsx file and check Modal/Button imports
cat -n apps/chat/src/components/disclaimer-modal.tsx | head -50

Repository: uzh-bf/klicker-uzh

Length of output: 1377


🏁 Script executed:

# Check if Modal and Button are re-exported or wrapped locally
rg -n "Modal|Button" apps/chat/src/components/disclaimer-modal.tsx | head -20

Repository: uzh-bf/klicker-uzh

Length of output: 539


🏁 Script executed:

# Check how Modal and Button are used elsewhere in the codebase
rg -B2 -A2 "data-cy=" apps/chat/src --glob "*.tsx" | head -40

Repository: uzh-bf/klicker-uzh

Length of output: 2843


🏁 Script executed:

# Look for any existing design-system component usage patterns
rg "from '@uzh-bf/design-system'" --glob "*.tsx" | head -15

Repository: uzh-bf/klicker-uzh

Length of output: 1707


🏁 Script executed:

# Check other Modal usages in the codebase to see if data-cy is commonly used
rg "Modal" apps/chat/src/components/disclaimer-modal.tsx -B3 -A3

Repository: uzh-bf/klicker-uzh

Length of output: 800


🏁 Script executed:

# Check package.json to see if there's a link to design-system source
cat apps/chat/package.json | grep -A5 -B5 "design-system"

Repository: uzh-bf/klicker-uzh

Length of output: 422


🏁 Script executed:

# Look for other Modal usages with data-cy
rg "Modal.*data-cy|data-cy.*Modal" --glob "*.tsx" | head -20

Repository: uzh-bf/klicker-uzh

Length of output: 44


🏁 Script executed:

# Search for test files that might show data-cy usage with design-system components
find . -name "*.test.*" -o -name "*.spec.*" | xargs grep -l "data-cy" | head -10

Repository: uzh-bf/klicker-uzh

Length of output: 44


🏁 Script executed:

# Check if there's any documentation or examples in the codebase
find . -name "*.md" -type f | xargs grep -l "data-cy\|design-system" | head -10

Repository: uzh-bf/klicker-uzh

Length of output: 133


🏁 Script executed:

# Look for Button usage with data-cy in the codebase
rg "Button.*data-cy|data-cy.*Button" --glob "*.tsx" -B2 -A2 | head -30

Repository: uzh-bf/klicker-uzh

Length of output: 849


🏁 Script executed:

# Check thread-list.tsx for Button data-cy usage
rg -B5 -A5 "chat-new-thread-button" apps/chat/src/components/thread-list.tsx

Repository: uzh-bf/klicker-uzh

Length of output: 339


🏁 Script executed:

# Check ImgWithModal.tsx which also uses Modal and Button
cat -n packages/markdown/src/ImgWithModal.tsx | head -100

Repository: uzh-bf/klicker-uzh

Length of output: 2537


🏁 Script executed:

# Search for all Button usages with data attributes to understand the pattern
rg "Button.*data\.|data=" --glob "*.tsx" -B2 -A2 | head -50

Repository: uzh-bf/klicker-uzh

Length of output: 4169


🏁 Script executed:

# Check if there's a pattern of using data object vs data-cy
rg "data-cy|data\s*=" packages/ apps/ --glob "*.tsx" | grep -E "data-cy|data\s*=" | head -30

Repository: uzh-bf/klicker-uzh

Length of output: 3080


Fix data-cy attributes on design-system components to use the correct data prop syntax.

Design-system components (Modal, Button) use data={{ cy: 'value' }} instead of data-cy="value". The current implementation passes data-cy as a standard HTML attribute, which will be silently ignored since these components expect a data prop object. Update lines 83, 140, and 143 to use data={{ cy: '...' }} to ensure Cypress selectors work correctly.

Example fix
- <Modal data-cy="chat-disclaimer-modal" title={disclaimer.title}
+ <Modal data={{ cy: 'chat-disclaimer-modal' }} title={disclaimer.title}

- <Button data-cy="chat-disclaimer-decline" onClick={handleDecline} disabled={isLoading}>
+ <Button data={{ cy: 'chat-disclaimer-decline' }} onClick={handleDecline} disabled={isLoading}>

- <Button data-cy="chat-disclaimer-accept" onClick={handleAccept} disabled={isLoading}>
+ <Button data={{ cy: 'chat-disclaimer-accept' }} onClick={handleAccept} disabled={isLoading}>
🤖 Prompt for AI Agents
In `@apps/chat/src/components/disclaimer-modal.tsx` around lines 82 - 84, The
Modal and Button usage passes data-cy as a plain attribute which the
design-system expects as a data prop object; update the Modal
(title={disclaimer.title}) and the Buttons in this file to replace any
data-cy="..." with data={{ cy: '...' }} so the components receive the data prop
(e.g., change Modal's data-cy and both Button instances' data-cy usages to
data={{ cy: 'your-value' }}).

Comment on lines +84 to +91
cy.getCookie('participant_token').then((cookie) => {
if (cookie) {
cy.setCookie('participant_token', cookie.value, {
domain: '127.0.0.1',
path: '/',
})
}
})
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

Silent no-op when participant_token cookie is missing will mask test failures.

If cy.loginStudent() fails to set the cookie, this block silently does nothing and the test continues without authentication. The test could still pass at line 98 due to the intercepted API responses, giving a false positive.

Suggested fix
-    cy.getCookie('participant_token').then((cookie) => {
-      if (cookie) {
-        cy.setCookie('participant_token', cookie.value, {
-          domain: '127.0.0.1',
-          path: '/',
-        })
-      }
-    })
+    cy.getCookie('participant_token').should('exist').then((cookie) => {
+      cy.setCookie('participant_token', cookie!.value, {
+        domain: '127.0.0.1',
+        path: '/',
+      })
+    })
📝 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
cy.getCookie('participant_token').then((cookie) => {
if (cookie) {
cy.setCookie('participant_token', cookie.value, {
domain: '127.0.0.1',
path: '/',
})
}
})
cy.getCookie('participant_token').should('exist').then((cookie) => {
cy.setCookie('participant_token', cookie!.value, {
domain: '127.0.0.1',
path: '/',
})
})
🤖 Prompt for AI Agents
In `@cypress/cypress/e2e/Y-chatbot-auth-workflow.cy.ts` around lines 84 - 91, The
current cy.getCookie('participant_token') block silently no-ops when the cookie
is absent; change it to explicitly assert/fail when the cookie is missing so
test doesn't continue unauthenticated. After calling
cy.getCookie('participant_token'), check the result and if falsy throw an error
or call an explicit Cypress assertion (e.g., expect/should) with a clear message
like "participant_token missing — cy.loginStudent() failed", otherwise call
cy.setCookie('participant_token', cookie.value, { domain: '127.0.0.1', path: '/'
}); keep the same identifiers (participant_token, cy.getCookie, cy.setCookie) so
the change is localized and fails fast on missing auth.

@rschlaefli rschlaefli force-pushed the claude/add-cypress-tests-T4tHl branch from 9deb888 to 2d190cd Compare February 8, 2026 07:32
@rschlaefli rschlaefli changed the base branch from v3 to feat/chat-gpt-5-1 February 8, 2026 07:39
@cypress
Copy link
Copy Markdown

cypress bot commented Feb 8, 2026

klicker-uzh    Run #6586

Run Properties:  status check failed Failed #6586  •  git commit ec59229e15 ℹ️: Merge 1713e7d1d2e9fabc436bdf40cb5da68372349b99 into 0267cc223f77dab4bc4d2ac909a0...
Project klicker-uzh
Branch Review claude/add-cypress-tests-T4tHl
Run status status check failed Failed #6586
Run duration 13m 52s
Commit git commit ec59229e15 ℹ️: Merge 1713e7d1d2e9fabc436bdf40cb5da68372349b99 into 0267cc223f77dab4bc4d2ac909a0...
Committer Roland Schläfli
View all properties for this run ↗︎

Test results
Tests that failed  Failures 35
Tests that were flaky  Flaky 1
Tests that did not run due to a developer annotating a test with .skip  Pending 0
Tests that did not run due to a failure in a mocha hook  Skipped 0
Tests that passed  Passing 758
View all changes introduced in this branch ↗︎

Tests for review

Failed  Y-chatbot-auth-workflow.cy.ts • 3 failed tests

View Output Video

Test Artifacts
Chatbot Authentication & Access Control > Unauthenticated user is redirected to /noLogin Test Replay Screenshots Video
Chatbot Authentication & Access Control > /noLogin page shows login-required message and login link Test Replay Screenshots Video
Chatbot Authentication & Access Control > Authenticated user with valid participation can access chatbot Test Replay Screenshots Video
Failed  Z-chatbot-disclaimer-workflow.cy.ts • 7 failed tests

View Output Video

Test Artifacts
Chatbot Disclaimer Flow > Disclaimer modal appears when required and not yet accepted Test Replay Screenshots Video
Chatbot Disclaimer Flow > Disclaimer modal displays Student Responsibility and Data Protection sections Test Replay Screenshots Video
Chatbot Disclaimer Flow > Accepting disclaimer closes modal and enables chat Test Replay Screenshots Video
Chatbot Disclaimer Flow > Declining disclaimer shows blocked message Test Replay Screenshots Video
Chatbot Disclaimer Flow > "Show disclaimer again" button re-opens modal after decline Test Replay Screenshots Video
Chatbot Disclaimer Flow > No disclaimer modal appears when disclaimer is already accepted Test Replay Screenshots Video
Chatbot Disclaimer Flow > No disclaimer modal appears when no disclaimer is required Test Replay Screenshots Video
Failed  ZA-chatbot-thread-management-workflow.cy.ts • 9 failed tests

View Output Video

Test Artifacts
Chatbot Thread Management > Sidebar shows Chat History header and New Chat button Test Replay Screenshots Video
Chatbot Thread Management > Existing threads appear in the sidebar thread list Test Replay Screenshots Video
Chatbot Thread Management > Clicking "New Chat" creates a new thread and navigates to it Test Replay Screenshots Video
Chatbot Thread Management > Clicking a thread in sidebar navigates to it and loads messages Test Replay Screenshots Video
Chatbot Thread Management > Thread edit icon opens inline title editing Test Replay Screenshots Video
Chatbot Thread Management > Saving an edited thread title calls the API Test Replay Screenshots Video
Chatbot Thread Management > Cancelling title edit reverts the input Test Replay Screenshots Video
Chatbot Thread Management > Deleting a thread removes it from the sidebar Test Replay Screenshots Video
Chatbot Thread Management > Empty thread list shows no thread items Test Replay Screenshots Video
Failed  ZB-chatbot-messaging-workflow.cy.ts • 7 failed tests

View Output Video

Test Artifacts
Chatbot Messaging Interface > Empty chat shows welcome message Test Replay Screenshots Video
Chatbot Messaging Interface > Composer input is visible and accepts text Test Replay Screenshots Video
Chatbot Messaging Interface > Send button is present and clickable Test Replay Screenshots Video
Chatbot Messaging Interface > Sending a message displays user message in the thread Test Replay Screenshots Video
Chatbot Messaging Interface > Assistant response appears after sending a message Test Replay Screenshots Video
Chatbot Messaging Interface > Welcome message disappears after sending first message Test Replay Screenshots Video
Chatbot Messaging Interface > Existing thread with messages renders user and assistant messages Test Replay Screenshots Video
Failed  ZC-chatbot-settings-workflow.cy.ts • 9 failed tests

View Output Video

Test Artifacts
Chatbot Settings Panel > Settings toggle is visible and panel is open by default Screenshots Video
Chatbot Settings Panel > Clicking settings toggle collapses and expands the panel Screenshots Video
Chatbot Settings Panel > Chat mode section shows available modes Screenshots Video
Chatbot Settings Panel > AI model section displays current model (automatic mode) Screenshots Video
Chatbot Settings Panel > Credits display shows current/total and percentage Screenshots Video
Chatbot Settings Panel > Zero credits shows "used up all credits" message Screenshots Video
Chatbot Settings Panel > Credits display shows zero percentage when total is zero Screenshots Video
Chatbot Settings Panel > Model selection dropdown appears when modelSelection is enabled Screenshots Video
Chatbot Settings Panel > Reasoning effort selector appears when model supports reasoning Screenshots Video
Flakiness  cypress/e2e/O-live-quiz-workflow.cy.ts • 1 flaky test

View Output Video

Test Artifacts
Different live-quiz workflows > Test the direct access links for the live quiz with embedded PIN (logged in users) Test Replay Screenshots Video

Base automatically changed from feat/chat-gpt-5-1 to v3 February 8, 2026 11:17
Add comprehensive data-cy attributes to all interactive elements across
the chatbot UI (thread, composer, settings, disclaimer, sidebar, noLogin)
and introduce 5 new Cypress test suites covering authentication, disclaimer
flow, thread management, messaging, and settings panel.

https://claude.ai/code/session_01XaniHBWXbZnTfuEcNsXjWQ
@rschlaefli rschlaefli force-pushed the claude/add-cypress-tests-T4tHl branch from 2d190cd to 1713e7d Compare February 8, 2026 13:00
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Feb 8, 2026

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

Caution

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

⚠️ Outside diff range comments (1)
apps/chat/src/components/disclaimer-modal.tsx (1)

1-1: ⚠️ Potential issue | 🟡 Minor

Fix Prettier formatting issues.

The CI pipeline reports Prettier formatting violations for this file. Run prettier --write to resolve. As per coding guidelines, the project enforces "no semicolons, single quotes, trailing comma es5, 2-space indent."

🤖 Fix all issues with AI agents
In `@apps/chat/src/components/assistant.tsx`:
- Line 150: The JSX elements in the Assistant component have long inline
attribute lists (e.g., the <div data-cy="chat-participation-required" ...> and
the other elements with data-cy attributes) that exceed Prettier's print width;
run prettier --write on apps/chat/src/components/assistant.tsx or manually wrap
attributes to separate lines so each prop (including data-cy) is on its own line
to satisfy formatting (apply same fix to the other two elements with data-cy
attributes in that component).

In `@cypress/cypress/e2e/Y-chatbot-auth-workflow.cy.ts`:
- Line 1: This file has Prettier formatting issues; run the project's formatter
to reformat it (e.g., execute prettier --write against the spec file) or run the
repository's formatting script so the leading triple-slash reference line (///
<reference types="cypress" />) and the rest of
cypress/e2e/Y-chatbot-auth-workflow.cy.ts conform to the project's Prettier
rules; commit the resulting changes so CI formatting checks pass.

In `@cypress/cypress/e2e/ZA-chatbot-thread-management-workflow.cy.ts`:
- Line 1: The file ZA-chatbot-thread-management-workflow.cy.ts has Prettier
formatting violations; run the project's formatter (e.g., execute prettier
--write on this file) or apply the repo's Prettier config to reformat the file
(ensure the leading triple-slash reference line and entire test file match the
project's Prettier rules), then commit the formatted file so CI no longer
reports formatting errors.

In `@cypress/cypress/e2e/ZB-chatbot-messaging-workflow.cy.ts`:
- Line 1: This file fails Prettier formatting; run the project's Prettier
formatter on cypress/cypress/e2e/ZB-chatbot-messaging-workflow.cy.ts (e.g., run
prettier --write cypress/cypress/e2e/ZB-chatbot-messaging-workflow.cy.ts or the
repo's format script) then stage and commit the rewritten file so the leading
triple-slash reference and the rest of the file conform to Prettier rules;
ensure your editor/CI settings match the project's Prettier config to avoid
future diffs.
- Around line 19-31: Update makeStreamBody to include a unique messageId on the
initial start event and an id on each text-stream event so the SDK can assemble
fragments (i.e., add messageId in the object for the 'start' event and include
id fields for 'text-start', 'text-delta', and 'text-end' events in
makeStreamBody), and ensure the HTTP response used in the test intercept that
returns this SSE sets the header "x-vercel-ai-ui-message-stream" to "v1" so the
mocked stream complies with the Vercel AI SDK Data Stream Protocol.

In `@cypress/cypress/e2e/ZC-chatbot-settings-workflow.cy.ts`:
- Around line 205-225: The test title claims to verify the reasoning-effort
selector but never asserts it; update the test by either renaming the it(...)
description to match the current assertions (keeping the uses of
setupChatIntercepts and the existing cy.get('[data-cy="chat-settings-panel"]') /
cy.get('[data-cy="chat-model-selection"]') checks) OR modify the mock and
assertions: change setupChatIntercepts call to return model config with
supportsReasoning: true and allowedReasoningEfforts containing multiple entries
and add an assertion for the reasoning UI element such as
cy.get('[data-cy="chat-reasoning-effort"]').should('be.visible') so the test
title matches the behavior being validated.
- Line 1: The file fails Prettier formatting; run your project's formatter
(e.g., prettier --write) on the file containing the top line "/// <reference
types=\"cypress\" />" to fix spacing/linebreaks and any trailing whitespace, or
apply the project's Prettier/ESLint autofix; commit the reformatted file so CI
no longer reports formatting errors.
🧹 Nitpick comments (4)
cypress/cypress/e2e/Y-chatbot-auth-workflow.cy.ts (1)

93-99: Weak assertion for authenticated access test.

The test only asserts chat-no-login doesn't exist (line 98), which would also pass if the page is blank or stuck loading. Consider adding a positive assertion that the chat interface (e.g., chat-composer or chat-loading) is visible, similar to the disclaimer tests that assert cy.get('[data-cy="chat-composer"]').should('be.visible').

Proposed fix
     // Should see the chat interface (composer) or loading state, not the noLogin page
     cy.get('[data-cy="chat-no-login"]').should('not.exist')
+    cy.get('[data-cy="chat-composer"]').should('be.visible')
cypress/cypress/e2e/ZB-chatbot-messaging-workflow.cy.ts (1)

33-88: Substantial duplication of intercept setup across test files.

The intercept setup for disclaimer, threads, credits, and chatbot metadata is duplicated across all five test files (Y-, Z-, ZA-, ZB-, ZC-). Consider extracting a shared helper module (e.g., cypress/cypress/support/chatbot-intercepts.ts) that exports a configurable setupChatIntercepts function to reduce maintenance burden.

Also applies to: 90-171

cypress/cypress/e2e/Z-chatbot-disclaimer-workflow.cy.ts (2)

179-219: Inline intercept duplication — reuse setupChatInterceptsWithDisclaimer.

This test duplicates all intercept definitions inline instead of calling setupChatInterceptsWithDisclaimer({ required: false, accepted: false }), which would produce the same result since the helper already accepts a status parameter. The only difference is disclaimer: null vs disclaimer: DISCLAIMER_DATA — you could extend the helper with a parameter to control that.

Suggested approach
-  it('No disclaimer modal appears when no disclaimer is required', () => {
-    cy.intercept('GET', `/api/chatbots/${CHATBOT_ID}/disclaimer`, {
-      statusCode: 200,
-      body: {
-        disclaimer: null,
-        status: { required: false, accepted: false },
-      },
-    }).as('getDisclaimer')
-
-    cy.intercept('GET', `/api/chatbots/${CHATBOT_ID}/threads`, {
-      ...
-    // ... 30+ lines of duplicated intercepts
+  it('No disclaimer modal appears when no disclaimer is required', () => {
+    setupChatInterceptsWithDisclaimer(
+      { required: false, accepted: false },
+      null // pass null disclaimer
+    )

This requires adding a second parameter to setupChatInterceptsWithDisclaimer for the disclaimer body.


66-73: cy.wait(500) is a brittle timing pattern (applies to all test files).

All five test files use cy.wait(500) in beforeEach after cy.loginStudent(). Fixed waits are fragile and slow down the suite. If the login command is async, prefer waiting on an alias or asserting a post-login condition (e.g., a cookie or a specific URL) instead.

if (participationRequired) {
return (
<div className="bg-muted flex min-h-screen w-full items-center justify-center px-4">
<div data-cy="chat-participation-required" className="bg-muted flex min-h-screen w-full items-center justify-center px-4">
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 Prettier formatting — long lines need wrapping.

The CI pipeline flags Prettier formatting issues in this file. Lines 150, 174, and 184 have the data-cy attribute inlined on the same line as multiple other attributes, likely exceeding the print width. Run prettier --write to auto-format.

Also applies to: 174-174, 184-184

🤖 Prompt for AI Agents
In `@apps/chat/src/components/assistant.tsx` at line 150, The JSX elements in the
Assistant component have long inline attribute lists (e.g., the <div
data-cy="chat-participation-required" ...> and the other elements with data-cy
attributes) that exceed Prettier's print width; run prettier --write on
apps/chat/src/components/assistant.tsx or manually wrap attributes to separate
lines so each prop (including data-cy) is on its own line to satisfy formatting
(apply same fix to the other two elements with data-cy attributes in that
component).

@@ -0,0 +1,100 @@
/// <reference types="cypress" />
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 Prettier formatting issues.

The CI pipeline reports formatting errors for this file. Run prettier --write to fix.

🧰 Tools
🪛 GitHub Actions: Check file formatting

[error] 1-1: Prettier formatting issues detected. Run 'prettier --write' to fix.

🤖 Prompt for AI Agents
In `@cypress/cypress/e2e/Y-chatbot-auth-workflow.cy.ts` at line 1, This file has
Prettier formatting issues; run the project's formatter to reformat it (e.g.,
execute prettier --write against the spec file) or run the repository's
formatting script so the leading triple-slash reference line (/// <reference
types="cypress" />) and the rest of cypress/e2e/Y-chatbot-auth-workflow.cy.ts
conform to the project's Prettier rules; commit the resulting changes so CI
formatting checks pass.

@@ -0,0 +1,322 @@
/// <reference types="cypress" />
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 Prettier formatting issues.

The CI pipeline reports formatting errors for this file. Run prettier --write to fix.

🧰 Tools
🪛 GitHub Actions: Check file formatting

[error] 1-1: Prettier formatting issues detected. Run 'prettier --write' to fix.

🤖 Prompt for AI Agents
In `@cypress/cypress/e2e/ZA-chatbot-thread-management-workflow.cy.ts` at line 1,
The file ZA-chatbot-thread-management-workflow.cy.ts has Prettier formatting
violations; run the project's formatter (e.g., execute prettier --write on this
file) or apply the repo's Prettier config to reformat the file (ensure the
leading triple-slash reference line and entire test file match the project's
Prettier rules), then commit the formatted file so CI no longer reports
formatting errors.

@@ -0,0 +1,313 @@
/// <reference types="cypress" />
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 Prettier formatting issues.

The CI pipeline reports formatting errors for this file. Run prettier --write to fix.

🧰 Tools
🪛 GitHub Actions: Check file formatting

[error] 1-1: Prettier formatting issues detected. Run 'prettier --write' to fix.

🤖 Prompt for AI Agents
In `@cypress/cypress/e2e/ZB-chatbot-messaging-workflow.cy.ts` at line 1, This file
fails Prettier formatting; run the project's Prettier formatter on
cypress/cypress/e2e/ZB-chatbot-messaging-workflow.cy.ts (e.g., run prettier
--write cypress/cypress/e2e/ZB-chatbot-messaging-workflow.cy.ts or the repo's
format script) then stage and commit the rewritten file so the leading
triple-slash reference and the rest of the file conform to Prettier rules;
ensure your editor/CI settings match the project's Prettier config to avoid
future diffs.

Comment on lines +19 to +31
function makeStreamBody(text: string) {
const lines = [
`data: ${JSON.stringify({ type: 'start' })}`,
`data: ${JSON.stringify({ type: 'start-step' })}`,
`data: ${JSON.stringify({ type: 'text-start' })}`,
`data: ${JSON.stringify({ type: 'text-delta', delta: text })}`,
`data: ${JSON.stringify({ type: 'text-end' })}`,
`data: ${JSON.stringify({ type: 'finish-step' })}`,
`data: ${JSON.stringify({ type: 'finish' })}`,
'data: [DONE]',
].join('\n')
return lines
}
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

🧩 Analysis chain

🌐 Web query:

Vercel AI SDK data stream protocol format specification 2025

💡 Result:

Vercel AI SDK Data Stream Protocol (v1) — format/spec (as used in 2025)

Transport

  • Uses Server-Sent Events (SSE): each stream part is sent as an SSE event line of the form data: <payload>\n\n, where <payload> is usually a JSON object. [1]
  • If you implement a compatible custom backend, set the HTTP response header:
    x-vercel-ai-ui-message-stream: v1 [1]
  • Stream terminates with an SSE literal marker:
    data: [DONE] [1]

Stream parts (JSON payloads)

Each SSE data: JSON object includes a "type" plus type-specific fields. Supported parts include: [1]

  • Message lifecycle

    • {"type":"start","messageId":"..."}
    • {"type":"finish"}
    • {"type":"abort","reason":"..."}
    • Steps (for multi-call/tool flows): {"type":"start-step"}, {"type":"finish-step"}
  • Text blocks (start/delta/end with a shared id)

    • {"type":"text-start","id":"..."}
    • {"type":"text-delta","id":"...","delta":"..."}
    • {"type":"text-end","id":"..."}
  • Reasoning blocks (start/delta/end with a shared id)

    • {"type":"reasoning-start","id":"..."}
    • {"type":"reasoning-delta","id":"...","delta":"..."}
    • {"type":"reasoning-end","id":"..."}
  • Sources

    • {"type":"source-url","sourceId":"...","url":"..."}
    • {"type":"source-document","sourceId":"...","mediaType":"file","title":"..."}
  • Files

    • {"type":"file","url":"...","mediaType":"image/png"}
  • Custom typed data

    • {"type":"data-<suffix>","data":{...}} (example: data-weather)
  • Errors

    • {"type":"error","errorText":"..."}
  • Tool I/O

    • Input streaming: tool-input-start, tool-input-delta, then tool-input-available (with full input)
    • Output: tool-output-available (with output)

Note on “SSE streaming” change

Vercel’s AI SDK moved to SSE as the standard for streaming (improving robustness/debuggability), and the above “data stream protocol” is defined on top of SSE. [1][2]

Sources: AI SDK UI “Stream Protocols” (latest spec) [1], Vercel AI SDK 5 blog (SSE standardization) [2].


🏁 Script executed:

cat -n cypress/cypress/e2e/ZB-chatbot-messaging-workflow.cy.ts | head -100

Repository: uzh-bf/klicker-uzh

Length of output: 3623


🏁 Script executed:

sed -n '250,280p' cypress/cypress/e2e/ZB-chatbot-messaging-workflow.cy.ts

Repository: uzh-bf/klicker-uzh

Length of output: 891


🏁 Script executed:

sed -n '260,270p' cypress/cypress/e2e/ZB-chatbot-messaging-workflow.cy.ts

Repository: uzh-bf/klicker-uzh

Length of output: 414


🏁 Script executed:

rg "chat-assistant-message" cypress/cypress/e2e/ZB-chatbot-messaging-workflow.cy.ts -A 3 -B 3

Repository: uzh-bf/klicker-uzh

Length of output: 634


🏁 Script executed:

rg -t ts,tsx "chat-assistant-message-content" --max-count 5 | head -20

Repository: uzh-bf/klicker-uzh

Length of output: 92


🏁 Script executed:

rg "chat-assistant-message-content" --type typescript --max-count 5

Repository: uzh-bf/klicker-uzh

Length of output: 96


🏁 Script executed:

fd -e ts -e tsx | xargs rg "chat-assistant-message-content" | head -20

Repository: uzh-bf/klicker-uzh

Length of output: 534


🏁 Script executed:

cat -n apps/chat/src/components/thread.tsx | head -200

Repository: uzh-bf/klicker-uzh

Length of output: 7940


🏁 Script executed:

sed -n '200,300p' apps/chat/src/components/thread.tsx

Repository: uzh-bf/klicker-uzh

Length of output: 3528


🏁 Script executed:

sed -n '300,400p' apps/chat/src/components/thread.tsx

Repository: uzh-bf/klicker-uzh

Length of output: 3548


🏁 Script executed:

sed -n '400,500p' apps/chat/src/components/thread.tsx

Repository: uzh-bf/klicker-uzh

Length of output: 4169


🏁 Script executed:

fd -e json package.json | xargs cat | jq '.dependencies, .devDependencies' | grep -i assistant

Repository: uzh-bf/klicker-uzh

Length of output: 182


🌐 Web query:

@assistant-ui/react 0.10.43 streaming protocol data stream format requirements

💡 Result:

For @assistant-ui/react 0.10.43, “streaming protocol” (via @assistant-ui/react-data-stream) expects your backend to return a Vercel AI SDK “Data Stream Protocol” response (SSE-based). (assistant-ui.com)

HTTP response requirements

  • Stream as Server-Sent Events (SSE) (i.e., text/event-stream with data: ... frames). (ai-sdk.dev)
  • Set header: x-vercel-ai-ui-message-stream: v1 (required for custom backends emitting data streams). (ai-sdk.dev)
  • Terminate the stream with: data: [DONE]. (ai-sdk.dev)

Event (frame) format requirements

Each SSE event is a JSON object in a data: line (followed by a blank line), e.g.:

  • Message lifecycle: {"type":"start", ...} then later {"type":"finish"}. (ai-sdk.dev)
  • Text streaming uses a start/delta/end pattern: text-start, text-delta, text-end. (ai-sdk.dev)
  • Tool calling parts (for tool input/output streaming):
    • tool-input-start, tool-input-delta, tool-input-available, tool-output-available. (ai-sdk.dev)
  • Errors/abort:
    • {"type":"error", ...} and {"type":"abort", ...}. (ai-sdk.dev)

Practical note (assistant-ui backend helper)

assistant-ui’s docs show implementing the endpoint with createAssistantStreamResponse from assistant-stream, which is intended to emit the right stream for the data-stream runtime. (assistant-ui.com)

Citations:


Add required id fields to text-stream events and messageId to the start event, and include the proper HTTP header.

The mocked SSE stream is missing required fields per the Vercel AI SDK Data Stream Protocol. Text-block events (text-start, text-delta, text-end) must each include an id field to enable proper message assembly in the SDK. The initial start event should include a messageId field. Additionally, the HTTP intercept should set the x-vercel-ai-ui-message-stream: v1 header to signal protocol compliance to custom backends.

Current mocked format (incomplete)
data: ${JSON.stringify({ type: 'start' })}
data: ${JSON.stringify({ type: 'text-start' })}
data: ${JSON.stringify({ type: 'text-delta', delta: text })}
data: ${JSON.stringify({ type: 'text-end' })}
data: [DONE]

Without these fields, the SDK may silently mishandle the stream fragments, and test assertions could pass by coincidence rather than correct implementation.

🤖 Prompt for AI Agents
In `@cypress/cypress/e2e/ZB-chatbot-messaging-workflow.cy.ts` around lines 19 -
31, Update makeStreamBody to include a unique messageId on the initial start
event and an id on each text-stream event so the SDK can assemble fragments
(i.e., add messageId in the object for the 'start' event and include id fields
for 'text-start', 'text-delta', and 'text-end' events in makeStreamBody), and
ensure the HTTP response used in the test intercept that returns this SSE sets
the header "x-vercel-ai-ui-message-stream" to "v1" so the mocked stream complies
with the Vercel AI SDK Data Stream Protocol.

@@ -0,0 +1,226 @@
/// <reference types="cypress" />
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 Prettier formatting issues.

The CI pipeline reports formatting errors for this file. Run prettier --write to fix.

🧰 Tools
🪛 GitHub Actions: Check file formatting

[error] 1-1: Prettier formatting issues detected. Run 'prettier --write' to fix.

🤖 Prompt for AI Agents
In `@cypress/cypress/e2e/ZC-chatbot-settings-workflow.cy.ts` at line 1, The file
fails Prettier formatting; run your project's formatter (e.g., prettier --write)
on the file containing the top line "/// <reference types=\"cypress\" />" to fix
spacing/linebreaks and any trailing whitespace, or apply the project's
Prettier/ESLint autofix; commit the reformatted file so CI no longer reports
formatting errors.

Comment on lines +205 to +225
it('Reasoning effort selector appears when model supports reasoning', () => {
// The reasoning effort selector is shown only when the selected model
// has supportsReasoning=true and allowedReasoningEfforts has more than 1 entry.
// This is determined client-side by the settingsStore, which reads from
// the chatbot API response. We simulate this by verifying the selector
// element exists when the store is configured accordingly.
setupChatIntercepts({ current: 50, total: 100 }, true)

cy.visit(`${Cypress.env('URL_CHAT')}/${CHATBOT_ID}`, {
failOnStatusCode: false,
})

cy.wait('@getDisclaimer')
cy.wait('@getChatbot')

// The reasoning effort selector visibility depends on the model's
// supportsReasoning flag. We verify the data-cy attribute is wired up
// and ready for when the flag is true.
cy.get('[data-cy="chat-settings-panel"]').should('be.visible')
cy.get('[data-cy="chat-model-selection"]').should('be.visible')
})
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

Test title is misleading — no reasoning effort selector is actually asserted.

This test claims to verify "Reasoning effort selector appears when model supports reasoning" but only asserts chat-settings-panel and chat-model-selection are visible — the same as other tests. The mock response doesn't include any reasoning-related configuration (e.g., supportsReasoning, allowedReasoningEfforts), and there's no assertion on a reasoning-specific data-cy attribute.

Either rename the test to reflect what it actually verifies, or update the mock to include reasoning configuration and add an assertion for the reasoning effort UI element.

🤖 Prompt for AI Agents
In `@cypress/cypress/e2e/ZC-chatbot-settings-workflow.cy.ts` around lines 205 -
225, The test title claims to verify the reasoning-effort selector but never
asserts it; update the test by either renaming the it(...) description to match
the current assertions (keeping the uses of setupChatIntercepts and the existing
cy.get('[data-cy="chat-settings-panel"]') /
cy.get('[data-cy="chat-model-selection"]') checks) OR modify the mock and
assertions: change setupChatIntercepts call to return model config with
supportsReasoning: true and allowedReasoningEfforts containing multiple entries
and add an assertion for the reasoning UI element such as
cy.get('[data-cy="chat-reasoning-effort"]').should('be.visible') so the test
title matches the behavior being validated.

@rschlaefli rschlaefli marked this pull request as draft February 8, 2026 22:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement size:XXL This PR changes 1000+ lines, ignoring generated files.

Development

Successfully merging this pull request may close these issues.

3 participants