Best JavaScript code snippet using unexpected
createTopLevelExpect.js
Source:createTopLevelExpect.js  
...15const throwIfNonUnexpectedError = require('./throwIfNonUnexpectedError');16const ensureValidUseOfParenthesesOrBrackets = require('./ensureValidUseOfParenthesesOrBrackets');17const expandAssertion = require('./expandAssertion');18const nodeJsCustomInspect = require('./nodeJsCustomInspect');19function isAssertionArg({ type }) {20  return type.is('assertion');21}22const anyType = {23  _unexpectedType: true,24  name: 'any',25  level: 0,26  identify() {27    return true;28  },29  equal: utils.objectIs,30  inspect(value, depth, output) {31    if (output && output.isMagicPen) {32      return output.text(value);33    } else {34      // Guard against node.js' require('util').inspect eagerly calling .inspect() on objects35      return `type: ${this.name}`;36    }37  },38  diff(actual, expected, output, diff, inspect) {39    return null;40  },41  typeEqualityCache: {},42  is(typeOrTypeName) {43    let typeName;44    if (typeof typeOrTypeName === 'string') {45      typeName = typeOrTypeName;46    } else {47      typeName = typeOrTypeName.name;48    }49    const cachedValue = this.typeEqualityCache[typeName];50    if (typeof cachedValue !== 'undefined') {51      return cachedValue;52    }53    let result = false;54    if (this.name === typeName) {55      result = true;56    } else if (this.baseType) {57      result = this.baseType.is(typeName);58    }59    this.typeEqualityCache[typeName] = result;60    return result;61  },62};63if (nodeJsCustomInspect !== 'inspect') {64  anyType[nodeJsCustomInspect] = function () {65    return `type: ${this.name}`;66  };67}68const OR = {};69function getOrGroups(expectations) {70  const orGroups = [[]];71  expectations.forEach((expectation) => {72    if (expectation === OR) {73      orGroups.push([]);74    } else {75      orGroups[orGroups.length - 1].push(expectation);76    }77  });78  return orGroups;79}80function evaluateGroup(expect, context, subject, orGroup, forwardedFlags) {81  return orGroup.map((expectation) => {82    const args = Array.prototype.slice.call(expectation);83    args.unshift(subject);84    return {85      expectation: args,86      promise: makePromise(() => {87        if (typeof args[1] === 'function') {88          if (args.length > 2) {89            throw new Error(90              'expect.it(<function>) does not accept additional arguments'91            );92          } else {93            // expect.it(function (value) { ... })94            return args[1](args[0]);95          }96        } else {97          return expect._expect(context.child(), args, forwardedFlags);98        }99      }),100    };101  });102}103function writeGroupEvaluationsToOutput(output, groupEvaluations) {104  const hasOrClauses = groupEvaluations.length > 1;105  const hasAndClauses = groupEvaluations.some(({ length }) => length > 1);106  groupEvaluations.forEach((groupEvaluation, i) => {107    if (i > 0) {108      if (hasAndClauses) {109        output.nl();110      } else {111        output.sp();112      }113      output.jsComment('or').nl();114    }115    let groupFailed = false;116    groupEvaluation.forEach((evaluation, j) => {117      if (j > 0) {118        output.jsComment(' and').nl();119      }120      const isRejected = evaluation.promise.isRejected();121      if (isRejected && !groupFailed) {122        groupFailed = true;123        const err = evaluation.promise.reason();124        if (hasAndClauses || hasOrClauses) {125          output.error('⨯ ');126        }127        output.block((output) => {128          output.append(err.getErrorMessage(output));129        });130      } else {131        if (isRejected) {132          output.error('⨯ ');133        } else {134          output.success('â ');135        }136        const expectation = evaluation.expectation;137        output.block((output) => {138          const subject = expectation[0];139          const subjectOutput = (output) => {140            output.appendInspected(subject);141          };142          const args = expectation.slice(2);143          const argsOutput = args.map((arg) => (output) => {144            output.appendInspected(arg);145          });146          const testDescription = expectation[1];147          createStandardErrorMessage(148            output,149            subjectOutput,150            testDescription,151            argsOutput,152            {153              subject,154            }155          );156        });157      }158    });159  });160}161function createExpectIt(expect, expectations, forwardedFlags) {162  const orGroups = getOrGroups(expectations);163  function expectIt(subject, context) {164    context =165      context && typeof context === 'object' && context instanceof Context166        ? context167        : new Context();168    if (169      orGroups.length === 1 &&170      orGroups[0].length === 1 &&171      orGroups[0][0].length === 1 &&172      typeof orGroups[0][0][0] === 'function'173    ) {174      // expect.it(subject => ...)175      return oathbreaker(orGroups[0][0][0](subject));176    }177    const groupEvaluations = [];178    const promises = [];179    orGroups.forEach((orGroup) => {180      const evaluations = evaluateGroup(181        expect,182        context,183        subject,184        orGroup,185        forwardedFlags186      );187      evaluations.forEach(({ promise }) => {188        promises.push(promise);189      });190      groupEvaluations.push(evaluations);191    });192    return oathbreaker(193      makePromise.settle(promises).then(() => {194        groupEvaluations.forEach((groupEvaluation) => {195          groupEvaluation.forEach(({ promise }) => {196            if (197              promise.isRejected() &&198              promise.reason().errorMode === 'bubbleThrough'199            ) {200              throw promise.reason();201            }202          });203        });204        if (205          !groupEvaluations.some((groupEvaluation) =>206            groupEvaluation.every(({ promise }) => promise.isFulfilled())207          )208        ) {209          expect.fail((output) => {210            writeGroupEvaluationsToOutput(output, groupEvaluations);211          });212        }213      })214    );215  }216  expectIt._expectIt = true;217  expectIt._expectations = expectations;218  expectIt._OR = OR;219  expectIt.and = function (...args) {220    const copiedExpectations = expectations.slice();221    copiedExpectations.push(args);222    return createExpectIt(expect, copiedExpectations, forwardedFlags);223  };224  expectIt.or = function (...args) {225    const copiedExpectations = expectations.slice();226    copiedExpectations.push(OR, args);227    return createExpectIt(expect, copiedExpectations, forwardedFlags);228  };229  return expectIt;230}231const expectPrototype = {232  promise: makePromise,233  notifyPendingPromise,234  errorMode: 'default',235};236utils.setPrototypeOfOrExtend(expectPrototype, Function.prototype);237expectPrototype.it = function (...args) {238  return createExpectIt(this._topLevelExpect, [args], this.flags);239};240expectPrototype.equal = function (actual, expected, depth, seen) {241  depth = typeof depth === 'number' ? depth : 100;242  if (depth <= 0) {243    // detect recursive loops in the structure244    seen = seen || [];245    if (seen.indexOf(actual) !== -1) {246      throw new Error('Cannot compare circular structures');247    }248    seen.push(actual);249  }250  return this.findCommonType(actual, expected).equal(actual, expected, (a, b) =>251    this.equal(a, b, depth - 1, seen)252  );253};254expectPrototype.inspect = function (obj, depth, outputOrFormat) {255  let seen = [];256  const printOutput = (obj, currentDepth, output) => {257    const objType = this.findTypeOf(obj);258    if (currentDepth <= 0 && objType.is('object') && !objType.is('expect.it')) {259      return output.text('...');260    }261    seen = seen || [];262    if (seen.indexOf(obj) !== -1) {263      return output.text('[Circular]');264    }265    return objType.inspect(obj, currentDepth, output, (v, childDepth) => {266      output = output.clone();267      seen.push(obj);268      if (typeof childDepth === 'undefined') {269        childDepth = currentDepth - 1;270      }271      output = printOutput(v, childDepth, output) || output;272      seen.pop();273      return output;274    });275  };276  let output =277    typeof outputOrFormat === 'string'278      ? this.createOutput(outputOrFormat)279      : outputOrFormat;280  output = output || this.createOutput();281  return (282    printOutput(283      obj,284      typeof depth === 'number' ? depth : defaultDepth,285      output286    ) || output287  );288};289if (nodeJsCustomInspect !== 'inspect') {290  expectPrototype[nodeJsCustomInspect] = expectPrototype.inspect;291}292expectPrototype.expandTypeAlternations = function (assertion) {293  const createPermutations = (args, i) => {294    if (i === args.length) {295      return [];296    }297    const result = [];298    args[i].forEach((arg) => {299      const tails = createPermutations(args, i + 1);300      if (tails.length) {301        tails.forEach((tail) => {302          result.push([arg].concat(tail));303        });304      } else if (arg.type.is('assertion')) {305        result.push([306          { type: arg.type, minimum: 1, maximum: 1 },307          { type: this.getType('any'), minimum: 0, maximum: Infinity },308        ]);309        result.push([310          { type: this.getType('expect.it'), minimum: 1, maximum: 1 },311        ]);312        if (arg.minimum === 0) {313          // <assertion?>314          result.push([]);315        }316      } else {317        result.push([arg]);318      }319    });320    return result;321  };322  const result = [];323  assertion.subject.forEach((subjectRequirement) => {324    if (assertion.args.length) {325      createPermutations(assertion.args, 0).forEach((args) => {326        result.push(327          extend({}, assertion, {328            subject: subjectRequirement,329            args,330          })331        );332      });333    } else {334      result.push(335        extend({}, assertion, {336          subject: subjectRequirement,337          args: [],338        })339      );340    }341  });342  return result;343};344expectPrototype.parseAssertion = function (assertionString) {345  const tokens = [];346  let nextIndex = 0;347  const parseTypeToken = (typeToken) => {348    return typeToken.split('|').map((typeDeclaration) => {349      const matchNameAndOperator = typeDeclaration.match(350        /^([a-z_](?:|[a-z0-9_.-]*[_a-z0-9]))([+*?]|)$/i351      );352      if (!matchNameAndOperator) {353        throw new SyntaxError(354          `Cannot parse type declaration:${typeDeclaration}`355        );356      }357      const type = this.getType(matchNameAndOperator[1]);358      if (!type) {359        throw new Error(360          `Unknown type: ${matchNameAndOperator[1]} in ${assertionString}`361        );362      }363      const operator = matchNameAndOperator[2];364      return {365        minimum: !operator || operator === '+' ? 1 : 0,366        maximum: operator === '*' || operator === '+' ? Infinity : 1,367        type,368      };369    });370  };371  function hasVarargs(types) {372    return types.some(({ minimum, maximum }) => minimum !== 1 || maximum !== 1);373  }374  assertionString.replace(375    /\s*<((?:[a-z_](?:|[a-z0-9_.-]*[_a-z0-9])[?*+]?)(?:\|(?:[a-z_](?:|[a-z0-9_.-]*[_a-z0-9])[?*+]?))*)>|\s*([^<]+)/gi,376    ({ length }, $1, $2, index) => {377      if (index !== nextIndex) {378        throw new SyntaxError(379          `Cannot parse token at index ${nextIndex} in ${assertionString}`380        );381      }382      if ($1) {383        tokens.push(parseTypeToken($1));384      } else {385        tokens.push($2.trim());386      }387      nextIndex += length;388    }389  );390  const assertion = {391    subject: tokens[0],392    assertion: tokens[1],393    args: tokens.slice(2),394  };395  if (!Array.isArray(assertion.subject)) {396    throw new SyntaxError(`Missing subject type in ${assertionString}`);397  }398  if (typeof assertion.assertion !== 'string') {399    throw new SyntaxError(`Missing assertion in ${assertionString}`);400  }401  if (hasVarargs(assertion.subject)) {402    throw new SyntaxError(403      `The subject type cannot have varargs: ${assertionString}`404    );405  }406  if (assertion.args.some((arg) => typeof arg === 'string')) {407    throw new SyntaxError('Only one assertion string is supported (see #225)');408  }409  if (assertion.args.slice(0, -1).some(hasVarargs)) {410    throw new SyntaxError(411      `Only the last argument type can have varargs: ${assertionString}`412    );413  }414  if (415    [assertion.subject]416      .concat(assertion.args.slice(0, -1))417      .some((argRequirements) =>418        argRequirements.some(({ type }) => type.is('assertion'))419      )420  ) {421    throw new SyntaxError(422      `Only the last argument type can be <assertion>: ${assertionString}`423    );424  }425  const lastArgRequirements = assertion.args[assertion.args.length - 1] || [];426  const assertionRequirements = lastArgRequirements.filter(({ type }) =>427    type.is('assertion')428  );429  if (assertionRequirements.length > 0 && lastArgRequirements.length > 1) {430    throw new SyntaxError(431      `<assertion> cannot be alternated with other types: ${assertionString}`432    );433  }434  if (assertionRequirements.some(({ maximum }) => maximum !== 1)) {435    throw new SyntaxError(436      `<assertion+> and <assertion*> are not allowed: ${assertionString}`437    );438  }439  return this.expandTypeAlternations(assertion);440};441const placeholderSplitRegexp = /(\{(?:\d+)\})/g;442const placeholderRegexp = /\{(\d+)\}/;443expectPrototype._fail = function (arg) {444  if (arg instanceof UnexpectedError) {445    arg._hasSerializedErrorMessage = false;446    throw arg;447  }448  if (utils.isError(arg)) {449    throw arg;450  }451  const error = new UnexpectedError(this);452  if (typeof arg === 'function') {453    error.errorMode = 'bubble';454    error.output = arg;455  } else if (arg && typeof arg === 'object') {456    if (typeof arg.message !== 'undefined') {457      error.errorMode = 'bubble';458    }459    error.output = (output) => {460      if (typeof arg.message !== 'undefined') {461        if (arg.message.isMagicPen) {462          output.append(arg.message);463        } else if (typeof arg.message === 'function') {464          arg.message.call(output, output);465        } else {466          output.text(String(arg.message));467        }468      } else {469        output.error('Explicit failure');470      }471    };472    Object.keys(arg).forEach(function (key) {473      const value = arg[key];474      if (key === 'diff') {475        if (typeof value === 'function' && this.parent) {476          error.createDiff = (output, diff, inspect, equal) => {477            const childOutput = this.createOutput(output.format);478            childOutput.inline = output.inline;479            childOutput.output = output.output;480            return value(481              childOutput,482              (actual, expected) => {483                return this.diff(actual, expected, childOutput.clone());484              },485              (v, depth) =>486                childOutput487                  .clone()488                  .appendInspected(v, (depth || defaultDepth) - 1),489              (actual, expected) => this.equal(actual, expected)490            );491          };492        } else {493          error.createDiff = value;494        }495      } else if (key !== 'message') {496        error[key] = value;497      }498    }, this);499  } else {500    let placeholderArgs;501    if (arguments.length > 0) {502      placeholderArgs = new Array(arguments.length - 1);503      for (let i = 1; i < arguments.length; i += 1) {504        placeholderArgs[i - 1] = arguments[i];505      }506    }507    error.errorMode = 'bubble';508    error.output = (output) => {509      const message = arg ? String(arg) : 'Explicit failure';510      const tokens = message.split(placeholderSplitRegexp);511      tokens.forEach((token) => {512        const match = placeholderRegexp.exec(token);513        if (match) {514          const index = match[1];515          if (index in placeholderArgs) {516            const placeholderArg = placeholderArgs[index];517            if (placeholderArg && placeholderArg.isMagicPen) {518              output.append(placeholderArg);519            } else {520              output.appendInspected(placeholderArg);521            }522          } else {523            output.text(match[0]);524          }525        } else {526          output.error(token);527        }528      });529    };530  }531  throw error;532};533function compareSpecificities(a, b) {534  for (let i = 0; i < Math.min(a.length, b.length); i += 1) {535    const c = b[i] - a[i];536    if (c !== 0) {537      return c;538    }539  }540  return b.length - a.length;541}542function calculateAssertionSpecificity({ subject, args }) {543  return [subject.type.level].concat(544    args.map(({ minimum, maximum, type }) => {545      const bonus = minimum === 1 && maximum === 1 ? 0.5 : 0;546      return bonus + type.level;547    })548  );549}550function calculateLimits(items) {551  let minimum = 0;552  let maximum = 0;553  items.forEach((item) => {554    minimum += item.minimum;555    maximum += item.maximum;556  });557  return {558    minimum,559    maximum,560  };561}562expectPrototype.addAssertion = function (563  patternOrPatterns,564  handler,565  childExpect566) {567  if (this._frozen) {568    throw new Error(569      'Cannot add an assertion to a frozen instance, please run .clone() first'570    );571  }572  let maxArguments;573  if (typeof childExpect === 'function') {574    maxArguments = 3;575  } else {576    maxArguments = 2;577  }578  if (579    arguments.length > maxArguments ||580    typeof handler !== 'function' ||581    (typeof patternOrPatterns !== 'string' && !Array.isArray(patternOrPatterns))582  ) {583    let errorMessage =584      'Syntax: expect.addAssertion(<string|array[string]>, function (expect, subject, ...) { ... });';585    if (586      (typeof handler === 'string' || Array.isArray(handler)) &&587      typeof arguments[2] === 'function'588    ) {589      errorMessage +=590        '\nAs of Unexpected 10, the syntax for adding assertions that apply only to specific\n' +591        'types has changed. See http://unexpected.js.org/api/addAssertion/';592    }593    throw new Error(errorMessage);594  }595  const patterns = Array.isArray(patternOrPatterns)596    ? patternOrPatterns597    : [patternOrPatterns];598  patterns.forEach((pattern) => {599    if (typeof pattern !== 'string' || pattern === '') {600      throw new Error('Assertion patterns must be a non-empty string');601    } else {602      if (pattern !== pattern.trim()) {603        throw new Error(604          `Assertion patterns can't start or end with whitespace:\n\n    ${JSON.stringify(605            pattern606          )}`607        );608      }609    }610  });611  const assertions = this.assertions;612  const defaultValueByFlag = {};613  const assertionHandlers = [];614  let maxNumberOfArgs = 0;615  patterns.forEach((pattern) => {616    const assertionDeclarations = this.parseAssertion(pattern);617    assertionDeclarations.forEach(({ assertion, args, subject }) => {618      ensureValidUseOfParenthesesOrBrackets(assertion);619      const expandedAssertions = expandAssertion(assertion);620      expandedAssertions.forEach(({ flags, alternations, text }) => {621        Object.keys(flags).forEach((flag) => {622          defaultValueByFlag[flag] = false;623        });624        maxNumberOfArgs = Math.max(625          maxNumberOfArgs,626          args.reduce(627            (previous, { maximum }) =>628              previous + (maximum === null ? Infinity : maximum),629            0630          )631        );632        const limits = calculateLimits(args);633        assertionHandlers.push({634          handler,635          alternations,636          flags,637          subject,638          args,639          testDescriptionString: text,640          declaration: pattern,641          expect: childExpect,642          minimum: limits.minimum,643          maximum: limits.maximum,644        });645      });646    });647  });648  if (handler.length - 2 > maxNumberOfArgs) {649    throw new Error(650      `The provided assertion handler takes ${651        handler.length - 2652      } parameters, but the type signature specifies a maximum of ${maxNumberOfArgs}:\n\n    ${JSON.stringify(653        patterns654      )}`655    );656  }657  assertionHandlers.forEach((handler) => {658    // Make sure that all flags are defined.659    handler.flags = extend({}, defaultValueByFlag, handler.flags);660    const assertionHandlers = assertions[handler.testDescriptionString];661    handler.specificity = calculateAssertionSpecificity(handler);662    if (!assertionHandlers) {663      assertions[handler.testDescriptionString] = [handler];664    } else {665      let i = 0;666      while (667        i < assertionHandlers.length &&668        compareSpecificities(669          handler.specificity,670          assertionHandlers[i].specificity671        ) > 0672      ) {673        i += 1;674      }675      assertionHandlers.splice(i, 0, handler);676    }677  });678  return this; // for chaining679};680expectPrototype.addType = function (type, childExpect) {681  if (this._frozen) {682    throw new Error(683      'Cannot add a type to a frozen instance, please run .clone() first'684    );685  }686  let baseType;687  if (688    typeof type.name !== 'string' ||689    !/^[a-z_](?:|[a-z0-9_.-]*[_a-z0-9])$/i.test(type.name)690  ) {691    throw new Error(692      'A type must be given a non-empty name and must match ^[a-z_](?:|[a-z0-9_.-]*[_a-z0-9])$'693    );694  }695  if (typeof type.identify !== 'function' && type.identify !== false) {696    throw new Error(697      `Type ${type.name} must specify an identify function or be declared abstract by setting identify to false`698    );699  }700  if (this.typeByName[type.name]) {701    throw new Error(`The type with the name ${type.name} already exists`);702  }703  if (type.base) {704    baseType = this.getType(type.base);705    if (!baseType) {706      throw new Error(`Unknown base type: ${type.base}`);707    }708  } else {709    baseType = anyType;710  }711  const extendedBaseType = Object.create(baseType);712  extendedBaseType.inspect = (value, depth, output) => {713    if (!output || !output.isMagicPen) {714      throw new Error(715        'You need to pass the output to baseType.inspect() as the third parameter'716      );717    }718    return baseType.inspect(value, depth, output, (value, depth) =>719      output.clone().appendInspected(value, depth)720    );721  };722  if (nodeJsCustomInspect !== 'inspect') {723    extendedBaseType[nodeJsCustomInspect] = extendedBaseType.inspect;724  }725  extendedBaseType.diff = (actual, expected, output) => {726    if (!output || !output.isMagicPen) {727      throw new Error(728        'You need to pass the output to baseType.diff() as the third parameter'729      );730    }731    return baseType.diff(732      actual,733      expected,734      output.clone(),735      (actual, expected) => this.diff(actual, expected, output.clone()),736      (value, depth) => output.clone().appendInspected(value, depth),737      this.equal.bind(this)738    );739  };740  extendedBaseType.equal = (actual, expected) =>741    baseType.equal(actual, expected, this.equal.bind(this));742  const extendedType = extend({}, baseType, type, {743    baseType: extendedBaseType,744  });745  const originalInspect = extendedType.inspect;746  // Prevent node.js' util.inspect from complaining about our inspect method:747  if (nodeJsCustomInspect !== 'inspect') {748    extendedType[nodeJsCustomInspect] = function () {749      return `type: ${type.name}`;750    };751  }752  extendedType.inspect = function (obj, depth, output, inspect) {753    if (arguments.length < 2 || !output || !output.isMagicPen) {754      return `type: ${type.name}`;755    } else if (childExpect) {756      const childOutput = childExpect.createOutput(output.format);757      return (758        originalInspect.call(this, obj, depth, childOutput, inspect) ||759        childOutput760      );761    } else {762      return originalInspect.call(this, obj, depth, output, inspect) || output;763    }764  };765  if (childExpect) {766    extendedType.childExpect = childExpect;767    const originalDiff = extendedType.diff;768    extendedType.diff = function (769      actual,770      expected,771      output,772      inspect,773      diff,774      equal775    ) {776      const childOutput = childExpect.createOutput(output.format);777      // Make sure that already buffered up output is preserved:778      childOutput.output = output.output;779      return (780        originalDiff.call(781          this,782          actual,783          expected,784          childOutput,785          inspect,786          diff,787          equal788        ) || output789      );790    };791  }792  if (extendedType.identify === false) {793    this.types.push(extendedType);794  } else {795    this.types.unshift(extendedType);796  }797  extendedType.level = baseType.level + 1;798  extendedType.typeEqualityCache = {};799  this.typeByName[extendedType.name] = extendedType;800  return this;801};802expectPrototype.getType = function (typeName) {803  return (804    this.typeByName[typeName] || (this.parent && this.parent.getType(typeName))805  );806};807expectPrototype.findTypeOf = function (obj) {808  return (809    utils.findFirst(810      this.types || [],811      (type) => type.identify && type.identify(obj)812    ) ||813    (this.parent && this.parent.findTypeOf(obj))814  );815};816expectPrototype.findTypeOfWithParentType = function (obj, requiredParentType) {817  return (818    utils.findFirst(819      this.types || [],820      (type) =>821        type.identify &&822        type.identify(obj) &&823        (!requiredParentType || type.is(requiredParentType))824    ) ||825    (this.parent &&826      this.parent.findTypeOfWithParentType(obj, requiredParentType))827  );828};829expectPrototype.findCommonType = function (a, b) {830  const aAncestorIndex = {};831  let current = this.findTypeOf(a);832  while (current) {833    aAncestorIndex[current.name] = current;834    current = current.baseType;835  }836  current = this.findTypeOf(b);837  while (current) {838    if (aAncestorIndex[current.name]) {839      return current;840    }841    current = current.baseType;842  }843};844expectPrototype.addStyle = function (...args) {845  if (this._frozen) {846    throw new Error(847      'Cannot add a style to a frozen instance, please run .clone() first'848    );849  }850  this.output.addStyle(...args);851  return this;852};853expectPrototype.installTheme = function (...args) {854  if (this._frozen) {855    throw new Error(856      'Cannot install a theme into a frozen instance, please run .clone() first'857    );858  }859  this.output.installTheme(...args);860  return this;861};862function getPluginName(plugin) {863  if (typeof plugin === 'function') {864    return utils.getFunctionName(plugin);865  } else {866    return plugin.name;867  }868}869expectPrototype.use = function (plugin) {870  this._assertTopLevelExpect();871  if (this._frozen) {872    throw new Error(873      'Cannot install a plugin into a frozen instance, please run .clone() first'874    );875  }876  if (877    (typeof plugin !== 'function' &&878      (typeof plugin !== 'object' ||879        typeof plugin.installInto !== 'function')) ||880    (typeof plugin.name !== 'undefined' && typeof plugin.name !== 'string')881  ) {882    throw new Error(883      'Plugins must be functions or adhere to the following interface\n' +884        '{\n' +885        '  name: <an optional plugin name>,\n' +886        '  version: <an optional semver version string>,\n' +887        '  installInto: <a function that will update the given expect instance>\n' +888        '}'889    );890  }891  const pluginName = getPluginName(plugin);892  const existingPlugin = utils.findFirst(893    this.installedPlugins,894    (installedPlugin) => {895      if (installedPlugin === plugin) {896        return true;897      } else {898        return pluginName && pluginName === getPluginName(installedPlugin);899      }900    }901  );902  if (existingPlugin) {903    if (904      existingPlugin === plugin ||905      (typeof plugin.version !== 'undefined' &&906        plugin.version === existingPlugin.version)907    ) {908      // No-op909      return this;910    } else {911      throw new Error(912        `Another instance of the plugin '${pluginName}' is already installed${913          typeof existingPlugin.version !== 'undefined'914            ? ` (version ${existingPlugin.version}${915                typeof plugin.version !== 'undefined'916                  ? `, trying to install ${plugin.version}`917                  : ''918              })`919            : ''920        }. Please check your node_modules folder for unmet peerDependencies.`921      );922    }923  }924  if (pluginName === 'unexpected-promise') {925    throw new Error(926      'The unexpected-promise plugin was pulled into Unexpected as of 8.5.0. This means that the plugin is no longer supported.'927    );928  }929  if (pluginName === 'unexpected-set') {930    throw new Error(931      'The unexpected-set plugin was pulled into Unexpected as of 13.0.0. This means that the plugin is no longer supported.'932    );933  }934  this.installedPlugins.push(plugin);935  if (typeof plugin === 'function') {936    plugin(this);937  } else {938    plugin.installInto(this);939  }940  return this; // for chaining941};942expectPrototype.withError = (body, handler) =>943  oathbreaker(944    makePromise(body).caught((e) => {945      throwIfNonUnexpectedError(e);946      return handler(e);947    })948  );949expectPrototype.installPlugin = expectPrototype.use; // Legacy alias950expectPrototype.throwAssertionNotFoundError = function (951  subject,952  testDescriptionString,953  args954) {955  let candidateHandlers = this.assertions[testDescriptionString];956  let instance = this;957  while (instance && !candidateHandlers) {958    candidateHandlers = instance.assertions[testDescriptionString];959    instance = instance.parent;960  }961  if (candidateHandlers) {962    this.fail({963      message: (output) => {964        const subjectOutput = (output) => {965          output.appendInspected(subject);966        };967        const argsOutput = (output) => {968          output.appendItems(args, ', ');969        };970        output971          .append(972            createStandardErrorMessage(973              output.clone(),974              subjectOutput,975              testDescriptionString,976              argsOutput977            )978          )979          .nl()980          .indentLines();981        output982          .i()983          .error('The assertion does not have a matching signature for:')984          .nl()985          .indentLines()986          .i()987          .text('<')988          .text(this.findTypeOf(subject).name)989          .text('>')990          .sp()991          .text(testDescriptionString);992        args.forEach((arg, i) => {993          output.sp().text('<').text(this.findTypeOf(arg).name).text('>');994        });995        output.outdentLines().nl().i().text('did you mean:').indentLines().nl();996        const assertionDeclarations = Object.keys(997          candidateHandlers.reduce((result, { declaration }) => {998            result[declaration] = true;999            return result;1000          }, {})1001        ).sort();1002        assertionDeclarations.forEach((declaration, i) => {1003          output1004            .nl(i > 0 ? 1 : 0)1005            .i()1006            .text(declaration);1007        });1008        output.outdentLines();1009      },1010    });1011  }1012  const assertionsWithScore = [];1013  const assertionStrings = [];1014  instance = this;1015  while (instance) {1016    assertionStrings.push(...Object.keys(instance.assertions));1017    instance = instance.parent;1018  }1019  const compareAssertions = (a, b) => {1020    const aAssertion = this.lookupAssertionRule(subject, a, args);1021    const bAssertion = this.lookupAssertionRule(subject, b, args);1022    if (!aAssertion && !bAssertion) {1023      return 0;1024    }1025    if (aAssertion && !bAssertion) {1026      return -1;1027    }1028    if (!aAssertion && bAssertion) {1029      return 1;1030    }1031    return compareSpecificities(aAssertion.specificity, bAssertion.specificity);1032  };1033  assertionStrings.forEach((assertionString) => {1034    const score = ukkonen(testDescriptionString, assertionString);1035    assertionsWithScore.push({1036      assertion: assertionString,1037      score,1038    });1039  });1040  const bestMatch = assertionsWithScore1041    .sort((a, b) => {1042      const c = a.score - b.score;1043      if (c !== 0) {1044        return c;1045      }1046      if (a.assertion < b.assertion) {1047        return -1;1048      } else {1049        return 1;1050      }1051    })1052    .slice(0, 10)1053    .filter(({ score }, i, arr) => Math.abs(score - arr[0].score) <= 2)1054    .sort((a, b) => {1055      const c = compareAssertions(a.assertion, b.assertion);1056      if (c !== 0) {1057        return c;1058      }1059      return a.score - b.score;1060    })[0];1061  this.fail({1062    errorMode: 'bubbleThrough',1063    message(output) {1064      output1065        .error("Unknown assertion '")1066        .jsString(testDescriptionString)1067        .error("', did you mean: '")1068        .jsString(bestMatch.assertion)1069        .error("'");1070    },1071  });1072};1073expectPrototype.lookupAssertionRule = function (1074  subject,1075  testDescriptionString,1076  args,1077  requireAssertionSuffix1078) {1079  if (typeof testDescriptionString !== 'string') {1080    throw new Error(1081      'The expect function requires the second parameter to be a string or an expect.it.'1082    );1083  }1084  let handlers;1085  let instance = this;1086  while (instance) {1087    const instanceHandlers = instance.assertions[testDescriptionString];1088    if (instanceHandlers) {1089      handlers = handlers1090        ? handlers.concat(instanceHandlers)1091        : instanceHandlers;1092    }1093    instance = instance.parent;1094  }1095  if (!handlers) {1096    return null;1097  }1098  const cachedTypes = {};1099  const findTypeOf = (value, key) => {1100    let type = cachedTypes[key];1101    if (!type) {1102      type = this.findTypeOf(value);1103      cachedTypes[key] = type;1104    }1105    return type;1106  };1107  const matches = (value, assertionType, key, relaxed) => {1108    if (assertionType.is('assertion') && typeof value === 'string') {1109      return true;1110    }1111    if (relaxed) {1112      if (assertionType.identify === false) {1113        return this.types.some(1114          (type) =>1115            type.identify && type.is(assertionType) && type.identify(value)1116        );1117      }1118      return assertionType.identify(value);1119    } else {1120      return findTypeOf(value, key).is(assertionType);1121    }1122  };1123  function matchesHandler(handler, relaxed) {1124    if (!matches(subject, handler.subject.type, 'subject', relaxed)) {1125      return false;1126    }1127    if (requireAssertionSuffix && !handler.args.some(isAssertionArg)) {1128      return false;1129    }1130    if (args.length < handler.minimum || handler.maximum < args.length) {1131      return false;1132    } else if (args.length === 0 && handler.maximum === 0) {1133      return true;1134    }1135    const lastRequirement = handler.args[handler.args.length - 1];1136    return args.every((arg, i) => {1137      if (i < handler.args.length - 1) {1138        return matches(arg, handler.args[i].type, i, relaxed);1139      } else {1140        return matches(arg, lastRequirement.type, i, relaxed);1141      }1142    });1143  }1144  let j, handler;1145  for (j = 0; j < handlers.length; j += 1) {1146    handler = handlers[j];1147    if (matchesHandler(handler)) {1148      return handler;1149    }1150  }1151  for (j = 0; j < handlers.length; j += 1) {1152    handler = handlers[j];1153    if (matchesHandler(handler, true)) {1154      return handler;1155    }1156  }1157  return null;1158};1159expectPrototype._assertTopLevelExpect = function () {1160  // Cannot use this !== this._topLevelExpect due to https://github.com/unexpectedjs/unexpected/issues/6311161  if (this.flags) {1162    throw new Error('This method only works on the top level expect function');1163  }1164};1165expectPrototype._assertWrappedExpect = function () {1166  // Cannot use this === this._topLevelExpect due to https://github.com/unexpectedjs/unexpected/issues/6311167  if (!this.flags) {1168    throw new Error(1169      'This method only works on the expect function handed to an assertion'1170    );1171  }1172};1173expectPrototype.setErrorMessage = function (err) {1174  err.serializeMessage(this.outputFormat());1175};1176expectPrototype._createWrappedExpect = function (1177  assertionRule,1178  subject,1179  args,1180  testDescriptionString,1181  context,1182  forwardedFlags1183) {1184  const flags = extend({}, forwardedFlags, assertionRule.flags);1185  const parentExpect = this;1186  function wrappedExpect(subject, testDescriptionString) {1187    if (arguments.length === 0) {1188      throw new Error('The expect function requires at least one parameter.');1189    } else if (arguments.length === 1) {1190      return addAdditionalPromiseMethods(1191        makePromise.resolve(subject),1192        wrappedExpect,1193        subject1194      );1195    } else if (typeof testDescriptionString === 'function') {1196      wrappedExpect.errorMode = 'nested';1197      return wrappedExpect.withError(1198        () => testDescriptionString(subject),1199        (err) => {1200          wrappedExpect.fail(err);1201        }1202      );1203    }1204    testDescriptionString = utils.forwardFlags(testDescriptionString, flags);1205    const args = new Array(arguments.length - 2);1206    for (let i = 2; i < arguments.length; i += 1) {1207      args[i - 2] = arguments[i];1208    }1209    return wrappedExpect._callInNestedContext(() =>1210      parentExpect._executeExpect(1211        context.child(),1212        subject,1213        testDescriptionString,1214        args,1215        wrappedExpect.flags1216      )1217    );1218  }1219  utils.setPrototypeOfOrExtend(wrappedExpect, this);1220  wrappedExpect.context = context;1221  wrappedExpect.execute = wrappedExpect;1222  wrappedExpect.alternations = assertionRule.alternations;1223  wrappedExpect.flags = flags;1224  wrappedExpect.subject = subject;1225  wrappedExpect.testDescription = testDescriptionString;1226  wrappedExpect.args = args;1227  wrappedExpect.assertionRule = assertionRule;1228  wrappedExpect.subjectOutput = (output) => {1229    output.appendInspected(subject);1230  };1231  wrappedExpect.argsOutput = args.map((arg, i) => {1232    const argRule = wrappedExpect.assertionRule.args[i];1233    if (1234      typeof arg === 'string' &&1235      ((argRule && argRule.type.is('assertion')) ||1236        wrappedExpect._getAssertionIndices().indexOf(i) >= 0)1237    ) {1238      return new AssertionString(utils.forwardFlags(arg, flags));1239    }1240    return (output) => {1241      output.appendInspected(arg);1242    };1243  });1244  return wrappedExpect;1245};1246expectPrototype._executeExpect = function (1247  context,1248  subject,1249  testDescriptionString,1250  args,1251  forwardedFlags1252) {1253  if (forwardedFlags) {1254    testDescriptionString = utils.forwardFlags(1255      testDescriptionString,1256      forwardedFlags1257    );1258  }1259  let assertionRule = this.lookupAssertionRule(1260    subject,1261    testDescriptionString,1262    args1263  );1264  if (!assertionRule) {1265    const tokens = testDescriptionString.split(' ');1266    // eslint-disable-next-line no-labels1267    OUTER: for (let n = tokens.length - 1; n > 0; n -= 1) {1268      const prefix = tokens.slice(0, n).join(' ');1269      const remainingTokens = tokens.slice(n);1270      const argsWithAssertionPrepended = [remainingTokens.join(' ')].concat(1271        args1272      );1273      assertionRule = this.lookupAssertionRule(1274        subject,1275        prefix,1276        argsWithAssertionPrepended,1277        true1278      );1279      if (assertionRule) {1280        // Found the longest prefix of the string that yielded a suitable assertion for the given subject and args1281        // To avoid bogus error messages when shifting later (#394) we require some prefix of the remaining tokens1282        // to be a valid assertion name:1283        for (let i = 1; i < remainingTokens.length; i += 1) {1284          if (1285            Object.prototype.hasOwnProperty.call(1286              this.assertions,1287              remainingTokens.slice(0, i + 1).join(' ')1288            )1289          ) {1290            testDescriptionString = prefix;1291            args = argsWithAssertionPrepended;1292            // eslint-disable-next-line no-labels1293            break OUTER;1294          }1295        }1296      }1297    }1298    if (!assertionRule) {1299      this.throwAssertionNotFoundError(subject, testDescriptionString, args);1300    }1301  }1302  if (assertionRule.expect && assertionRule.expect !== this._topLevelExpect) {1303    return assertionRule.expect._expect(context, [1304      subject,1305      testDescriptionString,1306      ...args,1307    ]);1308  }1309  const wrappedExpect = this._createWrappedExpect(1310    assertionRule,1311    subject,1312    args,1313    testDescriptionString,1314    context,1315    forwardedFlags1316  );1317  return oathbreaker(assertionRule.handler(wrappedExpect, subject, ...args));1318};1319expectPrototype._expect = function (context, args, forwardedFlags) {1320  const subject = args[0];1321  const testDescriptionString = args[1];1322  if (args.length < 2) {1323    throw new Error('The expect function requires at least two parameters.');1324  } else if (typeof testDescriptionString === 'function') {1325    return this.withError(1326      () => testDescriptionString(subject),1327      (err) => {1328        this.fail(err);1329      }1330    );1331  }1332  try {1333    let result = this._executeExpect(1334      context,1335      subject,1336      testDescriptionString,1337      Array.prototype.slice.call(args, 2),1338      forwardedFlags1339    );1340    if (utils.isPromise(result)) {1341      result = wrapPromiseIfNecessary(result);1342      if (result.isPending()) {1343        result = result.then(undefined, (e) => {1344          if (e && e._isUnexpected && context.level === 0) {1345            this.setErrorMessage(e);1346          }1347          throw e;1348        });1349        this.notifyPendingPromise(result);1350      }1351    } else {1352      result = makePromise.resolve(result);1353    }1354    return addAdditionalPromiseMethods(result, this, subject);1355  } catch (e) {1356    if (e && e._isUnexpected) {1357      let newError = e;1358      if (typeof mochaPhantomJS !== 'undefined') {1359        newError = e.clone();1360      }1361      if (context.level === 0) {1362        this.setErrorMessage(newError);1363      }1364      throw newError;1365    }1366    throw e;1367  }1368};1369expectPrototype.diff = function (1370  a,1371  b,1372  output = this.createOutput(),1373  recursions,1374  seen1375) {1376  const maxRecursions = 100;1377  recursions = typeof recursions === 'number' ? recursions : maxRecursions;1378  if (recursions <= 0) {1379    // detect recursive loops in the structure1380    seen = seen || [];1381    if (seen.indexOf(a) !== -1) {1382      throw new Error('Cannot compare circular structures');1383    }1384    seen.push(a);1385  }1386  return this.findCommonType(a, b).diff(1387    a,1388    b,1389    output,1390    (actual, expected) =>1391      this.diff(actual, expected, output.clone(), recursions - 1, seen),1392    (v, depth) => output.clone().appendInspected(v, depth),1393    (actual, expected) => this.equal(actual, expected)1394  );1395};1396expectPrototype.toString = function () {1397  const assertions = this.assertions;1398  const seen = {};1399  const declarations = [];1400  const pen = magicpen();1401  Object.keys(assertions)1402    .sort()1403    .forEach((key) => {1404      assertions[key].forEach(({ declaration }) => {1405        if (!seen[declaration]) {1406          declarations.push(declaration);1407          seen[declaration] = true;1408        }1409      });1410    });1411  declarations.forEach((declaration) => {1412    pen.text(declaration).nl();1413  });1414  return pen.toString();1415};1416expectPrototype.clone = function () {1417  this._assertTopLevelExpect();1418  const clonedAssertions = {};1419  Object.keys(this.assertions).forEach(function (assertion) {1420    clonedAssertions[assertion] = [].concat(this.assertions[assertion]);1421  }, this);1422  const expect = createTopLevelExpect({1423    assertions: clonedAssertions,1424    types: [].concat(this.types),1425    typeByName: extend({}, this.typeByName),1426    output: this.output.clone(),1427    format: this.outputFormat(),1428    installedPlugins: [].concat(this.installedPlugins),1429  });1430  // Install the hooks:1431  this.installedHooks.forEach((hook) => {1432    expect.hook(hook);1433  });1434  // expect._expect = this._expect;1435  // Make sure that changes to the parent's preferredWidth doesn't propagate:1436  expect.output.preferredWidth = this.output.preferredWidth;1437  return expect;1438};1439expectPrototype.child = function () {1440  this._assertTopLevelExpect();1441  const childExpect = createTopLevelExpect(1442    {1443      assertions: {},1444      types: [],1445      typeByName: {},1446      output: this.output.clone(),1447      format: this.outputFormat(),1448      installedPlugins: [],1449    },1450    this1451  );1452  childExpect.exportAssertion = function (testDescription, handler) {1453    childExpect.parent.addAssertion(testDescription, handler, childExpect);1454    return this;1455  };1456  childExpect.exportType = function (type) {1457    if (childExpect.getType(type.name) !== type) {1458      childExpect.addType(type);1459    }1460    childExpect.parent.addType(type, childExpect);1461    return this;1462  };1463  childExpect.exportStyle = function (name, handler, allowRedefinition) {1464    childExpect.parent.addStyle(1465      name,1466      function (...args) {1467        const childOutput = childExpect.createOutput(this.format);1468        this.append(handler.call(childOutput, ...args) || childOutput);1469      },1470      allowRedefinition1471    );1472    return this;1473  };1474  return childExpect;1475};1476expectPrototype.freeze = function () {1477  this._assertTopLevelExpect();1478  this._frozen = true;1479  return this;1480};1481expectPrototype.outputFormat = function (format) {1482  if (typeof format === 'undefined') {1483    return this._outputFormat;1484  } else {1485    this._assertTopLevelExpect();1486    this._outputFormat = format;1487    return this;1488  }1489};1490expectPrototype.createOutput = function (format) {1491  const that = this;1492  const output = this.output.clone(format || 'text');1493  output.addStyle('appendInspected', function (value, depth) {1494    this.append(that.inspect(value, depth, this.clone()));1495  });1496  return output;1497};1498expectPrototype.hook = function (fn) {1499  this._assertTopLevelExpect();1500  if (this._frozen) {1501    throw new Error(1502      'Cannot install a hook into a frozen instance, please run .clone() first'1503    );1504  }1505  this.installedHooks.push(fn);1506  this._expect = fn(this._expect.bind(this));1507};1508// This is not super elegant, but wrappedExpect.fail was different:1509expectPrototype.fail = function (...args) {1510  // Cannot use this !== this._topLevelExpect due to https://github.com/unexpectedjs/unexpected/issues/6311511  if (this.flags) {1512    this._callInNestedContext(() => {1513      this._topLevelExpect._fail(...args);1514    });1515  } else {1516    try {1517      this._fail(...args);1518    } catch (e) {1519      if (e && e._isUnexpected) {1520        this.setErrorMessage(e);1521      }1522      throw e;1523    }1524  }1525};1526function lookupAssertionsInParentChain(assertionString, expect) {1527  const assertions = [];1528  for (let instance = expect; instance; instance = instance.parent) {1529    if (instance.assertions[assertionString]) {1530      assertions.push(...instance.assertions[assertionString]);1531    }1532  }1533  return assertions;1534}1535function findSuffixAssertions(assertionString, expect) {1536  if (typeof assertionString !== 'string') {1537    return null;1538  }1539  const straightforwardAssertions = lookupAssertionsInParentChain(1540    assertionString,1541    expect1542  );1543  if (straightforwardAssertions.length > 0) {1544    return straightforwardAssertions;1545  }1546  const tokens = assertionString.split(' ');1547  for (let n = tokens.length - 1; n > 0; n -= 1) {1548    const suffix = tokens.slice(n).join(' ');1549    const suffixAssertions = lookupAssertionsInParentChain(suffix, expect);1550    if (1551      findSuffixAssertions(tokens.slice(0, n).join(' '), expect) &&1552      suffixAssertions.length > 01553    ) {1554      return suffixAssertions;1555    }1556  }1557  return null;1558}1559expectPrototype.standardErrorMessage = function (output, options) {1560  this._assertWrappedExpect();1561  options = typeof options === 'object' ? options : {};1562  if ('omitSubject' in output) {1563    options.subject = this.subject;1564  }1565  if (options && options.compact) {1566    options.compactSubject = (output) => {1567      output.jsFunctionName(this.subjectType.name);1568    };1569  }1570  return createStandardErrorMessage(1571    output,1572    this.subjectOutput,1573    this.testDescription,1574    this.argsOutput,1575    options1576  );1577};1578expectPrototype._callInNestedContext = function (callback) {1579  this._assertWrappedExpect();1580  try {1581    let result = oathbreaker(callback());1582    if (utils.isPromise(result)) {1583      result = wrapPromiseIfNecessary(result);1584      if (result.isPending()) {1585        result = result.then(undefined, (e) => {1586          if (e && e._isUnexpected) {1587            const wrappedError = new UnexpectedError(this, e);1588            wrappedError.originalError = e.originalError;1589            throw wrappedError;1590          }1591          throw e;1592        });1593      }1594    } else {1595      result = makePromise.resolve(result);1596    }1597    return addAdditionalPromiseMethods(result, this.execute, this.subject);1598  } catch (e) {1599    if (e && e._isUnexpected) {1600      const wrappedError = new UnexpectedError(this, e);1601      wrappedError.originalError = e.originalError;1602      throw wrappedError;1603    }1604    throw e;1605  }1606};1607expectPrototype.shift = function (subject, assertionIndex) {1608  this._assertWrappedExpect();1609  if (arguments.length <= 1) {1610    if (arguments.length === 0) {1611      subject = this.subject;1612    }1613    assertionIndex = -1;1614    for (let i = 0; i < this.assertionRule.args.length; i += 1) {1615      const type = this.assertionRule.args[i].type;1616      if (type.is('assertion') || type.is('expect.it')) {1617        assertionIndex = i;1618        break;1619      }1620    }1621  } else if (arguments.length === 3) {1622    // The 3-argument syntax for wrappedExpect.shift is deprecated, please omit the first (expect) arg1623    subject = arguments[1];1624    assertionIndex = arguments[2];1625  }1626  if (assertionIndex !== -1) {1627    const args = this.args.slice(0, assertionIndex);1628    const rest = this.args.slice(assertionIndex);1629    const nextArgumentType = this.findTypeOf(rest[0]);1630    if (arguments.length > 1) {1631      // Legacy1632      this.argsOutput = (output) => {1633        args.forEach((arg, index) => {1634          if (index > 0) {1635            output.text(', ');1636          }1637          output.appendInspected(arg);1638        });1639        if (args.length > 0) {1640          output.sp();1641        }1642        if (nextArgumentType.is('string')) {1643          output.error(rest[0]);1644        } else if (rest.length > 0) {1645          output.appendInspected(rest[0]);1646        }1647        if (rest.length > 1) {1648          output.sp();1649        }1650        rest.slice(1).forEach((arg, index) => {1651          if (index > 0) {1652            output.text(', ');1653          }1654          output.appendInspected(arg);1655        });1656      };1657    }1658    if (nextArgumentType.is('expect.it')) {1659      return this.withError(1660        () => rest[0](subject),1661        (err) => {1662          this.fail(err);1663        }1664      );1665    } else if (nextArgumentType.is('string')) {1666      return this.execute(subject, ...rest);1667    } else {1668      return subject;1669    }1670  } else {1671    // No assertion to delegate to. Provide the new subject as the fulfillment value:1672    return subject;1673  }1674};1675expectPrototype._getSubjectType = function () {1676  this._assertWrappedExpect();1677  return this.findTypeOfWithParentType(1678    this.subject,1679    this.assertionRule.subject.type1680  );1681};1682expectPrototype._getArgTypes = function (index) {1683  this._assertWrappedExpect();1684  const lastIndex = this.assertionRule.args.length - 1;1685  return this.args.map((arg, index) => {1686    return this.findTypeOfWithParentType(1687      arg,1688      this.assertionRule.args[Math.min(index, lastIndex)].type1689    );1690  });1691};1692expectPrototype._getAssertionIndices = function () {1693  this._assertWrappedExpect();1694  if (!this._assertionIndices) {1695    const assertionIndices = [];1696    const args = this.args;1697    let currentAssertionRule = this.assertionRule;1698    let offset = 0;1699    // eslint-disable-next-line no-labels1700    OUTER: while (true) {1701      if (1702        currentAssertionRule.args.length > 1 &&1703        isAssertionArg(1704          currentAssertionRule.args[currentAssertionRule.args.length - 2]1705        )1706      ) {1707        assertionIndices.push(offset + currentAssertionRule.args.length - 2);1708        const suffixAssertions = findSuffixAssertions(1709          args[offset + currentAssertionRule.args.length - 2],1710          this1711        );1712        if (suffixAssertions) {1713          for (let i = 0; i < suffixAssertions.length; i += 1) {1714            if (suffixAssertions[i].args.some(isAssertionArg)) {1715              offset += currentAssertionRule.args.length - 1;1716              currentAssertionRule = suffixAssertions[i];1717              // eslint-disable-next-line no-labels...Using AI Code Generation
1var unexpected = require('unexpected'),2    unexpectedHtmlLike = require('unexpected-htmllike-assertions'),3    unexpectedReact = require('unexpected-react'),4    React = require('react'),5    TestUtils = require('react-addons-test-utils'),6    unexpectedReact = require('unexpected-react'),7    MyComponent = require('../src/myComponent.js');8var expect = unexpected.clone()9    .use(unexpectedHtmlLike)10    .use(unexpectedReact);11describe('MyComponent', function () {12    it('should render a div', function () {13        var renderer = TestUtils.createRenderer();14        renderer.render(React.createElement(MyComponent));15        var output = renderer.getRenderOutput();16        expect(output, 'to have rendered', <div>some text</div>);17    });18});19var React = require('react');20var MyComponent = React.createClass({21    render: function () {22        return (23        );24    }25});26module.exports = MyComponent;Using AI Code Generation
1var expect = require('unexpected').clone();2var unexpected = require('unexpected');3var unexpectedSinon = require('unexpected-sinon');4var sinon = require('sinon');5expect.use(unexpectedSinon);6var spy = sinon.spy();7var stub = sinon.stub().returns(42);8expect(spy, 'was not called');9expect(stub, 'was called once');10expect(stub, 'was called with', 123);11expect(stub, 'was called with', 123, 456);12expect(stub, 'was called with', 123, 456, 789);13expect(stub, 'was called with', 123, 456, 789, 101112);14expect(stub, 'was called with', 123, 456, 789, 101112, 131415);15expect(stub, 'was called with', 123, 456, 789, 101112, 131415, 161718);16expect(stub, 'was called with', 123, 456, 789, 101112, 131415, 161718, 192021);17expect(stub, 'was called with', 123, 456, 789, 101112, 131415, 161718, 192021, 222324);18expect(stub, 'was called with', 123, 456, 789, 101112, 131415, 161718, 192021, 222324, 252627);19expect(stub, 'was called with', 123, 456, 789, 101112, 131415, 161718, 192021, 222324, 252627, 282930);20expect(stub, 'was called with', 123, 456, 789, 101112, 131415, 161718, 192021, 222324, 252627, 282930, 313233);21expect(stub, 'was called with', 123, 456, 789, 101112, 131415, 161718, 192021, 222324, 252627, 282930, 313233, 343536);22expect(stub, 'was called with', 123, 456, 789, 101112, 131415, 161718, 192021Using AI Code Generation
1const expect = require('unexpected')2    .clone()3    .use(require('unexpected-messy'));4const messy = require('messy');5expect(messy.isAssertionArg, 'to be a function');6const isAssertionArg = require('unexpected-messy').isAssertionArg;7const isExpectedArg = require('unexpected-messy').isExpectedArg;8const isUnexpectedArg = require('unexpected-messy').isUnexpectedArg;9const isMessageArg = require('unexpected-messy').isMessageArg;10const isDiffArg = require('unexpected-messy').isDiffArg;11const isDiffOptionsArg = require('unexpected-messy').isDiffOptionsArg;12const isDiffActualArg = require('unexpected-messyUsing AI Code Generation
1var expect = require('unexpected').clone();2var isAssertionArg = expect.isAssertionArg;3console.log(isAssertionArg('to be a string'));4console.log(isAssertionArg('to be a string', 'to be a number'));5console.log(isAssertionArg('to be a string', 'to be a number', 'to be a boolean'));6console.log(isAssertionArg('to be a string', 'to be a number', 'to be a boolean', 'to be a function'));7console.log(isAssertionArg('to be a string', 'to be a number', 'to be a boolean', 'to be a function', 'to be a regexp'));8console.log(isAssertionArg('to be a string', 'to be a number', 'to be a boolean', 'to be a function', 'to be a regexp', 'to be a date'));9console.log(isAssertionArg('to be a string', 'to be a number', 'to be a boolean', 'to be a function', 'to be a regexp', 'to be a date', 'to be a map'));10console.log(isAssertionArg('to be a string', 'to be a number', 'to be a boolean', 'to be a function', 'to be a regexp', 'to be a date', 'to be a map', 'to be a set'));11console.log(isAssertionArg('to be a string', 'to be a number', 'to be a boolean', 'to be a function', 'to be a regexp', 'to be a date', 'to be a map', 'to be a set', 'to be a promise'));12console.log(isAssertionArg('to be a string', 'to be a number', 'to be a boolean', 'to be a function', 'to be a regexp', 'to be a date', 'to be a map', 'to be a set', 'to be a promise', 'to be an error'));13console.log(isAssertionArg('to be a string', 'to be a number', 'to be a boolean', 'to be a function', 'to be a regexp', 'to be a date', 'to be a map', 'to be a set', 'to be a promise', 'to be an error', 'to be a buffer'));14console.log(isAssertionArg('to be a string', 'to be a number', 'to be a boolean', 'to be aUsing AI Code Generation
1var expect = require('unexpected').clone();2expect.use(require('unexpected-sinon'));3var sinon = require('sinon');4var myCode = require('./myCode.js');5var myCodeSpy = sinon.spy(myCode);6var myCodeStub = sinon.stub(myCode);7var myCodeMock = sinon.mock(myCode);8var myCodeFake = sinon.fake(myCode);9describe('myCode', function() {10    it('should call the callback', function() {11        var callback = sinon.spy();12        myCode(callback);13        expect(callback, 'was called');14    });15});16module.exports = function(callback) {17    callback();18};19var callback = sinon.spy();20myCode(callback);21expect(callback.function, 'was called');22You can also use the .call() method on the spy object:23var callback = sinon.spy();24myCode(callback);25expect(callback.call, 'was called');26var callback = sinon.spy();27myCode(callback);28expect(callback, 'was called');29var callback = sinon.spy();30myCode(callback);31expect(callback.called, 'to be true');32var callback = sinon.spy();33myCode(callback);34expect(callback.calledOnce, 'to be true');35var callback = sinon.spy();36myCode(callback);37expect(callback.callCount, 'to be', 1);Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
