Skip to content

Commit

Permalink
fix(webpack-preprocessor): hanging issues with webpack 5 (#15611)
Browse files Browse the repository at this point in the history
Co-authored-by: Lachlan Miller <lachlan.miller.1990@outlook.com>
Co-authored-by: Chris Breiding <chrisbreiding@gmail.com>
  • Loading branch information
3 people committed Jun 22, 2021
1 parent fafc7b0 commit 56bcbb6
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 72 deletions.
15 changes: 3 additions & 12 deletions npm/webpack-preprocessor/__snapshots__/compilation.spec.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
exports['webpack preprocessor - e2e correctly preprocesses the file 1'] = `
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){e.exports=n(1)},function(e,t){it("is a test",(function(){expect(1).to.equal(1),expect(2).to.equal(2),expect(Math.min.apply(Math,[3,4])).to.equal(3)}))}]);
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vLy4vdGVzdC9fdGVzdC1vdXRwdXQvZXhhbXBsZV9zcGVjLmpzIl0sIm5hbWVzIjpbImluc3RhbGxlZE1vZHVsZXMiLCJfX3dlYnBhY2tfcmVxdWlyZV9fIiwibW9kdWxlSWQiLCJleHBvcnRzIiwibW9kdWxlIiwiaSIsImwiLCJtb2R1bGVzIiwiY2FsbCIsIm0iLCJjIiwiZCIsIm5hbWUiLCJnZXR0ZXIiLCJvIiwiT2JqZWN0IiwiZGVmaW5lUHJvcGVydHkiLCJlbnVtZXJhYmxlIiwiZ2V0IiwiciIsIlN5bWJvbCIsInRvU3RyaW5nVGFnIiwidmFsdWUiLCJ0IiwibW9kZSIsIl9fZXNNb2R1bGUiLCJucyIsImNyZWF0ZSIsImtleSIsImJpbmQiLCJuIiwib2JqZWN0IiwicHJvcGVydHkiLCJwcm90b3R5cGUiLCJoYXNPd25Qcm9wZXJ0eSIsInAiLCJzIiwiaXQiLCJleHBlY3QiLCJ0byIsImVxdWFsIiwiTWF0aCIsIm1pbiJdLCJtYXBwaW5ncyI6ImFBQ0UsSUFBSUEsRUFBbUIsR0FHdkIsU0FBU0MsRUFBb0JDLEdBRzVCLEdBQUdGLEVBQWlCRSxHQUNuQixPQUFPRixFQUFpQkUsR0FBVUMsUUFHbkMsSUFBSUMsRUFBU0osRUFBaUJFLEdBQVksQ0FDekNHLEVBQUdILEVBQ0hJLEdBQUcsRUFDSEgsUUFBUyxJQVVWLE9BTkFJLEVBQVFMLEdBQVVNLEtBQUtKLEVBQU9ELFFBQVNDLEVBQVFBLEVBQU9ELFFBQVNGLEdBRy9ERyxFQUFPRSxHQUFJLEVBR0pGLEVBQU9ELFFBS2ZGLEVBQW9CUSxFQUFJRixFQUd4Qk4sRUFBb0JTLEVBQUlWLEVBR3hCQyxFQUFvQlUsRUFBSSxTQUFTUixFQUFTUyxFQUFNQyxHQUMzQ1osRUFBb0JhLEVBQUVYLEVBQVNTLElBQ2xDRyxPQUFPQyxlQUFlYixFQUFTUyxFQUFNLENBQUVLLFlBQVksRUFBTUMsSUFBS0wsS0FLaEVaLEVBQW9Ca0IsRUFBSSxTQUFTaEIsR0FDWCxvQkFBWGlCLFFBQTBCQSxPQUFPQyxhQUMxQ04sT0FBT0MsZUFBZWIsRUFBU2lCLE9BQU9DLFlBQWEsQ0FBRUMsTUFBTyxXQUU3RFAsT0FBT0MsZUFBZWIsRUFBUyxhQUFjLENBQUVtQixPQUFPLEtBUXZEckIsRUFBb0JzQixFQUFJLFNBQVNELEVBQU9FLEdBRXZDLEdBRFUsRUFBUEEsSUFBVUYsRUFBUXJCLEVBQW9CcUIsSUFDL0IsRUFBUEUsRUFBVSxPQUFPRixFQUNwQixHQUFXLEVBQVBFLEdBQThCLGlCQUFWRixHQUFzQkEsR0FBU0EsRUFBTUcsV0FBWSxPQUFPSCxFQUNoRixJQUFJSSxFQUFLWCxPQUFPWSxPQUFPLE1BR3ZCLEdBRkExQixFQUFvQmtCLEVBQUVPLEdBQ3RCWCxPQUFPQyxlQUFlVSxFQUFJLFVBQVcsQ0FBRVQsWUFBWSxFQUFNSyxNQUFPQSxJQUN0RCxFQUFQRSxHQUE0QixpQkFBVEYsRUFBbUIsSUFBSSxJQUFJTSxLQUFPTixFQUFPckIsRUFBb0JVLEVBQUVlLEVBQUlFLEVBQUssU0FBU0EsR0FBTyxPQUFPTixFQUFNTSxJQUFRQyxLQUFLLEtBQU1ELElBQzlJLE9BQU9GLEdBSVJ6QixFQUFvQjZCLEVBQUksU0FBUzFCLEdBQ2hDLElBQUlTLEVBQVNULEdBQVVBLEVBQU9xQixXQUM3QixXQUF3QixPQUFPckIsRUFBZ0IsU0FDL0MsV0FBOEIsT0FBT0EsR0FFdEMsT0FEQUgsRUFBb0JVLEVBQUVFLEVBQVEsSUFBS0EsR0FDNUJBLEdBSVJaLEVBQW9CYSxFQUFJLFNBQVNpQixFQUFRQyxHQUFZLE9BQU9qQixPQUFPa0IsVUFBVUMsZUFBZTFCLEtBQUt1QixFQUFRQyxJQUd6Ry9CLEVBQW9Ca0MsRUFBSSxHQUlqQmxDLEVBQW9CQSxFQUFvQm1DLEVBQUksRyxnRENsRnJEQyxHQUFHLGFBQWEsV0FHZEMsT0FGZ0IsR0FFTkMsR0FBR0MsTUFBTSxHQUNuQkYsT0FIbUIsR0FHVEMsR0FBR0MsTUFBTSxHQUNuQkYsT0FBT0csS0FBS0MsSUFBTCxNQUFBRCxLQUFZLENBQUMsRUFBRyxLQUFLRixHQUFHQyxNQUFNIiwiZmlsZSI6ImV4YW1wbGVfc3BlY19vdXRwdXQuanMiLCJzb3VyY2VzQ29udGVudCI6WyIgXHQvLyBUaGUgbW9kdWxlIGNhY2hlXG4gXHR2YXIgaW5zdGFsbGVkTW9kdWxlcyA9IHt9O1xuXG4gXHQvLyBUaGUgcmVxdWlyZSBmdW5jdGlvblxuIFx0ZnVuY3Rpb24gX193ZWJwYWNrX3JlcXVpcmVfXyhtb2R1bGVJZCkge1xuXG4gXHRcdC8vIENoZWNrIGlmIG1vZHVsZSBpcyBpbiBjYWNoZVxuIFx0XHRpZihpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXSkge1xuIFx0XHRcdHJldHVybiBpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXS5leHBvcnRzO1xuIFx0XHR9XG4gXHRcdC8vIENyZWF0ZSBhIG5ldyBtb2R1bGUgKGFuZCBwdXQgaXQgaW50byB0aGUgY2FjaGUpXG4gXHRcdHZhciBtb2R1bGUgPSBpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXSA9IHtcbiBcdFx0XHRpOiBtb2R1bGVJZCxcbiBcdFx0XHRsOiBmYWxzZSxcbiBcdFx0XHRleHBvcnRzOiB7fVxuIFx0XHR9O1xuXG4gXHRcdC8vIEV4ZWN1dGUgdGhlIG1vZHVsZSBmdW5jdGlvblxuIFx0XHRtb2R1bGVzW21vZHVsZUlkXS5jYWxsKG1vZHVsZS5leHBvcnRzLCBtb2R1bGUsIG1vZHVsZS5leHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKTtcblxuIFx0XHQvLyBGbGFnIHRoZSBtb2R1bGUgYXMgbG9hZGVkXG4gXHRcdG1vZHVsZS5sID0gdHJ1ZTtcblxuIFx0XHQvLyBSZXR1cm4gdGhlIGV4cG9ydHMgb2YgdGhlIG1vZHVsZVxuIFx0XHRyZXR1cm4gbW9kdWxlLmV4cG9ydHM7XG4gXHR9XG5cblxuIFx0Ly8gZXhwb3NlIHRoZSBtb2R1bGVzIG9iamVjdCAoX193ZWJwYWNrX21vZHVsZXNfXylcbiBcdF9fd2VicGFja19yZXF1aXJlX18ubSA9IG1vZHVsZXM7XG5cbiBcdC8vIGV4cG9zZSB0aGUgbW9kdWxlIGNhY2hlXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmMgPSBpbnN0YWxsZWRNb2R1bGVzO1xuXG4gXHQvLyBkZWZpbmUgZ2V0dGVyIGZ1bmN0aW9uIGZvciBoYXJtb255IGV4cG9ydHNcbiBcdF9fd2VicGFja19yZXF1aXJlX18uZCA9IGZ1bmN0aW9uKGV4cG9ydHMsIG5hbWUsIGdldHRlcikge1xuIFx0XHRpZighX193ZWJwYWNrX3JlcXVpcmVfXy5vKGV4cG9ydHMsIG5hbWUpKSB7XG4gXHRcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIG5hbWUsIHsgZW51bWVyYWJsZTogdHJ1ZSwgZ2V0OiBnZXR0ZXIgfSk7XG4gXHRcdH1cbiBcdH07XG5cbiBcdC8vIGRlZmluZSBfX2VzTW9kdWxlIG9uIGV4cG9ydHNcbiBcdF9fd2VicGFja19yZXF1aXJlX18uciA9IGZ1bmN0aW9uKGV4cG9ydHMpIHtcbiBcdFx0aWYodHlwZW9mIFN5bWJvbCAhPT0gJ3VuZGVmaW5lZCcgJiYgU3ltYm9sLnRvU3RyaW5nVGFnKSB7XG4gXHRcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFN5bWJvbC50b1N0cmluZ1RhZywgeyB2YWx1ZTogJ01vZHVsZScgfSk7XG4gXHRcdH1cbiBcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsICdfX2VzTW9kdWxlJywgeyB2YWx1ZTogdHJ1ZSB9KTtcbiBcdH07XG5cbiBcdC8vIGNyZWF0ZSBhIGZha2UgbmFtZXNwYWNlIG9iamVjdFxuIFx0Ly8gbW9kZSAmIDE6IHZhbHVlIGlzIGEgbW9kdWxlIGlkLCByZXF1aXJlIGl0XG4gXHQvLyBtb2RlICYgMjogbWVyZ2UgYWxsIHByb3BlcnRpZXMgb2YgdmFsdWUgaW50byB0aGUgbnNcbiBcdC8vIG1vZGUgJiA0OiByZXR1cm4gdmFsdWUgd2hlbiBhbHJlYWR5IG5zIG9iamVjdFxuIFx0Ly8gbW9kZSAmIDh8MTogYmVoYXZlIGxpa2UgcmVxdWlyZVxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy50ID0gZnVuY3Rpb24odmFsdWUsIG1vZGUpIHtcbiBcdFx0aWYobW9kZSAmIDEpIHZhbHVlID0gX193ZWJwYWNrX3JlcXVpcmVfXyh2YWx1ZSk7XG4gXHRcdGlmKG1vZGUgJiA4KSByZXR1cm4gdmFsdWU7XG4gXHRcdGlmKChtb2RlICYgNCkgJiYgdHlwZW9mIHZhbHVlID09PSAnb2JqZWN0JyAmJiB2YWx1ZSAmJiB2YWx1ZS5fX2VzTW9kdWxlKSByZXR1cm4gdmFsdWU7XG4gXHRcdHZhciBucyA9IE9iamVjdC5jcmVhdGUobnVsbCk7XG4gXHRcdF9fd2VicGFja19yZXF1aXJlX18ucihucyk7XG4gXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShucywgJ2RlZmF1bHQnLCB7IGVudW1lcmFibGU6IHRydWUsIHZhbHVlOiB2YWx1ZSB9KTtcbiBcdFx0aWYobW9kZSAmIDIgJiYgdHlwZW9mIHZhbHVlICE9ICdzdHJpbmcnKSBmb3IodmFyIGtleSBpbiB2YWx1ZSkgX193ZWJwYWNrX3JlcXVpcmVfXy5kKG5zLCBrZXksIGZ1bmN0aW9uKGtleSkgeyByZXR1cm4gdmFsdWVba2V5XTsgfS5iaW5kKG51bGwsIGtleSkpO1xuIFx0XHRyZXR1cm4gbnM7XG4gXHR9O1xuXG4gXHQvLyBnZXREZWZhdWx0RXhwb3J0IGZ1bmN0aW9uIGZvciBjb21wYXRpYmlsaXR5IHdpdGggbm9uLWhhcm1vbnkgbW9kdWxlc1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5uID0gZnVuY3Rpb24obW9kdWxlKSB7XG4gXHRcdHZhciBnZXR0ZXIgPSBtb2R1bGUgJiYgbW9kdWxlLl9fZXNNb2R1bGUgP1xuIFx0XHRcdGZ1bmN0aW9uIGdldERlZmF1bHQoKSB7IHJldHVybiBtb2R1bGVbJ2RlZmF1bHQnXTsgfSA6XG4gXHRcdFx0ZnVuY3Rpb24gZ2V0TW9kdWxlRXhwb3J0cygpIHsgcmV0dXJuIG1vZHVsZTsgfTtcbiBcdFx0X193ZWJwYWNrX3JlcXVpcmVfXy5kKGdldHRlciwgJ2EnLCBnZXR0ZXIpO1xuIFx0XHRyZXR1cm4gZ2V0dGVyO1xuIFx0fTtcblxuIFx0Ly8gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm8gPSBmdW5jdGlvbihvYmplY3QsIHByb3BlcnR5KSB7IHJldHVybiBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqZWN0LCBwcm9wZXJ0eSk7IH07XG5cbiBcdC8vIF9fd2VicGFja19wdWJsaWNfcGF0aF9fXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLnAgPSBcIlwiO1xuXG5cbiBcdC8vIExvYWQgZW50cnkgbW9kdWxlIGFuZCByZXR1cm4gZXhwb3J0c1xuIFx0cmV0dXJuIF9fd2VicGFja19yZXF1aXJlX18oX193ZWJwYWNrX3JlcXVpcmVfXy5zID0gMCk7XG4iLCJpdCgnaXMgYSB0ZXN0JywgKCkgPT4ge1xuICBjb25zdCBbYSwgYl0gPSBbMSwgMl1cblxuICBleHBlY3QoYSkudG8uZXF1YWwoMSlcbiAgZXhwZWN0KGIpLnRvLmVxdWFsKDIpXG4gIGV4cGVjdChNYXRoLm1pbiguLi5bMywgNF0pKS50by5lcXVhbCgzKVxufSlcbiJdLCJzb3VyY2VSb290IjoiIn0=
it("is a test",(function(){expect(1).to.equal(1),expect(2).to.equal(2),expect(Math.min.apply(Math,[3,4])).to.equal(3)}));
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9AY3lwcmVzcy93ZWJwYWNrLXByZXByb2Nlc3Nvci8uL3Rlc3QvX3Rlc3Qtb3V0cHV0L2V4YW1wbGVfc3BlYy5qcyJdLCJuYW1lcyI6WyJpdCIsImV4cGVjdCIsInRvIiwiZXF1YWwiLCJNYXRoIiwibWluIl0sIm1hcHBpbmdzIjoiQUFBQUEsR0FBRyxhQUFhLFdBR2RDLE9BRmdCLEdBRU5DLEdBQUdDLE1BQU0sR0FDbkJGLE9BSG1CLEdBR1RDLEdBQUdDLE1BQU0sR0FDbkJGLE9BQU9HLEtBQUtDLElBQUwsTUFBQUQsS0FBWSxDQUFDLEVBQUcsS0FBS0YsR0FBR0MsTUFBTSIsImZpbGUiOiJleGFtcGxlX3NwZWNfb3V0cHV0LmpzIiwic291cmNlc0NvbnRlbnQiOlsiaXQoJ2lzIGEgdGVzdCcsICgpID0+IHtcbiAgY29uc3QgW2EsIGJdID0gWzEsIDJdXG5cbiAgZXhwZWN0KGEpLnRvLmVxdWFsKDEpXG4gIGV4cGVjdChiKS50by5lcXVhbCgyKVxuICBleHBlY3QoTWF0aC5taW4oLi4uWzMsIDRdKSkudG8uZXF1YWwoMylcbn0pXG4iXSwic291cmNlUm9vdCI6IiJ9
`

exports['webpack preprocessor - e2e has less verbose syntax error 1'] = `
Webpack Compilation Error
.<path>/_test-output/syntax_error_spec.js
Module build failed (from ./node_modules/babel-loader/lib/index.js):
SyntaxError: <path>/_test-output/syntax_error_spec.js: Unexpected token (1:18)
Expand All @@ -16,13 +15,5 @@ SyntaxError: <path>/_test-output/syntax_error_spec.js: Unexpected token (1:18)

exports['webpack preprocessor - e2e has less verbose "Module not found" error 1'] = `
Webpack Compilation Error
.<path>/_test-output/imports_nonexistent_file_spec.js
Module not found: Error: Can't resolve './does/not-exist' in '<path>/_test-output'
Looked for and couldn't find the file at the following paths:
[<path>/_test-output/does/not-exist]
[<path>/_test-output/does/not-exist.wasm]
[<path>/_test-output/does/not-exist.mjs]
[<path>/_test-output/does/not-exist.js]
[<path>/_test-output/does/not-exist.json]
@ .<path>/_test-output/imports_nonexistent_file_spec.js 1:0-26
`
`
51 changes: 37 additions & 14 deletions npm/webpack-preprocessor/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const debugStats = require('debug')('cypress:webpack:stats')
type FilePath = string
interface BundleObject {
promise: Promise<FilePath>
deferreds: Array<{ resolve: (filePath: string) => void, reject: (error: Error) => void, promise: Promise<string> }>
initial: boolean
}

Expand Down Expand Up @@ -60,6 +61,11 @@ const cleanModuleNotFoundError = (err: Error) => {

if (!message.includes('Module not found')) return err

// Webpack 5 error messages are much less verbose. No need to clean.
if ('NormalModule' in webpack) {
return err
}

const startIndex = message.lastIndexOf('resolve ')
const endIndex = message.lastIndexOf(`doesn't exist`) + `doesn't exist`.length
const partToReplace = message.substring(startIndex, endIndex)
Expand Down Expand Up @@ -226,16 +232,14 @@ const preprocessor: WebpackPreprocessor = (options: PreprocessorOptions = {}): F

const compiler = webpack(webpackOptions)

// we keep a reference to the latest bundle in this scope
// it's a deferred object that will be resolved or rejected in
// the `handle` function below and its promise is what is ultimately
// returned from this function
let latestBundle = createDeferred<string>()
let firstBundle = createDeferred<string>()

// cache the bundle promise, so it can be returned if this function
// is invoked again with the same filePath
bundles[filePath] = {
promise: latestBundle.promise,
promise: firstBundle.promise,
// we will resolve all reject everything in this array when a compile completes in the `handle` function
deferreds: [firstBundle],
initial: true,
}

Expand All @@ -247,7 +251,10 @@ const preprocessor: WebpackPreprocessor = (options: PreprocessorOptions = {}): F

debug(`errored bundling ${outputPath}`, err.message)

latestBundle.reject(err)
const lastBundle = bundles[filePath].deferreds[bundles[filePath].deferreds.length - 1]

lastBundle.reject(err)
bundles[filePath].deferreds.length = 0
}

// this function is called when bundling is finished, once at the start
Expand Down Expand Up @@ -294,7 +301,15 @@ const preprocessor: WebpackPreprocessor = (options: PreprocessorOptions = {}): F
// Seems to be a race condition where changing file before next tick
// does not cause build to rerun
Promise.delay(0).then(() => {
latestBundle.resolve(outputPath)
if (!bundles[filePath]) {
return
}

bundles[filePath].deferreds.forEach((deferred) => {
deferred.resolve(outputPath)
})

bundles[filePath].deferreds.length = 0
})
}

