@@ -507,8 +507,153 @@ test.describe('Display Layout', () => {
507507 // In real time mode, we don't fetch annotations at all
508508 await expect . poll ( ( ) => networkRequests , { timeout : 10000 } ) . toHaveLength ( 0 ) ;
509509 } ) ;
510+
511+ test ( 'Same objects with different request options have unique subscriptions' , async ( {
512+ page
513+ } ) => {
514+ // Expand My Items
515+ await page . getByLabel ( 'Expand My Items folder' ) . click ( ) ;
516+
517+ // Create a Display Layout
518+ const displayLayout = await createDomainObjectWithDefaults ( page , {
519+ type : 'Display Layout' ,
520+ name : 'Test Display'
521+ } ) ;
522+
523+ // Create a State Generator, set to higher frequency updates
524+ const stateGenerator = await createDomainObjectWithDefaults ( page , {
525+ type : 'State Generator' ,
526+ name : 'State Generator'
527+ } ) ;
528+ const stateGeneratorTreeItem = page . getByRole ( 'treeitem' , {
529+ name : stateGenerator . name
530+ } ) ;
531+ await stateGeneratorTreeItem . click ( { button : 'right' } ) ;
532+ await page . getByLabel ( 'Edit Properties...' ) . click ( ) ;
533+ await page . getByLabel ( 'State Duration (seconds)' , { exact : true } ) . fill ( '0.1' ) ;
534+ await page . getByLabel ( 'Save' ) . click ( ) ;
535+
536+ // Create a Table for filtering ON values
537+ const tableFilterOnValue = await createDomainObjectWithDefaults ( page , {
538+ type : 'Telemetry Table' ,
539+ name : 'Table Filter On Value'
540+ } ) ;
541+ const tableFilterOnTreeItem = page . getByRole ( 'treeitem' , {
542+ name : tableFilterOnValue . name
543+ } ) ;
544+
545+ // Create a Table for filtering OFF values
546+ const tableFilterOffValue = await createDomainObjectWithDefaults ( page , {
547+ type : 'Telemetry Table' ,
548+ name : 'Table Filter Off Value'
549+ } ) ;
550+ const tableFilterOffTreeItem = page . getByRole ( 'treeitem' , {
551+ name : tableFilterOffValue . name
552+ } ) ;
553+
554+ // Navigate to ON filtering table and add state generator and setup filters
555+ await page . goto ( tableFilterOnValue . url ) ;
556+ await stateGeneratorTreeItem . dragTo ( page . getByLabel ( 'Object View' ) ) ;
557+ await selectFilterOption ( page , '1' ) ;
558+ await page . getByLabel ( 'Save' ) . click ( ) ;
559+ await page . getByRole ( 'listitem' , { name : 'Save and Finish Editing' } ) . click ( ) ;
560+
561+ // Navigate to OFF filtering table and add state generator and setup filters
562+ await page . goto ( tableFilterOffValue . url ) ;
563+ await stateGeneratorTreeItem . dragTo ( page . getByLabel ( 'Object View' ) ) ;
564+ await selectFilterOption ( page , '0' ) ;
565+ await page . getByLabel ( 'Save' ) . click ( ) ;
566+ await page . getByRole ( 'listitem' , { name : 'Save and Finish Editing' } ) . click ( ) ;
567+
568+ // Navigate to the display layout and edit it
569+ await page . goto ( displayLayout . url ) ;
570+
571+ // Add the tables to the display layout
572+ await page . getByLabel ( 'Edit Object' ) . click ( ) ;
573+ await tableFilterOffTreeItem . dragTo ( page . getByLabel ( 'Layout Grid' ) , {
574+ targetPosition : { x : 10 , y : 300 }
575+ } ) ;
576+ await page . locator ( '.c-frame-edit > div:nth-child(4)' ) . dragTo ( page . getByLabel ( 'Layout Grid' ) , {
577+ targetPosition : { x : 400 , y : 500 } ,
578+ // eslint-disable-next-line playwright/no-force-option
579+ force : true
580+ } ) ;
581+ await tableFilterOnTreeItem . dragTo ( page . getByLabel ( 'Layout Grid' ) , {
582+ targetPosition : { x : 10 , y : 100 }
583+ } ) ;
584+ await page . locator ( '.c-frame-edit > div:nth-child(4)' ) . dragTo ( page . getByLabel ( 'Layout Grid' ) , {
585+ targetPosition : { x : 400 , y : 300 } ,
586+ // eslint-disable-next-line playwright/no-force-option
587+ force : true
588+ } ) ;
589+ await page . getByLabel ( 'Save' ) . click ( ) ;
590+ await page . getByRole ( 'listitem' , { name : 'Save and Finish Editing' } ) . click ( ) ;
591+
592+ // Get the tables so we can verify filtering is working as expected
593+ const tableFilterOn = page . getByLabel ( `${ tableFilterOnValue . name } Frame` , {
594+ exact : true
595+ } ) ;
596+ const tableFilterOff = page . getByLabel ( `${ tableFilterOffValue . name } Frame` , {
597+ exact : true
598+ } ) ;
599+
600+ // Verify filtering is working correctly
601+
602+ // Create a promise that resolves when we've seen enough new rows added
603+ const rowsMutationPromise = page . evaluate ( ( ) => {
604+ return new Promise ( ( resolve ) => {
605+ const targetTable = document . querySelector (
606+ 'table[aria-label="Table Filter Off Value table content"]'
607+ ) ;
608+ const config = { childList : true , subtree : true } ;
609+ let changeCount = 0 ;
610+ const requiredChanges = 20 ; // Number of changes to wait for
611+
612+ const observer = new MutationObserver ( ( mutations ) => {
613+ mutations . forEach ( ( mutation ) => {
614+ if ( mutation . type === 'childList' ) {
615+ // Count added nodes
616+ changeCount += mutation . addedNodes . length ;
617+ }
618+ } ) ;
619+
620+ // Check if the required number of changes has been met
621+ if ( changeCount >= requiredChanges ) {
622+ observer . disconnect ( ) ; // Disconnect observer after the required changes
623+ resolve ( ) ;
624+ }
625+ } ) ;
626+
627+ observer . observe ( targetTable , config ) ;
628+ } ) ;
629+ } ) ;
630+
631+ await rowsMutationPromise ;
632+
633+ // Check ON table doesn't have any OFF values
634+ await expect ( tableFilterOn . locator ( 'td[title="OFF"]' ) ) . toHaveCount ( 0 ) ;
635+ const onCount = await tableFilterOn . locator ( 'td[title="ON"]' ) . count ( ) ;
636+ await expect ( onCount ) . toBeGreaterThan ( 0 ) ;
637+
638+ // Check OFF table doesn't have any ON values
639+ await expect ( tableFilterOff . locator ( 'td[title="ON"]' ) ) . toHaveCount ( 0 ) ;
640+ const offCount = await tableFilterOff . locator ( 'td[title="OFF"]' ) . count ( ) ;
641+ await expect ( offCount ) . toBeGreaterThan ( 0 ) ;
642+ } ) ;
510643} ) ;
511644
645+ async function selectFilterOption ( page , filterOption ) {
646+ await page . getByRole ( 'tab' , { name : 'Filters' } ) . click ( ) ;
647+ await page
648+ . getByLabel ( 'Inspector Views' )
649+ . locator ( 'li' )
650+ . filter ( { hasText : 'State Generator' } )
651+ . locator ( 'span' )
652+ . click ( ) ;
653+ await page . getByRole ( 'switch' ) . click ( ) ;
654+ await page . selectOption ( 'select[name="setSelectionThreshold"]' , filterOption ) ;
655+ }
656+
512657async function addAndRemoveDrawingObjectAndAssert ( page , layoutObject , DISPLAY_LAYOUT_NAME ) {
513658 await expect ( page . getByLabel ( layoutObject , { exact : true } ) ) . toHaveCount ( 0 ) ;
514659 await addLayoutObject ( page , DISPLAY_LAYOUT_NAME , layoutObject ) ;
0 commit comments