feat(workspace): refine career workflows

Make job/CV comparisons language-aware and filter recruitment noise. Improve responsive career navigation, shared spacing, dashboard priorities, settings, localized workspace controls, and portable browser tests.
This commit is contained in:
cesnimda
2026-08-29 16:44:44 +02:00
parent 4d4af47651
commit 9edcbfc5de
29 changed files with 827 additions and 236 deletions
+27 -1
View File
@@ -191,13 +191,39 @@ afterEach(() => {
test('dashboard attention card opens follow-up workspace', async () => {
renderLoop('/dashboard');
expect(await screen.findByText(/needs follow-up/i)).toBeInTheDocument();
expect(await screen.findByText(/^today$/i)).toBeInTheDocument();
fireEvent.click(await screen.findByRole('button', { name: /follow up/i }));
await waitFor(() => expect(screen.getByTestId('location-indicator')).toHaveTextContent('/jobs/42?section=communication&followMode=waiting-update'));
expect(screen.getByTestId('application-workspace')).toBeInTheDocument();
});
test('empty dashboard prioritizes onboarding and suppresses meaningless analytics', async () => {
mockedApi.get.mockImplementation((url: string) => {
if (url === '/jobapplications/stats') return Promise.resolve({ data: { total: 0, active: 0, deleted: 0, byStatus: {}, appliedLast30Days: 0, averageDaysSinceApplied: 0 } } as any);
if (url === '/jobapplications/analytics-overview') return Promise.resolve({ data: { funnel: Array.from({ length: 10 }, (_, index) => ({ label: `Stage ${index}`, count: 0 })), responseRateBySource: [], topCompanies: [], totalResponses: 0, totalActive: 0, timeInStage: [] } } as any);
if (url === '/jobapplications/reminders' || url === '/jobapplications/analytics' || url === '/jobapplications/tags') return Promise.resolve({ data: [] } as any);
if (url === '/jobapplications/tag-trends') return Promise.resolve({ data: { months: [], series: [] } } as any);
return Promise.resolve({ data: {} } as any);
});
const view = renderLoop('/dashboard');
expect(await screen.findByText(/get set up/i)).toBeInTheDocument();
await waitFor(() => expect(screen.queryByText(/application activity/i)).not.toBeInTheDocument());
expect(screen.queryByText(/conversion funnel/i)).not.toBeInTheDocument();
expect(screen.queryByText(/median time in stage/i)).not.toBeInTheDocument();
expect(screen.queryByText(/top companies by activity/i)).not.toBeInTheDocument();
expect(screen.queryByText(/^top skills$/i)).not.toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: /dismiss setup checklist/i }));
expect(screen.queryByText(/get set up/i)).not.toBeInTheDocument();
view.unmount();
renderLoop('/dashboard');
await waitFor(() => expect(screen.queryByText(/get set up/i)).not.toBeInTheDocument());
});
test('reminders open action routes tailored-cv gaps into the tailored cv workspace', async () => {
renderLoop('/reminders');