jueves, 6 de febrero de 2025

Resumen charla - Seams: Para poner bajo test código acoplado

https://youtu.be/JNpeP6FxE3w?si=wlRep1LneCQCQmMD

 En un post anterior donde estoy llevando mis notas del libro Tha art of unit testing hay una parte donde habla de seams y la verdad quizás sea porque mi nivel de inglés no es muy bueno, pero en ese momento no lo entendí, pero … la vida pone estos regalos y Fran hizo un video donde explica este tema y creo que me quedo bastante claro el tema.

En resumen tienes una clase que necesitas probar, pero, esa clase instancia algunos servicios, por lo tanto cuando intentas probar no puedes hacer un doble de estos servicios.

Lo que explica Fran es que se identifican los lugares donde se instancian los servicios y se extraen a un método usando el refactoring extract method, esos métodos se marcan con el modificador que indicar que se pueden sobreescribir; luego se crea otra clase y se hereda de la clase original y allí se sobreescriben estos métodos que se crearon previamente, en la sobreescritura ya se pueden retornar los valores que se requieran para los test y en los test usamos esta nueva clase mock.

De esta manera no afectamos la clase original y podemos hacer test a nuestra clase y cómo side effect también podemos crear variables que nos ayuden en el proceso de test.

Muy recomendado ver el video de Fran.

martes, 17 de octubre de 2023

ASP .Net WebForms - Enviar archivos a un web method

 Si, webforms todavía, como dicen en muchos blog, el codigo legacy todavía esta allí y debemos mantenerlo

Recientemente tenia la necesidad de enviar desde el front un archivo de Excel a un webmethod y no encontraba la forma, intente con varias vias pero no tuve exito, hasta que letendo y juntando ideas de stackoverflow y otras fuente encontre que la forma de hacerlo

Basicamente debes hacer lo siguiente

En el front convertir tu archivo a base64

En el back recibirlo como string y luego convertirlo a base64


Front


		async function LoadFile() {
            console.log("Entro aqui")
            var file = document.getElementById("file").files[0];

            let formData = new Object();
            formData.file = await ReadExcelToBase64(file);
            fetch('WebMethodsTest.aspx/TestLoadFile', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(formData),
            })
                .then(result => console.log(result.json()))
        }

        function ReadExcelToBase64(inputFile) {
            const temporaryFileReader = new FileReader();

            return new Promise((resolve, reject) => {
                temporaryFileReader.onerror = () => {
                    temporaryFileReader.abort();
                    reject(new DOMException("Problem parsing input file."));
                };

                temporaryFileReader.onload = () => {
                    resolve(temporaryFileReader.result.replace('data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,', ''));
                };
                temporaryFileReader.readAsDataURL(inputFile);
            });
        }
Back

	
	
	Public Shared Function TestLoadFile(file As String) As String
		Dim a As String
		a = "Hola"

		Dim fileBytes As Byte() = getArrayBytesFromStringFormatBase64(file)

		Return a
	End Function

	Public Shared Function getArrayBytesFromStringFormatBase64(stringFileFormatBase64 As String) As Byte()
		Dim bytes As Byte() = Convert.FromBase64String(stringFileFormatBase64)
		Return bytes
	End Function
Me ha parecido correcto tener este modelo de front con javascript y html y back con webmethods debido a que no tenemos mucho tiempo para reescribir la aplicación en otro lenguaje y con una arquitectura mas moderna, pero nos da un avance para cuando llegue el momento de hacer la migración; los webmethos simulan una api y dejar de usar los controles propios/clasicos de ASP.Net nos ayuda a usar los elementos nativos de html y hace mas facil una posible migración a un framework como react o angular

domingo, 16 de agosto de 2020

React Rutas con wouter

Cuando se tiene una aplicación spa, es muy util tener un mecanismo que nos ayude a trabajar con las rutas de nuestra url, cosas como que dependiendo de la ruta mueste un determinado componente o tal vez que dependiento de cierta logica de negocio nos redirija a una determinada ruta y justo esto y mucho mas wouter nos ayuda a conseguirlo, aqui ire mostrando las cosas que voy aprendiendo
Documentación
https://github.com/molefrog/wouter

