Search code examples
javascriptnode.jstypescriptautomated-testsplaywright

Why do I have to explicitly specify .ts in my typescript import statements (running inside playwright framework)


I'm trying to write some playwright tests that need some setup. This setup is called as the global setup in Playwright config file.

The setup has an import statement :

import { X, Y, Z} from '../../fixtures';

Here is my tsconfig.json :

{
    "compilerOptions": {
        "target": "es2018",
        "module": "Node16",
        "experimentalSpecifierrResolution": "node",
        "sourceMap": true,
        "esModuleInterop": true,
        "strict": false,
        "lib": [
            "dom",
            "es2018"
        ],
        "types": [
            "node",
            "cypress",
            "cypress-real-events"
        ],
        "moduleResolution": "node",

    },
    "include": [
        "**/*.ts"
    ]
}

And of course in my package.json file I have : "type": "module"

What I don't understand is when I try to run these tests I get the following error :

Error: Cannot find module 'C:\Users\x\project\e2e\fixtures' imported from C:\Users\x\projects\e2e\playwright\support\setupTests.ts

BUT if I import with the extension : import { X, Y, Z} from '../../fixtures.ts';

Everything works out fine.

I don't understand it. Especially that I have other imports in the setup file that don't use the .ts extension and they don't cause any issue.

I already the workaround of including the .ts extension in my import statement. and it actually ran my tests and setup file correctly.

Only problem is that I get a Typescript warning in my IDE : TS2691: An import path cannot end with a '.ts' extension.

And that I am baffled by this behavior.


Solution

  • Okay so I just finally understood how it works.

    After reading here : https://www.typescriptlang.org/docs/handbook/esm-node.html

    The right way to do the relative import is :

    import {X, Y, Z} from '../../fixtures.js';
    

    Typescript is confused when you have fixtures.ts and will give you that warning. And without an extension the compiled javascript file just doesn't make sense because ESM expect you to have the extension :

    relative import paths need full extensions (e.g we have to write import "./foo.js" instead of import "./foo")

    So yeah I still find it a bit bizarre to import a file that doesn't exist yet. but it's just one of typescript peculiarities.