-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathApp.test.tsx
More file actions
68 lines (58 loc) · 3.6 KB
/
Copy pathApp.test.tsx
File metadata and controls
68 lines (58 loc) · 3.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import { describe, it, expect, beforeEach } from 'vitest';
import { fireEvent, screen } from '@testing-library/react';
import App from './App';
import { renderWithI18n } from './test/render';
// The radar verdict ("X leads at N%…" / "Close call: … are within N points") is the single
// element that names the top option and its score, so its text changing proves the whole
// pipeline (factors → weights → rankings → analysis) recomputed.
const VERDICT = /leads at \d+%|within \d+ points/;
describe('App integration', () => {
// These exercise the Advisor; the app's default view is now the Home landing, so start on the
// Advisor (a returning-user state) by seeding the persisted view.
beforeEach(() => {
localStorage.clear();
localStorage.setItem('aa.main', JSON.stringify('advisor'));
});
it('AC-2: applying a preset instantly recomputes the recommendation', () => {
renderWithI18n(<App />, 'en');
const before = screen.getByText(VERDICT).textContent;
// Presets are cards in the Scenario Card Gallery (Blueprint Phase 1.3) — clicked directly.
fireEvent.click(screen.getByRole('button', { name: /Busy online shop/ }));
expect(screen.getByText(VERDICT).textContent).not.toBe(before);
});
it('AC-2: changing a single factor instantly recomputes the recommendation', () => {
renderWithI18n(<App />, 'en');
const before = screen.getByText(VERDICT).textContent;
fireEvent.click(screen.getByRole('radio', { name: 'High / extreme spikes' }));
expect(screen.getByText(VERDICT).textContent).not.toBe(before);
});
it('AC-13: the language toggle switches the UI strings', () => {
renderWithI18n(<App />, 'id');
expect(screen.getByText('Rekomendasi di 5 dimensi')).toBeInTheDocument();
expect(screen.queryByText('Recommendation across 5 dimensions')).not.toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: 'EN' }));
expect(screen.getByText('Recommendation across 5 dimensions')).toBeInTheDocument();
expect(screen.queryByText('Rekomendasi di 5 dimensi')).not.toBeInTheDocument();
});
it('opening the Guide then tapping a primary nav tab auto-closes it (Blueprint Phase 2.3)', async () => {
renderWithI18n(<App />, 'en');
// Open the "Panduan"/Guide modal from the header (ManualBook is lazy — await its mount).
fireEvent.click(screen.getAllByRole('button', { name: 'Guide' })[0]);
// ManualBook is a lazy chunk; under full-suite load the dynamic import can exceed the default
// 1s findBy timeout, so give it room (isolation-fast, contention-tolerant).
expect(await screen.findByRole('dialog', { name: /Manual/ }, { timeout: 5000 })).toBeInTheDocument();
// Tapping a primary tab (Home/Advisor/Insights) must dismiss the overlay, never leave it hanging.
fireEvent.click(screen.getAllByRole('button', { name: 'Insights' })[0]);
expect(screen.queryByRole('dialog', { name: /Manual/ })).not.toBeInTheDocument();
});
it('locking one QA weight in the override panel redistributes the others', () => {
renderWithI18n(<App />, 'en');
fireEvent.click(screen.getByRole('button', { name: 'Expert' }));
fireEvent.click(screen.getByRole('button', { name: /Adjust weights/ }));
const ttm = () => screen.getByRole('spinbutton', { name: 'Time-to-market / delivery speed' }) as HTMLInputElement;
const before = ttm().value; // highest weight by default (ttm=1)
// lock Security to 80% → the unlocked weights (incl. time-to-market) share the remaining 20%
fireEvent.change(screen.getByRole('spinbutton', { name: 'Security' }), { target: { value: '80' } });
expect(ttm().value).not.toBe(before);
});
});