Skip to content

Commit 560f739

Browse files
[test](i18n): runtime proof — Indonesian reaches every Insights sub-level
Render-level guard (jsdom) that mounts each Insights surface in lang=id and asserts Indonesian dataset/article copy actually appears — the defect the user reported ("Insights doesn't go deep with Indonesian at the deepest sub-levels"): - Lab / Roadmap / Academy: list AND drilled-in detail (watch/takeaway, step notes, quiz question + choices + explanation). - LearnView Playbook / Review / Library lenses (goal, verdict, definition, concepts) via the LensNav. - Markdown article body renders the ID side of the `<!-- lang:id -->` split (and asserts the English side is NOT shown). - lang=en still renders English with no ID leak. 108 -> 116 unit tests; all gates green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 0cb519d commit 560f739

1 file changed

Lines changed: 91 additions & 0 deletions

File tree

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { describe, it, expect, beforeEach, vi } from 'vitest';
2+
import { fireEvent, screen, within } from '@testing-library/react';
3+
import { renderWithI18n } from '../test/render';
4+
import LabView from './LabView';
5+
import RoadmapView from './RoadmapView';
6+
import AcademyView from './AcademyView';
7+
import LearnView from './LearnView';
8+
9+
// Runtime proof that the EN/ID toggle reaches the DEEPEST Insights sub-levels — not just the type
10+
// system. Each lens is rendered in Indonesian; we assert Indonesian dataset copy appears in the list
11+
// view AND after drilling into a detail view (steps/watch/takeaway/choices). Guards the exact defect
12+
// the user reported ("Insights doesn't go deep with Indonesian at the deepest sub-levels").
13+
14+
beforeEach(() => localStorage.clear());
15+
16+
describe('Insights renders Indonesian at the deepest sub-level (lang=id)', () => {
17+
it('Lab: list + experiment detail are in Indonesian', () => {
18+
renderWithI18n(<LabView onRun={vi.fn()} onOpenArch={vi.fn()} />, 'id');
19+
// List view shows each experiment's (translated) hypothesis.
20+
expect(screen.getByText(/lebih ditentukan oleh faktor tim\/organisasi/i)).toBeTruthy();
21+
// Drill into the first experiment → detail view.
22+
fireEvent.click(screen.getByText(/Kapan ukuran tim membalik D1\?/i));
23+
expect(screen.getByText(/Produk yang sudah terbukti dan sedang tumbuh/i)).toBeTruthy(); // brief
24+
expect(screen.getByText(/Peringkat D1 dan jarak antara modular monolith/i)).toBeTruthy(); // watch step
25+
expect(screen.getByText(/Bobot kemudahan rilis dan pemeliharaan mengikuti/i)).toBeTruthy(); // takeaway
26+
});
27+
28+
it('Roadmap: list + path detail are in Indonesian', () => {
29+
renderWithI18n(<RoadmapView onOpenArch={vi.fn()} onOpenArticle={vi.fn()} onOpenAdvisor={vi.fn()} />, 'id');
30+
expect(screen.getByText(/Mulai dari nol: apa itu keputusan arsitektur/i)).toBeTruthy(); // description
31+
fireEvent.click(screen.getByText(/Dasar-dasar arsitektur/i));
32+
expect(screen.getByText(/Kamu bisa menjelaskan gaya deployment dasar/i)).toBeTruthy(); // outcome
33+
expect(screen.getByText(/Kenali titik awal klasik lapisan/i)).toBeTruthy(); // step note (deepest)
34+
});
35+
36+
it('Academy: list + question/choices/explanation are in Indonesian', () => {
37+
renderWithI18n(<AcademyView onOpenArch={vi.fn()} onOpenArticle={vi.fn()} />, 'id');
38+
expect(screen.getByText(/kapan masing-masing sepadan dengan biayanya/i)).toBeTruthy(); // module description
39+
fireEvent.click(screen.getByText(/Deployment & komposisi/i));
40+
// Question + choices are translated.
41+
expect(screen.getByText(/default yang didukung bukti adalah/i)).toBeTruthy(); // q
42+
const correct = screen.getByText(/Monolith \(atau modular monolith\)/i); // choice
43+
expect(correct).toBeTruthy();
44+
// Answering reveals the (translated) explanation — the deepest sub-level.
45+
fireEvent.click(correct);
46+
expect(screen.getByText(/menyarankan membuktikan produk dan batasnya/i)).toBeTruthy(); // explain
47+
});
48+
49+
it('English still renders when lang=en (no accidental ID leak in the default)', () => {
50+
const { container } = renderWithI18n(<LabView onRun={vi.fn()} onOpenArch={vi.fn()} />, 'en');
51+
expect(within(container).getByText(/Deployment style \(D1\) is driven more by team/i)).toBeTruthy();
52+
expect(within(container).queryByText(/lebih ditentukan oleh faktor tim\/organisasi/i)).toBeNull();
53+
});
54+
});
55+
56+
describe('LearnView lenses + article bodies render Indonesian (lang=id)', () => {
57+
const renderLearn = () => renderWithI18n(<LearnView onOpenAdvisor={vi.fn()} onLoadLab={vi.fn()} />, 'id');
58+
59+
it('Playbook lens (insightPlaybooks) shows Indonesian goal + steps', () => {
60+
renderLearn();
61+
fireEvent.click(screen.getByRole('button', { name: /Playbook/ }));
62+
fireEvent.click(screen.getByRole('button', { name: /Serverless/ })); // English proper noun (model)
63+
expect(screen.getByText(/Fungsi yang dipicu event pada infrastruktur terkelola/i)).toBeTruthy(); // goal
64+
expect(screen.getByText(/Beban kerja yang berumur pendek, stateless/i)).toBeTruthy(); // prerequisite
65+
});
66+
67+
it('Review lens (insightReviews) shows Indonesian verdict', () => {
68+
renderLearn();
69+
fireEvent.click(screen.getByRole('button', { name: /Review/ }));
70+
fireEvent.click(screen.getByRole('button', { name: /Event Sourcing/ }));
71+
expect(screen.getByText(/Alat andalan spesialis: transformatif di mana audit/i)).toBeTruthy(); // verdict
72+
});
73+
74+
it('Library lens (insightLibrary) shows Indonesian definition + concepts', () => {
75+
renderLearn();
76+
fireEvent.click(screen.getByRole('button', { name: /Pustaka/ })); // "Library" section tab in ID
77+
fireEvent.click(screen.getByRole('button', { name: /Modular Monolith/ }));
78+
expect(screen.getByText(/Monolith yang kode internalnya dibagi menjadi modul/i)).toBeTruthy(); // definition
79+
expect(screen.getByText(/Batas logis \(modul\) dipisahkan dari batas fisik/i)).toBeTruthy(); // concept
80+
});
81+
82+
it('Markdown article body renders the Indonesian side of the `<!-- lang:id -->` split', () => {
83+
renderLearn();
84+
fireEvent.click(screen.getByRole('button', { name: /Peta Belajar/ })); // "Roadmap" section tab in ID
85+
fireEvent.click(screen.getByRole('button', { name: /monolith ke microservices/i }));
86+
fireEvent.click(screen.getByRole('button', { name: /Strangler Fig/ }));
87+
// The Indonesian body (below the delimiter), NOT the English one.
88+
expect(screen.getByText(/Menulis ulang sistem besar sekaligus/i)).toBeTruthy();
89+
expect(screen.queryByText(/Rewriting a large system in one go/i)).toBeNull();
90+
});
91+
});

0 commit comments

Comments
 (0)