diff --git a/frontend/__tests__/CookiesPage.test.tsx b/frontend/__tests__/CookiesPage.test.tsx index 8f9f20109..db2892e1b 100644 --- a/frontend/__tests__/CookiesPage.test.tsx +++ b/frontend/__tests__/CookiesPage.test.tsx @@ -1,5 +1,7 @@ // SPDX-FileCopyrightText: 2022 - 2023 Dusan Mijatovic (dv4all) // SPDX-FileCopyrightText: 2022 - 2023 dv4all +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center // // SPDX-License-Identifier: Apache-2.0 @@ -8,9 +10,11 @@ import {WrappedComponentWithProps} from '../utils/jest/WrappedComponents' import CookiesPage from '../pages/cookies' -// we mock default providers too +// use DEFAULT MOCK for login providers list +// required when AppHeader component is used jest.mock('~/auth/api/useLoginProviders') + it('renders cookies page with title Cookies', async() => { const props = { matomoId: null, diff --git a/frontend/__tests__/Home.test.tsx b/frontend/__tests__/Home.test.tsx index 80710f16d..e8731f62c 100644 --- a/frontend/__tests__/Home.test.tsx +++ b/frontend/__tests__/Home.test.tsx @@ -12,6 +12,12 @@ import Home from '../pages/index' import {defaultRsdSettings} from '~/config/rsdSettingsReducer' import {WrappedComponentWithProps} from '~/utils/jest/WrappedComponents' +// use DEFAULT MOCK for login providers list +// required when AppHeader component is used +jest.mock('~/auth/api/useLoginProviders') +// use DEFAULT MOCK for organisation list used by Helmholtz homepage +jest.mock('~/components/home/helmholtz/useOrganisations') + const props = { host: { name: 'rsd' diff --git a/frontend/__tests__/OrganisationItem.test.tsx b/frontend/__tests__/OrganisationPage.test.tsx similarity index 88% rename from frontend/__tests__/OrganisationItem.test.tsx rename to frontend/__tests__/OrganisationPage.test.tsx index fdd27efbe..e4a6a86e1 100644 --- a/frontend/__tests__/OrganisationItem.test.tsx +++ b/frontend/__tests__/OrganisationPage.test.tsx @@ -9,7 +9,7 @@ import {render, screen, waitForElementToBeRemoved} from '@testing-library/react' import {WithAppContext, mockSession} from '~/utils/jest/WithAppContext' -import OrganisationPage from '../pages/organisations/[...slug]' +import OrganisationPage, {OrganisationPageProps} from '../pages/organisations/[...slug]' // MOCKS import mockRORIinfo from './__mocks__/apiRORInfo.json' @@ -22,13 +22,20 @@ import {TabKey} from '~/components/organisation/tabs/OrganisationTabItems' // MOCK user agreement call jest.mock('~/components/user/settings/fetchAgreementStatus') +// use DEFAULT MOCK for login providers list +// required when AppHeader component is used +jest.mock('~/auth/api/useLoginProviders') + const mockProps = { organisation: mockOrganisation, slug:['dutch-research-council'], tab: 'software' as TabKey, ror: mockRORIinfo as any, - isMaintainer: false -} + isMaintainer: false, + rsd_page_rows: 12, + rsd_page_layout: 'grid' +} as OrganisationPageProps + // MOCK isMaintainerOfOrganisation const mockIsMaintainerOfOrganisation = jest.fn((props) => { // console.log('mockIsMaintainerOfOrganisation...', props) @@ -41,13 +48,17 @@ jest.mock('~/auth/permissions/isMaintainerOfOrganisation', () => { default: jest.fn(props=>mockIsMaintainerOfOrganisation(props)) } }) - // MOCK getSoftwareForOrganisation const mockSoftwareForOrganisation = jest.fn((props) => Promise.resolve({ status: 206, count: 0, data: [] })) +// MOCK software filters - use default mocks +jest.mock('~/components/organisation/software/filters/useOrgSoftwareKeywordsList') +jest.mock('~/components/organisation/software/filters/useOrgSoftwareLanguagesList') +jest.mock('~/components/organisation/software/filters/useOrgSoftwareLicensesList') + // MOCK getProjectsForOrganisation const mockProjectsForOrganisation = jest.fn((props) => Promise.resolve({ status: 206, @@ -62,9 +73,12 @@ jest.mock('~/components/organisation/apiOrganisations', () => ({ getOrganisationChildren: jest.fn((props)=>mockGetOrganisationChildren(props)) })) -// use DEFAULT MOCK for login providers list -// required when AppHeader component is used -jest.mock('~/auth/api/useLoginProviders') +// MOCK project filters - use default mocks +jest.mock('~/components/organisation/projects/filters/useOrgProjectDomainsList') +jest.mock('~/components/organisation/projects/filters/useOrgProjectKeywordsList') +jest.mock('~/components/organisation/projects/filters/useOrgProjectOrganisationsList') +jest.mock('~/components/organisation/projects/filters/useOrgProjectStatusList') + describe('pages/organisations/[...slug].tsx', () => { beforeEach(() => { diff --git a/frontend/__tests__/ProjectEditPage.test.tsx b/frontend/__tests__/ProjectEditPage.test.tsx index 14d209720..fd61a12cd 100644 --- a/frontend/__tests__/ProjectEditPage.test.tsx +++ b/frontend/__tests__/ProjectEditPage.test.tsx @@ -31,6 +31,8 @@ jest.mock('~/auth/permissions/isMaintainerOf', () => ({ // MOCK useProjectToEdit (default mock) jest.mock('~/components/projects/edit/information/useProjectToEdit') +// mock default keywords list (autocomplete) +jest.mock('~/components/projects/edit/information/searchForKeyword') // MOCK IntersectionObserver const mockObserve = jest.fn() diff --git a/frontend/__tests__/ProjectItem.test.tsx b/frontend/__tests__/ProjectItem.test.tsx index c25906797..047dc42c7 100644 --- a/frontend/__tests__/ProjectItem.test.tsx +++ b/frontend/__tests__/ProjectItem.test.tsx @@ -24,6 +24,10 @@ import {RelatedProject} from '../types/Project' import {MentionItemProps} from '../types/Mention' import {ProjectOrganisationProps} from '~/types/Organisation' +// use DEFAULT MOCK for login providers list +// required when AppHeader component is used +jest.mock('~/auth/api/useLoginProviders') + const mockedProps: ProjectPageProps = { slug: 'test-slug', project: projectItem, diff --git a/frontend/__tests__/ProjectsOverviewPage.test.tsx b/frontend/__tests__/ProjectsOverviewPage.test.tsx index 7f0729e17..d11e7d54f 100644 --- a/frontend/__tests__/ProjectsOverviewPage.test.tsx +++ b/frontend/__tests__/ProjectsOverviewPage.test.tsx @@ -13,6 +13,10 @@ import {LayoutType} from '~/components/software/overview/search/ViewToggleGroup' import mockData from './__mocks__/projectsOverview.json' +// use DEFAULT MOCK for login providers list +// required when AppHeader component is used +jest.mock('~/auth/api/useLoginProviders') + const mockProps = { search: null, order: null, diff --git a/frontend/__tests__/SoftwareItem.test.tsx b/frontend/__tests__/SoftwareItem.test.tsx index f2b878546..4c21e1724 100644 --- a/frontend/__tests__/SoftwareItem.test.tsx +++ b/frontend/__tests__/SoftwareItem.test.tsx @@ -1,5 +1,7 @@ // SPDX-FileCopyrightText: 2022 Dusan Mijatovic (dv4all) // SPDX-FileCopyrightText: 2022 dv4all +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center // // SPDX-License-Identifier: Apache-2.0 @@ -10,6 +12,10 @@ import {WrappedComponentWithProps} from '../utils/jest/WrappedComponents' // mock fetch response import softwareIndexData from './__mocks__/softwareIndexData' +// use DEFAULT MOCK for login providers list +// required when AppHeader component is used +jest.mock('~/auth/api/useLoginProviders') + jest.mock('../utils/getSoftware') // mock next router diff --git a/frontend/__tests__/SoftwareOverview.test.tsx b/frontend/__tests__/SoftwareOverview.test.tsx index 4274d8832..51af8f507 100644 --- a/frontend/__tests__/SoftwareOverview.test.tsx +++ b/frontend/__tests__/SoftwareOverview.test.tsx @@ -11,6 +11,10 @@ import {WithAppContext} from '~/utils/jest/WithAppContext' import SoftwareOverviewPage from '../pages/software/index' import {LayoutType} from '~/components/software/overview/search/ViewToggleGroup' +// use DEFAULT MOCK for login providers list +// required when AppHeader component is used +jest.mock('~/auth/api/useLoginProviders') + // mocked data & props import mockData from './__mocks__/softwareOverviewData.json' diff --git a/frontend/__tests__/UserPages.test.tsx b/frontend/__tests__/UserPages.test.tsx index 689c28471..8cba6f71a 100644 --- a/frontend/__tests__/UserPages.test.tsx +++ b/frontend/__tests__/UserPages.test.tsx @@ -1,3 +1,4 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) // SPDX-FileCopyrightText: 2023 Dusan Mijatovic (dv4all) // SPDX-FileCopyrightText: 2023 Dusan Mijatovic (dv4all) (dv4all) // SPDX-FileCopyrightText: 2023 Ewan Cahen (Netherlands eScience Center) @@ -11,8 +12,18 @@ import {WithAppContext, mockSession} from '~/utils/jest/WithAppContext' import UserPages from '../pages/user/[section]' +import mockSoftwareByMaintainer from '~/components/user/software/__mocks__/softwareByMaintainer.json' +import mockProjectsByMaintainer from '~/components/user/project/__mocks__/projectsByMaintainer.json' + +// use DEFAULT MOCK for login providers list +// required when AppHeader component is used +jest.mock('~/auth/api/useLoginProviders') // MOCK user agreement call jest.mock('~/components/user/settings/fetchAgreementStatus') +// MOCK user project list +jest.mock('~/components/user/project/useUserProjects') +// MOCK user software list +jest.mock('~/components/user/software/useUserSoftware') // MOCKS const mockProps = { @@ -73,25 +84,29 @@ describe('pages/user/[section].tsx', () => { it('renders user software section', async() => { mockProps.section = 'software' - const {container} = render( + render( ) - const loader = screen.getByRole('progressbar') + // validate software cards are shown + const software = screen.getAllByTestId('software-card-link') + expect(software.length).toEqual(mockSoftwareByMaintainer.length) }) it('renders user projects section', async() => { mockProps.section = 'projects' - const {container} = render( + render( ) - const loader = screen.getByRole('progressbar') + // validate project cards are shown + const project = screen.getAllByTestId('project-card-link') + expect(project.length).toEqual(mockProjectsByMaintainer.length) }) }) diff --git a/frontend/auth/index.test.tsx b/frontend/auth/AuthIndex.test.tsx similarity index 96% rename from frontend/auth/index.test.tsx rename to frontend/auth/AuthIndex.test.tsx index 7e0a865f3..07c65fcd4 100644 --- a/frontend/auth/index.test.tsx +++ b/frontend/auth/AuthIndex.test.tsx @@ -1,5 +1,7 @@ // SPDX-FileCopyrightText: 2022 Dusan Mijatovic (dv4all) // SPDX-FileCopyrightText: 2022 dv4all +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center // // SPDX-License-Identifier: Apache-2.0 diff --git a/frontend/auth/RsdAdminContent.test.tsx b/frontend/auth/RsdAdminContent.test.tsx index 42bc56c41..1b759da6c 100644 --- a/frontend/auth/RsdAdminContent.test.tsx +++ b/frontend/auth/RsdAdminContent.test.tsx @@ -1,11 +1,13 @@ // SPDX-FileCopyrightText: 2022 Dusan Mijatovic (dv4all) // SPDX-FileCopyrightText: 2022 dv4all +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center // // SPDX-License-Identifier: Apache-2.0 import {render, screen} from '@testing-library/react' -import {WrappedComponentWithProps} from '~/utils/jest/WrappedComponents' -import {useAuth, defaultSession} from '.' +import {WithAppContext, mockSession} from '~/utils/jest/WithAppContext' +import {useAuth,Session} from './index' import RsdAdminContent from './RsdAdminContent' @@ -26,53 +28,68 @@ function ProtectedComponent() { it('Shows loader when session.status==="loading"', () => { - defaultSession.status='loading' - render(WrappedComponentWithProps(ProtectedComponent, { - session: defaultSession - })) - const loader = screen.getByRole('progressbar') - expect(loader).toBeInTheDocument() + const testSession = { + ...mockSession, + status: 'loading' + } as Session + + render( + + + + ) + + screen.getByRole('progressbar') // screen.debug() }) it('Protects content with 401 when session.status==="missing"', () => { - defaultSession.status='missing' - render(WrappedComponentWithProps(ProtectedComponent, { - session: defaultSession - })) - const heading = screen.getByRole('heading') - expect(heading.innerHTML).toContain('401') + const testSession = { + ...mockSession, + status: 'missing' + } as Session + + render( + + + + ) + + screen.getByRole('heading', {name:'401'}) + }) it('Protects content with 403 when authenticated but not rsd_admin', () => { - defaultSession.status = 'authenticated' - defaultSession.user = { - iss: 'rsd_auth', - role: 'rsd_user', - exp: 1212121212, - account: 'test-account-string', - name: 'John Doe' - } - render(WrappedComponentWithProps(ProtectedComponent, { - session: defaultSession - })) - const heading = screen.getByRole('heading') - expect(heading.innerHTML).toContain('403') + const testSession = { + ...mockSession + } as Session + + render( + + + + ) + screen.getByRole('heading', {name: '403'}) + // screen.debug() }) it('Shows content when authenticated AND rsd_admin', () => { - defaultSession.status = 'authenticated' - defaultSession.user = { - iss: 'rsd_auth', - role: 'rsd_admin', - exp: 1212121212, - account: 'test-account-string', - name: 'John Doe' - } - defaultSession.token='TEST_RANDOM_TOKEN' - render(WrappedComponentWithProps(ProtectedComponent, { - session: defaultSession - })) + + const testSession = { + ...mockSession, + user: { + ...mockSession.user, + role: 'rsd_admin' + } + + } as Session + + render( + + + + ) + const heading = screen.getByRole('heading') expect(heading.innerHTML).toContain(adminText) // screen.debug() diff --git a/frontend/auth/RsdAdminContent.tsx b/frontend/auth/RsdAdminContent.tsx index 74770a78a..1807ed032 100644 --- a/frontend/auth/RsdAdminContent.tsx +++ b/frontend/auth/RsdAdminContent.tsx @@ -13,8 +13,6 @@ import PageErrorMessage from '~/components/layout/PageErrorMessage' export default function RsdAdminContent({children}:{children:any}) { const {session} = useAuth() - // if slug is provided we need to make api call to check if user - // is maintainer of the software const [status, setStatus] = useState(session?.status ? session?.status :'loading') useEffect(() => { diff --git a/frontend/auth/__mocks__/refreshSession.ts b/frontend/auth/__mocks__/refreshSession.ts new file mode 100644 index 000000000..93eedb022 --- /dev/null +++ b/frontend/auth/__mocks__/refreshSession.ts @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +import {Session} from '..' +import {mockSession} from '~/utils/jest/WithAppContext' + +export async function refreshSession(): Promise { + // return default mocked session + return mockSession +} diff --git a/frontend/auth/index.tsx b/frontend/auth/index.tsx index abdec9540..88de17f65 100644 --- a/frontend/auth/index.tsx +++ b/frontend/auth/index.tsx @@ -50,15 +50,15 @@ export const initSession: AuthSession = { setSession: () => defaultSession } -const AuthContext = createContext(initSession) +const AuthContext = createContext(initSession) // AuthProvider used in _app to share session between all components export function AuthProvider(props: any) { - const [session, setSession] = useState(props?.session ?? defaultSession) + const [session, setSession] = useState(props?.session) // console.group('AuthProvider') - // console.log('session.user..', session?.user) - // console.log('props.session.user...', props?.session?.user) + // console.log('session...', session) + // console.log('props.session...', props?.session) // console.groupEnd() useEffect(() => { @@ -66,7 +66,7 @@ export function AuthProvider(props: any) { let schedule: any // only if authenticated = valid token if (session.status === 'authenticated' - && session?.user) { + && session?.user?.exp) { const {user} = session const expiresInMs = getExpInMs(user.exp) const waitInMs = getWaitInMs(expiresInMs) @@ -74,11 +74,16 @@ export function AuthProvider(props: any) { if (schedule) clearTimeout(schedule) if (expiresInMs <= 0) { // token expired - setSession(defaultSession) + setSession({ + ...session, + status: 'expired', + token: `AuthProvider session EXPIRED for account ${session.user.account}`, + user: null + }) }else{ // console.log(`schedule refresh in ${waitInMs/1000}sec.`) schedule = setTimeout(() => { - // console.log('call...refreshSession') + // console.log('call...refreshSession...',user.account) // refresh token by sending current valid cookie refreshSession() .then(newSession => { @@ -102,7 +107,7 @@ export function AuthProvider(props: any) { clearTimeout(schedule) } } - }, [session, setSession]) + }, [session]) return } @@ -113,6 +118,11 @@ export const useAuth = () => useContext(AuthContext) // More specific session hook which destructures session export function useSession(){ const {session} = useContext(AuthContext) + + // console.group('useSession') + // console.log('session...', session) + // console.groupEnd() + return { ...session } diff --git a/frontend/auth/permissions/isMaintainerOfOrganisation.ts b/frontend/auth/permissions/isMaintainerOfOrganisation.ts index f54af71cd..57b9d7177 100644 --- a/frontend/auth/permissions/isMaintainerOfOrganisation.ts +++ b/frontend/auth/permissions/isMaintainerOfOrganisation.ts @@ -1,10 +1,41 @@ // SPDX-FileCopyrightText: 2022 - 2023 Dusan Mijatovic (dv4all) // SPDX-FileCopyrightText: 2022 - 2023 dv4all +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center // // SPDX-License-Identifier: Apache-2.0 import {createJsonHeaders, getBaseUrl} from '../../utils/fetchHelpers' import logger from '../../utils/logger' +import {RsdRole} from '../index' + +type IsOrganisationMaintainerProps = { + organisation: string + role?: RsdRole + account?: string + token?: string +} + +export async function isOrganisationMaintainer({organisation, role, account, token}: IsOrganisationMaintainerProps) { + // if no token no check needed + if (typeof token === 'undefined') return false + // if organisation provided and user role rsd_admin + if (organisation && role === 'rsd_admin' && account) { + return true + } + // make request + const isMaintainer = await isMaintainerOfOrganisation({ + organisation, + account, + token + }) + + // console.group('isOrganisationMaintainer') + // console.log('isMaintainer...', isMaintainer) + // console.groupEnd() + + return isMaintainer +} type IsMaintainerOfOrganisationProps = { organisation: string diff --git a/frontend/auth/permissions/useOrganisationMaintainer.test.tsx b/frontend/auth/permissions/useOrganisationMaintainer.test.tsx index 1a03e7f60..09fe92851 100644 --- a/frontend/auth/permissions/useOrganisationMaintainer.test.tsx +++ b/frontend/auth/permissions/useOrganisationMaintainer.test.tsx @@ -1,22 +1,26 @@ // SPDX-FileCopyrightText: 2022 Dusan Mijatovic (dv4all) // SPDX-FileCopyrightText: 2022 dv4all +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center // // SPDX-License-Identifier: Apache-2.0 import {render,screen} from '@testing-library/react' import {mockResolvedValueOnce} from '~/utils/jest/mockFetch' import useOrganisationMaintainer from './useOrganisationMaintainer' -import {WrappedComponentWithProps} from '~/utils/jest/WrappedComponents' -import {defaultSession} from '..' +import {WithAppContext, mockSession} from '~/utils/jest/WithAppContext' +import {Session} from '..' const mockData = { organisation: 'test-organisation-id', - account: 'test-account-id', + user: { + account: 'test-account-id', + role: 'rsd_admin' + }, token: 'TEST_TOKEN', frontend: true } - beforeEach(() => { // we need to reset fetch mock counts jest.resetAllMocks() @@ -27,7 +31,10 @@ function WrappedHook() { organisation: mockData.organisation }) - // console.log('2.isMaintainer...', isMaintainer) + // console.group('WrappedHook') + // console.log('loading...', loading) + // console.log('isMaintainer...', isMaintainer) + // console.groupEnd() if (loading===true) { return ( @@ -46,56 +53,152 @@ function WrappedHook() { ) } -it('returns isMaintainer=true for rsd_admin', async () => { - // set authenticated props - defaultSession.status = 'authenticated' - defaultSession.token = mockData.token - defaultSession.user = { - iss: 'rsd_auth', - role: 'rsd_admin', - exp: 11111111, - account: 'test-account', - name: 'John Doe' - } +it('returns isMaintainer=true for rsd_admin role', async () => { + const testSession = { + ...mockSession, + status: 'authenticated', + token: mockData.token, + user: { + ...mockSession.user, + ...mockData.user + } + } as Session // return response to getMaintainerOrganisations + // mockResolvedValueOnce(['Random organisation name']) + + render( + + + + ) + + // find maintainer header + await screen.findByRole('heading', {name: 'IS MAINTAINER'}) +}) + +it('returns isMaintainer=true when user is maintainer of organisation', async() => { + // return organisation in the list mockResolvedValueOnce([mockData.organisation]) - // render with basic privilegies - render(WrappedComponentWithProps(WrappedHook, { - session:defaultSession - })) + render( + + + + ) + + // find maintainer header + await screen.findByRole('heading',{name: 'IS MAINTAINER'}) +}) + +it('returns isMaintainer=false when user is NOT maintainer of organisation', async () => { + // set authenticated props + + mockResolvedValueOnce(['Random organisation name']) + + render( + + + + ) + + // find maintainer header + await screen.findByRole('heading',{name: '403'}) +}) + + +it('returns isMaintainer=false when user is NOT maintainer of organisation', async () => { + // set authenticated props + + mockResolvedValueOnce(['Random organisation name']) + + render( + + + + ) + + // find maintainer header + await screen.findByRole('heading',{name: '403'}) +}) + + +it('returns isMaintainer=false when NO user.account OR user.role defined', async () => { + // set authenticated props + // mockResolvedValueOnce(['Random organisation name']) + const noUser = { + ...mockSession, + user: {} + } as Session + + render( + + + + ) + + // find maintainer header + await screen.findByRole('heading',{name: '403'}) +}) + +it('returns isMaintainer=false when NO TOKEN', async () => { + // set authenticated props + // mockResolvedValueOnce(['Random organisation name']) + const noUser = { + ...mockSession, + token: '' + } as Session + + render( + + + + ) + + // find maintainer header + await screen.findByRole('heading',{name: '403'}) +}) + +it('returns isMaintainer=false when user.account=""', async () => { + // set authenticated props + // mockResolvedValueOnce(['Random organisation name']) + const noUser = { + ...mockSession, + user: { + ...mockSession.user, + account: '' + } + } as Session + + render( + + + + ) + + // find maintainer header + await screen.findByRole('heading',{name: '403'}) +}) + +it('returns isMaintainer=false when token is expired', async () => { + // set authenticated props + // mockResolvedValueOnce(['Random organisation name']) + const noUser = { + ...mockSession, + user: { + ...mockSession.user, + // expired user values + exp: 1111111 + } + } as Session + + render( + + + + ) - // check if maintainer - const content = await screen.findByText('IS MAINTAINER') - expect(content).toBeInTheDocument() + // find maintainer header + await screen.findByRole('heading',{name: '403'}) }) -// THIS DOES NOT WORK PROPERLY! -// it('returns isMaintainer=true when user is maintainer', async () => { -// // set authenticated props -// defaultSession.status = 'authenticated' -// defaultSession.token = mockData.token -// defaultSession.user = { -// iss: 'rsd_auth', -// role: 'rsd_user', -// exp: 11111111, -// account: 'test-account', -// name: 'John Doe' -// } - -// // return response to getMaintainerOrganisations -// mockResolvedValueOnce([mockData.organisation]) - -// // render with basic privilegies -// render(WrappedComponentWithProps(WrappedHook, { -// session:defaultSession -// })) - -// expect(global.fetch).toBeCalledTimes(1) -// // expect(global.fetch).toBeCalledWith({}) - -// // check if maintainer -// const content = await screen.findByText('IS MAINTAINER') -// expect(content).toBeInTheDocument() -// }) diff --git a/frontend/auth/permissions/useOrganisationMaintainer.tsx b/frontend/auth/permissions/useOrganisationMaintainer.tsx index ae1343c46..cf9f6958d 100644 --- a/frontend/auth/permissions/useOrganisationMaintainer.tsx +++ b/frontend/auth/permissions/useOrganisationMaintainer.tsx @@ -6,84 +6,52 @@ // SPDX-License-Identifier: Apache-2.0 import {useEffect,useState} from 'react' -import logger from '~/utils/logger' -import {RsdUser, useSession} from '..' -import isMaintainerOfOrganisation from './isMaintainerOfOrganisation' +import {useSession} from '../index' +import {isOrganisationMaintainer} from './isMaintainerOfOrganisation' -type UseOrganisationMaintainerProps = { - organisation?: string -} -type IsOrganisationMaintainerProps = { +type UseOrganisationMaintainerProps = { organisation: string - user: RsdUser | null - token?: string -} - -export async function isOrganisationMaintainer({organisation, user, token}: IsOrganisationMaintainerProps) { - // if no token no check needed - if (typeof token === 'undefined') return false - // if organisation provided and user role rsd_admin - if (organisation && user && user?.role === 'rsd_admin') { - return true - } - // make request - const isMaintainer = await isMaintainerOfOrganisation({ - organisation, - account: user?.account ?? '', - token - }) - return isMaintainer } export default function useOrganisationMaintainer({organisation}: UseOrganisationMaintainerProps) { - const {user,token,status} = useSession() - const [isMaintainer, setIsMaintainer] = useState(false) - const [loading, setLoading] = useState(true) + const {user,token} = useSession() + const [isMaintainer,setIsMaintainer] = useState(false) + const [loading,setLoading] = useState(true) // console.group('useOrganisationMaintainer') // console.log('organisation...', organisation) + // console.log('user...', user) + // console.log('token...', token) // console.log('status...', status) + // console.log('isMaintainer...', isMaintainer) // console.log('loading...', loading) - // console.log('1.isMaintainer...', isMaintainer) // console.groupEnd() useEffect(() => { let abort = false async function organisationMaintainer() { - if (organisation) { - setLoading(true) - const isMaintainer = await isMaintainerOfOrganisation({ - organisation, - account: user?.account ?? '', - token - }) - if (abort) return - setIsMaintainer(isMaintainer) - setLoading(false) - } else { - logger('useOrganisationMaintainer...organisation UNDEFINED', 'warn') - setIsMaintainer(false) - } + // console.log('organisationMaintainer...abort...',abort) + const isMaintainer = await isOrganisationMaintainer({ + organisation, + account: user?.account, + role: user?.role, + token + }) + // console.log('abort...',abort) + // console.log('organisationMaintainer...isMaintainer...',isMaintainer) + if (abort) return + setIsMaintainer(isMaintainer) + setLoading(false) } - if (organisation && - status === 'authenticated') { - if (user?.role === 'rsd_admin') { - if (abort) return - setIsMaintainer(true) - setLoading(false) - } else { - organisationMaintainer() - } - } else if (status !== 'authenticated' && isMaintainer === true) { - // console.log('Set back to false') - // set (back) to false + if (organisation && user?.account && user?.role && token != '') { + organisationMaintainer() + } else if (abort === false) { setIsMaintainer(false) - } else if (status!=='loading'){ setLoading(false) } return ()=>{abort=true} - },[organisation,user,status,token,isMaintainer]) + },[organisation,user?.account,user?.role,token,loading,isMaintainer]) return { loading, diff --git a/frontend/components/admin/AdminPageWithNav.test.tsx b/frontend/components/admin/AdminPageWithNav.test.tsx new file mode 100644 index 000000000..29323d69f --- /dev/null +++ b/frontend/components/admin/AdminPageWithNav.test.tsx @@ -0,0 +1,127 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +import {render, screen} from '@testing-library/react' +import {WithAppContext, mockSession} from '~/utils/jest/WithAppContext' + + +import AdminPageWithNav from './AdminPageWithNav' +import {Session} from '~/auth' + +it('returns 401 when status!=authenticated', async () => { + const testSession = { + ...mockSession, + status: 'expired' + } as Session + + const mockHeader='Admin content body' + + render( + + +

