From 429efc7312934f3756b1fa5f146d55b9eddc2d8d Mon Sep 17 00:00:00 2001 From: Fadhlan Ridhwanallah Date: Mon, 2 Feb 2026 15:41:32 +0700 Subject: [PATCH 1/2] Fix: ember-page-title errors when head format template contains --- packages/base/default-templates/head.gts | 3 +- packages/host/app/index.html | 96 +++++++++---------- .../host/app/services/host-mode-service.ts | 26 +++-- .../tests/acceptance/prerender-html-test.gts | 3 +- .../matrix/helpers/isolated-realm-server.ts | 2 +- packages/realm-server/server.ts | 9 +- packages/realm-server/tests/indexing-test.ts | 11 +-- .../realm-server/tests/prerendering-test.ts | 13 ++- 8 files changed, 87 insertions(+), 76 deletions(-) diff --git a/packages/base/default-templates/head.gts b/packages/base/default-templates/head.gts index 6e7d893f37a..4209e250b30 100644 --- a/packages/base/default-templates/head.gts +++ b/packages/base/default-templates/head.gts @@ -23,8 +23,7 @@ export default class DefaultHeadTemplate extends GlimmerComponent<{ <template> {{! template-lint-disable no-forbidden-elements }} - {{! TODO: restore in CS-9807 }} - {{!-- <title data-test-card-head-title>{{this.title}} --}} + {{this.title}} diff --git a/packages/host/app/index.html b/packages/host/app/index.html index cdb36deefab..570dafe5056 100644 --- a/packages/host/app/index.html +++ b/packages/host/app/index.html @@ -1,54 +1,48 @@ - - - Boxel - - - - {{content-for "head"}} - - - - - - - - - - {{content-for "head-footer"}} - - - - - - - - - - -
- {{content-for "body"}} - - - - - - {{content-for "body-footer"}} - - +
+ {{content-for "body"}} + + + + + + {{content-for "body-footer"}} + + + \ No newline at end of file diff --git a/packages/host/app/services/host-mode-service.ts b/packages/host/app/services/host-mode-service.ts index 0653779e9c6..6a06d43289d 100644 --- a/packages/host/app/services/host-mode-service.ts +++ b/packages/host/app/services/host-mode-service.ts @@ -3,6 +3,18 @@ import Service, { service } from '@ember/service'; import window from 'ember-window-mock'; import config from '@cardstack/host/config/environment'; + +const DEFAULT_HEAD_HTML = 'Boxel'; + +function headContainsTitle(html: string): boolean { + return /]/.test(html); +} + +function ensureSingleTitle(headHTML: string): string { + return headContainsTitle(headHTML) + ? headHTML + : `${DEFAULT_HEAD_HTML}\n${headHTML}`; +} import type HostModeStateService from '@cardstack/host/services/host-mode-state-service'; import type OperatorModeStateService from '@cardstack/host/services/operator-mode-state-service'; import type RealmService from '@cardstack/host/services/realm'; @@ -192,7 +204,9 @@ export default class HostModeService extends Service { return; } - this.replaceHeadTemplate(headHTML); + this.replaceHeadTemplate( + headHTML !== null ? ensureSingleTitle(headHTML) : null, + ); } private async fetchPrerenderedHead( @@ -270,11 +284,11 @@ export default class HostModeService extends Service { node = next; } - if (!headHTML || headHTML.trim().length === 0) { - return; - } - - let fragment = document.createRange().createContextualFragment(headHTML); + let contentToInsert = + !headHTML || headHTML.trim().length === 0 ? DEFAULT_HEAD_HTML : headHTML; + let fragment = document + .createRange() + .createContextualFragment(contentToInsert); parent.insertBefore(fragment, end); } diff --git a/packages/host/tests/acceptance/prerender-html-test.gts b/packages/host/tests/acceptance/prerender-html-test.gts index f84ce5e6679..b3aef30d07d 100644 --- a/packages/host/tests/acceptance/prerender-html-test.gts +++ b/packages/host/tests/acceptance/prerender-html-test.gts @@ -578,8 +578,7 @@ module('Acceptance | prerender | html', function (hooks) { test('prerender head html', async function (assert) { let url = `${testRealmURL}Cat/paper.json`; await visit(renderPath(url, '/html/head/0')); - // TODO: restore in CS-9807 - // assert.dom(`title`).containsText('Paper', 'head format is rendered'); + assert.dom(`title`).containsText('Paper', 'head format is rendered'); assert.dom('meta[property="og:title"]').hasAttribute('content', 'Paper'); }); diff --git a/packages/matrix/helpers/isolated-realm-server.ts b/packages/matrix/helpers/isolated-realm-server.ts index 06168e84511..23cd25653ea 100644 --- a/packages/matrix/helpers/isolated-realm-server.ts +++ b/packages/matrix/helpers/isolated-realm-server.ts @@ -333,7 +333,7 @@ export async function startServer({ }; realmServer.on('message', onMessage); }), - new Promise((r) => setTimeout(() => r(true), 60_000)), + new Promise((r) => setTimeout(() => r(true), 30000_000)), ]); if (timeout) { throw new Error( diff --git a/packages/realm-server/server.ts b/packages/realm-server/server.ts index e6df1c22042..570808e6a79 100644 --- a/packages/realm-server/server.ts +++ b/packages/realm-server/server.ts @@ -380,7 +380,7 @@ export class RealmServer { let headFragments: string[] = []; if (headHTML != null) { - headFragments.push(headHTML); + headFragments.push(this.ensureSingleTitle(headHTML)); } if (scopedCSS != null) { @@ -615,6 +615,13 @@ export class RealmServer { ) as Expression; } + private ensureSingleTitle(headHTML: string): string { + if (/]/.test(headHTML)) { + return headHTML; + } + return `Boxel\n${headHTML}`; + } + private truncateLogLines(value: string, maxLines = 3): string { let lines = value.split(/\r?\n/); if (lines.length <= maxLines) { diff --git a/packages/realm-server/tests/indexing-test.ts b/packages/realm-server/tests/indexing-test.ts index ca983533a68..82894ae3fc3 100644 --- a/packages/realm-server/tests/indexing-test.ts +++ b/packages/realm-server/tests/indexing-test.ts @@ -529,13 +529,12 @@ module(basename(__filename), function () { 'pre-rendered embedded format html is correct', ); + let cleanedHead = cleanWhiteSpace(entry.headHtml!); assert.ok(entry.headHtml, 'pre-rendered head format html is present'); - - // TODO: restore in CS-9807 - // assert.ok( - // cleanedHead.includes(''), - // `head html includes cardTitle: ${cleanedHead}`, - // ); + assert.ok( + cleanedHead.includes('<title data-test-card-head-title>'), + `head html includes cardTitle: ${cleanedHead}`, + ); assert.strictEqual( trimCardContainer( diff --git a/packages/realm-server/tests/prerendering-test.ts b/packages/realm-server/tests/prerendering-test.ts index 870b186bd61..88de3141fa0 100644 --- a/packages/realm-server/tests/prerendering-test.ts +++ b/packages/realm-server/tests/prerendering-test.ts @@ -1576,13 +1576,12 @@ module(basename(__filename), function () { assert.ok(result.headHTML, 'headHTML should be present'); let cleanedHead = cleanWhiteSpace(result.headHTML!); - // TODO: restore in CS-9807 - // assert.ok( - // cleanedHead.includes( - // '<title data-test-card-head-title>Untitled Cat', - // ), - // `failed to find title in head html:${cleanedHead}`, - // ); + assert.ok( + cleanedHead.includes( + 'Untitled Cat', + ), + `failed to find title in head html:${cleanedHead}`, + ); assert.ok( cleanedHead.includes('property="og:title" content="Untitled Cat"'), `failed to find og:title in head html:${cleanedHead}`, From 0ca659d5a5385fcbbfc34979719c6097c6bf4e70 Mon Sep 17 00:00:00 2001 From: Fadhlan Ridhwanallah Date: Mon, 2 Feb 2026 17:06:10 +0700 Subject: [PATCH 2/2] revert unnecessary change --- packages/matrix/helpers/isolated-realm-server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/matrix/helpers/isolated-realm-server.ts b/packages/matrix/helpers/isolated-realm-server.ts index 23cd25653ea..06168e84511 100644 --- a/packages/matrix/helpers/isolated-realm-server.ts +++ b/packages/matrix/helpers/isolated-realm-server.ts @@ -333,7 +333,7 @@ export async function startServer({ }; realmServer.on('message', onMessage); }), - new Promise((r) => setTimeout(() => r(true), 30000_000)), + new Promise((r) => setTimeout(() => r(true), 60_000)), ]); if (timeout) { throw new Error(