diff --git a/src/frontend/apps/desk/src/features/teams/__tests__/MemberAction.test.tsx b/src/frontend/apps/desk/src/features/members/__tests__/MemberAction.test.tsx similarity index 94% rename from src/frontend/apps/desk/src/features/teams/__tests__/MemberAction.test.tsx rename to src/frontend/apps/desk/src/features/members/__tests__/MemberAction.test.tsx index b34f1dc..4be9097 100644 --- a/src/frontend/apps/desk/src/features/teams/__tests__/MemberAction.test.tsx +++ b/src/frontend/apps/desk/src/features/members/__tests__/MemberAction.test.tsx @@ -4,8 +4,8 @@ import fetchMock from 'fetch-mock'; import { AppWrapper } from '@/tests/utils'; -import { Access, Role } from '../api'; -import { MemberAction } from '../components/Member/MemberAction'; +import { MemberAction } from '../components/MemberAction'; +import { Access, Role } from '../types'; const access: Access = { id: '789', diff --git a/src/frontend/apps/desk/src/features/teams/__tests__/MemberGrid.test.tsx b/src/frontend/apps/desk/src/features/members/__tests__/MemberGrid.test.tsx similarity index 98% rename from src/frontend/apps/desk/src/features/teams/__tests__/MemberGrid.test.tsx rename to src/frontend/apps/desk/src/features/members/__tests__/MemberGrid.test.tsx index 68b992b..f2330b6 100644 --- a/src/frontend/apps/desk/src/features/teams/__tests__/MemberGrid.test.tsx +++ b/src/frontend/apps/desk/src/features/members/__tests__/MemberGrid.test.tsx @@ -5,8 +5,8 @@ import fetchMock from 'fetch-mock'; import { AppWrapper } from '@/tests/utils'; -import { Access, Role } from '../api'; -import { MemberGrid } from '../components/Member/MemberGrid'; +import { MemberGrid } from '../components/MemberGrid'; +import { Access, Role } from '../types'; describe('MemberGrid', () => { afterEach(() => { diff --git a/src/frontend/apps/desk/src/features/teams/__tests__/ModalRole.test.tsx b/src/frontend/apps/desk/src/features/members/__tests__/ModalRole.test.tsx similarity index 98% rename from src/frontend/apps/desk/src/features/teams/__tests__/ModalRole.test.tsx rename to src/frontend/apps/desk/src/features/members/__tests__/ModalRole.test.tsx index d9efaf7..9e8a0c1 100644 --- a/src/frontend/apps/desk/src/features/teams/__tests__/ModalRole.test.tsx +++ b/src/frontend/apps/desk/src/features/members/__tests__/ModalRole.test.tsx @@ -6,8 +6,8 @@ import fetchMock from 'fetch-mock'; import { useAuthStore } from '@/features/auth'; import { AppWrapper } from '@/tests/utils'; -import { Access, Role } from '../api'; -import { ModalRole } from '../components/Member/ModalRole'; +import { ModalRole } from '../components/ModalRole'; +import { Access, Role } from '../types'; const toast = jest.fn(); jest.mock('@openfun/cunningham-react', () => ({ diff --git a/src/frontend/apps/desk/src/features/teams/api/useTeamsAccesses.tsx b/src/frontend/apps/desk/src/features/members/api/useTeamsAccesses.tsx similarity index 96% rename from src/frontend/apps/desk/src/features/teams/api/useTeamsAccesses.tsx rename to src/frontend/apps/desk/src/features/members/api/useTeamsAccesses.tsx index 123a0b7..cfadc9f 100644 --- a/src/frontend/apps/desk/src/features/teams/api/useTeamsAccesses.tsx +++ b/src/frontend/apps/desk/src/features/members/api/useTeamsAccesses.tsx @@ -2,7 +2,7 @@ import { UseQueryOptions, useQuery } from '@tanstack/react-query'; import { APIError, APIList, errorCauses, fetchAPI } from '@/api'; -import { Access } from './types'; +import { Access } from '../types'; export type TeamAccessesAPIParams = { page: number; diff --git a/src/frontend/apps/desk/src/features/teams/api/useUpdateTeamAccess.ts b/src/frontend/apps/desk/src/features/members/api/useUpdateTeamAccess.ts similarity index 94% rename from src/frontend/apps/desk/src/features/teams/api/useUpdateTeamAccess.ts rename to src/frontend/apps/desk/src/features/members/api/useUpdateTeamAccess.ts index 826ccf3..bf5f600 100644 --- a/src/frontend/apps/desk/src/features/teams/api/useUpdateTeamAccess.ts +++ b/src/frontend/apps/desk/src/features/members/api/useUpdateTeamAccess.ts @@ -5,9 +5,10 @@ import { } from '@tanstack/react-query'; import { APIError, errorCauses, fetchAPI } from '@/api'; +import { KEY_TEAM } from '@/features/teams/api/useTeam'; + +import { Access, Role } from '../types'; -import { Access, Role } from './types'; -import { KEY_TEAM } from './useTeam'; import { KEY_LIST_TEAM_ACCESSES } from './useTeamsAccesses'; interface UpdateTeamAccessProps { diff --git a/src/frontend/apps/desk/src/features/teams/components/Member/MemberAction.tsx b/src/frontend/apps/desk/src/features/members/components/MemberAction.tsx similarity index 97% rename from src/frontend/apps/desk/src/features/teams/components/Member/MemberAction.tsx rename to src/frontend/apps/desk/src/features/members/components/MemberAction.tsx index d70c7be..cb48a2b 100644 --- a/src/frontend/apps/desk/src/features/teams/components/Member/MemberAction.tsx +++ b/src/frontend/apps/desk/src/features/members/components/MemberAction.tsx @@ -3,7 +3,8 @@ import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { DropButton, Text } from '@/components'; -import { Access, Role } from '@/features/teams/api'; + +import { Access, Role } from '../types'; import { ModalRole } from './ModalRole'; diff --git a/src/frontend/apps/desk/src/features/teams/components/Member/MemberGrid.tsx b/src/frontend/apps/desk/src/features/members/components/MemberGrid.tsx similarity index 95% rename from src/frontend/apps/desk/src/features/teams/components/Member/MemberGrid.tsx rename to src/frontend/apps/desk/src/features/members/components/MemberGrid.tsx index d10b34d..d37ff38 100644 --- a/src/frontend/apps/desk/src/features/teams/components/Member/MemberGrid.tsx +++ b/src/frontend/apps/desk/src/features/members/components/MemberGrid.tsx @@ -5,8 +5,10 @@ import { useTranslation } from 'react-i18next'; import IconUser from '@/assets/icons/icon-user.svg'; import { Box, Card, TextErrors } from '@/components'; import { useCunninghamTheme } from '@/cunningham'; -import { Role, useTeamAccesses } from '@/features/teams/api/'; -import { PAGE_SIZE } from '@/features/teams/conf'; + +import { useTeamAccesses } from '../api/useTeamsAccesses'; +import { PAGE_SIZE } from '../conf'; +import { Role } from '../types'; import { MemberAction } from './MemberAction'; diff --git a/src/frontend/apps/desk/src/features/teams/components/Member/ModalRole.tsx b/src/frontend/apps/desk/src/features/members/components/ModalRole.tsx similarity index 97% rename from src/frontend/apps/desk/src/features/teams/components/Member/ModalRole.tsx rename to src/frontend/apps/desk/src/features/members/components/ModalRole.tsx index 117311c..1c29ed6 100644 --- a/src/frontend/apps/desk/src/features/teams/components/Member/ModalRole.tsx +++ b/src/frontend/apps/desk/src/features/members/components/ModalRole.tsx @@ -12,7 +12,9 @@ import { useState } from 'react'; import { Box, Text, TextErrors } from '@/components'; import { useAuthStore } from '@/features/auth'; -import { Access, Role, useUpdateTeamAccess } from '@/features/teams/api/'; + +import { useUpdateTeamAccess } from '../api/useUpdateTeamAccess'; +import { Access, Role } from '../types'; interface ModalRoleProps { access: Access; diff --git a/src/frontend/apps/desk/src/features/teams/conf.ts b/src/frontend/apps/desk/src/features/members/conf.ts similarity index 100% rename from src/frontend/apps/desk/src/features/teams/conf.ts rename to src/frontend/apps/desk/src/features/members/conf.ts diff --git a/src/frontend/apps/desk/src/features/members/index.ts b/src/frontend/apps/desk/src/features/members/index.ts new file mode 100644 index 0000000..2c353d9 --- /dev/null +++ b/src/frontend/apps/desk/src/features/members/index.ts @@ -0,0 +1,2 @@ +export * from './types'; +export * from './components/MemberGrid'; diff --git a/src/frontend/apps/desk/src/features/members/types.tsx b/src/frontend/apps/desk/src/features/members/types.tsx new file mode 100644 index 0000000..1429c2d --- /dev/null +++ b/src/frontend/apps/desk/src/features/members/types.tsx @@ -0,0 +1,20 @@ +import { User } from '@/features/auth/'; + +export enum Role { + MEMBER = 'member', + ADMIN = 'administrator', + OWNER = 'owner', +} + +export interface Access { + id: string; + role: Role; + user: User; + abilities: { + delete: boolean; + get: boolean; + patch: boolean; + put: boolean; + set_role_to: Role[]; + }; +} diff --git a/src/frontend/apps/desk/src/features/teams/api/index.ts b/src/frontend/apps/desk/src/features/teams/api/index.ts index a5dd14a..0b30a56 100644 --- a/src/frontend/apps/desk/src/features/teams/api/index.ts +++ b/src/frontend/apps/desk/src/features/teams/api/index.ts @@ -2,5 +2,3 @@ export * from './types'; export * from './useCreateTeam'; export * from './useTeam'; export * from './useTeams'; -export * from './useTeamsAccesses'; -export * from './useUpdateTeamAccess'; diff --git a/src/frontend/apps/desk/src/features/teams/api/types.tsx b/src/frontend/apps/desk/src/features/teams/api/types.tsx index 22f19ca..3fbd82e 100644 --- a/src/frontend/apps/desk/src/features/teams/api/types.tsx +++ b/src/frontend/apps/desk/src/features/teams/api/types.tsx @@ -1,23 +1,4 @@ -import { User } from '@/features/auth/'; - -export enum Role { - MEMBER = 'member', - ADMIN = 'administrator', - OWNER = 'owner', -} - -export interface Access { - id: string; - role: Role; - user: User; - abilities: { - delete: boolean; - get: boolean; - patch: boolean; - put: boolean; - set_role_to: Role[]; - }; -} +import { Access } from '@/features/members'; export interface Team { id: string; diff --git a/src/frontend/apps/desk/src/features/teams/components/index.ts b/src/frontend/apps/desk/src/features/teams/components/index.ts index dc884d9..38dec09 100644 --- a/src/frontend/apps/desk/src/features/teams/components/index.ts +++ b/src/frontend/apps/desk/src/features/teams/components/index.ts @@ -1,3 +1,2 @@ export * from './Panel/Panel'; export * from './TeamInfo'; -export * from './Member/MemberGrid'; diff --git a/src/frontend/apps/desk/src/pages/teams/[id].tsx b/src/frontend/apps/desk/src/pages/teams/[id].tsx index 6ec6e98..44b2a06 100644 --- a/src/frontend/apps/desk/src/pages/teams/[id].tsx +++ b/src/frontend/apps/desk/src/pages/teams/[id].tsx @@ -5,7 +5,8 @@ import { ReactElement } from 'react'; import { Box } from '@/components'; import { TextErrors } from '@/components/TextErrors'; -import { MemberGrid, Role, TeamInfo, useTeam } from '@/features/teams/'; +import { MemberGrid, Role } from '@/features/members'; +import { TeamInfo, useTeam } from '@/features/teams/'; import { NextPageWithLayout } from '@/types/next'; import TeamLayout from './TeamLayout'; diff --git a/src/frontend/apps/e2e/__tests__/app-desk/member-grid.spec.ts b/src/frontend/apps/e2e/__tests__/app-desk/member-grid.spec.ts new file mode 100644 index 0000000..d09e640 --- /dev/null +++ b/src/frontend/apps/e2e/__tests__/app-desk/member-grid.spec.ts @@ -0,0 +1,65 @@ +import { expect, test } from '@playwright/test'; + +import { createTeam, keyCloakSignIn } from './common'; + +test.beforeEach(async ({ page, browserName }) => { + await page.goto('/'); + await keyCloakSignIn(page, browserName); +}); + +test.describe('Member Grid', () => { + test('checks the owner member is displayed correctly', async ({ + page, + browserName, + }) => { + await createTeam(page, 'team-owner', browserName, 1); + + const table = page.getByLabel('List members card').getByRole('table'); + + const thead = table.locator('thead'); + await expect(thead.getByText(/Names/i)).toBeVisible(); + await expect(thead.getByText(/Emails/i)).toBeVisible(); + await expect(thead.getByText(/Roles/i)).toBeVisible(); + + const cells = table.getByRole('row').nth(1).getByRole('cell'); + await expect(cells.nth(0).getByLabel('Member icon')).toBeVisible(); + await expect(cells.nth(1)).toHaveText( + new RegExp(`E2E ${browserName}`, 'i'), + ); + await expect(cells.nth(2)).toHaveText(`user@${browserName}.e2e`); + await expect(cells.nth(3)).toHaveText(/Owner/i); + }); + + test('try to update the owner role but cannot because it is the last owner', async ({ + page, + browserName, + }) => { + await createTeam(page, 'team-owner-role', browserName, 1); + + const table = page.getByLabel('List members card').getByRole('table'); + + const cells = table.getByRole('row').nth(1).getByRole('cell'); + await expect(cells.nth(1)).toHaveText( + new RegExp(`E2E ${browserName}`, 'i'), + ); + await cells.nth(4).getByLabel('Member options').click(); + await page.getByText('Update the role').click(); + + await expect( + page.getByText('You are the last owner, you cannot change your role.'), + ).toBeVisible(); + + const radioGroup = page.getByLabel('Radio buttons to update the roles'); + + const radios = await radioGroup.getByRole('radio').all(); + for (const radio of radios) { + await expect(radio).toBeDisabled(); + } + + await expect( + page.getByRole('button', { + name: 'Validate', + }), + ).toBeDisabled(); + }); +}); diff --git a/src/frontend/apps/e2e/__tests__/app-desk/team.spec.ts b/src/frontend/apps/e2e/__tests__/app-desk/team.spec.ts index fd34a82..b732251 100644 --- a/src/frontend/apps/e2e/__tests__/app-desk/team.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-desk/team.spec.ts @@ -40,59 +40,4 @@ test.describe('Team', () => { page.getByText(`Last update at ${todayFormated}`), ).toBeVisible(); }); - - test('checks the owner member is displayed correctly', async ({ - page, - browserName, - }) => { - await createTeam(page, 'team-owner', browserName, 1); - - const table = page.getByLabel('List members card').getByRole('table'); - - const thead = table.locator('thead'); - await expect(thead.getByText(/Names/i)).toBeVisible(); - await expect(thead.getByText(/Emails/i)).toBeVisible(); - await expect(thead.getByText(/Roles/i)).toBeVisible(); - - const cells = table.getByRole('row').nth(1).getByRole('cell'); - await expect(cells.nth(0).getByLabel('Member icon')).toBeVisible(); - await expect(cells.nth(1)).toHaveText( - new RegExp(`E2E ${browserName}`, 'i'), - ); - await expect(cells.nth(2)).toHaveText(`user@${browserName}.e2e`); - await expect(cells.nth(3)).toHaveText(/Owner/i); - }); - - test('try to update the owner role but cannot because it is the last owner', async ({ - page, - browserName, - }) => { - await createTeam(page, 'team-owner-role', browserName, 1); - - const table = page.getByLabel('List members card').getByRole('table'); - - const cells = table.getByRole('row').nth(1).getByRole('cell'); - await expect(cells.nth(1)).toHaveText( - new RegExp(`E2E ${browserName}`, 'i'), - ); - await cells.nth(4).getByLabel('Member options').click(); - await page.getByText('Update the role').click(); - - await expect( - page.getByText('You are the last owner, you cannot change your role.'), - ).toBeVisible(); - - const radioGroup = page.getByLabel('Radio buttons to update the roles'); - - const radios = await radioGroup.getByRole('radio').all(); - for (const radio of radios) { - await expect(radio).toBeDisabled(); - } - - await expect( - page.getByRole('button', { - name: 'Validate', - }), - ).toBeDisabled(); - }); });