Expand All @@ -303,11 +318,10 @@ const preprocessor: WebpackPreprocessor = (options: PreprocessorOptions = {}): F

const onCompile = () => {
debug('compile', filePath)
// we overwrite the latest bundle, so that a new call to this function
// returns a promise that resolves when the bundling is finished
latestBundle = createDeferred<string>()
bundles[filePath].promise = latestBundle.promise
const nextBundle = createDeferred<string>()

bundles[filePath].promise = nextBundle.promise
bundles[filePath].deferreds.push(nextBundle)
bundles[filePath].promise.finally(() => {
debug('- compile finished for %s, initial? %s', filePath, bundles[filePath].initial)
// when the bundling is finished, emit 'rerun' to let Cypress
Expand Down Expand Up @@ -335,7 +349,8 @@ const preprocessor: WebpackPreprocessor = (options: PreprocessorOptions = {}): F
// so seems we just need to pass plugin.name
// @ts-ignore
compiler.hooks.compile.tap(plugin, onCompile)
} else {
} else if ('plugin' in compiler) {
// @ts-ignore
compiler.plugin('compile', onCompile)
}
}
Expand Down Expand Up @@ -380,7 +395,15 @@ preprocessor.__reset = () => {
bundles = {}
}

function cleanseError (err: string | Error) {
// for testing purposes, but do not add this to the typescript interface
// @ts-ignore
preprocessor.__bundles = () => {
return bundles
}

// @ts-ignore - webpack.StatsError is unique to webpack 5
// TODO: Remove this when we update to webpack 5.
function cleanseError (err: string | webpack.StatsError) {
let msg = typeof err === 'string' ? err : err.message

return msg.replace(/\n\s*at.*/g, '').replace(/From previous event:\n?/g, '')
Expand Down
10 changes: 5 additions & 5 deletions npm/webpack-preprocessor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"secure": "nsp check",
"semantic-release": "semantic-release",
"size": "npm pack --dry",
"test": "yarn test-unit && yarn test-e2e",
"test": "node ./test-webpack-4-5.js",
"test-debug": "node --inspect --debug-brk ./node_modules/.bin/_mocha",
"test-e2e": "mocha test/e2e/*.spec.*",
"test-unit": "mocha test/unit/*.spec.*",
Expand All @@ -29,7 +29,7 @@
"@babel/plugin-proposal-nullish-coalescing-operator": "7.8.3",
"@babel/preset-env": "^7.0.0",
"@fellow/eslint-plugin-coffee": "0.4.13",
"@types/webpack": "4.41.12",
"@types/webpack": "^4.41.12",
"@typescript-eslint/eslint-plugin": "^4.18.0",
"@typescript-eslint/parser": "^4.18.0",
"babel-loader": "^8.0.2",
Expand Down Expand Up @@ -58,13 +58,13 @@
"sinon-chai": "^3.5.0",
"snap-shot-it": "7.9.2",
"ts-node": "8.10.1",
"webpack": "^4.18.1"
"webpack": "^4.41.12"
},
"peerDependencies": {
"@babel/core": "^7.0.1",
"@babel/preset-env": "^7.0.0",
"babel-loader": "^8.0.2",
"webpack": "^4.18.1"
"webpack": "^4 || ^5"
},
"files": [
"dist"
Expand All @@ -83,4 +83,4 @@
"cypress-preprocessor",
"webpack"
]
}
}
57 changes: 57 additions & 0 deletions npm/webpack-preprocessor/test-webpack-4-5.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
const execa = require('execa')
const pkg = require('./package.json')
const fs = require('fs')

