Repository: DFE-Digital/find-information-about-academies-and-trusts
Pull request #799: Add basic layout for school pages
Author: login: dynamictulip
Created: 2025-04-17T09:56:18Z | Merged: 2025-04-24T14:26:35Z

This adds in the layout, nav and the skeleton of the school details page

[User Story 208370](https://dfe-gov-uk.visualstudio.com/Academies-and-Free-Schools-SIP/_workitems/edit/208370): Build : Basic Page Layout

It does not include the header or connections to the db

## Screenshots of UI changes

### School

![image](https://github.com/user-attachments/assets/e156892a-fc2f-47f5-87c4-9d4f806823bf)

### Academy

![image](https://github.com/user-attachments/assets/50009ce1-dffe-4500-ba05-31e127aebfef)

## Checklist

- [x] Pull request attached to the appropriate user story in Azure DevOps
- [ ] ADR decision log updated (if needed)
- [ ] Release notes added to CHANGELOG.md
- [x] Testing complete - all manual and automated tests pass



Diff:
diff --git a/DfE.FindInformationAcademiesTrusts.Data/Enums/SchoolCategory.cs b/DfE.FindInformationAcademiesTrusts.Data/Enums/SchoolCategory.cs
new file mode 100644
index 000000000..af5d23f07
--- /dev/null
+++ b/DfE.FindInformationAcademiesTrusts.Data/Enums/SchoolCategory.cs
@@ -0,0 +1,7 @@
+namespace DfE.FindInformationAcademiesTrusts.Data.Enums;
+
+public enum SchoolCategory
+{
+    LaMaintainedSchool,
+    Academy
+}
diff --git a/DfE.FindInformationAcademiesTrusts/Extensions/SchoolCategoryExtensions.cs b/DfE.FindInformationAcademiesTrusts/Extensions/SchoolCategoryExtensions.cs
new file mode 100644
index 000000000..155b920c6
--- /dev/null
+++ b/DfE.FindInformationAcademiesTrusts/Extensions/SchoolCategoryExtensions.cs
@@ -0,0 +1,16 @@
+using DfE.FindInformationAcademiesTrusts.Data.Enums;
+
+namespace DfE.FindInformationAcademiesTrusts.Extensions;
+
+public static class SchoolCategoryExtensions
+{
+    public static string ToDisplayString(this SchoolCategory type)
+    {
+        return type switch
+        {
+            SchoolCategory.LaMaintainedSchool => "School",
+            SchoolCategory.Academy => "Academy",
+            _ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
+        };
+    }
+}
diff --git a/DfE.FindInformationAcademiesTrusts/Pages/Schools/ISchoolAreaModel.cs b/DfE.FindInformationAcademiesTrusts/Pages/Schools/ISchoolAreaModel.cs
new file mode 100644
index 000000000..937e66cd2
--- /dev/null
+++ b/DfE.FindInformationAcademiesTrusts/Pages/Schools/ISchoolAreaModel.cs
@@ -0,0 +1,15 @@
+using DfE.FindInformationAcademiesTrusts.Data.Enums;
+using DfE.FindInformationAcademiesTrusts.Pages.Shared;
+using DfE.FindInformationAcademiesTrusts.Pages.Shared.DataSource;
+
+namespace DfE.FindInformationAcademiesTrusts.Pages.Schools;
+
+public interface ISchoolAreaModel
+{
+    string Urn { get; }
+    SchoolCategory SchoolCategory { get; }
+    List<DataSourcePageListEntry> DataSourcesPerPage { get; }
+    PageMetadata PageMetadata { get; }
+    string SchoolName { get; }
+    string SchoolType { get; }
+}
diff --git a/DfE.FindInformationAcademiesTrusts/Pages/Schools/Overview/Details.cshtml b/DfE.FindInformationAcademiesTrusts/Pages/Schools/Overview/Details.cshtml
new file mode 100644
index 000000000..5850390b1
--- /dev/null
+++ b/DfE.FindInformationAcademiesTrusts/Pages/Schools/Overview/Details.cshtml
@@ -0,0 +1,7 @@
+@page
+@model DetailsModel
+
+@{
+  Layout = "_SchoolLayout";
+}
+
diff --git a/DfE.FindInformationAcademiesTrusts/Pages/Schools/Overview/Details.cshtml.cs b/DfE.FindInformationAcademiesTrusts/Pages/Schools/Overview/Details.cshtml.cs
new file mode 100644
index 000000000..a7c4e7d07
--- /dev/null
+++ b/DfE.FindInformationAcademiesTrusts/Pages/Schools/Overview/Details.cshtml.cs
@@ -0,0 +1,22 @@
+using DfE.FindInformationAcademiesTrusts.Data.Enums;
+using DfE.FindInformationAcademiesTrusts.Pages.Shared;
+
+namespace DfE.FindInformationAcademiesTrusts.Pages.Schools.Overview;
+
+public class DetailsModel : OverviewAreaModel
+{
+    public override PageMetadata PageMetadata => base.PageMetadata with
+    {
+        SubPageName = SubPageName(SchoolCategory)
+    };
+
+    public static string SubPageName(SchoolCategory schoolCategory)
+    {
+        return schoolCategory switch
+        {
+            SchoolCategory.LaMaintainedSchool => "School details",
+            SchoolCategory.Academy => "Academy details",
+            _ => throw new ArgumentOutOfRangeException(nameof(schoolCategory))
+        };
+    }
+}
diff --git a/DfE.FindInformationAcademiesTrusts/Pages/Schools/Overview/OverviewAreaModel.cs b/DfE.FindInformationAcademiesTrusts/Pages/Schools/Overview/OverviewAreaModel.cs
new file mode 100644
index 000000000..e005b9495
--- /dev/null
+++ b/DfE.FindInformationAcademiesTrusts/Pages/Schools/Overview/OverviewAreaModel.cs
@@ -0,0 +1,9 @@
+using DfE.FindInformationAcademiesTrusts.Pages.Shared;
+
+namespace DfE.FindInformationAcademiesTrusts.Pages.Schools.Overview;
+
+public class OverviewAreaModel : SchoolAreaModel
+{
+    public const string PageName = "Overview";
+    public override PageMetadata PageMetadata => base.PageMetadata with { PageName = PageName };
+}
diff --git a/DfE.FindInformationAcademiesTrusts/Pages/Schools/SchoolAreaModel.cs b/DfE.FindInformationAcademiesTrusts/Pages/Schools/SchoolAreaModel.cs
new file mode 100644
index 000000000..fdc377624
--- /dev/null
+++ b/DfE.FindInformationAcademiesTrusts/Pages/Schools/SchoolAreaModel.cs
@@ -0,0 +1,30 @@
+using System.Diagnostics.CodeAnalysis;
+using DfE.FindInformationAcademiesTrusts.Data.Enums;
+using DfE.FindInformationAcademiesTrusts.Pages.Shared;
+using DfE.FindInformationAcademiesTrusts.Pages.Shared.DataSource;
+using Microsoft.AspNetCore.Mvc;
+
+namespace DfE.FindInformationAcademiesTrusts.Pages.Schools;
+
+[ExcludeFromCodeCoverage] //Temporary exclusion while this contains dummy data
+public class SchoolAreaModel : BasePageModel, ISchoolAreaModel
+{
+    [BindProperty(SupportsGet = true)] public string Urn { get; set; } = "";
+
+    public SchoolCategory SchoolCategory => Urn.EndsWith('2')
+        ? SchoolCategory.LaMaintainedSchool
+        : SchoolCategory.Academy;
+
+    public List<DataSourcePageListEntry> DataSourcesPerPage { get; set; } = [];
+    public virtual PageMetadata PageMetadata => new(SchoolName, ModelState.IsValid);
+
+    public string SchoolName
+        => Urn.EndsWith('2')
+            ? $"Cool School {Urn}"
+            : $"Chill Academy {Urn}";
+
+    public string SchoolType
+        => Urn.EndsWith('2')
+            ? "Community school"
+            : "Academy sponsor led";
+}
diff --git a/DfE.FindInformationAcademiesTrusts/Pages/Schools/SchoolNavMenu.cs b/DfE.FindInformationAcademiesTrusts/Pages/Schools/SchoolNavMenu.cs
new file mode 100644
index 000000000..755ca616f
--- /dev/null
+++ b/DfE.FindInformationAcademiesTrusts/Pages/Schools/SchoolNavMenu.cs
@@ -0,0 +1,58 @@
+using DfE.FindInformationAcademiesTrusts.Extensions;
+using DfE.FindInformationAcademiesTrusts.Pages.Schools.Overview;
+using DfE.FindInformationAcademiesTrusts.Pages.Shared.NavMenu;
+
+namespace DfE.FindInformationAcademiesTrusts.Pages.Schools;
+
+public static class SchoolNavMenu
+{
+    public static NavLink[] GetServiceNavLinks(ISchoolAreaModel activePage)
+    {
+        return
+        [
+            GetServiceNavLinkTo<OverviewAreaModel>(OverviewAreaModel.PageName, "/Schools/Overview/Details",
+                activePage)
+        ];
+    }
+
+    private static NavLink GetServiceNavLinkTo<T>(string linkDisplayText, string aspPage, ISchoolAreaModel activePage)
+    {
+        return new NavLink(activePage is T,
+            activePage.SchoolCategory.ToDisplayString(),
+            linkDisplayText,
+            aspPage,
+            $"{linkDisplayText}-nav".Kebabify(),
+            new Dictionary<string, string> { { "urn", activePage.Urn } });
+    }
+
+    public static NavLink[] GetSubNavLinks(ISchoolAreaModel activePage)
+    {
+        return activePage switch
+        {
+            OverviewAreaModel =>
+            [
+                GetSubNavLinkTo<DetailsModel>(
+                    OverviewAreaModel.PageName,
+                    DetailsModel.SubPageName(activePage.SchoolCategory),
+                    "/Schools/Overview/Details",
+                    activePage,
+                    "overview-details-subnav"
+                )
+            ],
+            _ => throw new ArgumentOutOfRangeException(nameof(activePage), activePage, "Page type is not supported.")
+        };
+    }
+
+    private static NavLink GetSubNavLinkTo<T>(string serviceName, string linkDisplayText, string aspPage,
+        ISchoolAreaModel activePage, string? testIdOverride = null)
+    {
+        return new NavLink(
+            activePage is T,
+            serviceName,
+            linkDisplayText,
+            aspPage,
+            testIdOverride ?? $"{serviceName}-{linkDisplayText}-subnav".Kebabify(),
+            new Dictionary<string, string> { { "urn", activePage.Urn } }
+        );
+    }
+}
diff --git a/DfE.FindInformationAcademiesTrusts/Pages/Schools/_SchoolBanner.cshtml b/DfE.FindInformationAcademiesTrusts/Pages/Schools/_SchoolBanner.cshtml
new file mode 100644
index 000000000..ae889a2ee
--- /dev/null
+++ b/DfE.FindInformationAcademiesTrusts/Pages/Schools/_SchoolBanner.cshtml
@@ -0,0 +1,15 @@
+﻿@model ISchoolAreaModel
+
+<aside class="app-banner" data-testid="app-school-header">
+  <div class="dfe-width-container">
+    <div class="govuk-grid-row">
+      <div class="govuk-grid-column-three-quarters">
+        <partial name="_SchoolBreadcrumbs" model="@Model" />
+        <h2 class="govuk-heading-l app-banner--heading govuk-!-margin-top-3 govuk-!-margin-bottom-3"
+            data-testid="school-name-heading">@Model.SchoolName</h2>
+        <p class="govuk-body app-banner--body govuk-!-margin-bottom-0"
+           data-testid="school-type">@Model.SchoolType</p>
+      </div>
+    </div>
+  </div>
+</aside>
diff --git a/DfE.FindInformationAcademiesTrusts/Pages/Schools/_SchoolBreadcrumbs.cshtml b/DfE.FindInformationAcademiesTrusts/Pages/Schools/_SchoolBreadcrumbs.cshtml
new file mode 100644
index 000000000..364ab6a19
--- /dev/null
+++ b/DfE.FindInformationAcademiesTrusts/Pages/Schools/_SchoolBreadcrumbs.cshtml
@@ -0,0 +1,23 @@
+﻿@using Microsoft.AspNetCore.Mvc.TagHelpers
+@model ISchoolAreaModel
+
+<div class="govuk-grid-row">
+  <div class="govuk-grid-column-full">
+    <nav class="govuk-breadcrumbs govuk-!-margin-0" aria-label="Breadcrumb">
+      <ol class="govuk-breadcrumbs__list">
+        <li class="govuk-breadcrumbs__list-item" data-testid="breadcrumb-home-link">
+          <a class="govuk-breadcrumbs__link" asp-page="/Index">Home</a>
+        </li>
+        <li class="govuk-breadcrumbs__list-item" data-testid="breadcrumb-trust-name">
+          <a class="govuk-breadcrumbs__link" asp-page="/Schools/Overview/Details"
+             asp-route-urn="@Model.Urn">
+            @Model.SchoolName
+          </a>
+        </li>
+        <li class="govuk-breadcrumbs__list-item" data-testid="breadcrumb-page-name">
+          @Model.PageMetadata.PageName
+        </li>
+      </ol>
+    </nav>
+  </div>
+</div>
diff --git a/DfE.FindInformationAcademiesTrusts/Pages/Schools/_SchoolLayout.cshtml b/DfE.FindInformationAcademiesTrusts/Pages/Schools/_SchoolLayout.cshtml
new file mode 100644
index 000000000..31aa48fd8
--- /dev/null
+++ b/DfE.FindInformationAcademiesTrusts/Pages/Schools/_SchoolLayout.cshtml
@@ -0,0 +1,29 @@
+@model ISchoolAreaModel
+
+@{
+  Layout = "_Layout";
+  ViewData["Title"] = Model.PageMetadata.BrowserTitle;
+}
+
+<partial name="_SchoolBanner" model="@Model" />
+<partial name="Shared/NavMenu/_ServiceNav" model="@SchoolNavMenu.GetServiceNavLinks(Model)" />
+<div class="govuk-main-wrapper govuk-!-padding-top-6">
+  <div class="dfe-width-container">
+    <div class="govuk-grid-row">
+      <div class="govuk-grid-column-full">
+        <main id="main-content">
+          <header>
+            <h1 class="govuk-heading-l" data-testid="page-name">@Model.PageMetadata.PageName</h1>
+          </header>
+          <partial name="Shared/NavMenu/_SubNav" model="@SchoolNavMenu.GetSubNavLinks(Model)" />
+          @RenderBody()
+        </main>
+        <partial name="Shared/DataSource/_SourceList" model="@Model.DataSourcesPerPage" />
+      </div>
+    </div>
+  </div>
+</div>
+
+@section Scripts {
+  @await RenderSectionAsync("Scripts", false)
+}
diff --git a/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/header-search-page.cy.ts b/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/header-search-page.cy.ts
index 987f97cb2..26ea22865 100644
--- a/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/header-search-page.cy.ts
+++ b/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/header-search-page.cy.ts
@@ -1,47 +1,49 @@
-import searchPage from "../../pages/searchPage";
-import headerPage from "../../pages/headerPage";
+import searchPage from '../../pages/searchPage';
+import headerPage from '../../pages/headerPage';
 
-describe("Testing the components of the header search", () => {
+describe(`Testing the components of the header search`, () => {
 
-    beforeEach(() => {
-        cy.login();
-        cy.visit('/trusts/overview/trust-details?uid=5527');
-    });
+    [`/schools/overview/details?urn=123452`, `/trusts/overview/trust-details?uid=5527`].forEach((url) => {
 
-    it("Should check that the header search bar and autocomplete is present and functional", () => {
-        headerPage
-            .enterHeaderSearchText("West")
-            .checkHeaderAutocompleteIsPresent()
-            .checkHeaderSearchButtonPresent()
-            .checkAutocompleteContainsTypedText("West");
-    });
+        beforeEach(() => {
+            cy.login();
+            cy.visit(url);
+        });
 
-    it("Should check that the autocomplete does not return results when entry does not exist", () => {
+        it(`Should check that the header search bar and autocomplete is present and functional for ${url})`, () => {
+            headerPage
+                .enterHeaderSearchText(`West`)
+                .checkHeaderAutocompleteIsPresent()
+                .checkHeaderSearchButtonPresent()
+                .checkAutocompleteContainsTypedText(`West`);
+        });
 
-        headerPage
-            .enterHeaderSearchText("KnowWhere")
-            .checkHeaderAutocompleteIsPresent()
-            .checkAutocompleteContainsTypedText("No results found");
-    });;
+        it(`Should check that the autocomplete does not return results when entry does not exist for ${url}`, () => {
 
-    it("Should check that search results are returned with a valid name entered when using the header search bar ", () => {
-        headerPage
-            .enterHeaderSearchText("west")
-            .clickHeaderSearchButton();
+            headerPage
+                .enterHeaderSearchText(`KnowWhere`)
+                .checkHeaderAutocompleteIsPresent()
+                .checkAutocompleteContainsTypedText(`No results found`);
+        });;
 
-        searchPage
-            .checkSearchResultsReturned('west');
+        it(`Should check that search results are returned with a valid name entered when using the header search bar for ${url}`, () => {
+            headerPage
+                .enterHeaderSearchText(`west`)
+                .clickHeaderSearchButton();
 
-    });
+            searchPage
+                .checkSearchResultsReturned('west');
 
-    it("Should return the correct trust when searching by TRN using the header search", () => {
+        });
 
-        headerPage
-            .enterHeaderSearchText("TR02343")
-            .clickHeaderSearchButton();
+        it(`Should return the correct trust when searching by TRN using the header search for ${url}`, () => {
 
-        searchPage
-            .checkSearchResultsReturned("UNITED LEARNING TRUST");
-    });
+            headerPage
+                .enterHeaderSearchText(`TR02343`)
+                .clickHeaderSearchButton();
 
+            searchPage
+                .checkSearchResultsReturned(`UNITED LEARNING TRUST`);
+        });
+    });
 });
diff --git a/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/navigation/breadcrumb-links.cy.ts b/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/navigation/breadcrumb-links.cy.ts
new file mode 100644
index 000000000..e45fe834f
--- /dev/null
+++ b/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/navigation/breadcrumb-links.cy.ts
@@ -0,0 +1,85 @@
+import navigation from "../../../pages/navigation";
+import { testSchoolData, testTrustData } from "../../../support/test-data-store";
+
+describe('Testing Navigation', () => {
+
+    describe("Testing the breadcrumb-links", () => {
+        beforeEach(() => {
+            cy.login();
+        });
+
+        describe("Testing the general page breadcrumb links and their relevant functionality", () => {
+            beforeEach(() => {
+                cy.login();
+            });
+
+            ['/search', '/accessibility', '/cookies', '/privacy', '/notfound'].forEach((url) => {
+                it(`Should have Home breadcrumb only on ${url}`, () => {
+                    cy.visit(url, { failOnStatusCode: false });
+
+                    navigation
+                        .checkCurrentURLIsCorrect(url)
+                        .checkHomeBreadcrumbPresent()
+                        .clickHomeBreadcrumbButton()
+                        .checkBrowserPageTitleContains('Home page');
+                });
+            });
+
+            ['/', '/error'].forEach((url) => {
+                it(`Should have no breadcrumb on ${url}`, () => {
+                    cy.visit(url);
+
+                    navigation
+                        .checkCurrentURLIsCorrect(url)
+                        .checkAccessibilityStatementLinkPresent() // ensure page content has loaded - all pages have an a11y statement link
+                        .checkBreadcrumbNotPresent();
+                });
+            });
+        });
+
+        describe("Testing the breadcrumb links on the trust academy details page", () => {
+            beforeEach(() => {
+                cy.login();
+            });
+
+            describe("Testing the breadcrumb links on the trust page", () => {
+                testTrustData.forEach(({ uid, trustName }) => {
+                    it('Should check that a trusts name breadcrumb is displayed on the trusts page', () => {
+                        cy.visit(`/trusts/overview/trust-details?uid=${uid}`);
+                        navigation
+                            .checkTrustNameBreadcrumbPresent(`${trustName}`)
+                            .clickHomeBreadcrumbButton()
+                            .checkBrowserPageTitleContains('Home page');
+                    });
+                });
+            });
+
+            describe("Testing the breadcrumb links on the pipeline academies pages", () => {
+                [`/trusts/academies/pipeline/pre-advisory-board?uid=16002`, `/trusts/academies/pipeline/post-advisory-board?uid=17584`, `/trusts/academies/pipeline/free-schools?uid=17584`].forEach((url) => {
+                    it("Checks the breadcrumb shows the correct page name", () => {
+                        cy.visit(url);
+                        navigation
+                            .checkPageNameBreadcrumbPresent("Academies");
+                        //revist adding this later need to rethink how the foreach handles differing uid pulls for the differnt pages .checkTrustNameBreadcrumbPresent('Ashton West End Primary Academy');
+                    });
+                });
+            });
+        });
+    });
+
+    describe("Testing the breadcrumb links on the schools overview pages", () => {
+        testSchoolData.forEach(({ urn }) => {
+            beforeEach(() => {
+                cy.login();
+            });
+
+            [`/schools/overview/details?urn=${urn}`].forEach((url) => {
+                it("Checks the breadcrumb shows the correct page name", () => {
+                    cy.visit(url);
+                    navigation
+                        .checkPageNameBreadcrumbPresent("Overview");
+                });
+            });
+        });
+    });
+});
diff --git a/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/navigation/footer-links-nav.cy.ts b/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/navigation/footer-links-nav.cy.ts
new file mode 100644
index 000000000..105e2e4c9
--- /dev/null
+++ b/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/navigation/footer-links-nav.cy.ts
@@ -0,0 +1,40 @@
+import navigation from "../../../pages/navigation";
+
+describe('Testing Navigation', () => {
+
+    describe("Testing the footer-links", () => {
+        beforeEach(() => {
+            cy.login();
+        });
+
+        it("Should check that the home page footer bar privacy link is present and functional", () => {
+            navigation
+                .checkPrivacyLinkPresent()
+                .clickPrivacyLink();
+
+            navigation
+                .checkCurrentURLIsCorrect('privacy');
+
+        });
+
+        it("Should check that the home page footer bar cookies link is present and functional", () => {
+            navigation
+                .checkCookiesLinkPresent()
+                .clickCookiesLink();
+
+            navigation
+                .checkCurrentURLIsCorrect('cookies');
+
+        });
+
+        it("Should check that the home page footer bar accessibility statement link is present and functional", () => {
+            navigation
+                .checkAccessibilityStatementLinkPresent()
+                .clickAccessibilityStatementLink();
+
+            navigation
+                .checkCurrentURLIsCorrect('accessibility');
+        });
+
+    });
+});
diff --git a/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/navigation.cy.ts b/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/navigation/trust-academies-navigation.cy.ts
similarity index 71%
rename from tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/navigation.cy.ts
rename to tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/navigation/trust-academies-navigation.cy.ts
index c2931a04b..b97658b92 100644
--- a/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/navigation.cy.ts
+++ b/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/navigation/trust-academies-navigation.cy.ts
@@ -1,94 +1,12 @@
-import navigation from "../../pages/navigation";
-import academiesInTrustPage from "../../pages/trusts/academiesInTrustPage";
-import governancePage from "../../pages/trusts/governancePage";
-import contactsPage from "../../pages/trusts/contactsPage";
-import overviewPage from "../../pages/trusts/overviewPage";
-import financialDocumentsPage from "../../pages/trusts/financialDocumentsPage";
-import ofstedPage from "../../pages/trusts/ofstedPage";
+import navigation from "../../../pages/navigation";
+import academiesInTrustPage from "../../../pages/trusts/academiesInTrustPage";
+import governancePage from "../../../pages/trusts/governancePage";
+import contactsPage from "../../../pages/trusts/contactsPage";
+import overviewPage from "../../../pages/trusts/overviewPage";
+import financialDocumentsPage from "../../../pages/trusts/financialDocumentsPage";
+import ofstedPage from "../../../pages/trusts/ofstedPage";
 
-describe('Testing Navigation', () => {
-
-    describe("Testing the footer-links", () => {
-        beforeEach(() => {
-            cy.login();
-        });
-
-        it("Should check that the home page footer bar privacy link is present and functional", () => {
-            navigation
-                .checkPrivacyLinkPresent()
-                .clickPrivacyLink();
-
-            navigation
-                .checkCurrentURLIsCorrect('privacy');
-
-        });
-
-        it("Should check that the home page footer bar cookies link is present and functional", () => {
-            navigation
-                .checkCookiesLinkPresent()
-                .clickCookiesLink();
-
-            navigation
-                .checkCurrentURLIsCorrect('cookies');
-
-        });
-
-        it("Should check that the home page footer bar accessibility statement link is present and functional", () => {
-            navigation
-                .checkAccessibilityStatementLinkPresent()
-                .clickAccessibilityStatementLink();
-
-            navigation
-                .checkCurrentURLIsCorrect('accessibility');
-        });
-    });
-
-    describe("Testing the breadcrumb links and their relevant functionality", () => {
-        beforeEach(() => {
-            cy.login();
-        });
-
-        ['/search', '/accessibility', '/cookies', '/privacy', '/notfound'].forEach((url) => {
-            it(`Should have Home breadcrumb only on ${url}`, () => {
-                cy.visit(url, { failOnStatusCode: false });
-
-                navigation
-                    .checkCurrentURLIsCorrect(url)
-                    .checkHomeBreadcrumbPresent()
-                    .clickHomeBreadcrumbButton()
-                    .checkBrowserPageTitleContains('Home page');
-            });
-        });
-
-        ['/', '/error'].forEach((url) => {
-            it(`Should have no breadcrumb on ${url}`, () => {
-                cy.visit(url);
-
-                navigation
-                    .checkCurrentURLIsCorrect(url)
-                    .checkAccessibilityStatementLinkPresent() // ensure page content has loaded - all pages have an a11y statement link
-                    .checkBreadcrumbNotPresent();
-            });
-        });
-
-        it('Should check that a trusts name breadcrumb is displayed on the trusts page', () => {
-            cy.visit('/trusts/overview/trust-details?uid=5712');
-
-            navigation
-                .checkTrustNameBreadcrumbPresent('Aspire North East Multi Academy Trust')
-                .clickHomeBreadcrumbButton()
-                .checkBrowserPageTitleContains('Home page');
-        });
-
-        it('Should check a different trusts name breadcrumb is displayed on the trusts page', () => {
-            cy.visit('/trusts/overview/trust-details?uid=5527');
-
-            navigation
-                .checkTrustNameBreadcrumbPresent('Ashton West End Primary Academy')
-                .clickHomeBreadcrumbButton()
-                .checkBrowserPageTitleContains('Home page');
-        });
-    });
+describe('Testing trust service navigation and sub navigation', () => {
 
     describe("Testing the trusts service navigation", () => {
         // Test each link from a different page in round robin
@@ -256,4 +174,52 @@ describe('Testing Navigation', () => {
                 .checkCurrentURLIsCorrect('/trusts/financial-documents/financial-statements?uid=5527');
         });
     });
+
+    describe("Testing the trust academies page sub navigation", () => {
+        beforeEach(() => {
+            cy.login();
+        });
+
+        // details -> pupil numbers        
+        it('Should check that the academies Pupil numbers navigation button takes me to the correct page', () => {
+            cy.visit('/trusts/academies/in-trust/details?uid=5527');
+            navigation
+                .clickPupilNumbersAcadmiesTrustButton()
+                .checkCurrentURLIsCorrect('/trusts/academies/in-trust/pupil-numbers?uid=5527')
+                .checkAllServiceNavItemsPresent()
+                .checkAllAcademiesNavItemsPresent();
+            academiesInTrustPage
+                .checkPupilNumbersHeadersPresent();
+        });
+
+        // pupil numbers -> free school meals 
+        it('Should check that the academies Free school meals navigation button takes me to the correct page', () => {
+            cy.visit('/trusts/academies/in-trust/pupil-numbers?uid=5527');
+            navigation
+                .clickFreeSchoolMealsAcadmiesTrustButton()
+                .checkCurrentURLIsCorrect('/trusts/academies/in-trust/free-school-meals?uid=5527')
+                .checkAllServiceNavItemsPresent()
+                .checkAllAcademiesNavItemsPresent();
+            academiesInTrustPage
+                .checkFreeSchoolMealsHeadersPresent();
+        });
+
+        // free school meals -> details  
+        it('Should check that the academies Details navigation button takes me to the correct page', () => {
+            cy.visit('/trusts/academies/in-trust/free-school-meals?uid=5527');
+            navigation
+                .clickDetailsAcadmiesTrustButton()
+                .checkCurrentURLIsCorrect('/trusts/academies/in-trust/details?uid=5527')
+                .checkAllServiceNavItemsPresent()
+                .checkAllAcademiesNavItemsPresent();
+            academiesInTrustPage
+                .checkDetailsHeadersPresent();
+        });
+
+        it('Should check that the academies sub nav items are not present when I am not in the relevant academies page', () => {
+            cy.visit('/trusts/overview/trust-details?uid=5527');
+            navigation
+                .checkAcademiesSubNavNotPresent();
+        });
+    });
 });
diff --git a/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/schools/school-page.cy.ts b/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/schools/school-page.cy.ts
new file mode 100644
index 000000000..7f70eab15
--- /dev/null
+++ b/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/schools/school-page.cy.ts
@@ -0,0 +1,27 @@
+import schoolsPage from "../../../pages/schools/schoolsPage";
+import { testSchoolData } from "../../../support/test-data-store";
+
+describe("Testing the components of the Schools page", () => {
+
+    describe("Header items", () => {
+        testSchoolData.forEach(({ typeOfSchool, urn }) => {
+            beforeEach(() => {
+                cy.login();
+            });
+
+            [`/schools/overview/details?urn=${urn}`].forEach((url) => {
+                it(`Checks the school type is correct on a ${typeOfSchool} on the urn ${urn}`, () => {
+                    cy.visit(url);
+                    schoolsPage
+                        .checkCorrectSchoolTypePresent();
+                });
+            });
+
+            it(`Checks the page name is correct on a ${typeOfSchool} on the urn ${urn}`, () => {
+                cy.visit(`/schools/overview/details?uid=${urn}`);
+                schoolsPage
+                    .checkOverviewPageNamePresent();
+            });
+        });
+    });
+});
diff --git a/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/trusts/contacts-page.cy.ts b/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/trusts/contacts-page.cy.ts
index 40c8fdc51..64904ae1d 100644
--- a/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/trusts/contacts-page.cy.ts
+++ b/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/trusts/contacts-page.cy.ts
@@ -1,6 +1,7 @@
 import contactsPage from "../../../pages/trusts/contactsPage";
 import commonPage from "../../../pages/commonPage";
 import navigation from "../../../pages/navigation";
+import { testTrustData } from "../../../support/test-data-store";
 
 function generateNameAndEmail() {
     const randomNumber = Math.floor(Math.random() * 9999);
@@ -10,17 +11,6 @@ function generateNameAndEmail() {
     };
 }
 
-const testTrustData = [
-    {
-        typeOfTrust: "single academy trust with contacts",
-        uid: 5527
-    },
-    {
-        typeOfTrust: "multi academy trust with contacts",
-        uid: 5712
-    }
-];
-
 describe("Testing the components of the Trust contacts page", () => {
     testTrustData.forEach(({ typeOfTrust, uid }) => {
         describe(`On the contacts in DfE page for a ${typeOfTrust}`, () => {
diff --git a/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/trusts/financial-docs.cy.ts b/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/trusts/financial-docs.cy.ts
index f1d59c1b9..4b60f7b13 100644
--- a/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/trusts/financial-docs.cy.ts
+++ b/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/trusts/financial-docs.cy.ts
@@ -42,7 +42,7 @@ testFinanceData.forEach(({ uid }) => {
 
         });
 
-        describe.only(`On the Management letters page for a trust`, () => {
+        describe(`On the Management letters page for a trust`, () => {
 
             beforeEach(() => {
                 cy.login();
diff --git a/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/trusts/governance-page.cy.ts b/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/trusts/governance-page.cy.ts
index 0708bc702..3f75c753f 100644
--- a/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/trusts/governance-page.cy.ts
+++ b/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/trusts/governance-page.cy.ts
@@ -1,6 +1,7 @@
 import commonPage from "../../../pages/commonPage";
 import navigation from "../../../pages/navigation";
 import governancePage from "../../../pages/trusts/governancePage";
+import { trustsWithGovernanceData } from "../../../support/test-data-store";
 
 describe("Testing the components of the Governance page", () => {
 
@@ -8,16 +9,6 @@ describe("Testing the components of the Governance page", () => {
         cy.login();
     });
 
-    const trustsWithGovernanceData = [
-        {
-            typeOfTrust: "single academy trust with governance data",
-            uid: 5527
-        },
-        {
-            typeOfTrust: "multi academy trust with governance data",
-            uid: 5712
-        }
-    ];
     trustsWithGovernanceData.forEach(({ typeOfTrust, uid }) => {
         describe(`On the Governance pages for a ${typeOfTrust}`, () => {
 
diff --git a/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/trusts/academies-in-trust.cy.ts b/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/trusts/trustAcademiesPage/academies-in-trust.cy.ts
similarity index 74%
rename from tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/trusts/academies-in-trust.cy.ts
rename to tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/trusts/trustAcademiesPage/academies-in-trust.cy.ts
index 594396459..74fb06d4e 100644
--- a/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/trusts/academies-in-trust.cy.ts
+++ b/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/trusts/trustAcademiesPage/academies-in-trust.cy.ts
@@ -1,17 +1,6 @@
-import academiesInTrustPage from "../../../pages/trusts/academiesInTrustPage";
-import navigation from "../../../pages/navigation";
-import commonPage from "../../../pages/commonPage";
-
-const testTrustData = [
-    {
-        typeOfTrust: "single academy trust with contacts",
-        uid: 5527
-    },
-    {
-        typeOfTrust: "multi academy trust with contacts",
-        uid: 5712
-    }
-];
+import academiesInTrustPage from "../../../../pages/trusts/academiesInTrustPage";
+import commonPage from "../../../../pages/commonPage";
+import { testTrustData } from "../../../../support/test-data-store";
 
 describe("Testing the components of the Academies page", () => {
 
@@ -147,50 +136,6 @@ describe("Testing the components of the Academies page", () => {
 
     });
 
-    describe("Testing the academies sub navigation", () => {
-        beforeEach(() => {
-            cy.login();
-            cy.visit('/trusts/academies/in-trust/details?uid=5527');
-        });
-
-        it('Should check that the academies Pupil numbers navigation button takes me to the correct page', () => {
-            navigation
-                .clickPupilNumbersAcadmiesTrustButton()
-                .checkCurrentURLIsCorrect('/trusts/academies/in-trust/pupil-numbers?uid=5527')
-                .checkAllServiceNavItemsPresent()
-                .checkAllAcademiesNavItemsPresent();
-            academiesInTrustPage
-                .checkPupilNumbersHeadersPresent();
-        });
-
-        it('Should check that the academies Free school meals navigation button takes me to the correct page', () => {
-            navigation
-                .clickFreeSchoolMealsAcadmiesTrustButton()
-                .checkCurrentURLIsCorrect('/trusts/academies/in-trust/free-school-meals?uid=5527')
-                .checkAllServiceNavItemsPresent()
-                .checkAllAcademiesNavItemsPresent();
-            academiesInTrustPage
-                .checkFreeSchoolMealsHeadersPresent();
-        });
-
-        it('Should check that the academies Details navigation button takes me to the correct page', () => {
-            cy.visit('/trusts/academies/in-trust/free-school-meals?uid=5527');
-            navigation
-                .clickDetailsAcadmiesTrustButton()
-                .checkCurrentURLIsCorrect('/trusts/academies/in-trust/details?uid=5527')
-                .checkAllServiceNavItemsPresent()
-                .checkAllAcademiesNavItemsPresent();
-            academiesInTrustPage
-                .checkDetailsHeadersPresent();
-        });
-
-        it('Should check that the academies sub nav items are not present when I am not in the relevant academies page', () => {
-            cy.visit('/trusts/overview/trust-details?uid=5527');
-            navigation
-                .checkAcademiesSubNavNotPresent();
-        });
-    });
-
     describe("Testing a trust that has no academies within it to ensure the issue of a 500 page appearing does not happen", () => {
         beforeEach(() => {
             cy.login();
diff --git a/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/trusts/pipeline-academies.cy.ts b/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/trusts/trustAcademiesPage/pipeline-academies.cy.ts
similarity index 77%
rename from tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/trusts/pipeline-academies.cy.ts
rename to tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/trusts/trustAcademiesPage/pipeline-academies.cy.ts
index 4d66d3477..c37a6177c 100644
--- a/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/trusts/pipeline-academies.cy.ts
+++ b/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/trusts/trustAcademiesPage/pipeline-academies.cy.ts
@@ -1,34 +1,7 @@
-import commonPage from "../../../pages/commonPage";
-import pipelineAcademiesPage from "../../../pages/trusts/pipelineAcademiesPage";
-import dataDownload from "../../../pages/trusts/dataDownload";
-import navigation from "../../../pages/navigation";
-
-const testPreAdvisoryData = [
-    {
-        uid: 16002
-    },
-    {
-        uid: 4921
-    }
-];
-
-const testPostAdvisoryData = [
-    {
-        uid: 17584
-    },
-    {
-        uid: 16857
-    }
-];
-
-const testFreeSchoolsData = [
-    {
-        uid: 17538
-    },
-    {
-        uid: 15786
-    }
-];
+import commonPage from "../../../../pages/commonPage";
+import pipelineAcademiesPage from "../../../../pages/trusts/pipelineAcademiesPage";
+import dataDownload from "../../../../pages/trusts/dataDownload";
+import { testPreAdvisoryData, testPostAdvisoryData, testFreeSchoolsData } from "../../../../support/test-data-store";
 
 describe("Testing the Pipeline academies pages", () => {
 
@@ -49,11 +22,6 @@ describe("Testing the Pipeline academies pages", () => {
                     .checkPreAdvisoryPageHeaderPresent();
             });
 
-            it("Checks the breadcrumb shows the correct page name", () => {
-                navigation
-                    .checkPageNameBreadcrumbPresent("Academies");
-            });
-
             it("Checks the correct Pipeline academies Pre advisory board table headers are present", () => {
                 pipelineAcademiesPage
                     .checkPreAdvisoryTableHeadersPresent();
@@ -104,11 +72,6 @@ describe("Testing the Pipeline academies pages", () => {
                     .checkPostAdvisoryPageHeaderPresent();
             });
 
-            it("Checks the breadcrumb shows the correct page name", () => {
-                navigation
-                    .checkPageNameBreadcrumbPresent("Academies");
-            });
-
             it("Checks the correct Pipeline academies Post advisory board table headers are present", () => {
                 pipelineAcademiesPage
                     .checkPostAdvisoryTableHeadersPresent();
@@ -154,11 +117,6 @@ describe("Testing the Pipeline academies pages", () => {
                     .checkFreeSchoolsPageHeaderPresent();
             });
 
-            it("Checks the breadcrumb shows the correct page name", () => {
-                navigation
-                    .checkPageNameBreadcrumbPresent("Academies");
-            });
-
             it("Checks the correct Pipeline academies Free schools table headers are present", () => {
                 pipelineAcademiesPage
                     .checkFreeSchoolsTableHeadersPresent();
@@ -232,29 +190,4 @@ describe("Testing the Pipeline academies pages", () => {
         });
     });
 
-    describe(`On the pages with no pipeline academy data under them`, () => {
-
-        beforeEach(() => {
-            cy.login();
-        });
-
-        it("Checks the Pipeline academies Pre advisory page when an academy doesnt exist under it to ensure the correct message is displayed", () => {
-            cy.visit(`/trusts/academies/pipeline/pre-advisory-board?uid=5712`);
-            pipelineAcademiesPage
-                .checkPreAdvisoryNoAcademyPresent();
-        });
-
-        it("Checks the Pipeline academies Post advisory page when an academy doesnt exist under it to ensure the correct message is displayed", () => {
-            cy.visit(`/trusts/academies/pipeline/post-advisory-board?uid=5712`);
-            pipelineAcademiesPage
-                .checkPostAdvisoryNoAcademyPresent();
-        });
-
-        it("Checks the Pipeline academies Free schools page when an academy doesnt exist under it to ensure the correct message is displayed", () => {
-            cy.visit(`/trusts/academies/pipeline/free-schools?uid=5712`);
-            pipelineAcademiesPage
-                .checkFreeSchoolsNoAcademyPresent();
-        });
-    });
-
 });
diff --git a/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/pages/schools/schoolsPage.ts b/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/pages/schools/schoolsPage.ts
new file mode 100644
index 000000000..f0efa73f3
--- /dev/null
+++ b/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/pages/schools/schoolsPage.ts
@@ -0,0 +1,33 @@
+
+class SchoolsPage {
+
+    elements = {
+        pageName: () => cy.get('[data-testid="page-name"]'),
+        subpageHeader: () => cy.get('[data-testid="subpage-header"]'),
+        schoolType: () => cy.get('[data-testid="school-type"]'),
+        nav: {
+            overviewNav: () => cy.get('[data-testid="overview-nav"]'),
+        },
+    };
+
+    private readonly checkElementMatches = (element: JQuery<HTMLElement>, expected: RegExp) => {
+        const text = element.text().trim();
+        expect(text).to.match(expected);
+    };
+
+    public checkValueIsValidSchoolType = (element: JQuery<HTMLElement>) =>
+        this.checkElementMatches(element, /^(Community school|Academy sponsor led|)$/);
+
+    public checkCorrectSchoolTypePresent(): this {
+        this.elements.schoolType().each(this.checkValueIsValidSchoolType);
+        return this;
+    }
+
+    public checkOverviewPageNamePresent(): this {
+        this.elements.pageName().should('contain', 'Overview');
+        return this;
+    }
+}
+
+const schoolsPage = new SchoolsPage();
+export default schoolsPage;
diff --git a/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/support/test-data-store.ts b/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/support/test-data-store.ts
index b8b88b259..60f14c984 100644
--- a/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/support/test-data-store.ts
+++ b/tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/support/test-data-store.ts
@@ -46,3 +46,60 @@ export class TestDataStore {
             },
         ];
 }
+
+export const testSchoolData = [
+    {
+        typeOfSchool: "Community school",
+        urn: 123452
+    },
+    {
+        typeOfSchool: "Academy sponsor led",
+        urn: 5712
+    }
+]; export const testPreAdvisoryData = [
+    {
+        uid: 16002
+    },
+    {
+        uid: 4921
+    }
+];
+export const testPostAdvisoryData = [
+    {
+        uid: 17584
+    },
+    {
+        uid: 16857
+    }
+];
+export const testFreeSchoolsData = [
+    {
+        uid: 17538
+    },
+    {
+        uid: 15786
+    }
+];
+export const testTrustData = [
+    {
+        trustName: "Ashton West End Primary Academy",
+        typeOfTrust: "single academy trust with contacts",
+        uid: 5527
+    },
+    {
+        trustName: "Aspire North East Multi Academy Trust",
+        typeOfTrust: "multi academy trust with contacts",
+        uid: 5712
+    }
+];
+export const trustsWithGovernanceData = [
+    {
+        typeOfTrust: "single academy trust with governance data",
+        uid: 5527
+    },
+    {
+        typeOfTrust: "multi academy trust with governance data",
+        uid: 5712
+    }
+];
+
diff --git a/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Extensions/SchoolCategoryExtensionsTests.cs b/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Extensions/SchoolCategoryExtensionsTests.cs
new file mode 100644
index 000000000..1c7e60d53
--- /dev/null
+++ b/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Extensions/SchoolCategoryExtensionsTests.cs
@@ -0,0 +1,24 @@
+﻿using DfE.FindInformationAcademiesTrusts.Data.Enums;
+using DfE.FindInformationAcademiesTrusts.Extensions;
+
+namespace DfE.FindInformationAcademiesTrusts.UnitTests.Extensions;
+
+public class SchoolCategoryExtensionsTests
+{
+    [Theory]
+    [InlineData(SchoolCategory.LaMaintainedSchool, "School")]
+    [InlineData(SchoolCategory.Academy, "Academy")]
+    public void ToDisplayString_returns_expected_value(
+        SchoolCategory schoolCategory, string expected)
+    {
+        var result = schoolCategory.ToDisplayString();
+        result.Should().Be(expected);
+    }
+
+    [Fact]
+    public void ToDisplayString__throws_when_mapping_is_invalid()
+    {
+        var act = () => ((SchoolCategory)9999).ToDisplayString();
+        act.Should().Throw<ArgumentException>();
+    }
+}
diff --git a/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Schools/BaseSchoolPageTests.cs b/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Schools/BaseSchoolPageTests.cs
new file mode 100644
index 000000000..fe067085b
--- /dev/null
+++ b/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Schools/BaseSchoolPageTests.cs
@@ -0,0 +1,23 @@
+using DfE.FindInformationAcademiesTrusts.Pages.Schools;
+
+namespace DfE.FindInformationAcademiesTrusts.UnitTests.Pages.Schools;
+
+public abstract class BaseSchoolPageTests<T> where T : SchoolAreaModel
+{
+    protected T Sut = null!;
+
+    [Fact]
+    public void ShowHeaderSearch_should_be_true()
+    {
+        Sut.ShowHeaderSearch.Should().Be(true);
+    }
+
+    [Fact]
+    public abstract Task OnGetAsync_should_configure_PageMetadata_PageName();
+
+    [Fact]
+    public abstract Task OnGetAsync_should_configure_PageMetadata_SubPageName();
+
+    [Fact]
+    public abstract Task OnGetAsync_sets_correct_data_source_list();
+}
diff --git a/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Schools/Overview/BaseOverviewAreaModelTests.cs b/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Schools/Overview/BaseOverviewAreaModelTests.cs
new file mode 100644
index 000000000..f0acba6df
--- /dev/null
+++ b/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Schools/Overview/BaseOverviewAreaModelTests.cs
@@ -0,0 +1,20 @@
+﻿using DfE.FindInformationAcademiesTrusts.Pages.Schools.Overview;
+
+namespace DfE.FindInformationAcademiesTrusts.UnitTests.Pages.Schools.Overview;
+
+public abstract class BaseOverviewAreaModelTests<T> : BaseSchoolPageTests<T> where T : OverviewAreaModel
+{
+    [Fact]
+    public override Task OnGetAsync_should_configure_PageMetadata_PageName()
+    {
+        Sut.PageMetadata.PageName.Should().Be("Overview");
+        return Task.CompletedTask;
+    }
+
+    [Fact]
+    public override Task OnGetAsync_sets_correct_data_source_list()
+    {
+        Sut.DataSourcesPerPage.Should().BeEmpty();
+        return Task.CompletedTask;
+    }
+}
diff --git a/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Schools/Overview/DetailsModelTests.cs b/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Schools/Overview/DetailsModelTests.cs
new file mode 100644
index 000000000..aa5e70d68
--- /dev/null
+++ b/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Schools/Overview/DetailsModelTests.cs
@@ -0,0 +1,48 @@
+﻿using DfE.FindInformationAcademiesTrusts.Data.Enums;
+using DfE.FindInformationAcademiesTrusts.Pages.Schools.Overview;
+
+namespace DfE.FindInformationAcademiesTrusts.UnitTests.Pages.Schools.Overview;
+
+public class DetailsModelTests : BaseOverviewAreaModelTests<DetailsModel>
+{
+    public DetailsModelTests()
+    {
+        Sut = new DetailsModel();
+    }
+
+    [Fact]
+    public override async Task OnGetAsync_should_configure_PageMetadata_SubPageName()
+    {
+        await OnGetAsync_should_configure_PageMetadata_SubPageName_for_school();
+        await OnGetAsync_should_configure_PageMetadata_SubPageName_for_academy();
+    }
+
+    private Task OnGetAsync_should_configure_PageMetadata_SubPageName_for_school()
+    {
+        Sut.Urn = "222222";
+        Sut.PageMetadata.SubPageName.Should().Be("School details");
+        return Task.CompletedTask;
+    }
+
+    private Task OnGetAsync_should_configure_PageMetadata_SubPageName_for_academy()
+    {
+        Sut.Urn = "123456";
+        Sut.PageMetadata.SubPageName.Should().Be("Academy details");
+        return Task.CompletedTask;
+    }
+
+    [Theory]
+    [InlineData(SchoolCategory.LaMaintainedSchool, "School details")]
+    [InlineData(SchoolCategory.Academy, "Academy details")]
+    public void SubPageName_should_include_school_type(SchoolCategory schoolCategory, string expectedSubPageName)
+    {
+        DetailsModel.SubPageName(schoolCategory).Should().Be(expectedSubPageName);
+    }
+
+    [Fact]
+    public void SubPageName_should_throw_for_unrecognised_school_type()
+    {
+        var act = () => DetailsModel.SubPageName((SchoolCategory)999);
+        act.Should().Throw<ArgumentOutOfRangeException>();
+    }
+}
diff --git a/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Schools/SchoolNavMenu/SchoolNavMenuServiceNavTests.cs b/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Schools/SchoolNavMenu/SchoolNavMenuServiceNavTests.cs
new file mode 100644
index 000000000..71109906c
--- /dev/null
+++ b/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Schools/SchoolNavMenu/SchoolNavMenuServiceNavTests.cs
@@ -0,0 +1,77 @@
+using DfE.FindInformationAcademiesTrusts.Data.Enums;
+using DfE.FindInformationAcademiesTrusts.Pages.Schools.Overview;
+using Sut = DfE.FindInformationAcademiesTrusts.Pages.Schools.SchoolNavMenu;
+
+namespace DfE.FindInformationAcademiesTrusts.UnitTests.Pages.Schools.SchoolNavMenu;
+
+public class SchoolNavMenuServiceNavTests : SchoolNavMenuTestsBase
+{
+    [Theory]
+    [InlineData("1234")]
+    [InlineData("5678")]
+    public void GetServiceNavLinks_should_set_route_data_to_urn(string expectedUrn)
+    {
+        var activePage = GetMockSchoolPage(typeof(DetailsModel), expectedUrn);
+
+        var results = Sut.GetServiceNavLinks(activePage);
+
+        results.Should().AllSatisfy(link =>
+        {
+            var route = link.AspAllRouteData.Should().ContainSingle().Subject;
+            route.Key.Should().Be("urn");
+            route.Value.Should().Be(expectedUrn);
+        });
+    }
+
+    [Theory]
+    [InlineData(SchoolCategory.LaMaintainedSchool, "School")]
+    [InlineData(SchoolCategory.Academy, "Academy")]
+    public void GetServiceNavLinks_should_set_hidden_text_to_school_type(SchoolCategory schoolCategory,
+        string expectedHiddenText)
+    {
+        var activePage = GetMockSchoolPage(typeof(DetailsModel), schoolCategory: schoolCategory);
+
+        var results = Sut.GetServiceNavLinks(activePage);
+
+        results.Should().AllSatisfy(link => { link.VisuallyHiddenLinkText.Should().Be(expectedHiddenText); });
+    }
+
+    [Fact]
+    public void GetServiceNavLinks_should_return_expected_links()
+    {
+        var activePage = GetMockSchoolPage(typeof(DetailsModel));
+
+        var results = Sut.GetServiceNavLinks(activePage);
+
+        results.Should().SatisfyRespectively(
+            l =>
+            {
+                l.LinkDisplayText.Should().Be("Overview");
+                l.AspPage.Should().Be("/Schools/Overview/Details");
+                l.TestId.Should().Be("overview-nav");
+            }
+        );
+    }
+
+    [Theory]
+    [MemberData(nameof(SubPageTypes))]
+    public void GetServiceNavLinks_should_set_active_page_link_when_on_any_subpage(Type activePageType)
+    {
+        var activePage = GetMockSchoolPage(activePageType);
+        var expectedActivePageLink = GetExpectedServiceNavAspLink(activePageType);
+
+        var results = Sut.GetServiceNavLinks(activePage);
+
+        results.Should().ContainSingle(l => l.LinkIsActive).Which.AspPage.Should().Be(expectedActivePageLink);
+    }
+
+    private static string GetExpectedServiceNavAspLink(Type pageType)
+    {
+        return pageType.Name switch
+        {
+            nameof(DetailsModel) => "/Schools/Overview/Details",
+            _ => throw new ArgumentException("Couldn't get expected service nav asp link for given page type",
+                nameof(pageType))
+        };
+    }
+}
diff --git a/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Schools/SchoolNavMenu/SchoolNavMenuSubNavTests.cs b/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Schools/SchoolNavMenu/SchoolNavMenuSubNavTests.cs
new file mode 100644
index 000000000..99eb9e02e
--- /dev/null
+++ b/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Schools/SchoolNavMenu/SchoolNavMenuSubNavTests.cs
@@ -0,0 +1,114 @@
+using DfE.FindInformationAcademiesTrusts.Data.Enums;
+using DfE.FindInformationAcademiesTrusts.Pages.Schools;
+using DfE.FindInformationAcademiesTrusts.Pages.Schools.Overview;
+using Sut = DfE.FindInformationAcademiesTrusts.Pages.Schools.SchoolNavMenu;
+
+namespace DfE.FindInformationAcademiesTrusts.UnitTests.Pages.Schools.SchoolNavMenu;
+
+public class SchoolNavMenuSubNavTests : SchoolNavMenuTestsBase
+{
+    [Theory]
+    [InlineData("1234")]
+    [InlineData("5678")]
+    public void GetSubNavLinks_should_set_route_data_to_urn(string expectedUrn)
+    {
+        var activePage = GetMockSchoolPage(typeof(DetailsModel), expectedUrn);
+
+        var results = Sut.GetSubNavLinks(activePage);
+
+        results.Should().AllSatisfy(link =>
+        {
+            var route = link.AspAllRouteData.Should().ContainSingle().Subject;
+            route.Key.Should().Be("urn");
+            route.Value.Should().Be(expectedUrn);
+        });
+    }
+
+    [Theory]
+    [MemberData(nameof(SubPageTypes))]
+    public void GetSubNavLinks_should_set_hidden_text_to_page_name(Type activePageType)
+    {
+        var activePage = GetMockSchoolPage(activePageType);
+        var expectedPageName = GetExpectedPageName(activePageType);
+
+        var results = Sut.GetSubNavLinks(activePage);
+
+        results.Should().AllSatisfy(link => { link.VisuallyHiddenLinkText.Should().Be(expectedPageName); });
+    }
+
+    private static string GetExpectedPageName(Type pageType)
+    {
+        return pageType.Name switch
+        {
+            nameof(DetailsModel) => "Overview",
+            _ => throw new ArgumentException("Couldn't get expected name for given page type", nameof(pageType))
+        };
+    }
+
+    [Theory]
+    [MemberData(nameof(SubPageTypes))]
+    public void GetSubNavLinks_should_set_active_sub_page_link(Type activePageType)
+    {
+        var activePage = GetMockSchoolPage(activePageType);
+        var expectedActiveSubPageLink = GetSubPageLinkTo(activePageType);
+
+        var results = Sut.GetSubNavLinks(activePage);
+
+        results.Should().ContainSingle(l => l.LinkIsActive).Which.AspPage.Should().Be(expectedActiveSubPageLink);
+    }
+
+    private static string GetSubPageLinkTo(Type pageType)
+    {
+        return pageType.Name switch
+        {
+            nameof(DetailsModel) => "/Schools/Overview/Details",
+            _ => throw new ArgumentException("Couldn't get expected sub page nav asp link for given page type",
+                nameof(pageType))
+        };
+    }
+
+    [Fact]
+    public void GetSubNavLinks_should_return_expected_links_for_overview_when_school()
+    {
+        var activePage = GetMockSchoolPage(typeof(DetailsModel), schoolCategory: SchoolCategory.LaMaintainedSchool);
+
+        var results = Sut.GetSubNavLinks(activePage);
+
+        results.Should().SatisfyRespectively(
+            l =>
+            {
+                l.LinkDisplayText.Should().Be("School details");
+                l.AspPage.Should().Be("/Schools/Overview/Details");
+                l.TestId.Should().Be("overview-details-subnav");
+            }
+        );
+    }
+
+    [Fact]
+    public void GetSubNavLinks_should_return_expected_links_for_overview_when_academy()
+    {
+        var activePage = GetMockSchoolPage(typeof(DetailsModel), schoolCategory: SchoolCategory.Academy);
+
+        var results = Sut.GetSubNavLinks(activePage);
+
+        results.Should().SatisfyRespectively(
+            l =>
+            {
+                l.LinkDisplayText.Should().Be("Academy details");
+                l.AspPage.Should().Be("/Schools/Overview/Details");
+                l.TestId.Should().Be("overview-details-subnav");
+            }
+        );
+    }
+
+    [Fact]
+    public void GetSubNavLinks_should_throw_if_page_not_supported()
+    {
+        var activePage = Substitute.For<ISchoolAreaModel>();
+
+        var action = () => Sut.GetSubNavLinks(activePage);
+
+        action.Should().Throw<ArgumentOutOfRangeException>()
+            .Which.Message.Should().StartWith("Page type is not supported.");
+    }
+}
diff --git a/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Schools/SchoolNavMenu/SchoolNavMenuTestsBase.cs b/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Schools/SchoolNavMenu/SchoolNavMenuTestsBase.cs
new file mode 100644
index 000000000..242dcb8f3
--- /dev/null
+++ b/tests/DfE.FindInformationAcademiesTrusts.UnitTests/Pages/Schools/SchoolNavMenu/SchoolNavMenuTestsBase.cs
@@ -0,0 +1,33 @@
+using DfE.FindInformationAcademiesTrusts.Data.Enums;
+using DfE.FindInformationAcademiesTrusts.Pages.Schools;
+using DfE.FindInformationAcademiesTrusts.Pages.Schools.Overview;
+
+namespace DfE.FindInformationAcademiesTrusts.UnitTests.Pages.Schools.SchoolNavMenu;
+
+public abstract class SchoolNavMenuTestsBase
+{
+    public static TheoryData<Type> SubPageTypes =>
+    [
+        //Overview
+        typeof(DetailsModel)
+    ];
+
+    protected static SchoolAreaModel GetMockSchoolPage(Type pageType, string? urn = null,
+        SchoolCategory schoolCategory = SchoolCategory.LaMaintainedSchool)
+    {
+        //Create a mock page
+        var parameters = pageType.GetConstructors()[0].GetParameters();
+        var arguments = parameters.Select(p => p.ParameterType.Name switch
+        {
+            _ => Substitute.For([p.ParameterType], [])
+        }).ToArray();
+
+        var mockPage = Activator.CreateInstance(pageType, arguments) as SchoolAreaModel ??
+                       throw new ArgumentException("Couldn't create mock for given page type", nameof(pageType));
+
+        //Set properties applicable to all types
+        mockPage.Urn = urn ?? (schoolCategory == SchoolCategory.Academy ? "123456" : "222222");
+
+        return mockPage;
+    }
+}


Reviews:
user: login: SteBradbury
state: DISMISSED
author_association: COLLABORATOR
submitted_at: 2025-04-17T14:45:29Z
user: login: dynamictulip
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-24T13:12:11Z
user: login: dynamictulip
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-24T13:38:12Z
user: login: SteBradbury
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-04-24T14:25:54Z

Review comments:
diff_hunk: @@ -1,47 +1,49 @@
-import searchPage from "../../pages/searchPage";
-import headerPage from "../../pages/headerPage";
+import searchPage from '../../pages/searchPage';
+import headerPage from '../../pages/headerPage';
 
-describe("Testing the components of the header search", () => {
+describe(`Testing the components of the header search`, () => {
 
-    beforeEach(() => {
-        cy.login();
-        cy.visit('/trusts/overview/trust-details?uid=5527');
-    });
+    [`/schools/overview/details?uid=5712`, `/trusts/overview/trust-details?uid=5527`].forEach((url) => {
path: tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/header-search-page.cy.ts
user: login: dynamictulip
body: The schools url should go to a valid urn
created_at: 2025-04-24T13:12:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,85 @@
+import navigation from "../../../pages/navigation";
+import { testSchoolData, testTrustData } from "../../../support/test-data-store";
+
+describe('Testing Navigation', () => {
+
+    describe("Testing the breadcrumb-links", () => {
+        beforeEach(() => {
+            cy.login();
+        });
+
+        describe("Testing the general page breadcrumb links and their relevant functionality", () => {
+            beforeEach(() => {
+                cy.login();
+            });
+
+            ['/search', '/accessibility', '/cookies', '/privacy', '/notfound'].forEach((url) => {
+                it(`Should have Home breadcrumb only on ${url}`, () => {
+                    cy.visit(url, { failOnStatusCode: false });
+
+                    navigation
+                        .checkCurrentURLIsCorrect(url)
+                        .checkHomeBreadcrumbPresent()
+                        .clickHomeBreadcrumbButton()
+                        .checkBrowserPageTitleContains('Home page');
+                });
+            });
+
+            ['/', '/error'].forEach((url) => {
+                it(`Should have no breadcrumb on ${url}`, () => {
+                    cy.visit(url);
+
+                    navigation
+                        .checkCurrentURLIsCorrect(url)
+                        .checkAccessibilityStatementLinkPresent() // ensure page content has loaded - all pages have an a11y statement link
+                        .checkBreadcrumbNotPresent();
+                });
+            });
+        });
+
+        describe("Testing the breadcrumb links on the trust academy details page", () => {
+            beforeEach(() => {
+                cy.login();
+            });
+
+            describe("Testing the breadcrumb links on the trust page", () => {
+                testTrustData.forEach(({ uid, trustName }) => {
+                    it('Should check that a trusts name breadcrumb is displayed on the trusts page', () => {
+                        cy.visit(`/trusts/overview/trust-details?uid=${uid}`);
+                        navigation
+                            .checkTrustNameBreadcrumbPresent(`${trustName}`)
+                            .clickHomeBreadcrumbButton()
+                            .checkBrowserPageTitleContains('Home page');
+                    });
+                });
+            });
+
+            describe("Testing the breadcrumb links on the pipeline academies pages", () => {
+                [`/trusts/academies/pipeline/pre-advisory-board?uid=16002`, `/trusts/academies/pipeline/post-advisory-board?uid=17584`, `/trusts/academies/pipeline/free-schools?uid=17584`].forEach((url) => {
+                    it("Checks the breadcrumb shows the correct page name", () => {
+                        cy.visit(url);
+                        navigation
+                            .checkPageNameBreadcrumbPresent("Academies");
+                        //revist adding this later need to rethink how the foreach handles differing uid pulls for the differnt pages .checkTrustNameBreadcrumbPresent('Ashton West End Primary Academy');
+                    });
+                });
+            });
+        });
+    });
+
+    describe("Testing the breadcrumb links on the schools overview pages", () => {
+        testSchoolData.forEach(({ urn }) => {
+            beforeEach(() => {
+                cy.login();
+            });
+
+            [`/schools/overview/details?uid=${urn}`].forEach((url) => {
path: tests/DFE.FindInformationAcademiesTrusts.CypressTests/cypress/e2e/regression/navigation/breadcrumb-links.cy.ts
user: login: dynamictulip
body: This one should be a urn
created_at: 2025-04-24T13:38:11Z
author_association: CONTRIBUTOR

PR comments:
user: login: sonarqubecloud[bot]
created_at: 2025-04-24T14:01:06Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=DFE-Digital_find-information-about-academies-and-trusts&pullRequest=799) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=DFE-Digital_find-information-about-academies-and-trusts&pullRequest=799&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=DFE-Digital_find-information-about-academies-and-trusts&pullRequest=799&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=DFE-Digital_find-information-about-academies-and-trusts&pullRequest=799&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [100.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=DFE-Digital_find-information-about-academies-and-trusts&pullRequest=799&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=DFE-Digital_find-information-about-academies-and-trusts&pullRequest=799&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=DFE-Digital_find-information-about-academies-and-trusts&pullRequest=799)


author_association: NONE