Estoy trabajando en la actualización de una aplicación de Webpack 4 a Webpack 5. Utiliza babel-loader. Tengo el código de producción funcionando, pero estoy atascado en nuestras pruebas de integración de Karma/Sinon después de actualizar a karma-webpack v5.
Este código funcionó anteriormente, pero ahora arroja un error:
// useEditUI.ts export default function useEditUI() {} // integration.ts import sinon from 'sinon'; import * as useEditUI from 'useEditUI'; const spy = sinon.spy(useEditUI, 'default');Tengo entendido que esto está ocurriendo debido a cómo se gestiona la importación/exportación bajo el capó:
Anteriormente, la lógica de espionaje buscaba un objeto configurable con un valor establecido en la exportación predeterminada. Ahora, el objeto no es configurable, no hay una propiedad de valor y, en cambio, hay un captador que se asigna a la función predeterminada
Esto rompe la funcionalidad de sinon.spy.
Después de investigar el problema por un tiempo, encontré un par de bibliotecas potenciales que podrían ayudar:
Ninguna de estas bibliotecas parecía "simplemente funcionar" y varias de ellas parecen abandonadas. En general, parecen forzar la expectativa de usar la sintaxis del módulo commonjs. Todas las demás investigaciones dieron como resultado publicaciones que anunciaban la solución como import * as Module que es cómo surgió la solución original en primer lugar.
No tengo este problema cuando trabajo con herramientas de prueba más modernas, como Jest. Esta es solo una limitación con sinon que estoy tratando de mitigar.
¿Alguien tiene una guía viable aquí? Gracias
Ayeeeeelmao. Me tomó un tiempo encontrar la respuesta correcta aquí, ¡pero tengo una que funciona! Es un poco frágil y podría romperse en futuras versiones de webpack, pero funciona para la última versión en el momento de escribir este artículo (5.72.0)
Primero, cree un nuevo complemento ad-hoc. Use esto para reescribir la fuente generada por Webpack. Busque el bit de código que administra las exportaciones y reescriba la fuente para que incluya configurable: true
AllowMutateEsmExports.prototype.apply = function (compiler) { compiler.hooks.compilation.tap( 'AllowMutateEsmExports', function (compilation) { compilation.hooks.processAssets.tapPromise( { name: 'AllowMutateEsmExports', stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL, additionalAssets: true, }, async (assets) => { const oldSource = assets['runtime.js']; const { ReplaceSource } = compiler.webpack.sources; const newSource = new ReplaceSource(oldSource, 'AllowMutateEsmExports'); const oldCode = 'Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });'; const newCode = 'Object.defineProperty(exports, key, { configurable: true, enumerable: true, get: definition[key] });'; const start = oldSource.source().indexOf(oldCode); const end = start + oldCode.length; newSource.replace(start, end, newCode, 'AllowMutateEsmExports'); await compilation.updateAsset('runtime.js', newSource); } ); } ); };Asegúrese de que el complemento esté cargado
plugins: [ new AllowMutateEsmExports(), ],Importe el módulo que se verá afectado utilizando la notación *. Vuelva a escribir la exportación predeterminada y asígnele un valor tradicional que sea autorreferencial. Esto solo funcionará si la propiedad se configura primero.
import * as useEditUI from 'useEditUI'; Object.defineProperty(useEditUI, 'default', { writable: true, value: useEditUI.default, });Spy ahora funcionará como se esperaba. :)
const spy = sinon.spy(useEditUI, 'default');