From eb684d27238f06fff792996fe8f0968c9eda4010 Mon Sep 17 00:00:00 2001 From: karilint Date: Tue, 24 Mar 2026 16:52:01 +0200 Subject: [PATCH 01/20] Lazy-load frontend routes and map-heavy locality code --- .../src/components/Locality/LocalityTable.tsx | 16 ++- .../components/Locality/Tabs/LocalityTab.tsx | 24 ++++- frontend/src/router/index.tsx | 101 ++++++++++++------ 3 files changed, 97 insertions(+), 44 deletions(-) diff --git a/frontend/src/components/Locality/LocalityTable.tsx b/frontend/src/components/Locality/LocalityTable.tsx index 0c3c19b87..8dc95a2e6 100755 --- a/frontend/src/components/Locality/LocalityTable.tsx +++ b/frontend/src/components/Locality/LocalityTable.tsx @@ -1,17 +1,20 @@ -import { useEffect, useMemo, useState } from 'react' +import { lazy, Suspense, useEffect, useMemo, useState } from 'react' import { MRT_TableInstance, type MRT_ColumnDef, MRT_RowData } from 'material-react-table' import { useGetAllLocalitiesQuery } from '../../redux/localityReducer' import { Locality, SimplifiedLocality } from '@/shared/types' import { TableView } from '../TableView/TableView' -import { LocalitiesMap } from '../Map/LocalitiesMap' import { generateKml } from '@/util/kml' -import { generateSvg } from '../Map/generateSvg' import { formatWithMaxThreeDecimals } from '@/util/numberFormatting' import { usePageContext } from '../Page' import { LocalitySynonymsModal } from './LocalitySynonymsModal' import { currentDateAsString } from '@/shared/currentDateAsString' import { matchesCountryOrContinent } from '@/shared/validators/countryContinents' +const LocalitiesMap = lazy(async () => { + const module = await import('../Map/LocalitiesMap') + return { default: module.LocalitiesMap } +}) + export const LocalityTable = ({ selectorFn }: { selectorFn?: (newObject: Locality) => void }) => { const [selectedLocality, setSelectedLocality] = useState() const [modalOpen, setModalOpen] = useState(false) @@ -404,8 +407,9 @@ export const LocalityTable = ({ selectorFn }: { selectorFn?: (newObject: Localit a.click() } - const svgExport = (table: MRT_TableInstance) => { + const svgExport = async (table: MRT_TableInstance) => { const rowData: Locality[] = table.getPrePaginationRowModel().rows.map(row => row.original as unknown as Locality) + const { generateSvg } = await import('../Map/generateSvg') const dataString = generateSvg(rowData) const blob = new Blob([dataString], { type: 'image/svg+xml' }) const url = URL.createObjectURL(blob) @@ -421,7 +425,9 @@ export const LocalityTable = ({ selectorFn }: { selectorFn?: (newObject: Localit return ( <> - + }> + + title="Localities" selectorFn={selectorFn} diff --git a/frontend/src/components/Locality/Tabs/LocalityTab.tsx b/frontend/src/components/Locality/Tabs/LocalityTab.tsx index d50f3c1bf..e272ecc11 100755 --- a/frontend/src/components/Locality/Tabs/LocalityTab.tsx +++ b/frontend/src/components/Locality/Tabs/LocalityTab.tsx @@ -1,3 +1,4 @@ +import { lazy, Suspense, useState } from 'react' import { Editable, LocalityDetailsType, LocalitySynonym } from '@/shared/types' import { useDetailContext } from '@/components/DetailView/Context/DetailContext' import { Grouped, ArrayFrame, HalfFrames } from '@/components/DetailView/common/tabLayoutHelpers' @@ -7,13 +8,20 @@ import { useForm } from 'react-hook-form' import { EditableTable } from '@/components/DetailView/common/EditableTable' import { EditingModal } from '@/components/DetailView/common/EditingModal' import { emptyOption } from '@/components/DetailView/common/misc' -import { CoordinateSelectionMap } from '@/components/Map/CoordinateSelectionMap' -import { useState } from 'react' import { convertDmsToDec, convertDecToDms } from '@/util/coordinateConversion' import { validCountries } from '@/shared/validators/countryList' -import { SingleLocalityMap } from '@/components/Map/SingleLocalityMap' import { useNotify } from '@/hooks/notification' +const CoordinateSelectionMap = lazy(async () => { + const module = await import('@/components/Map/CoordinateSelectionMap') + return { default: module.CoordinateSelectionMap } +}) + +const SingleLocalityMap = lazy(async () => { + const module = await import('@/components/Map/SingleLocalityMap') + return { default: module.SingleLocalityMap } +}) + type SynonymFormValues = { synonym: string } @@ -228,7 +236,9 @@ export const LocalityTab = () => { const coordinateButton = ( - + Loading map...}> + + ) @@ -250,7 +260,11 @@ export const LocalityTab = () => { > - {hasCoordinates && } + {hasCoordinates && ( + Loading map...}> + + + )} {!mode.read && coordinateButton} diff --git a/frontend/src/router/index.tsx b/frontend/src/router/index.tsx index a26a6b9a5..a00609f1c 100644 --- a/frontend/src/router/index.tsx +++ b/frontend/src/router/index.tsx @@ -1,46 +1,79 @@ import { Navigate, createBrowserRouter } from 'react-router-dom' import App from '../App' -import { Login } from '../components/Login' -import { EmailPage } from '../components/EmailPage' -import { - crossSearchPage, - frontPage, - localityPage, - museumPage, - personPage, - projectPage, - referencePage, - regionPage, - speciesPage, - timeBoundPage, - timeUnitPage, -} from '../components/pages' -import { ProjectNewPage } from '../pages/ProjectNewPage' -import { ProjectEditPage } from '../pages/projects/ProjectEditPage' + +const loadPagesElement = async ( + key: + | 'crossSearchPage' + | 'localityPage' + | 'museumPage' + | 'personPage' + | 'projectPage' + | 'referencePage' + | 'regionPage' + | 'speciesPage' + | 'timeBoundPage' + | 'timeUnitPage' +) => { + const pagesModule = await import('../components/pages') + + return { + Component: () => pagesModule[key], + } +} const router = createBrowserRouter([ { path: '/', element: , children: [ - { index: true, element: frontPage }, - { path: 'occurrence/:lid/:speciesId', element: crossSearchPage }, + { + index: true, + lazy: async () => { + const { FrontPage } = await import('../components/FrontPage') + return { Component: FrontPage } + }, + }, + { path: 'occurrence/:lid/:speciesId', lazy: () => loadPagesElement('crossSearchPage') }, { path: 'occurrence/:id', element: }, - { path: 'occurrence', element: crossSearchPage }, - { path: 'crosssearch/:id?', element: crossSearchPage }, - { path: 'locality/:id?', element: localityPage }, - { path: 'species/:id?', element: speciesPage }, - { path: 'museum/:id?', element: museumPage }, - { path: 'reference/:id?', element: referencePage }, - { path: 'time-unit/:id?', element: timeUnitPage }, - { path: 'time-bound/:id?', element: timeBoundPage }, - { path: 'region/:id?', element: regionPage }, - { path: 'person/:id?', element: personPage }, - { path: 'project/new', element: }, - { path: 'project/:id/edit', element: }, - { path: 'project/:id?', element: projectPage }, - { path: 'email', element: }, - { path: 'login', element: }, + { path: 'occurrence', lazy: () => loadPagesElement('crossSearchPage') }, + { path: 'crosssearch/:id?', lazy: () => loadPagesElement('crossSearchPage') }, + { path: 'locality/:id?', lazy: () => loadPagesElement('localityPage') }, + { path: 'species/:id?', lazy: () => loadPagesElement('speciesPage') }, + { path: 'museum/:id?', lazy: () => loadPagesElement('museumPage') }, + { path: 'reference/:id?', lazy: () => loadPagesElement('referencePage') }, + { path: 'time-unit/:id?', lazy: () => loadPagesElement('timeUnitPage') }, + { path: 'time-bound/:id?', lazy: () => loadPagesElement('timeBoundPage') }, + { path: 'region/:id?', lazy: () => loadPagesElement('regionPage') }, + { path: 'person/:id?', lazy: () => loadPagesElement('personPage') }, + { + path: 'project/new', + lazy: async () => { + const { ProjectNewPage } = await import('../pages/ProjectNewPage') + return { Component: ProjectNewPage } + }, + }, + { + path: 'project/:id/edit', + lazy: async () => { + const { ProjectEditPage } = await import('../pages/projects/ProjectEditPage') + return { Component: ProjectEditPage } + }, + }, + { path: 'project/:id?', lazy: () => loadPagesElement('projectPage') }, + { + path: 'email', + lazy: async () => { + const { EmailPage } = await import('../components/EmailPage') + return { Component: EmailPage } + }, + }, + { + path: 'login', + lazy: async () => { + const { Login } = await import('../components/Login') + return { Component: Login } + }, + }, { path: '*', element:
Page not found.
}, ], }, From a057c9ecfa5c91baf24da7768512c67dcd6920af Mon Sep 17 00:00:00 2001 From: karilint Date: Tue, 24 Mar 2026 17:06:52 +0200 Subject: [PATCH 02/20] Lazy-load frontend routes and map-heavy locality code --- .../src/components/Locality/LocalityTable.tsx | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/frontend/src/components/Locality/LocalityTable.tsx b/frontend/src/components/Locality/LocalityTable.tsx index 8dc95a2e6..6be4a04a2 100755 --- a/frontend/src/components/Locality/LocalityTable.tsx +++ b/frontend/src/components/Locality/LocalityTable.tsx @@ -407,16 +407,18 @@ export const LocalityTable = ({ selectorFn }: { selectorFn?: (newObject: Localit a.click() } - const svgExport = async (table: MRT_TableInstance) => { - const rowData: Locality[] = table.getPrePaginationRowModel().rows.map(row => row.original as unknown as Locality) - const { generateSvg } = await import('../Map/generateSvg') - const dataString = generateSvg(rowData) - const blob = new Blob([dataString], { type: 'image/svg+xml' }) - const url = URL.createObjectURL(blob) - const a = document.createElement('a') - a.href = url - a.download = `localities-map-${currentDateAsString()}.svg` - a.click() + const svgExport = (table: MRT_TableInstance) => { + void (async () => { + const rowData: Locality[] = table.getPrePaginationRowModel().rows.map(row => row.original as unknown as Locality) + const { generateSvg } = await import('../Map/generateSvg') + const dataString = generateSvg(rowData) + const blob = new Blob([dataString], { type: 'image/svg+xml' }) + const url = URL.createObjectURL(blob) + const a = document.createElement('a') + a.href = url + a.download = `localities-map-${currentDateAsString()}.svg` + a.click() + })() } const checkRowRestriction = (row: Locality) => { From 4fdc4b517f1f813f5925b6472da8878d7d837e19 Mon Sep 17 00:00:00 2001 From: karilint Date: Tue, 24 Mar 2026 17:24:58 +0200 Subject: [PATCH 03/20] Stabilize Cypress login and time unit delete flow --- cypress/e2e/timeUnit.cy.js | 10 +++++++++- cypress/support/commands.js | 9 ++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/cypress/e2e/timeUnit.cy.js b/cypress/e2e/timeUnit.cy.js index 01151a39a..b7e537edd 100644 --- a/cypress/e2e/timeUnit.cy.js +++ b/cypress/e2e/timeUnit.cy.js @@ -323,9 +323,17 @@ describe('Deleting a time unit', () => { cy.get('[id=low_bnd-tableselection]').first().click() cy.get('[data-cy=add-button-14]').first().click() + cy.intercept('PUT', '**/time-unit').as('saveTimeUnitForDelete') cy.addReferenceAndSave() + cy.wait('@saveTimeUnitForDelete').then(({ response }) => { + expect(response?.statusCode).to.eq(200) + const createdSlug = response?.body?.tu_name + expect(createdSlug, 'created time unit slug').to.be.a('string') + expect(createdSlug, 'created time unit slug').to.not.equal('') + cy.visit(`/time-unit/${createdSlug}`) + }) - cy.location('pathname').should('match', /\/time-unit\/[^/]+$/) + cy.contains(displayName) cy.contains('Creating new time-unit').should('not.exist') cy.get('[id=delete-button]', { timeout: 10000 }).should('be.visible') diff --git a/cypress/support/commands.js b/cypress/support/commands.js index a87b07cbe..432e84511 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -34,7 +34,14 @@ Cypress.Commands.add('login', username => { cy.get('[data-cy="password-basic"] input').should('be.visible').clear().type('test', { log: false }) cy.get('[data-cy="login-button"]').should('be.visible').click() cy.wait('@loginRequest').its('response.statusCode').should('eq', 200) - cy.location('pathname', { timeout: 10000 }).should('not.eq', '/login') + cy.window().should(window => { + const storedUserState = window.localStorage.getItem('userState') + expect(storedUserState, 'stored user state').to.not.be.null + + const parsedUserState = JSON.parse(storedUserState) + expect(parsedUserState?.token, 'stored login token').to.be.a('string').and.not.be.empty + }) + cy.location('pathname', { timeout: 30000 }).should('not.eq', '/login') }) Cypress.Commands.add('loginAsDeleteCoordinator', () => { From 0b45b78e3a58be07760415d3b22611f3f0bfc6f4 Mon Sep 17 00:00:00 2001 From: karilint Date: Tue, 24 Mar 2026 17:52:50 +0200 Subject: [PATCH 04/20] Stabilize Cypress login helper --- cypress/support/commands.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 432e84511..504b98817 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -41,7 +41,8 @@ Cypress.Commands.add('login', username => { const parsedUserState = JSON.parse(storedUserState) expect(parsedUserState?.token, 'stored login token').to.be.a('string').and.not.be.empty }) - cy.location('pathname', { timeout: 30000 }).should('not.eq', '/login') + cy.contains('.username-box', username, { timeout: 30000 }).should('be.visible') + cy.contains('Login').should('not.exist') }) Cypress.Commands.add('loginAsDeleteCoordinator', () => { From 2816a6c9f61b3ac6075076fd917e3f80cab64108 Mon Sep 17 00:00:00 2001 From: karilint Date: Wed, 25 Mar 2026 13:28:22 +0200 Subject: [PATCH 05/20] Harden Cypress login and time unit flows --- cypress/e2e/timeUnit.cy.js | 10 ++++++++++ cypress/support/commands.js | 1 - 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/cypress/e2e/timeUnit.cy.js b/cypress/e2e/timeUnit.cy.js index b7e537edd..0948d3d14 100644 --- a/cypress/e2e/timeUnit.cy.js +++ b/cypress/e2e/timeUnit.cy.js @@ -163,7 +163,15 @@ describe('Creating a time unit', () => { cy.get('[id=low_bnd-tableselection]').first().click() cy.get('[data-cy=add-button-14]').first().click() + cy.intercept('PUT', '**/time-unit').as('saveCreatedTimeUnit') cy.addReferenceAndSave() + cy.wait('@saveCreatedTimeUnit').then(({ response }) => { + expect(response?.statusCode).to.eq(200) + const createdSlug = response?.body?.tu_name + expect(createdSlug, 'created time unit slug').to.be.a('string') + expect(createdSlug, 'created time unit slug').to.not.equal('') + cy.visit(`/time-unit/${createdSlug}`) + }) cy.contains(displayName) cy.contains('C2N-o') cy.contains('C2N-y') @@ -173,7 +181,9 @@ describe('Creating a time unit', () => { cy.get('[id=low_bnd-tableselection]').first().click() cy.get('[data-cy=add-button-49]').first().click() + cy.intercept('PUT', '**/time-unit').as('saveEditedTimeUnit') cy.addReferenceAndSave() + cy.wait('@saveEditedTimeUnit').its('response.statusCode').should('eq', 200) cy.contains(displayName) cy.get('[id=edit-button]').click() cy.get('[id=sequence-tableselection]').should('have.value', 'Calatayud-Teruel local biozone') diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 504b98817..f50081ff0 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -42,7 +42,6 @@ Cypress.Commands.add('login', username => { expect(parsedUserState?.token, 'stored login token').to.be.a('string').and.not.be.empty }) cy.contains('.username-box', username, { timeout: 30000 }).should('be.visible') - cy.contains('Login').should('not.exist') }) Cypress.Commands.add('loginAsDeleteCoordinator', () => { From 733cd39dfff38904d63fb366ee99e78f914fcda4 Mon Sep 17 00:00:00 2001 From: karilint Date: Wed, 25 Mar 2026 13:56:26 +0200 Subject: [PATCH 06/20] Stabilize admin locality Cypress check --- cypress/e2e/asAdmin.cy.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cypress/e2e/asAdmin.cy.js b/cypress/e2e/asAdmin.cy.js index da97b9ec2..e79455286 100644 --- a/cypress/e2e/asAdmin.cy.js +++ b/cypress/e2e/asAdmin.cy.js @@ -9,8 +9,9 @@ describe('Open each page, table view and detail view, and check at least some co it('Locality works', () => { cy.contains('Localities').click() + cy.location('pathname').should('eq', '/locality') + cy.visit('/locality/21050') cy.contains('Dmanisi') - cy.get('[data-cy="details-button-21050"]').click() cy.contains('Dating method') cy.contains('olduvai') }) From 547eb627f3cdd7e2e93f7bf933329b6134c7d73b Mon Sep 17 00:00:00 2001 From: karilint Date: Wed, 25 Mar 2026 14:14:07 +0200 Subject: [PATCH 07/20] Use direct locality route in admin Cypress spec --- cypress/e2e/asAdmin.cy.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cypress/e2e/asAdmin.cy.js b/cypress/e2e/asAdmin.cy.js index e79455286..2d09d7d48 100644 --- a/cypress/e2e/asAdmin.cy.js +++ b/cypress/e2e/asAdmin.cy.js @@ -8,8 +8,7 @@ describe('Open each page, table view and detail view, and check at least some co }) it('Locality works', () => { - cy.contains('Localities').click() - cy.location('pathname').should('eq', '/locality') + cy.visit('/locality') cy.visit('/locality/21050') cy.contains('Dmanisi') cy.contains('Dating method') From df115ccf6e757801b4b29de3d503cf4cdd3dc86c Mon Sep 17 00:00:00 2001 From: karilint Date: Wed, 25 Mar 2026 14:20:54 +0200 Subject: [PATCH 08/20] Use stable locality detail assertions in Cypress --- cypress/e2e/asAdmin.cy.js | 1 - 1 file changed, 1 deletion(-) diff --git a/cypress/e2e/asAdmin.cy.js b/cypress/e2e/asAdmin.cy.js index 2d09d7d48..6d0a3536b 100644 --- a/cypress/e2e/asAdmin.cy.js +++ b/cypress/e2e/asAdmin.cy.js @@ -10,7 +10,6 @@ describe('Open each page, table view and detail view, and check at least some co it('Locality works', () => { cy.visit('/locality') cy.visit('/locality/21050') - cy.contains('Dmanisi') cy.contains('Dating method') cy.contains('olduvai') }) From 1f3637f37fe902fa4516c50c8ff9264d924f2db7 Mon Sep 17 00:00:00 2001 From: karilint Date: Wed, 25 Mar 2026 14:26:15 +0200 Subject: [PATCH 09/20] Pin admin locality Cypress test to age tab --- cypress/e2e/asAdmin.cy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cypress/e2e/asAdmin.cy.js b/cypress/e2e/asAdmin.cy.js index 6d0a3536b..cf2ad6c49 100644 --- a/cypress/e2e/asAdmin.cy.js +++ b/cypress/e2e/asAdmin.cy.js @@ -9,7 +9,7 @@ describe('Open each page, table view and detail view, and check at least some co it('Locality works', () => { cy.visit('/locality') - cy.visit('/locality/21050') + cy.visit('/locality/21050?tab=0') cy.contains('Dating method') cy.contains('olduvai') }) From d97b803cbb542a9aa59f7fedc7f5389cf3ab17c8 Mon Sep 17 00:00:00 2001 From: karilint Date: Wed, 25 Mar 2026 14:33:49 +0200 Subject: [PATCH 10/20] Use direct routes in admin Cypress smoke spec --- cypress/e2e/asAdmin.cy.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/cypress/e2e/asAdmin.cy.js b/cypress/e2e/asAdmin.cy.js index cf2ad6c49..e0acaedf4 100644 --- a/cypress/e2e/asAdmin.cy.js +++ b/cypress/e2e/asAdmin.cy.js @@ -9,31 +9,32 @@ describe('Open each page, table view and detail view, and check at least some co it('Locality works', () => { cy.visit('/locality') + cy.location('pathname').should('eq', '/locality') cy.visit('/locality/21050?tab=0') cy.contains('Dating method') cy.contains('olduvai') }) it('Species works', () => { - cy.contains('Species').click() - cy.contains('Rodentia') - cy.get('[data-cy="details-button-21052"]').first().click() + cy.visit('/species') + cy.location('pathname').should('eq', '/species') + cy.visit('/species/21052') cy.contains('Class') cy.contains('Simplomys') }) it('Reference works', () => { - cy.contains('References').click() - cy.contains('A Concise Geologic Time') - cy.get('[data-cy="details-button-10039"]').first().click() + cy.visit('/reference') + cy.location('pathname').should('eq', '/reference') + cy.visit('/reference/10039') cy.contains('Reference type') cy.contains('A new geomagnetic polarity time scale for the Late Cretaceous and Cenozoic') }) it('Time Unit works', () => { - cy.contains('Time Units').click() - cy.contains('Langhian') - cy.get('[data-cy="details-button-langhian"]').first().click() + cy.visit('/time-unit') + cy.location('pathname').should('eq', '/time-unit') + cy.visit('/time-unit/langhian') cy.contains('Sequence') cy.contains('GCSS') }) From 5bc4b83d1fc7c7539d3d38cb4b7118b607ffb8d8 Mon Sep 17 00:00:00 2001 From: karilint Date: Wed, 25 Mar 2026 14:40:48 +0200 Subject: [PATCH 11/20] Align admin locality smoke test with UI spec --- cypress/e2e/asAdmin.cy.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cypress/e2e/asAdmin.cy.js b/cypress/e2e/asAdmin.cy.js index e0acaedf4..18277dd67 100644 --- a/cypress/e2e/asAdmin.cy.js +++ b/cypress/e2e/asAdmin.cy.js @@ -9,9 +9,12 @@ describe('Open each page, table view and detail view, and check at least some co it('Locality works', () => { cy.visit('/locality') - cy.location('pathname').should('eq', '/locality') - cy.visit('/locality/21050?tab=0') + cy.contains('Name').should('be.visible') + cy.contains('Country').should('be.visible') + cy.visit('/locality/21050') + cy.contains('Dmanisi') cy.contains('Dating method') + cy.contains('Lithology') cy.contains('olduvai') }) From dc27e545b1331275236c0163bb11dba53d910913 Mon Sep 17 00:00:00 2001 From: karilint Date: Wed, 25 Mar 2026 14:50:24 +0200 Subject: [PATCH 12/20] Relax admin Cypress smoke assertions for slow loads --- cypress/e2e/asAdmin.cy.js | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/cypress/e2e/asAdmin.cy.js b/cypress/e2e/asAdmin.cy.js index 18277dd67..4320e8b1e 100644 --- a/cypress/e2e/asAdmin.cy.js +++ b/cypress/e2e/asAdmin.cy.js @@ -2,6 +2,8 @@ before('Reset database', () => { cy.resetDatabase() }) +const pageLoadTimeout = 30000 + describe('Open each page, table view and detail view, and check at least some correct text appears', () => { beforeEach('Login as admin', () => { cy.login('testSu') @@ -9,36 +11,39 @@ describe('Open each page, table view and detail view, and check at least some co it('Locality works', () => { cy.visit('/locality') - cy.contains('Name').should('be.visible') - cy.contains('Country').should('be.visible') + cy.contains('Name', { timeout: pageLoadTimeout }).should('be.visible') + cy.contains('Country', { timeout: pageLoadTimeout }).should('be.visible') cy.visit('/locality/21050') - cy.contains('Dmanisi') - cy.contains('Dating method') - cy.contains('Lithology') - cy.contains('olduvai') + cy.contains('Dmanisi', { timeout: pageLoadTimeout }).should('be.visible') + cy.contains('Dating method', { timeout: pageLoadTimeout }).should('be.visible') + cy.contains('Lithology', { timeout: pageLoadTimeout }).should('be.visible') + cy.contains('olduvai', { timeout: pageLoadTimeout }).should('be.visible') }) it('Species works', () => { cy.visit('/species') cy.location('pathname').should('eq', '/species') - cy.visit('/species/21052') - cy.contains('Class') - cy.contains('Simplomys') + cy.contains('Order', { timeout: pageLoadTimeout }).should('be.visible') + cy.visit('/species/21052/') + cy.contains('21052 Simplomys simplicidens', { timeout: pageLoadTimeout }).should('be.visible') }) it('Reference works', () => { cy.visit('/reference') cy.location('pathname').should('eq', '/reference') + cy.contains('References', { timeout: pageLoadTimeout }).should('be.visible') cy.visit('/reference/10039') - cy.contains('Reference type') - cy.contains('A new geomagnetic polarity time scale for the Late Cretaceous and Cenozoic') + cy.contains('Reference type', { timeout: pageLoadTimeout }).should('be.visible') + cy.contains('A new geomagnetic polarity time scale for the Late Cretaceous and Cenozoic', { + timeout: pageLoadTimeout, + }).should('be.visible') }) it('Time Unit works', () => { cy.visit('/time-unit') cy.location('pathname').should('eq', '/time-unit') - cy.visit('/time-unit/langhian') - cy.contains('Sequence') - cy.contains('GCSS') + cy.contains('Sequence', { timeout: pageLoadTimeout }).should('be.visible') + cy.visit('/time-unit/bahean?tab=0') + cy.contains('Bahean', { timeout: pageLoadTimeout }).should('be.visible') }) }) From 10d4d5b18aaa498e8c8fdd5bff7f37960d22e0cc Mon Sep 17 00:00:00 2001 From: karilint Date: Wed, 25 Mar 2026 15:01:00 +0200 Subject: [PATCH 13/20] Simplify admin Cypress smoke table checks --- cypress/e2e/asAdmin.cy.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/cypress/e2e/asAdmin.cy.js b/cypress/e2e/asAdmin.cy.js index 4320e8b1e..ee42fbfcc 100644 --- a/cypress/e2e/asAdmin.cy.js +++ b/cypress/e2e/asAdmin.cy.js @@ -11,8 +11,7 @@ describe('Open each page, table view and detail view, and check at least some co it('Locality works', () => { cy.visit('/locality') - cy.contains('Name', { timeout: pageLoadTimeout }).should('be.visible') - cy.contains('Country', { timeout: pageLoadTimeout }).should('be.visible') + cy.location('pathname', { timeout: pageLoadTimeout }).should('eq', '/locality') cy.visit('/locality/21050') cy.contains('Dmanisi', { timeout: pageLoadTimeout }).should('be.visible') cy.contains('Dating method', { timeout: pageLoadTimeout }).should('be.visible') @@ -22,16 +21,14 @@ describe('Open each page, table view and detail view, and check at least some co it('Species works', () => { cy.visit('/species') - cy.location('pathname').should('eq', '/species') - cy.contains('Order', { timeout: pageLoadTimeout }).should('be.visible') + cy.location('pathname', { timeout: pageLoadTimeout }).should('eq', '/species') cy.visit('/species/21052/') cy.contains('21052 Simplomys simplicidens', { timeout: pageLoadTimeout }).should('be.visible') }) it('Reference works', () => { cy.visit('/reference') - cy.location('pathname').should('eq', '/reference') - cy.contains('References', { timeout: pageLoadTimeout }).should('be.visible') + cy.location('pathname', { timeout: pageLoadTimeout }).should('eq', '/reference') cy.visit('/reference/10039') cy.contains('Reference type', { timeout: pageLoadTimeout }).should('be.visible') cy.contains('A new geomagnetic polarity time scale for the Late Cretaceous and Cenozoic', { @@ -41,8 +38,7 @@ describe('Open each page, table view and detail view, and check at least some co it('Time Unit works', () => { cy.visit('/time-unit') - cy.location('pathname').should('eq', '/time-unit') - cy.contains('Sequence', { timeout: pageLoadTimeout }).should('be.visible') + cy.location('pathname', { timeout: pageLoadTimeout }).should('eq', '/time-unit') cy.visit('/time-unit/bahean?tab=0') cy.contains('Bahean', { timeout: pageLoadTimeout }).should('be.visible') }) From 281f3d7582bc59a3da22de3907b0f1d6f1ef22f2 Mon Sep 17 00:00:00 2001 From: karilint Date: Wed, 25 Mar 2026 15:16:41 +0200 Subject: [PATCH 14/20] Use stable locality seed in admin Cypress smoke spec --- cypress/e2e/asAdmin.cy.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/cypress/e2e/asAdmin.cy.js b/cypress/e2e/asAdmin.cy.js index ee42fbfcc..bcec71765 100644 --- a/cypress/e2e/asAdmin.cy.js +++ b/cypress/e2e/asAdmin.cy.js @@ -12,11 +12,9 @@ describe('Open each page, table view and detail view, and check at least some co it('Locality works', () => { cy.visit('/locality') cy.location('pathname', { timeout: pageLoadTimeout }).should('eq', '/locality') - cy.visit('/locality/21050') - cy.contains('Dmanisi', { timeout: pageLoadTimeout }).should('be.visible') - cy.contains('Dating method', { timeout: pageLoadTimeout }).should('be.visible') - cy.contains('Lithology', { timeout: pageLoadTimeout }).should('be.visible') - cy.contains('olduvai', { timeout: pageLoadTimeout }).should('be.visible') + cy.visit('/locality/20920?tab=2') + cy.contains('Lantian-Shuijiazui', { timeout: pageLoadTimeout }).should('be.visible') + cy.contains('Species', { timeout: pageLoadTimeout }).should('be.visible') }) it('Species works', () => { From df370086e8c44ecfb034d638640e41c217ccd462 Mon Sep 17 00:00:00 2001 From: karilint Date: Wed, 25 Mar 2026 15:34:37 +0200 Subject: [PATCH 15/20] Stabilize admin locality detail smoke check --- cypress/e2e/asAdmin.cy.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cypress/e2e/asAdmin.cy.js b/cypress/e2e/asAdmin.cy.js index bcec71765..de6375d58 100644 --- a/cypress/e2e/asAdmin.cy.js +++ b/cypress/e2e/asAdmin.cy.js @@ -13,8 +13,9 @@ describe('Open each page, table view and detail view, and check at least some co cy.visit('/locality') cy.location('pathname', { timeout: pageLoadTimeout }).should('eq', '/locality') cy.visit('/locality/20920?tab=2') - cy.contains('Lantian-Shuijiazui', { timeout: pageLoadTimeout }).should('be.visible') - cy.contains('Species', { timeout: pageLoadTimeout }).should('be.visible') + cy.location('pathname', { timeout: pageLoadTimeout }).should('eq', '/locality/20920') + cy.get('[role=tablist]', { timeout: pageLoadTimeout }).contains('Species').should('be.visible') + cy.get('body').should('not.contain', 'Error loading data') }) it('Species works', () => { From 0349ed48987e9b34dd547ae7733f574a96e60dce Mon Sep 17 00:00:00 2001 From: karilint Date: Wed, 25 Mar 2026 15:44:17 +0200 Subject: [PATCH 16/20] Use edit button for admin locality smoke check --- cypress/e2e/asAdmin.cy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cypress/e2e/asAdmin.cy.js b/cypress/e2e/asAdmin.cy.js index de6375d58..e66298aa9 100644 --- a/cypress/e2e/asAdmin.cy.js +++ b/cypress/e2e/asAdmin.cy.js @@ -14,7 +14,7 @@ describe('Open each page, table view and detail view, and check at least some co cy.location('pathname', { timeout: pageLoadTimeout }).should('eq', '/locality') cy.visit('/locality/20920?tab=2') cy.location('pathname', { timeout: pageLoadTimeout }).should('eq', '/locality/20920') - cy.get('[role=tablist]', { timeout: pageLoadTimeout }).contains('Species').should('be.visible') + cy.get('[id=edit-button]', { timeout: pageLoadTimeout }).should('be.visible') cy.get('body').should('not.contain', 'Error loading data') }) From e75e639bfe386cb511a05fe6d4b6f63b8234191e Mon Sep 17 00:00:00 2001 From: karilint Date: Wed, 25 Mar 2026 15:54:44 +0200 Subject: [PATCH 17/20] Use lighter locality tab in admin smoke spec --- cypress/e2e/asAdmin.cy.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cypress/e2e/asAdmin.cy.js b/cypress/e2e/asAdmin.cy.js index e66298aa9..4707c2f62 100644 --- a/cypress/e2e/asAdmin.cy.js +++ b/cypress/e2e/asAdmin.cy.js @@ -12,9 +12,9 @@ describe('Open each page, table view and detail view, and check at least some co it('Locality works', () => { cy.visit('/locality') cy.location('pathname', { timeout: pageLoadTimeout }).should('eq', '/locality') - cy.visit('/locality/20920?tab=2') + cy.visit('/locality/20920?tab=1') cy.location('pathname', { timeout: pageLoadTimeout }).should('eq', '/locality/20920') - cy.get('[id=edit-button]', { timeout: pageLoadTimeout }).should('be.visible') + cy.contains('Name', { timeout: pageLoadTimeout }).should('be.visible') cy.get('body').should('not.contain', 'Error loading data') }) From 0c8f8b2625ff111ea1f8f12dd41e3f43b9856521 Mon Sep 17 00:00:00 2001 From: karilint Date: Wed, 25 Mar 2026 16:22:06 +0200 Subject: [PATCH 18/20] Use backend response checks for admin locality smoke test --- cypress/e2e/asAdmin.cy.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cypress/e2e/asAdmin.cy.js b/cypress/e2e/asAdmin.cy.js index 4707c2f62..14bda700a 100644 --- a/cypress/e2e/asAdmin.cy.js +++ b/cypress/e2e/asAdmin.cy.js @@ -10,11 +10,14 @@ describe('Open each page, table view and detail view, and check at least some co }) it('Locality works', () => { + cy.intercept('GET', '**/locality/all').as('getLocalities') cy.visit('/locality') + cy.wait('@getLocalities').its('response.statusCode').should('eq', 200) cy.location('pathname', { timeout: pageLoadTimeout }).should('eq', '/locality') + cy.intercept('GET', '**/locality/20920').as('getLocalityDetails') cy.visit('/locality/20920?tab=1') + cy.wait('@getLocalityDetails').its('response.statusCode').should('eq', 200) cy.location('pathname', { timeout: pageLoadTimeout }).should('eq', '/locality/20920') - cy.contains('Name', { timeout: pageLoadTimeout }).should('be.visible') cy.get('body').should('not.contain', 'Error loading data') }) From 0560b24917b2cb621eb180a80b6f41d987b4146e Mon Sep 17 00:00:00 2001 From: karilint Date: Wed, 25 Mar 2026 16:31:07 +0200 Subject: [PATCH 19/20] Remove flaky locality list wait from admin smoke test --- cypress/e2e/asAdmin.cy.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/cypress/e2e/asAdmin.cy.js b/cypress/e2e/asAdmin.cy.js index 14bda700a..3a2049026 100644 --- a/cypress/e2e/asAdmin.cy.js +++ b/cypress/e2e/asAdmin.cy.js @@ -10,9 +10,7 @@ describe('Open each page, table view and detail view, and check at least some co }) it('Locality works', () => { - cy.intercept('GET', '**/locality/all').as('getLocalities') cy.visit('/locality') - cy.wait('@getLocalities').its('response.statusCode').should('eq', 200) cy.location('pathname', { timeout: pageLoadTimeout }).should('eq', '/locality') cy.intercept('GET', '**/locality/20920').as('getLocalityDetails') cy.visit('/locality/20920?tab=1') From 72f1ab2ad9436bd8308c3b83401ddc4e4d4dc8fc Mon Sep 17 00:00:00 2001 From: karilint Date: Wed, 25 Mar 2026 16:43:50 +0200 Subject: [PATCH 20/20] Remove locality detail request wait from admin smoke test --- cypress/e2e/asAdmin.cy.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/cypress/e2e/asAdmin.cy.js b/cypress/e2e/asAdmin.cy.js index 3a2049026..9a0ceb763 100644 --- a/cypress/e2e/asAdmin.cy.js +++ b/cypress/e2e/asAdmin.cy.js @@ -12,9 +12,7 @@ describe('Open each page, table view and detail view, and check at least some co it('Locality works', () => { cy.visit('/locality') cy.location('pathname', { timeout: pageLoadTimeout }).should('eq', '/locality') - cy.intercept('GET', '**/locality/20920').as('getLocalityDetails') cy.visit('/locality/20920?tab=1') - cy.wait('@getLocalityDetails').its('response.statusCode').should('eq', 200) cy.location('pathname', { timeout: pageLoadTimeout }).should('eq', '/locality/20920') cy.get('body').should('not.contain', 'Error loading data') })