Repository: pandas-dev/pandas
File: pandas/_testing/asserters.py (Python)

Code before:
                )
                assert_numpy_array_equal(left.codes[level], right.codes[level])
            except AssertionError:
                llevel = left.get_level_values(level)
                rlevel = right.get_level_values(level)

                assert_index_equal(
                    llevel,
                    rlevel,
                    exact=exact,
                    check_names=check_names,
                    check_exact=check_exact,
                    check_categorical=check_categorical,
                    rtol=rtol,
                    atol=atol,
                    obj=lobj,
                )
            # get_level_values may change dtype
            _check_types(left.levels[level], right.levels[level], obj=lobj)

    # skip exact index checking when `check_categorical` is False
    elif check_exact and check_categorical:
        if not left.equals(right):
            try:
                mismatch = left._values != right._values
            except TypeError as e:
                raise AssertionError(
                    f"{obj} cannot be compared due to incompatible"
                    f"categorical types.\n{e}"
                ) from e

            if not isinstance(mismatch, np.ndarray):
                mismatch = cast("ExtensionArray", mismatch).fillna(True)

            diff = np.sum(mismatch.astype(int)) * 100.0 / len(left)
            msg = f"{obj} values are different ({np.round(diff, 5)} %)"
            raise_assert_detail(obj, msg, left, right)
    else:
        # if we have "equiv", this becomes True
        exact_bool = bool(exact)
        _testing.assert_almost_equal(
            left.values,
            right.values,
            rtol=rtol,
            atol=atol,
            check_dtype=exact_bool,
            obj=obj,
            lobj=left,
            robj=right,
        )


Review comment (suggestion):
If the `TypeError` is hit, we should be comparing the materialized version of the `CategoricalIndex` e.g. `left._internal_get_values() != right._internal_get_values()`

Code after:
                    rtol=rtol,
                    atol=atol,
                    obj=lobj,
                )
                assert_numpy_array_equal(left.codes[level], right.codes[level])
            except AssertionError:
                llevel = left.get_level_values(level)
                rlevel = right.get_level_values(level)

                assert_index_equal(
                    llevel,
                    rlevel,
                    exact=exact,
                    check_names=check_names,
                    check_exact=check_exact,
                    check_categorical=check_categorical,
                    rtol=rtol,
                    atol=atol,
                    obj=lobj,
                )
            # get_level_values may change dtype
            _check_types(left.levels[level], right.levels[level], obj=lobj)

    # skip exact index checking when `check_categorical` is False
    elif check_exact and check_categorical:
        if not left.equals(right):
            # _values compare can raise TypeError (non-comparable
            # categoricals (GH#61935)
            try:
                mismatch = left._values != right._values
            except TypeError:
                raise_assert_detail(
                    obj,
                    "types are not comparable (non-matching categorical categories)",
                    left,
                    right,
                )

            if not isinstance(mismatch, np.ndarray):
                mismatch = cast("ExtensionArray", mismatch).fillna(True)

            diff = np.sum(mismatch.astype(int)) * 100.0 / len(left)
            msg = f"{obj} values are different ({np.round(diff, 5)} %)"
            raise_assert_detail(obj, msg, left, right)
    else:
        # if we have "equiv", this becomes True
        exact_bool = bool(exact)
        _testing.assert_almost_equal(
            left.values,
            right.values,
            rtol=rtol,