fix(assets): declare the content subdirectories so onboarding ships
Audit of the same failure family as the shrunk drawables: references by NAME that nothing validates at compile time. The whole onboarding and release-notes feature had never shipped. Reading the installed APK: ZERO entries under assets/content/, while assets/icons/alarmas/* was present. pubspec declared `assets/content/`, and Flutter does not recurse -- naming a directory includes the files sitting directly in it, never its subdirectories. Every content file lives in one (onboarding/, updates/<locale>/), so none of them were packaged. On the device that surfaced on every single launch: Unable to load asset: "assets/content/onboarding/en.md" with the file plainly present on disk. That is why it never looked like a packaging problem. The tell was already in the pubspec: assets/icons/alarmas/ is listed explicitly, so the rule was known once and not applied here. All 14 content directories are now declared: onboarding/ plus updates/ for each of the 13 locales. The guard is a test that loads every file under assets/content/ through rootBundle, because that is the only thing that proves an asset is declared and will ship. A test asserting File.existsSync would have stayed green through all of this -- the files were never missing, only unpackaged. Run against the unfixed pubspec it fails 26 of 27; with the fix it passes. Tests: 1165 -> 1192.
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
/// Every file under `assets/content/` must be loadable through `rootBundle`,
|
||||
/// which is the only thing that proves it is DECLARED in pubspec.yaml and
|
||||
/// therefore actually ships.
|
||||
///
|
||||
/// Found by reading the installed APK: it contained ZERO entries under
|
||||
/// `assets/content/`, while `assets/icons/alarmas/*` was present. pubspec
|
||||
/// declared `assets/content/` — and Flutter does NOT recurse: naming a
|
||||
/// directory includes the files sitting directly in it, never its
|
||||
/// subdirectories. All of this content lives in subdirectories
|
||||
/// (`onboarding/`, `updates/<locale>/`), so the entire onboarding and
|
||||
/// release-notes feature had never shipped in any build. On the device it
|
||||
/// surfaced on every launch as:
|
||||
///
|
||||
/// Unable to load asset: "assets/content/onboarding/en.md"
|
||||
///
|
||||
/// with the file plainly present on disk.
|
||||
///
|
||||
/// Same family as the drawables the resource shrinker deleted: a reference by
|
||||
/// NAME that nothing validates at compile time, so it fails only on a device.
|
||||
/// A test that merely checked `File(...).existsSync()` would have stayed green
|
||||
/// throughout — the files were never missing. Loading through `rootBundle` is
|
||||
/// what makes it a real guard, because that is the path the app itself takes.
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
final directorio = Directory('assets/content');
|
||||
final ficheros =
|
||||
directorio
|
||||
.listSync(recursive: true)
|
||||
.whereType<File>()
|
||||
.map((f) => f.path.replaceAll(r'\', '/'))
|
||||
.toList()
|
||||
..sort();
|
||||
|
||||
test('hay contenido que comprobar (si no, este test sería vacuo)', () {
|
||||
expect(ficheros, isNotEmpty);
|
||||
});
|
||||
|
||||
for (final ruta in ficheros) {
|
||||
test('$ruta está declarado y se puede cargar', () async {
|
||||
await expectLater(
|
||||
rootBundle.loadString(ruta),
|
||||
completes,
|
||||
reason:
|
||||
'existe en disco pero rootBundle no lo encuentra: falta declarar '
|
||||
'su directorio en pubspec.yaml, y no viajará en el APK',
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user