Skip to content

Commit 07d4cd4

Browse files
committed
test(spec): pin that the id route is NOT read for a region-level page:header
The batch #58 pin in i18n-resolver.test.ts stayed green with the gate reverted to `if (addressed)`: homeBundle carries pages.sales_home_page.label, so the page-name overlay wins for `title` whether or not the id route was read. The test pinned precedence (page name wins when both routes are present) while its title claimed "page name only" - a pin that cannot fail on the regression it names. Split into two tests. The precedence pin keeps its body under a title that says what it measures. A new pin hands translatePage an id-only bundle (no pages.PAGE.label / title / subtitle), so the page-name overlay has nothing to win with and only the id route could move the header title, and asserts the authored title survives. Two controls keep the empty reading honest: the same id-only bundle translates the component that owns the id, and a nested page:header with that id stays id-addressed. Only the test file changes; the resolver, extractor, cli parity pin and changeset are untouched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T6HeZvT9wdSJD1ZxJb5Eno
1 parent e34ab34 commit 07d4cd4

1 file changed

Lines changed: 71 additions & 22 deletions

File tree

packages/spec/src/system/i18n-resolver.test.ts

Lines changed: 71 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1376,29 +1376,44 @@ describe('translatePage', () => {
13761376
// doc already says. One component, one address — `title` and `subtitle`
13771377
// now follow the same rule."
13781378
//
1379-
// This test previously asserted the OPPOSITE (`title` resolving to
1380-
// `快速新建`, the id route beating the page-name one). It is inverted, not
1381-
// deleted, because the inversion IS the behaviour change the ruling
1382-
// records: the id route was live for this component and preferred, and a
1383-
// bundle that used it now falls back to the page-name key.
1384-
it('reads a region-level `page:header` by page name only, id or no id (batch #58)', () => {
1385-
const doc = {
1386-
name: 'sales_home_page',
1387-
regions: [{
1388-
name: 'header',
1389-
// `properties` widened to the open bag it is: the overlay adds keys
1390-
// the literal does not spell out, and inferring it as `{title}` alone
1391-
// would make reading the result a type error.
1392-
components: [{
1393-
type: 'page:header',
1394-
id: 'quick_create',
1395-
properties: { title: 'Sales Home' } as Record<string, string>,
1396-
}],
1379+
// The ruling has two halves, and one bundle cannot measure both — so two
1380+
// pins. `homeBundle` carries `pages.sales_home_page.label`, and the
1381+
// page-name overlay is applied AFTER the id route and wins for `title`
1382+
// whether or not the id route was read: against that bundle the header's
1383+
// `title` reads `销售看板` on a resolver that still reads the id route.
1384+
// That is a real invariant (precedence when both routes are present) and
1385+
// the first pin names it as exactly that — it is NOT evidence that the id
1386+
// route is closed. The second pin hands the resolver an id-ONLY bundle —
1387+
// no `pages.<name>.label`, no `pages.<name>.title` — so the page-name
1388+
// overlay has nothing to win with and only the id route could move the
1389+
// title. Measured with the gate reverted to `if (addressed)`: the first
1390+
// pin stays green, the second goes red.
1391+
//
1392+
// A region-level `page:header` that carries an id. `properties` is
1393+
// widened to the open bag it is: the overlay adds keys the literal does
1394+
// not spell out, and inferring it as `{title}` alone would make reading
1395+
// the result a type error.
1396+
const regionHeaderWithId = () => ({
1397+
name: 'sales_home_page',
1398+
regions: [{
1399+
name: 'header',
1400+
components: [{
1401+
type: 'page:header',
1402+
id: 'quick_create',
1403+
properties: { title: 'Sales Home' } as Record<string, string>,
13971404
}],
1398-
};
1399-
const out = translatePage(doc, homeBundle, { locale: 'zh-CN' });
1400-
// `components.quick_create.title` (`快速新建`) is NOT read here — the
1401-
// page-name route is, falling back to `pages.<name>.label` for `title`.
1405+
}],
1406+
});
1407+
1408+
// Previously this asserted the OPPOSITE (`title` resolving to `快速新建`,
1409+
// the id route beating the page-name one). Inverted, not deleted, because
1410+
// the inversion IS the behaviour change the ruling records: the id route
1411+
// was live for this component and preferred, and a bundle that used it
1412+
// now falls back to the page-name key.
1413+
it('prefers the page-name route over the id route for a region-level `page:header` when a bundle carries both (batch #58)', () => {
1414+
const out = translatePage(regionHeaderWithId(), homeBundle, { locale: 'zh-CN' });
1415+
// `components.quick_create.title` (`快速新建`) does not win here — the
1416+
// page-name route does, falling back to `pages.<name>.label` for `title`.
14021417
expect(out.regions[0].components[0].properties.title).toBe('销售看板');
14031418
expect(out.regions[0].components[0].properties.subtitle).toBe('欢迎回来');
14041419
// Control: the very same bundle entry still reaches the component that
@@ -1408,6 +1423,40 @@ describe('translatePage', () => {
14081423
.properties.title).toBe('快速新建');
14091424
});
14101425

1426+
it('does not read the id route for a region-level `page:header` — an id-only bundle leaves its authored title alone (batch #58)', () => {
1427+
// No `pages.<name>.label` / `title` / `subtitle`: the page-name route
1428+
// resolves nothing for this page, so a translated title on the header
1429+
// could only have come from `components.quick_create.title`.
1430+
const idOnly: TranslationBundle = {
1431+
'zh-CN': { pages: { sales_home_page: { components: { quick_create: { title: '快速新建' } } } } },
1432+
};
1433+
const out = translatePage(regionHeaderWithId(), idOnly, { locale: 'zh-CN' });
1434+
expect(out.regions[0].components[0].properties.title).toBe('Sales Home');
1435+
// Control 1: the same id-only bundle DOES translate the component that
1436+
// owns the id, so the authored title above is the header's id route
1437+
// being closed and not a bundle nothing can resolve.
1438+
expect(byId(translatePage(homePage(), idOnly, { locale: 'zh-CN' }), 'quick_create')
1439+
.properties.title).toBe('快速新建');
1440+
// Control 2: a `page:header` NESTED in a container stays id-addressed —
1441+
// the ruling closes the id route at region level only, and the id route
1442+
// is the only one that reaches a nested header.
1443+
const nestedDoc = {
1444+
name: 'sales_home_page',
1445+
regions: [{
1446+
name: 'main',
1447+
components: [{
1448+
type: 'page:card',
1449+
id: 'wrapper',
1450+
properties: {
1451+
children: [{ type: 'page:header', id: 'quick_create', properties: { title: 'Sales Home' } as Record<string, string> }],
1452+
},
1453+
}],
1454+
}],
1455+
};
1456+
const nested = translatePage(nestedDoc, idOnly, { locale: 'zh-CN' });
1457+
expect((nested.regions[0].components[0].properties.children as any[])[0].properties.title).toBe('快速新建');
1458+
});
1459+
14111460
it('does not mutate the input page', () => {
14121461
const doc = homePage();
14131462
const snapshot = JSON.parse(JSON.stringify(doc));

0 commit comments

Comments
 (0)