{mockHeader}

+
+
+ ) + + // find maintainer header + await screen.findByRole('heading',{name: '401'}) +}) + +it('returns 401 when user token expired', async () => { + const testSession = { + ...mockSession, + user: { + ...mockSession.user, + role: 'rsd_admin', + exp: 1111111 + } + } as Session + + const mockHeader='Admin content body' + + render( + + +

{mockHeader}

+
+
+ ) + + // find maintainer header + await screen.findByRole('heading',{name: '401'}) +}) + +it('returns 403 when NOT rsd_admin role and status=authenticated', async () => { + const testSession = { + ...mockSession, + user: { + ...mockSession.user, + role: 'rsd_user' + } + } as Session + + const mockHeader='Admin content body' + + render( + + +

{mockHeader}

+
+
+ ) + + // find maintainer header + await screen.findByRole('heading',{name: '403'}) + // await screen.findByRole('heading', {name: mockHeader}) +}) + +it('returns 403 when no user', async () => { + const testSession = { + ...mockSession, + user: {} + } as Session + + const mockHeader='Admin content body' + + render( + + +

{mockHeader}

+
+
+ ) + + // find maintainer header + await screen.findByRole('heading',{name: '403'}) +}) + +it('returns title and content when rsd_admin role', async () => { + const testSession = { + ...mockSession, + user: { + ...mockSession.user, + role: 'rsd_admin' + } + } as Session + + const mockTitle = 'Test page title' + const mockContentId='admin-page-content' + + render( + + +
+

Just some content

