Compare commits
32 Commits
DarkLightT
...
master
@ -1,32 +0,0 @@
|
||||
# React-Native BUT2 Notation
|
||||
|
||||
Duration : 10 * 2h
|
||||
|
||||
## Documentation (4 pts)
|
||||
|
||||
* Application sketches
|
||||
|
||||
## Basics (10 pts)
|
||||
|
||||
* Navigation (2 pts)
|
||||
* Tab bottom navigation + at least one button
|
||||
* Store (2 pts)
|
||||
* Read data from redux store
|
||||
* Actions (1 pts)
|
||||
* Update data to redux store
|
||||
* Display list of items (2 pts)
|
||||
* FlatList, VirtualizedList or SectionList
|
||||
* Display image (1 pts)
|
||||
* Child props (1 pts)
|
||||
* TextInput (1 pts)
|
||||
|
||||
## Application features (6 pts)
|
||||
|
||||
* Retrieve data using the Web API (2 pts)
|
||||
* Store favorite data into phone storage (2 pts)
|
||||
* Write Tests (2 pts)
|
||||
|
||||
## Bonus (only taken into account if the basics are all mastered)
|
||||
|
||||
* Dark/Light mode switch (2pts)
|
||||
* Sexy UI (2 pts)
|
@ -1 +1,79 @@
|
||||
[Slides](https://iutsa01.blob.core.windows.net/react-native/ReactNative.pdf)
|
||||
<div align = center>
|
||||
|
||||
<img src="assets/banner.png" width="1050" height="">
|
||||
|
||||
</div>
|
||||
|
||||
<div align = center>
|
||||
|
||||
---
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
---
|
||||
|
||||
</div>
|
||||
|
||||
<div align = center>
|
||||
|
||||
# **DesckStone**
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
# :bookmark: Présentation
|
||||
|
||||
DeckStone est une application master detail créé grâce au framework React Native en TypeScript et en JavaScript.
|
||||
Elle vous permet la gestion des cartes hearstone que vous posséder avec la consultation des informations des cartes et l'utilisation de favoris persistants.
|
||||
|
||||
|
||||
|
||||
# Notation :white_check_mark:
|
||||
|
||||
|
||||
## ``` Documentation ```
|
||||
|
||||
:white_check_mark: **ReadMe**
|
||||
:white_check_mark: **Sketches** : 
|
||||
|
||||
## ```Bases```
|
||||
|
||||
:white_check_mark: **Navigation** : Nous avons une barre de navigation fonctionnel nous permettant de naviguer entre les trois écrans.
|
||||
:white_check_mark: **Store** : Nous utilisons le store pour charger nos données et les stocker mais aussi pour gérer les favoris.
|
||||
:white_check_mark: **Actions** : Nous utilisons les actions pour charger les données depuis le redux mais aussi pour ajouter et supprimer les favoris.
|
||||
:white_check_mark: **Display List of Items** : Nous affichons la liste des cartes et celles des favoris dans 2 écrans différents.
|
||||
:white_check_mark: **Display image** : Chaque cartes sont affiché par un component qui affiche l'image de la carte.
|
||||
:white_check_mark: **Child props** : Nous utilisons un props pour passer la carte au component qui l'affiche.
|
||||
:white_check_mark: **TextInput** : Une recherche par nom peut être effectué par dans les 2 listes.
|
||||
|
||||
## ```Application features```
|
||||
|
||||
:construction: **API** : Nous utilisons l'API officielle du jeu pour récupérer nos données, cependant nous n'avons pas pu gérer le changement de token, nous le changeons donc à la main.
|
||||
***Source*** : https://develop.battle.net/documentation/hearthstone/game-data-apis
|
||||
:white_check_mark: **Store favorite data into phone storage** : Nous utilison l'AsyncStorage pour sauvegarder la liste des favoris dans le téléphone.
|
||||
:construction: **Write Tests** : Nous testons les actions, le reducer et les composants UI que nous avons implémenter, cependant les éléments utilisant indirectement l'AsyncStorage ne passent pas les tests à cause d'un problème d'utilisation du mockAsyncStorage.
|
||||
|
||||
## ``Bonus``
|
||||
|
||||
* :construction: **Dark/Light mode switch** : Nous n'avons mis en place cette gestion seulement dans la branche dédié par souci de visuel
|
||||
* :construction: **Sexy UI** : A vous de juger !
|
||||
|
||||
|
||||
# :construction: Développeurs
|
||||
|
||||
- Corentin RICHARD : corentin.richard@etu.uca.fr
|
||||
- Pierre FERREIRA : pierre.ferreira@etu.uca.fr
|
||||
|
||||
<div align="center">
|
||||
<a href = "https://codefirst.iut.uca.fr/git/corentin.richard">
|
||||
<img src="https://codefirst.iut.uca.fr/git/avatars/4372364870f18ab9104f13222fa84d2e?size=870" width="50" >
|
||||
</a>
|
||||
<a href = "https://codefirst.iut.uca.fr/git/pierre.ferreira">
|
||||
<img src="https://codefirst.iut.uca.fr/git/avatars/edbacace5f621ae77077f206ebdcee27?size=870" width="50" >
|
||||
</a>
|
||||
|
||||
© IUT - Auvergne
|
||||
</div>
|
@ -0,0 +1,9 @@
|
||||
// somewhere in your configuration files
|
||||
import AsyncStorageMock from '@react-native-async-storage/async-storage/jest/async-storage-mock';
|
||||
|
||||
AsyncStorageMock.multiGet = jest.fn(([keys], callback) => {
|
||||
// do something here to retrieve data
|
||||
callback([]);
|
||||
});
|
||||
|
||||
export default AsyncStorageMock;
|
After Width: | Height: | Size: 144 KiB |
After Width: | Height: | Size: 286 KiB |
After Width: | Height: | Size: 281 KiB |
@ -0,0 +1,18 @@
|
||||
import { View } from 'react-native';
|
||||
import { Image } from 'react-native';
|
||||
|
||||
|
||||
type ItemProps = {
|
||||
url : string //Image URL
|
||||
}
|
||||
|
||||
export function ListItemComponent(props : ItemProps){
|
||||
return (
|
||||
<View>
|
||||
<Image
|
||||
source={{uri: props.url}}
|
||||
style={{flex:1, minHeight:250, minWidth:180}}
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
import { useDispatch } from "react-redux";
|
||||
import { Card } from "../models/Card";
|
||||
import { setFavList } from "../redux/actions/action_setFavList";
|
||||
import { Image, TouchableHighlight, View } from "react-native";
|
||||
import React, { useEffect } from "react";
|
||||
import {CardProps} from "../props/favProps"
|
||||
import { FontAwesome } from '@expo/vector-icons';
|
||||
import { StyleSheet} from 'react-native';
|
||||
|
||||
|
||||
export default function Item(props: CardProps){ // a mettre dans components et definir une props pour passer le param
|
||||
|
||||
const {route} = props;
|
||||
const item: Card = route.card;
|
||||
const bool: boolean = route.bool;
|
||||
const dispatch = useDispatch()
|
||||
|
||||
const HandleAddFav = (props : CardProps) => {
|
||||
dispatch(setFavList(props));
|
||||
}
|
||||
return(
|
||||
|
||||
/* dispatch , */
|
||||
<View style={styles.item}>
|
||||
<TouchableHighlight testID="button" style={item.fav?styles.favoriteButtonFav:styles.favoriteButtonNonFav} onPress={() => HandleAddFav(props)} >
|
||||
<FontAwesome name="heart-o" size={50} color="#fff" />
|
||||
</TouchableHighlight>
|
||||
<Image
|
||||
source={{uri:item.img}}
|
||||
style={{flex:1, minHeight:250, minWidth:180}}/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
const styles = StyleSheet.create({
|
||||
item: {
|
||||
zIndex:0
|
||||
},
|
||||
favoriteButtonNonFav: {
|
||||
position: 'absolute',
|
||||
top: 10,
|
||||
right: 10,
|
||||
backgroundColor: 'red',
|
||||
borderRadius: 50,
|
||||
padding: 10,
|
||||
zIndex:1
|
||||
},
|
||||
favoriteButtonFav: {
|
||||
position: 'absolute',
|
||||
top: 10,
|
||||
right: 10,
|
||||
backgroundColor: 'red',
|
||||
borderRadius: 50,
|
||||
padding: 10,
|
||||
zIndex:1
|
||||
},});
|
@ -1,41 +0,0 @@
|
||||
import { StatusBar } from 'expo-status-bar';
|
||||
import { StyleSheet, Text, View, Button } from 'react-native';
|
||||
import React, { useState } from "react";
|
||||
|
||||
// @ts-ignore
|
||||
export default function Main(props : mainProps){
|
||||
const [count, setCount] = useState(0);
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={styles.border}>
|
||||
<Text>Maman, prend la caméra ! !</Text>
|
||||
<StatusBar style="auto" />
|
||||
<Text>{count}</Text>
|
||||
<Button onPress={()=> setCount(count+1)} title="+1"/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#ffffff',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderWidth: 5,
|
||||
borderColor : "#ff00ff",
|
||||
},
|
||||
border: {
|
||||
flex: 1,
|
||||
backgroundColor: '#ff0000',
|
||||
maxHeight : 100,
|
||||
borderWidth : 15,
|
||||
borderRadius : 15,
|
||||
borderColor : '#00ffaa',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}
|
||||
});
|
@ -1,14 +0,0 @@
|
||||
|
||||
// export class ApiDataManager{
|
||||
|
||||
|
||||
// public async getCards() : Promise<String[]> {
|
||||
|
||||
|
||||
// const CardPromise = await fetch('https://omgvamp-hearthstone-v1.p.rapidapi.com/cards')
|
||||
|
||||
// const CardListJson = await CardPromise.json();
|
||||
// const CardList: String[] = Array.of(CardListJson);
|
||||
// return CardList;
|
||||
// }
|
||||
// }
|
@ -1,13 +0,0 @@
|
||||
import { Card } from "../models/Card"
|
||||
|
||||
export class StubLib {
|
||||
|
||||
public getCards(): Card[] {
|
||||
const NOUNOURS_LIST : Card[] = [
|
||||
|
||||
|
||||
]
|
||||
return NOUNOURS_LIST
|
||||
}
|
||||
}
|
||||
|
@ -1,37 +0,0 @@
|
||||
|
||||
export class CardSet {
|
||||
|
||||
constructor(id: number,name : string, type : string ) {
|
||||
this._id = id
|
||||
this._name =name
|
||||
this._type = type
|
||||
|
||||
}
|
||||
|
||||
private _id : number
|
||||
|
||||
get id(): number {
|
||||
return this._id
|
||||
}
|
||||
|
||||
// NAME //
|
||||
private _name : string;
|
||||
get name(): string {
|
||||
return this._name;
|
||||
}
|
||||
set name(value: string) {
|
||||
this._name = value;
|
||||
}
|
||||
|
||||
private _type : string;
|
||||
get type(): string {
|
||||
return this._type;
|
||||
}
|
||||
set type(value: string) {
|
||||
this._type = value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
export class Classe {
|
||||
constructor(private id : number, private name : string) {
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
export class Type{
|
||||
|
||||
constructor(private id : number, private name : string) {
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
|
||||
import { NavigationContainer } from '@react-navigation/native';
|
||||
import { createStackNavigator } from '@react-navigation/stack';
|
||||
import {createNativeStackNavigator} from '@react-navigation/native-stack';
|
||||
|
||||
import ListScreen from '../screens/ListScreen';
|
||||
import DetailCard from '../screens/DetailCard';
|
||||
|
||||
export default function DetailStackNav() {
|
||||
const Stack = createStackNavigator();
|
||||
return (
|
||||
<Stack.Navigator initialRouteName="CardList">
|
||||
<Stack.Screen name="CardList" component={ListScreen}/>
|
||||
<Stack.Screen name="DetailCard" component={DetailCard}/>
|
||||
</Stack.Navigator>
|
||||
)
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
|
||||
|
||||
// import { NavigationContainer } from '@react-navigation/native';
|
||||
// import { createStackNavigator } from '@react-navigation/stack';
|
||||
|
||||
// import HomeScreen from '../screens/HomeScreen';
|
||||
// import ListScreen from '../screens/ListScreen';
|
||||
// import ListFav from '../screens/ListFav';
|
||||
|
||||
|
||||
|
||||
|
||||
// export default function ListNavigator() {
|
||||
// const Stack = createStackNavigator();
|
||||
// return (
|
||||
// <Stack.Navigator initialRouteName="List">
|
||||
// <Stack.Screen name="List" component={ListScreen}/>
|
||||
// <Stack.Screen name="ListFav" component={ListFav}/>
|
||||
// </Stack.Navigator>
|
||||
// )
|
||||
// }
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,8 @@
|
||||
import { Card } from "../models/Card";
|
||||
|
||||
export interface CardProps{
|
||||
route : {
|
||||
card: Card;
|
||||
bool: boolean;
|
||||
}
|
||||
}
|
@ -1,85 +1,53 @@
|
||||
import { setCardsList } from "./action_setCardsList";
|
||||
|
||||
import { Card } from "../../models/Card";
|
||||
|
||||
//! se fichier devra possiblement changer de dossier !!!
|
||||
|
||||
//! classe pour tester
|
||||
// export class Card {
|
||||
// cardId : String
|
||||
// name : String
|
||||
// manaCost : number
|
||||
// attack : number
|
||||
// health : number
|
||||
// desc : String
|
||||
|
||||
// // constructor() {
|
||||
// // this.cardId = "cardId";
|
||||
// // this.name = "name";
|
||||
// // this.manaCost = 0;
|
||||
// // this.attack = 0;
|
||||
// // this.health = 0;
|
||||
// // this.desc = "desc";
|
||||
// // }
|
||||
|
||||
// constructor(cardId : String, name : String, manaCost : number, attack : number, health : number, desc : String){
|
||||
// this.cardId = cardId;
|
||||
// this.name = name;
|
||||
// this.manaCost = manaCost;
|
||||
// this.attack = attack;
|
||||
// this.health = health;
|
||||
// this.desc = desc;
|
||||
// }
|
||||
|
||||
|
||||
// }
|
||||
|
||||
|
||||
//Define your action creators that will be responsible for asynchronous operations
|
||||
//Fonction chargé de l'appel à l'API
|
||||
export const getAllCards = () => {
|
||||
//In order to use await your callback must be asynchronous using async keyword.
|
||||
console.log("getallcard")
|
||||
|
||||
//@ts-ignore
|
||||
return async dispatch => {
|
||||
//Then perform your asynchronous operations.
|
||||
try {
|
||||
//Have it first fetch data from our starwars url.
|
||||
const options = {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'content-length':'9505',
|
||||
'content-type':'application/json; charset=utf-8',
|
||||
'etag':'W/"74bb-QMT8DIj6saBS1wT4u5WWcEmZAdw"'
|
||||
'content-length': '9508',
|
||||
'content-type': 'application/json; charset=utf-8',
|
||||
'etag': 'W/"74bb-d4gMlMNks7UGES3Jmn6wzUTXaLI"',
|
||||
}
|
||||
|
||||
};
|
||||
const CardsPromise = await fetch('https://us.api.blizzard.com/hearthstone/cards?locale=en_US&access_token=EURTWhjBC2SRb4Ez42BT1kx8R2NcJc07kL', options);
|
||||
//console.log("FETCH")
|
||||
//console.log(CardsPromise)
|
||||
//! Actualisation de l'API (19/04) :
|
||||
const CardsPromise = await fetch('https://us.api.blizzard.com/hearthstone/cards?locale=en_US&access_token=EUo8Snb09AfE3zQR4CoaB71gq1q3qvSmgL', options);
|
||||
|
||||
//Then use the json method to get json data from api/
|
||||
const CardsListJson = await CardsPromise.json();
|
||||
|
||||
//console.log(CardsListJson['cards'])
|
||||
|
||||
|
||||
|
||||
//@ts-ignore
|
||||
const CardsList: Card[] = CardsListJson['cards'].map(elt => new Card(elt["id"] ? elt["id"] : 1,
|
||||
elt["name"] ? elt["name"] : "",
|
||||
elt["health"] ? elt["health"] : 0,
|
||||
elt["attack"] ? elt["attack"] : 0,
|
||||
elt["manaCost"] ? elt["manaCost"] : 0,
|
||||
elt["rarityId"] ? elt["rarityId"] : 0,
|
||||
elt["flavorText"] ? elt["flavorText"] : "",
|
||||
elt["classId"] ? elt["classId"] : 0,
|
||||
elt["multiClassIds"] ? elt["multiClassIds"] : "Nothing",
|
||||
elt["image"] ? elt["image"] : "",
|
||||
elt["imageGold"] ? elt["imageGold"] : "",
|
||||
elt["cropImage"] ? elt["cropImage"] : "",
|
||||
elt["artistName"] ? elt["artistName"] : "",
|
||||
)); //, elt["cardSet"], elt["type"], elt["faction"], elt["rarity"], elt["cost"], elt["attack"], elt["health"],elt["text"], elt["flavor"], elt["artist"], elt["collectible"], elt["elite"], elt["race"], elt["img"], elt["imgGold"]
|
||||
//elt["cardId"] == null ? elt["cardId"] : ""
|
||||
|
||||
//console.log("TOTO")
|
||||
|
||||
//console.log(CardsList)
|
||||
//call the action
|
||||
dispatch(setCardsList(CardsList));
|
||||
|
||||
} catch (error) {
|
||||
console.log('Error---------', error);
|
||||
//You can dispatch to another action if you want to display an error message in the application
|
||||
//dispatch(fetchDataRejected(error))
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
import {ADD_FAVORITE_DATA, FETCH_DATA} from '../constants';
|
||||
import { Card } from '../../models/Card';
|
||||
import { CardProps } from '../../props/favProps';
|
||||
import {ADD_FAVORITE_DATA} from '../constants';
|
||||
|
||||
export const setFavList = (List: String[]) => {
|
||||
export const setFavList = (props : CardProps) => {
|
||||
return {
|
||||
type: ADD_FAVORITE_DATA,
|
||||
payload: List,
|
||||
payload: props,
|
||||
};
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
import { Card } from '../../models/Card';
|
||||
import {SET_FAVS} from '../constants';
|
||||
|
||||
export const setList = (list: []) => {
|
||||
return {
|
||||
type: SET_FAVS,
|
||||
payload: list
|
||||
};
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
import {ADD_FAVORITE_DATA, FETCH_DATA} from '../constants';
|
||||
|
||||
export const setList = (List: String[]) => {
|
||||
return {
|
||||
type: FETCH_DATA,
|
||||
payload: List,
|
||||
};
|
||||
}
|
||||
|
||||
// export const setFavList = (List: String[]) => {
|
||||
// return {
|
||||
// type: ADD_FAVORITE_DATA,
|
||||
// payload: List,
|
||||
// };
|
||||
// }
|
@ -1,7 +1,6 @@
|
||||
|
||||
|
||||
export const FETCH_DATA = "FETCH_DATA"
|
||||
|
||||
export const ADD_FAVORITE_DATA = "ADD_FAVORITE_DATA"
|
||||
|
||||
export const DISPLAY_ALL_CARD = "DISPLAY_ALL_CARD"
|
||||
export const SET_FAVS = "SET_FAVS"
|
||||
|
||||
|
@ -0,0 +1,91 @@
|
||||
import { StyleSheet, Text, View, Button, FlatList } from 'react-native';
|
||||
import { StatusBar } from 'expo-status-bar';
|
||||
import React, { useState } from "react";
|
||||
import { Card } from '../models/Card';
|
||||
|
||||
import { Table, Row, Rows } from 'react-native-table-component';
|
||||
|
||||
//* Components
|
||||
import {ListItemComponent} from '../components/ListItemComponent'
|
||||
import { ScrollView } from 'react-native-gesture-handler';
|
||||
|
||||
//@ts-ignore
|
||||
export default function DetailMain({ route }){
|
||||
|
||||
const { card, other } = route.params;
|
||||
|
||||
const tableHead = ['Stat', 'Value'];
|
||||
const tableData = [
|
||||
['Mana cost :', card.manaCost],
|
||||
['Attack : ', card.attack],
|
||||
['Health : ', card.health],
|
||||
['Rarity : ', card.rarity],
|
||||
['Artist : ', card.artistName],
|
||||
['Class : ', card.classId],
|
||||
]
|
||||
|
||||
let pressed : Boolean = false
|
||||
const [titleText, setTitleText] = useState(card.name)
|
||||
const onPressTitle = () => {
|
||||
pressed ? setTitleText(titleText + '\n' + 'Id : ' + card.id) : setTitleText(card.name)
|
||||
pressed ? pressed = false :pressed = true
|
||||
};
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={styles.titleView}>
|
||||
<Text style={styles.title} onPress={onPressTitle} >{titleText}</Text>
|
||||
<Text style={styles.flavor}>{card.flavorText}</Text>
|
||||
</View>
|
||||
<View style={styles.item}>
|
||||
<ListItemComponent url={card.img}/>
|
||||
</View>
|
||||
|
||||
<ScrollView>
|
||||
<Table borderStyle={{borderWidth: 5, borderColor: '#c8e1ff'}}>
|
||||
<Row data={tableHead} style={styles.head} textStyle={styles.text}/>
|
||||
<Rows data={tableData} textStyle={styles.text}/>
|
||||
</Table>
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#fff',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
item: {
|
||||
borderRadius : 15,
|
||||
backgroundColor: '#efefef',
|
||||
padding: 15,
|
||||
maxHeight:300,
|
||||
maxWidth:350,
|
||||
},
|
||||
title: {
|
||||
fontStyle: "italic",
|
||||
fontWeight: "bold",
|
||||
fontSize: 20,
|
||||
},
|
||||
flavor: {
|
||||
fontStyle: "italic",
|
||||
},
|
||||
titleView: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
paddingVertical: 0,
|
||||
paddingHorizontal : 15,
|
||||
backgroundColor: '#fff',
|
||||
borderRadius : 10,
|
||||
borderWidth: 10,
|
||||
borderColor: '#efefef',
|
||||
maxHeight:100,
|
||||
minHeight: 100
|
||||
},
|
||||
head: { height: 40, backgroundColor: '#f1f8ff', minWidth: '90%'},
|
||||
text: { margin: 6 }
|
||||
});
|
@ -0,0 +1,28 @@
|
||||
import { Card } from "../models/Card";
|
||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||
|
||||
|
||||
export default class StorageHeart {
|
||||
|
||||
static async getItem(key: string): Promise<any> {
|
||||
try {
|
||||
const value = await AsyncStorage.getItem(key);
|
||||
|
||||
if (value !== null) {
|
||||
return JSON.parse(value);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`AsyncStorage getItem error: ${e}`);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static async setItem(key: string, value: any): Promise<void> {
|
||||
try {
|
||||
await AsyncStorage.setItem(key, JSON.stringify(value));
|
||||
|
||||
} catch (e) {
|
||||
console.error(`AsyncStorage setItem error: ${e}`);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
import { configureStore } from "@reduxjs/toolkit";
|
||||
import testReducer from "../setup/testReducer";
|
||||
import { Provider } from "react-redux";
|
||||
import { render } from "react-dom";
|
||||
import Item from "../../components/ListItemComponent";
|
||||
|
||||
jest.useFakeTimers();
|
||||
|
||||
const store = configureStore({
|
||||
reducer: {
|
||||
appReducer: testReducer,
|
||||
},
|
||||
middleware: (getDefaultMiddleWare) =>
|
||||
getDefaultMiddleWare({
|
||||
serializableCheck: false
|
||||
})
|
||||
});
|
||||
|
||||
const Wrapper = ({children}) => (<Provider store={store}>{children}</Provider>);
|
||||
|
||||
describe('<Item/>', ()=> {
|
||||
test('Assert displayed values', () =>{
|
||||
const expectedCardInfos = store.getState().appReducer.cards[0];
|
||||
|
||||
render(<Wrapper>
|
||||
<Item route={{
|
||||
card: expectedCardInfos,
|
||||
bool: false
|
||||
}} ></Item>
|
||||
</Wrapper>)
|
||||
|
||||
expect(screen.getByTestId('card-url')).toHaveProperty("source", {uri: expectedCardInfos.img})
|
||||
|
||||
|
||||
})
|
||||
})
|
@ -0,0 +1,44 @@
|
||||
import { configureStore } from "@reduxjs/toolkit";
|
||||
import testReducer from "../setup/testReducer";
|
||||
import { Provider } from "react-redux";
|
||||
import { render } from "react-dom";
|
||||
import Item from "../../components/ListItemComponent";
|
||||
import { fireEvent } from "@testing-library/react-native";
|
||||
import AsyncStorageMock from "../../__mocks__/@react-native-community/async-storage";
|
||||
|
||||
|
||||
jest.useFakeTimers();
|
||||
|
||||
const store = configureStore({
|
||||
reducer: {
|
||||
appReducer: testReducer,
|
||||
},
|
||||
middleware: (getDefaultMiddleWare) =>
|
||||
getDefaultMiddleWare({
|
||||
serializableCheck: false
|
||||
})
|
||||
});
|
||||
|
||||
const Wrapper = ({children}) => (<Provider store={store}>{children}</Provider>);
|
||||
|
||||
describe('<Item/>', ()=> {
|
||||
test('Assert displayed values for fav list', () =>{
|
||||
const expectedCardInfos = store.getState().appReducer.favoriteCards[0];
|
||||
|
||||
render(<Wrapper>
|
||||
<Item route={{
|
||||
card: expectedCardInfos,
|
||||
bool: true,
|
||||
}} ></Item>
|
||||
</Wrapper>)
|
||||
|
||||
expect(screen.getByTestId('card-url')).toHaveProperty("source", {uri: expectedCardInfos.img})
|
||||
|
||||
let size = store.getState().appReducer.favoriteCards.length;
|
||||
|
||||
fireEvent.press(screen.getByTestId("button"))
|
||||
|
||||
expect(store.getState().appReducer.favoriteCards.length).toBe(size - 1)
|
||||
|
||||
})
|
||||
});
|
@ -0,0 +1,14 @@
|
||||
import { Card } from "../../models/Card";
|
||||
import { setCardsList } from "../../redux/actions/action_setCardsList";
|
||||
|
||||
describe('setCardLIst',() => {
|
||||
it('should take the list', () => {
|
||||
const payload = [new Card("1","test1","",""),new Card("2","test2","","",true)];
|
||||
const expectation = {
|
||||
type: "FETCH_DATA",
|
||||
payload: payload,
|
||||
};
|
||||
|
||||
expect(setCardsList(payload)).toEqual(expectation);
|
||||
})
|
||||
})
|
@ -0,0 +1,16 @@
|
||||
import { Card } from "../../models/Card";
|
||||
import { setFavList } from "../../redux/actions/action_setFavList";
|
||||
import { setList } from "../../redux/actions/action_setFavs";
|
||||
|
||||
|
||||
describe('setFavs',() => {
|
||||
it('should take the list', () => {
|
||||
const payload = [new Card("1","test1","",""),new Card("2","test2","","",true)];
|
||||
const expectation = {
|
||||
type: "SET_FAVS",
|
||||
payload: payload,
|
||||
};
|
||||
|
||||
expect(setList(payload)).toEqual(expectation);
|
||||
})
|
||||
})
|
@ -0,0 +1,25 @@
|
||||
import appReducer from "../../redux/reducers/appReducer";
|
||||
|
||||
describe('Test Reducer', () => {
|
||||
let initialState = {
|
||||
cards: [],
|
||||
favoriteCards: []
|
||||
}
|
||||
|
||||
it('should return initial state', () => {
|
||||
expect(appReducer(undefined, {})).toEqual(initialState);
|
||||
});
|
||||
|
||||
it('should handle FETCH_DATA', () => {
|
||||
const payload = [new Card("1","test1","",""),new Card("2","test2","","",true)];
|
||||
expect(
|
||||
appReducer(initialState, {
|
||||
type: "FETCH_DATA",
|
||||
payload,
|
||||
})
|
||||
).toEqual({
|
||||
cards: payload,
|
||||
favoriteCards: [],
|
||||
});
|
||||
});
|
||||
});
|
@ -0,0 +1,3 @@
|
||||
import mockAsyncStorage from '@react-native-async-storage/async-storage/jest/async-storage-mock';
|
||||
|
||||
jest.mock('@react-native-community/async-storage', () => mockAsyncStorage);
|
@ -0,0 +1,13 @@
|
||||
import { Card } from "../../models/Card";
|
||||
import appReducer from "../../redux/reducers/appReducer"
|
||||
|
||||
const initialState = {
|
||||
cards: [new Card("1","test1","url1","urlGold2")],
|
||||
favoriteCards: [new Card("1","test1","url1","urlGold2")]
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
export default testReducer = (state = initialState, action) => {
|
||||
//@ts-ignore
|
||||
return appReducer(initialState,action);
|
||||
}
|
Loading…
Reference in new issue