Why when i install a dev module not work?

well my problem its simply relativy, the think is when i install a module of node in my local project with

npm install --save-dv jest

(jest for example)
when i run this code with npm test
(the code of my packet.json)

{
test:"jest"
}

i get a error from console.
the same thinks happend with other dev modules when i install like babel/preset-env.
Is there something I can do or something that fails?
note: when i install something with npm g all works.
note2: my vscode stay admin mode.

It is --save-dev or -D

Using --save-dv will install it as “dependencies” not “devDependencies”


It might help if you told us what error you are getting when running the script.

1 Like

goob! my code of jest works now but now when i try pass a module function suma my code ject this error.
Uploading: image.png…

 FAIL  __tests__/ejemplo-modulo.js
  ● Test suite failed to run

    TypeError: Cannot set properties of null (setting 'textContent')

       96 |             heading.textContent = 'Administra tus Citas '
       97 |         } else {
    >  98 |             heading.textContent = 'No hay Citas, comienza creando una'
          |             ^
       99 |         }
      100 |     }
      101 |

      at UI.textoHeading (js/classes/UI.js:98:13)
      at new UI (js/classes/UI.js:7:14)
      at Object.<anonymous> (js/funciones.js:15:12)
      at Object.<anonymous> (__tests__/ejemplo-modulo.js:1:1)

Test Suites: 1 failed, 1 total
Tests:       0 total
Snapshots:   0 total
Time:        11.396 s
Ran all test suites.

NOTE: i install babel

.babelrc

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "node": "current"
        }
      }
    ]
  ]
}

my package.json

{
  "name": "51-testing-jest",
  "version": "1.0.0",
  "description": "JEST",
  "main": "index.js",
  "scripts": {
    "test": "jest"
  },
  "author": "Javier",
  "license": "ISC",
  "devDependencies": {
    "@babel/preset-env": "^7.18.6",
    "jest": "26.4.2"
  }
}

my function archive

import Citas from "./classes/Citas.js";
import UI from "./classes/UI.js";

import {
  mascotaInput,
  propietarioInput,
  telefonoInput,
  fechaInput,
  horaInput,
  sintomasInput,
  formulario,
} from "./selectores.js";

const administrarCitas = new Citas();
const ui = new UI(administrarCitas);

let editando = false;

const citaObj = {
  mascota: "",
  propietario: "",
  telefono: "",
  fecha: "",
  hora: "",
  sintomas: "",
};

export function datosCita(e) {
  //  console.log(e.target.name) // Obtener el Input
  citaObj[e.target.name] = e.target.value;
}

export function nuevaCita(e) {
  e.preventDefault();

  const { mascota, propietario, telefono, fecha, hora, sintomas } = citaObj;

  // Validar
  if (
    mascota === "" ||
    propietario === "" ||
    telefono === "" ||
    fecha === "" ||
    hora === "" ||
    sintomas === ""
  ) {
    ui.imprimirAlerta("Todos los campos son Obligatorios", "error");

    return;
  }

  if (editando) {
    // Estamos editando
    administrarCitas.editarCita({ ...citaObj });

    ui.imprimirAlerta("Guardado Correctamente");

    formulario.querySelector('button[type="submit"]').textContent =
      "Crear Cita";

    editando = false;
  } else {
    // Nuevo Registrando

    // Generar un ID único
    citaObj.id = Date.now();

    // Añade la nueva cita
    administrarCitas.agregarCita({ ...citaObj });

    // Mostrar mensaje de que todo esta bien...
    ui.imprimirAlerta("Se agregó correctamente");
  }

  // Imprimir el HTML de citas
  ui.imprimirCitas(administrarCitas);

  // Reinicia el objeto para evitar futuros problemas de validación
  reiniciarObjeto();

  // Reiniciar Formulario
  formulario.reset();
}

export function reiniciarObjeto() {
  // Reiniciar el objeto
  citaObj.mascota = "";
  citaObj.propietario = "";
  citaObj.telefono = "";
  citaObj.fecha = "";
  citaObj.hora = "";
  citaObj.sintomas = "";
}

export function eliminarCita(id) {
  administrarCitas.eliminarCita(id);

  ui.imprimirCitas(administrarCitas);
}

export function cargarEdicion(cita) {
  const { mascota, propietario, telefono, fecha, hora, sintomas, id } = cita;

  // Reiniciar el objeto
  citaObj.mascota = mascota;
  citaObj.propietario = propietario;
  citaObj.telefono = telefono;
  citaObj.fecha = fecha;
  citaObj.hora = hora;
  citaObj.sintomas = sintomas;
  citaObj.id = id;

  // Llenar los Inputs
  mascotaInput.value = mascota;
  propietarioInput.value = propietario;
  telefonoInput.value = telefono;
  fechaInput.value = fecha;
  horaInput.value = hora;
  sintomasInput.value = sintomas;

  formulario.querySelector('button[type="submit"]').textContent =
    "Guardar Cambios";

  editando = true;
}

