Files
pluriwave/test/widgets/visualizador_audio_barras_test.dart
T
FreeTLab fcba592352 fix(visualizador): add a discrete-bar rendering mode
Audit 1.7/2.5 (t4 lines 66-68, 120-122): the prototype draws 30
discrete bottom-anchored bars (radius 2, vertical gradient); the
build's VisualizadorAudio painted a single continuous oscilloscope
stroke, so its `barras: 30` parameter never produced bars.

Adds an opt-in `barrasDiscretas` mode (default false, byte-identical
continuous rendering preserved for any other caller) plus a
`gradienteFinAlpha` knob for the two screens' differing gradient
end-alpha (.3 vs .45). Wires it into the Escuchar hero and the full
player, correcting the player's bar count/height to match the
prototype (26->30 bars, 46->40px) at the same time.
2026-07-30 00:04:03 +02:00

154 lines
5.0 KiB
Dart

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:pluriwave/servicios/servicio_audio.dart';
import 'package:pluriwave/widgets/visualizador_audio.dart';
/// Audit 1.7/2.5 (t4 lines 66-68, 120-122): the prototype draws 30 discrete
/// bottom-anchored bars (`border-radius:2px`, a top-to-bottom gradient), but
/// `_WaveFlowPainter` (`visualizador_audio.dart:206-275`) paints a single
/// continuous oscilloscope stroke — the `barras` parameter was inert. These
/// guards assert the actual bar COUNT and that the render is structurally
/// discrete (no `CustomPaint` stroke), not just "looks bar-ish".
void main() {
group('VisualizadorAudio.barrasDiscretas', () {
testWidgets(
'renders exactly `barras` discrete bars, not a single CustomPaint path',
(tester) async {
final controller = StreamController<EstadoReproduccion>.broadcast();
addTearDown(controller.close);
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: VisualizadorAudio(
estadoStream: controller.stream,
barras: 30,
barrasDiscretas: true,
),
),
),
);
await tester.pump();
for (var i = 0; i < 30; i++) {
expect(
find.byKey(Key('visualizador-barra-$i')),
findsOneWidget,
reason: 'bar $i of 30 must exist (t4 lines 66-68: 30 bars)',
);
}
expect(
find.byKey(const Key('visualizador-barra-30')),
findsNothing,
reason: 'exactly 30 bars, not 31+',
);
expect(
find.descendant(
of: find.byType(VisualizadorAudio),
matching: find.byType(CustomPaint),
),
findsNothing,
reason:
'discrete mode must not fall back to the continuous '
'_WaveFlowPainter stroke',
);
},
);
testWidgets('each bar has radius 2 and a top-to-bottom gradient ending '
'at the given alpha (t4 line 67: linear-gradient(180deg,#7EE4C2,'
'rgba(126,228,194,.3)))', (tester) async {
final controller = StreamController<EstadoReproduccion>.broadcast();
addTearDown(controller.close);
const color = Color(0xFF7EE4C2);
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: VisualizadorAudio(
estadoStream: controller.stream,
barras: 8,
barrasDiscretas: true,
color: color,
),
),
),
);
await tester.pump();
final barra = tester.widget<Container>(
find.byKey(const Key('visualizador-barra-0')),
);
final decoracion = barra.decoration as BoxDecoration;
expect(
decoracion.borderRadius,
BorderRadius.circular(2),
reason: 't4 line 67: border-radius:2px',
);
final gradiente = decoracion.gradient as LinearGradient;
expect(gradiente.begin, Alignment.topCenter);
expect(gradiente.end, Alignment.bottomCenter);
expect(gradiente.colors.first, color);
expect(gradiente.colors.last, color.withValues(alpha: 0.3));
});
testWidgets(
'a custom gradienteFinAlpha changes only the gradient END colour '
'(t4 line 121: the player uses rgba(244,184,96,.45), not .3)',
(tester) async {
final controller = StreamController<EstadoReproduccion>.broadcast();
addTearDown(controller.close);
const color = Color(0xFFF4B860);
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: VisualizadorAudio(
estadoStream: controller.stream,
barras: 8,
barrasDiscretas: true,
color: color,
gradienteFinAlpha: 0.45,
),
),
),
);
await tester.pump();
final barra = tester.widget<Container>(
find.byKey(const Key('visualizador-barra-0')),
);
final gradiente =
(barra.decoration as BoxDecoration).gradient as LinearGradient;
expect(gradiente.colors.last, color.withValues(alpha: 0.45));
},
);
testWidgets('barrasDiscretas defaults to false — existing callers keep the '
'continuous CustomPaint stroke, no regression', (tester) async {
final controller = StreamController<EstadoReproduccion>.broadcast();
addTearDown(controller.close);
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: VisualizadorAudio(estadoStream: controller.stream),
),
),
);
await tester.pump();
expect(
find.descendant(
of: find.byType(VisualizadorAudio),
matching: find.byType(CustomPaint),
),
findsOneWidget,
);
expect(find.byKey(const Key('visualizador-barra-0')), findsNothing);
});
});
}