Skip to content

Commit 03de435

Browse files
committed
Implementación y correcíon de erroes modulo de inventario
1 parent fee61a1 commit 03de435

3 files changed

Lines changed: 654 additions & 0 deletions

File tree

Frontend/resources/views/inventarioviews/ingredientes/inventario.blade.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,12 @@
120120
</div>
121121
@endif
122122

123+
@if (session('error') ?? $error ?? false)
124+
<div class="alert alert-danger border-0 shadow-sm mb-4" style="border-radius: 15px;">
125+
<i class="fas fa-exclamation-triangle me-2"></i> {{ session('error') ?? $error }}
126+
</div>
127+
@endif
128+
123129
{{-- ESTADÍSTICAS RÁPIDAS --}}
124130
<div class="row g-3 mb-4">
125131
<div class="col-md-4">
Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
<?php
2+
3+
namespace Tests\Feature\Inventario;
4+
5+
use Tests\TestCase;
6+
use Illuminate\Support\Facades\Http;
7+
use PHPUnit\Framework\Attributes\Test;
8+
9+
class IngredientesControllerTest extends TestCase
10+
{
11+
// Mock completo de todos los endpoints que usa index()
12+
private function mockIndexApis(): void
13+
{
14+
Http::fake([
15+
'*/ingredientes/lista' => Http::response([
16+
[
17+
'idIngrediente' => 1,
18+
'nombreIngrediente' => 'Harina',
19+
'referenciaIngrediente' => 'HAR-001',
20+
'idProveedor' => 1,
21+
'idCategoria' => 1,
22+
'abreviaturaUnidad' => 'kg'
23+
]
24+
], 200),
25+
'*/proveedores' => Http::response([
26+
['idProveedor' => 1, 'nombreProv' => 'Harina Dorada']
27+
], 200),
28+
'*/categorias/ingredientes' => Http::response([
29+
['idCategoriaIngrediente' => 1, 'nombreCategoria' => 'Harinas']
30+
], 200),
31+
'*/unidades-medida' => Http::response([
32+
['idUnidad' => 1, 'nombreUnidad' => 'Kilogramo', 'abreviaturaUnidad' => 'kg']
33+
], 200),
34+
]);
35+
}
36+
37+
// =========================================================
38+
// index()
39+
// =========================================================
40+
41+
#[Test]
42+
public function index_retorna_200_con_vista_correcta(): void
43+
{
44+
$this->mockIndexApis();
45+
46+
$response = $this->get('/inventario/ingredientes');
47+
48+
$response->assertStatus(200);
49+
$response->assertViewIs('inventarioviews.ingredientes.index');
50+
}
51+
52+
#[Test]
53+
public function index_pasa_las_4_variables_a_la_vista(): void
54+
{
55+
$this->mockIndexApis();
56+
57+
$response = $this->get('/inventario/ingredientes');
58+
59+
$response->assertViewHas('ingredientes');
60+
$response->assertViewHas('proveedores');
61+
$response->assertViewHas('categorias');
62+
$response->assertViewHas('unidades');
63+
}
64+
65+
#[Test]
66+
public function index_carga_aunque_spring_falle_en_proveedores(): void
67+
{
68+
// Si Spring falla en proveedores/categorias/unidades,
69+
// el try/catch del controller devuelve arrays vacíos
70+
// y la vista igual debe cargar sin explotar
71+
Http::fake([
72+
'*/ingredientes/lista' => Http::response([], 200),
73+
'*/proveedores' => Http::response([], 500),
74+
'*/categorias/*' => Http::response([], 500),
75+
'*/unidades-medida' => Http::response([], 500),
76+
]);
77+
78+
$response = $this->get('/inventario/ingredientes');
79+
80+
// No debe dar 500 — el catch garantiza arrays vacíos
81+
$response->assertStatus(200);
82+
}
83+
84+
// =========================================================
85+
// inventario() — stock
86+
// =========================================================
87+
88+
#[Test]
89+
public function inventario_retorna_vista_con_ingredientes(): void
90+
{
91+
Http::fake([
92+
'*/ingredientes/cantidad' => Http::response([
93+
['idIngrediente' => 1, 'nombreIngrediente' => 'Harina', 'cantidadIngrediente' => 50.0]
94+
], 200)
95+
]);
96+
97+
$response = $this->get('/inventario/ingredientes/stock');
98+
99+
$response->assertStatus(200);
100+
$response->assertViewIs('inventarioviews.ingredientes.inventario');
101+
$response->assertViewHas('ingredientes');
102+
}
103+
104+
#[Test]
105+
public function inventario_muestra_error_cuando_api_falla(): void
106+
{
107+
Http::fake([
108+
'*/ingredientes/cantidad' => Http::response([], 500)
109+
]);
110+
111+
$response = $this->get('/inventario/ingredientes/stock');
112+
113+
$response->assertStatus(200);
114+
$response->assertViewIs('inventarioviews.ingredientes.inventario');
115+
$response->assertViewHas('ingredientes', []);
116+
$response->assertViewHas('error');
117+
}
118+
119+
// =========================================================
120+
// store()
121+
// =========================================================
122+
123+
#[Test]
124+
public function store_con_datos_validos_redirige_con_success(): void
125+
{
126+
Http::fake([
127+
'*/crearingrediente' => Http::response('Creado con éxito', 200)
128+
]);
129+
130+
$response = $this->post('/inventario/ingredientes/store', [
131+
'idProveedor' => 1,
132+
'idCategoria' => 1,
133+
'idUnidadMedida' => 1,
134+
'nombreIngrediente' => 'Harina Test',
135+
'referenciaIngrediente' => 'HAR-TEST',
136+
]);
137+
138+
$response->assertRedirect(route('ingredientes.index'));
139+
$response->assertSessionHas('success', 'Ingrediente creado con éxito.');
140+
}
141+
142+
#[Test]
143+
public function store_falla_si_falta_idProveedor(): void
144+
{
145+
$response = $this->post('/inventario/ingredientes/store', [
146+
'idCategoria' => 1,
147+
'idUnidadMedida' => 1,
148+
'nombreIngrediente' => 'Harina',
149+
'referenciaIngrediente' => 'HAR-001',
150+
// idProveedor ausente
151+
]);
152+
153+
$response->assertSessionHasErrors(['idProveedor']);
154+
}
155+
156+
#[Test]
157+
public function store_falla_si_todos_los_campos_estan_vacios(): void
158+
{
159+
$response = $this->post('/inventario/ingredientes/store', []);
160+
161+
$response->assertSessionHasErrors([
162+
'idProveedor',
163+
'idCategoria',
164+
'idUnidadMedida',
165+
'nombreIngrediente',
166+
'referenciaIngrediente',
167+
]);
168+
}
169+
170+
#[Test]
171+
public function store_falla_si_referencia_supera_50_caracteres(): void
172+
{
173+
$response = $this->post('/inventario/ingredientes/store', [
174+
'idProveedor' => 1,
175+
'idCategoria' => 1,
176+
'idUnidadMedida' => 1,
177+
'nombreIngrediente' => 'Harina',
178+
'referenciaIngrediente' => str_repeat('X', 51), // 51 chars > max:50
179+
]);
180+
181+
$response->assertSessionHasErrors(['referenciaIngrediente']);
182+
}
183+
184+
#[Test]
185+
public function store_redirige_con_error_cuando_spring_rechaza(): void
186+
{
187+
Http::fake([
188+
'*/crearingrediente' => Http::response('Error en Spring', 400)
189+
]);
190+
191+
$response = $this->post('/inventario/ingredientes/store', [
192+
'idProveedor' => 1,
193+
'idCategoria' => 1,
194+
'idUnidadMedida' => 1,
195+
'nombreIngrediente' => 'Harina',
196+
'referenciaIngrediente' => 'HAR-001',
197+
]);
198+
199+
$response->assertSessionHas('error');
200+
$response->assertRedirect(); // vuelve atrás
201+
}
202+
203+
// =========================================================
204+
// update()
205+
// =========================================================
206+
207+
#[Test]
208+
public function update_con_datos_validos_redirige_con_success(): void
209+
{
210+
Http::fake([
211+
'*/ingrediente/1' => Http::response('Actualizado', 200)
212+
]);
213+
214+
$response = $this->put('/inventario/ingredientes/update/1', [
215+
'idProveedor' => 1,
216+
'idCategoria' => 1,
217+
'idUnidadMedida' => 1,
218+
'nombreIngrediente' => 'Harina Premium',
219+
'referenciaIngrediente' => 'HAR-002',
220+
]);
221+
222+
$response->assertRedirect(route('ingredientes.index'));
223+
$response->assertSessionHas('success', 'Ingrediente actualizado con éxito.');
224+
}
225+
226+
#[Test]
227+
public function update_falla_validacion_con_datos_vacios(): void
228+
{
229+
$response = $this->put('/inventario/ingredientes/update/1', []);
230+
231+
$response->assertSessionHasErrors([
232+
'idProveedor',
233+
'idCategoria',
234+
'idUnidadMedida',
235+
'nombreIngrediente',
236+
'referenciaIngrediente',
237+
]);
238+
}
239+
240+
// =========================================================
241+
// destroy()
242+
// =========================================================
243+
244+
#[Test]
245+
public function destroy_elimina_y_redirige_con_success(): void
246+
{
247+
Http::fake([
248+
'*/ingrediente/1' => Http::response('Eliminado', 200)
249+
]);
250+
251+
$response = $this->delete('/inventario/ingredientes/delete/1');
252+
253+
$response->assertRedirect(route('ingredientes.index'));
254+
$response->assertSessionHas('success', 'Ingrediente eliminado con éxito.');
255+
}
256+
257+
#[Test]
258+
public function destroy_redirige_con_error_cuando_spring_falla(): void
259+
{
260+
Http::fake([
261+
'*/ingrediente/1' => Http::response('Error', 500)
262+
]);
263+
264+
$response = $this->delete('/inventario/ingredientes/delete/1');
265+
266+
$response->assertSessionHas('error');
267+
}
268+
269+
// =========================================================
270+
// ingresarStock() — responde JSON
271+
// =========================================================
272+
273+
#[Test]
274+
public function ingresar_stock_retorna_json_success_true(): void
275+
{
276+
Http::fake([
277+
'*/ingredientes/1/ingreso' => Http::response('Stock actualizado', 200)
278+
]);
279+
280+
$response = $this->post('/ingredientes/1/ingresar-stock', [
281+
'cantidadIngresada' => 10.5
282+
]);
283+
284+
$response->assertStatus(200);
285+
$response->assertJson(['success' => true]);
286+
}
287+
288+
#[Test]
289+
public function ingresar_stock_falla_con_cantidad_cero(): void
290+
{
291+
$response = $this->post('/ingredientes/1/ingresar-stock', [
292+
'cantidadIngresada' => 0 // min:0.01
293+
]);
294+
295+
$response->assertSessionHasErrors(['cantidadIngresada']);
296+
}
297+
298+
#[Test]
299+
public function ingresar_stock_retorna_json_error_cuando_spring_falla(): void
300+
{
301+
Http::fake([
302+
'*/ingredientes/1/ingreso' => Http::response('Error stock', 500)
303+
]);
304+
305+
$response = $this->post('/ingredientes/1/ingresar-stock', [
306+
'cantidadIngresada' => 10.0
307+
]);
308+
309+
$response->assertStatus(500);
310+
$response->assertJson(['success' => false]);
311+
}
312+
}

0 commit comments

Comments
 (0)