fix: useAdminUsers null guard, unmount cleanup, split test

- Guard setUsers against null data with nullish coalescing (data ?? [])
- Add isMounted flag in useEffect to prevent setState after unmount
- Split combined inviteUser+deleteUser test into two independent it blocks

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-10 13:08:07 +03:00
parent 9189cc1b55
commit 3bbcf7e256
2 changed files with 24 additions and 6 deletions
@@ -48,14 +48,13 @@ describe('useAdminUsers', () => {
expect(result.current.users).toEqual([]);
});
it('inviteUser appends new user to state; deleteUser removes user from state', async () => {
it('inviteUser appends a user to state', async () => {
const existingUser = { id: '1', email: 'a@example.com', created_at: '2024-01-01', last_sign_in_at: null };
const newUser = { id: '2', email: 'b@example.com', created_at: '2024-01-03', last_sign_in_at: null };
mockInvoke
.mockResolvedValueOnce({ data: [existingUser], error: null })
.mockResolvedValueOnce({ data: newUser, error: null })
.mockResolvedValueOnce({ data: {}, error: null });
.mockResolvedValueOnce({ data: newUser, error: null });
const { result } = renderHook(() => useAdminUsers());
await act(async () => {});
@@ -65,6 +64,19 @@ describe('useAdminUsers', () => {
await result.current.inviteUser('b@example.com');
});
expect(result.current.users).toEqual([existingUser, newUser]);
});
it('deleteUser removes a user from state', async () => {
const existingUser = { id: '1', email: 'a@example.com', created_at: '2024-01-01', last_sign_in_at: null };
const newUser = { id: '2', email: 'b@example.com', created_at: '2024-01-03', last_sign_in_at: null };
mockInvoke
.mockResolvedValueOnce({ data: [existingUser, newUser], error: null })
.mockResolvedValueOnce({ data: {}, error: null });
const { result } = renderHook(() => useAdminUsers());
await act(async () => {});
expect(result.current.users).toEqual([existingUser, newUser]);
await act(async () => {
await result.current.deleteUser('1');
+9 -3
View File
@@ -6,19 +6,25 @@ export function useAdminUsers() {
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const fetchUsers = useCallback(async () => {
const fetchUsers = useCallback(async (isMounted) => {
const { data, error } = await supabase.functions.invoke('list-admin-users');
if (!isMounted) return;
if (error) {
setError(error.message);
} else {
setUsers(data);
setUsers(data ?? []);
}
setLoading(false);
}, []);
useEffect(() => {
fetchUsers();
let isMounted = true;
fetchUsers(isMounted);
return () => {
isMounted = false;
};
}, [fetchUsers]);
const inviteUser = async (email) => {