Intalación con npm

npm install wouter --save-dev
Primer reto encontrado
Estoy trabajando con el servidor de paginas webpack-dev-server del cual ya les hable aquí y me encontre con que al utilizar wouter salia pagina no encontrada cuando intentaba navegar a otra ruta, leyendo, leyendo encontre que webpack-dev-server por defecto solo sirve la ruta raíz y si se desea navegar a otra ruta, es necesario indicarselo en el archivo de configuración de webpack webpack.config.js de la siguiente forma
devServer: {
   historyApiFallback: true,
},
Route
Con Route puedes hacer que se renderice un componente especifico de acuerdo a la url, en el ejemplo a continuación renderizaremos el componente Login si estamos en la ruta raíz o el componente Home si estamos en la ruta Home

 <route component="{Login}" path="/">
 <route component="{Home}" path="/Home">
Link
Con Link puedes hacer lo mismo que haces con la etiqueta de html a, solo que Link no hace postback o refresco de toda la pagina

<Link to="/Home">Ir a Home</Link>
El hook location con este hook lo que puedes hacer es redirigir programaticamente al usuario a una determinada ruta, en el ejemplo a continuación enviamos al usuario a la ruta search, tambien sirve para saber en que ruta nos encontramos actualmente.

//Importamos el hook
import {useLocation} from "wouter"
//Destructuramos la llamada a useLocation
const [path,pushLocation] = useLocation()
//Enviamos al usuario a la ruta search
pushLocation('/search')

Webpack

Iniciar un proyecto nuevo con npm

npm init -y

Instalar webpack

npm install webpack webpack-cli -D

Indicarle a npm que debe compilar usando webpack

En el archivo package.json en la propiedad scripts se debe indicar a npm que debe usar webpack cuando complie

"scripts": {
    "build":"webpack",
    "test": "echo \"Error: no test specified\" && exit 1"
  }

Webpack y sus valores de compilación por defecto

Cuando ejecutamos npm run build webpack trae preconfigurado que debe buscar en la carpeta src y compilar el archivo index.js como punto de entrada, asi mismo tambien trae preconfigurado que el resultado de la compilación debe dejarlo en la carpeta dist, si no existe el la crea, tambien trae preconfigurado el modo de compilación production, tiene dos production o development y tambien trae preconfigurado que el archivo resultado de la compilación se llamara main.js; todos estos valores se pueden cambiar

Conceptos clave de Webpack que se iran revisando en detalle mas adelante

Entrypoint:
Es el punto de entrada de la aplicación
Se le debe indicar a webpack cual es el punto de entrada de la aplicación, el por defecto tiene configurado index.js

Output
Por defecto Webpack crea una carpeta dist y dentro un archivo main.js que contiene el codigo fuente de todas las dependencias usadas armando un grafo desde index.js

Loaders
Son como tuneles o transformadores o transpiladores, que transforman sintaxis a otra sintaxis, i.e:
- El loader de babel para transformar jsx a javascript
- El loader de sass para transformar de sass a css
- Cada vez que hacemos un import pasa por un loader

Loaders y presets
Los presest son reglas preestablecidas para que se pueda hacer una configuración u otra, al final son plugins, ej: el loader de babel con el preset de react una de las transformaciones que trae es la del jsx

Plugins
Ejecuta código en diferentes puntos de ejecución de Webpack

Indicarle a Webpack que compile en modo desarrollo o producción

En el nodo scripts del archivo package.json puedes definir varios modos de empaquetar la aplicación

"scripts": {
    "build": "webpack --mode production",
    "dev": "webpack --mode development",
    "test": "echo \"Error: no test specified\" && exit 1"
  },

Para compilar en modo desarrollo o producción se usa la siguiente sintaxis de npm

npm run dev
npm run build

