From 9f906b7417e7df177822c4b18f9f2376a5f82b04 Mon Sep 17 00:00:00 2001 From: James Player Date: Mon, 14 Jul 2025 17:16:33 +1200 Subject: [PATCH] refactor(app/tests): Make createMockUsers more deterministic [r8s-406] (#887) --- app/react-tools/test-mocks.ts | 11 +++++-- .../TeamAssociationSelector.stories.tsx | 4 +-- .../TeamMembersList.stories.tsx | 2 +- .../UsersList/UsersList.stories.tsx | 29 +++++++++++++++---- app/setup-tests/setup-handlers/users.ts | 5 +++- 5 files changed, 40 insertions(+), 11 deletions(-) diff --git a/app/react-tools/test-mocks.ts b/app/react-tools/test-mocks.ts index 20fe7dee3..d9c7d273c 100644 --- a/app/react-tools/test-mocks.ts +++ b/app/react-tools/test-mocks.ts @@ -10,7 +10,7 @@ import { export function createMockUsers( count: number, - roles: Role | Role[] | ((id: UserId) => Role) = () => _.random(1, 3) + roles: Role | Role[] | ((id: UserId) => Role) ): User[] { return _.range(1, count + 1).map((value) => ({ Id: value, @@ -40,7 +40,14 @@ function getRoles( return roles; } - return roles[id]; + // Roles is an array + if (roles.length === 0) { + throw new Error('No roles provided'); + } + + // The number of roles is not necessarily the same length as the number of users + // so we need to distribute the roles evenly and consistently + return roles[(id - 1) % roles.length]; } export function createMockTeams(count: number): Team[] { diff --git a/app/react/portainer/users/teams/ItemView/TeamAssociationSelector/TeamAssociationSelector.stories.tsx b/app/react/portainer/users/teams/ItemView/TeamAssociationSelector/TeamAssociationSelector.stories.tsx index d4d4142f7..9c7fa8a32 100644 --- a/app/react/portainer/users/teams/ItemView/TeamAssociationSelector/TeamAssociationSelector.stories.tsx +++ b/app/react/portainer/users/teams/ItemView/TeamAssociationSelector/TeamAssociationSelector.stories.tsx @@ -2,7 +2,7 @@ import { Meta } from '@storybook/react'; import { useMemo, useState } from 'react'; import { createMockUsers } from '@/react-tools/test-mocks'; -import { Role, User } from '@/portainer/users/types'; +import { Role } from '@/portainer/users/types'; import { UserViewModel } from '@/portainer/models/user'; import { UserContext } from '@/react/hooks/useUser'; @@ -28,7 +28,7 @@ function Example({ userRole }: Args) { () => ({ user: new UserViewModel({ Role: userRole }) }), [userRole] ); - const [users] = useState(createMockUsers(20) as User[]); + const [users] = useState(createMockUsers(20, Role.Standard)); const [memberships] = useState[]>( users diff --git a/app/react/portainer/users/teams/ItemView/TeamAssociationSelector/TeamMembersList/TeamMembersList.stories.tsx b/app/react/portainer/users/teams/ItemView/TeamAssociationSelector/TeamMembersList/TeamMembersList.stories.tsx index 6f2e53f1e..efe4cc908 100644 --- a/app/react/portainer/users/teams/ItemView/TeamAssociationSelector/TeamMembersList/TeamMembersList.stories.tsx +++ b/app/react/portainer/users/teams/ItemView/TeamAssociationSelector/TeamMembersList/TeamMembersList.stories.tsx @@ -28,7 +28,7 @@ function Example({ userRole }: Args) { [userRole] ); - const [users] = useState(createMockUsers(20)); + const [users] = useState(createMockUsers(20, Role.Standard)); const [roles] = useState( Object.fromEntries( users.map((user) => [ diff --git a/app/react/portainer/users/teams/ItemView/TeamAssociationSelector/UsersList/UsersList.stories.tsx b/app/react/portainer/users/teams/ItemView/TeamAssociationSelector/UsersList/UsersList.stories.tsx index bbbcc6498..8966d6fad 100644 --- a/app/react/portainer/users/teams/ItemView/TeamAssociationSelector/UsersList/UsersList.stories.tsx +++ b/app/react/portainer/users/teams/ItemView/TeamAssociationSelector/UsersList/UsersList.stories.tsx @@ -1,6 +1,10 @@ import { Meta } from '@storybook/react'; +import { useMemo } from 'react'; import { createMockUsers } from '@/react-tools/test-mocks'; +import { Role } from '@/portainer/users/types'; +import { UserContext } from '@/react/hooks/useUser'; +import { UserViewModel } from '@/portainer/models/user'; import { UsersList } from './UsersList'; @@ -13,10 +17,25 @@ export default meta; export { Example }; -function Example() { - const users = createMockUsers(20); - - return ; +interface Args { + userRole: Role; } -Example.args = {}; +function Example({ userRole }: Args) { + const userProviderState = useMemo( + () => ({ user: new UserViewModel({ Role: userRole }) }), + [userRole] + ); + + const users = createMockUsers(20, Role.Standard); + + return ( + + + + ); +} + +Example.args = { + userRole: Role.Admin, +}; diff --git a/app/setup-tests/setup-handlers/users.ts b/app/setup-tests/setup-handlers/users.ts index 67eb6debb..be8c3a5e3 100644 --- a/app/setup-tests/setup-handlers/users.ts +++ b/app/setup-tests/setup-handlers/users.ts @@ -2,9 +2,12 @@ import { http, HttpResponse } from 'msw'; import { TeamMembership } from '@/react/portainer/users/teams/types'; import { createMockUsers } from '@/react-tools/test-mocks'; +import { Role } from '@/portainer/users/types'; export const userHandlers = [ - http.get('/api/users', async () => HttpResponse.json(createMockUsers(10))), + http.get('/api/users', async () => + HttpResponse.json(createMockUsers(10, Role.Standard)) + ), http.get( '/api/users/:userId/memberships', () => HttpResponse.json([])