fastify-autoload: Typescript compiler error when running tests using Vitest

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Fastify version

3.28.0

Node.js version

16

Operating system

macOS

Operating system version (i.e. 20.04, 11.3, 10)

12.3

Description

I would like to test my fastify app using vitest, however I have noticed there is a typescript error I can’t seem to get around.

When I run my tests Fastify errors, fastify-autoload cannot import plugin ... . To fix this error compile TypeScript to JavaScript or use 'ts-node' to run your app..

I can successfully run the tests when I compile them to Javascript and import the javascript version in the test. This does however, feel a bit hacky. It can also impact the code coverage (depending on how you are generating the javascript).

Steps to Reproduce

Stackbliz link: https://stackblitz.com/edit/node-sdwsoh

Run the npm run test command.

Expected Behavior

Tests can be run in vitest using Typescript without having to compile first, and import the javascript version.

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 5
  • Comments: 52 (24 by maintainers)

Most upvoted comments

@Pustinyak solution worked for me. And based off this solution another solution that worked for me, was to simply leverage vitest’s deps option, ie

export default defineConfig({
  test: {
    deps: {
      inline: ["@fastify/autoload"],
    },
  },
});

deps.inline is now deprecated, and deps.optimizer should be used instead. I can’t get it to work with deps.optimizer, any suggestions @jimmy-guzman ? I tried using server.deps.inline and it works, but the ideal would be to stop using server.deps.inline completely as it is the intention mentioned in: https://github.com/vitest-dev/vitest/releases/tag/v0.34.0.

@Pustinyak solution worked for me. And based off this solution another solution that worked for me, was to simply leverage vitest’s deps option, ie

export default defineConfig({
  test: {
    deps: {
      inline: ["@fastify/autoload"],
    },
  },
});

Under-rated solution.

Literally, with a documentation update, this issue could be closed 👏👏👏

This looks like a really hard thing to solve, and I think the problem lies between vite and node. I couldn’t think of a way to add support for this edge case… Anyway, I created a simple workaround that toggles between vitest support.

  1. Install cjstoesm:
npm i -D cjstoesm
  1. In your ./package.json add scripts:
"scripts": {
  "pretest": "node ./test/vitest.js on",
  "test": "vitest",
  "posttest": "node ./test/vitest.js off",
}
  1. Create ./test/vitest.js with this code:
const fs = require("fs");
const path = require("path");
const { transform } = require("cjstoesm");

const autoloadPath = "node_modules/@fastify/autoload";
const indexJs = "index.js";
const indexTs = "index.ts";

main();

function main() {
  const [state] = process.argv.slice(2);
  changePackageType(state === "on");
  convertToESM();
}

function changePackageType(isOn = false) {
  const packagePath = path.join(autoloadPath, "package.json");
  const packageFile = fs.readFileSync(packagePath, "utf8");
  const updatedPackageFile = packageFile.replace(
    `"main": "${isOn ? indexJs : indexTs}"`,
    `"main": "${isOn ? indexTs : indexJs}"`
  );
  fs.writeFileSync(packagePath, updatedPackageFile);
}

async function convertToESM() {
  const indexTsPath = path.join(autoloadPath, indexTs);
  if (fs.existsSync(indexTsPath)) {
    return;
  }
  const result = await transform({
    input: path.join(autoloadPath, indexJs),
    write: false,
  });
  for (const { fileName, text } of result.files) {
    fs.writeFileSync(indexTsPath, text);
  }
}
  1. Run the tests
npm run test

For now it’s the only thing we can do, let me know if this works for you.

I have a potential PR

can confirm it works on latest vitest 0.34.1. No config modifications are needed now

This is somehow still reproducible with @fastify/autoload 5.7.1 and vitest 0.34.5. Running npx vitest run with no vitest.config.ts file gives the TypeError: Unknown file extension ".ts" error.

On the same note, Having vitest config with test.deps.inline: [“@fastify/autoload”] helps, as said above.

Hey, None of the solution worked for me. I had to remove '@fastify/autoload' and loads the plugins myself 🫣

This looks like a really hard thing to solve, and I think the problem lies between vite and node. I couldn’t think of a way to add support for this edge case… Anyway, I created a simple workaround that toggles between vitest support.

  1. Install cjstoesm:
npm i -D cjstoesm
  1. In your ./package.json add scripts:
"scripts": {
  "pretest": "node ./test/vitest.js on",
  "test": "vitest",
  "posttest": "node ./test/vitest.js off",
}
  1. Create ./test/vitest.js with this code:
const fs = require("fs");
const path = require("path");
const { transform } = require("cjstoesm");

const autoloadPath = "node_modules/@fastify/autoload";
const indexJs = "index.js";
const indexTs = "index.ts";

main();

function main() {
  const [state] = process.argv.slice(2);
  changePackageType(state === "on");
  convertToESM();
}

function changePackageType(isOn = false) {
  const packagePath = path.join(autoloadPath, "package.json");
  const packageFile = fs.readFileSync(packagePath, "utf8");
  const updatedPackageFile = packageFile.replace(
    `"main": "${isOn ? indexJs : indexTs}"`,
    `"main": "${isOn ? indexTs : indexJs}"`
  );
  fs.writeFileSync(packagePath, updatedPackageFile);
}

async function convertToESM() {
  const indexTsPath = path.join(autoloadPath, indexTs);
  if (fs.existsSync(indexTsPath)) {
    return;
  }
  const result = await transform({
    input: path.join(autoloadPath, indexJs),
    write: false,
  });
  for (const { fileName, text } of result.files) {
    fs.writeFileSync(indexTsPath, text);
  }
}
  1. Run the tests
npm run test

For now it’s the only thing we can do, let me know if this works for you.

this worked for me

Might be a config issue on my side, but when I now try my repro again (with the updated package), I get the following:

TypeError: Unknown file extension ".ts" for /Users/jclaessens/dev/github/vitest-alias-repro/packages/api/src/plugins/cors.ts
Serialized Error: {
  "code": "ERR_UNKNOWN_FILE_EXTENSION",
}

This is the same issue I got when I tried to do the changes myself.

Again, it might be a config issue on my side, but it’s unclear to me at this point.

You could test it by setting the repo and the branch for the package in package.json

{
  "dependencies": {
   ...
    "@fastify/autoload": "fastify/fastify-autoload#forceESM-for-vitest"
   ...
  }
}

Provided an alternative approach to set forceESM instead of ts-node #274

Just now seeing that #264 broke things mentioned in #266. Will take a look at that tomorrow and hopefully have a PR next week.

Reopen due to 6adc2966ba5f9414139af22033eb78b3cb0c1f91