From 044cbe07f99ee13ddbc46ee957ae24fc48961165 Mon Sep 17 00:00:00 2001
From: HenryShan <zshan2@illinois.edu>
Date: Mon, 29 Mar 2021 23:38:34 +0800
Subject: [PATCH 1/4] assignment3.1 ver2.0: all functionalities are
 implemented, going for testing

---
 README.md                                    |  19 ++
 src/App.js                                   | 257 ++++++++++++--
 src/Components/Loading.js                    |   6 +-
 src/Components/Profile.js                    |  11 +-
 src/Components/Repo.js                       |   8 +-
 src/Components/Unfound.js                    |   4 +-
 src/__tests__/App-test.js                    |  24 ++
 src/__tests__/__snapshots__/App-test.js.snap | 335 ++++++++++++++++++-
 8 files changed, 617 insertions(+), 47 deletions(-)

diff --git a/README.md b/README.md
index 42eeedf..7ab5a6a 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,21 @@
 # sp21-cs242-assignment3
 
+Description: this repo is for UIUC CS242 SP21's assignment3
+
+## Functionalities:
+- Giving github's graphQL API endpoint address, user OAuth token, and username, get personal info of this user and rendered it in mobile devices.
+- Find other github user's info through following & follower lists and public repo owners.
+
+## Environment Requirement:
+- Windows 7 or above
+- Javascript Environment
+- React-Native
+
+## External Resources:
+- React Navigation
+- Jest
+
+## Update Notes:
+- 3/29: Basic functionalities are completed.
+- 3/22: User's personal info pages are completed.
+
diff --git a/src/App.js b/src/App.js
index fdc4270..32ca65a 100644
--- a/src/App.js
+++ b/src/App.js
@@ -6,6 +6,7 @@ import Loading from './Components/Loading'
 import Profile from './Components/Profile'
 import Repo from './Components/Repo'
 import Unfound from './Components/Unfound'
+import Users from './Components/Users'
 import DataGenerator from './Components/DataGenerator'
 
 const Stack = createStackNavigator();
