Instalar Node.js: comprobar el funcionamiento de los botones en el servidor sin navegador

Para ejecutar JavaScript en un servidor, primero hay que instalar Node.js. Instalé Node.js 24.21.0 en un servidor WordPress con Nginx y Apache y, con jsdom 30.1.3, comprobé sin navegador el script de los botones de una página web.
El nodejs del repositorio predeterminado es la 16.20.2, pero jsdom 30.1.3, que uso para comprobar scripts, requiere Node.js 22.22.2 o posterior. Por eso lo instalé desde el flujo de módulo 24 de dnf.
1️⃣ Para qué instalar Node.js y jsdom en el servidor
Para comprobar scripts de botones en un servidor hacen falta dos cosas: Node.js y jsdom.
🔲 Node.js
JavaScript normalmente se ejecuta en el navegador, pero si instalas Node.js, el servidor también puede leer y ejecutar JavaScript.
Instalar Node.js es poner también en el servidor el entorno de ejecución de JavaScript que antes solo estaba en el navegador. Por eso Node.js se usa para crear servidores web, para hacer comandos que procesan muchos archivos a la vez o para cargar paquetes como jsdom y comprobar páginas. Ghost también es un CMS que funciona sobre Node.js.
🔲 jsdom
jsdom es un paquete de Node.js que lee el HTML y lo convierte en un documento cuyos botones se pueden pulsar como en un navegador. Crea dentro del servidor, sin pantalla, la misma estructura de documento (DOM) que genera un navegador al abrir una página, así que los scripts encuentran los botones y cambian el texto como si estuvieran en un navegador real. Como no abre ninguna ventana, se ejecuta en el servidor con una sola línea de comando.
Es decir, las comprobaciones que una persona hacía abriendo el navegador y pulsando uno a uno los elementos las hace el servidor con un comando. Por eso jsdom también se usa para probar automáticamente el comportamiento de los botones cada vez que se corrige algo, para extraer de una página solo contenidos como títulos y enlaces, o para retocar en bloque el HTML de las entradas.
Si descargas una página con PHP o curl, solo ves el HTML que llegó al principio. El texto que cambia al pulsar un botón solo aparece cuando se ejecuta el script.
El navegador pasa por cuatro pasos: recibir la página, leer la página, pulsar el botón y mostrarla en pantalla. jsdom ejecuta en el servidor todos menos el de mostrar en pantalla, así que la posición y el tamaño de los botones se comprueban en el navegador.
2️⃣ Antes de instalar: el repositorio predeterminado y los flujos de módulo
Antes de ejecutar [dnf install nodejs], comprueba primero qué versión se instalaría. El nodejs del repositorio predeterminado de AlmaLinux 9.8 es la 16.20.2.
dnf list --available nodejsAvailable Packages
nodejs.x86_64 1:16.20.2-8.el9_4 appstreamEl repositorio de módulos tiene cuatro flujos: 18, 20, 22 y 24. En la fecha de la comprobación, el flujo 22 estaba en la 22.23.2 y el 24 en la 24.21.0.
dnf module list nodejsnodejs 18 common [d], development, minimal, s2i Javascript runtime
nodejs 20 common [d], development, minimal, s2i Javascript runtime
nodejs 22 common [d], development, minimal, s2i Javascript runtime
nodejs 24 common [d], development, minimal, s2i Javascript runtimeSegún el registro de npm, jsdom 30.1.3 requiere la 22.22.2 o posterior en la rama 22, la 24.15.0 o posterior en la rama 24, o la 26 en adelante. Los flujos 22 y 24 cumplen esta condición.
3️⃣ Instalar Node.js: dnf module
Esta vez instalé el flujo 24 y, antes de ejecutarlo, revisé con la opción [--assumeno] la lista de paquetes que se instalarían.
dnf module install nodejs:24 --assumenoLa lista solo incluía cinco paquetes: nodejs, npm, nodejs-libs, nodejs-docs y nodejs-full-i18n. No había paquetes del servidor web, de PHP ni del kernel. Tras comprobarlo, se instala con la opción [-y].
dnf module install -y nodejs:24Dependencies resolved.
==============================================================================================
Package Architecture Version Repository Size
==============================================================================================
Installing group/module packages:
nodejs x86_64 1:24.21.0-1.module_el9.8.0+321+1555b6a2 appstream 70 k
npm noarch 1:11.19.0-1.24.21.0.1.module_el9.8.0+321+1555b6a2 appstream 2.1 M
Installing dependencies:
nodejs-libs x86_64 1:24.21.0-1.module_el9.8.0+321+1555b6a2 appstream 24 M
Installing weak dependencies:
nodejs-docs noarch 1:24.21.0-1.module_el9.8.0+321+1555b6a2 appstream 5.3 M
nodejs-full-i18n x86_64 1:24.21.0-1.module_el9.8.0+321+1555b6a2 appstream 8.9 M
Installing module profiles:
nodejs/common
Enabling module streams:
nodejs 24
Transaction Summary
==============================================================================================
Install 5 Packages
Total download size: 40 M
Installed size: 185 M[Installing weak dependencies] muestra las dependencias débiles (weak dependencies), paquetes que conviene instalar a la vez. La descarga ocupa 40M y la instalación, 185M.
node -vv24.21.0npm -v11.19.0cat /etc/dnf/modules.d/nodejs.module[nodejs]
name=nodejs
stream=24
profiles=common
state=enablednode quedó instalado en la 24.21.0 y npm en la 11.19.0. El único archivo de configuración que cambió con la instalación es [/etc/dnf/modules.d/nodejs.module], que registra como activos el flujo 24 y el perfil common.
4️⃣ Instalar jsdom y comprobar el script de un botón
jsdom se instala con npm en una carpeta de trabajo, y esa carpeta se crea fuera de la raíz web.
mkdir ~/jsdom-test && cd ~/jsdom-test
npm init -y[npm init -y] crea package.json con los valores predeterminados y, a continuación, se instala jsdom en la misma carpeta.
npm install jsdomadded 36 packages, and audited 37 packages in 2s
8 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilitiesnpm ls jsdomjsdom-test@1.0.0 /root/jsdom-test
└── jsdom@30.1.3Se instalaron 36 paquetes, incluido jsdom 30.1.3, con 0 vulnerabilidades conocidas. La carpeta node_modules de la carpeta de trabajo ocupa 26M.
node -e 'const { JSDOM } = require(`jsdom`); console.log(new JSDOM(`<h1>Hola</h1>`).window.document.querySelector(`h1`).textContent)'HolaSi jsdom lee como documento un HTML formado por una sola etiqueta h1 e imprime el texto de dentro, [Hola], la comprobación ha terminado.
Comprobar el script de un botón es verificar en el servidor que el texto cambia bien después de pulsarlo. Como ejemplo, creé en la carpeta de trabajo un archivo HTML en el que, al pulsar el botón [Copiar], el texto cambia a [Copiado].
cat btn.html<button id="copy">Copiar</button>
<script>
document.getElementById('copy').addEventListener('click', function () {
this.textContent = 'Copiado';
});
</script>El script de comprobación lee el archivo HTML con jsdom, ejecuta sus scripts e imprime el texto antes y después de pulsar el botón. Los errores de script se muestran en líneas que empiezan por [Error:].
cat check.jsconst fs = require('fs');
const { JSDOM, VirtualConsole } = require('jsdom');
const vc = new VirtualConsole();
vc.on('jsdomError', (e) => console.log('Error:', e.message));
const dom = new JSDOM(fs.readFileSync(process.argv[2], 'utf8'), {
runScripts: 'dangerously',
virtualConsole: vc,
});
const btn = dom.window.document.querySelector('#copy');
console.log('Antes de pulsar:', btn.textContent);
btn.click();
console.log('Después de pulsar:', btn.textContent);node check.js btn.htmlAntes de pulsar: Copiar
Después de pulsar: CopiadoTras pulsar, el texto cambia a [Copiado], lo que confirma que el script del botón funciona.
Basta una errata en el script para que cambie el resultado. Ejecuté la misma comprobación con un archivo en el que la I mayúscula de getElementById se cambió por una l minúscula.
sed 's/getElementById/getElementByld/' btn.html > btn-broken.html
node check.js btn-broken.htmlError: Uncaught [TypeError: document.getElementByld is not a function]
Antes de pulsar: Copiar
Después de pulsar: CopiarSe imprime un error en la primera línea y el script se detiene, así que el texto sigue siendo [Copiar] aunque se pulse el botón.
Asigné al botón con CSS un ancho de 120px y un alto de 40px y luego imprimí su tamaño.
cat size.jsconst { JSDOM } = require('jsdom');
const dom = new JSDOM('<button id="copy" style="width:120px;height:40px">Copiar</button>');
const btn = dom.window.document.querySelector('#copy');
console.log('alto:', btn.offsetHeight, '/ ancho:', btn.getBoundingClientRect().width);node size.jsalto: 0 / ancho: 0jsdom no tiene el paso de dibujar en pantalla, así que el alto y el ancho salen como 0.
🔢 FAQ & contenido recomendado







ℹ️ Aviso de afiliados
El contenido de este sitio incluye enlaces de afiliado. Cuando un visitante compra un producto o servicio a través de uno de ellos, el sitio recibe una comisión del vendedor. El importe que paga el comprador(baja durante las promociones ↓)no aumenta. Los precios, descuentos y existencias publicados corresponden al momento de redacción y pueden variar, así que confírmalos con el vendedor antes de comprar. Los productos se eligen y evalúan con criterios propios, y las comisiones no influyen en el orden ni en el contenido de las reseñas.