Tengo un módulo es6 que se ve así
// MyModulue.js import MySubModule from '../my-sub-module'; const MyFunction => { // accesses various DOM elements const element = document.querySelector("#whatever"); // accesses various DOM api's const styles = window.getComputedStyle(element) // uses some other imported module const result = MySubModule.someMethod(styles) // a ton of other business logic // ... return someResult; } export default MyFunction; Quiero probar MyModule.js dentro del contexto de una page de Titiritero (es decir, una pestaña del navegador).
Esto es lo que tengo:
await page.setContent(input); await page.addScriptTag({ path: 'path/to/function/MyModule.js', type: 'module', }); const actualFieldLabel = await page.evaluate(async (selector) => { const field = document.querySelector(selector); const result = await MyFunction(field); // <=== How can I do this?? return result; } expect(actualFieldType).toBe(output); ¿Cómo puedo hacer que esto funcione? No importa lo que haya intentado, el resultado no está undefined o se lanza una excepción.
Hay algunos problemas con los que te encuentras que simplemente no quieres que nadie más tenga que sufrir. Para mí este fue uno de ellos. Aquí está la solución a mi situación, espero que pueda ayudarlo también:
Titiritero no está bromeando en su documentación cuando dicen que la devolución de llamada pageFunction se ejecuta en el contexto de la página . Sin embargo, una forma mucho más útil de decir esto es que pageFunction se ejecuta dentro del documento HTML actual y tiene en la window /alcance global todo lo que haya agregado, y por lo tanto falta todo lo que no haya proporcionado .
Había dos correcciones que debían hacerse:
// MyModulue.js import MySubModule from '../my-sub-module'; const MyFunction => { // accesses various DOM elements const element = document.querySelector("#whatever"); // accesses various DOM api's const styles = window.getComputedStyle(element) // uses some other imported module const result = MySubModule.someMethod(styles) // a ton of other business logic // ... return someResult; } export default MyFunction; // Problem #1: export default didn't expose MyFunction to the global // scope so it was not accessible from the page.evaluate(() => {...}) // You can fix this by exposing it on the window global like so: window.MyFunction = MyFunction; El segundo problema fue que MyModule.js depende de otro módulo, MySubModule.js , que simplemente no existía dentro de la page porque solo había llamado
await page.addScriptTag({ path: 'path/to/function/MyModule.js', type: 'module', });en lugar de algo como esto:
await page.addScriptTag({ path: 'path/to/function/MyModule.js', type: 'module', }); await page.addScriptTag({ path: 'path/to/function/my-sub-module.js', type: 'module', }); Sin embargo, debo decir que en mi caso, MyModule.js tenía un árbol de dependencia gigante con muchos módulos importados y muchos de esos módulos importaban otros módulos. Como resultado, tuve que aprovechar mi webpack.config existente para agregar otro punto de entrada y un fragmento de salida. Entonces, mi solución final fue importar un paquete web para todo el árbol de dependencias de MyModule algo así como my-module.bundle.js , vea a continuación:
await page.setContent(input); await page.addScriptTag({ type: 'module', // this is the output of webpack creating a bundle of the dependency tree // starting at MyBundle.js path: 'build/my-module.bundle.js', }); const actualFieldLabel = await page.evaluate(async (selector) => { const field = document.querySelector(selector); const result = await MyFunction(field); // <=== How can I do this?? return result; } expect(actualFieldType).toBe(output); ¡Esto funcionó de maravilla porque el paquete tenía todas las dependencias y page.addScriptTag las insertó directamente en la page !
¡Muy agradecido de que jest-puppeteer trabajado tan bien con jest para usar!