diff --git a/ui/src/app/(index)/_components/AfterLogin.tsx b/ui/src/app/(index)/_components/AfterLogin.tsx index ee6a8a53..9b46d86b 100644 --- a/ui/src/app/(index)/_components/AfterLogin.tsx +++ b/ui/src/app/(index)/_components/AfterLogin.tsx @@ -16,13 +16,9 @@ const AfterLogin = ({ const isAdmin = currentUser.roles.includes(Role.ADMIN); const isOwner = currentUser.roles.includes(Role.OWNER); const getHighestRole = () => { - if (isAdmin) { - return 'Admin'; - } else if (isOwner) { - return 'Owner'; - } else { - return 'Member'; - } + if (isAdmin) return 'Admin'; + else if (isOwner) return 'Owner'; + else return 'Member'; } return ( @@ -47,8 +43,9 @@ const AfterLogin = ({
-

Welcome, {currentUser.firstName}!

+

Welcome, {currentUser.firstName}!

Role: {getHighestRole()}

diff --git a/ui/src/app/(index)/_components/BeforeLogin.tsx b/ui/src/app/(index)/_components/BeforeLogin.tsx index 51a464d6..d47e4a2f 100644 --- a/ui/src/app/(index)/_components/BeforeLogin.tsx +++ b/ui/src/app/(index)/_components/BeforeLogin.tsx @@ -1,5 +1,4 @@ import { Button } from '@/components/ui/button'; -import Link from 'next/link'; import { ArrowRight } from 'lucide-react'; import UHGroupingsInfo from '@/components/UHGroupingsInfo'; @@ -9,21 +8,15 @@ const BeforeLogin = () => {
- + + +
); }; -const LearnMoreButton = () => { - return ( - - - - ); -}; - export default BeforeLogin; diff --git a/ui/src/app/(index)/page.tsx b/ui/src/app/(index)/page.tsx index d4091590..d2ba3299 100644 --- a/ui/src/app/(index)/page.tsx +++ b/ui/src/app/(index)/page.tsx @@ -1,7 +1,7 @@ import Image from 'next/image'; import BeforeLogin from '@/app/(index)/_components/BeforeLogin'; import AfterLogin from '@/app/(index)/_components/AfterLogin'; -import { getCurrentUser } from '@/access/AuthenticationService'; +import {getCurrentUser} from '@/access/AuthenticationService'; import Role from '@/access/Role'; import LoginButton from '@/app/(index)/_components/LoginButton'; import {getAnnouncements, getNumberOfGroupings, getNumberOfMemberships} from '@/services/GroupingsApiService'; @@ -15,14 +15,20 @@ const Home = async () => { getAnnouncements() ]); - const activeAnnouncements = announcements?.announcements - ?.filter((announcement) => announcement.state === 'Active') - ?.map((announcement) => announcement.message) || []; + const activeAnnouncements = () => { + if (announcements && announcements.announcements) { + return announcements.announcements + .filter((announcement) => announcement.state === 'Active') + .map((announcement) => announcement.message) + } else { + return [] + } + } return (
- {activeAnnouncements.map((announcement: string, index: number) => ( + {activeAnnouncements().map((announcement: string, index: number) => ( ))}
diff --git a/ui/src/components/UHGroupingsInfo.tsx b/ui/src/components/UHGroupingsInfo.tsx index 17e4985b..33db56c1 100644 --- a/ui/src/components/UHGroupingsInfo.tsx +++ b/ui/src/components/UHGroupingsInfo.tsx @@ -14,7 +14,8 @@ const UHGroupingsInfo = ({

What is a UH Grouping?

-

A grouping is a collection of members +

A grouping is a collection of members (e.g., all full-time Hilo faculty).

diff --git a/ui/src/components/ui/alert.tsx b/ui/src/components/ui/alert.tsx index 2848a462..4832deac 100644 --- a/ui/src/components/ui/alert.tsx +++ b/ui/src/components/ui/alert.tsx @@ -13,7 +13,6 @@ const alertVariants = cva( variant: { default: 'bg-white text-slate-950 dark:bg-slate-950 dark:text-slate-50', destructive: - // eslint-disable-next-line @stylistic/max-len 'border-red-500/50 text-red-500 dark:border-red-500 [&>svg]:text-red-500 dark:border-red-900/50 dark:text-red-900 dark:dark:border-red-900 dark:[&>svg]:text-red-900', }, }, diff --git a/ui/tests/app/(index)/_components/AfterLogin.test.tsx b/ui/tests/app/(index)/_components/AfterLogin.test.tsx index 243af6d1..88ddd1b2 100644 --- a/ui/tests/app/(index)/_components/AfterLogin.test.tsx +++ b/ui/tests/app/(index)/_components/AfterLogin.test.tsx @@ -90,7 +90,8 @@ describe('AfterLogin', () => { const Groupings = (isOwner:boolean) => { if(isOwner) { - expect(screen.getByRole('img', {name: 'wrench-solid'})).toHaveAttribute('src', 'uhgroupings/wrench-solid.svg') + expect(screen.getByRole('img', {name: 'wrench-solid'})) + .toHaveAttribute('src', 'uhgroupings/wrench-solid.svg') expect(screen.getByText(numberOfGroupings)).toBeInTheDocument() expect(screen.getByRole('heading', {name: 'Groupings'})).toBeInTheDocument() expect(screen.getByText('Review members, manage Include and Exclude lists, ' + diff --git a/ui/tests/app/(index)/_components/BeforeLogin.test.tsx b/ui/tests/app/(index)/_components/BeforeLogin.test.tsx index 66db4d0f..bf73740e 100644 --- a/ui/tests/app/(index)/_components/BeforeLogin.test.tsx +++ b/ui/tests/app/(index)/_components/BeforeLogin.test.tsx @@ -1,23 +1,28 @@ import {render, screen} from '@testing-library/react'; import BeforeLogin from '@/app/(index)/_components/BeforeLogin'; describe('BeforeLogin Component', () =>{ - test('renders UHGroupingsInfo component', ()=> { + test('renders UHGroupingsInfo and a button with correct text and link', ()=> { render(); - const uhGroupingsInfo = screen.getByText('What is a UH Grouping?'); - expect(uhGroupingsInfo).toBeInTheDocument(); - }) + const size = 'text-[1.2rem]' + const linkUrl = 'https://uhawaii.atlassian.net/wiki/spaces/UHIAM/pages/13403213/UH+Groupings' + expect(screen.getByRole('heading', {name:'What is a UH Grouping?'})) + .toHaveClass('text-text-color'); + expect(screen.getByTestId('description')).toBeInTheDocument() - test('renders LearnMoreButton Component', ()=>{ - render(); - const LearnMoreButton = screen.getByText('Learn More'); - expect(LearnMoreButton).toBeInTheDocument(); - }) + expect(screen.getByAltText('Cogs icon')).toHaveAttribute('src', '/uhgroupings/cogs.svg') + expect(screen.getByText('Create groupings, manage grouping memberships, control members\' ' + + 'self-service options, designate sync destinations, and more.')).toHaveClass(size) + + expect(screen.getByAltText('Email icon')).toHaveAttribute('src', '/uhgroupings/id-email.svg') + expect(screen.getByText('Synchronize groupings email LISTSERV lists,' + + ' attributes for access control via CAS and LDAP, etc..')).toHaveClass(size) + + expect(screen.getByAltText('Watch icon')).toHaveAttribute('src', '/uhgroupings/watch.svg') + expect(screen.getByText('Leverage group data from official sources,' + + ' which can substantially reduce the manual overhead of membership management.')).toHaveClass(size) - test('LearningMoreButton redirects to the correct link', ()=>{ - render() - const linkElement = screen.getByRole('link'); - expect((linkElement)).toHaveAttribute('href', - 'https://uhawaii.atlassian.net/wiki/spaces/UHIAM/pages/13403213/UH+Groupings') + expect(screen.getByRole('link')).toHaveAttribute('href', linkUrl) + expect(screen.getByRole('button', {name:'Learn More'})).toBeInTheDocument() }) }) diff --git a/ui/tests/app/(index)/_components/LoginButton.test.tsx b/ui/tests/app/(index)/_components/LoginButton.test.tsx new file mode 100644 index 00000000..0cda274b --- /dev/null +++ b/ui/tests/app/(index)/_components/LoginButton.test.tsx @@ -0,0 +1,53 @@ +import { render, screen, fireEvent } from '@testing-library/react'; +import { redirect } from 'next/navigation'; +import User, { AnonymousUser } from '@/access/User'; +import Role from '@/access/Role'; +import LoginButton from "@/app/(index)/_components/LoginButton"; + +const casUrl = process.env.NEXT_PUBLIC_CAS_URL as string; +const baseUrl = process.env.NEXT_PUBLIC_BASE_URL as string; +const testUser: User = JSON.parse(process.env.TEST_USER_A as string); + +describe('LoginButton Component', () => { + + describe('User is not logged in', () => { + + it('should render a Login button', () => { + render(); + + expect(screen.getByRole('button', { name: 'Login Here' })).toBeInTheDocument; + }); + + it('should visit the CAS login url on click', () => { + render(); + + const casLoginUrl = `${casUrl}/login?service=${encodeURIComponent(`${baseUrl}/api/cas/login`)}`; + fireEvent.click(screen.getByRole('button', { name: 'Login Here' })); + expect(redirect).toHaveBeenCalledWith(casLoginUrl); + }); + + }); + + describe('User is logged in', () => { + + beforeAll(() => { + testUser.roles.push(Role.UH); + }); + + it('should render a Logout button with the uid of the logged-in user', () => { + render(); + + expect(screen.getByRole('button', { name: 'Logout' })).toBeInTheDocument; + }); + + it('should visit the CAS logout url on click', () => { + render(); + + const casLogoutUrl = `${casUrl}/logout?service=${encodeURIComponent(`${baseUrl}/api/cas/logout`)}`; + fireEvent.click(screen.getByRole('button', { name: 'Logout' })); + expect(redirect).toHaveBeenCalledWith(casLogoutUrl); + }); + + }); + +}); diff --git a/ui/tests/app/(index)/_components/UserInfoItem.test.tsx b/ui/tests/app/(index)/_components/UserInfoItem.test.tsx index 7c7d59b1..3b382a76 100644 --- a/ui/tests/app/(index)/_components/UserInfoItem.test.tsx +++ b/ui/tests/app/(index)/_components/UserInfoItem.test.tsx @@ -35,15 +35,11 @@ const renderUserInfoItem = ({ }; const assertCommonUserInfo = ({alt, src, title, description, link, text}: UserInfoItemProps) => { - const imageElement = screen.getByRole('img'); - expect(imageElement).toHaveAttribute('alt', alt); - expect(imageElement).toHaveAttribute('src', src); + expect(screen.getByAltText(alt)).toHaveAttribute('src', src); expect(screen.getByRole('heading', {name: title})).toBeInTheDocument(); expect(screen.getByText(description)).toBeInTheDocument(); - const linkElement = screen.getByRole('link'); - expect(linkElement).toHaveAttribute('href', link); - const buttonElement = screen.getByRole('button', {name: text}); - expect(buttonElement).toBeInTheDocument(); + expect(screen.getByRole('link')).toHaveAttribute('href', link); + expect(screen.getByRole('button', {name: text})).toBeInTheDocument(); }; describe('UserInfoItem Component', () => { @@ -64,7 +60,8 @@ describe('UserInfoItem Component', () => { number: 0, show: false, title: 'Administration', - description: 'Manage the list of Administrators for this service. Search for and manage any grouping on behalf of the owner.', + description: 'Manage the list of Administrators for this service. ' + + 'Search for and manage any grouping on behalf of the owner.', link: '/admin', text: 'Admin' }; diff --git a/ui/tests/components/UHGroupingsInfo.test.tsx b/ui/tests/components/UHGroupingsInfo.test.tsx index d99be733..e90ce33f 100644 --- a/ui/tests/components/UHGroupingsInfo.test.tsx +++ b/ui/tests/components/UHGroupingsInfo.test.tsx @@ -2,35 +2,46 @@ import {render,screen} from '@testing-library/react'; import UHGroupingsInfo from '@/components/UHGroupingsInfo'; describe('UHGroupings Component', ()=>{ - - const cogs= () => { + const cogs= (size: 'text-[1.2rem]'|'text-base') => { + const description = 'Create groupings, manage grouping memberships, control members\' ' + + 'self-service options, designate sync destinations, and more.' expect(screen.getByAltText('Cogs icon')).toHaveAttribute('src', '/uhgroupings/cogs.svg') - expect(screen.getByText('Create groupings, manage grouping memberships,' + - ' control members\' self-service options, designate sync destinations, and more.')).toBeInTheDocument() + expect(screen.getByText(description)).toHaveClass(size) } - const email = ()=> { + const email = (size: 'text-[1.2rem]'|'text-base')=> { + const description = 'Synchronize groupings email LISTSERV lists,' + + ' attributes for access control via CAS and LDAP, etc..' expect(screen.getByAltText('Email icon')).toHaveAttribute('src', '/uhgroupings/id-email.svg') - expect(screen.getByText('Synchronize groupings email LISTSERV lists,' + - ' attributes for access control via CAS and LDAP, etc.')).toBeInTheDocument() + expect(screen.getByText(description)).toHaveClass(size) } - const watch = () =>{ + const watch = (size: 'text-[1.2rem]'|'text-base') =>{ + const description = 'Leverage group data from official sources,' + + ' which can substantially reduce the manual overhead of membership management.' expect(screen.getByAltText('Watch icon')).toHaveAttribute('src', '/uhgroupings/watch.svg') - expect(screen.getByText('Leverage group data from official sources,' + - ' which can substantially reduce the manual overhead of membership management.')).toBeInTheDocument() + expect(screen.getByText(description)).toHaveClass(size) } test('renders with variant prop', ()=> { render() - - expect(screen.getByRole('heading', {name:'What is a UH Grouping?'})).toHaveClass('text-text-color'); - expect(screen.getByText('A grouping is a collection of members ' + - '(e.g., all full-time Hilo faculty).')).toBeInTheDocument() - cogs() - email() - watch() + expect(screen.getByRole('heading', {name:'What is a UH Grouping?'})) + .toHaveClass('text-text-color'); + expect(screen.getByTestId('description')).toBeInTheDocument() + cogs('text-[1.2rem]') + email('text-[1.2rem]') + watch('text-[1.2rem]') }) + + test('renders without variant prop', ()=>{ + render() + expect(screen.getByRole('heading', {name:'What is a UH Grouping?'})) + .toHaveClass('text-uh-black'); + expect(screen.getByTestId('description')).toBeInTheDocument() + cogs('text-base') + email('text-base') + watch('text-base') + }) })