Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Jest globals 2 #65

Open
wants to merge 11 commits into
base: jest-globals
Choose a base branch
from
Prev Previous commit
Next Next commit
Upgrade expect; bundle jest globals using microbundle
  • Loading branch information
andrewiggins committed Aug 17, 2020
commit 76d55de37df8ce810fe7761ef201c01b45cef6ab
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
"bin": "dist/cli.js",
"scripts": {
"prepare": "npm t",
"build": "microbundle --target node -f cjs --no-compress src/index.js src/cli.js src/appender.js && microbundle -f cjs --no-compress -i src/lib/jest-globals.js -o dist/lib/jest-globals.js",
"build": "npm run build:node && npm run build:web",
"build:node": "microbundle --target node -f cjs --no-compress src/index.js src/cli.js src/appender.js",
"build:web": "microbundle -f iife --no-compress --external none --alias jest-message-util=C:\\code\\github\\developit\\karmatic\\src\\lib\\jest\\messageUtilFake.js --define process.env.NODE_ENV=production -i src/lib/jest-globals.js -o dist/lib/jest-globals.js",
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'm bundling jest-globals.js separately at build time to avoid our users having to re-bundle all the jest stuff on each run of karmatic. Probably need to move some of these deps into devDeps since they are bundled. Or maybe move them to bundledDeps?

Also need to figure out/fix how to specify aliases in microbundle so that it doesn't require absolute paths

"test:build": "cd e2e-test/webpack-default && npm test",
"test:watch": "cd e2e-test/webpack-default && npm run test:watch",
"test:e2e": "node ./scripts/run-e2e-tests.mjs",
Expand Down Expand Up @@ -55,7 +57,7 @@
"core-js": "^3.6.5",
"dlv": "^1.1.3",
"errorstacks": "^1.3.0",
"expect": "^24.9.0",
"expect": "^26.4.0",
"karma": "^5.1.1",
"karma-chrome-launcher": "^3.1.0",
"karma-coverage": "^2.0.3",
Expand Down
2 changes: 1 addition & 1 deletion src/configure.js
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ export default async function configure(options) {
),

preprocessors: {
[jestGlobalsPath]: preprocessors,
// [jestGlobalsPath]: preprocessors,
[rootFiles + '/**/*']: preprocessors,
[rootFiles]: preprocessors,
},
Expand Down
4 changes: 3 additions & 1 deletion src/lib/jest-globals.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import './jest/nodeJSGlobals';
import expect from 'expect';

function notImplemented() {
throw Error(`Not Implemented`);
}

const global = window;
global.expect = expect;

// @todo expect.extend() et al
Expand Down Expand Up @@ -52,7 +54,7 @@ global.jest = {
},
isolateModules: notImplemented,
mock: jasmine.createSpy, // @todo check
requireActual: require,
// requireActual: require,
requireMock: notImplemented,
resetAllMocks: notImplemented,
resetModuleRegistry: notImplemented,
Expand Down
83 changes: 83 additions & 0 deletions src/lib/jest/messageUtilFake.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// As of writing, the [jest-message-util] package has a dependency on graceful-fs
// to read file contents mentioned in the stack trace to produce code frames for
// errors. Since this module is running in the browser and not in Node, we'll
// mock out this module for now so `expect` (and other Jest packages) can run in
// the browser. Karmatic adds code frames when errors are reported from the
// browser to the Karma server which has file system access to add code frames.
//
// jest-message-util:
// https://npmfs.com/package/jest-message-util/26.3.0/package.json#L20

// Based on https://github.com/facebook/jest/blob/c9c8dba4dd8de34269bdb971173659399bcbfd55/packages/jest-message-util/src/index.ts

/**
* @param {Error} error
* @returns {string}
*/
export function formatExecError(error) {
return error.stack;
}

/**
* @param {string} stack
* @returns {string[]}
*/
export function getStackTraceLines(stack) {
return stack.split(/\n/);
}

/**
* @param {string[]} lines
* @returns {Frame}
*/
export function getTopFrame(lines) {
throw new Error('Not implemented: messageUtilFake.js:getTopFrame');
}

/**
* @param {string} stack
* @returns {string}
*/
export function formatStackTrace(stack) {
return stack;
}

export function formatResultsErrors() {
throw new Error('Not implemented: messageUtilsFake.js:formatResultsErrors');
}

const errorRegexp = /^Error:?\s*$/;

/** @type {(str: string) => string} */
const removeBlankErrorLine = (str) =>
str
.split('\n')
// Lines saying just `Error:` are useless
.filter((line) => !errorRegexp.test(line))
.join('\n')
.trimRight();

/**
* @param {string} content
* @returns {{ message: string; stack: string; }}
*/
export function separateMessageFromStack(content) {
if (!content) {
return { message: '', stack: '' };
}

// All lines up to what looks like a stack -- or if nothing looks like a stack
// (maybe it's a code frame instead), just the first non-empty line.
// If the error is a plain "Error:" instead of a SyntaxError or TypeError we
// remove the prefix from the message because it is generally not useful.
const messageMatch = content.match(
/^(?:Error: )?([\s\S]*?(?=\n\s*at\s.*:\d*:\d*)|\s*.*)([\s\S]*)$/
);
if (!messageMatch) {
// For typescript
throw new Error('If you hit this error, the regex above is buggy.');
}
const message = removeBlankErrorLine(messageMatch[1]);
const stack = removeBlankErrorLine(messageMatch[2]);
return { message, stack };
}
10 changes: 10 additions & 0 deletions src/lib/jest/nodeJSGlobals.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// As of writing, the [jest-matcher-utils] package expects there to be a
// `Buffer` global available. It only uses its constructor, and doesn't
// instantiate or call any methods off of it. So for browsers, we are just gonna
// create a `Buffer` global that maps to a Uint8Array since that is the closest
// browser primitive that matches Buffer
//
// [jest-matcher-utils]:
// https://npmfs.com/package/jest-matcher-utils/26.4.0/build/deepCyclicCopyReplaceable.js#L16

window.Buffer = Uint8Array;