diff --git a/e2e/tests/journeys.spec.ts b/e2e/tests/journeys.spec.ts
index a5cc567..c168add 100644
--- a/e2e/tests/journeys.spec.ts
+++ b/e2e/tests/journeys.spec.ts
@@ -296,11 +296,13 @@ test('school type and gender switch straight to another value', async ({ page })
await gender.selectOption('boys');
await expect(page).toHaveURL(/[?&]gender=boys(&|$)/);
+ // Whatever types the data holds, choosing one leaves the same list on offer.
const type = page.getByRole('combobox', { name: 'School type', exact: true });
- const [first] = (await type.locator('option').allTextContents()).slice(1);
- await type.selectOption(first);
+ const offered = await type.locator('option').allTextContents();
+ expect(offered.length, 'no school type to choose').toBeGreaterThan(1);
+ await type.selectOption(offered[1]);
await expect(page).toHaveURL(/[?&]school_type=/);
- await expect.poll(() => type.locator('option').count()).toBeGreaterThan(2);
+ await expect.poll(() => type.locator('option').allTextContents()).toEqual(offered);
});
test('a phase outside primary/secondary filters to that phase, not to everything', async ({ page }) => {
diff --git a/nextjs-app/__tests__/components/FilterBarOptions.test.tsx b/nextjs-app/__tests__/components/FilterBarOptions.test.tsx
index 509b26f..35355b4 100644
--- a/nextjs-app/__tests__/components/FilterBarOptions.test.tsx
+++ b/nextjs-app/__tests__/components/FilterBarOptions.test.tsx
@@ -87,13 +87,19 @@ describe('the secondary-only filters', () => {
expect(shown(openSheet())).toEqual(secondaryOnly);
});
- it.each(['primary', 'nursery', 'middle deemed primary'])('hide for the %s phase', (phase) => {
+ it.each(['primary', 'nursery', 'middle deemed primary', 'Middle-deemed Primary'])(
+ 'hide for the %s phase', (phase) => {
params = new URLSearchParams(`postcode=SW196AR&radius=1&phase=${encodeURIComponent(phase)}`);
render();
expect(shown(openSheet())).toEqual([]);
});
- it.each(['secondary', 'all-through'])('show for the %s phase', (phase) => {
+ it('leave out a filter with no options, rather than show only its "any"', () => {
+ render();
+ expect(shown(openSheet())).toEqual(['Sixth form']);
+ });
+
+ it.each(['secondary', 'all-through', 'middle deemed secondary', '16 plus'])('show for the %s phase', (phase) => {
params = new URLSearchParams(`postcode=SW196AR&radius=1&phase=${phase}`);
render();
expect(shown(openSheet())).toEqual(secondaryOnly);
diff --git a/nextjs-app/components/FilterBar.tsx b/nextjs-app/components/FilterBar.tsx
index d2cc2ab..4f406c3 100644
--- a/nextjs-app/components/FilterBar.tsx
+++ b/nextjs-app/components/FilterBar.tsx
@@ -69,10 +69,19 @@ type FilterKey = (typeof FILTER_KEYS)[number];
/** Filters that only mean something for schools teaching beyond primary. */
const SECONDARY_ONLY_KEYS = ["gender", "has_sixth_form", "admissions_policy"] as const;
-/** Phases with no secondary-age pupils, for which those filters are hidden. */
-const PRIMARY_PHASES = new Set(["primary", "nursery", "middle deemed primary"]);
-
-const hasSecondaryFilters = (phase: string) => !PRIMARY_PHASES.has(phase.toLowerCase());
+/**
+ * False for a phase with no secondary-age pupils, for which those filters are
+ * hidden: Primary, Nursery and Middle deemed primary. Matched on the words,
+ * not exact labels, so a change of case, hyphen or spacing in the GIAS label
+ * cannot leave them showing. The same reading of "primary" as
+ * compareGroups in lib/compareLogic.ts. The API's PHASE_GROUPS answers a
+ * different question (which phases a phase filter returns: primary includes
+ * all-through), so it is not this list.
+ */
+function hasSecondaryFilters(phase: string): boolean {
+ const p = phase.toLowerCase().replace(/[^a-z]+/g, " ").trim();
+ return !(p === "nursery" || (p.includes("primary") && !p.includes("secondary")));
+}
function SlidersIcon() {
return (