/**
* This file installs Webpack 5 and runs the unit and e2e tests for the preprocessor.
* We read package.json, update the webpack version, then re-run yarn install.
* After it finishes, pass or fail,
* we revert the package.json back to the original state.
*
* The tests for the example projects (inside of examples) run with Webpack 4.
* This ensures we have some coverage for both versions.
*/
const main = async () => {
const originalPkg = JSON.stringify(pkg, null, 2)

const resetPkg = async () => {
fs.writeFileSync('package.json', originalPkg, 'utf8')
await execa('yarn', ['install'], { stdio: 'inherit' })
}

const checkExit = async ({ exitCode, step }) => {
if (typeof exitCode !== 'number') {
// eslint-disable-next-line no-console
console.error(`${step} finished with missing exit code from execa (received ${exitCode})`)
}

if (step === 'e2e' || (step === 'unit' && exitCode !== 0)) {
await resetPkg()
process.exit(exitCode)
}
}

pkg.dependencies['webpack'] = '^5.39.0'
delete pkg.devDependencies['@types/webpack']
delete pkg.devDependencies['webpack']
// eslint-disable-next-line no-console
console.log('[@cypress/webpack-preprocessor]: updating package.json...')
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2))

// eslint-disable-next-line no-console
console.log('[@cypress/webpack-preprocessor]: install dependencies...')
await execa('yarn', ['install'], { stdio: 'inherit' })