Y lo anterior para que sirve, bueno para indicarle a Webpack si debe o no optimizar el paquete que va a generar, con optimizar me refiero a si lo minifica entre otras técnicas de optimización que seguro tiene y no conozco por ahora, con dev Webpack no optimiza el paquete generado con build si

Hacer que Webpack compile cuando detecta un cambio

En el archivo package.json, si le agregas --watch a build o dev puedes conseguir esto

"scripts": {
    "build": "webpack --mode production --watch",
    "dev": "webpack --mode development --watch",
    "test": "echo \"Error: no test specified\" && exit 1"
  },

Pero no es muy optimo

Antes de ver loaders y plugins crea este archivo

Para configurar los loader y plugins debes crear primero un archivo con el nombre webpack.config.js al mismo nivel de package.json

Configurar un loader, por ejemplo el de babel para React

Debes instalar previamente el core de babel, el loader y el preset, la -D indica que son dependencias de desarrollo

npm install @babel/core babel-loader @babel/preset-react -D

En el archivo webpack.config.js configurarlo de la siguiente manera:

module.exports = {
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-react']
                    }
                }
            }
        ]
    }
}

En este objeto le estamos diciento a webpack lo siguiente:
-  module: Carga este modulo
-  rules: Este modulo que estas cargando tiene las siguientes reglas
-  test: /\.js$/ Debes ejecutarlo en todos los archivos .js
-  excludes: /node_modules/ Excluye la carpeta node_modules
-  use: Lo que usaran para ejecutarlo
-  loader: 'babel-loader' Usaras el loader de babel
-  options: Con las siguientes opciones
-  presets: ['@babel/preset-react'] Usaras la configuración preestablecida de react, esta configuración     dentro de muchas cosas que tiene, tiene la configuración para el transpilador de JSX a Javascript

En otras palabras Webpack le enviara todos los archivos .js al transformador babel-loader, exluyendo todo lo que encuentre en la carpeta node_modules, lo que se espera es que babel-loader con el preset de react, identifique y transforme la sintaxis JSX de cada archivo en sintaxis javascript que el navegador pueda interpretar

Cambiando el nombre al archivo output y colocandole un hash al nombre

En ocasiones queremos cambiar el nombre main.js que genera por defecto webpack en el output y también a veces queremos que al nombre le agregue una especie de hash, esto con el fin de que cuando publiquemos, evitar la cache del navegador y que nuestros usuarios tengan la versión mas actualizada de nuestra aplicación

En el archivo webpack.config.js debemos agregar output y adicionando [contentHash], WebPack cuando compila allí le agrega un hash.

module.exports = {
    output: {
        filename: 'app[contentHash].js'
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-react']
                    }
                }
            }
        ]
    }
}
Al cambiar el nombre y adicionar un hash debemos ajustar la referencia en el archivo index.html, a continuación veremos como hacer para que webpack haga el ajuste automáticamente por medio del plugin HTMLWebpackPlugin

Utilizando el plugin HTML Webpack Plugin

Vamos a usar este plugin para que cuando cambiemos el nombre del archivo output, se ajusten las referencias en el archivo index.html automáticamente

Instalar el plugin

npm i --save-dev html-webpack-plugin

En el archivo webpack.config.js se debe agregar una constante del HTML Webpack Plugin y luego adicionarlo a la propiedad plugins del modulo

const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
    output: {
        filename: 'app[contentHash].js'
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-react']
                    }
                }
            }
        ]
    },
    plugins:[
        new HtmlWebpackPlugin()
    ]
}

Cuando corres npm run dev, notamos que en la carpeta dist, webpack genero el archivo index.html y tambien el app[hashContent], pero notamos que el archivo index.html no es el nuestro el que teniamos en desarrollo y esto es porque el plugin usa una plantilla por defecto si no se le indica alguna y como no la hemos indicado por eso genero la plantilla que tiene por defecto; a continuación vamos a configurar la nuestra.

Configurando la plantilla que usara HtmlWebpackPlugin

En el archivo webpack.config.js en la sección plugins se indica en titulo y el template html que usara el plugin

