diff --git a/ui/src/Pages/PeoplePage/PeoplePage.test.tsx b/ui/src/Pages/PeoplePage/PeoplePage.test.tsx
new file mode 100644
index 0000000..0d9db98
--- /dev/null
+++ b/ui/src/Pages/PeoplePage/PeoplePage.test.tsx
@@ -0,0 +1,102 @@
+import '@testing-library/jest-dom'
+
+import React from 'react'
+import { render, screen, waitFor } from '@testing-library/react'
+import PeoplePage, { MY_FACES_QUERY } from './PeoplePage'
+import { MockedProvider } from '@apollo/client/testing'
+import { MemoryRouter } from 'react-router'
+
+require('../../localization').setupLocalization()
+
+jest.mock('../../hooks/useScrollPagination', () =>
+  jest.fn(() => ({
+    finished: true,
+    containerElem: jest.fn(),
+  }))
+)
+
+const graphqlMocks = [
+  {
+    request: {
+      query: MY_FACES_QUERY,
+      variables: {
+        limit: 50,
+        offset: 0,
+      },
+    },
+    result: {
+      data: {
+        myFaceGroups: [
+          {
+            __typename: 'FaceGroup',
+            id: '3',
+            label: 'Person A',
+            imageFaceCount: 2,
+            imageFaces: [
+              {
+                __typename: 'ImageFace',
+                id: '3',
+                rectangle: {
+                  __typename: 'FaceRectangle',
+                  minX: 0.2705079913139343,
+                  maxX: 0.3408200144767761,
+                  minY: 0.7691109776496887,
+                  maxY: 0.881434977054596,
+                },
+                media: {
+                  __typename: 'Media',
+                  id: '63',
+                  thumbnail: {
+                    __typename: 'MediaURL',
+                    url: 'http://localhost:4001/photo/thumbnail_L%C3%B8berute_jpg_p9x8dLWr.jpg',
+                    width: 1024,
+                    height: 641,
+                  },
+                },
+              },
+            ],
+          },
+          {
+            __typename: 'FaceGroup',
+            id: '1',
+            label: 'Person B',
+            imageFaceCount: 1,
+            imageFaces: [],
+          },
+        ],
+      },
+    },
+  },
+]
+
+test('people page', async () => {
+  const matchMock = {
+    params: {
+      person: undefined,
+    },
+  }
+
+  render(
+    <MemoryRouter initialEntries={['/people']}>
+      <MockedProvider mocks={graphqlMocks} addTypename={false}>
+        <PeoplePage match={matchMock} />
+      </MockedProvider>
+    </MemoryRouter>
+  )
+
+  expect(screen.getByTestId('Layout')).toBeInTheDocument()
+  expect(screen.getByText('Recognize unlabeled faces')).toBeInTheDocument()
+
+  await waitFor(() => {
+    expect(screen.getByText('Person A')).toBeInTheDocument()
+    expect(screen.getByText('Person B')).toBeInTheDocument()
+  })
+
+  expect(
+    screen.getAllByRole('link').some(x => x.getAttribute('href') == '/people/1')
+  ).toBeTruthy()
+
+  expect(
+    screen.getAllByRole('link').some(x => x.getAttribute('href') == '/people/3')
+  ).toBeTruthy()
+})
diff --git a/ui/src/Pages/PeoplePage/PeoplePage.js b/ui/src/Pages/PeoplePage/PeoplePage.tsx
similarity index 76%
rename from ui/src/Pages/PeoplePage/PeoplePage.js
rename to ui/src/Pages/PeoplePage/PeoplePage.tsx
index 991447b..2a625cd 100644
--- a/ui/src/Pages/PeoplePage/PeoplePage.js
+++ b/ui/src/Pages/PeoplePage/PeoplePage.tsx
@@ -1,5 +1,4 @@
 import React, { createRef, useEffect, useState } from 'react'
-import PropTypes from 'prop-types'
 import { gql, useMutation, useQuery } from '@apollo/client'
 import Layout from '../../Layout'
 import styled from 'styled-components'
@@ -10,6 +9,16 @@ import FaceCircleImage from './FaceCircleImage'
 import useScrollPagination from '../../hooks/useScrollPagination'
 import PaginateLoader from '../../components/PaginateLoader'
 import { useTranslation } from 'react-i18next'
+import {
+  setGroupLabel,
+  setGroupLabelVariables,
+} from './__generated__/setGroupLabel'
+import {
+  myFaces,
+  myFacesVariables,
+  myFaces_myFaceGroups,
+} from './__generated__/myFaces'
+import { recognizeUnlabeledFaces } from './__generated__/recognizeUnlabeledFaces'
 
 export const MY_FACES_QUERY = gql`
   query myFaces($limit: Int, $offset: Int) {
@@ -55,7 +64,7 @@ const RECOGNIZE_UNLABELED_FACES_MUTATION = gql`
   }
 `
 
-const FaceDetailsButton = styled.button`
+const FaceDetailsButton = styled.button<{ labeled: boolean }>`
   color: ${({ labeled }) => (labeled ? 'black' : '#aaa')};
   width: 150px;
   margin: 12px auto 24px;
@@ -73,13 +82,20 @@ const FaceDetailsButton = styled.button`
 
 const FaceLabel = styled.span``
 
