← All tasks
javascriptmochajs/mocha #5940Not a task: not reproduced

bug: lookupFiles() returns a string instead of string[] when given a direct file path

envgap__mochajs__mocha-5940

01 / FAILURE SIGNATURE

As reported upstream

No identifying execution failure has been captured.
Not a benchmark task.
  • In a clean container the reported failure did not reproduce, or the known fix did not make the project run.

02 / ENVIRONMENT RECIPE

Base commit
75c618d6d85d9754b0d9bb8b2e1709be737de970
Manifest
package.json
Reproduce
Awaiting issue-specific recipe
Run under trace
Awaiting a meaningful runtime command

03 / ORIGINAL ISSUE TEXT

mochajs/mocha #5940 · read the original issue
## Summary

`lookupFiles()` in `lib/cli/lookup-files.mjs` has a documented return type of `string[]`, but when given a direct file path (i.e., a file that exists on disk, not a glob or directory), it returns a bare `string` instead of a `string[]`.

## Environment

- Mocha version: latest (`main` branch)
- - Node.js version: v20+ / v22+
- - - Platform: Any
## Reproduction

```js
// lib/cli/lookup-files.mjs (lines 107-115)
try {
  stat = fs.statSync(filepath);
  if (stat.isFile() || stat.isFIFO()) {
    return filepath; // <- returns a bare string, not an array
  }
} catch {
  return;
}
```

**Minimal reproduction (programmatic API):**

```js
const { lookupFiles } = require('mocha/lib/cli/lookup-files');

const result = lookupFiles('./test/mytest.spec.js', ['js'], false);
// Expected: ['./test/mytest.spec.js']  (string[])
// Actual:   './test/mytest.spec.js'    (string)

// This breaks spread:
const files = [...result]; // iterates over characters, not file paths!
```

## Impact

The JSDoc on `lookupFiles` documents the return type as `{string[]}`:

```js
 * @return {string[]} An array of paths.
```

However, when a direct file path is passed (not a glob, not a directory), the function short-circuits and returns a plain `string`. This creates a type inconsistency that can silently break downstream consumers, including:

- Any programmatic API user who spreads the result: `[...lookupFiles(file)]` would iterate over **characters**.
- - Any consumer who calls `.map()` or `.filter()` on the result - these would act on characters of the string, not file paths.
- - - Plugins or third-party integrations that rely on the documented interface.
Currently, Mocha's own internal call site in `run-helpers.js` happens to use `[].concat(lookupFiles(...))`, which works around the inconsistency since `[].concat("string")` produces `["string"]`. However, this is fragile and relies on undocumented behavior.

## Suggested Fix

Wrap the file path in an array before returning, to match the documented return type:

```diff
if (stat.isFile() || stat.isFIFO()) {
-   return filepath;
+   return [filepath];
}
```

This is a 1-line change in `lib/cli/lookup-files.mjs` and makes the actual return type consistent with the documentation.

A corresponding test should also verify that a direct file path argument returns an array with exactly one element.

## Additional Context

This was discovered while auditing the `lib/cli/lookup-files.mjs` module. The inconsistency is subtle because the internal call site in `run-helpers.js` uses `[].concat(...)`, which silently handles both strings and arrays - masking the bug from the existing test suite.
Continue on GitHub ↗

04 / LABELS

Labels from the report text only; not yet run

No supported category has been assigned.

Label rules and the text that matched
[]