kulshekhar/ts-jest

[Bug]: ES6 still doesn't work

Creative-Difficulty opened this issue · 1 comments

Version

29.1.0

Steps to reproduce

jest.config.ts:

import type { JestConfigWithTsJest } from 'ts-jest'

const jestConfig: JestConfigWithTsJest = {
  // [...]
  preset: 'ts-jest/presets/default-esm', // or other ESM presets
  moduleNameMapper: {
    '^(\\.{1,2}/.*)\\.js$': '$1',
  },
  transform: {
    // '^.+\\.[tj]sx?$' to process js/ts with `ts-jest`
    // '^.+\\.m?[tj]sx?$' to process js/ts/mjs/mts with `ts-jest`
    '^.+\\.ts?$': [
      'ts-jest',
      {
        useESM: true,
      },
    ],
  },
}

export default jestConfig

npm test output:

C:\Users\name\Documents\Projects\Oxygen>npm test

> oxygen@0.8.0 test
> jest

 FAIL  tests/checkEnv.test.ts
  ● Test suite failed to run

    src/lib/checkEnv.ts:45:73 - error TS1378: Top-level 'await' expressions are only allowed when the 'module' option is set to 'es2022', 'esnext', 'system', 'node16', or 'nodenext', and the 'target' option is set to 'es2017' or higher.

    45 export const { Port, JWTSecret }: { Port: number, JWTSecret: string } = await checkEnv(path.join(dirname, ".env"));
                                                                               ~~~~~

 FAIL  tests/getUser.test.ts
  ● Test suite failed to run

    src/lib/checkEnv.ts:45:73 - error TS1378: Top-level 'await' expressions are only allowed when the 'module' option is set to 'es2022', 'esnext', 'system', 'node16', or 'nodenext', and the 'target' option is set to 'es2017' or higher.

    45 export const { Port, JWTSecret }: { Port: number, JWTSecret: string } = await checkEnv(path.join(dirname, ".env"));
                                                                               ~~~~~

Test Suites: 2 failed, 2 total
Tests:       0 total
Snapshots:   0 total
Time:        4.875 s
Ran all test suites.

C:\Users\name\Documents\Projects\Oxygen>

I import a function from my project in my test:

import path from "node:path";
import { checkEnv } from "../src/lib/checkEnv.js";
import * as fs from "node:fs/promises";

const dirname = path.resolve();
const portToTest = Math.floor(Math.random() * (65535 - 1 + 1) + 1);
const envPath = path.join(dirname, ".env");
let oldEnvContents: Buffer;

beforeAll(async () => {
    try {
        // Check if there is already a .env in the project root
        await fs.access(envPath, fs.constants.W_OK | fs.constants.R_OK);
        oldEnvContents = await fs.readFile(envPath);
        await fs.unlink(envPath);
    } finally {
        // Create new .env in project root for testing purposes
        return await fs.writeFile(envPath, `# Defaults to 512 random bytes if left blank (Seriously: just mash your keyboard for the best results)\n# WARNING: IF YOU CHANGE THE JWT-SECRET, THE ENTIRE DATABASE WILL BE INVALIDATED, THIS WILL LEAD TO UNEXPECTED BEHAVIOUR\n# IN THAT CASE PLEASE USE THE -d FLAG TO CLEAR THE DATABASE\nJWTSECRET=TestSecretTestSecret\n# WILL DEFAULT TO 9495 IF INVALID/BLANK\nPORT=${portToTest}`);
    }
});

test("checkEnv returns parsed Port and secret", async () => {
    const { Port, JWTSecret }: { Port: number, JWTSecret: string } = await checkEnv(envPath);
    expect(Port).toBe(portToTest);
    expect(JWTSecret).toBe("TestSecretTestSecret");
});

afterAll(async () => {
    await fs.unlink(envPath);
    if(oldEnvContents !== undefined) {
        return await fs.writeFile(envPath, oldEnvContents);
    }
});

src/lib/checkEnv.ts:


import { randomBytes } from "node:crypto";
import * as fs from "node:fs/promises"
import * as dotenv from "dotenv";
import { logger } from "./logger.js";
import path from "node:path";

