Преглед изворни кода

Merge pull request #30983 from overleaf/cd-close-modal-select-menus-on-click

Ensure select menus in Modals close on modal click

GitOrigin-RevId: 4a07f16146ac99e6fb1fdf09d222e6832cc93079
Chris Dryden пре 8 месеци
родитељ
комит
a054938414

+ 3 - 1
services/web/frontend/js/shared/components/focus-trap.tsx

@@ -25,7 +25,9 @@ export default function FocusTrap({
         fallbackFocus: () => containerRef.current as HTMLElement,
       }}
     >
-      <div ref={containerRef}>{children}</div>
+      <div ref={containerRef} tabIndex={-1}>
+        {children}
+      </div>
     </FocusTrapReact>
   )
 }

+ 36 - 0
services/web/test/frontend/components/shared/modal.spec.tsx

@@ -6,10 +6,22 @@ import {
   OLModalFooter,
   OLModalTitle,
 } from '@/shared/components/ol/ol-modal'
+import { Select } from '@/shared/components/select'
+
+type TestItem = {
+  key: string
+  label: string
+}
 
 function Modal({ backdrop }: { backdrop?: boolean | 'static' } = {}) {
   const [isModalOpen, setIsModalOpen] = useState(false)
 
+  const testItems: TestItem[] = [
+    { key: 'item1', label: 'First Item' },
+    { key: 'item2', label: 'Second Item' },
+    { key: 'item3', label: 'Third Item' },
+  ]
+
   return (
     <div>
       <button onClick={() => setIsModalOpen(true)}>Open modal</button>
@@ -26,6 +38,13 @@ function Modal({ backdrop }: { backdrop?: boolean | 'static' } = {}) {
           <p>This is for testing the modal behaviour</p>
           <label htmlFor="modal-input">Enter text:&nbsp;</label>
           <input id="modal-input" />
+          <Select
+            items={testItems}
+            itemToKey={item => item.key}
+            itemToString={item => item?.label || ''}
+            dataTestId="test-select"
+            defaultText="Select an item"
+          />
         </OLModalBody>
         <OLModalFooter>
           <button onClick={() => setIsModalOpen(false)}>Close the modal</button>
@@ -74,6 +93,8 @@ describe('<OLModal />', function () {
     cy.focused().tab()
     cy.findByLabelText(/enter text/i).should('be.focused')
     cy.focused().tab()
+    cy.get('[data-testid="test-select"]').should('be.focused')
+    cy.focused().tab()
     cy.findByRole('button', { name: 'Close the modal' }).should('be.focused')
     cy.focused().tab()
     cy.findByRole('button', { name: 'Close dialog' }).should('be.focused')
@@ -81,6 +102,21 @@ describe('<OLModal />', function () {
     cy.findByRole('button', { name: 'Close the modal' }).should('be.focused')
   })
 
+  it('closes select menus when the modal container is clicked on', function () {
+    cy.mount(<Modal />)
+    cy.findByRole('button', { name: 'Open modal' }).click()
+    cy.get('[data-testid="test-select"]').click()
+
+    cy.contains('First Item').should('be.visible')
+    cy.contains('Second Item').should('be.visible')
+    cy.contains('Third Item').should('be.visible')
+
+    cy.findByText('This is for testing the modal behaviour').click()
+    cy.contains('First Item').should('not.exist')
+    cy.contains('Second Item').should('not.exist')
+    cy.contains('Third Item').should('not.exist')
+  })
+
   it('restores focus to trigger button after modal closes', function () {
     cy.mount(<Modal />)
     cy.findByRole('button', { name: 'Open modal' }).click()

+ 6 - 6
services/web/test/frontend/features/share-project-modal/components/share-project-modal.test.tsx

@@ -912,17 +912,17 @@ describe('<ShareProjectModal/>', function () {
 
     // Pressing Tab should add the entered item
     fireEvent.keyDown(inputElement, { key: 'Tab', code: 'Tab' })
-    await waitFor(() => {
-      expect(screen.getAllByRole('button', { name: /Remove/ })).to.have.length(
-        1
-      )
+    const collaborators = await waitFor(() => {
+      return screen.getAllByRole('button', { name: /Remove/ })
     })
 
+    expect(collaborators).to.not.be.null
+
     // Blurring the input should not add another contact
     fireEvent.blur(inputElement)
     await waitFor(() => {
-      expect(screen.getAllByRole('button', { name: /Remove/ })).to.have.length(
-        1
+      expect(screen.getAllByRole('button', { name: /Remove/ }).length).to.eql(
+        collaborators.length
       )
     })
   })