EditPrinterLocationAccess.test.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. /**
  2. * Groups can be given a location (#1727), so editing a printer's location is
  3. * an access change: the dialog names the groups it affects, and clearing the
  4. * location has to actually clear it.
  5. */
  6. import { describe, it, expect, beforeEach, afterEach } from 'vitest';
  7. import { screen, waitFor } from '@testing-library/react';
  8. import userEvent from '@testing-library/user-event';
  9. import { http, HttpResponse } from 'msw';
  10. import { render } from '../utils';
  11. import { server } from '../mocks/server';
  12. import { PrintersPage } from '../../pages/PrintersPage';
  13. import { setAuthToken } from '../../api/client';
  14. const mockPrinter = {
  15. id: 1,
  16. name: 'X1 Carbon',
  17. ip_address: '192.168.1.100',
  18. serial_number: '00M09A350100001',
  19. model: 'X1C',
  20. location: 'Lab A',
  21. is_active: true,
  22. auto_archive: true,
  23. created_at: '2024-01-01T00:00:00Z',
  24. updated_at: '2024-01-01T00:00:00Z',
  25. };
  26. const teamGroup = (name: string, locations: string[], restrict = true) => ({
  27. id: name.length,
  28. name,
  29. description: null,
  30. permissions: [],
  31. is_system: false,
  32. restrict_printers: restrict,
  33. printer_ids: [],
  34. locations,
  35. user_count: 1,
  36. created_at: '2024-01-01T00:00:00Z',
  37. updated_at: '2024-01-01T00:00:00Z',
  38. });
  39. let patched: Record<string, unknown> | null;
  40. beforeEach(() => {
  41. patched = null;
  42. setAuthToken('test-token', 'session');
  43. server.use(
  44. http.get('*/api/v1/auth/status', () => HttpResponse.json({ auth_enabled: true, requires_setup: false })),
  45. http.get('*/api/v1/auth/me', () =>
  46. HttpResponse.json({ id: 1, username: 'boss', is_admin: true, groups: [], permissions: ['printers:update', 'printers:read'] })
  47. ),
  48. http.get('/api/v1/printers/', () => HttpResponse.json([mockPrinter])),
  49. http.get('/api/v1/printers/:id/status', () =>
  50. HttpResponse.json({
  51. connected: true,
  52. state: 'IDLE',
  53. progress: 0,
  54. layer_num: 0,
  55. total_layers: 0,
  56. temperatures: { nozzle: 25, bed: 25, chamber: 25 },
  57. remaining_time: 0,
  58. filename: null,
  59. wifi_signal: -50,
  60. vt_tray: [],
  61. })
  62. ),
  63. http.get('/api/v1/queue/', () => HttpResponse.json([])),
  64. http.get('/api/v1/groups/', () =>
  65. HttpResponse.json([
  66. teamGroup('Lab A team', ['Lab A']),
  67. teamGroup('Lab B crew', ['Lab B']),
  68. teamGroup('Unlimited', ['Lab A'], false),
  69. ])
  70. ),
  71. http.post('/api/v1/printers/diagnostic', () =>
  72. HttpResponse.json({ printer_id: null, ip_address: '192.168.1.100', overall: 'ok', checks: [] })
  73. ),
  74. http.patch('/api/v1/printers/:id', async ({ request }) => {
  75. patched = (await request.json()) as Record<string, unknown>;
  76. return HttpResponse.json({ ...mockPrinter, ...patched });
  77. })
  78. );
  79. });
  80. afterEach(() => {
  81. setAuthToken(null);
  82. });
  83. async function openEditModal() {
  84. render(<PrintersPage />);
  85. await waitFor(() => expect(screen.getByText('X1 Carbon')).toBeInTheDocument());
  86. const menuBtn = [...document.querySelectorAll('button')].find((b) => b.querySelector('.lucide-ellipsis-vertical'))!;
  87. await userEvent.click(menuBtn);
  88. await userEvent.click(await screen.findByRole('button', { name: /^edit$/i }));
  89. await screen.findByText('Edit Printer');
  90. }
  91. describe('EditPrinterModal location access', () => {
  92. it('names the limited groups a move affects', async () => {
  93. await openEditModal();
  94. const input = screen.getByDisplayValue('Lab A');
  95. expect(screen.queryByText(/changes who can use it/)).not.toBeInTheDocument();
  96. await userEvent.clear(input);
  97. await userEvent.type(input, 'Lab B');
  98. expect(
  99. await screen.findByText('Moving this printer to another location changes who can use it: Lab A team, Lab B crew.')
  100. ).toBeInTheDocument();
  101. });
  102. it('clears the location instead of keeping the old one', async () => {
  103. await openEditModal();
  104. await userEvent.clear(screen.getByDisplayValue('Lab A'));
  105. await userEvent.click(screen.getByRole('button', { name: /save changes/i }));
  106. await waitFor(() => expect(patched).not.toBeNull());
  107. expect(patched).toHaveProperty('location', null);
  108. });
  109. it('offers "Who has access" in the card menu', async () => {
  110. render(<PrintersPage />);
  111. await waitFor(() => expect(screen.getByText('X1 Carbon')).toBeInTheDocument());
  112. const menuBtn = [...document.querySelectorAll('button')].find((b) => b.querySelector('.lucide-ellipsis-vertical'))!;
  113. await userEvent.click(menuBtn);
  114. await userEvent.click(await screen.findByRole('button', { name: 'Who has access' }));
  115. await waitFor(() => expect(window.location.search).toBe('?tab=users&sub=printer-access&view=printers&printer=1'));
  116. });
  117. });