-const FaceDetails = ({ group }) => {
+type FaceDetailsProps = {
+  group: myFaces_myFaceGroups
+}
+
+const FaceDetails = ({ group }: FaceDetailsProps) => {
   const { t } = useTranslation()
   const [editLabel, setEditLabel] = useState(false)
   const [inputValue, setInputValue] = useState(group.label ?? '')
-  const inputRef = createRef()
+  const inputRef = createRef<Input>()
 
-  const [setGroupLabel, { loading }] = useMutation(SET_GROUP_LABEL_MUTATION, {
+  const [setGroupLabel, { loading }] = useMutation<
+    setGroupLabel,
+    setGroupLabelVariables
+  >(SET_GROUP_LABEL_MUTATION, {
     variables: {
       groupID: group.id,
     },
@@ -91,9 +107,7 @@ const FaceDetails = ({ group }) => {
   }
 
   useEffect(() => {
-    if (inputRef.current) {
-      inputRef.current.focus()
-    }
+    inputRef.current?.focus()
   }, [inputRef])
 
   useEffect(() => {
@@ -102,7 +116,7 @@ const FaceDetails = ({ group }) => {
     }
   }, [loading])
 
-  const onKeyUp = e => {
+  const onKeyUp = (e: React.ChangeEvent<HTMLInputElement> & KeyboardEvent) => {
     if (e.key == 'Escape') {
       resetLabel()
       return
@@ -111,6 +125,7 @@ const FaceDetails = ({ group }) => {
     if (e.key == 'Enter') {
       setGroupLabel({
         variables: {
+          groupID: group.id,
           label: e.target.value == '' ? null : e.target.value,
         },
       })
@@ -155,10 +170,6 @@ const FaceDetails = ({ group }) => {
   return label
 }
 
-FaceDetails.propTypes = {
-  group: PropTypes.object.isRequired,
-}
-
 const FaceImagesCount = styled.span`
   background-color: #eee;
   color: #222;
@@ -179,7 +190,11 @@ const EditIcon = styled(Icon)`
   }
 `
 
-const FaceGroup = ({ group }) => {
+type FaceGroupProps = {
+  group: myFaces_myFaceGroups
+}
+
+const FaceGroup = ({ group }: FaceGroupProps) => {
   const previewFace = group.imageFaces[0]
 
   return (
@@ -192,10 +207,6 @@ const FaceGroup = ({ group }) => {
   )
 }
 
-FaceGroup.propTypes = {
-  group: PropTypes.any,
-}
-
 const FaceGroupsWrapper = styled.div`
   display: flex;
   flex-wrap: wrap;
@@ -204,27 +215,29 @@ const FaceGroupsWrapper = styled.div`
 
 const PeopleGallery = () => {
   const { t } = useTranslation()
-  const { data, error, loading, fetchMore } = useQuery(MY_FACES_QUERY, {
+  const { data, error, loading, fetchMore } = useQuery<
+    myFaces,
+    myFacesVariables
+  >(MY_FACES_QUERY, {
     variables: {
       limit: 50,
       offset: 0,
     },
   })
 
-  const [
-    recognizeUnlabeled,
-    { loading: recognizeUnlabeledLoading },
-  ] = useMutation(RECOGNIZE_UNLABELED_FACES_MUTATION)
+  const [recognizeUnlabeled, { loading: recognizeUnlabeledLoading }] =
+    useMutation<recognizeUnlabeledFaces>(RECOGNIZE_UNLABELED_FACES_MUTATION)
 
-  const { containerElem, finished: finishedLoadingMore } = useScrollPagination({
-    loading,
-    fetchMore,
-    data,
-    getItems: data => data.myFaceGroups,
-  })
+  const { containerElem, finished: finishedLoadingMore } =
+    useScrollPagination<myFaces>({
+      loading,
+      fetchMore,
+      data,
+      getItems: data => data.myFaceGroups,
+    })
 
   if (error) {
-    return error.message
+    return <div>{error.message}</div>
   }
 
   let faces = null
@@ -258,11 +271,20 @@ const PeopleGallery = () => {
   )
 }
 
-const PeoplePage = ({ match }) => {
+type PeoplePageProps = {
+  match: {
+    params: {
+      person?: string
+    }
+  }
+}
+
+const PeoplePage = ({ match }: PeoplePageProps) => {
+  const { t } = useTranslation()
   const faceGroup = match.params.person
   if (faceGroup) {
     return (
-      <Layout>
+      <Layout title={t('title.people', 'People')}>
         <SingleFaceGroup faceGroupID={faceGroup} />
       </Layout>
     )
@@ -271,8 +293,4 @@ const PeoplePage = ({ match }) => {
   }
 }
 
-PeoplePage.propTypes = {
-  match: PropTypes.object.isRequired,
-}
-
 export default PeoplePage
diff --git a/ui/src/Pages/SharePage/SharePage.test.js b/ui/src/Pages/SharePage/SharePage.test.js
index bd85758..1dbf8d9 100644
--- a/ui/src/Pages/SharePage/SharePage.test.js
+++ b/ui/src/Pages/SharePage/SharePage.test.js
@@ -110,7 +110,7 @@ describe('load correct share page, based on graphql query', () => {
 
     expect(screen.getByText('Loading...')).toBeInTheDocument()
 
-    await waitForElementToBeRemoved(() => screen.getByText('Loading...'))
+    await waitForElementToBeRemoved(() => screen.queryByText('Loading...'))
 
     expect(screen.getByTestId('Layout')).toBeInTheDocument()
     expect(screen.getByTestId('MediaSharePage')).toBeInTheDocument()
