@@ -17,14 +17,8 @@ describe('Graph Rendering and Interaction', () => {
1717 cy . get ( '@graphSvg' ) . find ( 'path[data-cy^="link-"]' ) . should ( 'have.length.greaterThan' , 15 ) ;
1818 } ) ;
1919
20- it ( 'should display the most recent releases on the right side of the view' , ( ) => {
21- cy . get ( '[data-cy="node-v9.1.1-nightly"]' ) . should ( 'be.visible' ) ;
22- } ) ;
23-
24- it ( 'should hide minor releases of unsupported majors, but keep the major visible' , ( ) => {
25- cy . get ( '[data-cy="node-v7.6-RC1"]' ) . should ( 'exist' ) ;
26-
27- cy . get ( '[data-cy="node-v7.6.3"]' ) . should ( 'not.exist' ) ;
20+ it ( 'should display releases on the graph' , ( ) => {
21+ cy . get ( '@graphSvg' ) . find ( 'g[data-cy^="node-v"]' ) . first ( ) . should ( 'exist' ) ;
2822 } ) ;
2923 } ) ;
3024
@@ -51,11 +45,182 @@ describe('Graph Rendering and Interaction', () => {
5145 cy . get ( 'app-modal' ) . should ( 'be.visible' ) . as ( 'infoModal' ) ;
5246
5347 cy . get ( '@infoModal' ) . contains ( 'h2' , 'Release Support' ) ;
54- cy . get ( '@infoModal' ) . find ( '.release-content-item' ) . should ( 'have.length' , 4 ) ;
48+ cy . get ( '@infoModal' ) . find ( '.release-content-item' ) . should ( 'have.length' , 5 ) ;
5549 cy . get ( '@infoModal' ) . contains ( 'p' , 'Our policy is to provide major versions with one year of security support and six months of technical support.' ) ;
5650 cy . get ( '@infoModal' ) . find ( 'button[aria-label="Close modal"]' ) . click ( ) ;
5751
5852 cy . get ( 'app-modal' ) . should ( 'not.exist' ) ;
5953 } ) ;
6054 } ) ;
55+
56+ context ( 'Skip Node Functionality' , ( ) => {
57+ it ( 'should display skip nodes for version gaps' , ( ) => {
58+ cy . get ( '@graphSvg' ) . find ( 'g[data-cy^="skip-node-"]' ) . should ( 'have.length.greaterThan' , 0 ) ;
59+ } ) ;
60+
61+ it ( 'should display skip nodes with correct positioning between release nodes' , ( ) => {
62+ cy . get ( '@graphSvg' ) . find ( 'g[data-cy^="skip-node-"]' ) . first ( ) . as ( 'skipNode' ) ;
63+
64+ cy . get ( '@skipNode' ) . should ( 'exist' ) ;
65+ cy . get ( '@skipNode' ) . should ( 'have.attr' , 'transform' ) ;
66+ } ) ;
67+
68+ it ( 'should display dotted links to and from skip nodes' , ( ) => {
69+ cy . get ( '@graphSvg' ) . find ( 'path.dotted' ) . should ( 'have.length.greaterThan' , 0 ) ;
70+ } ) ;
71+
72+ it ( 'should open skip node modal when clicking on a skip node' , ( ) => {
73+ cy . get ( 'app-modal' ) . should ( 'not.exist' ) ;
74+
75+ cy . get ( '@graphSvg' ) . find ( 'g[data-cy^="skip-node-"]' ) . first ( ) . click ( { force : true } ) ;
76+
77+ cy . get ( 'app-modal' ) . should ( 'be.visible' ) . as ( 'skipModal' ) ;
78+ cy . get ( '@skipModal' ) . should ( 'contain' , 'Skipped Releases' ) ;
79+ } ) ;
80+
81+ it ( 'should display skipped versions in the modal with proper structure' , ( ) => {
82+ cy . get ( '@graphSvg' ) . find ( 'g[data-cy^="skip-node-"]' ) . first ( ) . click ( { force : true } ) ;
83+
84+ cy . get ( 'app-modal' ) . should ( 'be.visible' ) . as ( 'skipModal' ) ;
85+ cy . get ( '@skipModal' ) . find ( '.skipped-versions-list' ) . should ( 'be.visible' ) ;
86+ cy . get ( '@skipModal' ) . find ( '.version-root, .version-patch' ) . should ( 'have.length.greaterThan' , 0 ) ;
87+ } ) ;
88+
89+ it ( 'should show version badges in the skipped releases modal' , ( ) => {
90+ cy . get ( '@graphSvg' ) . find ( 'g[data-cy^="skip-node-"]' ) . first ( ) . click ( { force : true } ) ;
91+
92+ cy . get ( 'app-modal' ) . should ( 'be.visible' ) ;
93+ cy . get ( '.version-type-badge' ) . should ( 'have.length.greaterThan' , 0 ) ;
94+ cy . get ( '.version-type-badge' ) . first ( ) . invoke ( 'text' ) . should ( 'match' , / M A J O R | M I N O R | P A T C H / ) ;
95+ } ) ;
96+
97+ it ( 'should allow clicking on skipped version to view release details' , ( ) => {
98+ cy . get ( '@graphSvg' ) . find ( 'g[data-cy^="skip-node-"]' ) . first ( ) . click ( { force : true } ) ;
99+
100+ cy . get ( 'app-modal' ) . should ( 'be.visible' ) ;
101+ cy . get ( '.version-root' ) . first ( ) . click ( ) ;
102+
103+ cy . get ( 'app-release-off-canvas' ) . should ( 'be.visible' ) ;
104+ } ) ;
105+
106+ it ( 'should close skip node modal when clicking close button' , ( ) => {
107+ cy . get ( '@graphSvg' ) . find ( 'g[data-cy^="skip-node-"]' ) . first ( ) . click ( { force : true } ) ;
108+
109+ cy . get ( 'app-modal' ) . should ( 'be.visible' ) ;
110+ cy . get ( 'app-modal' ) . find ( 'button[aria-label="Close modal"]' ) . click ( ) ;
111+
112+ cy . get ( 'app-modal' ) . should ( 'not.exist' ) ;
113+ } ) ;
114+
115+ it ( 'should close skip node modal when clicking outside' , ( ) => {
116+ cy . get ( '@graphSvg' ) . find ( 'g[data-cy^="skip-node-"]' ) . first ( ) . click ( { force : true } ) ;
117+
118+ cy . get ( 'app-modal' ) . should ( 'be.visible' ) ;
119+ cy . get ( '.modal-backdrop' ) . click ( { force : true } ) ;
120+
121+ cy . get ( 'app-modal' ) . should ( 'not.exist' ) ;
122+ } ) ;
123+
124+ it ( 'should display initial skip node if there are skipped versions at the beginning' , ( ) => {
125+ cy . get ( '@graphSvg' ) . find ( 'g[data-cy^="skip-node-"]' ) . then ( ( $skipNodes ) => {
126+ const initialSkipNode = $skipNodes . filter ( '[data-cy^="skip-node-skip-initial-"]' ) ;
127+ if ( initialSkipNode . length > 0 ) {
128+ expect ( initialSkipNode ) . to . have . length . greaterThan ( 0 ) ;
129+ }
130+ } ) ;
131+ } ) ;
132+
133+ it ( 'should show proper fade-in links from start position if they exist' , ( ) => {
134+ cy . get ( '@graphSvg' ) . then ( ( $svg ) => {
135+ const links = $svg . find ( 'path[data-cy^="link-start-node-"]' ) ;
136+ if ( links . length > 0 ) {
137+ expect ( links ) . to . have . length . greaterThan ( 0 ) ;
138+ expect ( links . first ( ) ) . to . have . class ( 'dotted' ) ;
139+ }
140+ } ) ;
141+ } ) ;
142+
143+ it ( 'should handle skip nodes with different skip counts correctly' , ( ) => {
144+ cy . get ( '@graphSvg' ) . find ( 'g[data-cy^="skip-node-"]' ) . then ( ( $skipNodes ) => {
145+ const nodesToTest = $skipNodes . slice ( 0 , 3 ) ;
146+ cy . wrap ( nodesToTest ) . each ( ( $skipNode ) => {
147+ cy . wrap ( $skipNode ) . click ( { force : true } ) ;
148+ cy . get ( 'app-modal' ) . should ( 'be.visible' ) ;
149+
150+ cy . get ( '.skipped-versions-list' ) . should ( 'be.visible' ) ;
151+
152+ cy . get ( 'app-modal' ) . find ( 'button[aria-label="Close modal"]' ) . click ( ) ;
153+ cy . get ( 'app-modal' ) . should ( 'not.exist' ) ;
154+ } ) ;
155+ } ) ;
156+ } ) ;
157+
158+ it ( 'should display skip count number on skip nodes' , ( ) => {
159+ cy . get ( '@graphSvg' ) . find ( 'g[data-cy^="skip-node-"]' ) . first ( ) . find ( 'text.skip-text' ) . should ( 'exist' ) ;
160+ cy . get ( '@graphSvg' ) . find ( 'g[data-cy^="skip-node-"]' ) . first ( ) . find ( 'text.skip-text' ) . invoke ( 'text' ) . should ( 'not.be.empty' ) ;
161+ } ) ;
162+
163+ it ( 'should show proper tree structure with patches indented' , ( ) => {
164+ cy . get ( '@graphSvg' ) . find ( 'g[data-cy^="skip-node-"]' ) . first ( ) . click ( { force : true } ) ;
165+
166+ cy . get ( 'app-modal' ) . should ( 'be.visible' ) ;
167+ cy . get ( '.version-patch' ) . should ( 'contain' , '└─' ) ;
168+ cy . get ( '.version-patch .patch-indent' ) . should ( 'be.visible' ) ;
169+ } ) ;
170+ } ) ;
171+
172+ context ( 'Skip Node Integration with Graph Layout' , ( ) => {
173+ it ( 'should maintain proper spacing between skip nodes and release nodes' , ( ) => {
174+ cy . get ( '@graphSvg' ) . find ( 'g[data-cy^="skip-node-"]' ) . first ( ) . as ( 'skipNode' ) ;
175+ cy . get ( '@graphSvg' ) . find ( 'g[data-cy^="node-v"]' ) . first ( ) . as ( 'releaseNode' ) ;
176+
177+ cy . get ( '@skipNode' ) . invoke ( 'attr' , 'transform' ) . then ( ( skipTransform ) => {
178+ cy . get ( '@releaseNode' ) . invoke ( 'attr' , 'transform' ) . then ( ( releaseTransform ) => {
179+ const skipMatch = skipTransform ! . match ( / t r a n s l a t e \( ( [ ^ , ] + ) , ( [ ^ ) ] + ) \) / ) ;
180+ const releaseMatch = releaseTransform ! . match ( / t r a n s l a t e \( ( [ ^ , ] + ) , ( [ ^ ) ] + ) \) / ) ;
181+
182+ if ( skipMatch && releaseMatch ) {
183+ const distance = Math . abs ( parseFloat ( skipMatch [ 1 ] ) - parseFloat ( releaseMatch [ 1 ] ) ) ;
184+ expect ( distance ) . to . be . greaterThan ( 50 ) ;
185+ }
186+ } ) ;
187+ } ) ;
188+ } ) ;
189+
190+ it ( 'should have skip nodes positioned on the same y-level as master branch' , ( ) => {
191+ cy . get ( '@graphSvg' ) . find ( 'g[data-cy^="skip-node-"]' ) . first ( ) . as ( 'skipNode' ) ;
192+ cy . get ( '@graphSvg' ) . find ( 'g[data-cy^="node-v"]' ) . first ( ) . as ( 'masterNode' ) ;
193+
194+ cy . get ( '@skipNode' ) . invoke ( 'attr' , 'transform' ) . then ( ( skipTransform ) => {
195+ cy . get ( '@masterNode' ) . invoke ( 'attr' , 'transform' ) . then ( ( masterTransform ) => {
196+ const skipMatch = skipTransform ! . match ( / t r a n s l a t e \( [ ^ , ] + , ( [ ^ ) ] + ) \) / ) ;
197+ const masterMatch = masterTransform ! . match ( / t r a n s l a t e \( [ ^ , ] + , ( [ ^ ) ] + ) \) / ) ;
198+
199+ if ( skipMatch && masterMatch ) {
200+ expect ( parseFloat ( skipMatch [ 1 ] ) ) . to . equal ( parseFloat ( masterMatch [ 1 ] ) ) ;
201+ }
202+ } ) ;
203+ } ) ;
204+ } ) ;
205+
206+ it ( 'should show skip nodes with appropriate visual styling' , ( ) => {
207+ cy . get ( '@graphSvg' ) . find ( 'g[data-cy^="skip-node-"]' ) . first ( ) . find ( 'circle.skip-circle' ) . as ( 'skipCircle' ) ;
208+
209+ cy . get ( '@skipCircle' ) . should ( 'exist' ) ;
210+ cy . get ( '@skipCircle' ) . should ( 'have.attr' , 'r' , '20' ) ;
211+ } ) ;
212+
213+ it ( 'should display skip nodes as interactive elements with cursor pointer' , ( ) => {
214+ cy . get ( '@graphSvg' ) . find ( 'g[data-cy^="skip-node-"]' ) . first ( ) . should ( 'have.class' , 'skip-node' ) ;
215+ } ) ;
216+
217+ it ( 'should show correct skip count text on skip nodes' , ( ) => {
218+ cy . get ( '@graphSvg' ) . find ( 'g[data-cy^="skip-node-"]' ) . each ( ( $skipNode ) => {
219+ cy . wrap ( $skipNode ) . find ( 'text.skip-text' ) . then ( ( $text ) => {
220+ const skipCount = parseInt ( $text . text ( ) ) ;
221+ expect ( skipCount ) . to . be . greaterThan ( 0 ) ;
222+ } ) ;
223+ } ) ;
224+ } ) ;
225+ } ) ;
61226} ) ;
0 commit comments