From eeee4b9d0173f0c0e0be1cb54769a24632d8ff3e Mon Sep 17 00:00:00 2001 From: mahula Date: Sun, 5 Oct 2025 11:59:41 +0200 Subject: [PATCH] add itemsearch tests to cypress search testing --- cypress/e2e/search/item-search.cy.ts | 50 +++++++++++++++ cypress/eslint.config.mjs | 1 + cypress/support/commands.ts | 63 +++++++++++++++++++ .../Subcomponents/Controls/SearchControl.tsx | 12 +++- 4 files changed, 123 insertions(+), 3 deletions(-) create mode 100644 cypress/e2e/search/item-search.cy.ts diff --git a/cypress/e2e/search/item-search.cy.ts b/cypress/e2e/search/item-search.cy.ts new file mode 100644 index 00000000..b7790426 --- /dev/null +++ b/cypress/e2e/search/item-search.cy.ts @@ -0,0 +1,50 @@ +/// + +describe('Utopia Map Item Search', () => { + beforeEach(() => { + cy.clearCookies() + cy.clearLocalStorage() + cy.window().then((win) => { + win.sessionStorage.clear() + }) + + cy.visit('/') + cy.waitForMapReady() + }) + + it('should find items by exact name match', () => { + cy.searchFor('Tech Meetup Munich') + cy.get('[data-cy="search-suggestions"]').should('contain', 'Tech Meetup Munich') + }) + + it('should find items by partial name match (case insensitive)', () => { + cy.searchFor('café collaboration') + cy.get('[data-cy="search-suggestions"]').should('contain', 'Café Collaboration London') + }) + + it('should find items by text content', () => { + cy.searchFor('sustainability') + cy.get('[data-cy="search-suggestions"]').should('contain', 'Alex Entrepreneur') + }) + + it('should navigate to item profile when clicking search result', () => { + cy.intercept('GET', '**/items*').as('getItems') + + cy.visit('/') + cy.waitForMapReady() + + cy.searchFor('makerspace') + cy.get('[data-cy="search-suggestions"]').within(() => { + cy.get('[data-cy="search-item-result"]').contains('Makerspace Tokyo').click() + }) + + cy.url().should('match', /\/(item\/|[a-f0-9-]+)/) + cy.get('body').should('contain', 'Makerspace Tokyo') + + // Verify search uses local filtering (items already loaded) + cy.get('@getItems.all').then((calls) => { + expect(calls.length).to.be.greaterThan(0) + }) + }) + +}) diff --git a/cypress/eslint.config.mjs b/cypress/eslint.config.mjs index d0785a16..80634cae 100644 --- a/cypress/eslint.config.mjs +++ b/cypress/eslint.config.mjs @@ -87,6 +87,7 @@ export default tseslint.config( 'cypress/downloads/**', 'cypress/screenshots/**', 'cypress/videos/**', + 'results/**', 'dist/**', 'build/**', '*.min.js' diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index d526f674..72832e81 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -22,6 +22,43 @@ declare global { * @example cy.waitForMapReady() */ waitForMapReady(): Chainable + + /** + * Click on a map marker + * @example cy.clickMarker() // clicks first marker + */ + clickMarker(): Chainable + + /** + * Wait for a popup to appear on the map + * @example cy.waitForPopup() + */ + waitForPopup(): Chainable + + /** + * Close the currently open popup + * @example cy.closePopup() + */ + closePopup(): Chainable + + /** + * Toggle a layer's visibility in the layer control + * @param layerName - Name of the layer to toggle + * @example cy.toggleLayer('places') + */ + toggleLayer(layerName: string): Chainable + + /** + * Open the layer control panel + * @example cy.openLayerControl() + */ + openLayerControl(): Chainable + + /** + * Close the layer control panel + * @example cy.closeLayerControl() + */ + closeLayerControl(): Chainable } } } @@ -42,4 +79,30 @@ Cypress.Commands.add('waitForMapReady', () => { cy.get('.leaflet-marker-icon', { timeout: 15000 }).should('have.length.at.least', 1) }) +Cypress.Commands.add('clickMarker', () => { + // For now, always use force click since markers might be clustered or outside viewport + cy.get('.leaflet-marker-icon').first().click({ force: true }) +}) + +Cypress.Commands.add('waitForPopup', () => { + cy.get('[data-cy="item-popup"]', { timeout: 10000 }).should('be.visible') +}) + +Cypress.Commands.add('closePopup', () => { + cy.get('.leaflet-popup-close-button').click() +}) + +Cypress.Commands.add('toggleLayer', (layerName: string) => { + cy.get(`[data-cy="layer-checkbox-${layerName}"]`).click() +}) + +Cypress.Commands.add('openLayerControl', () => { + cy.get('[data-cy="layer-control-button"]').click() + cy.get('[data-cy="layer-control-panel"]', { timeout: 5000 }).should('be.visible') +}) + +Cypress.Commands.add('closeLayerControl', () => { + cy.get('[data-cy="layer-control-close"]').click() +}) + export {} diff --git a/lib/src/Components/Map/Subcomponents/Controls/SearchControl.tsx b/lib/src/Components/Map/Subcomponents/Controls/SearchControl.tsx index 1193cbe2..05f1a300 100644 --- a/lib/src/Components/Map/Subcomponents/Controls/SearchControl.tsx +++ b/lib/src/Components/Map/Subcomponents/Controls/SearchControl.tsx @@ -113,6 +113,7 @@ export const SearchControl = () => { autoComplete='off' value={value} className='tw:input tw:input-bordered tw:h-12 tw:grow tw:shadow-xl tw:rounded-box tw:pr-12 tw:w-full' + data-cy='search-input' ref={searchInput} onChange={(e) => setValue(e.target.value)} onFocus={() => { @@ -124,6 +125,7 @@ export const SearchControl = () => { {value.length > 0 && (