@@ -250,4 +250,153 @@ test.describe('Glossary Bulk Import Export', () => {
250250 }
251251 } ) ;
252252 } ) ;
253+
254+ test ( 'Check for Circular Reference in Glossary Import' , async ( {
255+ page,
256+ browser,
257+ } ) => {
258+ const circularRefGlossary = new Glossary ( 'Test CSV' ) ;
259+
260+ try {
261+ await test . step (
262+ 'Create glossary for circular reference test' ,
263+ async ( ) => {
264+ const { apiContext, afterAction } = await createNewPage ( browser ) ;
265+
266+ await circularRefGlossary . create ( apiContext ) ;
267+ await afterAction ( ) ;
268+ }
269+ ) ;
270+
271+ await test . step ( 'Import initial glossary terms' , async ( ) => {
272+ await sidebarClick ( page , SidebarItem . GLOSSARY ) ;
273+ await selectActiveGlossary ( page , circularRefGlossary . data . displayName ) ;
274+
275+ await page . click ( '[data-testid="manage-button"]' ) ;
276+ await page . click ( '[data-testid="import-button-description"]' ) ;
277+
278+ const initialCsvContent = `parent,name*,displayName,description,synonyms,relatedTerms,references,tags,reviewers,owner,glossaryStatus,color,iconURL,extension
279+ ,name1,name1,<p>name1</p>,,,,,,user:admin,Approved,,,
280+ ,parent,parent,<p>parent</p>,,,,,,user:admin,Approved,,,
281+ ${ circularRefGlossary . data . name } .parent,child,child,<p>child</p>,,,,,,user:admin,Approved,,,`;
282+
283+ const initialCsvBlob = new Blob ( [ initialCsvContent ] , {
284+ type : 'text/csv' ,
285+ } ) ;
286+ const initialCsvFile = new File ( [ initialCsvBlob ] , 'initial-terms.csv' , {
287+ type : 'text/csv' ,
288+ } ) ;
289+
290+ const fileInput = page . getByTestId ( 'upload-file-widget' ) ;
291+
292+ await fileInput ?. setInputFiles ( [
293+ {
294+ name : initialCsvFile . name ,
295+ mimeType : initialCsvFile . type ,
296+ buffer : Buffer . from ( await initialCsvFile . arrayBuffer ( ) ) ,
297+ } ,
298+ ] ) ;
299+
300+ await page . waitForTimeout ( 500 ) ;
301+
302+ await expect ( page . locator ( '.rdg-header-row' ) ) . toBeVisible ( ) ;
303+
304+ await page . getByRole ( 'button' , { name : 'Next' } ) . click ( ) ;
305+
306+ const loader = page . locator (
307+ '.inovua-react-toolkit-load-mask__background-layer'
308+ ) ;
309+
310+ await loader . waitFor ( { state : 'hidden' } ) ;
311+
312+ await validateImportStatus ( page , {
313+ passed : '4' ,
314+ processed : '4' ,
315+ failed : '0' ,
316+ } ) ;
317+
318+ await page . getByRole ( 'button' , { name : 'Update' } ) . click ( ) ;
319+ await page
320+ . locator ( '.inovua-react-toolkit-load-mask__background-layer' )
321+ . waitFor ( { state : 'detached' } ) ;
322+
323+ await toastNotification (
324+ page ,
325+ `Glossaryterm ${ circularRefGlossary . responseData . fullyQualifiedName } details updated successfully`
326+ ) ;
327+ } ) ;
328+
329+ await test . step (
330+ 'Import CSV with circular reference and verify error' ,
331+ async ( ) => {
332+ await sidebarClick ( page , SidebarItem . GLOSSARY ) ;
333+ await selectActiveGlossary (
334+ page ,
335+ circularRefGlossary . data . displayName
336+ ) ;
337+
338+ await page . click ( '[data-testid="manage-button"]' ) ;
339+ await page . click ( '[data-testid="import-button-description"]' ) ;
340+
341+ const circularCsvContent = `parent,name*,displayName,description,synonyms,relatedTerms,references,tags,reviewers,owner,glossaryStatus,color,iconURL,extension
342+ ${ circularRefGlossary . data . name } .name1,name1,name1,<p>name1</p>,,,,,,user:admin,Approved,,,
343+ ,parent,parent,<p>parent</p>,,,,,,user:admin,Approved,,,
344+ ${ circularRefGlossary . data . name } .parent,child,child,<p>child</p>,,,,,,user:admin,Approved,,,`;
345+
346+ const circularCsvBlob = new Blob ( [ circularCsvContent ] , {
347+ type : 'text/csv' ,
348+ } ) ;
349+ const circularCsvFile = new File (
350+ [ circularCsvBlob ] ,
351+ 'circular-reference.csv' ,
352+ {
353+ type : 'text/csv' ,
354+ }
355+ ) ;
356+
357+ const fileInput = page . getByTestId ( 'upload-file-widget' ) ;
358+
359+ await fileInput ?. setInputFiles ( [
360+ {
361+ name : circularCsvFile . name ,
362+ mimeType : circularCsvFile . type ,
363+ buffer : Buffer . from ( await circularCsvFile . arrayBuffer ( ) ) ,
364+ } ,
365+ ] ) ;
366+
367+ await page . waitForTimeout ( 500 ) ;
368+
369+ await expect ( page . locator ( '.rdg-header-row' ) ) . toBeVisible ( ) ;
370+
371+ await page . getByRole ( 'button' , { name : 'Next' } ) . click ( ) ;
372+
373+ const loader = page . locator (
374+ '.inovua-react-toolkit-load-mask__background-layer'
375+ ) ;
376+
377+ await loader . waitFor ( { state : 'hidden' } ) ;
378+
379+ await validateImportStatus ( page , {
380+ passed : '3' ,
381+ processed : '4' ,
382+ failed : '1' ,
383+ } ) ;
384+
385+ const rows = await page . $$ ( '.rdg-row' ) ;
386+ const firstRow = rows [ 0 ] ;
387+ const detailsCell = await firstRow . $ ( '.rdg-cell-details' ) ;
388+ const errorText = await detailsCell ?. textContent ( ) ;
389+
390+ expect ( errorText ) . toContain (
391+ "Invalid hierarchy: Term 'Test CSV.name1' cannot be its own parent"
392+ ) ;
393+ }
394+ ) ;
395+ } finally {
396+ const { apiContext, afterAction } = await createNewPage ( browser ) ;
397+
398+ await circularRefGlossary . delete ( apiContext ) ;
399+ await afterAction ( ) ;
400+ }
401+ } ) ;
253402} ) ;
0 commit comments