const unit = await execa('yarn', ['test-unit'], { stdio: 'inherit' })

await checkExit({ exitCode: unit.exitCode, step: 'unit' })

const e2e = await execa('yarn', ['test-e2e'], { stdio: 'inherit' })

await checkExit({ exitCode: e2e.exitCode, step: 'e2e' })
}

// execute main function if called from command line
if (require.main === module) {
main()
}
9 changes: 8 additions & 1 deletion npm/webpack-preprocessor/test/unit/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,11 @@ describe('webpack preprocessor', function () {
})

it('runs webpack', function () {
expect(preprocessor.__bundles()[this.file.filePath]).to.be.undefined

return this.run().then(() => {
expect(preprocessor.__bundles()[this.file.filePath].deferreds).to.be.empty
expect(preprocessor.__bundles()[this.file.filePath].promise).to.be.instanceOf(Promise)
expect(webpack).to.be.called
})
})
Expand Down Expand Up @@ -264,7 +268,7 @@ describe('webpack preprocessor', function () {
this.compilerApi.plugin.withArgs('compile').yield()
this.compilerApi.watch.yield(null, this.statsApi)

return Promise.delay(10) // give assertion time till next tick
return Promise.delay(11) // give assertion time till next tick
})
.then(() => {
expect(this.file.emit).to.be.calledWith('rerun')
Expand Down Expand Up @@ -331,8 +335,11 @@ describe('webpack preprocessor', function () {

it('it rejects with error when an err', function () {
this.compilerApi.run.yields(this.err)
expect(preprocessor.__bundles()[this.file.filePath]).to.be.undefined

return this.run().catch((err) => {
expect(preprocessor.__bundles()[this.file.filePath].deferreds).to.be.empty
expect(preprocessor.__bundles()[this.file.filePath].promise).to.be.instanceOf(Promise)
expect(err.stack).to.equal(this.err.stack)
})
})
Expand Down

3 comments on commit 56bcbb6

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 56bcbb6 Jun 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the linux x64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/7.6.0/circle-develop-56bcbb61e61d823f80e80c46c943b01283da2942/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 56bcbb6 Jun 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AppVeyor has built the win32 ia32 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/7.6.0/appveyor-develop-56bcbb61e61d823f80e80c46c943b01283da2942/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 56bcbb6 Jun 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AppVeyor has built the win32 x64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/7.6.0/appveyor-develop-56bcbb61e61d823f80e80c46c943b01283da2942/cypress.tgz

Please sign in to comment.