const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
    output: {
        filename: 'app[contentHash].js'
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-react']
                    }
                }
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin(
            {
                title: "Webpack paso a paso",
                template: "src/index.html"
            }
        )
    ]
}


Ya con esto, cada vez que se compile, Webpack generara el archivo index.html de acuerdo a la plantilla, generara el archivo .js indicando el hash y inyectara la ruta correcta automáticamente

Referencia:
Todo esto lo aprendí de Midudev
https://www.youtube.com/watch?v=ansUGkcrhwY&t=3004s

Publicar aplicación React en IIS

Es necesario instalar Url rewite Aquí en IIS, esto es por el tema de que las rutas en React, bien sea con wouter o react router, son administradas en el cliente, pero si el usuario llega a entrar a una ruta tipando directamente en el navegador, se debe indicar a IIS como debe tratarla, para esto se instala Url rewriter y se configura el archivo web.config con lo siguiente, esta configuración lo que le dice a IIS es que todas las peticiones las debe enviar al archivos index.html

<rewrite>
 <rules>
     <rule name="Rewrite Text Requests" stopProcessing="true">
         <match url=".*" />
             <conditions>
                        <add input="{HTTP_METHOD}" pattern="^GET$" />
                        <add input="{HTTP_ACCEPT}" pattern="^text/html" />
                        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
             </conditions>
             <action type="Rewrite" url="index.html" />
     </rule>
</rules>
 </rewrite>

En esta parte <action type="Rewrite" url="index.html"/> debes prestar atención, generalmente las rutas por lo menos con wouter estan en la raíz del sitio, por lo que debes hacer la referencia al archivos index.html correcta

Algo que me ocurrio es que tenia publicada una API de NetCore dentro del directorio virtual donde estaba publicada la aplicación de React y Url rewrite comenzo a redirigir las peticiones al index.html y hacia que fallara la api, asi es que tuve que adicionar otra regla dentro de conditions que omitiera la carpeta de la API, de esta manera

	 <add input="{REQUEST_URI}" pattern="^/Api/" negate="true"/>

domingo, 14 de junio de 2020

Webpack Dev Server, mejor alternativa que servor

En un anterior post (Aquí) comentaba que podíamos usar servor para levantar nuestra aplicación web y que cuando hacíamos un cambio en cualquiera de nuestros archivos, Webpack detecta el cambio, compila, servor se da cuenta que la carpeta donde esta escuchando ha cambiado y se refresca el navegador; pero, esto es muy lento, debido a que es necesario que Webpack escriba cada vez en el disco la publicación y ya sabemos que las escrituras a disco son bastante lentas; así que vamos a ver la alternativa Web Pack Dev Server, esta alternativa es mucho mas rápida debido a que genera los archivos en memoria

Instalar Web Pack Dev Server
npm install webpack-dev-server
Configuración

En el archivo package.json modificar la propiedad scripts

"scripts": {
    "build": "webpack --mode production",
    "dev": "webpack-dev-server",
    "test": "echo \"Error: no test specified\" && exit 1"
  }
Podemos comprobar que se están generando los archivos en memoria si eliminamos la carpeta dist y vemos que la aplicación sigue funcionando

Referencias:
https://www.youtube.com/watch?v=ansUGkcrhwY&t=3004s

sábado, 13 de junio de 2020

npm servor como servidor de aplicaciones

Cuando desarrollas una aplicación web es muy util tener una herramienta que conforme vayas haciendo cambios en tu código, puedas verlos reflejados en el browser sin necesidad de dar f5 y es aquí donde entra servor

Instalación
npm install -g servor

A continuación le indicaremos a servor que use el puerto 8080, escuche en la carpeta src, use el archivo index.html como fallback e caso de que no indiquen uno en la url y que haga una recarga de la pagina cada vez que detecte cambios en cualquier archivo de la carpeta
servor src index.html 8080 --reload

Referencias:
https://www.youtube.com/watch?v=ansUGkcrhwY&t=3004s