ProtectedRouteRetrying.test.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. /**
  2. * A stored sign-in the server can't check yet waits on the page it asked for
  3. * instead of landing on /login (#3360): a SpoolBuddy kiosk is touch-only and
  4. * has no way to sign in there, so it stayed on the login page until a reboot.
  5. */
  6. import { afterEach, beforeEach, describe, expect, it } from 'vitest';
  7. import { render, screen } from '@testing-library/react';
  8. import { MemoryRouter, Route, Routes } from 'react-router-dom';
  9. import { http, HttpResponse } from 'msw';
  10. import { server } from '../mocks/server';
  11. import { AuthProvider } from '../../contexts/AuthContext';
  12. import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
  13. import { PermissionRoute, ProtectedRoute } from '../../App';
  14. import { CamWallPage } from '../../pages/CamWallPage';
  15. import { setAuthToken } from '../../api/client';
  16. function renderKiosk() {
  17. return render(
  18. <MemoryRouter initialEntries={['/spoolbuddy']}>
  19. <AuthProvider>
  20. <Routes>
  21. <Route path="/login" element={<div>login page</div>} />
  22. <Route path="/spoolbuddy" element={<ProtectedRoute><div>kiosk page</div></ProtectedRoute>} />
  23. </Routes>
  24. </AuthProvider>
  25. </MemoryRouter>
  26. );
  27. }
  28. describe('ProtectedRoute while the sign-in is unconfirmed (#3360)', () => {
  29. let down: boolean;
  30. beforeEach(() => {
  31. down = true;
  32. setAuthToken('bb_kiosk', 'persistent');
  33. server.use(
  34. http.get('/api/v1/auth/status', () => HttpResponse.json({ auth_enabled: true, requires_setup: false })),
  35. http.get('/api/v1/auth/me', () =>
  36. down
  37. ? HttpResponse.json({ detail: 'Authentication service temporarily unavailable' }, { status: 503 })
  38. : HttpResponse.json({ id: 1, username: 'kiosk', is_active: true, permissions: [], groups: [] })
  39. )
  40. );
  41. });
  42. afterEach(() => {
  43. setAuthToken(null);
  44. });
  45. it('shows the retry screen, then the page once Bambuddy answers', async () => {
  46. renderKiosk();
  47. expect(await screen.findByText("Can't reach Bambuddy. Retrying…", {}, { timeout: 4000 })).toBeInTheDocument();
  48. expect(screen.queryByText('login page')).not.toBeInTheDocument();
  49. down = false;
  50. expect(await screen.findByText('kiosk page', {}, { timeout: 6000 })).toBeInTheDocument();
  51. }, 12000);
  52. it('waits the same way on a permission-gated page', async () => {
  53. render(
  54. <MemoryRouter initialEntries={['/settings']}>
  55. <AuthProvider>
  56. <Routes>
  57. <Route path="/login" element={<div>login page</div>} />
  58. <Route path="/settings" element={<PermissionRoute permission="settings:read"><div>settings</div></PermissionRoute>} />
  59. </Routes>
  60. </AuthProvider>
  61. </MemoryRouter>
  62. );
  63. expect(await screen.findByText("Can't reach Bambuddy. Retrying…", {}, { timeout: 4000 })).toBeInTheDocument();
  64. expect(screen.queryByText('login page')).not.toBeInTheDocument();
  65. });
  66. it('waits the same way on the Cam Wall opened with a session', async () => {
  67. render(
  68. <QueryClientProvider client={new QueryClient({ defaultOptions: { queries: { retry: false } } })}>
  69. <MemoryRouter initialEntries={['/camwall']}>
  70. <AuthProvider>
  71. <Routes>
  72. <Route path="/login" element={<div>login page</div>} />
  73. <Route path="/camwall" element={<CamWallPage />} />
  74. </Routes>
  75. </AuthProvider>
  76. </MemoryRouter>
  77. </QueryClientProvider>
  78. );
  79. expect(await screen.findByText("Can't reach Bambuddy. Retrying…", {}, { timeout: 4000 })).toBeInTheDocument();
  80. expect(screen.queryByText('login page')).not.toBeInTheDocument();
  81. });
  82. it('still goes to the login page on a definite 401', async () => {
  83. server.use(http.get('/api/v1/auth/me', () => HttpResponse.json({ detail: 'Invalid API key' }, { status: 401 })));
  84. renderKiosk();
  85. expect(await screen.findByText('login page', {}, { timeout: 4000 })).toBeInTheDocument();
  86. });
  87. });