+
+
+
+ ) + + // find page title + await screen.findByRole('heading', {name: mockTitle}) + // find passed page content + screen.getByTestId(mockContentId) +}) diff --git a/frontend/components/admin/keywords/AdminKeywordsPage.test.tsx b/frontend/components/admin/keywords/AdminKeywordsPage.test.tsx new file mode 100644 index 000000000..6586be97c --- /dev/null +++ b/frontend/components/admin/keywords/AdminKeywordsPage.test.tsx @@ -0,0 +1,32 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +import {render, screen} from '@testing-library/react' +import {WithAppContext, mockSession} from '~/utils/jest/WithAppContext' + +import AdminKeywordsIndexPage from '~/components/admin/keywords/index' +import {Session} from '~/auth' + +const testSession = { + ...mockSession, + user: { + ...mockSession.user, + role: 'rsd_admin' + } +} as Session + +describe('components/admin/keywords/index.tsx', () => { + + it('shows progressbar initialy', () => { + + render( + + + + ) + screen.getByRole('progressbar') + // screen.debug() + }) +}) diff --git a/frontend/components/admin/keywords/KeywordEdit.test.tsx b/frontend/components/admin/keywords/KeywordEdit.test.tsx new file mode 100644 index 000000000..b43b1c761 --- /dev/null +++ b/frontend/components/admin/keywords/KeywordEdit.test.tsx @@ -0,0 +1,89 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +import {fireEvent, render, screen} from '@testing-library/react' + +import KeywordEdit from './KeywordEdit' + +// MOCKS +import mockKeywordData from './__mocks__/keyword_cnt.json' +const mockPatchKeyword = jest.fn() +jest.mock('./apiKeywords', () => ({ + patchKeyword:(props:any)=>mockPatchKeyword(props) +})) + + +beforeEach(() => { + jest.resetAllMocks() +}) + +it('shows data to edit', () => { + + render( + + ) + + const input = screen.getByRole('textbox') + expect(input.value).toEqual(mockKeywordData[0].keyword) +}) + +it('Escape resets to original value', async() => { + + render( + + ) + + const input = screen.getByRole('textbox') + + // change value + fireEvent.change(input, {target: {value: 'Test value'}}) + // validate changed value + expect(input.value).toEqual('Test value') + + // now use escape to reset + fireEvent.keyDown(input, {key:'Escape'}) + expect(input.value).toEqual(mockKeywordData[0].keyword) +}) + +it('On blur updates keyword', async() => { + + render( + + ) + + const input = screen.getByRole('textbox') + const newValue = 'Test value' + // change value + fireEvent.change(input, {target: {value: newValue}}) + // validate changed value + expect(input.value).toEqual(newValue) + + // now use escape to reset + fireEvent.blur(input) + + expect(mockPatchKeyword).toBeCalledTimes(1) + + const expected = { + 'id': mockKeywordData[0].id, + 'token': 'TEST-TOKEN', + 'value': newValue, + } + expect(mockPatchKeyword).toBeCalledWith(expected) + +}) + + diff --git a/frontend/components/admin/keywords/KeywordTable.test.tsx b/frontend/components/admin/keywords/KeywordTable.test.tsx new file mode 100644 index 000000000..e10656a5a --- /dev/null +++ b/frontend/components/admin/keywords/KeywordTable.test.tsx @@ -0,0 +1,116 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +import {fireEvent, render, screen} from '@testing-library/react' + +import KeywordTable from './KeywordTable' + +import mockKeywordData from './__mocks__/keyword_cnt.json' + +const mockProps = { + loading: true, + keywords: [], + searchFor: '', + deleteKeyword: jest.fn() +} + +beforeEach(() => { + jest.resetAllMocks() +}) + +it('shows loader when loading=true', () => { + + render( + + ) + screen.getByRole('progressbar') +}) + +it('shows no keyword message', () => { + mockProps.loading = false + mockProps.keywords = [] + + render( + + ) + + screen.getByText('Keyword not found') +}) + +it('shows mocked data with deleteBtn', () => { + mockProps.loading = false + mockProps.keywords = mockKeywordData as any + + render( + + ) + + // get all delete buttons + const deleteBtn = screen.getAllByRole('button') + // expect each keyword has one + expect(deleteBtn.length).toEqual(mockKeywordData.length) + // screen.debug() +}) + +it('has links to software and project pages with the correct keyword filter', () => { + mockProps.loading = false + mockProps.keywords = mockKeywordData as any + + render( + + ) + + // get all delete buttons + const links = screen.getAllByRole('link') + // expect each keyword has two links + expect(links.length).toEqual(mockKeywordData.length * 2) + + // expect links to software and project overview with keyword filter + expect((links[0] as HTMLAnchorElement).href).toEqual('http://localhost/software?keywords=%5B%22Big%20data%22%5D') + expect((links[1] as HTMLAnchorElement).href).toEqual('http://localhost/projects?keywords=%5B%22Big%20data%22%5D') +}) + + +it('deleteBtn is disabled when keyword is used (count>0)', () => { + mockProps.loading = false + mockProps.keywords = mockKeywordData as any + + render( + + ) + + // get all delete buttons + const deleteBtn = screen.getAllByRole('button') + // expect each keyword has one + expect(deleteBtn[0]).toBeDisabled() + // screen.debug() +}) + +it('deleteBtn is enabled when keyword is NOT used', async() => { + const newMock = [ + { + ...mockKeywordData[0], + software_cnt: 0, + projects_cnt: 0 + } + ] + mockProps.loading = false + mockProps.keywords = newMock as any + + render( + + ) + + // get all delete buttons + const deleteBtn = screen.getAllByRole('button') + // expect each keyword has one + expect(deleteBtn[0]).toBeEnabled() + + fireEvent.click(deleteBtn[0]) + // validate call + expect(mockProps.deleteKeyword).toBeCalledTimes(1) + expect(mockProps.deleteKeyword).toBeCalledWith(mockKeywordData[0].id) + // screen.debug() +}) diff --git a/frontend/components/admin/keywords/__mocks__/keyword_cnt.json b/frontend/components/admin/keywords/__mocks__/keyword_cnt.json new file mode 100644 index 000000000..803500588 --- /dev/null +++ b/frontend/components/admin/keywords/__mocks__/keyword_cnt.json @@ -0,0 +1,74 @@ +[ + { + "id": "f74c2e52-ecd1-4529-b317-9323656462de", + "keyword": "Big data", + "software_cnt": 44, + "projects_cnt": 41 + }, + { + "id": "6a8d6bc2-98df-4a0d-b423-9773c2cc7d72", + "keyword": "GPU", + "software_cnt": 45, + "projects_cnt": 34 + }, + { + "id": "f14bc70e-7188-4718-89b7-52cf1f827ad9", + "keyword": "High performance computing", + "software_cnt": 42, + "projects_cnt": 48 + }, + { + "id": "f2e83f93-552a-452c-ad67-dd4e3b8592fa", + "keyword": "Image processing", + "software_cnt": 32, + "projects_cnt": 49 + }, + { + "id": "3cbe1b57-39ee-4eec-a966-703c6ae2af03", + "keyword": "Inter-operability & linked data", + "software_cnt": 39, + "projects_cnt": 42 + }, + { + "id": "4a65aa76-4f67-4e3e-afb2-9915b7cdf844", + "keyword": "Machine learning", + "software_cnt": 45, + "projects_cnt": 43 + }, + { + "id": "4c7805ae-69d3-4ccc-ad37-9b86ac755be9", + "keyword": "Multi-scale & multi model simulations", + "software_cnt": 41, + "projects_cnt": 35 + }, + { + "id": "08b8578e-237c-409d-8ffb-86389552ede2", + "keyword": "Optimized data handling", + "software_cnt": 35, + "projects_cnt": 35 + }, + { + "id": "0fe51727-5c4a-4505-8ad5-67b483baf83a", + "keyword": "Real time data analysis", + "software_cnt": 39, + "projects_cnt": 40 + }, + { + "id": "1601622b-ac2f-44b3-b03d-6c47c043d80d", + "keyword": "Text analysis & natural language processing", + "software_cnt": 48, + "projects_cnt": 46 + }, + { + "id": "4c20cfe9-1962-45fc-913a-0455934a051f", + "keyword": "Visualization", + "software_cnt": 49, + "projects_cnt": 44 + }, + { + "id": "898a3028-f8a4-4a63-8f26-c9fba5f29c71", + "keyword": "Workflow technologies", + "software_cnt": 35, + "projects_cnt": 54 + } +] \ No newline at end of file diff --git a/frontend/components/admin/keywords/__mocks__/keyword_cnt.json.license b/frontend/components/admin/keywords/__mocks__/keyword_cnt.json.license new file mode 100644 index 000000000..546d6c9eb --- /dev/null +++ b/frontend/components/admin/keywords/__mocks__/keyword_cnt.json.license @@ -0,0 +1,4 @@ +SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +SPDX-FileCopyrightText: 2023 Netherlands eScience Center + +SPDX-License-Identifier: Apache-2.0 diff --git a/frontend/components/admin/keywords/index.tsx b/frontend/components/admin/keywords/index.tsx index 0724c3fff..07208b0be 100644 --- a/frontend/components/admin/keywords/index.tsx +++ b/frontend/components/admin/keywords/index.tsx @@ -1,4 +1,6 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) // SPDX-FileCopyrightText: 2023 Dusan Mijatovic (dv4all) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center // SPDX-FileCopyrightText: 2023 dv4all // // SPDX-License-Identifier: Apache-2.0 @@ -19,7 +21,9 @@ export default function KeywordsPage() { const disabled = (typeof searchFor === 'undefined' || searchFor.length < 2) // console.group('KeywordsPage') - // console.log('searchFor...', searchFor) + // console.log('token...', token) + // console.log('keywordProps...', keywordProps) + // console.log('disabled...', disabled) // console.groupEnd() return ( diff --git a/frontend/components/admin/organisations/AddOrganisation.test.tsx b/frontend/components/admin/organisations/AddOrganisation.test.tsx new file mode 100644 index 000000000..25df8210a --- /dev/null +++ b/frontend/components/admin/organisations/AddOrganisation.test.tsx @@ -0,0 +1,135 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +import {fireEvent, render, screen, waitFor} from '@testing-library/react' + +import AddOrganisation from './AddOrganisation' + +const mockAutocompleteOptions = [{ + key: 'primary-key-1', + label: 'Test organisation 1', + data: { + id: null, + slug: 'test-organisation-1', + parent: null, + primary_maintainer: null, + name: 'Test organisation 1', + ror_id: 'TEST_ROR_ID', + is_tenant: false, + website: 'https://test-site.org', + logo_id: null, + source: 'ROR', + description: null + } +}] + +const mockOnAddOrganisation = jest.fn() +const mockFindInROR = jest.fn() + +jest.mock('~/utils/getROR',()=>({ + findInROR: (props:any)=>mockFindInROR(props) +})) + +beforeEach(() => { + jest.resetAllMocks() +}) + +it('renders add organisation combobox', () => { + + render( + + ) + + screen.getByRole('combobox',{name: 'Find or add organisation'}) + // screen.debug() +}) + +it('calls findROR api on search', async () => { + + const searchFor = 'Test organisation' + + render( + + ) + + const find = screen.getByRole('combobox', {name: 'Find or add organisation'}) + fireEvent.change(find, {target: {value: searchFor}}) + expect(find.value).toEqual(searchFor) + + await waitFor(() => { + expect(mockFindInROR).toBeCalledTimes(1) + expect(mockFindInROR).toBeCalledWith({ + 'searchFor': searchFor + }) + }) +}) + + +it('offers to add organisation when not found in ROR', async () => { + + const searchFor = 'Test organisation' + // return nothing found + mockFindInROR.mockResolvedValueOnce([]) + + render( + + ) + + const find = screen.getByRole('combobox', {name: 'Find or add organisation'}) + fireEvent.change(find, {target: {value: searchFor}}) + expect(find.value).toEqual(searchFor) + + await waitFor(() => { + expect(mockFindInROR).toBeCalledTimes(1) + expect(mockFindInROR).toBeCalledWith({ + 'searchFor': searchFor + }) + }) + + // has one option + const options = screen.getAllByRole('option') + expect(options.length).toEqual(1) + // that contains Add organisation option + expect(options[0].innerHTML).toContain(`Add "${searchFor}"`) + // screen.debug(options[0]) +}) + + +it('shows option found in ROR', async () => { + + const searchFor = 'Test organisation' + // return nothing found + mockFindInROR.mockResolvedValueOnce(mockAutocompleteOptions) + + render( + + ) + + const find = screen.getByRole('combobox', {name: 'Find or add organisation'}) + fireEvent.change(find, {target: {value: searchFor}}) + expect(find.value).toEqual(searchFor) + + await waitFor(() => { + expect(mockFindInROR).toBeCalledTimes(1) + expect(mockFindInROR).toBeCalledWith({ + 'searchFor': searchFor + }) + }) + + // has one option + const options = screen.getAllByRole('option') + expect(options.length).toEqual(2) + // that contains Add organisation option + expect(options[1].innerHTML).toContain(mockAutocompleteOptions[0].label) + // screen.debug(options) +}) diff --git a/frontend/components/admin/organisations/OrganisationItem.test.tsx b/frontend/components/admin/organisations/OrganisationItem.test.tsx new file mode 100644 index 000000000..2ab1cdf67 --- /dev/null +++ b/frontend/components/admin/organisations/OrganisationItem.test.tsx @@ -0,0 +1,112 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +import {fireEvent, render, screen} from '@testing-library/react' + +import OrganisationItem from './OrganisationItem' +import {OrganisationList} from '~/types/Organisation' + +const mockOrganisationItem = { + id:'test-organisation-id', + parent: null, + name: 'Test organisation', + short_description: null, + country: null, + website: 'https://organisation.org', + is_tenant: true, + rsd_path: 'test-organistion-path', + logo_id: null, + software_cnt: 0, + project_cnt: 0, + score: 0 +} as OrganisationList + +const mockOnDelete = jest.fn() + +beforeEach(() => { + jest.resetAllMocks() +}) + + +it('renders organisation item', () => { + render( + + ) + + // organisation name + screen.getByText(mockOrganisationItem.name) + // edit icon button + screen.getByTestId('EditIcon') + // delete icon button + screen.getByTestId('DeleteIcon') + // screen.debug() +}) + +it('can DELETE organisation with zero software and projects', () => { + // ensuren zero counts + mockOrganisationItem.software_cnt = 0 + mockOrganisationItem.project_cnt=0 + + render( + + ) + + // delete icon button + const deleteBtn = screen.getByRole('button',{name:'delete'}) + fireEvent.click(deleteBtn) + + // check calling + expect(mockOnDelete).toBeCalledTimes(1) + + // screen.debug(deleteBtn) +}) + +it('canNOT DELETE organisation with software or projects', () => { + // ensuren zero counts + mockOrganisationItem.software_cnt = 1 + mockOrganisationItem.project_cnt = 0 + + render( + + ) + + // delete icon button + const deleteBtn = screen.getByRole('button',{name:'delete'}) + expect(deleteBtn).toBeDisabled() + + // check calling + fireEvent.click(deleteBtn) + expect(mockOnDelete).toBeCalledTimes(0) + + // screen.debug(deleteBtn) +}) + +it('can EDIT organisation with software or projects', () => { + // ensuren zero counts + mockOrganisationItem.software_cnt = 1 + mockOrganisationItem.project_cnt = 0 + + const editLink=`http://localhost/organisations/${mockOrganisationItem.rsd_path}?page=settings` + + render( + + ) + + // edit link + const editBtn = screen.getByRole('link',{name:'edit'}) + expect(editBtn.href).toEqual(editLink) +}) diff --git a/frontend/components/admin/organisations/OrganisationsAdminList.test.tsx b/frontend/components/admin/organisations/OrganisationsAdminList.test.tsx new file mode 100644 index 000000000..1f4db9c83 --- /dev/null +++ b/frontend/components/admin/organisations/OrganisationsAdminList.test.tsx @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +import {render, screen} from '@testing-library/react' + +import OrganisationsAdminList from './OrganisationsAdminList' + +// MOCKS +import mockOrganisationList from '../../../__tests__/__mocks__/organisationsOverview.json' +const mockOnDelete = jest.fn() +const mockProps = { + loading: true, + organisations: mockOrganisationList as any, + onDeleteOrganisation: mockOnDelete +} + + +beforeEach(() => { + jest.resetAllMocks() +}) + +it('renders loader on loading', () => { + mockProps.loading = true + render( + + ) + + screen.getByRole('progressbar') + // screen.debug() +}) + + +it('renders list of organisations passed in props', () => { + mockProps.loading = false + + render( + + ) + + const items = screen.getAllByTestId('admin-organisation-item') + expect(items.length).toEqual(mockProps.organisations.length) + // screen.debug() +}) diff --git a/frontend/components/admin/organisations/OrganisationsAdminPage.test.tsx b/frontend/components/admin/organisations/OrganisationsAdminPage.test.tsx new file mode 100644 index 000000000..6ce7ac94e --- /dev/null +++ b/frontend/components/admin/organisations/OrganisationsAdminPage.test.tsx @@ -0,0 +1,67 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +import {render, screen} from '@testing-library/react' +import {WithAppContext, mockSession} from '~/utils/jest/WithAppContext' +import {Session} from '~/auth' + +import OrganisationsAdminPage from './index' + +// MOCKS +import mockOrganisationList from '../../../__tests__/__mocks__/organisationsOverview.json' +const mockUseOrganisation = jest.fn() +jest.mock('./apiOrganisation', () => ({ + useOrganisations:(token:string)=>mockUseOrganisation(token) +})) + +const testSession = { + ...mockSession, + user: { + ...mockSession.user, + role: 'rsd_admin' + } +} as Session + +const mockAddOrganisation = jest.fn() +const mockRemoveOrganisation = jest.fn() +const mockUseResponse = { + loading:true, + organisations:mockOrganisationList, + addOrganisation:mockAddOrganisation, + removeOrganisation:mockRemoveOrganisation +} + + +describe('components/admin/organisations/index.tsx', () => { + + it('shows progressbar initialy', () => { + mockUseResponse.loading=true + // mock hook response + mockUseOrganisation.mockReturnValueOnce(mockUseResponse) + + render( + + + + ) + screen.getByRole('progressbar') + // screen.debug() + }) + + it('shows list of organisations', () => { + mockUseResponse.loading=false + // mock hook response + mockUseOrganisation.mockReturnValueOnce(mockUseResponse) + + render( + + + + ) + + const items = screen.getAllByTestId('admin-organisation-item') + expect(items.length).toEqual(mockUseResponse.organisations.length) + }) +}) diff --git a/frontend/components/admin/organisations/index.tsx b/frontend/components/admin/organisations/index.tsx index 218d62469..e4aabe9b8 100644 --- a/frontend/components/admin/organisations/index.tsx +++ b/frontend/components/admin/organisations/index.tsx @@ -15,7 +15,7 @@ import OrganisationsAdminList from './OrganisationsAdminList' import AddOrganisation from './AddOrganisation' import {useOrganisations} from './apiOrganisation' -export default function OrganisationAdminPage() { +export default function OrganisationsAdminPage() { const {token} = useSession() const {pagination:{count}} = useContext(PaginationContext) const {organisations, loading, addOrganisation, removeOrganisation} = useOrganisations(token) diff --git a/frontend/components/admin/rsd-contributors/apiContributors.tsx b/frontend/components/admin/rsd-contributors/apiContributors.tsx index 5fb48ac0f..3063097ea 100644 --- a/frontend/components/admin/rsd-contributors/apiContributors.tsx +++ b/frontend/components/admin/rsd-contributors/apiContributors.tsx @@ -38,7 +38,7 @@ export function useContributors({token, orderBy}:useContributorsProps) { const {searchFor, page, rows, setCount} = usePaginationWithSearch('Find contributor') const [contributors, setContributors] = useState([]) const [loading, setLoading] = useState(true) - const [columns, setColumns] = useState(createColumns(token)) + const [columns] = useState(createColumns(token)) const loadContributors = useCallback(async () => { let abort = false diff --git a/frontend/components/cards/CardContentFrame.tsx b/frontend/components/cards/CardContentFrame.tsx index e4abbd0e0..81aa51823 100644 --- a/frontend/components/cards/CardContentFrame.tsx +++ b/frontend/components/cards/CardContentFrame.tsx @@ -3,9 +3,9 @@ // // SPDX-License-Identifier: Apache-2.0 -import React from 'react' +import {JSX} from 'react' -export default function CardContentFrame({children}:{children:React.JSX.Element[]}) { +export default function CardContentFrame({children}:{children:JSX.Element[]}) { return (
{children} diff --git a/frontend/components/cards/CardImageFrame.tsx b/frontend/components/cards/CardImageFrame.tsx index c2c0b793f..74ab569d4 100644 --- a/frontend/components/cards/CardImageFrame.tsx +++ b/frontend/components/cards/CardImageFrame.tsx @@ -3,9 +3,9 @@ // // SPDX-License-Identifier: Apache-2.0 -import React from 'react' +import {JSX} from 'react' -export default function CardImageFrame({children}:{children:React.JSX.Element}) { +export default function CardImageFrame({children}:{children:JSX.Element}) { return (
{children} diff --git a/frontend/components/filter/FilterOption.test.tsx b/frontend/components/filter/FilterOption.test.tsx new file mode 100644 index 000000000..910e3b6ea --- /dev/null +++ b/frontend/components/filter/FilterOption.test.tsx @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +import {render, screen} from '@testing-library/react' + +import FilterOption from './FilterOption' + +const mockProps = { + // props: document.createAttribute('aria-label'), + label: 'test label', + count: 20, + capitalize: false +} + +it('renders filter option label', () => { + + render( + + ) + + screen.getByText(mockProps.label) + // screen.debug() +}) + +it('renders filter option label capitalized', () => { + mockProps.capitalize = true + + render( + + ) + + const div = screen.getByText(mockProps.label) + expect(div).toHaveClass('capitalize') +}) diff --git a/frontend/components/form/ControlledTextField.tsx b/frontend/components/form/ControlledTextField.tsx index 4f9119c5a..9350cbc39 100644 --- a/frontend/components/form/ControlledTextField.tsx +++ b/frontend/components/form/ControlledTextField.tsx @@ -6,8 +6,7 @@ // // SPDX-License-Identifier: Apache-2.0 -import React from 'react' -import {useEffect, useRef} from 'react' +import {useEffect, useRef, JSX} from 'react' import {Controller} from 'react-hook-form' import TextField, {TextFieldProps} from '@mui/material/TextField' import HelperTextWithCounter from './HelperTextWithCounter' @@ -25,7 +24,7 @@ export type ControlledTextFieldOptions = { variant?: 'outlined'|'standard' useNull?: boolean, defaultValue?: string | number | null - helperTextMessage?: string | React.JSX.Element + helperTextMessage?: string | JSX.Element helperTextCnt?: string disabled?: boolean muiProps?: TextFieldProps diff --git a/frontend/components/form/HelperTextWithCounter.tsx b/frontend/components/form/HelperTextWithCounter.tsx index 3d0124f56..9e1567ab7 100644 --- a/frontend/components/form/HelperTextWithCounter.tsx +++ b/frontend/components/form/HelperTextWithCounter.tsx @@ -6,9 +6,9 @@ // // SPDX-License-Identifier: Apache-2.0 -import React from 'react' +import {JSX} from 'react' -export default function HelperTextWithCounter({message,count}:{message:string|undefined|React.JSX.Element,count:string}) { +export default function HelperTextWithCounter({message,count}:{message:string|undefined|JSX.Element,count:string}) { return ( <> {message} diff --git a/frontend/components/home/helmholtz/__mocks__/useOrganisations.tsx b/frontend/components/home/helmholtz/__mocks__/useOrganisations.tsx new file mode 100644 index 000000000..6c2f9ca55 --- /dev/null +++ b/frontend/components/home/helmholtz/__mocks__/useOrganisations.tsx @@ -0,0 +1,15 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +import mockOrganisations from '../../../../__tests__/__mocks__/organisationsOverview.json' + +// DEAFULT MOCK +export default function useOrganisations(token: string) { + // console.log('useOrganisations...default MOCK') + return { + loading:false, + organisations:mockOrganisations + } +} diff --git a/frontend/components/layout/ConfirmDeleteModal.tsx b/frontend/components/layout/ConfirmDeleteModal.tsx index 4f5a8dcef..81c134b0e 100644 --- a/frontend/components/layout/ConfirmDeleteModal.tsx +++ b/frontend/components/layout/ConfirmDeleteModal.tsx @@ -6,7 +6,7 @@ // // SPDX-License-Identifier: Apache-2.0 -import React from 'react' +import {JSX} from 'react' import Button from '@mui/material/Button' import Dialog from '@mui/material/Dialog' import DialogActions from '@mui/material/DialogActions' @@ -19,7 +19,7 @@ import WarningIcon from '@mui/icons-material/Warning' type ConfirmDeleteModalProps = { open: boolean, title: string, - body: React.JSX.Element, + body: JSX.Element, onCancel: () => void, onDelete: () => void } diff --git a/frontend/components/layout/ContentContainer.tsx b/frontend/components/layout/ContentContainer.tsx index 14e6a5e63..db059e23c 100644 --- a/frontend/components/layout/ContentContainer.tsx +++ b/frontend/components/layout/ContentContainer.tsx @@ -3,12 +3,12 @@ // // SPDX-License-Identifier: Apache-2.0 -import React from 'react' +import {JSX} from 'react' type ContentContainerProps = { element?: 'section' | 'article' | 'main' | 'div' className?: string - children: React.JSX.Element | React.JSX.Element[] + children: JSX.Element | JSX.Element[] } export default function ContentContainer(props: ContentContainerProps) { diff --git a/frontend/components/layout/SortableList.tsx b/frontend/components/layout/SortableList.tsx index 07268397c..2b6e1965c 100644 --- a/frontend/components/layout/SortableList.tsx +++ b/frontend/components/layout/SortableList.tsx @@ -5,7 +5,7 @@ // // SPDX-License-Identifier: Apache-2.0 -import React from 'react' +import {JSX} from 'react' import { DndContext, DragEndEvent, useSensor, useSensors, TouchSensor, MouseSensor @@ -23,7 +23,7 @@ export type RequiredListProps = { type SortableListProps={ items:T[], onSorted: (items: T[]) => void - onRenderItem:(item:T,index:number) => React.JSX.Element + onRenderItem:(item:T,index:number) => JSX.Element } export default function SortableList({ diff --git a/frontend/components/mention/ImportMentions/DoiInputBody.tsx b/frontend/components/mention/ImportMentions/DoiInputBody.tsx index f05d45da7..bbe9675e4 100644 --- a/frontend/components/mention/ImportMentions/DoiInputBody.tsx +++ b/frontend/components/mention/ImportMentions/DoiInputBody.tsx @@ -1,4 +1,6 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) // SPDX-FileCopyrightText: 2023 Dusan Mijatovic (dv4all) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center // SPDX-FileCopyrightText: 2023 dv4all // // SPDX-License-Identifier: Apache-2.0 @@ -12,8 +14,8 @@ import {useState} from 'react' import {DoiBulkImportReport, useValidateInputList} from './apiImportMentions' import {useSession} from '~/auth' import Box from '@mui/material/Box' -import BuilkDialogTitle from './ImportDialogTitle' -import BulkDialogActions from './ImportDialogActions' +import ImportDialogTitle from './ImportDialogTitle' +import ImportDialogActions from './ImportDialogActions' import config from './config' @@ -54,14 +56,16 @@ export default function DoiInputDialogBody({onCancel, onSubmit}: DoiInputDialogB return ( <> - - + - +
{error.message ? error.message : config.doiInput.helperText}...{`${error.count}/${config.doiInput.maxRows}`}
@@ -104,7 +108,7 @@ export default function DoiInputDialogBody({onCancel, onSubmit}: DoiInputDialogB Next
- + {validating && { + jest.resetAllMocks() +}) + + +describe('components/mention/ImportMentions/index.tsx', () => { + + it('validates provided doi list', async() => { + + render( + + + + ) + + // has import button + const importBtn = screen.getByRole('button',{name: 'Import'}) + + fireEvent.click(importBtn) + + // shows dialog + const importDialog = screen.getByRole('dialog',{name: 'Import publications'}) + + // has two buttons + const btns = within(importDialog).getAllByRole('button') + expect(btns.length).toBe(2) + + // Next button is disabled + expect(btns[1]).toBeDisabled() + + // input DOI's + const input = screen.getByRole('textbox') + fireEvent.change(input,{target:{value:mockDoiList.join('\n')}}) + + // check Next in enabled + expect(btns[1]).toBeEnabled() + + // click next + fireEvent.click(btns[1]) + + // shows Import button after succefol validation + await screen.findByRole('button',{name:'Import'}) + + // reports all doi items we provided + const reportItems = screen.getAllByTestId('import-mention-report-item') + expect(reportItems.length).toEqual(mockDoiList.length) + + // cancel button + const cancel = screen.getByRole('button', {name: 'Cancel'}) + fireEvent.click(cancel) + // validate dialog is removed + expect(importDialog).not.toBeInTheDocument() + // screen.debug() + }) + + it('imports provided doi list', async() => { + + render( + + + + + + ) + + // has import button + const importBtn = screen.getByRole('button',{name: 'Import'}) + + fireEvent.click(importBtn) + + // shows dialog + const importDialog = screen.getByRole('dialog',{name: 'Import publications'}) + + // has two buttons + const btns = within(importDialog).getAllByRole('button') + expect(btns.length).toBe(2) + + // Next button is disabled + expect(btns[1]).toBeDisabled() + + // input DOI's + const input = screen.getByRole('textbox') + fireEvent.change(input,{target:{value:mockDoiList.join('\n')}}) + + // check Next in enabled + expect(btns[1]).toBeEnabled() + + // click next + fireEvent.click(btns[1]) + + // shows Import button after succefol validation + await screen.findByRole('button',{name:'Import'}) + + // reports all doi items we provided + const reportItems = screen.getAllByTestId('import-mention-report-item') + expect(reportItems.length).toEqual(mockDoiList.length) + + // has select to import buttons + // const switches = screen.getAllByTestId('switch-toggle-button') + const switches = screen.getAllByRole('checkbox') + expect(switches.length).toEqual(switches.length) + + // deselect first item + fireEvent.click(switches[0]) + expect(switches[0]).not.toBeChecked() + + // Import button + const impBtn = screen.getByRole('button', {name: 'Import'}) + fireEvent.click(impBtn) + + await waitFor(() => { + // calls onSuccess fn + expect(mockProps.onSuccess).toBeCalledTimes(1) + // shows snackbar success message + screen.getByTestId('SuccessOutlinedIcon') + // screen.debug() + }) + }) +}) diff --git a/frontend/components/mention/ImportMentions/ImportReportBody.tsx b/frontend/components/mention/ImportMentions/ImportReportBody.tsx index f51ac16fa..27b2ef7ca 100644 --- a/frontend/components/mention/ImportMentions/ImportReportBody.tsx +++ b/frontend/components/mention/ImportMentions/ImportReportBody.tsx @@ -1,4 +1,6 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) // SPDX-FileCopyrightText: 2023 Dusan Mijatovic (dv4all) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center // SPDX-FileCopyrightText: 2023 dv4all // // SPDX-License-Identifier: Apache-2.0 @@ -105,9 +107,11 @@ export default function ImportReportBody({initialResults,onCancel,onImport}: Bul // console.log('key...', key) html.push( toggleSelection(index)} diff --git a/frontend/components/mention/ImportMentions/__mocks__/addMentions.json b/frontend/components/mention/ImportMentions/__mocks__/addMentions.json new file mode 100644 index 000000000..c748de7bc --- /dev/null +++ b/frontend/components/mention/ImportMentions/__mocks__/addMentions.json @@ -0,0 +1,62 @@ +[ + { + "id": "92d6a505-015b-46be-a810-7ba104c5cd3b", + "doi": "10.5270/esa-nzfsox4", + "doi_registration_date": null, + "url": "https://doi.org/10.5270%2Fesa-nzfsox4", + "title": "MARS", + "authors": "undefined undefined", + "publisher": "European Space Agency", + "publication_year": null, + "journal": "MARS", + "page": null, + "image_url": null, + "mention_type": "dataset", + "source": "Crossref", + "version": null, + "note": null, + "scraped_at": null, + "created_at": "2023-08-25T08:08:11.363529+00:00", + "updated_at": "2023-08-25T08:08:11.363529+00:00" + }, + { + "id": "7de99048-300c-4cbd-9198-1dceb4b32b90", + "doi": "10.23943/princeton/9780691209258.003.0001", + "doi_registration_date": null, + "url": "https://doi.org/10.23943%2Fprinceton%2F9780691209258.003.0001", + "title": "Why Mars Matters", + "authors": "David A. Weintraub", + "publisher": "Princeton University Press", + "publication_year": 2020, + "journal": "Life on Mars", + "page": "1-11", + "image_url": null, + "mention_type": "bookSection", + "source": "Crossref", + "version": null, + "note": null, + "scraped_at": null, + "created_at": "2023-08-25T08:08:11.363529+00:00", + "updated_at": "2023-08-25T08:08:11.363529+00:00" + }, + { + "id": "7baa5d95-1ae0-491f-afb4-8a333542226d", + "doi": "10.1555/mars.2006.0005", + "doi_registration_date": null, + "url": "https://doi.org/10.1555%2Fmars.2006.0005", + "title": "Mars life support systems", + "authors": "Donald Rapp", + "publisher": "Mars Informatics", + "publication_year": 2006, + "journal": "The Mars Journal", + "page": "72-82", + "image_url": null, + "mention_type": "journalArticle", + "source": "Crossref", + "version": null, + "note": null, + "scraped_at": null, + "created_at": "2023-08-25T08:08:11.363529+00:00", + "updated_at": "2023-08-25T08:08:11.363529+00:00" + } +] \ No newline at end of file diff --git a/frontend/components/mention/ImportMentions/__mocks__/addMentions.json.license b/frontend/components/mention/ImportMentions/__mocks__/addMentions.json.license new file mode 100644 index 000000000..546d6c9eb --- /dev/null +++ b/frontend/components/mention/ImportMentions/__mocks__/addMentions.json.license @@ -0,0 +1,4 @@ +SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +SPDX-FileCopyrightText: 2023 Netherlands eScience Center + +SPDX-License-Identifier: Apache-2.0 diff --git a/frontend/components/mention/ImportMentions/__mocks__/apiImportMentions.tsx b/frontend/components/mention/ImportMentions/__mocks__/apiImportMentions.tsx new file mode 100644 index 000000000..8a5e541c5 --- /dev/null +++ b/frontend/components/mention/ImportMentions/__mocks__/apiImportMentions.tsx @@ -0,0 +1,61 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +import {MentionItemProps} from '~/types/Mention' + +// MOCKED responses + +import mockMentionResponse from './addMentions.json' + +async function mockValidateInput(value: string){ + const doiList = value.split(/\r\n|\n|\r/) + const results = new Map() + + // Just return all values as VALID + doiList.forEach((doi,index) => { + results.set(doi.toLocaleLowerCase(), { + doi: doi.toLocaleLowerCase(), + status: 'valid', + include: true, + source: 'Crossref', + mention: { + id: null, + doi, + title: `Test item ${doi}` + } + }) + }) + + // console.log('mockValidateInput...results...', results) + return results +} + +export function useValidateInputList(token: string) { + // console.log('useValidateInputList...default MOCK...token...', token) + return { + validateInput: mockValidateInput, + validating: false + } +} + + +export async function linkMentionToEntity({ids, table, entityName, entityId, token}: { + ids: string[], table: string, entityName: string, entityId: string, token: string +}) { + // console.log('linkMentionToEntity...default MOCK...ids...', ids) + return { + status: 200, + message: 'OK' + } +} + + +export async function addMentions({mentions, token}: { mentions: MentionItemProps[], token: string }) { + // console.log('addMentions...default MOCK...mentions...', mentions) + return { + status: 200, + message: mockMentionResponse + } +} diff --git a/frontend/components/mention/ImportMentions/index.tsx b/frontend/components/mention/ImportMentions/index.tsx index d74e84153..590f25bb9 100644 --- a/frontend/components/mention/ImportMentions/index.tsx +++ b/frontend/components/mention/ImportMentions/index.tsx @@ -1,3 +1,4 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) // SPDX-FileCopyrightText: 2023 Dusan Mijatovic (dv4all) // SPDX-FileCopyrightText: 2023 Ewan Cahen (Netherlands eScience Center) // SPDX-FileCopyrightText: 2023 Netherlands eScience Center @@ -34,7 +35,7 @@ type ImportMentionsProps = { onSuccess:()=>void } -export default function BulkImport({table, entityId, onSuccess}:ImportMentionsProps) { +export default function ImportMentions({table, entityId, onSuccess}:ImportMentionsProps) { const {token} = useSession() const {showErrorMessage,showSuccessMessage} = useSnackbar() const smallScreen = useMediaQuery('(max-width:768px)') @@ -98,6 +99,7 @@ export default function BulkImport({table, entityId, onSuccess}:ImportMentionsPr entityId, token }) + if (resp.status === 200) { showSuccessMessage(`Succesfully added ${mentionIdsToSave.length} items`) onSuccess() @@ -116,36 +118,39 @@ export default function BulkImport({table, entityId, onSuccess}:ImportMentionsPr > Import - + {searchResults !== null ? + + : + setSearchResults(report)} + /> } - }} - > - {searchResults !== null ? - - : - setSearchResults(report) } - /> - } - + + : null + } ) } diff --git a/frontend/components/mention/editMentionContext.tsx b/frontend/components/mention/editMentionContext.tsx index a76708668..86872e62b 100644 --- a/frontend/components/mention/editMentionContext.tsx +++ b/frontend/components/mention/editMentionContext.tsx @@ -6,8 +6,7 @@ // // SPDX-License-Identifier: Apache-2.0 -import React from 'react' -import {createContext} from 'react' +import {createContext,JSX} from 'react' import {MentionItemProps} from '~/types/Mention' import {EditMentionAction, EditMentionState} from './editMentionReducer' import NoMentionItems from './NoMentionItems' @@ -15,7 +14,7 @@ import NoMentionItems from './NoMentionItems' export type EditMentionSettings = { editModalTitle: string, confirmDeleteModalTitle: string, - noItemsComponent:()=>React.JSX.Element + noItemsComponent:()=>JSX.Element } export type EditModalProps = { diff --git a/frontend/components/menu/IconBtnMenuOnAction.tsx b/frontend/components/menu/IconBtnMenuOnAction.tsx index 3247335c5..c5ed729cc 100644 --- a/frontend/components/menu/IconBtnMenuOnAction.tsx +++ b/frontend/components/menu/IconBtnMenuOnAction.tsx @@ -5,7 +5,7 @@ // // SPDX-License-Identifier: Apache-2.0 -import {useState} from 'react' +import {useState, JSX} from 'react' import IconButton from '@mui/material/IconButton' import MoreVertIcon from '@mui/icons-material/MoreVert' import Menu from '@mui/material/Menu' @@ -16,7 +16,7 @@ export type IconBtnMenuOption = { type: 'divider' | 'action' key: string, label: string, - icon?: React.JSX.Element, + icon?: JSX.Element, action: T disabled?: boolean, } diff --git a/frontend/components/organisation/apiOrganisations.ts b/frontend/components/organisation/apiOrganisations.ts index 110923aa1..15038770f 100644 --- a/frontend/components/organisation/apiOrganisations.ts +++ b/frontend/components/organisation/apiOrganisations.ts @@ -7,7 +7,7 @@ // SPDX-License-Identifier: Apache-2.0 import {RsdUser} from '~/auth' -import {isOrganisationMaintainer} from '~/auth/permissions/useOrganisationMaintainer' +import {isOrganisationMaintainer} from '~/auth/permissions/isMaintainerOfOrganisation' import { Organisation, OrganisationForOverview, OrganisationList, ProjectOfOrganisation, @@ -86,7 +86,8 @@ export async function getOrganisationBySlug({slug,user,token}: // is this user maintainer of this organisation const isMaintainer = await isOrganisationMaintainer({ organisation: uuid, - user, + account: user?.account, + role: user?.role, token }) // console.log('getOrganisationBySlug...isMaintainer...', isMaintainer) diff --git a/frontend/components/organisation/metadata/Links.tsx b/frontend/components/organisation/metadata/Links.tsx index a654eb476..d9e4a35dc 100644 --- a/frontend/components/organisation/metadata/Links.tsx +++ b/frontend/components/organisation/metadata/Links.tsx @@ -5,13 +5,13 @@ // // SPDX-License-Identifier: Apache-2.0 -import React from 'react' +import {JSX} from 'react' import Link from 'next/link' export type LinksProps = { title: string, url: string - icon: React.JSX.Element, + icon: JSX.Element, } export default function Links({links=[]}:{links:LinksProps[]}) { diff --git a/frontend/components/organisation/overview/useOrganisationOverviewParams.test.tsx b/frontend/components/organisation/overview/useOrganisationOverviewParams.test.tsx new file mode 100644 index 000000000..6d53988f5 --- /dev/null +++ b/frontend/components/organisation/overview/useOrganisationOverviewParams.test.tsx @@ -0,0 +1,76 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +import useOrganisationOverviewParams from './useOrganisationOverviewParams' + +// mock next router +const mockBack = jest.fn() +const mockReplace = jest.fn() +const mockPush = jest.fn() + +jest.mock('next/router', () => ({ + useRouter: () => ({ + back: mockBack, + replace: mockReplace, + push: mockPush, + pathname: '/organisations', + query: { + rows: 12, + page: 1, + } + }) +})) + + +beforeEach(() => { + jest.resetAllMocks() +}) + +it('handlesQueryChange with search param', () => { + // extract function + const {handleQueryChange} = useOrganisationOverviewParams() + + // call it with random param + handleQueryChange('search', 'test-value') + + expect(mockPush).toBeCalledTimes(1) + expect(mockPush).toBeCalledWith( + '/organisations?search=test-value&page=1&rows=12', + '/organisations?search=test-value&page=1&rows=12', + {'scroll': false} + ) +}) + +it('handlesQueryChange for pagination', () => { + // extract function + const {handleQueryChange} = useOrganisationOverviewParams() + + // call it with random param + handleQueryChange('page', '2') + + + expect(mockPush).toBeCalledTimes(1) + expect(mockPush).toBeCalledWith( + '/organisations?page=2&rows=12', + '/organisations?page=2&rows=12', + {'scroll': true} + ) +}) + + +it('resetFilters calls push without any params', () => { + // extract function + const {resetFilters} = useOrganisationOverviewParams() + + // call it with random param + resetFilters() + + expect(mockPush).toBeCalledTimes(1) + expect(mockPush).toBeCalledWith( + '/organisations', + '/organisations', + {'scroll': false} + ) +}) diff --git a/frontend/components/organisation/overview/useOrganisationOverviewParams.ts b/frontend/components/organisation/overview/useOrganisationOverviewParams.tsx similarity index 100% rename from frontend/components/organisation/overview/useOrganisationOverviewParams.ts rename to frontend/components/organisation/overview/useOrganisationOverviewParams.tsx diff --git a/frontend/components/organisation/projects/OrganisationProjectsIndex.test.tsx b/frontend/components/organisation/projects/OrganisationProjectsIndex.test.tsx index 80d270435..bfe8ee3d1 100644 --- a/frontend/components/organisation/projects/OrganisationProjectsIndex.test.tsx +++ b/frontend/components/organisation/projects/OrganisationProjectsIndex.test.tsx @@ -22,11 +22,6 @@ const mockProps = { } // MOCK getProjectsForOrganisation -// const mockProjectsForOrganisation = jest.fn((props) => Promise.resolve({ -// status: 206, -// count: 0, -// data: [] -// })) const mockUseOrganisationProjects = jest.fn((props) => ({ loading: false, count: 0, @@ -46,6 +41,12 @@ jest.mock('~/utils/editProject', () => ({ patchProjectForOrganisation: jest.fn((props)=>mockPatchProjectForOrganisation(props)) })) +// MOCK project filters - use default mocks +jest.mock('~/components/organisation/projects/filters/useOrgProjectDomainsList') +jest.mock('~/components/organisation/projects/filters/useOrgProjectKeywordsList') +jest.mock('~/components/organisation/projects/filters/useOrgProjectOrganisationsList') +jest.mock('~/components/organisation/projects/filters/useOrgProjectStatusList') + describe('frontend/components/organisation/projects/index.tsx', () => { beforeEach(() => { diff --git a/frontend/components/organisation/projects/filters/__mocks__/mockProjectDomainsList.json b/frontend/components/organisation/projects/filters/__mocks__/mockProjectDomainsList.json new file mode 100644 index 000000000..a4f65bf6d --- /dev/null +++ b/frontend/components/organisation/projects/filters/__mocks__/mockProjectDomainsList.json @@ -0,0 +1,47 @@ +[ + { + "key": "LS7_15", + "domain": "LS7_15", + "domain_cnt": 1 + }, + { + "key": "LS8_4", + "domain": "LS8_4", + "domain_cnt": 1 + }, + { + "key": "LS9_2", + "domain": "LS9_2", + "domain_cnt": 1 + }, + { + "key": "LS9_5", + "domain": "LS9_5", + "domain_cnt": 1 + }, + { + "key": "PE1_13", + "domain": "PE1_13", + "domain_cnt": 1 + }, + { + "key": "PE9_2", + "domain": "PE9_2", + "domain_cnt": 1 + }, + { + "key": "SH1_14", + "domain": "SH1_14", + "domain_cnt": 1 + }, + { + "key": "SH3", + "domain": "SH3", + "domain_cnt": 1 + }, + { + "key": "SH6_8", + "domain": "SH6_8", + "domain_cnt": 1 + } +] \ No newline at end of file diff --git a/frontend/components/organisation/projects/filters/__mocks__/mockProjectDomainsList.json.license b/frontend/components/organisation/projects/filters/__mocks__/mockProjectDomainsList.json.license new file mode 100644 index 000000000..546d6c9eb --- /dev/null +++ b/frontend/components/organisation/projects/filters/__mocks__/mockProjectDomainsList.json.license @@ -0,0 +1,4 @@ +SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +SPDX-FileCopyrightText: 2023 Netherlands eScience Center + +SPDX-License-Identifier: Apache-2.0 diff --git a/frontend/components/organisation/projects/filters/__mocks__/org_project_keywords_filter.json b/frontend/components/organisation/projects/filters/__mocks__/org_project_keywords_filter.json new file mode 100644 index 000000000..bf450694f --- /dev/null +++ b/frontend/components/organisation/projects/filters/__mocks__/org_project_keywords_filter.json @@ -0,0 +1,42 @@ +[ + { + "keyword": "Big data", + "keyword_cnt": 1 + }, + { + "keyword": "GPU", + "keyword_cnt": 2 + }, + { + "keyword": "High performance computing", + "keyword_cnt": 1 + }, + { + "keyword": "Image processing", + "keyword_cnt": 1 + }, + { + "keyword": "Inter-operability & linked data", + "keyword_cnt": 1 + }, + { + "keyword": "Multi-scale & multi model simulations", + "keyword_cnt": 1 + }, + { + "keyword": "Optimized data handling", + "keyword_cnt": 1 + }, + { + "keyword": "Text analysis & natural language processing", + "keyword_cnt": 2 + }, + { + "keyword": "Visualization", + "keyword_cnt": 2 + }, + { + "keyword": "Workflow technologies", + "keyword_cnt": 2 + } +] \ No newline at end of file diff --git a/frontend/components/organisation/projects/filters/__mocks__/org_project_keywords_filter.json.license b/frontend/components/organisation/projects/filters/__mocks__/org_project_keywords_filter.json.license new file mode 100644 index 000000000..546d6c9eb --- /dev/null +++ b/frontend/components/organisation/projects/filters/__mocks__/org_project_keywords_filter.json.license @@ -0,0 +1,4 @@ +SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +SPDX-FileCopyrightText: 2023 Netherlands eScience Center + +SPDX-License-Identifier: Apache-2.0 diff --git a/frontend/components/organisation/projects/filters/__mocks__/org_project_participating_organisations_filter.json b/frontend/components/organisation/projects/filters/__mocks__/org_project_participating_organisations_filter.json new file mode 100644 index 000000000..795ee270e --- /dev/null +++ b/frontend/components/organisation/projects/filters/__mocks__/org_project_participating_organisations_filter.json @@ -0,0 +1,106 @@ +[ + { + "organisation": "Organisation: and Handcrafted Freeway et", + "organisation_cnt": 1 + }, + { + "organisation": "Organisation: auxiliary Southeast South", + "organisation_cnt": 1 + }, + { + "organisation": "Organisation: Bicycle Gasoline", + "organisation_cnt": 1 + }, + { + "organisation": "Organisation: Concrete", + "organisation_cnt": 1 + }, + { + "organisation": "Organisation: connect under Tungsten impolite", + "organisation_cnt": 1 + }, + { + "organisation": "Organisation: Ergonomic Representative", + "organisation_cnt": 1 + }, + { + "organisation": "Organisation: foodstuffs duh Electronic Designer", + "organisation_cnt": 1 + }, + { + "organisation": "Organisation: Games Indio", + "organisation_cnt": 1 + }, + { + "organisation": "Organisation: Internal Louisiana Metal", + "organisation_cnt": 1 + }, + { + "organisation": "Organisation: intuitive 1080p leverage", + "organisation_cnt": 3 + }, + { + "organisation": "Organisation: Inverse", + "organisation_cnt": 1 + }, + { + "organisation": "Organisation: invoice Southeast", + "organisation_cnt": 1 + }, + { + "organisation": "Organisation: Legacy", + "organisation_cnt": 1 + }, + { + "organisation": "Organisation: lumen along Saint Intranet", + "organisation_cnt": 1 + }, + { + "organisation": "Organisation: mostly", + "organisation_cnt": 1 + }, + { + "organisation": "Organisation: networks silver", + "organisation_cnt": 1 + }, + { + "organisation": "Organisation: newton", + "organisation_cnt": 1 + }, + { + "organisation": "Organisation: North tesla", + "organisation_cnt": 1 + }, + { + "organisation": "Organisation: Northwest Ergonomic through", + "organisation_cnt": 1 + }, + { + "organisation": "Organisation: Northwest Manors circuit proactive", + "organisation_cnt": 1 + }, + { + "organisation": "Organisation: onto Analyst Volkswagen urban", + "organisation_cnt": 1 + }, + { + "organisation": "Organisation: plum", + "organisation_cnt": 1 + }, + { + "organisation": "Organisation: Raleigh since Southwest Mews", + "organisation_cnt": 2 + }, + { + "organisation": "Organisation: SUV", + "organisation_cnt": 1 + }, + { + "organisation": "Organisation: woman Unbranded midst upliftingly phooey silver Gorgeous excepting invoice OCR calculating bandwidth repudiandae punt purple Berkshire which South grey Senior", + "organisation_cnt": 1 + }, + { + "organisation": "Organisation: yellow", + "organisation_cnt": 1 + } +] \ No newline at end of file diff --git a/frontend/components/organisation/projects/filters/__mocks__/org_project_participating_organisations_filter.json.license b/frontend/components/organisation/projects/filters/__mocks__/org_project_participating_organisations_filter.json.license new file mode 100644 index 000000000..546d6c9eb --- /dev/null +++ b/frontend/components/organisation/projects/filters/__mocks__/org_project_participating_organisations_filter.json.license @@ -0,0 +1,4 @@ +SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +SPDX-FileCopyrightText: 2023 Netherlands eScience Center + +SPDX-License-Identifier: Apache-2.0 diff --git a/frontend/components/organisation/projects/filters/__mocks__/org_project_status_filter.json b/frontend/components/organisation/projects/filters/__mocks__/org_project_status_filter.json new file mode 100644 index 000000000..e38dbd74e --- /dev/null +++ b/frontend/components/organisation/projects/filters/__mocks__/org_project_status_filter.json @@ -0,0 +1,18 @@ +[ + { + "project_status": "finished", + "project_status_cnt": 5 + }, + { + "project_status": "in_progress", + "project_status_cnt": 3 + }, + { + "project_status": "pending", + "project_status_cnt": 3 + }, + { + "project_status": "unknown", + "project_status_cnt": 1 + } +] \ No newline at end of file diff --git a/frontend/components/organisation/projects/filters/__mocks__/org_project_status_filter.json.license b/frontend/components/organisation/projects/filters/__mocks__/org_project_status_filter.json.license new file mode 100644 index 000000000..546d6c9eb --- /dev/null +++ b/frontend/components/organisation/projects/filters/__mocks__/org_project_status_filter.json.license @@ -0,0 +1,4 @@ +SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +SPDX-FileCopyrightText: 2023 Netherlands eScience Center + +SPDX-License-Identifier: Apache-2.0 diff --git a/frontend/components/organisation/projects/filters/__mocks__/useOrgProjectDomainsList.tsx b/frontend/components/organisation/projects/filters/__mocks__/useOrgProjectDomainsList.tsx new file mode 100644 index 000000000..6853c2084 --- /dev/null +++ b/frontend/components/organisation/projects/filters/__mocks__/useOrgProjectDomainsList.tsx @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +import mockDomainsList from './mockProjectDomainsList.json' + +export default function useOrgProjectDomainsFilter() { + // console.log('useOrgProjectDomainsFilter...default mock') + return { + domainsList: mockDomainsList + } + +} diff --git a/frontend/components/organisation/projects/filters/__mocks__/useOrgProjectKeywordsList.tsx b/frontend/components/organisation/projects/filters/__mocks__/useOrgProjectKeywordsList.tsx new file mode 100644 index 000000000..8b581a1b7 --- /dev/null +++ b/frontend/components/organisation/projects/filters/__mocks__/useOrgProjectKeywordsList.tsx @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +import mockKeywordsList from './org_project_keywords_filter.json' + +export default function useOrgProjectKeywordsList() { + // console.log('useOrgProjectKeywordsList...default mock') + return { + keywordsList:mockKeywordsList + } +} diff --git a/frontend/components/organisation/projects/filters/__mocks__/useOrgProjectOrganisationsList.tsx b/frontend/components/organisation/projects/filters/__mocks__/useOrgProjectOrganisationsList.tsx new file mode 100644 index 000000000..f3352fe9e --- /dev/null +++ b/frontend/components/organisation/projects/filters/__mocks__/useOrgProjectOrganisationsList.tsx @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +import mockOrganisationList from './org_project_participating_organisations_filter.json' + +export default function useOrgProjectOrganisationList() { + // console.log('useOrgProjectOrganisationList...default mock') + return { + organisationList: mockOrganisationList + } +} diff --git a/frontend/components/organisation/projects/filters/__mocks__/useOrgProjectStatusList.tsx b/frontend/components/organisation/projects/filters/__mocks__/useOrgProjectStatusList.tsx new file mode 100644 index 000000000..2410e37e6 --- /dev/null +++ b/frontend/components/organisation/projects/filters/__mocks__/useOrgProjectStatusList.tsx @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +import mockStatusList from './org_project_status_filter.json' + +export default function useOrgProjectStatusList() { + // console.log('useOrgProjectStatusList...default mock') + return { + statusList: mockStatusList + } +} diff --git a/frontend/components/organisation/projects/useQueryChange.test.tsx b/frontend/components/organisation/projects/useQueryChange.test.tsx new file mode 100644 index 000000000..d66dac18a --- /dev/null +++ b/frontend/components/organisation/projects/useQueryChange.test.tsx @@ -0,0 +1,98 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +import {useEffect} from 'react' +import {render} from '@testing-library/react' +import useQueryChange from './useQueryChange' +import {TabKey} from '../tabs/OrganisationTabItems' + +// mock next router +const mockBack = jest.fn() +const mockReplace = jest.fn() +const mockPush = jest.fn() + +jest.mock('next/router', () => ({ + useRouter: () => ({ + back: mockBack, + replace: mockReplace, + push: mockPush, + pathname: '/organisations', + query: { + slug:'test-slug-project', + rows: 12, + page: 1, + } + }) +})) + +beforeEach(() => { + jest.resetAllMocks() +}) + +function WrappedHandleChangeHook({param,value}:{param: string, value: string | string[]}) { + // extract function + const {handleQueryChange} = useQueryChange() + + useEffect(() => { + // call it with random param + handleQueryChange(param, value) + },[param,value,handleQueryChange]) + + return ( +
WrappedHandleChangeHook
+ ) +} + +function WrappedResetFilterHook({tab}:{tab:TabKey}) { + // extract function + const {resetFilters} = useQueryChange() + + useEffect(() => { + // call it with random param + resetFilters(tab) + },[tab,resetFilters]) + + return ( +
WrappedResetFiltersHook
+ ) +} + + +it('handlesQueryChange with search param', () => { + + render() + + expect(mockPush).toBeCalledTimes(1) + expect(mockPush).toBeCalledWith( + {'query': {'page': 1, 'rows': 12, 'slug': 'test-slug-project','search': 'test-value'}}, + undefined, + {'scroll': false} + ) +}) + +it('handlesQueryChange pagination', () => { + + render() + + expect(mockPush).toBeCalledTimes(1) + expect(mockPush).toBeCalledWith( + {'query': {'page': '2', 'rows': 12, 'slug': 'test-slug-project'}}, + undefined, + {'scroll': true} + ) +}) + +it('resetFilters pagination', () => { + + render() + + expect(mockPush).toBeCalledTimes(1) + expect(mockPush).toBeCalledWith( + {'query': {'slug': 'test-slug-project', 'tab': 'projects'}}, + undefined, + {'scroll': false} + ) +}) + diff --git a/frontend/components/organisation/releases/OrganisationReleasesIndex.test.tsx b/frontend/components/organisation/releases/OrganisationReleasesIndex.test.tsx new file mode 100644 index 000000000..031cfbb2d --- /dev/null +++ b/frontend/components/organisation/releases/OrganisationReleasesIndex.test.tsx @@ -0,0 +1,69 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +import {render, screen, waitForElementToBeRemoved} from '@testing-library/react' +import {WithAppContext, mockSession} from '~/utils/jest/WithAppContext' +import {WithOrganisationContext} from '~/utils/jest/WithOrganisationContext' + +import OrganisationSoftwareReleases from './index' +import {Session} from '~/auth' + +// MOCKS +import mockOrganisation from '~/components/organisation/__mocks__/mockOrganisation' +import mockReleaseCount from './__mocks__/release_cnt_by_year.json' +import mockReleases from './__mocks__/releases_by_organisation.json' + +const testSession = { + ...mockSession, + user: { + ...mockSession.user, + role: 'rsd_user' + } +} as Session + +const mockProps = { + organisation: mockOrganisation, + isMaintainer: false +} + +// mock api - default mock +jest.mock('~/components/organisation/releases/apiOrganisationReleases') + +describe('components/organisation/releases/index.tsx', () => { + + it('shows loader', () => { + render( + + + + + + ) + + screen.getByRole('progressbar') + }) + + it('shows releases page', async() => { + render( + + + + + + ) + + await waitForElementToBeRemoved(screen.getByRole('progressbar')) + + // buttons + const years = screen.getAllByRole('button') + expect(years.length).toEqual(mockReleaseCount.length) + + // find release items + const releases = await screen.findAllByTestId('release-item') + // validate all items are shown + expect(releases.length).toEqual(mockReleases.length) + }) + +}) diff --git a/frontend/components/organisation/releases/ReleaseItem.tsx b/frontend/components/organisation/releases/ReleaseItem.tsx index 2f8aac5cd..81d82a4d0 100644 --- a/frontend/components/organisation/releases/ReleaseItem.tsx +++ b/frontend/components/organisation/releases/ReleaseItem.tsx @@ -9,7 +9,7 @@ import Chip from '@mui/material/Chip' import OpenInNewIcon from '@mui/icons-material/OpenInNew' import Link from 'next/link' -import {SoftwareReleaseInfo} from './useSoftwareReleases' +import {SoftwareReleaseInfo} from './apiOrganisationReleases' function LinkToVersionDoi({tag,doi}:{tag: string | null,doi:string|null}) { @@ -66,7 +66,10 @@ function LinkToVersionDoi({tag,doi}:{tag: string | null,doi:string|null}) { export default function ReleaseItem({release}: { release: SoftwareReleaseInfo }) { const releaseDate = new Date(release.release_date) return ( -
+
{/* release date */}
diff --git a/frontend/components/organisation/releases/__mocks__/apiOrganisationReleases.ts b/frontend/components/organisation/releases/__mocks__/apiOrganisationReleases.ts new file mode 100644 index 000000000..0036eaf16 --- /dev/null +++ b/frontend/components/organisation/releases/__mocks__/apiOrganisationReleases.ts @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +import {UseSoftwareReleaseProps} from '../useSoftwareReleases' + +import mockReleasesForOrganisation from './releases_by_organisation.json' +import mockReleaseCntByYear from './release_cnt_by_year.json' + +export type SoftwareReleaseInfo = { + software_id: string + software_slug: string + software_name: string + release_doi: string + release_tag: string | null + release_date: string + release_year: number + release_authors: string +} + +export type ReleaseCountByYear = { + release_year: number + release_cnt: number +} + + +export async function getReleasesForOrganisation({organisation_id, release_year, token}: UseSoftwareReleaseProps) { + // console.log('getReleasesForOrganisation...default MOCK') + return mockReleasesForOrganisation +} + +export async function getReleasesCountForOrganisation({organisation_id, token}: UseSoftwareReleaseProps) { + // console.log('getReleasesCountForOrganisation...default MOCK') + return mockReleaseCntByYear +} diff --git a/frontend/components/organisation/releases/__mocks__/release_cnt_by_year.json b/frontend/components/organisation/releases/__mocks__/release_cnt_by_year.json new file mode 100644 index 000000000..5b48aafb8 --- /dev/null +++ b/frontend/components/organisation/releases/__mocks__/release_cnt_by_year.json @@ -0,0 +1,102 @@ +[ + { + "release_year": 2025, + "release_cnt": 7 + }, + { + "release_year": 2024, + "release_cnt": 1 + }, + { + "release_year": 2023, + "release_cnt": 11 + }, + { + "release_year": 2022, + "release_cnt": 29 + }, + { + "release_year": 2021, + "release_cnt": 35 + }, + { + "release_year": 2020, + "release_cnt": 18 + }, + { + "release_year": 2019, + "release_cnt": 24 + }, + { + "release_year": 2018, + "release_cnt": 16 + }, + { + "release_year": 2017, + "release_cnt": 16 + }, + { + "release_year": 2016, + "release_cnt": 15 + }, + { + "release_year": 2015, + "release_cnt": 29 + }, + { + "release_year": 2014, + "release_cnt": 8 + }, + { + "release_year": 2013, + "release_cnt": 18 + }, + { + "release_year": 2012, + "release_cnt": 5 + }, + { + "release_year": 2011, + "release_cnt": 13 + }, + { + "release_year": 2010, + "release_cnt": 6 + }, + { + "release_year": 2009, + "release_cnt": 3 + }, + { + "release_year": 2007, + "release_cnt": 8 + }, + { + "release_year": 2006, + "release_cnt": 9 + }, + { + "release_year": 2005, + "release_cnt": 5 + }, + { + "release_year": 2004, + "release_cnt": 19 + }, + { + "release_year": 2003, + "release_cnt": 19 + }, + { + "release_year": 2002, + "release_cnt": 4 + }, + { + "release_year": 2001, + "release_cnt": 26 + }, + { + "release_year": 2000, + "release_cnt": 11 + } +] \ No newline at end of file diff --git a/frontend/components/organisation/releases/__mocks__/release_cnt_by_year.json.license b/frontend/components/organisation/releases/__mocks__/release_cnt_by_year.json.license new file mode 100644 index 000000000..546d6c9eb --- /dev/null +++ b/frontend/components/organisation/releases/__mocks__/release_cnt_by_year.json.license @@ -0,0 +1,4 @@ +SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +SPDX-FileCopyrightText: 2023 Netherlands eScience Center + +SPDX-License-Identifier: Apache-2.0 diff --git a/frontend/components/organisation/releases/__mocks__/releases_by_organisation.json b/frontend/components/organisation/releases/__mocks__/releases_by_organisation.json new file mode 100644 index 000000000..0a84e2486 --- /dev/null +++ b/frontend/components/organisation/releases/__mocks__/releases_by_organisation.json @@ -0,0 +1,79 @@ +[ + { + "organisation_id": "0c544eda-0885-4f94-9795-42b22baf7053", + "software_id": "02a39f97-3a27-4ef4-9eec-85caf1579d2b", + "software_slug": "software-northwest-sex-chris-withdrawal", + "software_name": "Software: Northwest sex Chris withdrawal", + "release_doi": null, + "release_tag": "9.6.3", + "release_date": null, + "release_year": 2025, + "release_authors": "Teresa Schumm" + }, + { + "organisation_id": "0c544eda-0885-4f94-9795-42b22baf7053", + "software_id": "02a39f97-3a27-4ef4-9eec-85caf1579d2b", + "software_slug": "software-northwest-sex-chris-withdrawal", + "software_name": "Software: Northwest sex Chris withdrawal", + "release_doi": null, + "release_tag": null, + "release_date": null, + "release_year": 2025, + "release_authors": null + }, + { + "organisation_id": "0c544eda-0885-4f94-9795-42b22baf7053", + "software_id": "0ebaba3e-5dbc-4e29-9c26-2b4e184feead", + "software_slug": "software-engineer-gibraltar-web-green", + "software_name": "Software: engineer Gibraltar Web green", + "release_doi": null, + "release_tag": "9.6.3", + "release_date": null, + "release_year": 2025, + "release_authors": "Teresa Schumm" + }, + { + "organisation_id": "0c544eda-0885-4f94-9795-42b22baf7053", + "software_id": "39209170-68d4-4d4a-bca1-09556ec41a3d", + "software_slug": "software-country", + "software_name": "Software: Country", + "release_doi": null, + "release_tag": "6.3.4", + "release_date": null, + "release_year": 2025, + "release_authors": "Miss Edna Lueilwitz" + }, + { + "organisation_id": "0c544eda-0885-4f94-9795-42b22baf7053", + "software_id": "39209170-68d4-4d4a-bca1-09556ec41a3d", + "software_slug": "software-country", + "software_name": "Software: Country", + "release_doi": null, + "release_tag": null, + "release_date": null, + "release_year": 2025, + "release_authors": null + }, + { + "organisation_id": "0c544eda-0885-4f94-9795-42b22baf7053", + "software_id": "ac38caf6-fa32-4201-a634-889a5da5479e", + "software_slug": "software-newton-nod-gee", + "software_name": "Software: newton nod gee", + "release_doi": null, + "release_tag": null, + "release_date": null, + "release_year": 2025, + "release_authors": null + }, + { + "organisation_id": "0c544eda-0885-4f94-9795-42b22baf7053", + "software_id": "d8d1a400-d18a-4fa9-a701-a25c8dbc9f5f", + "software_slug": "software-joule-mazda", + "software_name": "Software: joule Mazda", + "release_doi": null, + "release_tag": null, + "release_date": null, + "release_year": 2025, + "release_authors": null + } +] \ No newline at end of file diff --git a/frontend/components/organisation/releases/__mocks__/releases_by_organisation.json.license b/frontend/components/organisation/releases/__mocks__/releases_by_organisation.json.license new file mode 100644 index 000000000..546d6c9eb --- /dev/null +++ b/frontend/components/organisation/releases/__mocks__/releases_by_organisation.json.license @@ -0,0 +1,4 @@ +SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +SPDX-FileCopyrightText: 2023 Netherlands eScience Center + +SPDX-License-Identifier: Apache-2.0 diff --git a/frontend/components/organisation/releases/apiOrganisationReleases.ts b/frontend/components/organisation/releases/apiOrganisationReleases.ts new file mode 100644 index 000000000..dfef5af58 --- /dev/null +++ b/frontend/components/organisation/releases/apiOrganisationReleases.ts @@ -0,0 +1,74 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +import {createJsonHeaders, getBaseUrl} from '~/utils/fetchHelpers' +import logger from '~/utils/logger' +import {UseSoftwareReleaseProps} from './useSoftwareReleases' + +export type SoftwareReleaseInfo = { + software_id: string + software_slug: string + software_name: string + release_doi: string + release_tag: string | null + release_date: string + release_year: number + release_authors: string +} + +export type ReleaseCountByYear = { + release_year: number + release_cnt: number +} + +export async function getReleasesForOrganisation({organisation_id, release_year, token}: UseSoftwareReleaseProps) { + try { + const query = `organisation_id=eq.${organisation_id}&release_year=eq.${release_year}&order=release_date.desc` + const url = `${getBaseUrl()}/rpc/releases_by_organisation?${query}` + // make request + const resp = await fetch(url, { + method: 'GET', + headers: { + ...createJsonHeaders(token) + }, + }) + + if (resp.status === 200) { + const data: SoftwareReleaseInfo[] = await resp.json() + return data + } + // some other errors + logger(`getReleasesForOrganisation...${resp.status} ${resp.statusText}`) + return null + } catch (e: any) { + logger(`getReleasesForOrganisation...error...${e.message}`) + return null + } +} + +export async function getReleasesCountForOrganisation({organisation_id, token}: UseSoftwareReleaseProps) { + try { + const query = `organisation_id=${organisation_id}&order=release_year.desc` + const url = `${getBaseUrl()}/rpc/release_cnt_by_year?${query}` + // make request + const resp = await fetch(url, { + method: 'GET', + headers: { + ...createJsonHeaders(token) + }, + }) + + if (resp.status === 200) { + const data: ReleaseCountByYear[] = await resp.json() + return data + } + // some other errors + logger(`getReleasesCountForOrganisation...${resp.status} ${resp.statusText}`) + return null + } catch (e: any) { + logger(`getReleasesCountForOrganisation...error...${e.message}`) + return null + } +} diff --git a/frontend/components/organisation/releases/useReleaseCount.tsx b/frontend/components/organisation/releases/useReleaseCount.tsx index a7e967245..073a3546c 100644 --- a/frontend/components/organisation/releases/useReleaseCount.tsx +++ b/frontend/components/organisation/releases/useReleaseCount.tsx @@ -6,43 +6,13 @@ // SPDX-License-Identifier: Apache-2.0 import {useEffect, useState} from 'react' -import {createJsonHeaders, getBaseUrl} from '~/utils/fetchHelpers' -import logger from '~/utils/logger' - -export type ReleaseCountByYear = { - release_year: number - release_cnt: number -} +import {ReleaseCountByYear, getReleasesCountForOrganisation} from './apiOrganisationReleases' type UseSoftwareReleaseProps = { organisation_id?: string, token: string } -async function getReleasesCountForOrganisation({organisation_id, token}:UseSoftwareReleaseProps) { - try { - const query = `organisation_id=${organisation_id}&order=release_year.desc` - const url = `${getBaseUrl()}/rpc/release_cnt_by_year?${query}` - // make request - const resp = await fetch(url, { - method: 'GET', - headers: { - ...createJsonHeaders(token) - }, - }) - - if (resp.status === 200) { - const data:ReleaseCountByYear[] = await resp.json() - return data - } - // some other errors - logger(`getReleasesCountForOrganisation...${resp.status} ${resp.statusText}`) - return null - } catch(e:any) { - logger(`getReleasesCountForOrganisation...error...${e.message}`) - return null - } -} export default function useReleaseCount({organisation_id, token}:UseSoftwareReleaseProps) { const [loading, setLoading] = useState(true) diff --git a/frontend/components/organisation/releases/useSoftwareReleases.tsx b/frontend/components/organisation/releases/useSoftwareReleases.tsx index ad8387906..4f51f4186 100644 --- a/frontend/components/organisation/releases/useSoftwareReleases.tsx +++ b/frontend/components/organisation/releases/useSoftwareReleases.tsx @@ -7,55 +7,19 @@ // SPDX-License-Identifier: Apache-2.0 import {useEffect, useState} from 'react' -import {createJsonHeaders, getBaseUrl} from '~/utils/fetchHelpers' -import logger from '~/utils/logger' - -export type SoftwareReleaseInfo = { - software_id: string - software_slug: string - software_name: string - release_doi: string - release_tag: string | null - release_date: string - release_year: number - release_authors: string -} +import {SoftwareReleaseInfo, getReleasesForOrganisation} from './apiOrganisationReleases' export type ReleaseCountByYear = { release_year: number release_cnt: number } -type UseSoftwareReleaseProps = { +export type UseSoftwareReleaseProps = { organisation_id?: string, release_year?: string, token: string } -async function getReleasesForOrganisation({organisation_id,release_year,token}:UseSoftwareReleaseProps) { - try { - const query = `organisation_id=eq.${organisation_id}&release_year=eq.${release_year}&order=release_date.desc` - const url = `${getBaseUrl()}/rpc/releases_by_organisation?${query}` - // make request - const resp = await fetch(url, { - method: 'GET', - headers: { - ...createJsonHeaders(token) - }, - }) - - if (resp.status === 200) { - const data:SoftwareReleaseInfo[] = await resp.json() - return data - } - // some other errors - logger(`getReleasesForOrganisation...${resp.status} ${resp.statusText}`) - return null - } catch(e:any) { - logger(`getReleasesForOrganisation...error...${e.message}`) - return null - } -} export default function useSoftwareRelease({organisation_id,release_year,token}:UseSoftwareReleaseProps) { const [loading, setLoading] = useState(true) diff --git a/frontend/components/organisation/settings/OrganisationSettingsIndex.test.tsx b/frontend/components/organisation/settings/OrganisationSettingsIndex.test.tsx index 206bf12ec..4b251e73c 100644 --- a/frontend/components/organisation/settings/OrganisationSettingsIndex.test.tsx +++ b/frontend/components/organisation/settings/OrganisationSettingsIndex.test.tsx @@ -13,6 +13,9 @@ import OrganisationSettings from './index' import config from './general/generalSettingsConfig' import mockOrganisation from '../__mocks__/mockOrganisation' +// MOCK user agreement call +jest.mock('~/components/user/settings/fetchAgreementStatus') + const mockProps = { organisation: mockOrganisation, isMaintainer: false diff --git a/frontend/components/organisation/settings/SettingsNavItems.tsx b/frontend/components/organisation/settings/SettingsNavItems.tsx index e1a5b25dc..802d56a8a 100644 --- a/frontend/components/organisation/settings/SettingsNavItems.tsx +++ b/frontend/components/organisation/settings/SettingsNavItems.tsx @@ -5,7 +5,7 @@ // // SPDX-License-Identifier: Apache-2.0 -import React from 'react' +import {JSX} from 'react' import InfoIcon from '@mui/icons-material/Info' import PersonIcon from '@mui/icons-material/Person' import SettingsIcon from '@mui/icons-material/Settings' @@ -14,7 +14,7 @@ export type SettingsMenuProps = { id: string, status: string, label: (props?:any)=>string, - icon: React.JSX.Element + icon: JSX.Element } export const settingsMenu: SettingsMenuProps[] = [ diff --git a/frontend/components/organisation/settings/about-page/OrganisationAboutPageIndex.test.tsx b/frontend/components/organisation/settings/about-page/OrganisationAboutPageIndex.test.tsx new file mode 100644 index 000000000..db4f73758 --- /dev/null +++ b/frontend/components/organisation/settings/about-page/OrganisationAboutPageIndex.test.tsx @@ -0,0 +1,77 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +import {fireEvent, render, screen, waitFor} from '@testing-library/react' +import {WithAppContext, mockSession} from '~/utils/jest/WithAppContext' +import {WithOrganisationContext} from '~/utils/jest/WithOrganisationContext' + +import {Session} from '~/auth' + +import OrganisationAboutPage from './index' + +// MOCKS +import mockOrganisation from '~/components/organisation/__mocks__/mockOrganisation' + +const mockPatchOrganisationTable = jest.fn() +jest.mock('../updateOrganisationSettings', () => ({ + patchOrganisationTable: async(props:any)=>mockPatchOrganisationTable(props) +})) + +const testSession = { + ...mockSession, + user: { + ...mockSession.user, + role: 'rsd_user' + } +} as Session + +const mockProps = { + organisation: mockOrganisation, + isMaintainer: false +} + +beforeEach(() => { + jest.clearAllMocks() +}) + +describe('components/organisation/releases/index.tsx', () => { + + it('can update markdown input', async() => { + const markdown = '# Test title' + mockPatchOrganisationTable.mockResolvedValueOnce({status:200,message:'OK'}) + + render( + + + + + + ) + + const preview = screen.getByRole('tab', {name: 'Preview'}) + + // change input + const input = screen.getByRole('textbox') + fireEvent.change(input,{target:{value:markdown}}) + // trigger save + fireEvent.blur(input) + + // move to preview + fireEvent.click(preview) + // confirm markdown present + screen.getByText(markdown) + + await waitFor(() => { + expect(mockPatchOrganisationTable).toBeCalledTimes(1) + expect(mockPatchOrganisationTable).toBeCalledWith({ + 'data':{ + 'description': markdown, + }, + 'id': mockProps.organisation.id, + 'token': testSession.token, + }) + }) + }) +}) diff --git a/frontend/components/organisation/software/filters/__mocks__/org_software_keywords_filter.json b/frontend/components/organisation/software/filters/__mocks__/org_software_keywords_filter.json new file mode 100644 index 000000000..b86dca52f --- /dev/null +++ b/frontend/components/organisation/software/filters/__mocks__/org_software_keywords_filter.json @@ -0,0 +1,39 @@ + +[ + { + "keyword": "High performance computing", + "keyword_cnt": 2 + }, + { + "keyword": "Image processing", + "keyword_cnt": 1 + }, + { + "keyword": "Machine learning", + "keyword_cnt": 1 + }, + { + "keyword": "Multi-scale & multi model simulations", + "keyword_cnt": 1 + }, + { + "keyword": "Optimized data handling", + "keyword_cnt": 1 + }, + { + "keyword": "Real time data analysis", + "keyword_cnt": 1 + }, + { + "keyword": "Text analysis & natural language processing", + "keyword_cnt": 1 + }, + { + "keyword": "Visualization", + "keyword_cnt": 3 + }, + { + "keyword": "Workflow technologies", + "keyword_cnt": 1 + } +] \ No newline at end of file diff --git a/frontend/components/organisation/software/filters/__mocks__/org_software_keywords_filter.json.license b/frontend/components/organisation/software/filters/__mocks__/org_software_keywords_filter.json.license new file mode 100644 index 000000000..546d6c9eb --- /dev/null +++ b/frontend/components/organisation/software/filters/__mocks__/org_software_keywords_filter.json.license @@ -0,0 +1,4 @@ +SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +SPDX-FileCopyrightText: 2023 Netherlands eScience Center + +SPDX-License-Identifier: Apache-2.0 diff --git a/frontend/components/organisation/software/filters/__mocks__/org_software_languages_filter.json b/frontend/components/organisation/software/filters/__mocks__/org_software_languages_filter.json new file mode 100644 index 000000000..d4333f8b8 --- /dev/null +++ b/frontend/components/organisation/software/filters/__mocks__/org_software_languages_filter.json @@ -0,0 +1,7 @@ + +[ + { + "prog_language": "R", + "prog_language_cnt": 1 + } +] \ No newline at end of file diff --git a/frontend/components/organisation/software/filters/__mocks__/org_software_languages_filter.json.license b/frontend/components/organisation/software/filters/__mocks__/org_software_languages_filter.json.license new file mode 100644 index 000000000..546d6c9eb --- /dev/null +++ b/frontend/components/organisation/software/filters/__mocks__/org_software_languages_filter.json.license @@ -0,0 +1,4 @@ +SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +SPDX-FileCopyrightText: 2023 Netherlands eScience Center + +SPDX-License-Identifier: Apache-2.0 diff --git a/frontend/components/organisation/software/filters/__mocks__/org_software_licenses_filter.json b/frontend/components/organisation/software/filters/__mocks__/org_software_licenses_filter.json new file mode 100644 index 000000000..e963ac423 --- /dev/null +++ b/frontend/components/organisation/software/filters/__mocks__/org_software_licenses_filter.json @@ -0,0 +1,26 @@ +[ + { + "license": "Apache-2.0", + "license_cnt": 1 + }, + { + "license": "CC-BY-4.0", + "license_cnt": 2 + }, + { + "license": "CC-BY-NC-ND-3.0", + "license_cnt": 2 + }, + { + "license": "GPL-2.0-or-later", + "license_cnt": 2 + }, + { + "license": "LGPL-2.0-or-later", + "license_cnt": 2 + }, + { + "license": "MIT", + "license_cnt": 1 + } +] \ No newline at end of file diff --git a/frontend/components/organisation/software/filters/__mocks__/org_software_licenses_filter.json.license b/frontend/components/organisation/software/filters/__mocks__/org_software_licenses_filter.json.license new file mode 100644 index 000000000..546d6c9eb --- /dev/null +++ b/frontend/components/organisation/software/filters/__mocks__/org_software_licenses_filter.json.license @@ -0,0 +1,4 @@ +SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +SPDX-FileCopyrightText: 2023 Netherlands eScience Center + +SPDX-License-Identifier: Apache-2.0 diff --git a/frontend/components/organisation/software/filters/__mocks__/useOrgSoftwareKeywordsList.tsx b/frontend/components/organisation/software/filters/__mocks__/useOrgSoftwareKeywordsList.tsx new file mode 100644 index 000000000..93104b4c3 --- /dev/null +++ b/frontend/components/organisation/software/filters/__mocks__/useOrgSoftwareKeywordsList.tsx @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +import mockKeywordsList from './org_software_keywords_filter.json' + +// DEFAULT MOCK +export default function useOrgSoftwareKeywordsList() { + // console.log('useOrgSoftwareKeywordsList...default mock') + return { + keywordsList: mockKeywordsList + } +} diff --git a/frontend/components/organisation/software/filters/__mocks__/useOrgSoftwareLanguagesList.tsx b/frontend/components/organisation/software/filters/__mocks__/useOrgSoftwareLanguagesList.tsx new file mode 100644 index 000000000..8089e9945 --- /dev/null +++ b/frontend/components/organisation/software/filters/__mocks__/useOrgSoftwareLanguagesList.tsx @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +import mockLanguageList from './org_software_languages_filter.json' + +export default function useOrgSoftwareLanguagesList() { + // console.log('useOrgSoftwareLanguagesList...default mock') + return { + languagesList:mockLanguageList + } +} diff --git a/frontend/components/organisation/software/filters/__mocks__/useOrgSoftwareLicensesList.tsx b/frontend/components/organisation/software/filters/__mocks__/useOrgSoftwareLicensesList.tsx new file mode 100644 index 000000000..d5bee850e --- /dev/null +++ b/frontend/components/organisation/software/filters/__mocks__/useOrgSoftwareLicensesList.tsx @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +import mockLicensesList from './org_software_licenses_filter.json' + +export default function useOrgSoftwareLicensesList() { + // console.log('useOrgSoftwareLicensesList...default mock') + return { + licensesList: mockLicensesList + } +} diff --git a/frontend/components/organisation/tabs/OrganisationTabItems.tsx b/frontend/components/organisation/tabs/OrganisationTabItems.tsx index 3590e6d88..81a169066 100644 --- a/frontend/components/organisation/tabs/OrganisationTabItems.tsx +++ b/frontend/components/organisation/tabs/OrganisationTabItems.tsx @@ -3,7 +3,7 @@ // // SPDX-License-Identifier: Apache-2.0 -import React from 'react' +import {JSX} from 'react' import InfoIcon from '@mui/icons-material/Info' import TerminalIcon from '@mui/icons-material/Terminal' import AccountTreeIcon from '@mui/icons-material/AccountTree' @@ -21,7 +21,7 @@ type IsVisibleProps = Partial & { export type OrganisationTabItemProps = { id: string, label: (props:any)=>string, - icon: React.JSX.Element, + icon: JSX.Element, isVisible: (props: IsVisibleProps) => boolean } diff --git a/frontend/components/organisation/units/ResearchUnitItem.tsx b/frontend/components/organisation/units/ResearchUnitItem.tsx index 09a30b883..29e25bd2f 100644 --- a/frontend/components/organisation/units/ResearchUnitItem.tsx +++ b/frontend/components/organisation/units/ResearchUnitItem.tsx @@ -29,8 +29,6 @@ type UnitListItemProps = { export default function UnitItem({pos,slug,name,website,logo_id,isMaintainer,onEdit}: UnitListItemProps) { const router = useRouter() - // remove query params from url (id) - const baseUrl = router.asPath.split('?') const slugs = [] if (typeof router.query['slug'] === 'string') { slugs.push(router.query['slug']) diff --git a/frontend/components/projects/edit/editProjectPages.tsx b/frontend/components/projects/edit/editProjectPages.tsx index 800e37e00..777cf869b 100644 --- a/frontend/components/projects/edit/editProjectPages.tsx +++ b/frontend/components/projects/edit/editProjectPages.tsx @@ -5,7 +5,7 @@ // // SPDX-License-Identifier: Apache-2.0 -import React from 'react' +import {JSX} from 'react' import dynamic from 'next/dynamic' import InfoIcon from '@mui/icons-material/Info' @@ -53,8 +53,8 @@ export type EditProjectPageProps = { id: string, status: string, label: string, - icon: React.JSX.Element, - render: () => React.JSX.Element + icon: JSX.Element, + render: () => JSX.Element } export const editProjectPage: EditProjectPageProps[] = [ diff --git a/frontend/components/projects/edit/information/__mocks__/searchForKeyword.ts b/frontend/components/projects/edit/information/__mocks__/searchForKeyword.ts new file mode 100644 index 000000000..d03e32c25 --- /dev/null +++ b/frontend/components/projects/edit/information/__mocks__/searchForKeyword.ts @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +export type Keyword = { + id: string, + keyword: string, + cnt: number | null +} + +export type NewKeyword = { + id: null, + keyword: string +} + +// DEFAULT MOCK +export async function searchForProjectKeyword({searchFor}: { searchFor: string }) { + // console.log('searchForProjectKeyword...default MOCK') + return [] +} diff --git a/frontend/components/projects/edit/maintainers/EditProjectMaintainersIndex.test.tsx b/frontend/components/projects/edit/maintainers/EditProjectMaintainersIndex.test.tsx index 8609dc9c4..b723a2bc1 100644 --- a/frontend/components/projects/edit/maintainers/EditProjectMaintainersIndex.test.tsx +++ b/frontend/components/projects/edit/maintainers/EditProjectMaintainersIndex.test.tsx @@ -1,5 +1,7 @@ // SPDX-FileCopyrightText: 2022 Dusan Mijatovic (dv4all) (dv4all) // SPDX-FileCopyrightText: 2022 dv4all +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center // // SPDX-License-Identifier: Apache-2.0 @@ -12,13 +14,14 @@ import {mockResolvedValueOnce} from '~/utils/jest/mockFetch' import ProjectMaintainers from './index' import editProjectState from '../__mocks__/editProjectState' +// MOCK user agreement call +jest.mock('~/components/user/settings/fetchAgreementStatus') // MOCKS const mockGetUnusedInvitations=jest.fn(props=>Promise.resolve([])) jest.mock('~/utils/getUnusedInvitations', () => ({ getUnusedInvitations: jest.fn(props=>mockGetUnusedInvitations(props)) })) - describe('frontend/components/projects/edit/maintainers/index.tsx', () => { beforeEach(() => { jest.clearAllMocks() diff --git a/frontend/components/projects/overview/cards/ProjectOverviewGrid.tsx b/frontend/components/projects/overview/cards/ProjectOverviewGrid.tsx index 1897d5306..59f646a9e 100644 --- a/frontend/components/projects/overview/cards/ProjectOverviewGrid.tsx +++ b/frontend/components/projects/overview/cards/ProjectOverviewGrid.tsx @@ -6,9 +6,9 @@ // // SPDX-License-Identifier: Apache-2.0 -import React from 'react' +import {JSX} from 'react' -export default function ProjectOverviewGrid({children}: { children: React.JSX.Element | React.JSX.Element[] }) { +export default function ProjectOverviewGrid({children}: { children: JSX.Element | JSX.Element[] }) { // console.log('ProjectOverviewGrid') return (
React.JSX.Element + icon: JSX.Element, + render: () => JSX.Element } export const editSoftwarePage:EditSoftwarePageProps[] = [{ diff --git a/frontend/components/software/overview/cards/SoftwareOverviewGrid.tsx b/frontend/components/software/overview/cards/SoftwareOverviewGrid.tsx index bafa7bc78..83f6f030b 100644 --- a/frontend/components/software/overview/cards/SoftwareOverviewGrid.tsx +++ b/frontend/components/software/overview/cards/SoftwareOverviewGrid.tsx @@ -6,9 +6,9 @@ // // SPDX-License-Identifier: Apache-2.0 -import React from 'react' +import {JSX} from 'react' -export default function SoftwareOverviewGrid({children}: { children: React.JSX.Element | React.JSX.Element[] }) { +export default function SoftwareOverviewGrid({children}: { children: JSX.Element | JSX.Element[] }) { return (
= { sx?: SxProps order?: OrderProps patchFn?: (props: UpdateProps) => Promise<{ status: number, message: string }> - renderFn?: (data:T) => React.JSX.Element + renderFn?: (data:T) => JSX.Element } export type OrderByProps = { diff --git a/frontend/components/user/UserNavItems.tsx b/frontend/components/user/UserNavItems.tsx index a3f25d985..9e754b81c 100644 --- a/frontend/components/user/UserNavItems.tsx +++ b/frontend/components/user/UserNavItems.tsx @@ -8,7 +8,7 @@ // // SPDX-License-Identifier: Apache-2.0 -import React from 'react' +import {JSX} from 'react' import dynamic from 'next/dynamic' import TerminalIcon from '@mui/icons-material/Terminal' @@ -44,8 +44,8 @@ export type UserMenuProps = { id: string, status: string, label: (props:any)=>string, - icon: React.JSX.Element, - component: (props: any) => React.JSX.Element + icon: JSX.Element, + component: (props: any) => JSX.Element showSearch: boolean } diff --git a/frontend/components/user/project-quality/SortableTable.tsx b/frontend/components/user/project-quality/SortableTable.tsx index f6ed3a870..30de96795 100644 --- a/frontend/components/user/project-quality/SortableTable.tsx +++ b/frontend/components/user/project-quality/SortableTable.tsx @@ -35,7 +35,7 @@ type SortableTableProps = { export default function SortableTable({metadata, initialData, initialOrder=''}: SortableTableProps) { const propKeys = Array.from(metadata.keys()) const [sortColumn, setSortColumn] = useState(initialOrder) - const [data, setData] = useState(initialData) + const [data] = useState(initialData) const [ascending, setAscending] = useState(true) function getDirection(metadataKey:string){ diff --git a/frontend/components/user/project/__mocks__/useUserProjects.tsx b/frontend/components/user/project/__mocks__/useUserProjects.tsx new file mode 100644 index 000000000..f2c8815c7 --- /dev/null +++ b/frontend/components/user/project/__mocks__/useUserProjects.tsx @@ -0,0 +1,23 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +import {Session} from '~/auth' +import mockProjectsByMaintainer from './projectsByMaintainer.json' + +export type UserProjectsProp = { + searchFor?: string + page: number, + rows: number, + session: Session +} + +export default function useUserProjects({searchFor, page, rows, session}: UserProjectsProp) { + + return { + projects: mockProjectsByMaintainer, + count: mockProjectsByMaintainer.length, + loading: false + } +} diff --git a/frontend/components/user/software/__mocks__/useUserSoftware.tsx b/frontend/components/user/software/__mocks__/useUserSoftware.tsx new file mode 100644 index 000000000..39c205aef --- /dev/null +++ b/frontend/components/user/software/__mocks__/useUserSoftware.tsx @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +import {Session} from '~/auth' + + +import mockSoftwareByMaintainer from './softwareByMaintainer.json' + +type UserSoftwareProp = { + searchFor?: string + page: number, + rows: number, + session: Session +} + +export default function useUserSoftware({searchFor, page, rows, session}:UserSoftwareProp) { + + return { + software:mockSoftwareByMaintainer, + count:mockSoftwareByMaintainer.length, + loading:false + } +} diff --git a/frontend/config/menuItems.ts b/frontend/config/menuItems.ts index 95aaf511d..68714949c 100644 --- a/frontend/config/menuItems.ts +++ b/frontend/config/menuItems.ts @@ -7,7 +7,7 @@ // // SPDX-License-Identifier: Apache-2.0 -import React from 'react' +import {JSX} from 'react' export type MenuItemType = { type?: 'link' | 'function' |'divider' @@ -18,7 +18,7 @@ export type MenuItemType = { match?: string, // used to customize menu items per user/profile active?: boolean - icon?: React.JSX.Element, + icon?: JSX.Element, // optional, but fn is provided it will have higher priority // than path fn?: Function, diff --git a/frontend/pages/admin/keywords.tsx b/frontend/pages/admin/keywords.tsx index 13cce9ac9..76cf2a90f 100644 --- a/frontend/pages/admin/keywords.tsx +++ b/frontend/pages/admin/keywords.tsx @@ -1,4 +1,6 @@ +// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center) // SPDX-FileCopyrightText: 2023 Dusan Mijatovic (dv4all) +// SPDX-FileCopyrightText: 2023 Netherlands eScience Center // SPDX-FileCopyrightText: 2023 dv4all // // SPDX-License-Identifier: Apache-2.0 @@ -24,7 +26,7 @@ const pagination = { labelRowsPerPage:'Per page' } -export default function AdminKeywordsPage(props:any) { +export default function AdminKeywordsPage() { // console.group('AdminKeywordsPage') // console.log('keywords...', keywords) @@ -38,7 +40,7 @@ export default function AdminKeywordsPage(props:any) { - + diff --git a/frontend/utils/jest/WithAppContext.tsx b/frontend/utils/jest/WithAppContext.tsx index 0d66c1fbb..717e9086a 100644 --- a/frontend/utils/jest/WithAppContext.tsx +++ b/frontend/utils/jest/WithAppContext.tsx @@ -52,6 +52,7 @@ export function WithAppContext({children,options}:WithAppContextProps) { // console.group('WithAppContext') // console.log('session...', session) // console.log('settings...', settings) + // console.log('muiTheme...', muiTheme) // console.groupEnd() return ( diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 1b4c42f81..72bca8de6 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -8,9 +8,9 @@ integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== "@adobe/css-tools@^4.0.1": - version "4.3.0" - resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.3.0.tgz#1991d273fb29edbd2f63060f5bdaf0af26aa64e3" - integrity sha512-+RNNcQvw2V1bmnBTPAtOLfW/9mhH2vC67+rUSi5T8EtEWt6lEnGNY2GuhZ1/YwbgikT1TkhvidCDmN5Q5YCo/w== + version "4.3.1" + resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.3.1.tgz#abfccb8ca78075a2b6187345c26243c1a0842f28" + integrity sha512-/62yikz7NLScCGAAST5SHdnjaDJQBDq0M2muyRTpf2VQhw6StBg2ALiu73zSJQ4fMVLA+0uBhBHAle7Wg+2kSg== "@alloc/quick-lru@^5.2.0": version "5.2.0" @@ -1212,9 +1212,9 @@ eslint-visitor-keys "^3.3.0" "@eslint-community/regexpp@^4.6.1": - version "4.6.2" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.6.2.tgz#1816b5f6948029c5eaacb0703b850ee0cb37d8f8" - integrity sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw== + version "4.7.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.7.0.tgz#96e7c05e738327602ae5942437f9c6b177ec279a" + integrity sha512-+HencqxU7CFJnQb7IKtuNBqS6Yx3Tz4kOL8BJXo+JyeiBm5MEX6pO8onXDkjrkCRlfYXS1Axro15ZjVFe9YgsA== "@eslint/eslintrc@^2.1.1": version "2.1.2" @@ -1271,109 +1271,109 @@ resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== -"@jest/console@^29.6.2": - version "29.6.2" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.6.2.tgz#bf1d4101347c23e07c029a1b1ae07d550f5cc541" - integrity sha512-0N0yZof5hi44HAR2pPS+ikJ3nzKNoZdVu8FffRf3wy47I7Dm7etk/3KetMdRUqzVd16V4O2m2ISpNTbnIuqy1w== +"@jest/console@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.6.3.tgz#55ad945087c27e380d6d9fcbb85181ed802543f3" + integrity sha512-ukZbHAdDH4ktZIOKvWs1juAXhiVAdvCyM8zv4S/7Ii3vJSDvMW5k+wOVGMQmHLHUFw3Ko63ZQNy7NI6PSlsD5w== dependencies: - "@jest/types" "^29.6.1" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" - jest-message-util "^29.6.2" - jest-util "^29.6.2" + jest-message-util "^29.6.3" + jest-util "^29.6.3" slash "^3.0.0" -"@jest/core@^29.5.0", "@jest/core@^29.6.2": - version "29.6.2" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.6.2.tgz#6f2d1dbe8aa0265fcd4fb8082ae1952f148209c8" - integrity sha512-Oj+5B+sDMiMWLhPFF+4/DvHOf+U10rgvCLGPHP8Xlsy/7QxS51aU/eBngudHlJXnaWD5EohAgJ4js+T6pa+zOg== +"@jest/core@^29.5.0", "@jest/core@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.6.3.tgz#bccee53680762e1bdef2a0038f123cc8d7ba4ab8" + integrity sha512-skV1XrfNxfagmjRUrk2FyN5/2YwIzdWVVBa/orUfbLvQUANXxERq2pTvY0I+FinWHjDKB2HRmpveUiph4X0TJw== dependencies: - "@jest/console" "^29.6.2" - "@jest/reporters" "^29.6.2" - "@jest/test-result" "^29.6.2" - "@jest/transform" "^29.6.2" - "@jest/types" "^29.6.1" + "@jest/console" "^29.6.3" + "@jest/reporters" "^29.6.3" + "@jest/test-result" "^29.6.3" + "@jest/transform" "^29.6.3" + "@jest/types" "^29.6.3" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" ci-info "^3.2.0" exit "^0.1.2" graceful-fs "^4.2.9" - jest-changed-files "^29.5.0" - jest-config "^29.6.2" - jest-haste-map "^29.6.2" - jest-message-util "^29.6.2" - jest-regex-util "^29.4.3" - jest-resolve "^29.6.2" - jest-resolve-dependencies "^29.6.2" - jest-runner "^29.6.2" - jest-runtime "^29.6.2" - jest-snapshot "^29.6.2" - jest-util "^29.6.2" - jest-validate "^29.6.2" - jest-watcher "^29.6.2" + jest-changed-files "^29.6.3" + jest-config "^29.6.3" + jest-haste-map "^29.6.3" + jest-message-util "^29.6.3" + jest-regex-util "^29.6.3" + jest-resolve "^29.6.3" + jest-resolve-dependencies "^29.6.3" + jest-runner "^29.6.3" + jest-runtime "^29.6.3" + jest-snapshot "^29.6.3" + jest-util "^29.6.3" + jest-validate "^29.6.3" + jest-watcher "^29.6.3" micromatch "^4.0.4" - pretty-format "^29.6.2" + pretty-format "^29.6.3" slash "^3.0.0" strip-ansi "^6.0.0" -"@jest/environment@^29.5.0", "@jest/environment@^29.6.2": - version "29.6.2" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.6.2.tgz#794c0f769d85e7553439d107d3f43186dc6874a9" - integrity sha512-AEcW43C7huGd/vogTddNNTDRpO6vQ2zaQNrttvWV18ArBx9Z56h7BIsXkNFJVOO4/kblWEQz30ckw0+L3izc+Q== +"@jest/environment@^29.5.0", "@jest/environment@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.6.3.tgz#bb02535c729393a0345b8d2c5eef94d34f7b35a3" + integrity sha512-u/u3cCztYCfgBiGHsamqP5x+XvucftOGPbf5RJQxfpeC1y4AL8pCjKvPDA3oCmdhZYPgk5AE0VOD/flweR69WA== dependencies: - "@jest/fake-timers" "^29.6.2" - "@jest/types" "^29.6.1" + "@jest/fake-timers" "^29.6.3" + "@jest/types" "^29.6.3" "@types/node" "*" - jest-mock "^29.6.2" + jest-mock "^29.6.3" -"@jest/expect-utils@^29.6.2": - version "29.6.2" - resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.6.2.tgz#1b97f290d0185d264dd9fdec7567a14a38a90534" - integrity sha512-6zIhM8go3RV2IG4aIZaZbxwpOzz3ZiM23oxAlkquOIole+G6TrbeXnykxWYlqF7kz2HlBjdKtca20x9atkEQYg== +"@jest/expect-utils@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.6.3.tgz#5ef1a9689fdaa348da837c8be8d1219f56940ea3" + integrity sha512-nvOEW4YoqRKD9HBJ9OJ6przvIvP9qilp5nAn1462P5ZlL/MM9SgPEZFyjTGPfs7QkocdUsJa6KjHhyRn4ueItA== dependencies: - jest-get-type "^29.4.3" + jest-get-type "^29.6.3" -"@jest/expect@^29.6.2": - version "29.6.2" - resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.6.2.tgz#5a2ad58bb345165d9ce0a1845bbf873c480a4b28" - integrity sha512-m6DrEJxVKjkELTVAztTLyS/7C92Y2b0VYqmDROYKLLALHn8T/04yPs70NADUYPrV3ruI+H3J0iUIuhkjp7vkfg== +"@jest/expect@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.6.3.tgz#d54e1e7134982166f62653add0d4b8262dd72db9" + integrity sha512-Ic08XbI2jlg6rECy+CGwk/8NDa6VE7UmIG6++9OTPAMnQmNGY28hu69Nf629CWv6T7YMODLbONxDFKdmQeI9FA== dependencies: - expect "^29.6.2" - jest-snapshot "^29.6.2" + expect "^29.6.3" + jest-snapshot "^29.6.3" -"@jest/fake-timers@^29.5.0", "@jest/fake-timers@^29.6.2": - version "29.6.2" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.6.2.tgz#fe9d43c5e4b1b901168fe6f46f861b3e652a2df4" - integrity sha512-euZDmIlWjm1Z0lJ1D0f7a0/y5Kh/koLFMUBE5SUYWrmy8oNhJpbTBDAP6CxKnadcMLDoDf4waRYCe35cH6G6PA== +"@jest/fake-timers@^29.5.0", "@jest/fake-timers@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.6.3.tgz#7e780b05b14ad59dca68bdc188f6cf085552a0e8" + integrity sha512-pa1wmqvbj6eX0nMvOM2VDAWvJOI5A/Mk3l8O7n7EsAh71sMZblaKO9iT4GjIj0LwwK3CP/Jp1ypEV0x3m89RvA== dependencies: - "@jest/types" "^29.6.1" + "@jest/types" "^29.6.3" "@sinonjs/fake-timers" "^10.0.2" "@types/node" "*" - jest-message-util "^29.6.2" - jest-mock "^29.6.2" - jest-util "^29.6.2" + jest-message-util "^29.6.3" + jest-mock "^29.6.3" + jest-util "^29.6.3" -"@jest/globals@^29.6.2": - version "29.6.2" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.6.2.tgz#74af81b9249122cc46f1eb25793617eec69bf21a" - integrity sha512-cjuJmNDjs6aMijCmSa1g2TNG4Lby/AeU7/02VtpW+SLcZXzOLK2GpN2nLqcFjmhy3B3AoPeQVx7BnyOf681bAw== +"@jest/globals@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.6.3.tgz#fe9e302bc20683ba8feb683b8804e38a9913b783" + integrity sha512-RB+uI+CZMHntzlnOPlll5x/jgRff3LEPl/td/jzMXiIgR0iIhKq9qm1HLU+EC52NuoVy/1swit/sDGjVn4bc6A== dependencies: - "@jest/environment" "^29.6.2" - "@jest/expect" "^29.6.2" - "@jest/types" "^29.6.1" - jest-mock "^29.6.2" + "@jest/environment" "^29.6.3" + "@jest/expect" "^29.6.3" + "@jest/types" "^29.6.3" + jest-mock "^29.6.3" -"@jest/reporters@^29.6.2": - version "29.6.2" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.6.2.tgz#524afe1d76da33d31309c2c4a2c8062d0c48780a" - integrity sha512-sWtijrvIav8LgfJZlrGCdN0nP2EWbakglJY49J1Y5QihcQLfy7ovyxxjJBRXMNltgt4uPtEcFmIMbVshEDfFWw== +"@jest/reporters@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.6.3.tgz#e5071915d74f43e0f49982fa518ca3283a9f4c5a" + integrity sha512-kGz59zMi0GkVjD2CJeYWG9k6cvj7eBqt9aDAqo2rcCLRTYlvQ62Gu/n+tOmJMBHGjzeijjuCENjzTyYBgrtLUw== dependencies: "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^29.6.2" - "@jest/test-result" "^29.6.2" - "@jest/transform" "^29.6.2" - "@jest/types" "^29.6.1" + "@jest/console" "^29.6.3" + "@jest/test-result" "^29.6.3" + "@jest/transform" "^29.6.3" + "@jest/types" "^29.6.3" "@jridgewell/trace-mapping" "^0.3.18" "@types/node" "*" chalk "^4.0.0" @@ -1382,81 +1382,81 @@ glob "^7.1.3" graceful-fs "^4.2.9" istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^5.1.0" + istanbul-lib-instrument "^6.0.0" istanbul-lib-report "^3.0.0" istanbul-lib-source-maps "^4.0.0" istanbul-reports "^3.1.3" - jest-message-util "^29.6.2" - jest-util "^29.6.2" - jest-worker "^29.6.2" + jest-message-util "^29.6.3" + jest-util "^29.6.3" + jest-worker "^29.6.3" slash "^3.0.0" string-length "^4.0.1" strip-ansi "^6.0.0" v8-to-istanbul "^9.0.1" -"@jest/schemas@^29.6.0": - version "29.6.0" - resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.0.tgz#0f4cb2c8e3dca80c135507ba5635a4fd755b0040" - integrity sha512-rxLjXyJBTL4LQeJW3aKo0M/+GkCOXsO+8i9Iu7eDb6KwtP65ayoDsitrdPBtujxQ88k4wI2FNYfa6TOGwSn6cQ== +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== dependencies: "@sinclair/typebox" "^0.27.8" -"@jest/source-map@^29.6.0": - version "29.6.0" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.0.tgz#bd34a05b5737cb1a99d43e1957020ac8e5b9ddb1" - integrity sha512-oA+I2SHHQGxDCZpbrsCQSoMLb3Bz547JnM+jUr9qEbuw0vQlWZfpPS7CO9J7XiwKicEz9OFn/IYoLkkiUD7bzA== +"@jest/source-map@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" + integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== dependencies: "@jridgewell/trace-mapping" "^0.3.18" callsites "^3.0.0" graceful-fs "^4.2.9" -"@jest/test-result@^29.6.2": - version "29.6.2" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.6.2.tgz#fdd11583cd1608e4db3114e8f0cce277bf7a32ed" - integrity sha512-3VKFXzcV42EYhMCsJQURptSqnyjqCGbtLuX5Xxb6Pm6gUf1wIRIl+mandIRGJyWKgNKYF9cnstti6Ls5ekduqw== +"@jest/test-result@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.6.3.tgz#1da4c6749c16a71c108644624d9cd0d17206aa2b" + integrity sha512-k7ZZaNvOSMBHPZYiy0kuiaFoyansR5QnTwDux1EjK3kD5iWpRVyJIJ0RAIV39SThafchuW59vra7F8mdy5Hfgw== dependencies: - "@jest/console" "^29.6.2" - "@jest/types" "^29.6.1" + "@jest/console" "^29.6.3" + "@jest/types" "^29.6.3" "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^29.6.2": - version "29.6.2" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.6.2.tgz#585eff07a68dd75225a7eacf319780cb9f6b9bf4" - integrity sha512-GVYi6PfPwVejO7slw6IDO0qKVum5jtrJ3KoLGbgBWyr2qr4GaxFV6su+ZAjdTX75Sr1DkMFRk09r2ZVa+wtCGw== +"@jest/test-sequencer@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.6.3.tgz#e59f422bc3786d79fac504c16979a5f1b999a932" + integrity sha512-/SmijaAU2TY9ComFGIYa6Z+fmKqQMnqs2Nmwb0P/Z/tROdZ7M0iruES1EaaU9PBf8o9uED5xzaJ3YPFEIcDgAg== dependencies: - "@jest/test-result" "^29.6.2" + "@jest/test-result" "^29.6.3" graceful-fs "^4.2.9" - jest-haste-map "^29.6.2" + jest-haste-map "^29.6.3" slash "^3.0.0" -"@jest/transform@^29.6.2": - version "29.6.2" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.6.2.tgz#522901ebbb211af08835bc3bcdf765ab778094e3" - integrity sha512-ZqCqEISr58Ce3U+buNFJYUktLJZOggfyvR+bZMaiV1e8B1SIvJbwZMrYz3gx/KAPn9EXmOmN+uB08yLCjWkQQg== +"@jest/transform@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.6.3.tgz#e8e376f56fffe827b529bf03a9881e58d152c14b" + integrity sha512-dPIc3DsvMZ/S8ut4L2ViCj265mKO0owB0wfzBv2oGzL9pQ+iRvJewHqLBmsGb7XFb5UotWIEtvY5A/lnylaIoQ== dependencies: "@babel/core" "^7.11.6" - "@jest/types" "^29.6.1" + "@jest/types" "^29.6.3" "@jridgewell/trace-mapping" "^0.3.18" babel-plugin-istanbul "^6.1.1" chalk "^4.0.0" convert-source-map "^2.0.0" fast-json-stable-stringify "^2.1.0" graceful-fs "^4.2.9" - jest-haste-map "^29.6.2" - jest-regex-util "^29.4.3" - jest-util "^29.6.2" + jest-haste-map "^29.6.3" + jest-regex-util "^29.6.3" + jest-util "^29.6.3" micromatch "^4.0.4" pirates "^4.0.4" slash "^3.0.0" write-file-atomic "^4.0.2" -"@jest/types@^29.5.0", "@jest/types@^29.6.1": - version "29.6.1" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.1.tgz#ae79080278acff0a6af5eb49d063385aaa897bf2" - integrity sha512-tPKQNMPuXgvdOn2/Lg9HNfUvjYVGolt04Hp03f5hAk878uwOLikN+JzeLY0HcVgKgFl9Hs3EIqpu3WX27XNhnw== +"@jest/types@^29.5.0", "@jest/types@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" + integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== dependencies: - "@jest/schemas" "^29.6.0" + "@jest/schemas" "^29.6.3" "@types/istanbul-lib-coverage" "^2.0.0" "@types/istanbul-reports" "^3.0.0" "@types/node" "*" @@ -2231,9 +2231,9 @@ integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== "@types/node@*": - version "20.5.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.5.0.tgz#7fc8636d5f1aaa3b21e6245e97d56b7f56702313" - integrity sha512-Mgq7eCtoTjT89FqNoTzzXg2XvCi5VMhRV6+I2aYanc6kQCBImeNaAYRs/DyoVqk1YEUJK5gN9VO7HRIdz4Wo3Q== + version "20.5.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.5.1.tgz#178d58ee7e4834152b0e8b4d30cbfab578b9bb30" + integrity sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg== "@types/node@20.3.3": version "20.3.3" @@ -2356,14 +2356,14 @@ debug "^4.3.4" "@typescript-eslint/parser@^5.4.2 || ^6.0.0": - version "6.3.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.3.0.tgz#359684c443f4f848db3c4f14674f544f169c8f46" - integrity sha512-ibP+y2Gr6p0qsUkhs7InMdXrwldjxZw66wpcQq9/PzAroM45wdwyu81T+7RibNCh8oc0AgrsyCwJByncY0Ongg== - dependencies: - "@typescript-eslint/scope-manager" "6.3.0" - "@typescript-eslint/types" "6.3.0" - "@typescript-eslint/typescript-estree" "6.3.0" - "@typescript-eslint/visitor-keys" "6.3.0" + version "6.4.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.4.1.tgz#85ad550bf4ac4aa227504f1becb828f8e46c44e3" + integrity sha512-610G6KHymg9V7EqOaNBMtD1GgpAmGROsmfHJPXNLCU9bfIuLrkdOygltK784F6Crboyd5tBFayPB7Sf0McrQwg== + dependencies: + "@typescript-eslint/scope-manager" "6.4.1" + "@typescript-eslint/types" "6.4.1" + "@typescript-eslint/typescript-estree" "6.4.1" + "@typescript-eslint/visitor-keys" "6.4.1" debug "^4.3.4" "@typescript-eslint/scope-manager@5.62.0": @@ -2374,23 +2374,23 @@ "@typescript-eslint/types" "5.62.0" "@typescript-eslint/visitor-keys" "5.62.0" -"@typescript-eslint/scope-manager@6.3.0": - version "6.3.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.3.0.tgz#6b74e338c4b88d5e1dfc1a28c570dd5cf8c86b09" - integrity sha512-WlNFgBEuGu74ahrXzgefiz/QlVb+qg8KDTpknKwR7hMH+lQygWyx0CQFoUmMn1zDkQjTBBIn75IxtWss77iBIQ== +"@typescript-eslint/scope-manager@6.4.1": + version "6.4.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.4.1.tgz#4b073a30be2dbe603e44e9ae0cff7e1d3ed19278" + integrity sha512-p/OavqOQfm4/Hdrr7kvacOSFjwQ2rrDVJRPxt/o0TOWdFnjJptnjnZ+sYDR7fi4OimvIuKp+2LCkc+rt9fIW+A== dependencies: - "@typescript-eslint/types" "6.3.0" - "@typescript-eslint/visitor-keys" "6.3.0" + "@typescript-eslint/types" "6.4.1" + "@typescript-eslint/visitor-keys" "6.4.1" "@typescript-eslint/types@5.62.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ== -"@typescript-eslint/types@6.3.0": - version "6.3.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.3.0.tgz#84517f1427923e714b8418981e493b6635ab4c9d" - integrity sha512-K6TZOvfVyc7MO9j60MkRNWyFSf86IbOatTKGrpTQnzarDZPYPVy0oe3myTMq7VjhfsUAbNUW8I5s+2lZvtx1gg== +"@typescript-eslint/types@6.4.1": + version "6.4.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.4.1.tgz#b2c61159f46dda210fed9f117f5d027f65bb5c3b" + integrity sha512-zAAopbNuYu++ijY1GV2ylCsQsi3B8QvfPHVqhGdDcbx/NK5lkqMnCGU53amAjccSpk+LfeONxwzUhDzArSfZJg== "@typescript-eslint/typescript-estree@5.62.0", "@typescript-eslint/typescript-estree@^5.27.1": version "5.62.0" @@ -2405,13 +2405,13 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@6.3.0": - version "6.3.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.3.0.tgz#20e1e10e2f51cdb9e19a2751215cac92c003643c" - integrity sha512-Xh4NVDaC4eYKY4O3QGPuQNp5NxBAlEvNQYOqJquR2MePNxO11E5K3t5x4M4Mx53IZvtpW+mBxIT0s274fLUocg== +"@typescript-eslint/typescript-estree@6.4.1": + version "6.4.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.4.1.tgz#91ff88101c710adb0f70a317f2f65efa9441da45" + integrity sha512-xF6Y7SatVE/OyV93h1xGgfOkHr2iXuo8ip0gbfzaKeGGuKiAnzS+HtVhSPx8Www243bwlW8IF7X0/B62SzFftg== dependencies: - "@typescript-eslint/types" "6.3.0" - "@typescript-eslint/visitor-keys" "6.3.0" + "@typescript-eslint/types" "6.4.1" + "@typescript-eslint/visitor-keys" "6.4.1" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" @@ -2426,12 +2426,12 @@ "@typescript-eslint/types" "5.62.0" eslint-visitor-keys "^3.3.0" -"@typescript-eslint/visitor-keys@6.3.0": - version "6.3.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.3.0.tgz#8d09aa3e389ae0971426124c155ac289afbe450a" - integrity sha512-kEhRRj7HnvaSjux1J9+7dBen15CdWmDnwrpyiHsFX6Qx2iW5LOBUgNefOFeh2PjWPlNwN8TOn6+4eBU3J/gupw== +"@typescript-eslint/visitor-keys@6.4.1": + version "6.4.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.4.1.tgz#e3ccf7b8d42e625946ac5094ed92a405fb4115e0" + integrity sha512-y/TyRJsbZPkJIZQXrHfdnxVnxyKegnpEvnRGNam7s3TRR2ykGefEWOhaef00/UUN3IZxizS7BTO3svd3lCOJRQ== dependencies: - "@typescript-eslint/types" "6.3.0" + "@typescript-eslint/types" "6.4.1" eslint-visitor-keys "^3.4.1" abab@^2.0.6: @@ -2646,6 +2646,13 @@ ast-types-flow@^0.0.7: resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" integrity sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag== +asynciterator.prototype@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz#8c5df0514936cdd133604dfcc9d3fb93f09b2b62" + integrity sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg== + dependencies: + has-symbols "^1.0.3" + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -2680,15 +2687,15 @@ axobject-query@^3.1.1: dependencies: dequal "^2.0.3" -babel-jest@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.6.2.tgz#cada0a59e07f5acaeb11cbae7e3ba92aec9c1126" - integrity sha512-BYCzImLos6J3BH/+HvUCHG1dTf2MzmAB4jaVxHV+29RZLjR29XuYTmsf2sdDwkrb+FczkGo3kOhE7ga6sI0P4A== +babel-jest@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.6.3.tgz#e62f6c38f3ec8c147244168ee18ef0b919f10348" + integrity sha512-1Ne93zZZEy5XmTa4Q+W5+zxBrDpExX8E3iy+xJJ+24ewlfo/T3qHfQJCzi/MMVFmBQDNxtRR/Gfd2dwb/0yrQw== dependencies: - "@jest/transform" "^29.6.2" + "@jest/transform" "^29.6.3" "@types/babel__core" "^7.1.14" babel-plugin-istanbul "^6.1.1" - babel-preset-jest "^29.5.0" + babel-preset-jest "^29.6.3" chalk "^4.0.0" graceful-fs "^4.2.9" slash "^3.0.0" @@ -2704,10 +2711,10 @@ babel-plugin-istanbul@^6.1.1: istanbul-lib-instrument "^5.0.4" test-exclude "^6.0.0" -babel-plugin-jest-hoist@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz#a97db437936f441ec196990c9738d4b88538618a" - integrity sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w== +babel-plugin-jest-hoist@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" + integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== dependencies: "@babel/template" "^7.3.3" "@babel/types" "^7.3.3" @@ -2765,12 +2772,12 @@ babel-preset-current-node-syntax@^1.0.0: "@babel/plugin-syntax-optional-chaining" "^7.8.3" "@babel/plugin-syntax-top-level-await" "^7.8.3" -babel-preset-jest@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz#57bc8cc88097af7ff6a5ab59d1cd29d52a5916e2" - integrity sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg== +babel-preset-jest@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" + integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== dependencies: - babel-plugin-jest-hoist "^29.5.0" + babel-plugin-jest-hoist "^29.6.3" babel-preset-current-node-syntax "^1.0.0" bail@^2.0.0: @@ -2822,7 +2829,7 @@ braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" -browserslist@^4.21.5, browserslist@^4.21.9: +browserslist@^4.21.10, browserslist@^4.21.5, browserslist@^4.21.9: version "4.21.10" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.10.tgz#dbbac576628c13d3b2231332cb2ec5a46e015bb0" integrity sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ== @@ -2898,9 +2905,9 @@ camelcase@^6.2.0: integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001464, caniuse-lite@^1.0.30001517: - version "1.0.30001520" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001520.tgz#62e2b7a1c7b35269594cf296a80bdf8cb9565006" - integrity sha512-tahF5O9EiiTzwTUqAeFjIZbn4Dnqxzz7ktrgGlMYNLH43Ul26IgTMH/zvL3DG0lZxBYnlT04axvInszUsZULdA== + version "1.0.30001522" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001522.tgz#44b87a406c901269adcdb834713e23582dd71856" + integrity sha512-TKiyTVZxJGhsTszLuzb+6vUZSjVOAhClszBr2Ta2k9IwtNBT/4dzmL6aywt0HCgEZlmwJzXJd8yNiob6HgwTRg== ccount@^2.0.0: version "2.0.1" @@ -3120,11 +3127,11 @@ cookie@0.5.0: integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== core-js-compat@^3.31.0: - version "3.32.0" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.32.0.tgz#f41574b6893ab15ddb0ac1693681bd56c8550a90" - integrity sha512-7a9a3D1k4UCVKnLhrgALyFcP7YCsLOQIxPd0dKjf/6GuPcgyiGP70ewWdCGrSK7evyhymi0qO4EqCmSJofDeYw== + version "3.32.1" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.32.1.tgz#55f9a7d297c0761a8eb1d31b593e0f5b6ffae964" + integrity sha512-GSvKDv4wE0bPnQtjklV101juQ85g6H3rm5PDP20mqlS5j0kXF3pP97YvAu5hl+uFHqMictp3b2VxOHljWMAtuA== dependencies: - browserslist "^4.21.9" + browserslist "^4.21.10" core-util-is@~1.0.0: version "1.0.3" @@ -3614,10 +3621,10 @@ didyoumean@^1.2.2: resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw== -diff-sequences@^29.4.3: - version "29.4.3" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2" - integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA== +diff-sequences@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== diff@^5.0.0: version "5.1.0" @@ -3723,9 +3730,9 @@ ecdsa-sig-formatter@1.0.11: safe-buffer "^5.0.1" electron-to-chromium@^1.4.477: - version "1.4.490" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.490.tgz#d99286f6e915667fa18ea4554def1aa60eb4d5f1" - integrity sha512-6s7NVJz+sATdYnIwhdshx/N/9O6rvMxmhVoDSDFdj6iA45gHR8EQje70+RYsF4GeB+k0IeNSBnP7yG9ZXJFr7A== + version "1.4.498" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.498.tgz#cef35341123f62a35ba7084e439c911d25e0d81b" + integrity sha512-4LODxAzKGVy7CJyhhN5mebwe7U2L29P+0G+HUriHnabm0d7LSff8Yn7t+Wq+2/9ze2Fu1dhX7mww090xfv7qXQ== emittery@^0.13.1: version "0.13.1" @@ -3769,7 +3776,7 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.19.0, es-abstract@^1.20.4, es-abstract@^1.21.2: +es-abstract@^1.19.0, es-abstract@^1.20.4, es-abstract@^1.21.2, es-abstract@^1.21.3: version "1.22.1" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.1.tgz#8b4e5fc5cefd7f1660f0f8e1a52900dfbc9d9ccc" integrity sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw== @@ -3829,6 +3836,26 @@ es-get-iterator@^1.1.3: isarray "^2.0.5" stop-iteration-iterator "^1.0.0" +es-iterator-helpers@^1.0.12: + version "1.0.13" + resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.13.tgz#72101046ffc19baf9996adc70e6177a26e6e8084" + integrity sha512-LK3VGwzvaPWobO8xzXXGRUOGw8Dcjyfk62CsY/wfHN75CwsJPbuypOYJxK6g5RyEL8YDjIWcl6jgd8foO6mmrA== + dependencies: + asynciterator.prototype "^1.0.0" + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.21.3" + es-set-tostringtag "^2.0.1" + function-bind "^1.1.1" + get-intrinsic "^1.2.1" + globalthis "^1.0.3" + has-property-descriptors "^1.0.0" + has-proto "^1.0.1" + has-symbols "^1.0.3" + internal-slot "^1.0.5" + iterator.prototype "^1.1.0" + safe-array-concat "^1.0.0" + es-set-tostringtag@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" @@ -3935,9 +3962,9 @@ eslint-module-utils@^2.7.4, eslint-module-utils@^2.8.0: debug "^3.2.7" eslint-plugin-import@^2.26.0: - version "2.28.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.28.0.tgz#8d66d6925117b06c4018d491ae84469eb3cb1005" - integrity sha512-B8s/n+ZluN7sxj9eUf7/pRFERX0r5bnFA2dCaLHy2ZeaQEAz0k+ZZkFWRFHJAqxfxQDx6KLv9LeIki7cFdwW+Q== + version "2.28.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz#63b8b5b3c409bfc75ebaf8fb206b07ab435482c4" + integrity sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A== dependencies: array-includes "^3.1.6" array.prototype.findlastindex "^1.2.2" @@ -3948,13 +3975,12 @@ eslint-plugin-import@^2.26.0: eslint-import-resolver-node "^0.3.7" eslint-module-utils "^2.8.0" has "^1.0.3" - is-core-module "^2.12.1" + is-core-module "^2.13.0" is-glob "^4.0.3" minimatch "^3.1.2" object.fromentries "^2.0.6" object.groupby "^1.0.0" object.values "^1.1.6" - resolve "^1.22.3" semver "^6.3.1" tsconfig-paths "^3.14.2" @@ -3986,14 +4012,15 @@ eslint-plugin-react-hooks@5.0.0-canary-7118f5dd7-20230705: integrity sha512-AZYbMo/NW9chdL7vk6HQzQhT+PvTAEVqWk9ziruUoW2kAOcN5qNyelv70e0F1VNQAbvutOC9oc+xfWycI9FxDw== eslint-plugin-react@^7.31.7: - version "7.33.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.33.1.tgz#bc27cccf860ae45413a4a4150bf0977345c1ceab" - integrity sha512-L093k0WAMvr6VhNwReB8VgOq5s2LesZmrpPdKz/kZElQDzqS7G7+DnKoqT+w4JwuiGeAhAvHO0fvy0Eyk4ejDA== + version "7.33.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz#69ee09443ffc583927eafe86ffebb470ee737608" + integrity sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw== dependencies: array-includes "^3.1.6" array.prototype.flatmap "^1.3.1" array.prototype.tosorted "^1.1.1" doctrine "^2.1.0" + es-iterator-helpers "^1.0.12" estraverse "^5.3.0" jsx-ast-utils "^2.4.1 || ^3.0.0" minimatch "^3.1.2" @@ -4125,17 +4152,16 @@ expand-template@^2.0.3: resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== -expect@^29.0.0, expect@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/expect/-/expect-29.6.2.tgz#7b08e83eba18ddc4a2cf62b5f2d1918f5cd84521" - integrity sha512-iAErsLxJ8C+S02QbLAwgSGSezLQK+XXRDt8IuFXFpwCNw2ECmzZSmjKcCaFVp5VRMk+WAvz6h6jokzEzBFZEuA== +expect@^29.0.0, expect@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.6.3.tgz#e74b57c35a81fd93ece6b570e371309c53dc4f54" + integrity sha512-x1vY4LlEMWUYVZQrFi4ZANXFwqYbJ/JNQspLVvzhW2BNY28aNcXMQH6imBbt+RBf5sVRTodYHXtSP/TLEU0Dxw== dependencies: - "@jest/expect-utils" "^29.6.2" - "@types/node" "*" - jest-get-type "^29.4.3" - jest-matcher-utils "^29.6.2" - jest-message-util "^29.6.2" - jest-util "^29.6.2" + "@jest/expect-utils" "^29.6.3" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.6.3" + jest-message-util "^29.6.3" + jest-util "^29.6.3" extend@^3.0.0: version "3.0.2" @@ -4261,9 +4287,9 @@ form-data@^4.0.0: mime-types "^2.1.12" fraction.js@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" - integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== + version "4.2.1" + resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.1.tgz#14b4cc886575a5684f8d5fd5759c5db376bb7bb8" + integrity sha512-/KxoyCnPM0GwYI4NN0Iag38Tqt+od3/mLuguepLgCAKPn0ZhC544nssAW0tG2/00zXEYl9W+7hwAIpLHo6Oc7Q== fs-constants@^1.0.0: version "1.0.0" @@ -4276,9 +4302,9 @@ fs.realpath@^1.0.0: integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== fsevents@^2.3.2, fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== function-bind@^1.1.1: version "1.1.1" @@ -4668,6 +4694,13 @@ is-arrayish@^0.3.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== +is-async-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.0.0.tgz#8e4418efd3e5d3a6ebb0164c05ef5afb69aa9646" + integrity sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA== + dependencies: + has-tostringtag "^1.0.0" + is-bigint@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" @@ -4700,7 +4733,7 @@ is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-core-module@^2.11.0, is-core-module@^2.12.1, is-core-module@^2.13.0, is-core-module@^2.9.0: +is-core-module@^2.11.0, is-core-module@^2.13.0, is-core-module@^2.9.0: version "2.13.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db" integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ== @@ -4719,6 +4752,13 @@ is-extglob@^2.1.1: resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== +is-finalizationregistry@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz#c8749b65f17c133313e661b1289b95ad3dbd62e6" + integrity sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw== + dependencies: + call-bind "^1.0.2" + is-fullwidth-code-point@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" @@ -4729,6 +4769,13 @@ is-generator-fn@^2.0.0: resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== +is-generator-function@^1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" + integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== + dependencies: + has-tostringtag "^1.0.0" + is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" @@ -4874,7 +4921,7 @@ istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== -istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: +istanbul-lib-instrument@^5.0.4: version "5.2.1" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== @@ -4885,6 +4932,17 @@ istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: istanbul-lib-coverage "^3.2.0" semver "^6.3.0" +istanbul-lib-instrument@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.0.tgz#7a8af094cbfff1d5bb280f62ce043695ae8dd5b8" + integrity sha512-x58orMzEVfzPUKqlbLd1hXCnySCxKdDKa6Rjg97CwuLLRI4g3FHTdnExu1OqffVFay6zeMW+T6/DowFLndWnIw== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^7.5.4" + istanbul-lib-report@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" @@ -4911,113 +4969,125 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -jest-changed-files@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.5.0.tgz#e88786dca8bf2aa899ec4af7644e16d9dcf9b23e" - integrity sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag== +iterator.prototype@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.0.tgz#690c88b043d821f783843aaf725d7ac3b62e3b46" + integrity sha512-rjuhAk1AJ1fssphHD0IFV6TWL40CwRZ53FrztKx43yk2v6rguBYsY4Bj1VU4HmoMmKwZUlx7mfnhDf9cOp4YTw== + dependencies: + define-properties "^1.1.4" + get-intrinsic "^1.1.3" + has-symbols "^1.0.3" + has-tostringtag "^1.0.0" + reflect.getprototypeof "^1.0.3" + +jest-changed-files@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.6.3.tgz#97cfdc93f74fb8af2a1acb0b78f836f1fb40c449" + integrity sha512-G5wDnElqLa4/c66ma5PG9eRjE342lIbF6SUnTJi26C3J28Fv2TVY2rOyKB9YGbSA5ogwevgmxc4j4aVjrEK6Yg== dependencies: execa "^5.0.0" + jest-util "^29.6.3" p-limit "^3.1.0" -jest-circus@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.6.2.tgz#1e6ffca60151ac66cad63fce34f443f6b5bb4258" - integrity sha512-G9mN+KOYIUe2sB9kpJkO9Bk18J4dTDArNFPwoZ7WKHKel55eKIS/u2bLthxgojwlf9NLCVQfgzM/WsOVvoC6Fw== +jest-circus@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.6.3.tgz#c5ac37758bb9e78fd78ebd655ed1d28b220d6fd3" + integrity sha512-p0R5YqZEMnOpHqHLWRSjm2z/0p6RNsrNE/GRRT3eli8QGOAozj6Ys/3Tv+Ej+IfltJoSPwcQ6/hOCRkNlxLLCw== dependencies: - "@jest/environment" "^29.6.2" - "@jest/expect" "^29.6.2" - "@jest/test-result" "^29.6.2" - "@jest/types" "^29.6.1" + "@jest/environment" "^29.6.3" + "@jest/expect" "^29.6.3" + "@jest/test-result" "^29.6.3" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" co "^4.6.0" dedent "^1.0.0" is-generator-fn "^2.0.0" - jest-each "^29.6.2" - jest-matcher-utils "^29.6.2" - jest-message-util "^29.6.2" - jest-runtime "^29.6.2" - jest-snapshot "^29.6.2" - jest-util "^29.6.2" + jest-each "^29.6.3" + jest-matcher-utils "^29.6.3" + jest-message-util "^29.6.3" + jest-runtime "^29.6.3" + jest-snapshot "^29.6.3" + jest-util "^29.6.3" p-limit "^3.1.0" - pretty-format "^29.6.2" + pretty-format "^29.6.3" pure-rand "^6.0.0" slash "^3.0.0" stack-utils "^2.0.3" jest-cli@^29.5.0: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.6.2.tgz#edb381763398d1a292cd1b636a98bfa5644b8fda" - integrity sha512-TT6O247v6dCEX2UGHGyflMpxhnrL0DNqP2fRTKYm3nJJpCTfXX3GCMQPGFjXDoj0i5/Blp3jriKXFgdfmbYB6Q== + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.6.3.tgz#1e6520106e9d7443a481ebe07ffed46e1568a51f" + integrity sha512-KuPdXUPXQIf0t6DvmG8MV4QyhcjR1a6ruKl3YL7aGn/AQ8JkROwFkWzEpDIpt11Qy188dHbRm8WjwMsV/4nmnQ== dependencies: - "@jest/core" "^29.6.2" - "@jest/test-result" "^29.6.2" - "@jest/types" "^29.6.1" + "@jest/core" "^29.6.3" + "@jest/test-result" "^29.6.3" + "@jest/types" "^29.6.3" chalk "^4.0.0" exit "^0.1.2" graceful-fs "^4.2.9" import-local "^3.0.2" - jest-config "^29.6.2" - jest-util "^29.6.2" - jest-validate "^29.6.2" + jest-config "^29.6.3" + jest-util "^29.6.3" + jest-validate "^29.6.3" prompts "^2.0.1" yargs "^17.3.1" -jest-config@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.6.2.tgz#c68723f06b31ca5e63030686e604727d406cd7c3" - integrity sha512-VxwFOC8gkiJbuodG9CPtMRjBUNZEHxwfQXmIudSTzFWxaci3Qub1ddTRbFNQlD/zUeaifLndh/eDccFX4wCMQw== +jest-config@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.6.3.tgz#2d1490005a28291806022f7f95ec3debf55eaaf7" + integrity sha512-nb9bOq2aEqogbyL4F9mLkAeQGAgNt7Uz6U59YtQDIxFPiL7Ejgq0YIrp78oyEHD6H4CIV/k7mFrK7eFDzUJ69w== dependencies: "@babel/core" "^7.11.6" - "@jest/test-sequencer" "^29.6.2" - "@jest/types" "^29.6.1" - babel-jest "^29.6.2" + "@jest/test-sequencer" "^29.6.3" + "@jest/types" "^29.6.3" + babel-jest "^29.6.3" chalk "^4.0.0" ci-info "^3.2.0" deepmerge "^4.2.2" glob "^7.1.3" graceful-fs "^4.2.9" - jest-circus "^29.6.2" - jest-environment-node "^29.6.2" - jest-get-type "^29.4.3" - jest-regex-util "^29.4.3" - jest-resolve "^29.6.2" - jest-runner "^29.6.2" - jest-util "^29.6.2" - jest-validate "^29.6.2" + jest-circus "^29.6.3" + jest-environment-node "^29.6.3" + jest-get-type "^29.6.3" + jest-regex-util "^29.6.3" + jest-resolve "^29.6.3" + jest-runner "^29.6.3" + jest-util "^29.6.3" + jest-validate "^29.6.3" micromatch "^4.0.4" parse-json "^5.2.0" - pretty-format "^29.6.2" + pretty-format "^29.6.3" slash "^3.0.0" strip-json-comments "^3.1.1" -jest-diff@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.6.2.tgz#c36001e5543e82a0805051d3ceac32e6825c1c46" - integrity sha512-t+ST7CB9GX5F2xKwhwCf0TAR17uNDiaPTZnVymP9lw0lssa9vG+AFyDZoeIHStU3WowFFwT+ky+er0WVl2yGhA== +jest-diff@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.6.3.tgz#365c6b037ea8e67d2f2af68bc018fc18d44311f0" + integrity sha512-3sw+AdWnwH9sSNohMRKA7JiYUJSRr/WS6+sEFfBuhxU5V5GlEVKfvUn8JuMHE0wqKowemR1C2aHy8VtXbaV8dQ== dependencies: chalk "^4.0.0" - diff-sequences "^29.4.3" - jest-get-type "^29.4.3" - pretty-format "^29.6.2" + diff-sequences "^29.6.3" + jest-get-type "^29.6.3" + pretty-format "^29.6.3" -jest-docblock@^29.4.3: - version "29.4.3" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.4.3.tgz#90505aa89514a1c7dceeac1123df79e414636ea8" - integrity sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg== +jest-docblock@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.6.3.tgz#293dca5188846c9f7c0c2b1bb33e5b11f21645f2" + integrity sha512-2+H+GOTQBEm2+qFSQ7Ma+BvyV+waiIFxmZF5LdpBsAEjWX8QYjSCa4FrkIYtbfXUJJJnFCYrOtt6TZ+IAiTjBQ== dependencies: detect-newline "^3.0.0" -jest-each@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.6.2.tgz#c9e4b340bcbe838c73adf46b76817b15712d02ce" - integrity sha512-MsrsqA0Ia99cIpABBc3izS1ZYoYfhIy0NNWqPSE0YXbQjwchyt6B1HD2khzyPe1WiJA7hbxXy77ZoUQxn8UlSw== +jest-each@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.6.3.tgz#1956f14f5f0cb8ae0b2e7cabc10bb03ec817c142" + integrity sha512-KoXfJ42k8cqbkfshW7sSHcdfnv5agDdHCPA87ZBdmHP+zJstTJc0ttQaJ/x7zK6noAL76hOuTIJ6ZkQRS5dcyg== dependencies: - "@jest/types" "^29.6.1" + "@jest/types" "^29.6.3" chalk "^4.0.0" - jest-get-type "^29.4.3" - jest-util "^29.6.2" - pretty-format "^29.6.2" + jest-get-type "^29.6.3" + jest-util "^29.6.3" + pretty-format "^29.6.3" jest-environment-jsdom@29.5.0: version "29.5.0" @@ -5033,243 +5103,243 @@ jest-environment-jsdom@29.5.0: jest-util "^29.5.0" jsdom "^20.0.0" -jest-environment-node@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.6.2.tgz#a9ea2cabff39b08eca14ccb32c8ceb924c8bb1ad" - integrity sha512-YGdFeZ3T9a+/612c5mTQIllvWkddPbYcN2v95ZH24oWMbGA4GGS2XdIF92QMhUhvrjjuQWYgUGW2zawOyH63MQ== +jest-environment-node@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.6.3.tgz#72217a00db2c26755406241c70ad73c334917e28" + integrity sha512-PKl7upfPJXMYbWpD+60o4HP86KvFO2c9dZ+Zr6wUzsG5xcPx/65o3ArNgHW5M0RFvLYdW4/aieR4JSooD0a2ew== dependencies: - "@jest/environment" "^29.6.2" - "@jest/fake-timers" "^29.6.2" - "@jest/types" "^29.6.1" + "@jest/environment" "^29.6.3" + "@jest/fake-timers" "^29.6.3" + "@jest/types" "^29.6.3" "@types/node" "*" - jest-mock "^29.6.2" - jest-util "^29.6.2" + jest-mock "^29.6.3" + jest-util "^29.6.3" -jest-get-type@^29.4.3: - version "29.4.3" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.4.3.tgz#1ab7a5207c995161100b5187159ca82dd48b3dd5" - integrity sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg== +jest-get-type@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" + integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== -jest-haste-map@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.6.2.tgz#298c25ea5255cfad8b723179d4295cf3a50a70d1" - integrity sha512-+51XleTDAAysvU8rT6AnS1ZJ+WHVNqhj1k6nTvN2PYP+HjU3kqlaKQ1Lnw3NYW3bm2r8vq82X0Z1nDDHZMzHVA== +jest-haste-map@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.6.3.tgz#a53ac35a137fd32d932039aab29d02a9dab30689" + integrity sha512-GecR5YavfjkhOytEFHAeI6aWWG3f/cOKNB1YJvj/B76xAmeVjy4zJUYobGF030cRmKaO1FBw3V8CZZ6KVh9ZSw== dependencies: - "@jest/types" "^29.6.1" + "@jest/types" "^29.6.3" "@types/graceful-fs" "^4.1.3" "@types/node" "*" anymatch "^3.0.3" fb-watchman "^2.0.0" graceful-fs "^4.2.9" - jest-regex-util "^29.4.3" - jest-util "^29.6.2" - jest-worker "^29.6.2" + jest-regex-util "^29.6.3" + jest-util "^29.6.3" + jest-worker "^29.6.3" micromatch "^4.0.4" walker "^1.0.8" optionalDependencies: fsevents "^2.3.2" -jest-leak-detector@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.6.2.tgz#e2b307fee78cab091c37858a98c7e1d73cdf5b38" - integrity sha512-aNqYhfp5uYEO3tdWMb2bfWv6f0b4I0LOxVRpnRLAeque2uqOVVMLh6khnTcE2qJ5wAKop0HcreM1btoysD6bPQ== +jest-leak-detector@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.6.3.tgz#b9661bc3aec8874e59aff361fa0c6d7cd507ea01" + integrity sha512-0kfbESIHXYdhAdpLsW7xdwmYhLf1BRu4AA118/OxFm0Ho1b2RcTmO4oF6aAMaxpxdxnJ3zve2rgwzNBD4Zbm7Q== dependencies: - jest-get-type "^29.4.3" - pretty-format "^29.6.2" + jest-get-type "^29.6.3" + pretty-format "^29.6.3" -jest-matcher-utils@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.6.2.tgz#39de0be2baca7a64eacb27291f0bd834fea3a535" - integrity sha512-4LiAk3hSSobtomeIAzFTe+N8kL6z0JtF3n6I4fg29iIW7tt99R7ZcIFW34QkX+DuVrf+CUe6wuVOpm7ZKFJzZQ== +jest-matcher-utils@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.6.3.tgz#a7574092b635d96a38fa0a22d015fb596b9c2efc" + integrity sha512-6ZrMYINZdwduSt5Xu18/n49O1IgXdjsfG7NEZaQws9k69eTKWKcVbJBw/MZsjOZe2sSyJFmuzh8042XWwl54Zg== dependencies: chalk "^4.0.0" - jest-diff "^29.6.2" - jest-get-type "^29.4.3" - pretty-format "^29.6.2" + jest-diff "^29.6.3" + jest-get-type "^29.6.3" + pretty-format "^29.6.3" -jest-message-util@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.6.2.tgz#af7adc2209c552f3f5ae31e77cf0a261f23dc2bb" - integrity sha512-vnIGYEjoPSuRqV8W9t+Wow95SDp6KPX2Uf7EoeG9G99J2OVh7OSwpS4B6J0NfpEIpfkBNHlBZpA2rblEuEFhZQ== +jest-message-util@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.6.3.tgz#bce16050d86801b165f20cfde34dc01d3cf85fbf" + integrity sha512-FtzaEEHzjDpQp51HX4UMkPZjy46ati4T5pEMyM6Ik48ztu4T9LQplZ6OsimHx7EuM9dfEh5HJa6D3trEftu3dA== dependencies: "@babel/code-frame" "^7.12.13" - "@jest/types" "^29.6.1" + "@jest/types" "^29.6.3" "@types/stack-utils" "^2.0.0" chalk "^4.0.0" graceful-fs "^4.2.9" micromatch "^4.0.4" - pretty-format "^29.6.2" + pretty-format "^29.6.3" slash "^3.0.0" stack-utils "^2.0.3" -jest-mock@^29.5.0, jest-mock@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.6.2.tgz#ef9c9b4d38c34a2ad61010a021866dad41ce5e00" - integrity sha512-hoSv3lb3byzdKfwqCuT6uTscan471GUECqgNYykg6ob0yiAw3zYc7OrPnI9Qv8Wwoa4lC7AZ9hyS4AiIx5U2zg== +jest-mock@^29.5.0, jest-mock@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.6.3.tgz#433f3fd528c8ec5a76860177484940628bdf5e0a" + integrity sha512-Z7Gs/mOyTSR4yPsaZ72a/MtuK6RnC3JYqWONe48oLaoEcYwEDxqvbXz85G4SJrm2Z5Ar9zp6MiHF4AlFlRM4Pg== dependencies: - "@jest/types" "^29.6.1" + "@jest/types" "^29.6.3" "@types/node" "*" - jest-util "^29.6.2" + jest-util "^29.6.3" jest-pnp-resolver@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== -jest-regex-util@^29.4.3: - version "29.4.3" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.4.3.tgz#a42616141e0cae052cfa32c169945d00c0aa0bb8" - integrity sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg== +jest-regex-util@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" + integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== -jest-resolve-dependencies@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.6.2.tgz#36435269b6672c256bcc85fb384872c134cc4cf2" - integrity sha512-LGqjDWxg2fuQQm7ypDxduLu/m4+4Lb4gczc13v51VMZbVP5tSBILqVx8qfWcsdP8f0G7aIqByIALDB0R93yL+w== +jest-resolve-dependencies@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.6.3.tgz#fc58ac08f9ed992b10d5cfb0bbb1d89b98508ff3" + integrity sha512-iah5nhSPTwtUV7yzpTc9xGg8gP3Ch2VNsuFMsKoCkNCrQSbFtx5KRPemmPJ32AUhTSDqJXB6djPN6zAaUGV53g== dependencies: - jest-regex-util "^29.4.3" - jest-snapshot "^29.6.2" + jest-regex-util "^29.6.3" + jest-snapshot "^29.6.3" -jest-resolve@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.6.2.tgz#f18405fe4b50159b7b6d85e81f6a524d22afb838" - integrity sha512-G/iQUvZWI5e3SMFssc4ug4dH0aZiZpsDq9o1PtXTV1210Ztyb2+w+ZgQkB3iOiC5SmAEzJBOHWz6Hvrd+QnNPw== +jest-resolve@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.6.3.tgz#e3114e1514973c8f1607387c3042f4d2926f2d60" + integrity sha512-WMXwxhvzDeA/J+9jz1i8ZKGmbw/n+s988EiUvRI4egM+eTn31Hb5v10Re3slG3/qxntkBt2/6GkQVDGu6Bwyhw== dependencies: chalk "^4.0.0" graceful-fs "^4.2.9" - jest-haste-map "^29.6.2" + jest-haste-map "^29.6.3" jest-pnp-resolver "^1.2.2" - jest-util "^29.6.2" - jest-validate "^29.6.2" + jest-util "^29.6.3" + jest-validate "^29.6.3" resolve "^1.20.0" resolve.exports "^2.0.0" slash "^3.0.0" -jest-runner@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.6.2.tgz#89e8e32a8fef24781a7c4c49cd1cb6358ac7fc01" - integrity sha512-wXOT/a0EspYgfMiYHxwGLPCZfC0c38MivAlb2lMEAlwHINKemrttu1uSbcGbfDV31sFaPWnWJPmb2qXM8pqZ4w== +jest-runner@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.6.3.tgz#162b1a549c4728265e716d75533b65b4c77e6b22" + integrity sha512-E4zsMhQnjhirFPhDTJgoLMWUrVCDij/KGzWlbslDHGuO8Hl2pVUfOiygMzVZtZq+BzmlqwEr7LYmW+WFLlmX8w== dependencies: - "@jest/console" "^29.6.2" - "@jest/environment" "^29.6.2" - "@jest/test-result" "^29.6.2" - "@jest/transform" "^29.6.2" - "@jest/types" "^29.6.1" + "@jest/console" "^29.6.3" + "@jest/environment" "^29.6.3" + "@jest/test-result" "^29.6.3" + "@jest/transform" "^29.6.3" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" emittery "^0.13.1" graceful-fs "^4.2.9" - jest-docblock "^29.4.3" - jest-environment-node "^29.6.2" - jest-haste-map "^29.6.2" - jest-leak-detector "^29.6.2" - jest-message-util "^29.6.2" - jest-resolve "^29.6.2" - jest-runtime "^29.6.2" - jest-util "^29.6.2" - jest-watcher "^29.6.2" - jest-worker "^29.6.2" + jest-docblock "^29.6.3" + jest-environment-node "^29.6.3" + jest-haste-map "^29.6.3" + jest-leak-detector "^29.6.3" + jest-message-util "^29.6.3" + jest-resolve "^29.6.3" + jest-runtime "^29.6.3" + jest-util "^29.6.3" + jest-watcher "^29.6.3" + jest-worker "^29.6.3" p-limit "^3.1.0" source-map-support "0.5.13" -jest-runtime@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.6.2.tgz#692f25e387f982e89ab83270e684a9786248e545" - integrity sha512-2X9dqK768KufGJyIeLmIzToDmsN0m7Iek8QNxRSI/2+iPFYHF0jTwlO3ftn7gdKd98G/VQw9XJCk77rbTGZnJg== - dependencies: - "@jest/environment" "^29.6.2" - "@jest/fake-timers" "^29.6.2" - "@jest/globals" "^29.6.2" - "@jest/source-map" "^29.6.0" - "@jest/test-result" "^29.6.2" - "@jest/transform" "^29.6.2" - "@jest/types" "^29.6.1" +jest-runtime@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.6.3.tgz#8bfa29447808419a7b5bed13beb0447a90344c65" + integrity sha512-VM0Z3a9xaqizGpEKwCOIhImkrINYzxgwk8oQAvrmAiXX8LNrJrRjyva30RkuRY0ETAotHLlUcd2moviCA1hgsQ== + dependencies: + "@jest/environment" "^29.6.3" + "@jest/fake-timers" "^29.6.3" + "@jest/globals" "^29.6.3" + "@jest/source-map" "^29.6.3" + "@jest/test-result" "^29.6.3" + "@jest/transform" "^29.6.3" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" cjs-module-lexer "^1.0.0" collect-v8-coverage "^1.0.0" glob "^7.1.3" graceful-fs "^4.2.9" - jest-haste-map "^29.6.2" - jest-message-util "^29.6.2" - jest-mock "^29.6.2" - jest-regex-util "^29.4.3" - jest-resolve "^29.6.2" - jest-snapshot "^29.6.2" - jest-util "^29.6.2" + jest-haste-map "^29.6.3" + jest-message-util "^29.6.3" + jest-mock "^29.6.3" + jest-regex-util "^29.6.3" + jest-resolve "^29.6.3" + jest-snapshot "^29.6.3" + jest-util "^29.6.3" slash "^3.0.0" strip-bom "^4.0.0" -jest-snapshot@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.6.2.tgz#9b431b561a83f2bdfe041e1cab8a6becdb01af9c" - integrity sha512-1OdjqvqmRdGNvWXr/YZHuyhh5DeaLp1p/F8Tht/MrMw4Kr1Uu/j4lRG+iKl1DAqUJDWxtQBMk41Lnf/JETYBRA== +jest-snapshot@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.6.3.tgz#2435b50881f7bffdc1a66e66c64a2602c8086281" + integrity sha512-66Iu7H1ojiveQMGFnKecHIZPPPBjZwfQEnF6wxqpxGf57sV3YSUtAb5/sTKM5TPa3OndyxZp1wxHFbmgVhc53w== dependencies: "@babel/core" "^7.11.6" "@babel/generator" "^7.7.2" "@babel/plugin-syntax-jsx" "^7.7.2" "@babel/plugin-syntax-typescript" "^7.7.2" "@babel/types" "^7.3.3" - "@jest/expect-utils" "^29.6.2" - "@jest/transform" "^29.6.2" - "@jest/types" "^29.6.1" + "@jest/expect-utils" "^29.6.3" + "@jest/transform" "^29.6.3" + "@jest/types" "^29.6.3" babel-preset-current-node-syntax "^1.0.0" chalk "^4.0.0" - expect "^29.6.2" + expect "^29.6.3" graceful-fs "^4.2.9" - jest-diff "^29.6.2" - jest-get-type "^29.4.3" - jest-matcher-utils "^29.6.2" - jest-message-util "^29.6.2" - jest-util "^29.6.2" + jest-diff "^29.6.3" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.6.3" + jest-message-util "^29.6.3" + jest-util "^29.6.3" natural-compare "^1.4.0" - pretty-format "^29.6.2" + pretty-format "^29.6.3" semver "^7.5.3" -jest-util@^29.5.0, jest-util@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.6.2.tgz#8a052df8fff2eebe446769fd88814521a517664d" - integrity sha512-3eX1qb6L88lJNCFlEADKOkjpXJQyZRiavX1INZ4tRnrBVr2COd3RgcTLyUiEXMNBlDU/cgYq6taUS0fExrWW4w== +jest-util@^29.5.0, jest-util@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.6.3.tgz#e15c3eac8716440d1ed076f09bc63ace1aebca63" + integrity sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA== dependencies: - "@jest/types" "^29.6.1" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" ci-info "^3.2.0" graceful-fs "^4.2.9" picomatch "^2.2.3" -jest-validate@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.6.2.tgz#25d972af35b2415b83b1373baf1a47bb266c1082" - integrity sha512-vGz0yMN5fUFRRbpJDPwxMpgSXW1LDKROHfBopAvDcmD6s+B/s8WJrwi+4bfH4SdInBA5C3P3BI19dBtKzx1Arg== +jest-validate@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.6.3.tgz#a75fca774cfb1c5758c70d035d30a1f9c2784b4d" + integrity sha512-e7KWZcAIX+2W1o3cHfnqpGajdCs1jSM3DkXjGeLSNmCazv1EeI1ggTeK5wdZhF+7N+g44JI2Od3veojoaumlfg== dependencies: - "@jest/types" "^29.6.1" + "@jest/types" "^29.6.3" camelcase "^6.2.0" chalk "^4.0.0" - jest-get-type "^29.4.3" + jest-get-type "^29.6.3" leven "^3.1.0" - pretty-format "^29.6.2" + pretty-format "^29.6.3" -jest-watcher@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.6.2.tgz#77c224674f0620d9f6643c4cfca186d8893ca088" - integrity sha512-GZitlqkMkhkefjfN/p3SJjrDaxPflqxEAv3/ik10OirZqJGYH5rPiIsgVcfof0Tdqg3shQGdEIxDBx+B4tuLzA== +jest-watcher@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.6.3.tgz#f5089852fc5f57ba1d956ec02d80cf2f6f34156d" + integrity sha512-NgpFjZ2U2MKusjidbi4Oiu7tfs+nrgdIxIEVROvH1cFmOei9Uj25lwkMsakqLnH/s0nEcvxO1ck77FiRlcnpZg== dependencies: - "@jest/test-result" "^29.6.2" - "@jest/types" "^29.6.1" + "@jest/test-result" "^29.6.3" + "@jest/types" "^29.6.3" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" emittery "^0.13.1" - jest-util "^29.6.2" + jest-util "^29.6.3" string-length "^4.0.1" -jest-worker@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.6.2.tgz#682fbc4b6856ad0aa122a5403c6d048b83f3fb44" - integrity sha512-l3ccBOabTdkng8I/ORCkADz4eSMKejTYv1vB/Z83UiubqhC1oQ5Li6dWCyqOIvSifGjUBxuvxvlm6KGK2DtuAQ== +jest-worker@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.6.3.tgz#7b1a47bbb6559f3c0882d16595938590e63915d5" + integrity sha512-wacANXecZ/GbQakpf2CClrqrlwsYYDSXFd4fIGdL+dXpM2GWoJ+6bhQ7vR3TKi3+gkSfBkjy1/khH/WrYS4Q6g== dependencies: "@types/node" "*" - jest-util "^29.6.2" + jest-util "^29.6.3" merge-stream "^2.0.0" supports-color "^8.0.0" @@ -5284,9 +5354,9 @@ jest@29.5.0: jest-cli "^29.5.0" jiti@^1.18.2: - version "1.19.1" - resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.19.1.tgz#fa99e4b76a23053e0e7cde098efe1704a14c16f1" - integrity sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg== + version "1.19.3" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.19.3.tgz#ef554f76465b3c2b222dc077834a71f0d4a37569" + integrity sha512-5eEbBDQT/jF1xg6l36P+mWGGoH9Spuy0PCdSr2dtWRDGC6ph/w9ZCL4lmESW8f8F7MwT3XKescfP0wnZWAKL9w== "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" @@ -6131,9 +6201,9 @@ no-case@^3.0.4: tslib "^2.0.3" node-abi@^3.3.0: - version "3.45.0" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.45.0.tgz#f568f163a3bfca5aacfce1fbeee1fa2cc98441f5" - integrity sha512-iwXuFrMAcFVi/ZoZiqq8BzAdsLw9kxDfTC0HMyjXfSL/6CSDAGD5UmR7azrAgWV1zKYq7dUUMj4owusBWKLsiQ== + version "3.47.0" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.47.0.tgz#6cbfa2916805ae25c2b7156ca640131632eb05e8" + integrity sha512-2s6B2CWZM//kPgwnuI0KrYwNjfdByE25zvAaEpq9IH4zcNsarH8Ihu/UuX6XMPEogDAxkuUFeZn60pXNHAqn3A== dependencies: semver "^7.3.5" @@ -6517,9 +6587,9 @@ postcss@8.4.24: source-map-js "^1.0.2" postcss@^8.4.23: - version "8.4.27" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.27.tgz#234d7e4b72e34ba5a92c29636734349e0d9c3057" - integrity sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ== + version "8.4.28" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.28.tgz#c6cc681ed00109072816e1557f889ef51cf950a5" + integrity sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw== dependencies: nanoid "^3.3.6" picocolors "^1.0.0" @@ -6557,12 +6627,12 @@ pretty-format@^27.0.2: ansi-styles "^5.0.0" react-is "^17.0.1" -pretty-format@^29.0.0, pretty-format@^29.6.2: - version "29.6.2" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.6.2.tgz#3d5829261a8a4d89d8b9769064b29c50ed486a47" - integrity sha512-1q0oC8eRveTg5nnBEWMXAU2qpv65Gnuf2eCQzSjxpWFkPaPARwqZZDGuNE0zPAZfTCHzIk3A8dIjwlQKKLphyg== +pretty-format@^29.0.0, pretty-format@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.6.3.tgz#d432bb4f1ca6f9463410c3fb25a0ba88e594ace7" + integrity sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw== dependencies: - "@jest/schemas" "^29.6.0" + "@jest/schemas" "^29.6.3" ansi-styles "^5.0.0" react-is "^18.0.0" @@ -6775,6 +6845,18 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" +reflect.getprototypeof@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.3.tgz#2738fd896fcc3477ffbd4190b40c2458026b6928" + integrity sha512-TTAOZpkJ2YLxl7mVHWrNo3iDMEkYlva/kgFcXndqMgbo/AZUmmavEkdXV+hXtE4P8xdyEKRzalaFqZVuwIk/Nw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + get-intrinsic "^1.1.1" + globalthis "^1.0.3" + which-builtin-type "^1.1.3" + regenerate-unicode-properties@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz#7c3192cab6dd24e21cb4461e5ddd7dd24fa8374c" @@ -6902,7 +6984,7 @@ resolve.exports@^2.0.0: resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== -resolve@^1.1.7, resolve@^1.10.0, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.2, resolve@^1.22.3, resolve@^1.22.4: +resolve@^1.1.7, resolve@^1.10.0, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.2, resolve@^1.22.4: version "1.22.4" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.4.tgz#1dc40df46554cdaf8948a486a10f6ba1e2026c34" integrity sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg== @@ -7537,9 +7619,9 @@ trough@^2.0.0: integrity sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g== ts-api-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.1.tgz#8144e811d44c749cd65b2da305a032510774452d" - integrity sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A== + version "1.0.2" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.2.tgz#7c094f753b6705ee4faee25c3c684ade52d66d99" + integrity sha512-Cbu4nIqnEdd+THNEsBdkolnOXhg0I8XteoHaEKgvsxpsbWda4IsUut2c187HxywQCvveojow0Dgw/amxtSKVkQ== ts-interface-checker@^0.1.9: version "0.1.13" @@ -7562,9 +7644,9 @@ tslib@^1.8.1: integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== tslib@^2.0.0, tslib@^2.0.3, tslib@^2.4.0: - version "2.6.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.1.tgz#fd8c9a0ff42590b25703c0acb3de3d3f4ede0410" - integrity sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig== + version "2.6.2" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" + integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== tsutils@^3.21.0: version "3.21.0" @@ -7924,6 +8006,24 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" +which-builtin-type@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.1.3.tgz#b1b8443707cc58b6e9bf98d32110ff0c2cbd029b" + integrity sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw== + dependencies: + function.prototype.name "^1.1.5" + has-tostringtag "^1.0.0" + is-async-function "^2.0.0" + is-date-object "^1.0.5" + is-finalizationregistry "^1.0.2" + is-generator-function "^1.0.10" + is-regex "^1.1.4" + is-weakref "^1.0.2" + isarray "^2.0.5" + which-boxed-primitive "^1.0.2" + which-collection "^1.0.1" + which-typed-array "^1.1.9" + which-collection@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906"