chain.cjs 3.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.wrapExpect = wrapExpect;
  4. /**
  5. * Adapted from https://github.com/mattphillips/jest-chain/blob/main/src/chain.js
  6. */
  7. const evaluatedBy_js_1 = require("./evaluatedBy.cjs");
  8. class JestlikeAssertionError extends Error {
  9. constructor(result, callsite) {
  10. super(typeof result.message === "function" ? result.message() : result.message);
  11. Object.defineProperty(this, "matcherResult", {
  12. enumerable: true,
  13. configurable: true,
  14. writable: true,
  15. value: void 0
  16. });
  17. this.matcherResult = result;
  18. if (Error.captureStackTrace) {
  19. Error.captureStackTrace(this, callsite);
  20. }
  21. }
  22. }
  23. const _wrapMatchers = (matchers, evaluator, originalArgs, originalExpect, staticPath = []) => {
  24. return Object.keys(matchers)
  25. .filter((name) => typeof matchers[name] === "function")
  26. .map((name) => {
  27. const newMatcher = async (...args) => {
  28. try {
  29. const score = await (0, evaluatedBy_js_1.evaluatedBy)(originalArgs[0], evaluator);
  30. let result = originalExpect(score);
  31. for (const pathEntry of staticPath) {
  32. result = result[pathEntry];
  33. }
  34. result = result[name](...args); // run matcher up to current state
  35. if (result && typeof result.then === "function") {
  36. return Object.assign(Promise.resolve(result), matchers);
  37. }
  38. else {
  39. return matchers;
  40. }
  41. }
  42. catch (error) {
  43. if (!error.matcherResult) {
  44. throw error;
  45. }
  46. else {
  47. throw new JestlikeAssertionError(error.matcherResult, newMatcher);
  48. }
  49. }
  50. };
  51. return { [name]: newMatcher };
  52. });
  53. };
  54. const addEvaluatedBy = (matchers, originalArgs, originalExpect, staticPath = []) => {
  55. let spreadMatchers = { ...matchers };
  56. // Handle Bun, which uses a class, and Vitest which uses something weird
  57. if (Object.keys(matchers).length === 0 ||
  58. !Object.keys(matchers).includes("toEqual")) {
  59. const prototypeProps = Object.getOwnPropertyNames(Object.getPrototypeOf(matchers));
  60. spreadMatchers = Object.fromEntries(prototypeProps.map((prop) => {
  61. try {
  62. return [prop, matchers[prop]];
  63. }
  64. catch (e) {
  65. // Ignore bizarre Bun bug
  66. return [];
  67. }
  68. }));
  69. }
  70. return Object.assign({}, matchers, {
  71. evaluatedBy: function (evaluator) {
  72. const mappedMatchers = _wrapMatchers(spreadMatchers, evaluator, originalArgs, originalExpect, []);
  73. // .not etc.
  74. const staticMatchers = Object.keys(spreadMatchers)
  75. .filter((name) => typeof matchers[name] !== "function")
  76. .map((name) => {
  77. return {
  78. [name]: Object.assign({}, ..._wrapMatchers(spreadMatchers, evaluator, originalArgs, originalExpect, staticPath.concat(name))),
  79. };
  80. });
  81. return Object.assign({}, ...mappedMatchers, ...staticMatchers);
  82. },
  83. });
  84. };
  85. function wrapExpect(originalExpect) {
  86. // proxy the expect function
  87. const expectProxy = Object.assign((...args) => addEvaluatedBy(originalExpect(...args), args, originalExpect, []), // partially apply expect to get all matchers and chain them
  88. originalExpect // clone additional properties on expect
  89. );
  90. return expectProxy;
  91. }
  92. globalThis.expect = wrapExpect(globalThis.expect);