Coding - djsordo/senda GitHub Wiki
Fechas con sentido
La funcion formatDateUtil
convierte un dato fecha de javascript en
una cadena de texto como "mañana (03/04)", o "hace una hora (16:05)".
Su uso es relativamente simple:
import { formatDateUtil } from './string-util';
formatDateUtil( tomorrow ) -> retorna "mañana (dd/mm)"
Más adelante seguramente se cambie para que en lugar de un dato tipo Date
coja un dato tipo timestamp
, que tiene más sentido.
Crear entradas de firestore con nuestros propios id's
Si usamos la función addDoc
de firestore, ésta creará un
id propio que no informa mucho, por ejemplo eC38vvLRv9JNYBKAno60
.
En cambio, si usamos setDoc
le podemos poner el id que queramos,
siempre y cuando tenga letras y números... para este fin he creado
la función make_id
. Usarla es sencillo:
Por ejemplo, los literales Raúl Luna
quedarian convertidos en raul_luna
,
permitiendo que se cree un id con ese valor perfectamente. Para invocarlo:
import { make_id } from 'string-util';
make_id( 'esto', 'es', 'una', 'prueba' ) => 'esto_es_una_prueba'
Sobre localStorage y testabilidad de la aplicación
La api localStorage es expuesta por muchos navegadores para acceder a una base de datos "local" en formato clave/valor. Hasta aquí bien.
Sin embargo, el uso de esta api directamente provoca un problema de testabilidad de la aplicación.
Veamos este código:
private async initCurrentUser(){
this.usuarioService.getUsuarioBD( localStorage.getItem('emailUsuario') )
.subscribe(usuarios => {
this.usuario = usuarios[0];
console.log('usuario: ', usuarios);
});
}
En el componente, mientras ejecutemos la aplicación, la llamada a
localStorage funcionará y traerá un valor del localStorage
que ha sido guardado en pantallas previas.
Pero se plantea un problema cuando queramos testar el componente aislado: en ese momento se ejecutará en un navegador instrumentalizado que viene "limpio": el localStorage no tendrá ningún valor almacenado previamente.
¿Podemos permitir la testabilidad de un componente y a la vez seguir accediendo a localStorage???
Si. La inyección de dependencias de Angular nos permitirá inyectar un servicio con una implementación "real" en la aplicación en producción y a la vez un servicio con una implementación para pruebas en los tests.
LocalStorage
que será nuestro mock
Paso 1: creamos el servicio @Injectable({
providedIn : 'root'
})
export class LocalStorage{
values : Map<string,string>;
constructor() {
this.values = new Map<string,string>();
}
setValues( values : [{key:string, value:string}] ){
for( let value of values ){
this.values.set( value.key, value.value );
}
}
setItem( key : string, value : string ) : void {
this.values.set( key, value );
}
getItem( key : string ) : string {
return this.values.get( key );
}
removeItem( key : string ) : void {
this.values.delete( key );
}
}
Esta es una clase normal que guarda los grupos clave/valor en un mapa.
A continuación lo que haremos será crear la clase que implemente la
funcionalidad real, accediendo de verdad a localStorage
:
@Injectable({
providedIn : 'root'
})
export class LocalStorageService extends LocalStorage {
setItem(key: string, value: string): void {
localStorage.setItem( key, value );
}
getItem(key: string): string {
return localStorage.getItem( key );
}
removeItem(key: string): void {
localStorage.removeItem( key );
}
}
Paso 2: declarar el componente para que cada vez que se registre, llame al servicio real y no al mock
Ahora viene la magia: cuando vayamos a usar esta clase en nuestra aplicación, la declararemos así:
providers: [{ provide : LocalStorage,
useClass : LocalStorageService }],
Esto se puede colocar en app.module.ts
para que esté disponible
para toda la aplicación o bien puede declararse por componente.
Paso 3: hacer las modificaciones correspondientes en los tests
En los tests, lo haremos al revés: nos aseguraremos no sólo de inyectar el servicio de pruebas, sino además de meterle los valores que necesita nuestro componente para funcionar correctamente:
beforeAll( ( callMeOnFinish ) => {
TestBed.configureTestingModule({
imports: [ ... ],
providers: [{ provide : LocalStorage, useFactory: () => {
let localStorage = new LocalStorage();
localStorage.setValues( [{key : 'emailUsuario',
value : '[email protected]'}]);
return localStorage;
} } ]
});
callMeOnFinish();
} );
En este caso, en la inyección de dependencias, hemos usado
useFactory
, que nos permite insertar unos valores de pruebas
para que el test vaya bien.