En esta práctica estudiaremos los mecanismos de almacenamiento de datos en el navegador. De esta manera nuestra aplicación podrá guardar su estado (listado de gastos) aunque se cierre la ventana del navegador.
El repositorio base de la práctica está disponible en: https://github.com/pedroprieto/practica_dwec_gestor_presupuesto
Se supone que ya está configurado el repositorio personal y el remoto secundario (profesor
). Si no es así, revisa las instrucciones de las prácticas anteriores. En el apartado de Preparación se indica cómo proceder.
Para poder realizar esta práctica y que funcione adecuadamente el entorno de test será necesario instalar el siguiente software en el equipo:
Para realizar la práctica se seguirán los principios del Desarrollo Guiado por Test. Para ello se proporciona en el repositorio una serie de ficheros que permiten ejecutar tests. Dichos tests comprobarán que el programa cumple con algunos de los requisitos de la práctica.
El repositorio se ha configurado para que se ejecuten los tests automáticamente en la nube de GitHub cuando se realice un push o una pull request. Para ello se hará uso del servicio GitHub Actions.
- Instalar los requisitos de software indicados
- Abrir un terminal
- Situarse en la carpeta del repositorio personal de la práctica
- Incorporar a tu repositorio personal los cambios realizados por el profesor correspondientes a los archivos de esta práctica. Para ello hay que ejecutar:
git pull profesor master
- Este comando descarga los cambios que ha realizado el profesor en el repositorio base y los integra en tu repositorio personal. Tras realizar este paso, seguramente git abra el editor configurado por defecto para que introduzcas un mensaje para crear un nuevo commit que integre tus cambios y los cambios del profesor. Debes introducir el texto y guardar los cambios.
- En principio no deben producirse conflictos. En caso de que se produzcan (por ejemplo, porque has editado el fichero
.gitignore
y yo también porque lo exigía la práctica), resuélvelos y notifícamelo a través de un Issue. - Ejecuta el comando
git push
para subir los cambios a tu repositorio personal (el remoto principal) en GitHub y que queden guardados ahí también. - Ejecutar el comando
npm install
. Este comando instalará todas las librerías de Node necesarias para ejecutar los tests. Dichas librerías se guardarán en una carpeta con nombrenode_modules
dentro del repositorio. Nótese que dicha carpeta está excluida del repositorio en el archivo.gitignore
. - Ejecutar el comando
npm run test8
para lanzar los tests de esta práctica. Este comando podrá ejecutarse tantas veces como sea necesario. Por pantalla se mostrarán los tests que se pasan y los que no, de manera que se tendrá información sobre las acciones que hay que realizar. Los tests también se ejecutarán automáticamente en GitHub Actions al subir los cambios al repositorio y al realizar la pull request. - Opcionalmente (recomendable), ejecutar el comando
npm test
para lanzar todos los tests presentes en el repositorio. Se deberá comprobar que se pasan los tests de las prácticas anteriores a la que se esté realizando. Lógicamente, si el repositorio incluye los tests de prácticas posteriores a la que se esté realizando, dichos tests no se pasarán (ya que el trabajo está todavía por hacer). Este último caso puede darse si la persona no está realizando la práctica propuesta en la semana actual (va con “retraso”, por así decirlo). En GitHub Actions se ejecutarán todos los tests en tareas independientes: así se podrá comprobar si el test de la práctica que se está realizando se ha pasado.¡IMPORTANTE! Esta práctica utiliza la suite de test Cypress. Puedes ejecutar el test en consola de la manera habitual (
npm run test8
) o bien ejecutar el modo gráfico mediante el comandonpx cypress open
. Recuerda ejecutarnpm install
antes para instalar el paquetecypress
.Recuerda que puedes utilizar el navegador para visualizar el trabajo que vas haciendo. Como la carga de scripts la realizamos a través de módulos, no basta con hacer doble clic en el archivo
HTML
, sino que es necesario visualizar la página desde un servidor. Para ello puedes utilizar la extensión Live Server de Vísual Studio Code.
Lee atentamente los siguientes artículos y sus correspondientes subsecciones en caso de que las tengan:
- https://es.javascript.info/cookie
- https://es.javascript.info/localstorage
- https://es.javascript.info/indexeddb (opcional)
Vamos a utilizar los ficheros de la práctica anterior realizando modificaciones sobre el archivo js/gestionPresupuestoWeb.js
.
Utilizaremos de nuevo el fichero interaccionHTML.html
para mostrar los datos e interactuar con la aplicación a través del navegador.
La aplicación funcionará de la siguiente manera:
- El usuario abrirá el archivo
interaccionHTML.html
en el navegador (a través de un servidor web, tal como se ha comentado en la sección de Preparación). - El archivo
interaccionHTML.html
cargará el programajs/generarDatosEstaticos.js
. Dicho programa hará uso de dos programas (que se utilizarán como librerías):- Librería
js/gestionPresupuestoWeb.js
, que definirá una serie de funciones para interactuar con el DOM de la página y mostrar los datos en HTML. En esta práctica realizaremos modificaciones en este fichero para añadir un formulario de filtrado y una lógica de comprobación de datos mediante expresiones regulares. - Librería
js/gestionPresupuesto.js
, que contiene la lógica de negocio de la aplicación (funciones para crear, editar, borrar y mostrar gastos).
- Librería
El archivo js/generarDatosEstaticos.js
se utilizará para crear unos gastos iniciales para poder hacer pruebas durante el desarrollo (para que no aparezca la aplicación vacía). Por tanto, en una aplicación en producción no sería necesario: el archivo HTML funcionaría cargando el archivo /js/gestionPresupuestoWeb.js
directamente.
Vamos a añadir dos botones a la capa <div id="controlesprincipales">
:
- Un botón de tipo
button
conid
guardar-gastos
y textoGuardar gastos
. - Un botón de tipo
button
conid
cargar-gastos
y textoCargar gastos
.
Dichos botones se utilizarán para guardar el listado de datos en el almacenamiento local del navegador utilizando localstorage.
La lógica de la aplicación que hemos desarrollado nos permite obtener el listado completo de gastos (función listarGastos
), pero no nos permite sobreescribir el listado completo de gastos desde una copia de seguridad. Es por ello que vamos a crear una función que implemente dicha funcionalidad.
Vamos a añadir esta función al paquete gestionPresupuesto.js
. La función deberá realizar las siguientes tareas:
- Tomará como parámetro un array de gastos. Dicho array de gastos procederá del almacenamiento. Los gastos que contiene son objetos que previamente se habían convertido a formato JSON. Cuando la función
cargarGastosWeb
los recupere, los objetos solo contendrán las propiedades: no tendrán acceso a los métodos disponibles en un objeto creado medianteCrearGasto
(anyadirEtiquetas
,actualizarValor
, etc.). Por tanto, la funcióncargarGastos
tendrá que transformar ese array de objetos “planos” (sin funcionalidad) en objetos de tipoCrearGasto
. A este proceso se le suele llamar rehidratación de objetos. - Inicializará la variable global
gastos
asignándole un array vacío. - Para cada gasto recibido, realizará las siguientes acciones:
- Creará un nuevo objeto mediante el constructor
CrearGasto
. - A continuación, copiará las propiedades existentes en el gasto obtenido del almacenamiento a ese nuevo objeto creado.
- Por último, añadirá el nuevo gasto rehidratado a la variable global
gastos
.
- Creará un nuevo objeto mediante el constructor
- El código necesario se muestra a continuación:
function cargarGastos(gastosAlmacenamiento) { // gastosAlmacenamiento es un array de objetos "planos" // No tienen acceso a los métodos creados con "CrearGasto": // "anyadirEtiquetas", "actualizarValor",... // Solo tienen guardadas sus propiedades: descripcion, valor, fecha y etiquetas // Reseteamos la variable global "gastos" gastos = []; // Procesamos cada gasto del listado pasado a la función for (let g of gastosAlmacenamiento) { // Creamos un nuevo objeto mediante el constructor // Este objeto tiene acceso a los métodos "anyadirEtiquetas", "actualizarValor",... // Pero sus propiedades (descripcion, valor, fecha y etiquetas) están sin asignar let gastoRehidratado = new CrearGasto(); // Copiamos los datos del objeto guardado en el almacenamiento // al gasto rehidratado // https://es.javascript.info/object-copy#cloning-and-merging-object-assign Object.assign(gastoRehidratado, g); // Ahora "gastoRehidratado" tiene las propiedades del gasto // almacenado y además tiene acceso a los métodos de "CrearGasto" // Añadimos el gasto rehidratado a "gastos" gastos.push(gastoRehidratado) } }
Por último, se deberá exportar la función cargarGastos
.
Vamos a hacer una serie de modificaciones sobre este fichero con respecto a la práctica anterior.
Añadiremos dos funciones para guardar y cargar respectivamente el listado de gastos en el almacenamiento local del navegador.
¡¡IMPORTANTE!! Al ejecutar los tests se eliminarán los datos de la aplicación que haya guardados previamente.
Esta función se utilizará como manejadora de eventos del evento click
del botón guardar-gastos
.
Se encargará de guardar el listado de gastos (disponible en la función listarGastos
del paquete js/gestionPresupuesto.js
) en la clave de almacenamiento de localstorage denominada GestorGastosDWEC
. Ten en cuenta que solo se pueden almacenar strings.
Esta función se utilizará como manejadora de eventos del evento click
del botón cargar-gastos
.
Se encargará de cargar el listado de gastos (función cargarGastos
del paquete js/gestionPresupuesto.js
) desde la clave de almacenamiento de localstorage denominada GestorGastosDWEC
. Ten en cuenta que solo se pueden almacenar strings.
Si no existe la clave en el almacenamiento, llamará a cargarGastos
con un array vacío.
Una vez cargados los gastos deberá llamar a la función repintar
para que se muestren correctamente en el HTML.
- Cada persona trabajará en su repositorio personal que habrá creado tras realizar el fork del repositorio base.
- Todos los archivos de la práctica se guardarán en el repositorio y se subirán a GitHub periódicamente. Es conveniente ir subiendo los cambios aunque no sean definitivos. No se admitirán entregas de tareas que tengan un solo commit.
- Como mínimo se debe realizar un commit por cada elemento de la lista de tareas a realizar (si es que estas exigen crear código, claro está).
- Para cualquier tipo de duda o consulta se pueden abrir
Issues
haciendo referencia al profesor mediante el texto@pedroprieto
dentro del texto delIssue
. Losissues
deben crearse en tu repositorio: si no se muestra la pestaña deIssues
puedes activarla en losSettings
de tu repositorio. - Una vez finalizada la tarea se debe realizar una
Pull Request
al repositorio base indicando tu nombre y apellidos en el mensaje.