javascriptnode.jstypescripttypescript-execute

tsx could not find directory


I'm using Node 19 and have a small library using TypeScript and the builtin testrunner. Based on this Github issue comment I'm trying to test the .ts files.

tsconfig.json

{
    "compilerOptions": {
        "baseUrl": ".",
        "declaration": true,
        "esModuleInterop": true,
        "lib": ["es2022", "dom"],
        "module": "commonjs",
        "outDir": "build",
        "resolveJsonModule": true,
        "strict": true,
        "target": "es2022"
    },
    "include": ["./**/*.ts"],
    "exclude": ["./build"]
}

package.json

{
    "scripts": {
        "test": "tsc --noEmit && node --loader tsx --test test/**/*Tests.ts"
    },
    "dependencies": {
        "@types/node": "18.11.9"
    },
    "devDependencies": {
        "tsx": "3.11.0",
        "typescript": "4.8.4"
    }
}

./test/someTests.ts

import assert from 'assert/strict';
import { describe, it } from 'node:test';

describe('tests', () => {
    it('passes', () => {
        assert.ok(true);
    });
});

When running npm run test I get the error

Could not find '/home/.../repository/test/**/*Tests.ts'

Does someone know what's wrong?


Solution

  • EDIT:

    See this example project which I have created.

    Problem

    I haven't tested your environment, but if I had to guess I believe it is your npm script which is incorrect:

    tsc --noEmit && node --loader tsx --test test/**/*Tests.ts
    

    On a POSIX system npm will execute the script with /bin/sh. The pattern test/**/*Tests.ts is not expanded by node or npm it is up to /bin/sh to expand it. However, **, also known as globstar is not supported by /bin/sh, it is not being expanded as you would expect. The globstar is supported by /bin/bash, but must be enabled.

    Solution

    I could be wrong, but I believe since globstar is not supported, the pattern test/**/*Tests.ts becomes test/*/*Tests.ts which will only match files in a subdirectory of your test folder, such as test/abc/xyzTests.ts. If you just wanted to match tests in the root of the test folder, you could rewrite the pattern as test/*Tests.ts, which would match tests/xyzTests.ts, but would not match files in a subdirectory of your test folder.

    Better Solution

    It would be better to rewrite the script in a cross-platform manner, instead of relying on platform dependent features in your scripts which is may be unreliable. This way your script should even work on Windows.

    There might be an easier way to leverage another package, but I think I would just move it into a JavaScript or TypeScript script.

    Change your script to:

    tsc --noEmit && node --loader tsx runTests.ts
    

    Then create a file named runTests.ts.

    I don't have the time to experiment with a full script, but I expect you would want to use the glob package to get the list of files and the child_process Node API to then call node --loader tsx --test ....

    Related

    Why can't ** be used (for recursive globbing) in a npm package.json script, if it works in 'npm shell'?

    Why you should always quote your globs in NPM scripts.