LDAPSettingsWiring.test.tsx 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /**
  2. * LDAP settings: the save request carries every ldap_* field including the
  3. * group mapping and default group, the bind password only when it was typed,
  4. * and the enable toggle / test button hit the right endpoints.
  5. */
  6. import { describe, it, expect, beforeEach } 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 { LDAPSettings } from '../../components/LDAPSettings';
  13. type Captured = { method: string; path: string; body: Record<string, unknown> | null };
  14. let captured: Captured[];
  15. let ldapStatus: { ldap_enabled: boolean; ldap_configured: boolean };
  16. const STORED = {
  17. ldap_enabled: false,
  18. ldap_server_url: 'ldaps://ldap.example:636',
  19. ldap_bind_dn: 'cn=svc,dc=example',
  20. ldap_bind_password: '',
  21. ldap_search_base: 'dc=example',
  22. ldap_user_filter: '(uid={username})',
  23. ldap_security: 'ldaps',
  24. ldap_group_mapping: '',
  25. ldap_auto_provision: false,
  26. ldap_default_group: '',
  27. };
  28. async function capture(request: Request) {
  29. const text = await request.text();
  30. captured.push({
  31. method: request.method,
  32. path: new URL(request.url).pathname,
  33. body: text ? JSON.parse(text) : null,
  34. });
  35. }
  36. beforeEach(() => {
  37. captured = [];
  38. ldapStatus = { ldap_enabled: false, ldap_configured: true };
  39. server.use(
  40. http.get('*/api/v1/auth/status', () => HttpResponse.json({ auth_enabled: true, requires_setup: false })),
  41. http.get('*/api/v1/settings/', () => HttpResponse.json(STORED)),
  42. http.get('*/api/v1/auth/ldap/status', () => HttpResponse.json(ldapStatus)),
  43. http.get('*/api/v1/groups/', () =>
  44. HttpResponse.json([
  45. { id: 1, name: 'Administrators' },
  46. { id: 2, name: 'Operators' },
  47. ]),
  48. ),
  49. http.put('*/api/v1/settings/', async ({ request }) => {
  50. await capture(request);
  51. return HttpResponse.json(STORED);
  52. }),
  53. http.post('*/api/v1/auth/ldap/test', async ({ request }) => {
  54. await capture(request);
  55. return HttpResponse.json({ success: true, message: 'Connected' });
  56. }),
  57. );
  58. });
  59. describe('LDAPSettings wiring', () => {
  60. it('save sends all ldap_* fields with group mapping/default group and no bind password when untouched', async () => {
  61. const user = userEvent.setup();
  62. render(<LDAPSettings />);
  63. const base = await screen.findByDisplayValue('dc=example');
  64. await user.clear(base);
  65. await user.type(base, 'ou=people,dc=example');
  66. await user.click(screen.getByRole('button', { name: /advanced/i }));
  67. await user.click(screen.getByPlaceholderText(/PrintFarm_Admins/));
  68. await user.paste('{"cn=farm,dc=example":"Operators"}');
  69. await user.selectOptions(screen.getByRole('combobox'), 'Operators');
  70. await user.click(screen.getByRole('button', { name: /^save$/i }));
  71. await waitFor(() => expect(captured).toHaveLength(1));
  72. expect(captured[0].method).toBe('PUT');
  73. expect(captured[0].path).toBe('/api/v1/settings/');
  74. expect(captured[0].body).toEqual({
  75. ldap_server_url: 'ldaps://ldap.example:636',
  76. ldap_bind_dn: 'cn=svc,dc=example',
  77. ldap_search_base: 'ou=people,dc=example',
  78. ldap_user_filter: '(uid={username})',
  79. ldap_security: 'ldaps',
  80. ldap_group_mapping: '{"cn=farm,dc=example":"Operators"}',
  81. ldap_auto_provision: false,
  82. ldap_default_group: 'Operators',
  83. });
  84. expect(captured[0].body).not.toHaveProperty('ldap_bind_password');
  85. });
  86. it('a typed bind password is sent with the save', async () => {
  87. const user = userEvent.setup();
  88. render(<LDAPSettings />);
  89. await screen.findByDisplayValue('dc=example');
  90. await user.type(document.querySelector('input[type="password"]') as HTMLInputElement, 'test-password-1');
  91. await user.click(screen.getByRole('button', { name: /^save$/i }));
  92. await waitFor(() => expect(captured).toHaveLength(1));
  93. expect(captured[0].body).toMatchObject({ ldap_bind_password: 'test-password-1' });
  94. });
  95. it('save without a server URL sends nothing', async () => {
  96. const user = userEvent.setup();
  97. render(<LDAPSettings />);
  98. await user.clear(await screen.findByDisplayValue('ldaps://ldap.example:636'));
  99. await user.click(screen.getByRole('button', { name: /^save$/i }));
  100. expect(await screen.findByText(/ldap server url is required/i)).toBeInTheDocument();
  101. expect(captured).toHaveLength(0);
  102. });
  103. it('test connection posts the form as it is, unsaved edits included', async () => {
  104. const user = userEvent.setup();
  105. render(<LDAPSettings />);
  106. const base = await screen.findByDisplayValue('dc=example');
  107. await user.clear(base);
  108. await user.type(base, 'ou=people,dc=example');
  109. await user.click(screen.getByRole('button', { name: /test connection/i }));
  110. await waitFor(() => expect(captured).toHaveLength(1));
  111. expect(captured[0]).toEqual({
  112. method: 'POST',
  113. path: '/api/v1/auth/ldap/test',
  114. body: {
  115. ldap_server_url: 'ldaps://ldap.example:636',
  116. ldap_bind_dn: 'cn=svc,dc=example',
  117. ldap_bind_password: '',
  118. ldap_search_base: 'ou=people,dc=example',
  119. ldap_user_filter: '(uid={username})',
  120. ldap_security: 'ldaps',
  121. },
  122. });
  123. });
  124. it('enable sends only {ldap_enabled:true}', async () => {
  125. const user = userEvent.setup();
  126. render(<LDAPSettings />);
  127. await screen.findByDisplayValue('dc=example');
  128. await waitFor(async () => {
  129. await user.click(screen.getByRole('button', { name: /^enable$/i }));
  130. expect(captured).toHaveLength(1);
  131. });
  132. expect(captured[0]).toEqual({ method: 'PUT', path: '/api/v1/settings/', body: { ldap_enabled: true } });
  133. });
  134. it('disable sends {ldap_enabled:false} when LDAP is on', async () => {
  135. ldapStatus = { ldap_enabled: true, ldap_configured: true };
  136. const user = userEvent.setup();
  137. render(<LDAPSettings />);
  138. await screen.findByText(/ldap authentication is enabled/i);
  139. await waitFor(async () => {
  140. await user.click(screen.getByRole('button', { name: /^disable$/i }));
  141. expect(captured).toHaveLength(1);
  142. });
  143. expect(captured[0].body).toEqual({ ldap_enabled: false });
  144. });
  145. it('enable sends nothing until LDAP settings are saved', async () => {
  146. ldapStatus = { ldap_enabled: false, ldap_configured: false };
  147. const user = userEvent.setup();
  148. render(<LDAPSettings />);
  149. await screen.findByDisplayValue('dc=example');
  150. await waitFor(async () => {
  151. await user.click(screen.getByRole('button', { name: /^enable$/i }));
  152. expect(screen.getAllByText(/save ldap settings first/i).length).toBeGreaterThan(0);
  153. });
  154. expect(captured).toHaveLength(0);
  155. });
  156. });