Merge branch 'master' of https://codefirst.iut.uca.fr/git/Sae_LeftOvers/LeftOvers
continuous-integration/drone/push Build is passing Details

WORK-LPA
Louison PARANT 1 year ago
commit 3ff45314bc

@ -4,7 +4,7 @@ import Recipes from "../../Models/Recipes";
export default class RecipesService implements IRecipesService {
private readonly API_URL = "http://leftovers.alwaysdata.net/recipes";
private readonly IA_URL = "https://codefirst.iut.uca.fr/containers/Sae_LeftOvers-leftovers_ia/getrecipes"
private readonly IA_URL = "https://codefirst.iut.uca.fr/containers/Sae_LeftOvers-leftovers_ia"
async getAllRecipes(): Promise<Recipes[]> {
try {
@ -26,9 +26,17 @@ export default class RecipesService implements IRecipesService {
}
async getRecipeWithIngredients(ids: string[]): Promise<Recipes[]>{
const recipe: Recipes[] = [];
try {
const response = await axios.get(`${this.IA_URL}/${ids}`);
const response = await axios.get(`${this.IA_URL}/getrecipes/${ids}`);
return response.data as Recipes[];
} catch (error) {
throw new Error('Erreur lors de la récupération des recettes dans getRecipeWithIngredients : ' + error.message);
}
}
async getRecipeWithIngredientsAndFilters(ids: string[], filters: string): Promise<Recipes[]> {
try {
const response = await axios.get(`${this.IA_URL}/getrecipeswithfilters/${ids}/${filters}`);
return response.data as Recipes[];
} catch (error) {
throw new Error('Erreur lors de la récupération des recettes dans getRecipeWithIngredients : ' + error.message);

@ -0,0 +1,38 @@
import IngredientService from '../Services/Ingredients/IngredientsServices';
describe('IngredientService', () => {
const ingredient_service = new IngredientService();
it('should get one ingredient', async () => {
const result = await ingredient_service.getIngredientById(1)
expect(result.id).toBe(1);
});
it('should get all ingredients', async () => {
const result = await ingredient_service.getAllIngredient()
const test = result.length >= 1
expect(test).toBe(true);
});
it('should return several ingredients starting by letter a', async () => {
const result = await ingredient_service.getIngredientByLetter('a')
let test = true
for (let ingredient of result) {
if (ingredient.name[0] !== 'a') {
test = false
}
}
expect(test).toBe(true);
});
it('should return several ingredients with car in the name', async () => {
const result = await ingredient_service.getfilteredIngredient('car')
let test = true
for (let ingredient of result) {
if (!ingredient.name.includes('car')) {
test = false
}
}
expect(test).toBe(true);
});
});

@ -0,0 +1,124 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import ProfileService from '../Services/Profiles/ProfileService';
import Profile from '../Models/Profile';
type AsyncStorageMock = {
getItem: jest.Mock<Promise<string | null>, [string]>,
setItem: jest.Mock<Promise<void>, [string, string]>,
clear: jest.Mock<Promise<void>>,
};
jest.mock('@react-native-async-storage/async-storage', () => {
const asyncStorageMock: AsyncStorageMock = {
getItem: jest.fn(),
setItem: jest.fn(),
clear: jest.fn(),
};
return asyncStorageMock;
});
describe('ProfileService', () => {
beforeEach(() => {
(AsyncStorage.getItem as jest.Mock).mockReset();
(AsyncStorage.setItem as jest.Mock).mockReset();
(AsyncStorage.clear as jest.Mock).mockReset();
});
describe('getProfiles', () => {
it('should return an empty array if no profiles are stored', async () => {
(AsyncStorage.getItem as jest.Mock).mockResolvedValueOnce(null);
const profileService = new ProfileService();
const profiles = await profileService.getProfiles();
expect(profiles).toEqual([]);
});
it('should return an array of profiles if profiles are stored', async () => {
const storedProfiles = [
{ _name: 'John', _avatar: 'avatar1', _allergy: ['none'], _diets: [] },
{ _name: 'Jane', _avatar: 'avatar2', _allergy: ['peanuts'], _diets: ['vegan'] },
];
(AsyncStorage.getItem as jest.Mock).mockResolvedValueOnce(JSON.stringify(storedProfiles));
const profileService = new ProfileService();
const profiles = await profileService.getProfiles();
expect(profiles.length).toBe(2);
expect(profiles[0]).toBeInstanceOf(Profile);
expect(profiles[0].name).toEqual('John');
});
});
describe('addProfile', () => {
it('should add a new profile to the stored profiles', async () => {
const existingProfiles = [
{ _name: 'John', _avatar: 'avatar1', _allergy: ['none'], _diets: [] },
];
(AsyncStorage.getItem as jest.Mock).mockResolvedValueOnce(JSON.stringify(existingProfiles));
(AsyncStorage.setItem as jest.Mock).mockResolvedValueOnce(null);
const newProfile = new Profile('Jane', 'avatar2', ['peanuts'], ['vegan']);
const profileService = new ProfileService();
const result = await profileService.addProfile(newProfile);
expect(result).toBe(true);
expect(AsyncStorage.setItem).toHaveBeenCalledWith('profiles', expect.any(String));
});
it('should not add a profile if it already exists', async () => {
const existingProfiles = [
{ _name: 'John', _avatar: 'avatar1', _allergy: ['none'], _diets: [] },
];
(AsyncStorage.getItem as jest.Mock).mockResolvedValueOnce(JSON.stringify(existingProfiles));
const existingProfile = new Profile('John', 'avatar1', ['none'], []);
const profileService = new ProfileService();
const result = await profileService.addProfile(existingProfile);
expect(result).toBe(false);
expect(AsyncStorage.setItem).not.toHaveBeenCalled();
});
});
describe('delProfile', () => {
it('should delete a profile by name', async () => {
const existingProfiles = [
{ _name: 'John', _avatar: 'avatar1', _allergy: ['none'], _diets: [] },
{ _name: 'Jane', _avatar: 'avatar2', _allergy: ['peanuts'], _diets: ['vegan'] },
];
(AsyncStorage.getItem as jest.Mock).mockResolvedValueOnce(JSON.stringify(existingProfiles));
(AsyncStorage.setItem as jest.Mock).mockResolvedValueOnce(null);
const profileService = new ProfileService();
const result = await profileService.delProfile('John');
expect(result).toBe(true);
expect(AsyncStorage.setItem).toHaveBeenCalledWith('profiles', expect.any(String));
});
it('should return false if the profile does not exist', async () => {
const existingProfiles = [
{ _name: 'John', _avatar: 'avatar1', _allergy: ['none'], _diets: [] },
];
(AsyncStorage.getItem as jest.Mock).mockResolvedValueOnce(JSON.stringify(existingProfiles));
const profileService = new ProfileService();
const result = await profileService.delProfile('Jane');
expect(result).toBe(false);
expect(AsyncStorage.setItem).not.toHaveBeenCalled();
});
});
});

@ -0,0 +1,22 @@
import RecipesService from '../Services/Recipes/RecipesServices';
describe('RecipesService', () => {
const recipe_service = new RecipesService();
it('should get one recipe', async () => {
const result = await recipe_service.getRecipeById(4444)
expect(result.id).toBe(4444);
});
it('should get all recipes', async () => {
const result = await recipe_service.getAllRecipes()
const test = result.length >= 1
expect(test).toBe(true);
}, 120000);
it('should get one recipe', async () => {
const result = await recipe_service.getRecipeWithIngredients(['1928:2148:2809:2853:3723:6261:6335:7076'])
const test = result.length >= 1
expect(test).toBe(true);
});
});

File diff suppressed because it is too large Load Diff

@ -6,7 +6,8 @@
"start": "expo start --dev-client",
"android": "expo run:android",
"ios": "expo run:ios",
"web": "expo start --web"
"web": "expo start --web",
"test": "jest --coverage"
},
"dependencies": {
"@expo/webpack-config": "^19.0.0",
@ -18,6 +19,7 @@
"axios": "^1.6.2",
"expo": "~49.0.15",
"expo-blur": "^12.4.1",
"expo-image-picker": "~14.3.2",
"expo-linear-gradient": "~12.3.0",
"expo-splash-screen": "~0.20.5",
"expo-status-bar": "~1.6.0",
@ -31,11 +33,12 @@
"react-native-splash-screen": "^3.3.0",
"react-native-virtualized-view": "^1.0.0",
"react-native-web": "~0.19.6",
"typescript": "^5.1.3",
"expo-image-picker": "~14.3.2"
"typescript": "^5.1.3"
},
"devDependencies": {
"@babel/core": "^7.20.0"
"@babel/core": "^7.20.0",
"@types/jest": "^29.5.11",
"jest": "^29.7.0"
},
"private": true
}

@ -38,7 +38,6 @@ export default function RecipeSuggestion({ route, navigation }) {
let selectedIngredients: string[];
const die = [{value: "Gluten free"}, {value: "Porkless"}, {value: "Gluten free"}, {value: "Porkless"}]
const all = []
@ -95,22 +94,34 @@ export default function RecipeSuggestion({ route, navigation }) {
const loadRecipes = async () => {
const ids: string[] = getIngredientsIds(ingredients);
console.log('load recipes - active diets tab :', activeDiets)
const filters: string = activeDiets.map(diet => diet).join(':')
try {
const recipes: Recipes[] = await recipeService.getRecipeWithIngredients(ids);
if(recipes[0].id != -1 ){
setSelectedRecipes(recipes);
if (filters) {
const recipes: Recipes[] = await recipeService.getRecipeWithIngredientsAndFilters(ids, filters)
if(recipes[0].id != -1 ){
setSelectedRecipes(recipes);
}
}
else {
const recipes: Recipes[] = await recipeService.getRecipeWithIngredients(ids);
if(recipes[0].id != -1 ){
setSelectedRecipes(recipes);
}
}
} catch (error) {
console.error(error)
}
};
useEffect(() => {
loadRecipes()
fetchActiveDiets()
}, []);
useEffect(() => {
loadRecipes();
}, [activeDiets]);
const styles = StyleSheet.create({
linearGradient: {
width: "100%",
@ -206,12 +217,16 @@ export default function RecipeSuggestion({ route, navigation }) {
});
const fetchActiveDiets = async () => {
const results = await AsyncStorage.getItem('activeDiets')
let existingActiveDiets = JSON.parse(results)
if(existingActiveDiets.length == 0){
existingActiveDiets.push(IngredientClass.None)
try {
const results = await AsyncStorage.getItem('activeDiets');
let existingActiveDiets = JSON.parse(results);
if (existingActiveDiets.length === 0) {
existingActiveDiets = [];
}
setActiveDiets(existingActiveDiets)
} catch (error) {
console.error('Error fetching active diets:', error);
}
}
const ingredientElements = limitedList.map((source, index) => (
@ -287,9 +302,9 @@ export default function RecipeSuggestion({ route, navigation }) {
<View style={styles.background}>
<View style={styles.filterBar}>
<Text style={styles.filters}>Additional Filters</Text>
<Text style={styles.nbSelected}>{die.length} selected</Text>
<Text style={styles.nbSelected}>{activeDiets.length} selected</Text>
</View>
<ListWithoutSelect title="Diets" content={die}></ListWithoutSelect>
<ListWithoutSelect title="Diets" content={activeDiets}></ListWithoutSelect>
<View style={{marginTop: "3%"}}/>
<ListWithoutSelect title="Allergies" content={all}></ListWithoutSelect>
<View style={{marginTop: "3%"}}/>

8723
package-lock.json generated

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save