export function suma(a, b) {
  return a + b;
}

my UI class

import { eliminarCita, cargarEdicion } from '../funciones.js';
import { contenedorCitas, heading } from '../selectores.js';

class UI {

    constructor({citas}) {
        this.textoHeading(citas);
    }

    imprimirAlerta(mensaje, tipo) {
        // Crea el div
        const divMensaje = document.createElement('div');
        divMensaje.classList.add('text-center', 'alert', 'd-block', 'col-12');
        
        // Si es de tipo error agrega una clase
        if(tipo === 'error') {
             divMensaje.classList.add('alert-danger');
        } else {
             divMensaje.classList.add('alert-success');
        }

        // Mensaje de error
        divMensaje.textContent = mensaje;

        // Insertar en el DOM
        document.querySelector('#contenido').insertBefore( divMensaje , document.querySelector('.agregar-cita'));

        // Quitar el alert despues de 3 segundos
        setTimeout( () => {
            divMensaje.remove();
        }, 3000);
   }

   imprimirCitas({citas}) { // Se puede aplicar destructuring desde la función...
       
        this.limpiarHTML();

        this.textoHeading(citas);

        citas.forEach(cita => {
            const {mascota, propietario, telefono, fecha, hora, sintomas, id } = cita;

            const divCita = document.createElement('div');
            divCita.classList.add('cita', 'p-3');
            divCita.dataset.id = id;

            // scRIPTING DE LOS ELEMENTOS...
            const mascotaParrafo = document.createElement('h2');
            mascotaParrafo.classList.add('card-title', 'font-weight-bolder');
            mascotaParrafo.innerHTML = `${mascota}`;

            const propietarioParrafo = document.createElement('p');
            propietarioParrafo.innerHTML = `<span class="font-weight-bolder">Propietario: </span> ${propietario}`;

            const telefonoParrafo = document.createElement('p');
            telefonoParrafo.innerHTML = `<span class="font-weight-bolder">Teléfono: </span> ${telefono}`;

            const fechaParrafo = document.createElement('p');
            fechaParrafo.innerHTML = `<span class="font-weight-bolder">Fecha: </span> ${fecha}`;

            const horaParrafo = document.createElement('p');
            horaParrafo.innerHTML = `<span class="font-weight-bolder">Hora: </span> ${hora}`;

            const sintomasParrafo = document.createElement('p');
            sintomasParrafo.innerHTML = `<span class="font-weight-bolder">Síntomas: </span> ${sintomas}`;

            // Agregar un botón de eliminar...
            const btnEliminar = document.createElement('button');
            btnEliminar.onclick = () => eliminarCita(id); // añade la opción de eliminar
            btnEliminar.classList.add('btn', 'btn-danger', 'mr-2');
            btnEliminar.innerHTML = 'Eliminar <svg fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" stroke="currentColor"><path d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>'

            // Añade un botón de editar...
            const btnEditar = document.createElement('button');
            btnEditar.onclick = () => cargarEdicion(cita);

            btnEditar.classList.add('btn', 'btn-info');
            btnEditar.innerHTML = 'Editar <svg fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" stroke="currentColor"><path d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"></path></svg>'

            // Agregar al HTML
            divCita.appendChild(mascotaParrafo);
            divCita.appendChild(propietarioParrafo);
            divCita.appendChild(telefonoParrafo);
            divCita.appendChild(fechaParrafo);
            divCita.appendChild(horaParrafo);
            divCita.appendChild(sintomasParrafo);
            divCita.appendChild(btnEliminar)
            divCita.appendChild(btnEditar)

            contenedorCitas.appendChild(divCita);
        });    
   }

   textoHeading(citas) {
        if(citas.length > 0 ) {
            heading.textContent = 'Administra tus Citas '
        } else {
            heading.textContent = 'No hay Citas, comienza creando una'
        }
    }

   limpiarHTML() {
        while(contenedorCitas.firstChild) {
            contenedorCitas.removeChild(contenedorCitas.firstChild);
        }
   }
}

export default UI;

The best way to debug errors like this is to “work backwards”.

Where heading must be undefined/null. Since you’re importing heading from another file (selectores.js) then that file must be exporting heading as null.

I’d also like to throw out a warning on the architecture of the code so far from what is posted. One of the biggest pain points with OOP is the “where does state go” problem. If your UI class updates the HTML defined within another file selectores.js via reference, it might become hard to track and debug these changes over time.

A “UI” class sounds somewhat like a potential “god class” as what isn’t the UI in a web-app? It might be sensible to isolate parts of your app into separate classes named after their parts, rather than having 1 generic UI class.

But this is all general warnings going off of OOP and UI design.

1 Like