@@ -70,4 +70,147 @@ test.describe("Machine Filtering and Sorting", () => {
7070 page . getByRole ( "button" , { name : "Open Issues (Most)" } )
7171 ) . toBeVisible ( ) ;
7272 } ) ;
73+
74+ test ( "user can filter machines by status" , async ( { page } ) => {
75+ await page . goto ( "/m" ) ;
76+ await expect ( page . getByRole ( "heading" , { name : "Machines" } ) ) . toBeVisible ( ) ;
77+
78+ // Open Status filter dropdown (MultiSelect button containing "Status" text)
79+ const statusFilter = page
80+ . getByRole ( "combobox" )
81+ . filter ( { hasText : "Status" } ) ;
82+ await statusFilter . click ( ) ;
83+
84+ // Select "Unplayable" status from the dropdown
85+ await page . getByRole ( "option" , { name : "Unplayable" } ) . click ( ) ;
86+
87+ // Close the dropdown
88+ await page . keyboard . press ( "Escape" ) ;
89+
90+ // Wait for URL to update with status filter
91+ await expect ( page ) . toHaveURL ( / s t a t u s = u n p l a y a b l e / ) ;
92+
93+ // Eight Ball Deluxe should be visible (it has an unplayable issue)
94+ await expect (
95+ page . getByRole ( "link" , { name : / E i g h t B a l l D e l u x e / i } )
96+ ) . toBeVisible ( ) ;
97+
98+ // Machines without unplayable status should not be visible
99+ await expect (
100+ page . getByRole ( "link" , { name : / A t t a c k f r o m M a r s / i } )
101+ ) . not . toBeVisible ( ) ;
102+ await expect (
103+ page . getByRole ( "link" , { name : / M e d i e v a l M a d n e s s / i } )
104+ ) . not . toBeVisible ( ) ;
105+
106+ // Verify filter badge appears (shows count)
107+ await expect ( statusFilter . getByText ( "1" ) ) . toBeVisible ( ) ;
108+ } ) ;
109+
110+ test ( "user can filter machines by owner" , async ( { page } ) => {
111+ await page . goto ( "/m" ) ;
112+ await expect ( page . getByRole ( "heading" , { name : "Machines" } ) ) . toBeVisible ( ) ;
113+
114+ // Open Owner filter dropdown
115+ const ownerFilter = page . getByRole ( "combobox" ) . filter ( { hasText : "Owner" } ) ;
116+ await ownerFilter . click ( ) ;
117+
118+ // Select "Member User" as owner
119+ await page . getByRole ( "option" , { name : "Member User" } ) . click ( ) ;
120+
121+ // Close the dropdown
122+ await page . keyboard . press ( "Escape" ) ;
123+
124+ // Wait for URL to update with owner filter
125+ await expect ( page ) . toHaveURL ( / o w n e r = / ) ;
126+
127+ // Member owns: Slick Chick, Eight Ball Deluxe, Attack from Mars
128+ await expect (
129+ page . getByRole ( "link" , { name : / E i g h t B a l l D e l u x e / i } )
130+ ) . toBeVisible ( ) ;
131+ await expect (
132+ page . getByRole ( "link" , { name : / A t t a c k f r o m M a r s / i } )
133+ ) . toBeVisible ( ) ;
134+
135+ // Admin-owned machines should not be visible
136+ await expect (
137+ page . getByRole ( "link" , { name : / M e d i e v a l M a d n e s s / i } )
138+ ) . not . toBeVisible ( ) ;
139+ await expect (
140+ page . getByRole ( "link" , { name : / G o d z i l l a / i } )
141+ ) . not . toBeVisible ( ) ;
142+ } ) ;
143+
144+ test ( "user can combine multiple filters" , async ( { page } ) => {
145+ await page . goto ( "/m" ) ;
146+ await expect ( page . getByRole ( "heading" , { name : "Machines" } ) ) . toBeVisible ( ) ;
147+
148+ // First apply search filter
149+ const searchInput = page . getByPlaceholder (
150+ "Search machines by name or initials..."
151+ ) ;
152+ await searchInput . fill ( "Ball" ) ;
153+ await expect ( page ) . toHaveURL ( / q = B a l l / ) ;
154+
155+ // Then apply status filter
156+ const statusFilter = page
157+ . getByRole ( "combobox" )
158+ . filter ( { hasText : "Status" } ) ;
159+ await statusFilter . click ( ) ;
160+ await page . getByRole ( "option" , { name : "Unplayable" } ) . click ( ) ;
161+ await page . keyboard . press ( "Escape" ) ;
162+
163+ // Wait for both filters in URL
164+ await expect ( page ) . toHaveURL ( / q = B a l l / ) ;
165+ await expect ( page ) . toHaveURL ( / s t a t u s = u n p l a y a b l e / ) ;
166+
167+ // Only Eight Ball Deluxe matches both "Ball" search AND "Unplayable" status
168+ await expect (
169+ page . getByRole ( "link" , { name : / E i g h t B a l l D e l u x e / i } )
170+ ) . toBeVisible ( ) ;
171+
172+ // Fireball matches "Ball" but isn't unplayable
173+ await expect (
174+ page . getByRole ( "link" , { name : / F i r e b a l l / i } )
175+ ) . not . toBeVisible ( ) ;
176+ } ) ;
177+
178+ test ( "user can clear filters via Clear All button" , async ( { page } ) => {
179+ await page . goto ( "/m" ) ;
180+
181+ // Apply a status filter
182+ const statusFilter = page
183+ . getByRole ( "combobox" )
184+ . filter ( { hasText : "Status" } ) ;
185+ await statusFilter . click ( ) ;
186+ await page . getByRole ( "option" , { name : "Unplayable" } ) . click ( ) ;
187+ await page . keyboard . press ( "Escape" ) ;
188+
189+ await expect ( page ) . toHaveURL ( / s t a t u s = u n p l a y a b l e / ) ;
190+
191+ // Only Eight Ball Deluxe should be visible before clearing
192+ await expect (
193+ page . getByRole ( "link" , { name : / E i g h t B a l l D e l u x e / i } )
194+ ) . toBeVisible ( ) ;
195+ await expect (
196+ page . getByRole ( "link" , { name : / A t t a c k f r o m M a r s / i } )
197+ ) . not . toBeVisible ( ) ;
198+
199+ // Click Clear All
200+ await page . getByRole ( "button" , { name : "Clear All" } ) . click ( ) ;
201+
202+ // URL should no longer have the specific unplayable filter
203+ await expect ( page ) . not . toHaveURL ( / s t a t u s = u n p l a y a b l e / ) ;
204+
205+ // All machines should be visible again
206+ await expect (
207+ page . getByRole ( "link" , { name : / A t t a c k f r o m M a r s / i } )
208+ ) . toBeVisible ( ) ;
209+ await expect (
210+ page . getByRole ( "link" , { name : / M e d i e v a l M a d n e s s / i } )
211+ ) . toBeVisible ( ) ;
212+ await expect (
213+ page . getByRole ( "link" , { name : / E i g h t B a l l D e l u x e / i } )
214+ ) . toBeVisible ( ) ;
215+ } ) ;
73216} ) ;
0 commit comments