export async function checkEnv(envPath: string): Promise<{ Port: number, JWTSecret: string }> {
    try {
        await fs.access(envPath);
    } catch {
        logger.error("Cannot access .env configuration file, creating a new one with default configuration...")
        let defaultJWTSecret = randomBytes(512).toString("hex");
        await fs.writeFile(envPath, `# Defaults to 512 random bytes if left blank (Seriously: just mash your keyboard for the best results)\n# WARNING: IF YOU CHANGE THE JWT-SECRET, THE ENTIRE DATABASE WILL BE INVALIDATED, THIS WILL LEAD TO UNEXPECTED BEHAVIOUR\n# IN THAT CASE PLEASE USE THE -d FLAG TO CLEAR THE DATABASE\nJWTSECRET=${defaultJWTSecret}\n# WILL DEFAULT TO 9495 IF INVALID/BLANK\nPORT=9495`);
        logger.info("Done!");
    }
    
    dotenv.config();

    if(typeof process.env.JWTSECRET !== "string") {
        let defaultJWTSecret = randomBytes(512).toString("hex");
        process.env.JWTSECRET = defaultJWTSecret;
        logger.error("Invalid JWTSecret environment variable detected, defaulting to 512 random bytes");
        await fs.writeFile(envPath, `# defaults to 512 random bytes if left blank (Seriously: just mash your keyboard for the best results)\n# WARNING: IF YOU CHANGE THE JWT-SECRET, THE ENTIRE DATABASE WILL BE INVALIDATED, THIS WILL LEAD TO UNEXPECTED BEHAVIOUR\n# IN THAT CASE PLEASE USE THE -d FLAG TO CLEAR THE DATABASE\nJWTSECRET=${defaultJWTSecret}\n # WILL DEFAULT TO 9495 IF INVALID/BLANK\nPORT=${process.env.PORT}`);
        logger.info("Done!");
    }
    let defaultJWTSecret = randomBytes(512).toString("hex");
    const JWTSecret = process.env.JWTSECRET || defaultJWTSecret;
    
    if (JWTSecret.length < 16) logger.warn("JWTSecret is too short and could easily be cracked in case of a database leak, please change it to a more secure one.");
    
    if(parseInt(process.env.PORT) >= 65535 || parseInt(process.env.PORT) <= 0 || process.env.PORT === "undefined") {
        process.env.PORT = "9495";
        logger.error("Invalid Port environment variable detected, defaulting to Port 9495");
        await fs.writeFile(envPath, `# defaults to 512 random bytes if left blank (Seriously: just mash your keyboard for the best results)\n# WARNING: IF YOU CHANGE THE JWT-SECRET, THE ENTIRE DATABASE WILL BE INVALIDATED, THIS WILL LEAD TO UNEXPECTED BEHAVIOUR\n# IN THAT CASE PLEASE USE THE -d FLAG TO CLEAR THE DATABASE\nJWTSECRET=${JWTSecret}\n # WILL DEFAULT TO 9495 IF INVALID/BLANK\nPORT=9495`);
        logger.info("Done!");
    }
    
    const Port = parseInt(process.env.PORT);
    return {
        Port,
        JWTSecret
    }
}
const dirname = path.resolve();
export const { Port, JWTSecret }: { Port: number, JWTSecret: string } = await checkEnv(path.join(dirname, ".env"));

src/lib/checkEnv.ts also imports from other files, all of them use top level await.

Notice that i use https://www.npmjs.com/package/ts-jest-resolver to resolve the TypeScript imports.

Expected behavior

I expected the test to work

Actual behavior

^
|
|

Debug log

Too long for GitHub: https://justpaste.it/3zzlv

Additional context

No response

Environment

System:
    OS: Windows 10 10.0.19045
    CPU: (12) x64 AMD Ryzen 5 3600 6-Core Processor
  Binaries:
    Node: 18.5.0 - C:\Program Files\nodejs\node.EXE
    npm: 9.8.1 - C:\Program Files\nodejs\npm.CMD
    pnpm: 8.6.11 - ~\AppData\Local\pnpm\pnpm.EXE
  npmPackages:
    jest: ^29.5.0 => 29.6.4

Have migrated to bun (it's just better) LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL