Lección 9 de 10 · 11 min de lectura · Revisado el 26/10/2026
Accesibilidad en el flujo de desarrollo: componentes, previsualizaciones y pruebas automatizadas
Todo lo que has aprendido en este curso se pierde en el siguiente sprint si nadie lo protege: un componente nuevo sin etiqueta, una refactorización que fija la altura de una celda, una librería actualizada que deja de anunciar el cambio de pantalla. Esta lección se centra en el trabajo diario del equipo de desarrollo: construir una capa de componentes que haga difícil equivocarse, revisar la accesibilidad mientras se programa y automatizar las comprobaciones en las pruebas de iOS, Android, React Native y Flutter. La auditoría formal de apps, con Accessibility Inspector, Accessibility Scanner y el protocolo de pruebas manuales, la verás en el curso «Evaluación de aplicaciones móviles» de este mismo nivel.
Componentes que obligan a hacerlo bien
En la lección de apps híbridas se recomendaba una capa de componentes accesibles propia. La versión más eficaz de esa idea es diseñar las firmas de los componentes para que el error no compile: si el nombre accesible es un parámetro obligatorio, nadie puede olvidarlo.
// Compose: el botón de icono exige una descripción
@Composable
fun BotonIcono(icono: ImageVector, descripcion: String, onClick: () -> Unit) {
IconButton(onClick = onClick) { // rol de botón y 48 dp de serie
Icon(icono, contentDescription = descripcion)
}
}
// SwiftUI: el título es obligatorio aunque solo se vea el icono
struct BotonIcono: View {
let titulo: LocalizedStringKey
let simbolo: String
let accion: () -> Void
var body: some View {
Button(action: accion) { Label(titulo, systemImage: simbolo) }
.labelStyle(.iconOnly) // el título sigue siendo el nombre accesible
}
} Aplica la misma idea a la fila de lista (nombre compuesto y acciones como parámetros), a la cabecera de sección (que siempre marca encabezado), al campo de formulario (etiqueta visible obligatoria, propósito de entrada y mensaje de error) y al diálogo (título obligatorio y foco gestionado). Documenta en cada componente qué garantiza y qué queda en manos de quien lo usa.
Punto clave
Un componente bien diseñado corrige cien pantallas a la vez; un componente mal diseñado propaga el mismo fallo a todas ellas. Por eso la revisión de accesibilidad más rentable es la de la librería de componentes, antes de que se use.
Revisar mientras programas: análisis estático y previsualizaciones
El análisis estático detecta omisiones evidentes sin ejecutar la app:
- Android Lint incluye comprobaciones de accesibilidad como
ContentDescription(imagen sin descripción),ClickableViewAccessibility,KeyboardInaccessibleWidgetyLabelFor. Elévalas a error en la configuración del proyecto para que bloqueen la integración. - SwiftLint ofrece reglas opcionales como
accessibility_label_for_imageyaccessibility_trait_for_buttonpara SwiftUI. - React Native: eslint-plugin-react-native-a11y, que ya conociste en la lección de apps híbridas.
Las previsualizaciones permiten ver cada pantalla con texto grande o contraste aumentado sin abrir el simulador:
// SwiftUI
#Preview("Texto AX5") {
FichaCita(cita: .ejemplo)
.environment(\.dynamicTypeSize, .accessibility5)
}
// Compose: varias escalas de fuente en una sola anotación
@PreviewFontScale
@Composable
fun FichaCitaPreview() { FichaCita(cita = citaEjemplo) }
@Preview(fontScale = 2f, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
fun FichaCitaGrandeOscuroPreview() { FichaCita(cita = citaEjemplo) } Durante la ejecución, el panel Environment Overrides de Xcode cambia al vuelo Dynamic Type, Aumentar contraste o Texto en negrita, y el modo UI Check de las previsualizaciones de Compose en Android Studio señala problemas de accesibilidad y de adaptación. Son revisiones de minutos que detectan textos truncados y contrastes insuficientes antes de llegar a pruebas.
Infografía · Niveles
Capas de protección de la accesibilidad en una app
De la base, que previene errores, a la cima, que confirma la experiencia real
- Nivel 1 (base): Componentes accesiblesBotón, campo, fila y cabecera ya traen nombre, rol, estado y 48 dp
- Nivel 2: Análisis estáticoAndroid Lint, SwiftLint y eslint detectan etiquetas y roles ausentes
- Nivel 3: PrevisualizacionesTexto grande, modo oscuro y contraste en cada pantalla antes de ejecutar
- Nivel 4: Pruebas de semánticaTests que verifican nombre, rol, estado y acciones de cada componente
- Nivel 5: Auditoría en pruebas de UIperformAccessibilityAudit, AccessibilityChecks y guías de Flutter en CI
- Nivel 6 (cima): Pruebas manualesVoiceOver, TalkBack, Switch y teclado en dispositivo real, y usuarios
Leer la infografía como texto
Seis capas apiladas, de la base a la cima, que protegen la accesibilidad de una app en su desarrollo. Base, componentes accesibles: el botón, el campo, la fila y la cabecera ya traen nombre, rol, estado y 48 dp. Segunda capa, análisis estático: Android Lint, SwiftLint y eslint detectan etiquetas y roles ausentes. Tercera, previsualizaciones: cada pantalla se revisa con texto grande, modo oscuro y contraste antes de ejecutarla. Cuarta, pruebas de semántica: tests que verifican nombre, rol, estado y acciones. Quinta, auditorías en las pruebas de interfaz: performAccessibilityAudit, AccessibilityChecks y las guías de Flutter en la integración continua. Cima, pruebas manuales con VoiceOver, TalkBack, Switch Access y teclado en dispositivo real, y con personas usuarias. Cada capa detecta lo que las inferiores no pueden ver.
Pruebas de semántica
Una prueba de semántica comprueba que un componente expone el nombre, el rol, el estado y las acciones que debe. Es rápida, estable y documenta el comportamiento esperado.
// Compose
@get:Rule val compose = createComposeRule()
@Test fun botonBuscarTieneNombreRolYAccion() {
compose.setContent { BarraSuperior() }
compose.onNodeWithContentDescription("Buscar")
.assertHasClickAction()
.assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
compose.onNodeWithText("Movimientos de marzo")
.assert(SemanticsMatcher.keyIsDefined(SemanticsProperties.Heading))
}
// React Native Testing Library
expect(screen.getByRole('button', { name: 'Buscar' })).toBeOnTheScreen();
// Flutter: búsqueda por etiqueta semántica
expect(find.bySemanticsLabel('Buscar'), findsOneWidget); En iOS, las pruebas de UI localizan los elementos a través de la información de accesibilidad: app.buttons["Buscar"] busca un botón por su identificador o su etiqueta, y puedes comprobar que label tiene el valor esperado.
Error frecuente
Para que las pruebas de UI encuentren los elementos, alguien asigna a los botones etiquetas como "btn_buscar_test". Las pruebas pasan y VoiceOver lee «btn buscar test». Para localizar elementos en pruebas usa accessibilityIdentifier en iOS, testTag en Compose o testID en React Native, que no se anuncian; reserva la etiqueta para el nombre que debe oír la persona, y compruébala en el test.
Auditorías automáticas dentro de las pruebas de UI
Las plataformas permiten ejecutar comprobaciones automáticas de accesibilidad sobre cada pantalla que recorren las pruebas:
// iOS 17 / Xcode 15: auditoría de la pantalla actual
func testAuditoriaMisCitas() throws {
let app = XCUIApplication()
app.launch()
app.buttons["Mis citas"].tap()
try app.performAccessibilityAudit(for: [.dynamicType, .contrast, .hitRegion,
.sufficientElementDescription, .textClipped]) { incidencia in
// Devuelve true solo para incidencias revisadas y documentadas
incidencia.auditType == .contrast && incidencia.element?.identifier == "logo-municipal"
}
}
// Android con Espresso: comprobaciones del Accessibility Test Framework en cada acción
@BeforeClass @JvmStatic
fun activarComprobaciones() {
AccessibilityChecks.enable().setRunChecksFromRootView(true)
}
// Flutter: guías incluidas en flutter_test
testWidgets('la pantalla de citas cumple las guías básicas', (tester) async {
final handle = tester.ensureSemantics();
await tester.pumpWidget(const MiApp());
await expectLater(tester, meetsGuideline(androidTapTargetGuideline));
await expectLater(tester, meetsGuideline(labeledTapTargetGuideline));
await expectLater(tester, meetsGuideline(textContrastGuideline));
handle.dispose();
}); Las versiones recientes de la biblioteca de pruebas de Compose permiten activar también las comprobaciones del Accessibility Test Framework; consulta la documentación de tu versión. Estas auditorías detectan elementos sin descripción, objetivos táctiles pequeños, contraste insuficiente o texto recortado con texto grande. No detectan si una etiqueta es correcta, si el orden de lectura tiene sentido, si el foco vuelve al sitio adecuado al cerrar un diálogo ni si una tarea completa se puede realizar: como viste en el curso de herramientas automáticas del nivel 4, la automatización cubre solo una parte de los problemas.
Criterios de aceptación y definición de hecho
La automatización se sostiene con acuerdos de equipo. Incluye en la definición de hecho de cada historia con interfaz unos pocos criterios verificables:
- Recorrido completo de la funcionalidad con VoiceOver y TalkBack en dispositivo real, sin elementos mudos ni duplicados.
- Pantallas revisadas con el texto al máximo y con texto en negrita, sin truncados.
- Gestos con alternativa y acciones de accesibilidad; objetivos de 44 pt o 48 dp.
- Foco gestionado en cambios de pantalla, diálogos y errores.
- Pruebas de semántica y auditoría automática en verde en la integración continua.
Pruébalo tú
Si tienes acceso al código de una app, ejecuta Android Lint o SwiftLint con las reglas de accesibilidad activadas y cuenta las advertencias. Si no, abre una previsualización o el simulador con el tamaño de texto más grande y anota cuántas pantallas truncan textos. Ese número es un buen punto de partida para tu primera definición de hecho.
Resumen
- Diseña componentes cuyas firmas exijan el nombre accesible, la etiqueta visible y el título: el error deja de compilar.
- Usa análisis estático (Android Lint, SwiftLint, eslint) y previsualizaciones con texto grande y contraste mientras programas.
- Las pruebas de semántica verifican nombre, rol, estado y acciones; localiza elementos con identificadores de prueba, nunca con etiquetas falsas.
performAccessibilityAudit,AccessibilityChecksy las guías deflutter_testautomatizan comprobaciones en cada pantalla, pero no sustituyen la prueba manual.- Una definición de hecho con criterios de accesibilidad verificables protege el trabajo en cada entrega.
Comprueba lo que has aprendido
Esta lección se puede leer libremente. Para hacer su test de 3 preguntas, los ejercicios prácticos con páginas reales, guardar tu avance y optar al examen y al certificado, matricúlate en el curso.
Matricularme · nivel 6 (119 €)