diff --git a/src/NotFoundPage.tsx b/src/NotFoundPage.tsx
new file mode 100644
index 000000000..be2754c69
--- /dev/null
+++ b/src/NotFoundPage.tsx
@@ -0,0 +1,10 @@
+import React from 'react'
+
+const NotFoundPage: React.FC = () => (
+
+
404 - Not Found
+
The page you are looking for does not exist.
+
+)
+
+export default NotFoundPage
diff --git a/src/router/aboutRoutes.tsx b/src/router/aboutRoutes.tsx
index 92d659b36..d0859656c 100644
--- a/src/router/aboutRoutes.tsx
+++ b/src/router/aboutRoutes.tsx
@@ -4,6 +4,7 @@ import About, { TabId, tabIds } from 'about/ui/about'
import { CachedMarkupService } from 'markup/application/MarkupService'
import { sitemapDefaults } from 'router/sitemap'
import { HeadTagsService } from 'router/head'
+import NotFoundPage from 'NotFoundPage'
import { newsletters } from 'about/ui/news'
// ToDo:
@@ -44,6 +45,11 @@ export default function AboutRoutes({
)}
{...(sitemap && sitemapDefaults)}
/>,
+ }
+ />,
(
(
(
(
,
+ }
+ />,
,
+ }
+ />,
]
}
diff --git a/src/router/dictionaryRoutes.tsx b/src/router/dictionaryRoutes.tsx
index b4995d33e..71ab629a2 100644
--- a/src/router/dictionaryRoutes.tsx
+++ b/src/router/dictionaryRoutes.tsx
@@ -9,6 +9,7 @@ import { Route } from 'react-router-dom'
import SignService from 'signs/application/SignService'
import { DictionarySlugs, sitemapDefaults } from 'router/sitemap'
import { HeadTagsService } from 'router/head'
+import NotFoundPage from 'NotFoundPage'
export default function DictionaryRoutes({
sitemap,
@@ -29,6 +30,7 @@ export default function DictionaryRoutes({
(
(
(
,
+ }
+ />,
]
}
diff --git a/src/router/fragmentariumRoutes.tsx b/src/router/fragmentariumRoutes.tsx
index 5ee436e67..9d65f8d97 100644
--- a/src/router/fragmentariumRoutes.tsx
+++ b/src/router/fragmentariumRoutes.tsx
@@ -22,7 +22,7 @@ import { HeadTagsService } from 'router/head'
import BibliographyService from 'bibliography/application/BibliographyService'
import { FindspotService } from 'fragmentarium/application/FindspotService'
import AfoRegisterService from 'afo-register/application/AfoRegisterService'
-
+import NotFoundPage from 'NotFoundPage'
function parseStringParam(location: Location, param: string): string | null {
const value = parse(location.search)[param]
return _.isArray(value) ? value.join('') : value
@@ -78,6 +78,7 @@ export default function FragmentariumRoutes({
(
(
(
(
{(session) => (
@@ -157,6 +161,7 @@ export default function FragmentariumRoutes({
(
,
+ }
+ />,
]
}
diff --git a/src/router/notFoundRoutes.test.tsx b/src/router/notFoundRoutes.test.tsx
new file mode 100644
index 000000000..aa7019f18
--- /dev/null
+++ b/src/router/notFoundRoutes.test.tsx
@@ -0,0 +1,177 @@
+import React from 'react'
+import { render, screen } from '@testing-library/react'
+import { Router, Switch } from 'react-router-dom'
+import { getServices } from 'test-support/AppDriver'
+import { createMemoryHistory } from 'history'
+import AboutRoutes from './aboutRoutes'
+import FragmentariumRoutes from './fragmentariumRoutes'
+import BibliographyRoutes from './bibliographyRoutes'
+import CorpusRoutes from './corpusRoutes'
+import DictionaryRoutes from './dictionaryRoutes'
+import SignRoutes from './signRoutes'
+import ToolsRoutes from './toolsRoutes'
+
+describe('NotFoundPage rendering in FragmentariumRoutes', () => {
+ const nonExistentRoutes = [
+ '/fragmentarium/search/non-existent',
+ '/fragmentarium/Fragment.12345/match/non-existent',
+ '/fragmentarium/Fragment.12345/annotate/non-existent',
+ '/fragmentarium/Fragment.12345/non-existent',
+ ]
+ nonExistentRoutes.forEach((path) => {
+ const history = createMemoryHistory({ initialEntries: [path] })
+ test(`renders NotFoundPage for "${path}"`, () => {
+ render(
+
+
+ {[...FragmentariumRoutes({ ...getServices(), sitemap: false })]}
+
+
+ )
+ expect(
+ screen.getByText(/The page you are looking for does not exist./i)
+ ).toBeInTheDocument()
+ })
+ })
+})
+
+describe('NotFoundPage rendering in AboutRoutes', () => {
+ const nonExistentAboutRoutes = [
+ '/about/non-existent-page',
+ '/about/invalid-section',
+ '/about/undefined-route',
+ ]
+ nonExistentAboutRoutes.forEach((path) => {
+ const history = createMemoryHistory({ initialEntries: [path] })
+ test(`renders NotFoundPage for "${path}"`, () => {
+ render(
+
+
+ {[...AboutRoutes({ ...getServices(), sitemap: false })]}
+
+
+ )
+ expect(
+ screen.getByText(/The page you are looking for does not exist./i)
+ ).toBeInTheDocument()
+ })
+ })
+})
+
+describe('NotFoundPage rendering in BibliographyRoutes', () => {
+ const nonExistentAboutRoutes = [
+ '/bibliography/search/non-existent',
+ '/bibliography/afo-register/non-existent-page',
+ '/bibliography/afo-register/invalid-section',
+ '/bibliography/afo-register/undefined-route',
+ ]
+ nonExistentAboutRoutes.forEach((path) => {
+ const history = createMemoryHistory({ initialEntries: [path] })
+ test(`renders NotFoundPage for "${path}"`, () => {
+ render(
+
+
+ {[...BibliographyRoutes({ ...getServices(), sitemap: false })]}
+
+
+ )
+ expect(
+ screen.getByText(/The page you are looking for does not exist./i)
+ ).toBeInTheDocument()
+ })
+ })
+})
+
+describe('NotFoundPage rendering in CorpusRoutes', () => {
+ const nonExistentAboutRoutes = [
+ '/corpus/Corpus.12345/non-existent-page',
+ '/corpus/Corpus.12345/invalid-section',
+ '/corpus/Corpus.12345/undefined-route',
+ ]
+ nonExistentAboutRoutes.forEach((path) => {
+ const history = createMemoryHistory({ initialEntries: [path] })
+ test(`renders NotFoundPage for "${path}"`, () => {
+ render(
+
+
+ {[...CorpusRoutes({ ...getServices(), sitemap: false })]}
+
+
+ )
+ expect(
+ screen.getByText(/The page you are looking for does not exist./i)
+ ).toBeInTheDocument()
+ })
+ })
+})
+
+describe('NotFoundPage rendering in DictionaryRoutes', () => {
+ const nonExistentAboutRoutes = [
+ '/dictionary/search/non-existent',
+ '/dictionary/Dictionary.12345/non-existent-page',
+ '/dictionary/Dictionary.12345/invalid-section',
+ '/dictionary/Dictionary.12345/undefined-route',
+ ]
+ nonExistentAboutRoutes.forEach((path) => {
+ const history = createMemoryHistory({ initialEntries: [path] })
+ test(`renders NotFoundPage for "${path}"`, () => {
+ render(
+
+
+ {[...DictionaryRoutes({ ...getServices(), sitemap: false })]}
+
+
+ )
+ expect(
+ screen.getByText(/The page you are looking for does not exist./i)
+ ).toBeInTheDocument()
+ })
+ })
+})
+
+describe('NotFoundPage rendering in SignRoutes', () => {
+ const nonExistentAboutRoutes = [
+ '/signs/search/non-existent',
+ '/signs/Signs.12345/non-existent-page',
+ '/signs/Signs.12345/invalid-section',
+ '/signs/Signs.12345/undefined-route',
+ ]
+ nonExistentAboutRoutes.forEach((path) => {
+ const history = createMemoryHistory({ initialEntries: [path] })
+ test(`renders NotFoundPage for "${path}"`, () => {
+ render(
+
+
+ {[...SignRoutes({ ...getServices(), sitemap: false })]}
+
+
+ )
+ expect(
+ screen.getByText(/The page you are looking for does not exist./i)
+ ).toBeInTheDocument()
+ })
+ })
+})
+
+describe('NotFoundPage rendering in ToolsRoutes', () => {
+ const nonExistentAboutRoutes = [
+ '/tools/date-converter/non-existent-page',
+ '/tools/date-converter/invalid-section',
+ '/tools/date-converter/undefined-route',
+ ]
+ nonExistentAboutRoutes.forEach((path) => {
+ const history = createMemoryHistory({ initialEntries: [path] })
+ test(`renders NotFoundPage for "${path}"`, () => {
+ render(
+
+
+ {[...ToolsRoutes({ ...getServices(), sitemap: false })]}
+
+
+ )
+ expect(
+ screen.getByText(/The page you are looking for does not exist./i)
+ ).toBeInTheDocument()
+ })
+ })
+})
diff --git a/src/router/router.tsx b/src/router/router.tsx
index 2577bcb17..cbcb5b1fe 100644
--- a/src/router/router.tsx
+++ b/src/router/router.tsx
@@ -24,6 +24,7 @@ import ToolsRoutes from 'router/toolsRoutes'
import Sitemap, { sitemapDefaults, Slugs } from 'router/sitemap'
import Header from 'Header'
+import NotFoundPage from 'NotFoundPage'
import { helmetContext } from 'router/head'
import { HelmetProvider } from 'react-helmet-async'
import { FindspotService } from 'fragmentarium/application/FindspotService'
@@ -51,6 +52,7 @@ export default function Router(services: Services): JSX.Element {
{WebsiteRoutes(services, false)}
+
)
diff --git a/src/router/signRoutes.tsx b/src/router/signRoutes.tsx
index 99f2125f1..8ef01723d 100644
--- a/src/router/signRoutes.tsx
+++ b/src/router/signRoutes.tsx
@@ -6,6 +6,7 @@ import SignDisplay from 'signs/ui/display/SignDisplay'
import Signs from 'signs/ui/search/Signs'
import { SignSlugs, sitemapDefaults } from 'router/sitemap'
import { HeadTagsService } from 'router/head'
+import NotFoundPage from 'NotFoundPage'
export default function SignRoutes({
sitemap,
@@ -22,6 +23,7 @@ export default function SignRoutes({
(
(
,
+ }
+ />,
]
}
diff --git a/src/router/toolsRoutes.tsx b/src/router/toolsRoutes.tsx
index 34f2b3900..9896cd978 100644
--- a/src/router/toolsRoutes.tsx
+++ b/src/router/toolsRoutes.tsx
@@ -17,6 +17,7 @@ import DateConverterForm, {
import ListOfKings from 'chronology/ui/Kings/BrinkmanKingsTable'
import _ from 'lodash'
import 'about/ui/about.sass'
+import NotFoundPage from 'NotFoundPage'
const tabIds = ['date-converter', 'list-of-kings'] as const
type TabId = typeof tabIds[number]
@@ -71,8 +72,8 @@ export default function ToolsRoutes({
return [
): ReactNode => (
,
+ }
+ />,
- )
+ return {
+ signService,
+ wordService,
+ fragmentService,
+ fragmentSearchService,
+ bibliographyService,
+ textService,
+ markupService,
+ cachedMarkupService,
+ afoRegisterService,
+ findspotService,
+ }
+}
+
+function createApp(api): JSX.Element {
+ return
}
const breadcrumbs = {