@@ -23,6 +24,7 @@ const styles = StyleSheet.create({
 function generateData(route, navigation) {
   const {name, login, avatarUrl, bio, createdAt, email, websiteUrl, repositories} = route.params;
   const dataFile = {}
+  dataFile['login'] = login
   dataFile['navi'] = navigation
   dataFile['nameContent'] = 'Name: \n' + name
   dataFile['userNameContent'] = 'UserName\n: ' + login
@@ -44,11 +46,15 @@ function generateData(route, navigation) {
 
 /** Home page **/
 function HomeScreen({ navigation }) {
+  const dataJson = require('C:/Coding/cs242-assignment3/env.json')
+  const myUserName = dataJson['login']
+  const data = {}
+  data['login'] = myUserName
   return (
     <View style={styles.container}>
-      <ImageBackground source={require('C:/Coding/cs242-assignment3/GitView/assets/ice.jpg')} style={styles.image}>
+      <ImageBackground source={{uri: "https://www.fonewalls.com/wp-content/uploads/2020/04/Ice-Phone-Wallpaper.jpg"}} style={styles.image}>
       <View style={styles.viewStyleVertical}>
-        <Pressable  style={styles.pressableStyle} onPress={() => navigation.navigate('LoadingProfile')}>
+        <Pressable  style={styles.pressableStyle} onPress={() => navigation.push('LoadingProfile', data)}>
           <Text> Start </Text>
         </Pressable>
       </View>
@@ -67,29 +73,117 @@ function ProfileScreen({ route, navigation }) {
 
 /** Repo page **/
 function RepoScreen({ route, navigation }) {
-  const {nodes} = route.params
+  const user = route.params
+  const nodes = user['repositories']['nodes']
+  const login = user['login']
   let cards = [];
   for (let i = 0; i < nodes.length; i++) {
     var repoName = 'Repo name: \n' + nodes[i]['name'] + '\n'
     var repoDescription = 'Repo description: \n' + nodes[i]['description'] + '\n'
     var repoOwner = 'Repo owner: \n' + nodes[i]['owner']['login'] + '\n'
-    var nativeID = 'repo#' + i
+    var key = 'repo#' + i
     cards.push(
-    <View style={styles.textBox} nativeID={nativeID}>
+    <Pressable style={styles.textBox} key={key} Pressable style={styles.textBox} onPress={() => navigation.push('LoadingProfile', {login: nodes[i]['owner']['login']})}>
       <Text> {repoName} </Text>
       <Text> {repoDescription} </Text>
       <Text> {repoOwner} </Text>
-    </View>
+    </Pressable>
     )
   }
   const dataFile = {}
   dataFile['cards'] = cards
   dataFile['navi'] = navigation
+  dataFile['login'] = login
   return (
     <Repo data={dataFile}/>
   );
 }
 
+/** Follower page **/
+function FollowerScreen({ route, navigation }) {
+  const user = route.params
+  const nodes = user['followers']['nodes']
+  const login = user['login']
+  let cards = []
+  if (nodes.length === 0) {
+    cards.push(
+      <Pressable style={styles.textBox} key={'Nobody'}>
+          <Text style={{ fontSize: 30 }}> 
+            Oops! Nobody is in this list!
+          </Text> 
+      </Pressable>
+    )
+  } else {
+    for (let i = 0; i < nodes.length; i++) {
+      var name = 'Name: \n' + nodes[i]['name'] + '\n'
+      var userName = 'Github Username: \n' + nodes[i]['login'] + '\n'
+      var key = 'user#' + i
+      var avatarUrl = nodes[i]['avatarUrl']
+      cards.push(
+      <Pressable style={styles.textBox} key={key} onPress={()=>navigation.push('LoadingProfile', {login: nodes[i]['login']})}>
+        <View style={styles.viewStyleVertical}>
+          <Image style={{width:90, height:90}} source={{uri: avatarUrl}}/>
+        </View>
+        <View style={styles.viewStyleVertical}>
+          <Text> {name} </Text>
+          <Text> {userName} </Text>
+        </View>
+      </Pressable>
+      )
+    }
+  }
+  const dataFile = {}
+  dataFile['cards'] = cards
+  dataFile['navi'] = navigation
+  dataFile['login'] = login
+  console.log(login)
+  return (
+    <Users data={dataFile}/>
+  );
+}
+
+/** Following page **/
+function FollowingScreen({ route, navigation }) {
+  const user = route.params
+  const nodes = user['following']['nodes']
+  const login = user['login']
+  let cards = []
+  if (nodes.length === 0) {
+    cards.push(
+      <Pressable style={styles.textBox} key={'Nobody'}>
+          <Text style={{ fontSize: 30 }}> 
+            Oops! Nobody is in this list!
+          </Text> 
+      </Pressable>
+    )
+  } else {
+    for (let i = 0; i < nodes.length; i++) {
+      var name = 'Name: \n' + nodes[i]['name'] + '\n'
+      var userName = 'Github Username: \n' + nodes[i]['login'] + '\n'
+      var key = 'user#' + i
+      var avatarUrl = nodes[i]['avatarUrl']
+      cards.push(
+      <Pressable style={styles.textBox} key={key} onPress={()=>navigation.push('LoadingProfile', {login: nodes[i]['login']})}>
+        <View style={styles.viewStyleVertical}>
+          <Image style={{width:90, height:90}} source={{uri: avatarUrl}}/>
+        </View>
+        <View style={styles.viewStyleVertical}>
+          <Text> {name} </Text>
+          <Text> {userName} </Text>
+        </View>
+      </Pressable>
+      )
+    }
+  }
+  const dataFile = {}
+  dataFile['cards'] = cards
+  dataFile['navi'] = navigation
+  dataFile['login'] = login
+  return (
+    <Users data={dataFile}/>
+  );
+}
+
 /** Unfound page **/
 function UnfoundScreen({ route, navigation }) {
   const {errorMsg} = route.params
@@ -101,9 +195,12 @@ function UnfoundScreen({ route, navigation }) {
   );
 }
 
+
+
 /** Loading Profile page **/
-function LoadProfileScreen({navigation}) {
-  const dataJson = require('C:/Coding/cs242-assignment3/env.json');
+function LoadProfileScreen({route, navigation}) {
+  const dataJson = require('C:/Coding/cs242-assignment3/env.json')
+  const {login} = route.params
   fetch(dataJson['endPoint'], {
     method: 'POST',
     headers: {
@@ -113,7 +210,7 @@ function LoadProfileScreen({navigation}) {
     body: JSON.stringify({
       query: `
         query {
-          viewer {
+          user(login:"`+ login + `") {
             name
             login
             avatarUrl
@@ -133,11 +230,17 @@ function LoadProfileScreen({navigation}) {
   })
   .then(res => res.json())
   .then((data)=> {
-    navigation.navigate('Profile', data['data']['viewer'])
+    if (data['data']['user'] === null) {
+      /** User not found! **/
+      navigation.push('Unfound', {errorMsg: 'Wrong!'})
+      console.log('Error, cannot find the github user by the login username:' + login + ', maybe this is an organization!')
+    } else {
+      navigation.push('Profile', data['data']['user'])
+    }
   })
   .catch(error => {
     console.error('Error:', error)
-    navigation.navigate('Unfound', {errorMsg: error})
+    navigation.push('Unfound', {errorMsg: error})
   })
 
   return (
@@ -146,10 +249,8 @@ function LoadProfileScreen({navigation}) {
 }
 
 /** Loading Repo page **/
-function LoadRepoScreen({navigation}) {
-  // setTimeout(function(){
-  //   navigation.navigate('Unfound'); 
-  // }, 1000)
+function LoadRepoScreen({route, navigation}) {
+  const {login} = route.params
   const dataJson = require('C:/Coding/cs242-assignment3/env.json');
   fetch(dataJson['endPoint'], {
     method: 'POST',
@@ -160,7 +261,8 @@ function LoadRepoScreen({navigation}) {
     body: JSON.stringify({
       query: `
         query {
-          viewer{
+          user(login:"`+login+`"){
+            login
             repositories(last:100, privacy:PUBLIC){
               nodes{
                 name
@@ -176,14 +278,65 @@ function LoadRepoScreen({navigation}) {
     })
   })
   .then(res => res.json())
-  // .then((data) => console.log(data['data']['viewer']['repositories']['nodes']))
-  // .then((data) => console.log(data))
   .then((data)=> {
-    navigation.navigate('Repo', data['data']['viewer']['repositories'])
+    if (data['data']['user'] === null) {
+      /** User not found! **/
+      navigation.push('Unfound', {errorMsg: 'Wrong!'})
+      console.log('Error, cannot find the github user by the login username:' + login + ', maybe this is an organization!')
+    } else {
+      navigation.push('Repo', data['data']['user'])
+    }
+  })
+  .catch(error => {
+    console.error('Error:', error)
+    navigation.push('Unfound', {errorMsg: error})
+  })
+
+  return (
+    <Loading/>
+  );
+}
+
+/** Loading Followers page **/
+function LoadFollowersScreen({route, navigation}) {
+  const {login} = route.params
+  const dataJson = require('C:/Coding/cs242-assignment3/env.json');
+  fetch(dataJson['endPoint'], {
+    method: 'POST',
+    headers: {
+      "Content-Type": "application/json",
+      "Authorization": dataJson['token']
+    },
+    body: JSON.stringify({
+      query: `
+        query {
+          user(login:"`+ login +`"){
+            login
+            followers(last:100) {
+              nodes {
+                name
+                login
+                avatarUrl
+              }
+            }
+          }
+        }
+      `
+    })
+  })
+  .then(res => res.json())
+  .then((data)=> {
+    if (data['data']['user'] === null) {
+      /** User not found! **/
+      navigation.push('Unfound', {errorMsg: 'Wrong!'})
+      console.log('Error, cannot find the github user by the login username:' + login + ', maybe this is an organization!')
+    } else {
+      navigation.push('Followers', data['data']['user'])
+    }
   })
   .catch(error => {
     console.error('Error:', error)
-    navigation.navigate('Unfound', {errorMsg: error})
+    navigation.push('Unfound', {errorMsg: error})
   })
 
   return (
@@ -191,17 +344,69 @@ function LoadRepoScreen({navigation}) {
   );
 }
 
+/** Loading Followings page **/
+function LoadFollowingScreen({route, navigation}) {
+  const {login} = route.params
+  const dataJson = require('C:/Coding/cs242-assignment3/env.json');
+  fetch(dataJson['endPoint'], {
+    method: 'POST',
+    headers: {
+      "Content-Type": "application/json",
+      "Authorization": dataJson['token']
+    },
+    body: JSON.stringify({
+      query: `
+        query {
+          user(login:"` + login + `"){
+            login
+            following(last:100) {
+              nodes {
+                name
+                login
+                avatarUrl
+              }
+            }
+          }
+        }
+      `
+    })
+  })
+  .then(res => res.json())
+  .then((data)=> {
+    if (data['data']['user'] === null) {
+      /** User not found! **/
+      navigation.push('Unfound', {errorMsg: 'Wrong!'})
+      console.log('Error, cannot find the github user by the login username:' + login + ', maybe this is an organization!')
+    } else {
+      navigation.push('Following', data['data']['user'])
+    }
+  })
+  .catch(error => {
+    console.error('Error:', error)
+    navigation.push('Unfound', {errorMsg: error})
+  })
+
+  return (
+    <Loading/>
+  );
+}
+
+
 /** Page loader **/
 function App() {
   return (
     <NavigationContainer>
       <Stack.Navigator initialRouteName="Home">
-        <Stack.Screen name="Home" component={HomeScreen} options={{ title: 'Github User Info' }}/>
-        <Stack.Screen name="Profile" component={ProfileScreen} />
-        <Stack.Screen name="Repo" component={RepoScreen} options={{ title: 'Repositories' }}/>
-        <Stack.Screen name="LoadingProfile" component={LoadProfileScreen} />
-        <Stack.Screen name="LoadingRepo" component={LoadRepoScreen} />
-        <Stack.Screen name="Unfound" component={UnfoundScreen} options={{ title: 'Error' }}/>
+        <Stack.Screen name='Home' component={HomeScreen} options={{ title: 'Github User Info', animationEnabled: true}}/>
+        <Stack.Screen name='Profile' component={ProfileScreen} options={{animationEnabled: true}}/>
+        <Stack.Screen name='Repo' component={RepoScreen} options={{ title: 'Repositories', animationEnabled:true }}/>
+        <Stack.Screen name="LoadingProfile" component={LoadProfileScreen} options={{animationEnabled: true}} />
+        <Stack.Screen name='LoadingRepo' component={LoadRepoScreen} options={{animationEnabled: true}}/>
+        <Stack.Screen name='Unfound' component={UnfoundScreen} options={{ title: 'Error', animationEnabled:true }}/>
+        <Stack.Screen name='LoadingFollowers' component={LoadFollowersScreen} options={{animationEnabled: true}}/> 
+        <Stack.Screen name='LoadingFollowing' component={LoadFollowingScreen} options={{animationEnabled: true}}/>
+        <Stack.Screen name='Followers' component={FollowerScreen} options={{animationEnabled: true}}/>
+        <Stack.Screen name='Following' component={FollowingScreen} options={{animationEnabled: true}}/>
       </Stack.Navigator>
     </NavigationContainer>
   );
diff --git a/src/Components/Loading.js b/src/Components/Loading.js
index 2e3ee0c..694ff72 100644
--- a/src/Components/Loading.js
+++ b/src/Components/Loading.js
@@ -13,13 +13,13 @@ const styles = StyleSheet.create({
 });
 
 const Loading = () => {
-    const pic = require('C:/Coding/cs242-assignment3/GitView/assets/loading.png')
+    const pic = "http://simpleicon.com/wp-content/uploads/refresh.png"
     return (
         <View style={styles.container}>
-            <ImageBackground source={require('C:/Coding/cs242-assignment3/GitView/assets/ice.jpg')} style={styles.image}>
+            <ImageBackground source={{uri: "https://www.fonewalls.com/wp-content/uploads/2020/04/Ice-Phone-Wallpaper.jpg"}} style={styles.image}>
             <View style={styles.viewStyleVertical}>
                 <Text style={{ fontSize: 30 }}>Loading......</Text>
-                <Image source={pic} style={{width: 200, height: 200}}/>
+                <Image source={{uri: pic}} style={{width: 200, height: 200}}/>
             </View>
             </ImageBackground>
         </View>
diff --git a/src/Components/Profile.js b/src/Components/Profile.js
index a6d95f8..2856a2d 100644
--- a/src/Components/Profile.js
+++ b/src/Components/Profile.js
@@ -25,18 +25,19 @@ const Profile = (props) => {
     const createDate = file['createDate']
     const repoCount = file['repoCount']
     const navigation = file['navi']
+    const login = file['login']
     return (
         <View style={styles.container}>
-            <ImageBackground source={require('C:/Coding/cs242-assignment3/GitView/assets/ice.jpg')} style={styles.image}> 
+            <ImageBackground source={{uri: "https://www.fonewalls.com/wp-content/uploads/2020/04/Ice-Phone-Wallpaper.jpg"}} style={styles.image}> 
             <View style={styles.viewStyleVertical}>
                 <View style={styles.viewStyleVertical}> 
-                <Image style={{width: 100, height: 100}} source={iconUrl} />
+                <Image style={{width: 100, height: 100}} source={{uri: iconUrl}} />
                 </View>
                 <View style={styles.viewStyleHorizon}> 
-                <Pressable style={styles.pressableStyle}> 
+                <Pressable style={styles.pressableStyle} onPress={() => navigation.push('LoadingFollowers', {login: login})}> 
                     <Text> Followers </Text>
                 </Pressable>
-                <Pressable style={styles.pressableStyle}>
+                <Pressable style={styles.pressableStyle} onPress={() => navigation.push('LoadingFollowing', {login: login})}>
                     <Text> Followings </Text>
                 </Pressable>
                 </View>
@@ -49,7 +50,7 @@ const Profile = (props) => {
                 <Text style={styles.textBox}> {createDate} </Text>
                 </View>
                 <View style={styles.viewStyleVertical} > 
-                <Pressable  style={styles.pressableStyle} onPress={() => navigation.navigate('LoadingRepo')}> 
+                <Pressable  style={styles.pressableStyle} onPress={() => navigation.push('LoadingRepo', {login: login})}> 
                     <Text> {repoCount} </Text>
                 </Pressable>
                 </View>
diff --git a/src/Components/Repo.js b/src/Components/Repo.js
index 05b44e6..811276f 100644
--- a/src/Components/Repo.js
+++ b/src/Components/Repo.js
@@ -18,12 +18,16 @@ const Repo = (props) => {
     const file = props.data
     const cards = file['cards']
     const navigation = file['navi']
+    const login = file['login']
     return (
         <View style={styles.container}>
-            <ImageBackground source={require('C:/Coding/cs242-assignment3/GitView/assets/ice.jpg')} style={styles.image}>
+            <ImageBackground source={{uri: "https://www.fonewalls.com/wp-content/uploads/2020/04/Ice-Phone-Wallpaper.jpg"}} style={styles.image}>
             <View style={styles.viewStyleVertical}>
+                <Pressable  style={styles.pressableStyle} onPress={() => navigation.pop(2)}>
+                <Text> Go to Profile </Text>
+                </Pressable>
                 {cards}
-                <Pressable  style={styles.pressableStyle} onPress={() => navigation.navigate('Profile')}>
+                <Pressable  style={styles.pressableStyle} onPress={() => navigation.pop(2)}>
                 <Text> Go to Profile </Text>
                 </Pressable>
             </View>
diff --git a/src/Components/Unfound.js b/src/Components/Unfound.js
index 1bfc4a9..6b3772a 100644
--- a/src/Components/Unfound.js
+++ b/src/Components/Unfound.js
@@ -19,10 +19,10 @@ const Unfound = (props) => {
     const navigation = dataFile['navi']
     return (
         <View style={styles.container}>
-            <ImageBackground source={require('C:/Coding/cs242-assignment3/GitView/assets/ice.jpg')} style={styles.image}>
+            <ImageBackground source={{uri: "https://www.fonewalls.com/wp-content/uploads/2020/04/Ice-Phone-Wallpaper.jpg"}} style={styles.image}>
             <View style={styles.viewStyleVertical}>
                 <Text style={{ fontSize: 30 }}> Error! Check log to see details </Text>
-                <Image style={{width: 200, height: 200}} source={require('C:/Coding/cs242-assignment3/GitView/assets/warn.png')} />
+                <Image style={{width: 200, height: 200}} source={{uri: "https://upload.wikimedia.org/wikipedia/commons/thumb/1/17/Warning.svg/156px-Warning.svg.png"}} />
                 <Pressable  style={styles.pressableStyle} onPress={() => navigation.navigate('Home')}> 
                 <Text> Go back to Home Page </Text>
                 </Pressable>
diff --git a/src/__tests__/App-test.js b/src/__tests__/App-test.js
index 79c4721..f76ba57 100644
--- a/src/__tests__/App-test.js
+++ b/src/__tests__/App-test.js
@@ -11,6 +11,7 @@ import Unfound from '../Components/Unfound';
 
 const Stack = createStackNavigator();
 
+/** Testing all loading pages */
 test('renders correctly', () => {
     const tree = renderer.create(
       <Loading />
@@ -36,6 +37,7 @@ test('renders correctly', () => {
     expect(tree).toMatchSnapshot();
   });
 
+  /** Testing repo pages */
   test('renders correctly', ({navigation}) => {
     const dataFile = {
       iconUrl: "https://avatars.githubusercontent.com/u/42978932?u=b4a7beb2752bb6059cd13d12ca26d097767abf77&v=4",
@@ -54,6 +56,28 @@ test('renders correctly', () => {
     expect(tree).toMatchSnapshot();
   });
 
+
+  /** Testing all Users pages (Followers and Following) */
+  test('renders correctly', ({navigation}) => {
+    const dataFile = {
+      iconUrl: "https://avatars.githubusercontent.com/u/42978932?u=b4a7beb2752bb6059cd13d12ca26d097767abf77&v=4",
+      nameContent: null,
+      userNameContent: null,
+      bioContent: null,
+      websiteLink: null,
+      emailContent: null,
+      createData: null,
+      repoCount: 0,
+      navi: navigation
+    }
+    const tree = renderer.create(
+      <Users data={dataFile}/>
+    ).toJSON();
+    expect(tree).toMatchSnapshot();
+  });
+
+  
+  /** Testing unfound/error pages */
   test('renders correctly', ({navigation}) => {
     const dataFile = {
       navi: navigation
diff --git a/src/__tests__/__snapshots__/App-test.js.snap b/src/__tests__/__snapshots__/App-test.js.snap
index 365ee0e..3f7171f 100644
--- a/src/__tests__/__snapshots__/App-test.js.snap
+++ b/src/__tests__/__snapshots__/App-test.js.snap
@@ -19,7 +19,88 @@ exports[`renders correctly 1`] = `
     }
   >
     <Image
-      source="test-file-stub"
+      source={
+        Object {
+          "uri": "https://www.fonewalls.com/wp-content/uploads/2020/04/Ice-Phone-Wallpaper.jpg",
+        }
+      }
+      style={
+        Array [
+          Object {
+            "bottom": 0,
+            "left": 0,
+            "position": "absolute",
+            "right": 0,
+            "top": 0,
+          },
+          Object {
+            "height": undefined,
+            "width": undefined,
+          },
+          undefined,
+        ]
+      }
+    />
+    <View
+      style={
+        Object {
+          "alignItems": "center",
+          "justifyContent": "center",
+          "margin": "10%",
+        }
+      }
+    >
+      <Text
+        style={
+          Object {
+            "fontSize": 30,
+          }
+        }
+      >
+        Loading......
+      </Text>
+      <Image
+        source={
+          Object {
+            "uri": "http://simpleicon.com/wp-content/uploads/refresh.png",
+          }
+        }
+        style={
+          Object {
+            "height": 200,
+            "width": 200,
+          }
+        }
+      />
+    </View>
+  </View>
+</View>
+`;
+
+exports[`renders correctly 2`] = `
+<View
+  style={
+    Object {
+      "flex": 1,
+    }
+  }
+>
+  <View
+    accessibilityIgnoresInvertColors={true}
+    style={
+      Object {
+        "flex": 1,
+        "justifyContent": "center",
+        "resizeMode": "cover",
+      }
+    }
+  >
+    <Image
+      source={
+        Object {
+          "uri": "https://www.fonewalls.com/wp-content/uploads/2020/04/Ice-Phone-Wallpaper.jpg",
+        }
+      }
       style={
         Array [
           Object {
@@ -56,7 +137,7 @@ exports[`renders correctly 1`] = `
         }
       >
         <Image
-          source="test-file-stub"
+          source="https://avatars.githubusercontent.com/u/42978932?u=b4a7beb2752bb6059cd13d12ca26d097767abf77&v=4"
           style={
             Object {
               "height": 100,
@@ -164,7 +245,8 @@ exports[`renders correctly 1`] = `
             }
           }
         >
-           nameContent 
+           
+           
         </Text>
         <Text
           style={
@@ -182,7 +264,8 @@ exports[`renders correctly 1`] = `
             }
           }
         >
-           userNameContent 
+           
+           
         </Text>
         <Text
           style={
@@ -200,7 +283,8 @@ exports[`renders correctly 1`] = `
             }
           }
         >
-           bioContent 
+           
+           
         </Text>
         <Text
           style={
@@ -218,7 +302,8 @@ exports[`renders correctly 1`] = `
             }
           }
         >
-           websiteLink 
+           
+           
         </Text>
         <Text
           style={
@@ -236,7 +321,8 @@ exports[`renders correctly 1`] = `
             }
           }
         >
-           emailContent 
+           
+           
         </Text>
         <Text
           style={
@@ -254,7 +340,8 @@ exports[`renders correctly 1`] = `
             }
           }
         >
-           createDate 
+           
+           
         </Text>
       </View>
       <View
@@ -295,7 +382,9 @@ exports[`renders correctly 1`] = `
           }
         >
           <Text>
-             repoCount 
+             
+            0
+             
           </Text>
         </View>
       </View>
@@ -303,3 +392,231 @@ exports[`renders correctly 1`] = `
   </View>
 </View>
 `;
+
+exports[`renders correctly 3`] = `
+<View
+  style={
+    Object {
+      "flex": 1,
+    }
+  }
+>
+  <View
+    accessibilityIgnoresInvertColors={true}
+    style={
+      Object {
+        "flex": 1,
+        "justifyContent": "center",
+        "resizeMode": "cover",
+      }
+    }
+  >
+    <Image
+      source={
+        Object {
+          "uri": "https://www.fonewalls.com/wp-content/uploads/2020/04/Ice-Phone-Wallpaper.jpg",
+        }
+      }
+      style={
+        Array [
+          Object {
+            "bottom": 0,
+            "left": 0,
+            "position": "absolute",
+            "right": 0,
+            "top": 0,
+          },
+          Object {
+            "height": undefined,
+            "width": undefined,
+          },
+          undefined,
+        ]
+      }
+    />
+    <View
+      style={
+        Object {
+          "alignItems": "center",
+          "justifyContent": "center",
+          "margin": "10%",
+        }
+      }
+    >
+      <View
+        accessible={true}
+        focusable={true}
+        onBlur={[Function]}
+        onClick={[Function]}
+        onFocus={[Function]}
+        onResponderGrant={[Function]}
+        onResponderMove={[Function]}
+        onResponderRelease={[Function]}
+        onResponderTerminate={[Function]}
+        onResponderTerminationRequest={[Function]}
+        onStartShouldSetResponder={[Function]}
+        style={
+          Object {
+            "backgroundColor": "lavender",
+            "borderColor": "thistle",
+            "borderRadius": 5,
+            "borderWidth": 2,
+            "flex": 1,
+            "flexDirection": "row",
+            "justifyContent": "space-between",
+            "marginHorizontal": 10,
+            "marginTop": 10,
+            "paddingHorizontal": 20,
+            "paddingVertical": 10,
+          }
+        }
+      >
+        <Text>
+           Go to Profile 
+        </Text>
+      </View>
+      <View
+        accessible={true}
+        focusable={true}
+        onBlur={[Function]}
+        onClick={[Function]}
+        onFocus={[Function]}
+        onResponderGrant={[Function]}
+        onResponderMove={[Function]}
+        onResponderRelease={[Function]}
+        onResponderTerminate={[Function]}
+        onResponderTerminationRequest={[Function]}
+        onStartShouldSetResponder={[Function]}
+        style={
+          Object {
+            "backgroundColor": "lavender",
+            "borderColor": "thistle",
+            "borderRadius": 5,
+            "borderWidth": 2,
+            "flex": 1,
+            "flexDirection": "row",
+            "justifyContent": "space-between",
+            "marginHorizontal": 10,
+            "marginTop": 10,
+            "paddingHorizontal": 20,
+            "paddingVertical": 10,
+          }
+        }
+      >
+        <Text>
+           Go to Profile 
+        </Text>
+      </View>
+    </View>
+  </View>
+</View>
+`;
+
+exports[`renders correctly 4`] = `
+<View
+  style={
+    Object {
+      "flex": 1,
+    }
+  }
+>
+  <View
+    accessibilityIgnoresInvertColors={true}
+    style={
+      Object {
+        "flex": 1,
+        "justifyContent": "center",
+        "resizeMode": "cover",
+      }
+    }
+  >
+    <Image
+      source={
+        Object {
+          "uri": "https://www.fonewalls.com/wp-content/uploads/2020/04/Ice-Phone-Wallpaper.jpg",
+        }
+      }
+      style={
+        Array [
+          Object {
+            "bottom": 0,
+            "left": 0,
+            "position": "absolute",
+            "right": 0,
+            "top": 0,
+          },
+          Object {
+            "height": undefined,
+            "width": undefined,
+          },
+          undefined,
+        ]
+      }
+    />
+    <View
+      style={
+        Object {
+          "alignItems": "center",
+          "justifyContent": "center",
+          "margin": "10%",
+        }
+      }
+    >
+      <Text
+        style={
+          Object {
+            "fontSize": 30,
+          }
+        }
+      >
+         Error! Check log to see details 
+      </Text>
+      <Image
+        source={
+          Object {
+            "uri": "https://upload.wikimedia.org/wikipedia/commons/thumb/1/17/Warning.svg/156px-Warning.svg.png",
+          }
+        }
+        style={
+          Object {
+            "height": 200,
+            "width": 200,
+          }
+        }
+      />
+      <View
+        accessible={true}
+        focusable={true}
+        onBlur={[Function]}
+        onClick={[Function]}
+        onFocus={[Function]}
+        onResponderGrant={[Function]}
+        onResponderMove={[Function]}
+        onResponderRelease={[Function]}
+        onResponderTerminate={[Function]}
+        onResponderTerminationRequest={[Function]}
+        onStartShouldSetResponder={[Function]}
+        style={
+          Object {
+            "backgroundColor": "lavender",
+            "borderColor": "thistle",
+            "borderRadius": 5,
+            "borderWidth": 2,
+            "flex": 1,
+            "flexDirection": "row",
+            "justifyContent": "space-between",
+            "marginHorizontal": 10,
+            "marginTop": 10,
+            "paddingHorizontal": 20,
+            "paddingVertical": 10,
+          }
+        }
+      >
+        <Text>
+           Go back to Home Page 
+        </Text>
+      </View>
+    </View>
+  </View>
+</View>
+`;
-- 
GitLab


From 6ce28402d297e7f09b8affe43a6ac5eff00843c9 Mon Sep 17 00:00:00 2001
From: HenryShan <zshan2@illinois.edu>
Date: Tue, 30 Mar 2021 08:11:57 +0800
Subject: [PATCH 2/4] assignment3.0 ver3: all snapshot tests deployed, going
 for navigation test

---
 src/App.js                | 271 ++++----------------------------------
 src/Components/Loading.js |   2 +-
 src/Components/Profile.js |   4 +-
 src/Components/Repo.js    |   4 +-
 src/Components/Unfound.js |   2 -
 src/package.json          |   7 +-
 6 files changed, 36 insertions(+), 254 deletions(-)

diff --git a/src/App.js b/src/App.js
index 32ca65a..b9549e1 100644
--- a/src/App.js
+++ b/src/App.js
@@ -7,7 +7,14 @@ import Profile from './Components/Profile'
 import Repo from './Components/Repo'
 import Unfound from './Components/Unfound'
 import Users from './Components/Users'
-import DataGenerator from './Components/DataGenerator'
+import LoadFollowingScreenModule from './Components/LoadFollowingScreenModule'
+import LoadFollowersScreenModule from './Components/LoadFollowersScreenModule'
+import LoadProfileScreenModule from './Components/LoadProfileScreenModule'
+import LoadRepoScreenModule from './Components/LoadRepoScreenModule'
+import Follower from './Components/Followers'
+import Following from './Components/Following'
+
+
 
 const Stack = createStackNavigator();
 const styles = StyleSheet.create({
@@ -35,9 +42,9 @@ function generateData(route, navigation) {
   dataFile['repoCount'] = 'Repository count: ' + repositories['nodes'].length
   var iconUrl
   if (avatarUrl != null) {
-    iconUrl = { uri: avatarUrl }
+    iconUrl = avatarUrl
   } else {
-    iconUrl = require('C:/Coding/cs242-assignment3/GitView/assets/default.png')
+    iconUrl = "https://png.pngtree.com/element_our/20200610/ourlarge/pngtree-cat-default-avatar-image_2246581.jpg"
   }
   dataFile['iconUrl'] = iconUrl
   return dataFile
@@ -102,86 +109,13 @@ function RepoScreen({ route, navigation }) {
 /** Follower page **/
 function FollowerScreen({ route, navigation }) {
   const user = route.params
-  const nodes = user['followers']['nodes']
-  const login = user['login']
-  let cards = []
-  if (nodes.length === 0) {
-    cards.push(
-      <Pressable style={styles.textBox} key={'Nobody'}>
-          <Text style={{ fontSize: 30 }}> 
-            Oops! Nobody is in this list!
-          </Text> 
-      </Pressable>
-    )
-  } else {
-    for (let i = 0; i < nodes.length; i++) {
-      var name = 'Name: \n' + nodes[i]['name'] + '\n'
-      var userName = 'Github Username: \n' + nodes[i]['login'] + '\n'
-      var key = 'user#' + i
-      var avatarUrl = nodes[i]['avatarUrl']
-      cards.push(
-      <Pressable style={styles.textBox} key={key} onPress={()=>navigation.push('LoadingProfile', {login: nodes[i]['login']})}>
-        <View style={styles.viewStyleVertical}>
-          <Image style={{width:90, height:90}} source={{uri: avatarUrl}}/>
-        </View>
-        <View style={styles.viewStyleVertical}>
-          <Text> {name} </Text>
-          <Text> {userName} </Text>
-        </View>
-      </Pressable>
-      )
-    }
-  }
-  const dataFile = {}
-  dataFile['cards'] = cards
-  dataFile['navi'] = navigation
-  dataFile['login'] = login
-  console.log(login)
-  return (
-    <Users data={dataFile}/>
-  );
+  return Follower(user, navigation)
 }
 
 /** Following page **/
 function FollowingScreen({ route, navigation }) {
   const user = route.params
-  const nodes = user['following']['nodes']
-  const login = user['login']
-  let cards = []
-  if (nodes.length === 0) {
-    cards.push(
-      <Pressable style={styles.textBox} key={'Nobody'}>
-          <Text style={{ fontSize: 30 }}> 
-            Oops! Nobody is in this list!
-          </Text> 
-      </Pressable>
-    )
-  } else {
-    for (let i = 0; i < nodes.length; i++) {
-      var name = 'Name: \n' + nodes[i]['name'] + '\n'
-      var userName = 'Github Username: \n' + nodes[i]['login'] + '\n'
-      var key = 'user#' + i
-      var avatarUrl = nodes[i]['avatarUrl']
-      cards.push(
-      <Pressable style={styles.textBox} key={key} onPress={()=>navigation.push('LoadingProfile', {login: nodes[i]['login']})}>
-        <View style={styles.viewStyleVertical}>
-          <Image style={{width:90, height:90}} source={{uri: avatarUrl}}/>
-        </View>
-        <View style={styles.viewStyleVertical}>
-          <Text> {name} </Text>
-          <Text> {userName} </Text>
-        </View>
-      </Pressable>
-      )
-    }
-  }
-  const dataFile = {}
-  dataFile['cards'] = cards
-  dataFile['navi'] = navigation
-  dataFile['login'] = login
-  return (
-    <Users data={dataFile}/>
-  );
+  return Following(user, navigation)
 }
 
 /** Unfound page **/
@@ -201,48 +135,9 @@ function UnfoundScreen({ route, navigation }) {
 function LoadProfileScreen({route, navigation}) {
   const dataJson = require('C:/Coding/cs242-assignment3/env.json')
   const {login} = route.params
-  fetch(dataJson['endPoint'], {
-    method: 'POST',
-    headers: {
-      "Content-Type": "application/json",
-      "Authorization": dataJson['token']
-    },
-    body: JSON.stringify({
-      query: `
-        query {
-          user(login:"`+ login + `") {
-            name
-            login
-            avatarUrl
-            bio
-            createdAt
-            email
-            websiteUrl
-            repositories(last:100, privacy:PUBLIC){
-              nodes{
-                name
-              }
-            }
-          }
-        }
-      `
-    })
-  })
-  .then(res => res.json())
-  .then((data)=> {
-    if (data['data']['user'] === null) {
-      /** User not found! **/
-      navigation.push('Unfound', {errorMsg: 'Wrong!'})
-      console.log('Error, cannot find the github user by the login username:' + login + ', maybe this is an organization!')
-    } else {
-      navigation.push('Profile', data['data']['user'])
-    }
-  })
-  .catch(error => {
-    console.error('Error:', error)
-    navigation.push('Unfound', {errorMsg: error})
-  })
-
+  const endPoint = dataJson['endPoint']
+  const token = dataJson['token']
+  LoadProfileScreenModule(login, endPoint, token, navigation)
   return (
     <Loading/>
   );
@@ -250,48 +145,11 @@ function LoadProfileScreen({route, navigation}) {
 
 /** Loading Repo page **/
 function LoadRepoScreen({route, navigation}) {
+  const dataJson = require('C:/Coding/cs242-assignment3/env.json')
   const {login} = route.params
-  const dataJson = require('C:/Coding/cs242-assignment3/env.json');
-  fetch(dataJson['endPoint'], {
-    method: 'POST',
-    headers: {
-      "Content-Type": "application/json",
-      "Authorization": dataJson['token']
-    },
-    body: JSON.stringify({
-      query: `
-        query {
-          user(login:"`+login+`"){
-            login
-            repositories(last:100, privacy:PUBLIC){
-              nodes{
-                name
-                owner{
-                  login
-                }
-                description
-              }
-            }
-          }
-        }
-      `
-    })
-  })
-  .then(res => res.json())
-  .then((data)=> {
-    if (data['data']['user'] === null) {
-      /** User not found! **/
-      navigation.push('Unfound', {errorMsg: 'Wrong!'})
-      console.log('Error, cannot find the github user by the login username:' + login + ', maybe this is an organization!')
-    } else {
-      navigation.push('Repo', data['data']['user'])
-    }
-  })
-  .catch(error => {
-    console.error('Error:', error)
-    navigation.push('Unfound', {errorMsg: error})
-  })
-
+  const endPoint = dataJson['endPoint']
+  const token = dataJson['token']
+  LoadRepoScreenModule(login, endPoint, token, navigation)
   return (
     <Loading/>
   );
@@ -301,94 +159,21 @@ function LoadRepoScreen({route, navigation}) {
 function LoadFollowersScreen({route, navigation}) {
   const {login} = route.params
   const dataJson = require('C:/Coding/cs242-assignment3/env.json');
-  fetch(dataJson['endPoint'], {
-    method: 'POST',
-    headers: {
-      "Content-Type": "application/json",
-      "Authorization": dataJson['token']
-    },
-    body: JSON.stringify({
-      query: `
-        query {
-          user(login:"`+ login +`"){
-            login
-            followers(last:100) {
-              nodes {
-                name
-                login
-                avatarUrl
-              }
-            }
-          }
-        }
-      `
-    })
-  })
-  .then(res => res.json())
-  .then((data)=> {
-    if (data['data']['user'] === null) {
-      /** User not found! **/
-      navigation.push('Unfound', {errorMsg: 'Wrong!'})
-      console.log('Error, cannot find the github user by the login username:' + login + ', maybe this is an organization!')
-    } else {
-      navigation.push('Followers', data['data']['user'])
-    }
-  })
-  .catch(error => {
-    console.error('Error:', error)
-    navigation.push('Unfound', {errorMsg: error})
-  })
-
-  return (
-    <Loading/>
-  );
+  const endPoint = dataJson['endPoint']
+  const token = dataJson['token']
+  /** Call function in module part to fetch data and send to view part */
+  return LoadFollowersScreenModule(login, endPoint, token, navigation)
 }
 
 /** Loading Followings page **/
 function LoadFollowingScreen({route, navigation}) {
   const {login} = route.params
   const dataJson = require('C:/Coding/cs242-assignment3/env.json');
-  fetch(dataJson['endPoint'], {
-    method: 'POST',
-    headers: {
-      "Content-Type": "application/json",
-      "Authorization": dataJson['token']
-    },
-    body: JSON.stringify({
-      query: `
-        query {
-          user(login:"` + login + `"){
-            login
-            following(last:100) {
-              nodes {
-                name
-                login
-                avatarUrl
-              }
-            }
-          }
-        }
-      `
-    })
-  })
-  .then(res => res.json())
-  .then((data)=> {
-    if (data['data']['user'] === null) {
-      /** User not found! **/
-      navigation.push('Unfound', {errorMsg: 'Wrong!'})
-      console.log('Error, cannot find the github user by the login username:' + login + ', maybe this is an organization!')
-    } else {
-      navigation.push('Following', data['data']['user'])
-    }
-  })
-  .catch(error => {
-    console.error('Error:', error)
-    navigation.push('Unfound', {errorMsg: error})
-  })
-
-  return (
-    <Loading/>
-  );
+  const endPoint = dataJson['endPoint']
+  const token = dataJson['token']
+  /** Call function in module part to fetch data and send to view part */
+  return LoadFollowingScreenModule(login, endPoint, token, navigation)
+  
 }
 
 
diff --git a/src/Components/Loading.js b/src/Components/Loading.js
index 694ff72..0bc32a3 100644
--- a/src/Components/Loading.js
+++ b/src/Components/Loading.js
@@ -1,5 +1,5 @@
 import * as React from 'react';
-import { Pressable, View, Text, Image, StyleSheet, ImageBackground } from 'react-native';
+import { View, Text, Image, StyleSheet, ImageBackground } from 'react-native';
 
 const styles = StyleSheet.create({
   viewStyleVertical : { alignItems: 'center', justifyContent: 'center', margin: '10%' },
diff --git a/src/Components/Profile.js b/src/Components/Profile.js
index 2856a2d..ea75c83 100644
--- a/src/Components/Profile.js
+++ b/src/Components/Profile.js
@@ -1,8 +1,6 @@
 import * as React from 'react';
 import { Pressable, View, Text, Image, StyleSheet, ImageBackground } from 'react-native';
-import { createStackNavigator } from '@react-navigation/stack';
 
-const Stack = createStackNavigator();
 const styles = StyleSheet.create({
   viewStyleVertical : { alignItems: 'center', justifyContent: 'center', margin: '10%' },
   viewStyleHorizon : { flex: 1, flexDirection: 'row', justifyContent: 'space-between'},
@@ -31,7 +29,7 @@ const Profile = (props) => {
             <ImageBackground source={{uri: "https://www.fonewalls.com/wp-content/uploads/2020/04/Ice-Phone-Wallpaper.jpg"}} style={styles.image}> 
             <View style={styles.viewStyleVertical}>
                 <View style={styles.viewStyleVertical}> 
-                <Image style={{width: 100, height: 100}} source={{uri: iconUrl}} />
+                <Image style={{width: 120, height: 120}} source={{uri: iconUrl}}/>
                 </View>
                 <View style={styles.viewStyleHorizon}> 
                 <Pressable style={styles.pressableStyle} onPress={() => navigation.push('LoadingFollowers', {login: login})}> 
diff --git a/src/Components/Repo.js b/src/Components/Repo.js
index 811276f..67038d8 100644
--- a/src/Components/Repo.js
+++ b/src/Components/Repo.js
@@ -1,8 +1,7 @@
 import * as React from 'react';
 import { Pressable, View, Text, Image, StyleSheet, ImageBackground } from 'react-native';
-import { createStackNavigator } from '@react-navigation/stack';
 
-const Stack = createStackNavigator();
+
 const styles = StyleSheet.create({
   viewStyleVertical : { alignItems: 'center', justifyContent: 'center', margin: '10%' },
   viewStyleHorizon : { flex: 1, flexDirection: 'row', justifyContent: 'space-between'},
@@ -18,7 +17,6 @@ const Repo = (props) => {
     const file = props.data
     const cards = file['cards']
     const navigation = file['navi']
-    const login = file['login']
     return (
         <View style={styles.container}>
             <ImageBackground source={{uri: "https://www.fonewalls.com/wp-content/uploads/2020/04/Ice-Phone-Wallpaper.jpg"}} style={styles.image}>
diff --git a/src/Components/Unfound.js b/src/Components/Unfound.js
index 6b3772a..7098417 100644
--- a/src/Components/Unfound.js
+++ b/src/Components/Unfound.js
@@ -1,8 +1,6 @@
 import * as React from 'react';
 import { Pressable, View, Text, Image, StyleSheet, ImageBackground } from 'react-native';
-import { createStackNavigator } from '@react-navigation/stack';
 
-const Stack = createStackNavigator();
 const styles = StyleSheet.create({
   viewStyleVertical : { alignItems: 'center', justifyContent: 'center', margin: '10%' },
   viewStyleHorizon : { flex: 1, flexDirection: 'row', justifyContent: 'space-between'},
diff --git a/src/package.json b/src/package.json
index 87fc242..9273acf 100644
--- a/src/package.json
+++ b/src/package.json
@@ -9,9 +9,10 @@
     "test": "jest"
   },
   "jest": {
-    "preset": "react-native",
+    "preset": "jest-expo",
+    "automock": false,
     "setupFiles": [
-      "./node_modules/react-native-gesture-handler/jestSetup.js"
+      "./setupJest.js"
     ],
     "moduleNameMapper": {
       "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
@@ -24,6 +25,8 @@
     "@react-navigation/stack": "^5.14.3",
     "expo": "~40.0.0",
     "expo-status-bar": "~1.0.3",
+    "jest-expo": "^40.0.2",
+    "jest-fetch-mock": "^3.0.3",
     "react": "16.13.1",
     "react-dom": "16.13.1",
     "react-native": "https://github.com/expo/react-native/archive/sdk-40.0.1.tar.gz",
-- 
GitLab


From 30719ac6a01d5b468cad3d72da390c5186c560ce Mon Sep 17 00:00:00 2001
From: HenryShan <zshan2@illinois.edu>
Date: Tue, 30 Mar 2021 12:27:55 +0800
Subject: [PATCH 3/4] repairing uploading

---
 src/Components/Followers.js                   |  56 +++
 src/Components/Following.js                   |  55 +++
 src/Components/LoadFollowersScreenModule.js   |  48 +++
 src/Components/LoadFollowingScreenModule.js   |  47 +++
 src/Components/LoadProfileScreenModule.js     |  46 +++
 src/Components/LoadRepoScreenModule.js        |  42 +++
 src/Components/Users.js                       |  36 ++
 src/__tests__/Button-test.js                  |  59 ++++
 src/__tests__/ErrorInFollowers-test.js        |  57 ++++
 src/__tests__/ErrorInProfile-test.js          |  87 +++++
 src/__tests__/FollowerScreen-test.js          |  74 ++++
 src/__tests__/FollowingScreen-test.js         |  74 ++++
 src/__tests__/Loading-test.js                 |  17 +
 src/__tests__/LoadingFollowersScreen-test.js  |  40 +++
 src/__tests__/LoadingFollowingScreen-test.js  |  39 +++
 src/__tests__/Profile-test.js                 |  26 ++
 src/__tests__/Repo-test.js                    |  27 ++
 src/__tests__/Unfound-test.js                 |  21 ++
 src/__tests__/Users-test.js                   |  27 ++
 .../ErrorInFollowers-test.js.snap             | 155 +++++++++
 .../__snapshots__/Loading-test.js.snap        |  78 +++++
 .../LoadingFollowersScreen-test.js.snap       |  78 +++++
 .../LoadingFollowingScreen-test.js.snap       |  78 +++++
 .../__snapshots__/Profile-test.js.snap        | 321 ++++++++++++++++++
 src/__tests__/__snapshots__/Repo-test.js.snap | 120 +++++++
 .../__snapshots__/Unfound-test.js.snap        | 110 ++++++
 .../__snapshots__/Users-test.js.snap          | 120 +++++++
 src/package.json                              |   1 +
 28 files changed, 1939 insertions(+)
 create mode 100644 src/Components/Followers.js
 create mode 100644 src/Components/Following.js
 create mode 100644 src/Components/LoadFollowersScreenModule.js
 create mode 100644 src/Components/LoadFollowingScreenModule.js
 create mode 100644 src/Components/LoadProfileScreenModule.js
 create mode 100644 src/Components/LoadRepoScreenModule.js
 create mode 100644 src/Components/Users.js
 create mode 100644 src/__tests__/Button-test.js
 create mode 100644 src/__tests__/ErrorInFollowers-test.js
 create mode 100644 src/__tests__/ErrorInProfile-test.js
 create mode 100644 src/__tests__/FollowerScreen-test.js
 create mode 100644 src/__tests__/FollowingScreen-test.js
 create mode 100644 src/__tests__/Loading-test.js
 create mode 100644 src/__tests__/LoadingFollowersScreen-test.js
 create mode 100644 src/__tests__/LoadingFollowingScreen-test.js
 create mode 100644 src/__tests__/Profile-test.js
 create mode 100644 src/__tests__/Repo-test.js
 create mode 100644 src/__tests__/Unfound-test.js
 create mode 100644 src/__tests__/Users-test.js
 create mode 100644 src/__tests__/__snapshots__/ErrorInFollowers-test.js.snap
 create mode 100644 src/__tests__/__snapshots__/Loading-test.js.snap
 create mode 100644 src/__tests__/__snapshots__/LoadingFollowersScreen-test.js.snap
 create mode 100644 src/__tests__/__snapshots__/LoadingFollowingScreen-test.js.snap
 create mode 100644 src/__tests__/__snapshots__/Profile-test.js.snap
 create mode 100644 src/__tests__/__snapshots__/Repo-test.js.snap
 create mode 100644 src/__tests__/__snapshots__/Unfound-test.js.snap
 create mode 100644 src/__tests__/__snapshots__/Users-test.js.snap

diff --git a/src/Components/Followers.js b/src/Components/Followers.js
new file mode 100644
index 0000000..778230d
--- /dev/null
+++ b/src/Components/Followers.js
@@ -0,0 +1,56 @@
+import * as React from 'react';
+import { Pressable, View, Text, Image, StyleSheet } from 'react-native';
+import Users from './Users'
+
+const styles = StyleSheet.create({
+  viewStyleVertical : { alignItems: 'center', justifyContent: 'center', margin: '10%' },
+  viewStyleHorizon : { flex: 1, flexDirection: 'row', justifyContent: 'space-between'},
+  pressableStyle : {flex: 1, flexDirection: 'row', justifyContent: 'space-between', backgroundColor:'lavender', paddingHorizontal:20, 
+  paddingVertical:10, borderColor:'thistle', borderWidth:2, borderRadius:5, marginHorizontal: 10, marginTop: 10},
+  image: { flex: 1, resizeMode: "cover", justifyContent: "center"},
+  container : {flex: 1},
+  textBox : {flex: 1, marginTop: 20, backgroundColor:'white', borderColor:'black', borderWidth:2, borderRadius:5, 
+  marginHorizontal: 10, paddingVertical:10, paddingHorizontal: 50, alignItems: 'flex-start'}
+});
+
+function Followers (user, navigation) {
+    const nodes = user['followers']['nodes']
+    const login = user['login']
+    let cards = []
+    if (nodes.length === 0) {
+        cards.push(
+        <Pressable style={styles.textBox} key={'Nobody'}>
+            <Text style={{ fontSize: 30 }}> 
+                Oops! Nobody is in this list!
+            </Text> 
+        </Pressable>
+        )
+    } else {
+        for (let i = 0; i < nodes.length; i++) {
+        var name = 'Name: \n' + nodes[i]['name'] + '\n'
+        var userName = 'Github Username: \n' + nodes[i]['login'] + '\n'
+        var key = 'user#' + i
+        var avatarUrl = nodes[i]['avatarUrl']
+        cards.push(
+        <Pressable style={styles.textBox} key={key} onPress={()=>navigation.push('LoadingProfile', {login: nodes[i]['login']})}>
+            <View style={styles.viewStyleVertical}>
+                <Image style={{width:90, height:90}} source={{uri: avatarUrl}}/>
+            </View>
+            <View style={styles.viewStyleVertical}>
+                <Text> {name} </Text>
+                <Text> {userName} </Text>
+            </View>
+        </Pressable>
+        )
+        }
+    }
+    const dataFile = {}
+    dataFile['cards'] = cards
+    dataFile['navi'] = navigation
+    dataFile['login'] = login
+    return (
+        <Users data={dataFile}/>
+    );
+}
+
+export default Followers
\ No newline at end of file
diff --git a/src/Components/Following.js b/src/Components/Following.js
new file mode 100644
index 0000000..79a8a9d
--- /dev/null
+++ b/src/Components/Following.js
@@ -0,0 +1,55 @@
+import * as React from 'react';
+import { Pressable, View, Text, Image, StyleSheet } from 'react-native';
+import Users from './Users'
+
+const styles = StyleSheet.create({
+  viewStyleVertical : { alignItems: 'center', justifyContent: 'center', margin: '10%' },
+  viewStyleHorizon : { flex: 1, flexDirection: 'row', justifyContent: 'space-between'},
+  pressableStyle : {flex: 1, flexDirection: 'row', justifyContent: 'space-between', backgroundColor:'lavender', paddingHorizontal:20, 
+  paddingVertical:10, borderColor:'thistle', borderWidth:2, borderRadius:5, marginHorizontal: 10, marginTop: 10},
+  image: { flex: 1, resizeMode: "cover", justifyContent: "center"},
+  container : {flex: 1},
+  textBox : {flex: 1, marginTop: 20, backgroundColor:'white', borderColor:'black', borderWidth:2, borderRadius:5, 
+  marginHorizontal: 10, paddingVertical:10, paddingHorizontal: 50, alignItems: 'flex-start'}
+});
+
+function Following (user, navigation) {
+    const nodes = user['following']['nodes']
+    const login = user['login']
+    let cards = []
+    if (nodes.length === 0) {
+        cards.push(
+        <Pressable style={styles.textBox} key={'Nobody'}>
+            <Text style={{ fontSize: 30 }}> 
+                Oops! Nobody is in this list!
+            </Text> 
+        </Pressable>
+        )
+    } else {
+        for (let i = 0; i < nodes.length; i++) {
+        var name = 'Name: \n' + nodes[i]['name'] + '\n'
+        var userName = 'Github Username: \n' + nodes[i]['login'] + '\n'
+        var key = 'user#' + i
+        var avatarUrl = nodes[i]['avatarUrl']
+        cards.push(
+            <Pressable style={styles.textBox} key={key} onPress={()=>navigation.push('LoadingProfile', {login: nodes[i]['login']})}>
+                <View style={styles.viewStyleVertical}>
+                <Image style={{width:90, height:90}} source={{uri: avatarUrl}}/>
+                </View>
+                <View style={styles.viewStyleVertical}>
+                <Text> {name} </Text>
+                <Text> {userName} </Text>
+                </View>
+            </Pressable>
+            )
+        }
+    }
+    const dataFile = {}
+    dataFile['cards'] = cards
+    dataFile['navi'] = navigation
+    dataFile['login'] = login
+    return (
+        <Users data={dataFile}/>
+    );
+}
+export default Following
\ No newline at end of file
diff --git a/src/Components/LoadFollowersScreenModule.js b/src/Components/LoadFollowersScreenModule.js
new file mode 100644
index 0000000..785c471
--- /dev/null
+++ b/src/Components/LoadFollowersScreenModule.js
@@ -0,0 +1,48 @@
+import * as React from 'react';
+import Loading from './Loading'
+
+/** Module part of followers screen, used to fetch data and send to View part */
+function LoadFollowersScreenModule(login, endPoint, token, navigation) {
+    fetch(endPoint, {
+        method: 'POST',
+        headers: {
+          "Content-Type": "application/json",
+          "Authorization": token
+        },
+        body: JSON.stringify({
+          query: `
+            query {
+              user(login:"`+ login +`"){
+                login
+                followers(last:100) {
+                  nodes {
+                    name
+                    login
+                    avatarUrl
+                  }
+                }
+              }
+            }
+          `
+        })
+      })
+      .then(res => res.json())
+      .then((data)=> {
+        if (data['data']['user'] === null) {
+          /** User not found! **/
+          navigation.push('Unfound', {errorMsg: 'Error, cannot find the github user by the login username:' 
+          + login + ', maybe this is an organization! \n Also maybe your internet was unstable'})
+        } else {
+          navigation.push('Followers', data['data']['user'])
+        }
+      })
+      .catch(error => {
+        navigation.push('Unfound', {errorMsg: 'Error happened' + error})
+      })
+      
+      return (
+        <Loading/>
+      );
+}
+
+export default LoadFollowersScreenModule
\ No newline at end of file
diff --git a/src/Components/LoadFollowingScreenModule.js b/src/Components/LoadFollowingScreenModule.js
new file mode 100644
index 0000000..44e8631
--- /dev/null
+++ b/src/Components/LoadFollowingScreenModule.js
@@ -0,0 +1,47 @@
+import * as React from 'react';
+import Loading from './Loading'
+
+/** Module part of following screen, used to fetch data and send to View part */
+function LoadFollowingScreenModule(login, endPoint, token, navigation) {
+    fetch(endPoint, {
+    method: 'POST',
+    headers: {
+      "Content-Type": "application/json",
+      "Authorization": token
+    },
+    body: JSON.stringify({
+      query: `
+        query {
+          user(login:"` + login + `"){
+            login
+            following(last:100) {
+              nodes {
+                name
+                login
+                avatarUrl
+              }
+            }
+          }
+        }
+      `
+    })
+  })
+  .then(res => res.json())
+  .then((data)=> {
+    if (data['data']['user'] === null) {
+      /** User not found! **/
+      navigation.push('Unfound', {errorMsg: 'Error, cannot find the github user by the login username:' 
+      + login + ', maybe this is an organization! \n Also maybe your internet was unstable'})
+    } else {
+      navigation.push('Following', data['data']['user'])
+    }
+  })
+  .catch(error => {
+    navigation.push('Unfound', {errorMsg: 'Error happened' + error})
+  })
+  return (
+    <Loading/>
+  );
+}
+
+export default LoadFollowingScreenModule;
\ No newline at end of file
diff --git a/src/Components/LoadProfileScreenModule.js b/src/Components/LoadProfileScreenModule.js
new file mode 100644
index 0000000..60c63fa
--- /dev/null
+++ b/src/Components/LoadProfileScreenModule.js
@@ -0,0 +1,46 @@
+async function LoadProfileScreenModule(login, endPoint, token, navigation) {
+    await fetch(endPoint, {
+        method: 'POST',
+        headers: {
+          "Content-Type": "application/json",
+          "Authorization": token
+        },
+        body: JSON.stringify({
+          query: `
+            query {
+              user(login:"`+ login + `") {
+                name
+                login
+                avatarUrl
+                bio
+                createdAt
+                email
+                websiteUrl
+                repositories(last:100, privacy:PUBLIC){
+                  nodes{
+                    name
+                  }
+                }
+              }
+            }
+          `
+        })
+      })
+      .then(res => res.json())
+      .then((data)=> {
+        if (data['data']['user'] === undefined) {
+          /** User not found! **/
+          navigation.push('Unfound', {errorMsg: 'Error, cannot find the github user by the login username:' 
+          + login + ', maybe this is an organization!'})
+          throw new Error('User Unfound!')
+        } else {
+          navigation.push('Profile', data['data']['user'])
+        }
+      })
+      .catch(error => {
+        navigation.push('Unfound', {errorMsg: 'Error: ' + error})
+      })
+    
+}
+
+export default LoadProfileScreenModule;
\ No newline at end of file
diff --git a/src/Components/LoadRepoScreenModule.js b/src/Components/LoadRepoScreenModule.js
new file mode 100644
index 0000000..9181ea2
--- /dev/null
+++ b/src/Components/LoadRepoScreenModule.js
@@ -0,0 +1,42 @@
+function LoadRepoScreenModule(login, endPoint, token, navigation) {
+    fetch(endPoint, {
+        method: 'POST',
+        headers: {
+          "Content-Type": "application/json",
+          "Authorization": token
+        },
+        body: JSON.stringify({
+          query: `
+            query {
+              user(login:"`+login+`"){
+                login
+                repositories(last:100, privacy:PUBLIC){
+                  nodes{
+                    name
+                    owner{
+                      login
+                    }
+                    description
+                  }
+                }
+              }
+            }
+          `
+        })
+      })
+      .then(res => res.json())
+      .then((data)=> {
+        if (data['data']['user'] === null) {
+          /** User not found! **/
+          navigation.push('Unfound', {errorMsg: 'Error, cannot find the github user by the login username:' + login + ', maybe this is an organization!'})
+        } else {
+          navigation.push('Repo', data['data']['user'])
+        }
+      })
+      .catch(error => {
+        navigation.push('Unfound', {errorMsg: 'Error: ' + error})
+      })
+    
+}
+
+export default LoadRepoScreenModule;
\ No newline at end of file
diff --git a/src/Components/Users.js b/src/Components/Users.js
new file mode 100644
index 0000000..ef70491
--- /dev/null
+++ b/src/Components/Users.js
@@ -0,0 +1,36 @@
+import * as React from 'react';
+import { Pressable, View, Text, Image, StyleSheet, ImageBackground } from 'react-native';
+
+const styles = StyleSheet.create({
+  viewStyleVertical : { alignItems: 'center', justifyContent: 'center', margin: '10%' },
+  viewStyleHorizon : { flex: 1, flexDirection: 'row', justifyContent: 'space-between'},
+  pressableStyle : {flex: 1, flexDirection: 'row', justifyContent: 'space-between', backgroundColor:'lavender', paddingHorizontal:20, 
+  paddingVertical:10, borderColor:'thistle', borderWidth:2, borderRadius:5, marginHorizontal: 10, marginTop: 10},
+  image: { flex: 1, resizeMode: "cover", justifyContent: "center"},
+  container : {flex: 1},
+  textBox : {flex: 1, marginTop: 20, backgroundColor:'white', borderColor:'black', borderWidth:2, borderRadius:5, 
+  marginHorizontal: 10, paddingVertical:10, paddingHorizontal: 50, alignItems: 'flex-start'}
+});
+
+const Users = (props) => {
+    const file = props.data
+    const cards = file['cards']
+    const navigation = file['navi']
+    return (
+        <View style={styles.container}>
+            <ImageBackground source={{uri: "https://www.fonewalls.com/wp-content/uploads/2020/04/Ice-Phone-Wallpaper.jpg"}} style={styles.image}>
+            <View style={styles.viewStyleVertical}>
+                <Pressable  style={styles.pressableStyle} onPress={() => navigation.pop(2)}>
+                <Text> Go to Profile </Text>
+                </Pressable>
+                {cards}
+                <Pressable  style={styles.pressableStyle} onPress={() => navigation.pop(2)}>
+                <Text> Go to Profile </Text>
+                </Pressable>
+            </View>
+            </ImageBackground>
+        </View>
+    )
+}
+
+export default Users;
diff --git a/src/__tests__/Button-test.js b/src/__tests__/Button-test.js
new file mode 100644
index 0000000..911bf83
--- /dev/null
+++ b/src/__tests__/Button-test.js
@@ -0,0 +1,59 @@
+import * as React from 'react';
+import { View, Text, Pressable, StyleSheet } from 'react-native';
+import { render, fireEvent } from '@testing-library/react-native';
+import Profile from '../Components/Profile'
+
+const styles = StyleSheet.create({
+  viewStyleVertical : { alignItems: 'center', justifyContent: 'center', margin: '10%' },
+  viewStyleHorizon : { flex: 1, flexDirection: 'row', justifyContent: 'space-between'},
+  pressableStyle : {flex: 1, flexDirection: 'row', justifyContent: 'space-between', backgroundColor:'lavender', paddingHorizontal:20, 
+  paddingVertical:10, borderColor:'thistle', borderWidth:2, borderRadius:5, marginHorizontal: 10, marginTop: 10},
+  image: { flex: 1, resizeMode: "cover", justifyContent: "center"},
+  container : {flex: 1},
+  textBox : {flex: 1, marginTop: 20, backgroundColor:'white', borderColor:'black', borderWidth:2, borderRadius:5, 
+  marginHorizontal: 10, paddingVertical:10, paddingHorizontal: 50, alignItems: 'flex-start'}
+});
+
+test('Followers button should trigger navigating', () => {
+  const push = jest.fn()
+  const dataFile = {
+    iconUrl: "https://avatars.githubusercontent.com/u/42978932?u=b4a7beb2752bb6059cd13d12ca26d097767abf77&v=4",
+      nameContent: null,
+      userNameContent: null,
+      bioContent: null,
+      websiteLink: null,
+      emailContent: null,
+      createData: null,
+      repoCount: 0,
+      navi: {push},
+      login: "test1"
+  }
+  const { getByText } = render(
+    <Profile data={dataFile} />
+  );
+
+  fireEvent.press(getByText(' Followers '));
+  expect(push).toHaveBeenNthCalledWith(1, "LoadingFollowers" ,{"login": "test1"});
+})
+
+test('Following button should trigger navigating', () => {
+  const push = jest.fn()
+  const dataFile = {
+    iconUrl: "https://avatars.githubusercontent.com/u/42978932?u=b4a7beb2752bb6059cd13d12ca26d097767abf77&v=4",
+      nameContent: null,
+      userNameContent: null,
+      bioContent: null,
+      websiteLink: null,
+      emailContent: null,
+      createData: null,
+      repoCount: 0,
+      navi: {push},
+      login: "test2"
+  }
+  const { getByText } = render(
+    <Profile data={dataFile} />
+  );
+
+  fireEvent.press(getByText(' Followings '));
+  expect(push).toHaveBeenNthCalledWith(1, "LoadingFollowing", {"login": "test2"});
+})
\ No newline at end of file
diff --git a/src/__tests__/ErrorInFollowers-test.js b/src/__tests__/ErrorInFollowers-test.js
new file mode 100644
index 0000000..99798c5
--- /dev/null
+++ b/src/__tests__/ErrorInFollowers-test.js
@@ -0,0 +1,57 @@
+import 'react-native';
+import renderer from 'react-test-renderer';
+import LoadFollowersScreenModule from  '../Components/LoadFollowersScreenModule'
+
+beforeEach(() => {
+  fetch.resetMocks();
+});
+
+/** Testing Loading View of Followers with Empty avatarUrl link */
+test('In the case that a user has no avatarUrl, its avatar should be a default one set in main page', () => {
+    fetch.mockResponseOnce(JSON.stringify({
+      data: {
+        user: {
+          login: "HenryShan",
+          followers: {
+            nodes: [{
+              name: "RX-78-2",
+              login: "G plan",
+              avatarUrl: null
+            }]
+          }
+        }
+      }
+    }));
+    const login = "HenryShan"
+    const envData = require('C:/Coding/cs242-assignment3/env.json')
+    const endPoint = envData['endPoint']
+    const token = envData['token']
+    const navigation = { push: jest.fn() };
+    const tree = renderer.create(
+       LoadFollowersScreenModule(login, endPoint, token, navigation)
+    ).toJSON();
+    expect(tree).toMatchSnapshot();
+  }, 70000);
+
+  /** Testing the loading view of followers when the followers value is empty, a textbox should be shown and informing this */
+  test('In the case that a user has no avatarUrl, its avatar should be a default one set in main page', () => {
+    fetch.mockResponseOnce(JSON.stringify({
+      data: {
+        user: {
+          login: "HenryShan",
+          followers: {
+            nodes: [{}]
+          }
+        }
+      }
+    }));
+    const login = "HenryShan"
+    const envData = require('C:/Coding/cs242-assignment3/env.json')
+    const endPoint = envData['endPoint']
+    const token = envData['token']
+    const navigation = { push: jest.fn() };
+    const tree = renderer.create(
+       LoadFollowersScreenModule(login, endPoint, token, navigation)
+    ).toJSON();
+    expect(tree).toMatchSnapshot();
+  }, 70000);
\ No newline at end of file
diff --git a/src/__tests__/ErrorInProfile-test.js b/src/__tests__/ErrorInProfile-test.js
new file mode 100644
index 0000000..73e6c32
--- /dev/null
+++ b/src/__tests__/ErrorInProfile-test.js
@@ -0,0 +1,87 @@
+import LoadProfileScreenModule from '../Components/LoadProfileScreenModule'
+import 'react-native';
+
+beforeEach(() => {
+    fetch.resetMocks();
+  });
+
+
+/** Testing the case when the username/login is not a person but other thing like an org */
+test('expect throwing error', () => {
+    
+    fetch.mockResponseOnce(JSON.stringify({
+        "data": {
+          "user": null
+        },
+        "errors": [
+          {
+            "type": "NOT_FOUND",
+            "path": [
+              "user"
+            ],
+            "locations": [
+              {
+                "line": 32,
+                "column": 3
+              }
+            ],
+            "message": "Could not resolve to a User with the login of '???'."
+          }
+        ]
+    }))
+    const onResponse = jest.fn();
+    const onError = jest.fn();
+    const login = "???"
+    const envData = require('C:/Coding/cs242-assignment3/env.json')
+    const endPoint = envData['endPoint']
+    const token = envData['token']
+    const navigation = { push: jest.fn() };
+    return LoadProfileScreenModule(login, endPoint, token, navigation)
+        .then(onResponse)
+        .catch(onError)
+        .finally(() => {
+            // since in this situation, return value still contains data PKT thus still get in response state
+            expect(onResponse).toHaveBeenCalled();
+            expect(onError).not.toHaveBeenCalled();
+        });
+  }, 70000);
+
+  /** Testing the case when the Internet is down and loading Profile should return the error page and throw error*/
+test('expect throwing error', () => {
+    
+    fetch.mockResponseOnce(JSON.stringify({
+        "data": {
+            "user": null
+          },
+          "errors": [
+            {
+              "type": "INTERNET_DOWN",
+              "path": [
+                "user"
+              ],
+              "locations": [
+                {
+                  "line": 32,
+                  "column": 3
+                }
+              ],
+              "message": "Cannot connect to graphQL API server."
+            }
+          ]
+    }))
+    const onResponse = jest.fn();
+    const onError = jest.fn();
+    const login = 'HenryShan'
+    const envData = require('C:/Coding/cs242-assignment3/env.json')
+    const endPoint = envData['endPoint']
+    const token = envData['token']
+    const navigation = { push: jest.fn() };
+    return LoadProfileScreenModule(login, endPoint, token, navigation)
+        .then(onResponse)
+        .catch(onError)
+        .finally(() => {
+            // since in this situation, return value still contains data PKT thus still get in response
+            expect(onResponse).toHaveBeenCalled();
+            expect(onError).not.toHaveBeenCalled();
+        });
+  }, 70000);
diff --git a/src/__tests__/FollowerScreen-test.js b/src/__tests__/FollowerScreen-test.js
new file mode 100644
index 0000000..0d419e7
--- /dev/null
+++ b/src/__tests__/FollowerScreen-test.js
@@ -0,0 +1,74 @@
+import 'react-native';
+import Followers from '../Components/Followers'
+import renderer from 'react-test-renderer';
+
+beforeEach(() => {
+    fetch.resetMocks();
+  });
+
+test('renders correctly', () => {
+    fetch.mockResponseOnce(JSON.stringify({
+      data: {
+        user: {
+            login: "HenryShan",
+            followers: {
+                nodes: [{
+                    name: "RX-78-2",
+                    login: "G plan",
+                    avatarUrl: "https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/7b10552b-57d8-42a7-8dba-d4aaad8e7c82/"
+                    + "d7p3uno-38b831f7-4933-4f09-b366-b951231e1751.jpg?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ"
+                    +"1cm46YXBwOiIsImlzcyI6InVybjphcHA6Iiwib2JqIjpbW3sicGF0aCI6IlwvZlwvN2IxMDU1MmItNTdkOC00MmE3LThkYmEtZDRhYWFk"
+                    +"OGU3YzgyXC9kN3AzdW5vLTM4YjgzMWY3LTQ5MzMtNGYwOS1iMzY2LWI5NTEyMzFlMTc1MS5qcGcifV1dLCJhdWQiOlsidXJuOnNlcnZpY2"
+                    +"U6ZmlsZS5kb3dubG9hZCJdfQ.PsPJAzWqHC1z07YMdxE4zYtFuUMXCtEMMI6VRr7Hq-k"
+                }]
+            }
+        }
+      }
+    }));
+    const login = "HenryShan"
+    const envData = require('C:/Coding/cs242-assignment3/env.json')
+    const endPoint = envData['endPoint']
+    const token = envData['token']
+    const navigation = { push: jest.fn() };
+    fetch(endPoint, {
+        method: 'POST',
+        headers: {
+          "Content-Type": "application/json",
+          "Authorization": token
+        },
+        body: JSON.stringify({
+          query: `
+            query {
+              user(login:"`+ login +`"){
+                login
+                followers(last:100) {
+                  nodes {
+                    name
+                    login
+                    avatarUrl
+                  }
+                }
+              }
+            }
+          `
+        })
+      })
+      .then(res => res.json())
+      .then((data)=> {
+        if (data['data']['user'] === null) {
+          /** User not found! **/
+          navigation.push('Unfound', {errorMsg: 'Error, cannot find the github user by the login username:' + login + ', maybe this is an organization! \n Also maybe your internet was unstable'})
+        } else {
+        //   navigation.push('Followers', data['data']['user'])
+          const tree = renderer.create(
+             Followers(data['data']['user'], navigation)
+          ).toJSON();
+          expect(tree).toMatchSnapshot();
+        }
+      })
+      .catch(error => {
+        navigation.push('Unfound', {errorMsg: 'Error:' + error})
+      })
+    
+    
+  }, 70000);
\ No newline at end of file
diff --git a/src/__tests__/FollowingScreen-test.js b/src/__tests__/FollowingScreen-test.js
new file mode 100644
index 0000000..082581b
--- /dev/null
+++ b/src/__tests__/FollowingScreen-test.js
@@ -0,0 +1,74 @@
+import 'react-native';
+import renderer from 'react-test-renderer';
+import Following from '../Components/Following';
+
+beforeEach(() => {
+    fetch.resetMocks();
+  });
+
+test('renders correctly', () => {
+    fetch.mockResponseOnce(JSON.stringify({
+      data: {
+        user: {
+            login: "HenryShan",
+            following: {
+                nodes: [{
+                    name: "RX-78-2",
+                    login: "G plan",
+                    avatarUrl: "https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/7b10552b-57d8-42a7-8dba-d4aaad8e7c82/"
+                    + "d7p3uno-38b831f7-4933-4f09-b366-b951231e1751.jpg?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ"
+                    +"1cm46YXBwOiIsImlzcyI6InVybjphcHA6Iiwib2JqIjpbW3sicGF0aCI6IlwvZlwvN2IxMDU1MmItNTdkOC00MmE3LThkYmEtZDRhYWFk"
+                    +"OGU3YzgyXC9kN3AzdW5vLTM4YjgzMWY3LTQ5MzMtNGYwOS1iMzY2LWI5NTEyMzFlMTc1MS5qcGcifV1dLCJhdWQiOlsidXJuOnNlcnZpY2"
+                    +"U6ZmlsZS5kb3dubG9hZCJdfQ.PsPJAzWqHC1z07YMdxE4zYtFuUMXCtEMMI6VRr7Hq-k"
+                }]
+            }
+        }
+      }
+    }));
+    const login = "HenryShan"
+    const envData = require('C:/Coding/cs242-assignment3/env.json')
+    const endPoint = envData['endPoint']
+    const token = envData['token']
+    const navigation = { push: jest.fn() };
+    fetch(endPoint, {
+        method: 'POST',
+        headers: {
+          "Content-Type": "application/json",
+          "Authorization": token
+        },
+        body: JSON.stringify({
+          query: `
+            query {
+              user(login:"`+ login +`"){
+                login
+                followers(last:100) {
+                  nodes {
+                    name
+                    login
+                    avatarUrl
+                  }
+                }
+              }
+            }
+          `
+        })
+      })
+      .then(res => res.json())
+      .then((data)=> {
+        if (data['data']['user'] === null) {
+          /** User not found! **/
+          navigation.push('Unfound', {errorMsg: 'Error, cannot find the github user by the login username:' + login + ', maybe this is an organization! \n Also maybe your internet was unstable'})
+        } else {
+        //   navigation.push('Followers', data['data']['user'])
+          const tree = renderer.create(
+             Following(data['data']['user'], navigation)
+          ).toJSON();
+          expect(tree).toMatchSnapshot();
+        }
+      })
+      .catch(error => {
+        navigation.push('Unfound', {errorMsg: 'Error: ' + error})
+      })
+    
+    
+  }, 70000);
\ No newline at end of file
diff --git a/src/__tests__/Loading-test.js b/src/__tests__/Loading-test.js
new file mode 100644
index 0000000..2fee5fd
--- /dev/null
+++ b/src/__tests__/Loading-test.js
@@ -0,0 +1,17 @@
+import 'react-native';
+import React from 'react';
+import renderer from 'react-test-renderer';
+import Loading from '../Components/Loading';
+import { createStackNavigator } from '@react-navigation/stack';
+
+beforeEach(() => {
+    fetch.resetMocks();
+  });
+
+/** Testing all loading pages */
+test('renders correctly', () => {
+    const tree = renderer.create(
+        <Loading />
+    ).toJSON();
+    expect(tree).toMatchSnapshot();
+});
\ No newline at end of file
diff --git a/src/__tests__/LoadingFollowersScreen-test.js b/src/__tests__/LoadingFollowersScreen-test.js
new file mode 100644
index 0000000..2b18f62
--- /dev/null
+++ b/src/__tests__/LoadingFollowersScreen-test.js
@@ -0,0 +1,40 @@
+import * as React from 'react';
+import 'react-native';
+import renderer from 'react-test-renderer';
+import LoadFollowersScreenModule from  '../Components/LoadFollowersScreenModule'
+
+beforeEach(() => {
+  fetch.resetMocks();
+});
+
+  /** Testing Loading View of Followers */
+  test('renders correctly', () => {
+    fetch.mockResponseOnce(JSON.stringify({
+      data: {
+        user: {
+          login: "HenryShan",
+          followers: {
+            nodes: [{
+              name: "RX-78-2",
+              login: "G plan",
+              avatarUrl: "https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/7b10552b-57d8-42a7-8dba-d4aaad8e7c82/"
+                + "d7p3uno-38b831f7-4933-4f09-b366-b951231e1751.jpg?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ"
+                +"1cm46YXBwOiIsImlzcyI6InVybjphcHA6Iiwib2JqIjpbW3sicGF0aCI6IlwvZlwvN2IxMDU1MmItNTdkOC00MmE3LThkYmEtZDRhYWFk"
+                +"OGU3YzgyXC9kN3AzdW5vLTM4YjgzMWY3LTQ5MzMtNGYwOS1iMzY2LWI5NTEyMzFlMTc1MS5qcGcifV1dLCJhdWQiOlsidXJuOnNlcnZpY2"
+                +"U6ZmlsZS5kb3dubG9hZCJdfQ.PsPJAzWqHC1z07YMdxE4zYtFuUMXCtEMMI6VRr7Hq-k"
+            }]
+          }
+        }
+      }
+    }));
+    const login = "HenryShan"
+    const envData = require('C:/Coding/cs242-assignment3/env.json')
+    const endPoint = envData['endPoint']
+    const token = envData['token']
+    const push = jest.fn();
+    const tree = renderer.create(
+       LoadFollowersScreenModule(login, endPoint, token, {push})
+    ).toJSON();
+    expect(tree).toMatchSnapshot();
+  }, 70000);
+  
diff --git a/src/__tests__/LoadingFollowingScreen-test.js b/src/__tests__/LoadingFollowingScreen-test.js
new file mode 100644
index 0000000..6abcee1
--- /dev/null
+++ b/src/__tests__/LoadingFollowingScreen-test.js
@@ -0,0 +1,39 @@
+import 'react-native';
+import renderer from 'react-test-renderer';
+import LoadFollowingScreenModule from  '../Components/LoadFollowingScreenModule'
+
+beforeEach(() => {
+    fetch.resetMocks();
+  });
+
+  /** Testing Loading View for Following */
+  test('renders correctly', () => {
+    fetch.mockResponseOnce(JSON.stringify({
+        data: {
+            user: {
+                login: "HenryShan",
+                following: {
+                    nodes: [{
+                        name: "RX-78-2",
+                        login: "G plan",
+                        avatarUrl: "https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/7b10552b-57d8-42a7-8dba-d4aaad8e7c82/"
+                        + "d7p3uno-38b831f7-4933-4f09-b366-b951231e1751.jpg?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ"
+                        +"1cm46YXBwOiIsImlzcyI6InVybjphcHA6Iiwib2JqIjpbW3sicGF0aCI6IlwvZlwvN2IxMDU1MmItNTdkOC00MmE3LThkYmEtZDRhYWFk"
+                        +"OGU3YzgyXC9kN3AzdW5vLTM4YjgzMWY3LTQ5MzMtNGYwOS1iMzY2LWI5NTEyMzFlMTc1MS5qcGcifV1dLCJhdWQiOlsidXJuOnNlcnZpY2"
+                        +"U6ZmlsZS5kb3dubG9hZCJdfQ.PsPJAzWqHC1z07YMdxE4zYtFuUMXCtEMMI6VRr7Hq-k"
+                    }]
+                }
+            }
+        }
+    }));
+    const login = "HenryShan"
+    const envData = require('C:/Coding/cs242-assignment3/env.json')
+    const endPoint = envData['endPoint']
+    const token = envData['token']
+    const navigation = { push: jest.fn() };
+    const tree = renderer.create(
+        LoadFollowingScreenModule(login, endPoint, token, navigation)
+    ).toJSON();
+    expect(tree).toMatchSnapshot();
+  }, 70000);
+  
\ No newline at end of file
diff --git a/src/__tests__/Profile-test.js b/src/__tests__/Profile-test.js
new file mode 100644
index 0000000..031ed57
--- /dev/null
+++ b/src/__tests__/Profile-test.js
@@ -0,0 +1,26 @@
+import 'react-native';
+import React from 'react';
+import Profile from '../Components/Profile';
+import renderer from 'react-test-renderer';
+
+beforeEach(() => {
+    fetch.resetMocks();
+  });
+
+test('renders correctly', () => {
+    const dataFile = {
+      iconUrl: "https://avatars.githubusercontent.com/u/42978932?u=b4a7beb2752bb6059cd13d12ca26d097767abf77&v=4",
+      nameContent: null,
+      userNameContent: null,
+      bioContent: null,
+      websiteLink: null,
+      emailContent: null,
+      createData: null,
+      repoCount: 0,
+      navi: { navigate: jest.fn() }
+    }
+    const tree = renderer.create(
+      <Profile data={dataFile}/>
+    ).toJSON();
+    expect(tree).toMatchSnapshot();
+  }, 70000);
\ No newline at end of file
diff --git a/src/__tests__/Repo-test.js b/src/__tests__/Repo-test.js
new file mode 100644
index 0000000..2ac8c22
--- /dev/null
+++ b/src/__tests__/Repo-test.js
@@ -0,0 +1,27 @@
+import 'react-native';
+import React from 'react';
+import renderer from 'react-test-renderer';
+import Repo from '../Components/Repo';
+
+beforeEach(() => {
+    fetch.resetMocks();
+  });
+
+  /** Testing repo pages */
+  test('renders correctly', () => {
+    const dataFile = {
+      iconUrl: "https://avatars.githubusercontent.com/u/42978932?u=b4a7beb2752bb6059cd13d12ca26d097767abf77&v=4",
+      nameContent: null,
+      userNameContent: null,
+      bioContent: null,
+      websiteLink: null,
+      emailContent: null,
+      createData: null,
+      repoCount: 0,
+      navi: { navigate: jest.fn() }
+    }
+    const tree = renderer.create(
+      <Repo data={dataFile}/>
+    ).toJSON();
+    expect(tree).toMatchSnapshot();
+  }, 70000);
diff --git a/src/__tests__/Unfound-test.js b/src/__tests__/Unfound-test.js
new file mode 100644
index 0000000..70973c3
--- /dev/null
+++ b/src/__tests__/Unfound-test.js
@@ -0,0 +1,21 @@
+import 'react-native';
+import React from 'react';
+import renderer from 'react-test-renderer';
+import Unfound from '../Components/Unfound';
+
+beforeEach(() => {
+    fetch.resetMocks();
+  });
+
+
+
+/** Testing unfound/error pages */
+test('renders correctly', () => {
+  const dataFile = {
+    navi: jest.fn()
+  }
+  const tree = renderer.create(
+    <Unfound data={dataFile}/>
+  ).toJSON();
+    expect(tree).toMatchSnapshot();
+}, 50000);
\ No newline at end of file
diff --git a/src/__tests__/Users-test.js b/src/__tests__/Users-test.js
new file mode 100644
index 0000000..2699b83
--- /dev/null
+++ b/src/__tests__/Users-test.js
@@ -0,0 +1,27 @@
+import 'react-native';
+import React from 'react';
+import renderer from 'react-test-renderer';
+import Users from  '../Components/Users'
+
+beforeEach(() => {
+  fetch.resetMocks();
+});
+
+  /** Testing all Users pages (Followers and Following) */
+  test('renders correctly', () => {
+    const dataFile = {
+      iconUrl: "https://avatars.githubusercontent.com/u/42978932?u=b4a7beb2752bb6059cd13d12ca26d097767abf77&v=4",
+      nameContent: null,
+      userNameContent: null,
+      bioContent: null,
+      websiteLink: null,
+      emailContent: null,
+      createData: null,
+      repoCount: 0,
+      navi: { navigate: jest.fn() }
+    }
+    const tree = renderer.create(
+      <Users data={dataFile}/>
+    ).toJSON();
+    expect(tree).toMatchSnapshot();
+  }, 70000);
\ No newline at end of file
diff --git a/src/__tests__/__snapshots__/ErrorInFollowers-test.js.snap b/src/__tests__/__snapshots__/ErrorInFollowers-test.js.snap
new file mode 100644
index 0000000..d557758
--- /dev/null
+++ b/src/__tests__/__snapshots__/ErrorInFollowers-test.js.snap
@@ -0,0 +1,155 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`In the case that a user has no avatarUrl, its avatar should be a default one set in main page 1`] = `
+<View
+  style={
+    Object {
+      "flex": 1,
+    }
+  }
+>
+  <View
+    accessibilityIgnoresInvertColors={true}
+    style={
+      Object {
+        "flex": 1,
+        "justifyContent": "center",
+        "resizeMode": "cover",
+      }
+    }
+  >
+    <Image
+      source={
+        Object {
+          "uri": "https://www.fonewalls.com/wp-content/uploads/2020/04/Ice-Phone-Wallpaper.jpg",
+        }
+      }
+      style={
+        Array [
+          Object {
+            "bottom": 0,
+            "left": 0,
+            "position": "absolute",
+            "right": 0,
+            "top": 0,
+          },
+          Object {
+            "height": undefined,
+            "width": undefined,
+          },
+          undefined,
+        ]
+      }
+    />
+    <View
+      style={
+        Object {
+          "alignItems": "center",
+          "justifyContent": "center",
+          "margin": "10%",
+        }
+      }
+    >
+      <Text
+        style={
+          Object {
+            "fontSize": 30,
+          }
+        }
+      >
+        Loading......
+      </Text>
+      <Image
+        source={
+          Object {
+            "uri": "http://simpleicon.com/wp-content/uploads/refresh.png",
+          }
+        }
+        style={
+          Object {
+            "height": 200,
+            "width": 200,
+          }
+        }
+      />
+    </View>
+  </View>
+</View>
+`;
+
+exports[`In the case that a user has no avatarUrl, its avatar should be a default one set in main page 2`] = `
+<View
+  style={
+    Object {
+      "flex": 1,
+    }
+  }
+>
+  <View
+    accessibilityIgnoresInvertColors={true}
+    style={
+      Object {
+        "flex": 1,
+        "justifyContent": "center",
+        "resizeMode": "cover",
+      }
+    }
+  >
+    <Image
+      source={
+        Object {
+          "uri": "https://www.fonewalls.com/wp-content/uploads/2020/04/Ice-Phone-Wallpaper.jpg",
+        }
+      }
+      style={
+        Array [
+          Object {
+            "bottom": 0,
+            "left": 0,
+            "position": "absolute",
+            "right": 0,
+            "top": 0,
+          },
+          Object {
+            "height": undefined,
+            "width": undefined,
+          },
+          undefined,
+        ]
+      }
+    />
+    <View
+      style={
+        Object {
+          "alignItems": "center",
+          "justifyContent": "center",
+          "margin": "10%",
+        }
+      }
+    >
+      <Text
+        style={
+          Object {
+            "fontSize": 30,
+          }
+        }
+      >
+        Loading......
+      </Text>
+      <Image
+        source={
+          Object {
+            "uri": "http://simpleicon.com/wp-content/uploads/refresh.png",
+          }
+        }
+        style={
+          Object {
+            "height": 200,
+            "width": 200,
+          }
+        }
+      />
+    </View>
+  </View>
+</View>
+`;
diff --git a/src/__tests__/__snapshots__/Loading-test.js.snap b/src/__tests__/__snapshots__/Loading-test.js.snap
new file mode 100644
index 0000000..9834e0e
--- /dev/null
+++ b/src/__tests__/__snapshots__/Loading-test.js.snap
@@ -0,0 +1,78 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+<View
+  style={
+    Object {
+      "flex": 1,
+    }
+  }
+>
+  <View
+    accessibilityIgnoresInvertColors={true}
+    style={
+      Object {
+        "flex": 1,
+        "justifyContent": "center",
+        "resizeMode": "cover",
+      }
+    }
+  >
+    <Image
+      source={
+        Object {
+          "uri": "https://www.fonewalls.com/wp-content/uploads/2020/04/Ice-Phone-Wallpaper.jpg",
+        }
+      }
+      style={
+        Array [
+          Object {
+            "bottom": 0,
+            "left": 0,
+            "position": "absolute",
+            "right": 0,
+            "top": 0,
+          },
+          Object {
+            "height": undefined,
+            "width": undefined,
+          },
+          undefined,
+        ]
+      }
+    />
+    <View
+      style={
+        Object {
+          "alignItems": "center",
+          "justifyContent": "center",
+          "margin": "10%",
+        }
+      }
+    >
+      <Text
+        style={
+          Object {
+            "fontSize": 30,
+          }
+        }
+      >
+        Loading......
+      </Text>
+      <Image
+        source={
+          Object {
+            "uri": "http://simpleicon.com/wp-content/uploads/refresh.png",
+          }
+        }
+        style={
+          Object {
+            "height": 200,
+            "width": 200,
+          }
+        }
+      />
+    </View>
+  </View>
+</View>
+`;
diff --git a/src/__tests__/__snapshots__/LoadingFollowersScreen-test.js.snap b/src/__tests__/__snapshots__/LoadingFollowersScreen-test.js.snap
new file mode 100644
index 0000000..9834e0e
--- /dev/null
+++ b/src/__tests__/__snapshots__/LoadingFollowersScreen-test.js.snap
@@ -0,0 +1,78 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+<View
+  style={
+    Object {
+      "flex": 1,
+    }
+  }
+>
+  <View
+    accessibilityIgnoresInvertColors={true}
+    style={
+      Object {
+        "flex": 1,
+        "justifyContent": "center",
+        "resizeMode": "cover",
+      }
+    }
+  >
+    <Image
+      source={
+        Object {
+          "uri": "https://www.fonewalls.com/wp-content/uploads/2020/04/Ice-Phone-Wallpaper.jpg",
+        }
+      }
+      style={
+        Array [
+          Object {
+            "bottom": 0,
+            "left": 0,
+            "position": "absolute",
+            "right": 0,
+            "top": 0,
+          },
+          Object {
+            "height": undefined,
+            "width": undefined,
+          },
+          undefined,
+        ]
+      }
+    />
+    <View
+      style={
+        Object {
+          "alignItems": "center",
+          "justifyContent": "center",
+          "margin": "10%",
+        }
+      }
+    >
+      <Text
+        style={
+          Object {
+            "fontSize": 30,
+          }
+        }
+      >
+        Loading......
+      </Text>
+      <Image
+        source={
+          Object {
+            "uri": "http://simpleicon.com/wp-content/uploads/refresh.png",
+          }
+        }
+        style={
+          Object {
+            "height": 200,
+            "width": 200,
+          }
+        }
+      />
+    </View>
+  </View>
+</View>
+`;
diff --git a/src/__tests__/__snapshots__/LoadingFollowingScreen-test.js.snap b/src/__tests__/__snapshots__/LoadingFollowingScreen-test.js.snap
new file mode 100644
index 0000000..9834e0e
--- /dev/null
+++ b/src/__tests__/__snapshots__/LoadingFollowingScreen-test.js.snap
@@ -0,0 +1,78 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+<View
+  style={
+    Object {
+      "flex": 1,
+    }
+  }
+>
+  <View
+    accessibilityIgnoresInvertColors={true}
+    style={
+      Object {
+        "flex": 1,
+        "justifyContent": "center",
+        "resizeMode": "cover",
+      }
+    }
+  >
+    <Image
+      source={
+        Object {
+          "uri": "https://www.fonewalls.com/wp-content/uploads/2020/04/Ice-Phone-Wallpaper.jpg",
+        }
+      }
+      style={
+        Array [
+          Object {
+            "bottom": 0,
+            "left": 0,
+            "position": "absolute",
+            "right": 0,
+            "top": 0,
+          },
+          Object {
+            "height": undefined,
+            "width": undefined,
+          },
+          undefined,
+        ]
+      }
+    />
+    <View
+      style={
+        Object {
+          "alignItems": "center",
+          "justifyContent": "center",
+          "margin": "10%",
+        }
+      }
+    >
+      <Text
+        style={
+          Object {
+            "fontSize": 30,
+          }
+        }
+      >
+        Loading......
+      </Text>
+      <Image
+        source={
+          Object {
+            "uri": "http://simpleicon.com/wp-content/uploads/refresh.png",
+          }
+        }
+        style={
+          Object {
+            "height": 200,
+            "width": 200,
+          }
+        }
+      />
+    </View>
+  </View>
+</View>
+`;
diff --git a/src/__tests__/__snapshots__/Profile-test.js.snap b/src/__tests__/__snapshots__/Profile-test.js.snap
new file mode 100644
index 0000000..04de496
--- /dev/null
+++ b/src/__tests__/__snapshots__/Profile-test.js.snap
@@ -0,0 +1,321 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+<View
+  style={
+    Object {
+      "flex": 1,
+    }
+  }
+>
+  <View
+    accessibilityIgnoresInvertColors={true}
+    style={
+      Object {
+        "flex": 1,
+        "justifyContent": "center",
+        "resizeMode": "cover",
+      }
+    }
+  >
+    <Image
+      source={
+        Object {
+          "uri": "https://www.fonewalls.com/wp-content/uploads/2020/04/Ice-Phone-Wallpaper.jpg",
+        }
+      }
+      style={
+        Array [
+          Object {
+            "bottom": 0,
+            "left": 0,
+            "position": "absolute",
+            "right": 0,
+            "top": 0,
+          },
+          Object {
+            "height": undefined,
+            "width": undefined,
+          },
+          undefined,
+        ]
+      }
+    />
+    <View
+      style={
+        Object {
+          "alignItems": "center",
+          "justifyContent": "center",
+          "margin": "10%",
+        }
+      }
+    >
+      <View
+        style={
+          Object {
+            "alignItems": "center",
+            "justifyContent": "center",
+            "margin": "10%",
+          }
+        }
+      >
+        <Image
+          source={
+            Object {
+              "uri": "https://avatars.githubusercontent.com/u/42978932?u=b4a7beb2752bb6059cd13d12ca26d097767abf77&v=4",
+            }
+          }
+          style={
+            Object {
+              "height": 120,
+              "width": 120,
+            }
+          }
+        />
+      </View>
+      <View
+        style={
+          Object {
+            "flex": 1,
+            "flexDirection": "row",
+            "justifyContent": "space-between",
+          }
+        }
+      >
+        <View
+          accessible={true}
+          focusable={true}
+          onBlur={[Function]}
+          onClick={[Function]}
+          onFocus={[Function]}
+          onResponderGrant={[Function]}
+          onResponderMove={[Function]}
+          onResponderRelease={[Function]}
+          onResponderTerminate={[Function]}
+          onResponderTerminationRequest={[Function]}
+          onStartShouldSetResponder={[Function]}
+          style={
+            Object {
+              "backgroundColor": "lavender",
+              "borderColor": "thistle",
+              "borderRadius": 5,
+              "borderWidth": 2,
+              "flex": 1,
+              "flexDirection": "row",
+              "justifyContent": "space-between",
+              "marginHorizontal": 10,
+              "marginTop": 10,
+              "paddingHorizontal": 20,
+              "paddingVertical": 10,
+            }
+          }
+        >
+          <Text>
+             Followers 
+          </Text>
+        </View>
+        <View
+          accessible={true}
+          focusable={true}
+          onBlur={[Function]}
+          onClick={[Function]}
+          onFocus={[Function]}
+          onResponderGrant={[Function]}
+          onResponderMove={[Function]}
+          onResponderRelease={[Function]}
+          onResponderTerminate={[Function]}
+          onResponderTerminationRequest={[Function]}
+          onStartShouldSetResponder={[Function]}
+          style={
+            Object {
+              "backgroundColor": "lavender",
+              "borderColor": "thistle",
+              "borderRadius": 5,
+              "borderWidth": 2,
+              "flex": 1,
+              "flexDirection": "row",
+              "justifyContent": "space-between",
+              "marginHorizontal": 10,
+              "marginTop": 10,
+              "paddingHorizontal": 20,
+              "paddingVertical": 10,
+            }
+          }
+        >
+          <Text>
+             Followings 
+          </Text>
+        </View>
+      </View>
+      <View
+        style={
+          Object {
+            "alignItems": "center",
+            "justifyContent": "center",
+            "margin": "10%",
+          }
+        }
+      >
+        <Text
+          style={
+            Object {
+              "alignItems": "flex-start",
+              "backgroundColor": "white",
+              "borderColor": "black",
+              "borderRadius": 5,
+              "borderWidth": 2,
+              "flex": 1,
+              "marginHorizontal": 10,
+              "marginTop": 20,
+              "paddingHorizontal": 50,
+              "paddingVertical": 10,
+            }
+          }
+        >
+           
+           
+        </Text>
+        <Text
+          style={
+            Object {
+              "alignItems": "flex-start",
+              "backgroundColor": "white",
+              "borderColor": "black",
+              "borderRadius": 5,
+              "borderWidth": 2,
+              "flex": 1,
+              "marginHorizontal": 10,
+              "marginTop": 20,
+              "paddingHorizontal": 50,
+              "paddingVertical": 10,
+            }
+          }
+        >
+           
+           
+        </Text>
+        <Text
+          style={
+            Object {
+              "alignItems": "flex-start",
+              "backgroundColor": "white",
+              "borderColor": "black",
+              "borderRadius": 5,
+              "borderWidth": 2,
+              "flex": 1,
+              "marginHorizontal": 10,
+              "marginTop": 20,
+              "paddingHorizontal": 50,
+              "paddingVertical": 10,
+            }
+          }
+        >
+           
+           
+        </Text>
+        <Text
+          style={
+            Object {
+              "alignItems": "flex-start",
+              "backgroundColor": "white",
+              "borderColor": "black",
+              "borderRadius": 5,
+              "borderWidth": 2,
+              "flex": 1,
+              "marginHorizontal": 10,
+              "marginTop": 20,
+              "paddingHorizontal": 50,
+              "paddingVertical": 10,
+            }
+          }
+        >
+           
+           
+        </Text>
+        <Text
+          style={
+            Object {
+              "alignItems": "flex-start",
+              "backgroundColor": "white",
+              "borderColor": "black",
+              "borderRadius": 5,
+              "borderWidth": 2,
+              "flex": 1,
+              "marginHorizontal": 10,
+              "marginTop": 20,
+              "paddingHorizontal": 50,
+              "paddingVertical": 10,
+            }
+          }
+        >
+           
+           
+        </Text>
+        <Text
+          style={
+            Object {
+              "alignItems": "flex-start",
+              "backgroundColor": "white",
+              "borderColor": "black",
+              "borderRadius": 5,
+              "borderWidth": 2,
+              "flex": 1,
+              "marginHorizontal": 10,
+              "marginTop": 20,
+              "paddingHorizontal": 50,
+              "paddingVertical": 10,
+            }
+          }
+        >
+           
+           
+        </Text>
+      </View>
+      <View
+        style={
+          Object {
+            "alignItems": "center",
+            "justifyContent": "center",
+            "margin": "10%",
+          }
+        }
+      >
+        <View
+          accessible={true}
+          focusable={true}
+          onBlur={[Function]}
+          onClick={[Function]}
+          onFocus={[Function]}
+          onResponderGrant={[Function]}
+          onResponderMove={[Function]}
+          onResponderRelease={[Function]}
+          onResponderTerminate={[Function]}
+          onResponderTerminationRequest={[Function]}
+          onStartShouldSetResponder={[Function]}
+          style={
+            Object {
+              "backgroundColor": "lavender",
+              "borderColor": "thistle",
+              "borderRadius": 5,
+              "borderWidth": 2,
+              "flex": 1,
+              "flexDirection": "row",
+              "justifyContent": "space-between",
+              "marginHorizontal": 10,
+              "marginTop": 10,
+              "paddingHorizontal": 20,
+              "paddingVertical": 10,
+            }
+          }
+        >
+          <Text>
+             
+            0
+             
+          </Text>
+        </View>
+      </View>
+    </View>
+  </View>
+</View>
+`;
diff --git a/src/__tests__/__snapshots__/Repo-test.js.snap b/src/__tests__/__snapshots__/Repo-test.js.snap
new file mode 100644
index 0000000..7fc91eb
--- /dev/null
+++ b/src/__tests__/__snapshots__/Repo-test.js.snap
@@ -0,0 +1,120 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+<View
+  style={
+    Object {
+      "flex": 1,
+    }
+  }
+>
+  <View
+    accessibilityIgnoresInvertColors={true}
+    style={
+      Object {
+        "flex": 1,
+        "justifyContent": "center",
+        "resizeMode": "cover",
+      }
+    }
+  >
+    <Image
+      source={
+        Object {
+          "uri": "https://www.fonewalls.com/wp-content/uploads/2020/04/Ice-Phone-Wallpaper.jpg",
+        }
+      }
+      style={
+        Array [
+          Object {
+            "bottom": 0,
+            "left": 0,
+            "position": "absolute",
+            "right": 0,
+            "top": 0,
+          },
+          Object {
+            "height": undefined,
+            "width": undefined,
+          },
+          undefined,
+        ]
+      }
+    />
+    <View
+      style={
+        Object {
+          "alignItems": "center",
+          "justifyContent": "center",
+          "margin": "10%",
+        }
+      }
+    >
+      <View
+        accessible={true}
+        focusable={true}
+        onBlur={[Function]}
+        onClick={[Function]}
+        onFocus={[Function]}
+        onResponderGrant={[Function]}
+        onResponderMove={[Function]}
+        onResponderRelease={[Function]}
+        onResponderTerminate={[Function]}
+        onResponderTerminationRequest={[Function]}
+        onStartShouldSetResponder={[Function]}
+        style={
+          Object {
+            "backgroundColor": "lavender",
+            "borderColor": "thistle",
+            "borderRadius": 5,
+            "borderWidth": 2,
+            "flex": 1,
+            "flexDirection": "row",
+            "justifyContent": "space-between",
+            "marginHorizontal": 10,
+            "marginTop": 10,
+            "paddingHorizontal": 20,
+            "paddingVertical": 10,
+          }
+        }
+      >
+        <Text>
+           Go to Profile 
+        </Text>
+      </View>
+      <View
+        accessible={true}
+        focusable={true}
+        onBlur={[Function]}
+        onClick={[Function]}
+        onFocus={[Function]}
+        onResponderGrant={[Function]}
+        onResponderMove={[Function]}
+        onResponderRelease={[Function]}
+        onResponderTerminate={[Function]}
+        onResponderTerminationRequest={[Function]}
+        onStartShouldSetResponder={[Function]}
+        style={
+          Object {
+            "backgroundColor": "lavender",
+            "borderColor": "thistle",
+            "borderRadius": 5,
+            "borderWidth": 2,
+            "flex": 1,
+            "flexDirection": "row",
+            "justifyContent": "space-between",
+            "marginHorizontal": 10,
+            "marginTop": 10,
+            "paddingHorizontal": 20,
+            "paddingVertical": 10,
+          }
+        }
+      >
+        <Text>
+           Go to Profile 
+        </Text>
+      </View>
+    </View>
+  </View>
+</View>
+`;
diff --git a/src/__tests__/__snapshots__/Unfound-test.js.snap b/src/__tests__/__snapshots__/Unfound-test.js.snap
new file mode 100644
index 0000000..7822434
--- /dev/null
+++ b/src/__tests__/__snapshots__/Unfound-test.js.snap
@@ -0,0 +1,110 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+<View
+  style={
+    Object {
+      "flex": 1,
+    }
+  }
+>
+  <View
+    accessibilityIgnoresInvertColors={true}
+    style={
+      Object {
+        "flex": 1,
+        "justifyContent": "center",
+        "resizeMode": "cover",
+      }
+    }
+  >
+    <Image
+      source={
+        Object {
+          "uri": "https://www.fonewalls.com/wp-content/uploads/2020/04/Ice-Phone-Wallpaper.jpg",
+        }
+      }
+      style={
+        Array [
+          Object {
+            "bottom": 0,
+            "left": 0,
+            "position": "absolute",
+            "right": 0,
+            "top": 0,
+          },
+          Object {
+            "height": undefined,
+            "width": undefined,
+          },
+          undefined,
+        ]
+      }
+    />
+    <View
+      style={
+        Object {
+          "alignItems": "center",
+          "justifyContent": "center",
+          "margin": "10%",
+        }
+      }
+    >
+      <Text
+        style={
+          Object {
+            "fontSize": 30,
+          }
+        }
+      >
+         Error! Check log to see details 
+      </Text>
+      <Image
+        source={
+          Object {
+            "uri": "https://upload.wikimedia.org/wikipedia/commons/thumb/1/17/Warning.svg/156px-Warning.svg.png",
+          }
+        }
+        style={
+          Object {
+            "height": 200,
+            "width": 200,
+          }
+        }
+      />
+      <View
+        accessible={true}
+        focusable={true}
+        onBlur={[Function]}
+        onClick={[Function]}
+        onFocus={[Function]}
+        onResponderGrant={[Function]}
+        onResponderMove={[Function]}
+        onResponderRelease={[Function]}
+        onResponderTerminate={[Function]}
+        onResponderTerminationRequest={[Function]}
+        onStartShouldSetResponder={[Function]}
+        style={
+          Object {
+            "backgroundColor": "lavender",
+            "borderColor": "thistle",
+            "borderRadius": 5,
+            "borderWidth": 2,
+            "flex": 1,
+            "flexDirection": "row",
+            "justifyContent": "space-between",
+            "marginHorizontal": 10,
+            "marginTop": 10,
+            "paddingHorizontal": 20,
+            "paddingVertical": 10,
+          }
+        }
+      >
+        <Text>
+           Go back to Home Page 
+        </Text>
+      </View>
+    </View>
+  </View>
+</View>
+`;
diff --git a/src/__tests__/__snapshots__/Users-test.js.snap b/src/__tests__/__snapshots__/Users-test.js.snap
new file mode 100644
index 0000000..7fc91eb
--- /dev/null
+++ b/src/__tests__/__snapshots__/Users-test.js.snap
@@ -0,0 +1,120 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+<View
+  style={
+    Object {
+      "flex": 1,
+    }
+  }
+>
+  <View
+    accessibilityIgnoresInvertColors={true}
+    style={
+      Object {
+        "flex": 1,
+        "justifyContent": "center",
+        "resizeMode": "cover",
+      }
+    }
+  >
+    <Image
+      source={
+        Object {
+          "uri": "https://www.fonewalls.com/wp-content/uploads/2020/04/Ice-Phone-Wallpaper.jpg",
+        }
+      }
+      style={
+        Array [
+          Object {
+            "bottom": 0,
+            "left": 0,
+            "position": "absolute",
+            "right": 0,
+            "top": 0,
+          },
+          Object {
+            "height": undefined,
+            "width": undefined,
+          },
+          undefined,
+        ]
+      }
+    />
+    <View
+      style={
+        Object {
+          "alignItems": "center",
+          "justifyContent": "center",
+          "margin": "10%",
+        }
+      }
+    >
+      <View
+        accessible={true}
+        focusable={true}
+        onBlur={[Function]}
+        onClick={[Function]}
+        onFocus={[Function]}
+        onResponderGrant={[Function]}
+        onResponderMove={[Function]}
+        onResponderRelease={[Function]}
+        onResponderTerminate={[Function]}
+        onResponderTerminationRequest={[Function]}
+        onStartShouldSetResponder={[Function]}
+        style={
+          Object {
+            "backgroundColor": "lavender",
+            "borderColor": "thistle",
+            "borderRadius": 5,
+            "borderWidth": 2,
+            "flex": 1,
+            "flexDirection": "row",
+            "justifyContent": "space-between",
+            "marginHorizontal": 10,
+            "marginTop": 10,
+            "paddingHorizontal": 20,
+            "paddingVertical": 10,
+          }
+        }
+      >
+        <Text>
+           Go to Profile 
+        </Text>
+      </View>
+      <View
+        accessible={true}
+        focusable={true}
+        onBlur={[Function]}
+        onClick={[Function]}
+        onFocus={[Function]}
+        onResponderGrant={[Function]}
+        onResponderMove={[Function]}
+        onResponderRelease={[Function]}
+        onResponderTerminate={[Function]}
+        onResponderTerminationRequest={[Function]}
+        onStartShouldSetResponder={[Function]}
+        style={
+          Object {
+            "backgroundColor": "lavender",
+            "borderColor": "thistle",
+            "borderRadius": 5,
+            "borderWidth": 2,
+            "flex": 1,
+            "flexDirection": "row",
+            "justifyContent": "space-between",
+            "marginHorizontal": 10,
+            "marginTop": 10,
+            "paddingHorizontal": 20,
+            "paddingVertical": 10,
+          }
+        }
+      >
+        <Text>
+           Go to Profile 
+        </Text>
+      </View>
+    </View>
+  </View>
+</View>
+`;
diff --git a/src/package.json b/src/package.json
index 9273acf..8486e4a 100644
--- a/src/package.json
+++ b/src/package.json
@@ -39,6 +39,7 @@
   },
   "devDependencies": {
     "@babel/core": "~7.9.0",
+    "@testing-library/react-native": "^7.2.0",
     "jest": "^26.6.3"
   },
   "private": true
-- 
GitLab


From 06f3386adb81fe259b4112a84ec5e573c16670fb Mon Sep 17 00:00:00 2001
From: HenryShan <zshan2@illinois.edu>
Date: Tue, 30 Mar 2021 12:29:36 +0800
Subject: [PATCH 4/4] ReadMe updated

---
 GitView   | 2 +-
 README.md | 3 +++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/GitView b/GitView
index 6902827..f7225e5 160000
--- a/GitView
+++ b/GitView
@@ -1 +1 @@
-Subproject commit 690282746b8a50666215d24d2bf4c8cb7801b9de
+Subproject commit f7225e509f6d0c009ab70f58c906ec2d474caa7e
diff --git a/README.md b/README.md
index 7ab5a6a..6ea8ec1 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,9 @@
 
 Description: this repo is for UIUC CS242 SP21's assignment3
 
+## Important: 
+Necessary files are all in /src directory since /GitView is considered as a submodule by git now, please check that folder.
+
 ## Functionalities:
 - Giving github's graphQL API endpoint address, user OAuth token, and username, get personal info of this user and rendered it in mobile devices.
 - Find other github user's info through following & follower lists and public repo owners.
-- 
GitLab