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

chai doesn't catch an error has thrown #1414

Open
MakariukVl opened this issue Sep 19, 2021 · 3 comments
Open

chai doesn't catch an error has thrown #1414

MakariukVl opened this issue Sep 19, 2021 · 3 comments

Comments

@MakariukVl
Copy link

MakariukVl commented Sep 19, 2021

this is my test
test16

which fails with the message:

1) Test suite for quickSort function
     #16. The comparer function is not specified in attributes. In this case,
      an array of objects can't be sorted because compare function doesn't know
      how so quickSort() throws TypeError:
   TypeError: Default compare function for arrays of objects is not supported
	at quickSort ...
	at Context.<anonymous> ...
	at processImmediate ...

but other similar test passed:

test15

I couldn't find any explanations / solutions / workarounds for this, so I think it's a bug with the expect(x).to.throw assertion.

@koddsson
Copy link
Member

koddsson commented Oct 4, 2021

@MakariukVl Can you provide a minimum viable code that reproduces the issue?

@MakariukVl
Copy link
Author

Yes of course @koddsson, I will attach the code. The quickSort function should cause an error in line 24 if the input array is an object array. The error itself is called, test No16 (line 209) must verify this, but chai doesn't catch this error. Another similar test No15 passed.

quicksort.js

function quickSort(array, compare) {
  const INPUT_TYPE = Object.prototype.toString.call(array);
  const ARRAY_TYPE = "[object Array]";
  const OBJECT_TYPE = "[object Object]";
  const STRING_TYPE = "[object String]";

  if (!(INPUT_TYPE === ARRAY_TYPE) && !(INPUT_TYPE === STRING_TYPE))
    throw new TypeError("The 'array' property must be an Array or String");

  if (array.length < 2) return array;

  compare = compare || null;
  if (INPUT_TYPE === ARRAY_TYPE) {
    if (array.filter(Array.isArray).length >= 1 && compare == null) {
      throw new TypeError(
        "Default compare function for multidimensional arrays is not supported"
      );
    }
    if (
      array.filter((v) => Object.prototype.toString.call(v) === OBJECT_TYPE)
        .length >= 1 &&
      compare == null
    ) {
      throw new TypeError(
        "Default compare function for arrays of objects is not supported"
      );
    }
  }

  let result, cmp;

  if (INPUT_TYPE === STRING_TYPE) {
    cmp = (a, b) => a.localeCompare(b);
    let str = array.split("");

    result = sort(str, cmp).join("");
  } else {
    // INPUT_TYPE === ARRAY_TYPE
    cmp =
      compare ||
      function (a, b) {
        return a - b;
      };
    result = sort(array, cmp);
  }

  return result;

  function sort(arr, cmp) {
    var left = [];
    var right = [];
    var indexMid = Math.floor(arr.length / 2);
    var mid = arr[indexMid];

    for (let i = 0; i < arr.length; i++) {
      if (i === indexMid) continue;
      if (cmp(mid, arr[i]) > 0) left.push(arr[i]);
      else right.push(arr[i]);
    }

    let result = [];
    result.push(...quickSort(left, cmp));
    result.push(mid);
    result.push(...quickSort(right, cmp));

    return result;
  }
}

export { quickSort };

quicksort.test.js

// chai: https://github.com/chaijs/chai
import chai from "chai";
// chaiArrays: https://github.com/GaneshSPatil/chai-arrays
import chaiArrays from "chai-arrays";
import { quickSort } from "../src/quickSort.js";

const expect = chai.expect;
chai.use(chaiArrays);

describe("Test suite for quickSort function", function () {
  ....
  it("#15. The comparer function is not specified in attributes. In this case,\n\t2d array can't be sorted because compare function doesn't know how so \n\tquickSort() throws TypeError", function () {
    const arr = [
      [50, 86],
      [77, 2],
      [90, 8],
      [7, 8],
      [1, 2],
      [13, 8],
      [2, 10],
      [33, 24],
    ];
    expect(quickSort.bind(null, arr)).to.throw(TypeError);
  });
  it("#16. The comparer function is not specified in attributes. In this case,\n\tarray of objects can't be sorted because compare function doesn't know\n\thow so quickSort() throws TypeError", function () {
    const arr = quickSort([
      { Name: "Bob", Age: 17 },
      { Name: "Daniel", Age: 33 },
      { Name: "Clara", Age: 41 },
      { Name: "Ann", Age: 15 },
      { Name: "John", Age: 36 },
      { Name: "Jane", Age: 31 },
      { Name: "Jack", Age: 70 },
      { Name: "Sara", Age: 7 },
    ]);
    // Bug - chai doesn't catch an error has thrown: https://github.com/chaijs/chai/issues/1414
    expect(quickSort.bind(null, arr)).to.throw(TypeError);
  });
  ....
});

@rvantonisse
Copy link

Hey there,

I was experiencing a similar situation.

This basic example should run the tests as expected without exiting.

// someFunction.js
export default function someFunction(arg) {
  if (!arg) {
    throw new Error("Oops")
  }
}

and testfile:

import "chai/register-should.js"

import someFunction from "./someFunction.js"

describe("someFunction()", function functionName() {

  it("should throw without arguments", function () {
    someFunction.should.throw()
  })

  it("should not throw with an argument", function () {
    (()=> someFunction("argument")).should.not.throw()
  })
})

You should pay attention to catching errors in your other tests and code usage where you use / instanciate a function that throws errors on wrong usage. If you don't, testing will exit with the actual error thrown.

In my situation I was instanciating someFunction without arguments in another describe block, like:

// describe block
const value = someFunction()

which caused my tests to stop running due to thrown error.

In your case the code exits because somewhere you throw an error when an array with objects is passed:

throw new TypeError("Default compare function for arrays of objects is not supported");

Due to quickSort being a kind of recursive function calling quickSort again with different arguments might cause your tests to exit. It did not throw the error with first call, but quickSort got called again internally which threw the error that did not get caught. So your test did not pass or fail.

Should chai.should.throw also catch errors that occur in this situation as well? Whilst running the initial called tested function?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants