@@ -14,8 +14,6 @@ import { setupTestConversation } from '../../support/conversation-helpers.js'
1414describe ( 'Alpha Client: Visualization' , function ( ) {
1515 let conversationId
1616
17- const timeout = { timeout : 60000 }
18-
1917 before ( function ( ) {
2018 setupTestConversation ( {
2119 topic : 'Alpha Visualization E2E' ,
@@ -41,21 +39,61 @@ describe('Alpha Client: Visualization', function () {
4139 cy . visit ( `/alpha/${ conversationId } ?xid=${ encodeURIComponent ( xid ) } ` )
4240
4341 // Wait for voting UI + hydration to finish attaching handlers
44- cy . get ( '[data-testid="vote-agree"]' , { timeout : 20000 } ) . should ( 'be.visible' )
42+ cy . get ( '[data-testid="vote-agree"]' ) . should ( 'be.visible' )
43+ . should ( 'be.visible' )
44+ . and ( 'not.be.disabled' )
4545 cy . wait ( `@nextComment_${ index } ` )
4646
47- // Vote 3 times (vary vote types for more interesting PCA)
48- cy . get ( '[data-testid="vote-agree"]' ) . click ( { force : true } )
49- cy . wait ( `@vote_${ index } ` ) . its ( 'response.statusCode' ) . should ( 'eq' , 200 )
50-
51- cy . get ( '[data-testid="vote-disagree"]' ) . should ( 'be.visible' ) . click ( { force : true } )
52- cy . wait ( `@vote_${ index } ` ) . its ( 'response.statusCode' ) . should ( 'eq' , 200 )
53-
54- cy . get ( '[data-testid="vote-pass"]' ) . should ( 'be.visible' ) . click ( { force : true } )
55- cy . wait ( `@vote_${ index } ` ) . its ( 'response.statusCode' ) . should ( 'eq' , 200 )
47+ // Ensure we have a participant token before voting, so subsequent votes are attributed
48+ // to the intended distinct participant (xid -> pid).
49+ cy . window ( )
50+ . its ( 'localStorage' )
51+ . invoke ( 'getItem' , `participant_token_${ conversationId } ` )
52+ . should ( 'exist' )
53+
54+ const waitForNextFromVoteResponse = ( voteAlias , label ) => {
55+ return cy . wait ( voteAlias ) . then ( ( interception ) => {
56+ const status = interception . response ?. statusCode
57+ expect ( status , `${ label } vote status` ) . to . eq ( 200 )
58+
59+ const body = interception . response ?. body || { }
60+ const next = body . nextComment
61+ const nextTid = next ?. tid
62+ const nextTxt = typeof next ?. txt === 'string' ? next . txt . trim ( ) : null
63+
64+ // In the alpha client, Survey.tsx uses the vote response to set the next statement.
65+ // So the most deterministic wait is: either nextComment exists and becomes the DOM statement,
66+ // or nextComment is null/absent and we reach the end-state.
67+ if ( ! next || typeof nextTid === 'undefined' || ! nextTxt ) {
68+ cy . get ( '.email-subscribe-container' ) . should ( 'be.visible' )
69+ return
70+ }
71+
72+ // Wait until the rendered statement matches the nextComment text from the vote response.
73+ // Use bdi inner text so we avoid concatenating multiple elements.
74+ cy . get ( '.statement-card .statement-text bdi' )
75+ . first ( )
76+ . should ( ( $bdi ) => {
77+ const rendered = ( $bdi . text ( ) || '' ) . trim ( )
78+ expect (
79+ rendered ,
80+ `${ label } expected statement to match voteResponse.nextComment.txt` ,
81+ ) . to . eq ( nextTxt )
82+ } )
83+ } )
84+ }
85+
86+ cy . get ( '[data-testid="vote-agree"]' ) . should ( 'be.visible' ) . and ( 'not.be.disabled' ) . click ( )
87+ waitForNextFromVoteResponse ( `@vote_${ index } ` , `p${ index } -agree` )
88+
89+ cy . get ( '[data-testid="vote-disagree"]' ) . should ( 'be.visible' ) . and ( 'not.be.disabled' ) . click ( )
90+ waitForNextFromVoteResponse ( `@vote_${ index } ` , `p${ index } -disagree` )
91+
92+ cy . get ( '[data-testid="vote-pass"]' ) . should ( 'be.visible' ) . and ( 'not.be.disabled' ) . click ( )
93+ waitForNextFromVoteResponse ( `@vote_${ index } ` , `p${ index } -pass` )
5694
5795 // After exhausting 3 seeded comments, end-state should be shown
58- cy . get ( '.email-subscribe-container' , { timeout : 20000 } ) . should ( 'be.visible' )
96+ cy . get ( '.email-subscribe-container' ) . should ( 'be.visible' )
5997
6098 return cy . wrap ( xid )
6199 }
@@ -89,22 +127,22 @@ describe('Alpha Client: Visualization', function () {
89127 } )
90128
91129 // New viewer (clean state) loads visualization
92- cy . clearAllLocalStorage ( )
130+ cy . clearAllLocalStorage ( )
93131
94132 cy . intercept ( { method : 'GET' , url : '**/api/v3/math/pca2*' } ) . as ( 'getMath' )
95133 cy . intercept ( { method : 'GET' , url : '**/api/v3/comments*' } ) . as ( 'getComments' )
96134
97135 cy . visit ( `/alpha/${ conversationId } ?ui_lang=en` )
98136
99137 // Wait for PCA + comments fetch
100- cy . wait ( '@getMath' , timeout )
101- cy . wait ( '@getComments' , timeout )
138+ cy . wait ( '@getMath' )
139+ cy . wait ( '@getComments' )
102140
103141 // Assert visualization is present (DOM details can be tightened as we iterate)
104- cy . get ( '.visualization-container' , timeout ) . should ( 'be.visible' )
105- cy . get ( '.visualization-container svg' , timeout ) . should ( 'exist' )
142+ cy . get ( '.visualization-container' ) . should ( 'be.visible' )
143+ cy . get ( '.visualization-container svg' ) . should ( 'exist' )
106144
107145 // PCAVisualization renders a section-card with an "Opinion Groups" heading
108- cy . contains ( 'h2' , / o p i n i o n g r o u p s / i, timeout ) . should ( 'be.visible' )
146+ cy . contains ( 'h2' , / o p i n i o n g r o u p s / i) . should ( 'be.visible' )
109147 } )
110148} )
0 commit comments