diff --git a/common/services/prismic/link-resolver.ts b/common/services/prismic/link-resolver.ts index fa4a3b172d..f891bf943e 100644 --- a/common/services/prismic/link-resolver.ts +++ b/common/services/prismic/link-resolver.ts @@ -7,6 +7,8 @@ type Props = { type: string; siteSection?: SiteSection; }; + +// Untransformed data type DataProps = { uid?: string; type: string; @@ -20,7 +22,8 @@ type DataProps = { }; function linkResolver(doc: Props | DataProps): string { - // this is mostly useful for scenarios like rendering in Page Builder + // This is mostly useful for scenarios like rendering in Page Builder + // which doesn't necessarily have access to all data if (!doc) return '/'; const { uid, type } = doc; @@ -52,18 +55,20 @@ function linkResolver(doc: Props | DataProps): string { } if (type === 'pages') { - if ('siteSection' in doc) { - return `${doc.siteSection}/${uid}`; - } else if ('tags' in doc) { - // Needed for Prismic previews - const docSiteSection = doc.tags.find(t => isSiteSection(t)); + let siteSection: SiteSection | undefined; - const isLandingPage = docSiteSection === uid; - if (isLandingPage) return `/${uid}`; + if ('siteSection' in doc) { + siteSection = doc.siteSection; + } - return `${docSiteSection ? '/' + docSiteSection : ''}/${uid}`; + // Prismic previews come through here. + if ('tags' in doc) { + siteSection = doc.tags.find(t => isSiteSection(t)); } - return `/${uid}`; + + const isLandingPage = siteSection === uid; + + return isLandingPage || !siteSection ? `/${uid}` : `/${siteSection}/${uid}`; } if (isContentType(type)) { diff --git a/content/webapp/pages/events/[eventId]/index.tsx b/content/webapp/pages/events/[eventId]/index.tsx index a6e6023e84..031ea5606a 100644 --- a/content/webapp/pages/events/[eventId]/index.tsx +++ b/content/webapp/pages/events/[eventId]/index.tsx @@ -185,14 +185,11 @@ const EventPage: NextPage = ({ url: '/events', text: 'Events', }, - ...event.series.map(series => { - console.log(series); - return { - url: linkResolver(series), - text: series.title || '', - prefix: 'Part of', - }; - }), + ...event.series.map(series => ({ + url: linkResolver(series), + text: series.title || '', + prefix: 'Part of', + })), scheduledIn ? { url: linkResolver(scheduledIn), diff --git a/content/webapp/pages/pages/[pageId].tsx b/content/webapp/pages/pages/[pageId].tsx index d279acfd6d..8c9ca64656 100644 --- a/content/webapp/pages/pages/[pageId].tsx +++ b/content/webapp/pages/pages/[pageId].tsx @@ -108,7 +108,13 @@ export const getServerSideProps: GetServerSideProps< const { pageId } = context.query; const siteSection = toMaybeString(context.params?.siteSection); - if (!looksLikePrismicId(pageId)) { + // We don't allow e.g. /visit-us/visit-us as it's a landing page + // Should only display on /visit-us + const isLandingPageRenderingAsSubPage = + pageId === siteSection && + context.resolvedUrl.indexOf(`/${siteSection}/${pageId}`) === 0; + + if (!looksLikePrismicId(pageId) || isLandingPageRenderingAsSubPage) { return { notFound: true }; } @@ -123,10 +129,16 @@ export const getServerSideProps: GetServerSideProps< const basicDocSiteSection = basicDocument.tags.find(t => isSiteSection(t) ); + const isLandingPage = basicDocSiteSection === pageId; + + const redirectUrl = + isLandingPage || !basicDocSiteSection + ? `/${pageId}` + : `/${basicDocSiteSection}/${pageId}`; return { redirect: { - destination: `${basicDocSiteSection ? '/' + basicDocSiteSection : ''}/${basicDocument.uid}`, + destination: redirectUrl, permanent: false, }, }; diff --git a/content/webapp/services/prismic/transformers/exhibition-guides.test.ts b/content/webapp/services/prismic/transformers/exhibition-guides.test.ts index 8c122c962d..fbd9d94746 100644 --- a/content/webapp/services/prismic/transformers/exhibition-guides.test.ts +++ b/content/webapp/services/prismic/transformers/exhibition-guides.test.ts @@ -213,7 +213,6 @@ describe('transformExhibitionGuide', () => { it('returns a set of components', () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any const exhibition = transformExhibitionGuide(exhibitionGuidesDoc as any); - console.log(exhibition.components.length, 'the exhibition'); expect(exhibition.components.length).toBe(2); }); }); diff --git a/playwright/test/helpers/contexts.ts b/playwright/test/helpers/contexts.ts index 38cd062ef1..71945eda6b 100644 --- a/playwright/test/helpers/contexts.ts +++ b/playwright/test/helpers/contexts.ts @@ -84,9 +84,7 @@ const stageApiToggleCookie = createCookie({ value: 'true', }); -// TODO: context.addCookies should run for the first test of a suite (even on beforeAll/beforeEach) - -const requiredCookies = useStageApis +export const requiredCookies = useStageApis ? [acceptCookieCookie, stageApiToggleCookie] : [acceptCookieCookie]; diff --git a/playwright/test/pages.test.ts b/playwright/test/pages.test.ts new file mode 100644 index 0000000000..dfaf9f4311 --- /dev/null +++ b/playwright/test/pages.test.ts @@ -0,0 +1,32 @@ +import { expect, test } from '@playwright/test'; + +import { gotoWithoutCache, requiredCookies } from './helpers/contexts'; +import { baseUrl } from './helpers/utils'; + +test.describe('Server-side redirection logic works as expected', () => { + test('/pages/ route redirects to relevant URL', async ({ context, page }) => { + await context.addCookies(requiredCookies); + + // Visit Us site section + await gotoWithoutCache(`${baseUrl}/pages/accessibility`, page); + await expect(page.url()).toEqual(`${baseUrl}/visit-us/accessibility`); + + // Orphan page + await gotoWithoutCache(`${baseUrl}/pages/contact-us`, page); + await expect(page.url()).toEqual(`${baseUrl}/contact-us`); + }); + + test("Landing pages don't have a parent route", async ({ context, page }) => { + await context.addCookies(requiredCookies); + + await gotoWithoutCache(`${baseUrl}/visit-us/visit-us`, page); + await expect( + page + .getByRole('heading') + .getByText('Not the Wellcome you were expecting?') + ).toBeVisible(); + + await gotoWithoutCache(`${baseUrl}/pages/visit-us`, page); + await expect(page.url()).toEqual(`${baseUrl}/visit-us`); + }); +});