vitest icon indicating copy to clipboard operation
vitest copied to clipboard

[Windows] Vitest can not run in folders that are symlinked

Open Primajin opened this issue 2 years ago • 9 comments

Describe the bug

I have symlinked a folder on Windows 11. When running vitest it tells me the file does not exist and gives out the "canonical" path to the file - however this path is absolutely correct and the file exist. When I run vitest directly in the "canonical" path it works as expected.

Screenshot 2023-09-09 155306

Screenshot 2023-09-09 155148

Screenshot 2023-09-09 155212

Reproduction

This seems to be an issue with resolving directories in NTFS, I don't know how to set up a reproducible environment that is running Windows 11.

  1. Have a machine running Windows 10 / 11 with NTFS file system
  2. Create Folder A and set up a basic vitest project with one test
  3. Run vitest
  4. Everything should be fine here
  5. Go one folder up and create a symlink to Folder A and call it Folder B
  6. mklink /D "Folder B" "Folder A" (Keep in mind that mklink works the other way around than you are used to with ln -s)
  7. Go into Folder B
  8. You should see the files of Folder A, however your path shows Folder B
  9. Run vitest
  10. You will see an error that C:\YourPath\Folder A\yourFile.js can not be found although it is there and you are in Folder B

System Info

System:
    OS: Windows 10 10.0.22621
    CPU: (12) x64 AMD Ryzen 5 5600G with Radeon Graphics
    Memory: 5.60 GB / 15.89 GB
  Binaries:
    Node: 20.6.1 - C:\Program Files\nodejs\node.EXE
    npm: 10.1.0 - C:\Program Files\nodejs\npm.CMD
  Browsers:
    Edge: Spartan (44.22621.2215.0), Chromium (116.0.1938.69)
    Internet Explorer: 11.0.22621.1
  npmPackages:
    @vitejs/plugin-react: ^4.0.4 => 4.0.4
    vite: ^4.4.9 => 4.4.9
    vitest: ^0.34.4 => 0.34.4


### Used Package Manager

npm

### Validations

- [X] Follow our [Code of Conduct](https://github.com/vitest-dev/vitest/blob/main/CODE_OF_CONDUCT.md)
- [X] Read the [Contributing Guidelines](https://github.com/vitest-dev/vitest/blob/main/CONTRIBUTING.md).
- [X] Read the [docs](https://vitest.dev/guide/).
- [X] Check that there isn't [already an issue](https://github.com/vitest-dev/vitest/issues) that reports the same bug to avoid creating a duplicate.
- [X] Check that this is a concrete bug. For Q&A open a [GitHub Discussion](https://github.com/vitest-dev/vitest/discussions) or join our [Discord Chat Server](https://chat.vitest.dev).
- [X] The provided reproduction is a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) of the bug.

Primajin avatar Sep 09 '23 14:09 Primajin

I was getting similar errors when running vite server in dev mode:

When I started vite in the symlinked directory I was getting the error:

Screenshot 2023-09-09 162530

Screenshot 2023-09-09 162552

as if the file was never transpiled.

When I ran the command in the canonical folder the error did not happen and the app rendered as expected.

I could solve that for vite by adding

	resolve: {
		preserveSymlinks: true,
	},

However this doesn't seem to work / affect vitest only vite.

Primajin avatar Sep 09 '23 14:09 Primajin

Maybe it thinks it's outside of root? If you disable server.fs.strict, will it work?

sheremet-va avatar Sep 09 '23 14:09 sheremet-va

WOW! Yes that works.

I added

server: {
		fs: {
			strict: false,
		},
	},

Primajin avatar Sep 09 '23 14:09 Primajin

OK I fiddled around a little bit more and went with the following instead:

		fs: {
			allow: [searchForWorkspaceRoot(process.cwd()), __dirname],
		},

which seems redundant but gets the job done

Primajin avatar Sep 09 '23 15:09 Primajin

So I assume something like searchForWorkspaceRoot(process.cwd()) is built in as default setting.

What we could do is to check if searchForWorkspaceRoot(process.cwd()) !== __dirname and then also add __dirname to the allowlist.

I guess I would either hook in here: https://github.com/vitejs/vite/blob/c7969597caba80cf5d3348cba9f18ad9d14e9295/packages/vite/src/node/config.ts#L499

or here: https://github.com/vitejs/vite/blob/c7969597caba80cf5d3348cba9f18ad9d14e9295/packages/vite/src/node/server/index.ts#L801

🤔

I would be very happy to submit a PR if you think it makes sense.

Cheers! 👋🏻

Primajin avatar Sep 13 '23 08:09 Primajin

I guess I would either hook in here

Actually, we already override it:

https://github.com/vitest-dev/vitest/blob/b75f91d26529d7c6a09bd1d9149e8672c5de978e/packages/vitest/src/node/plugins/utils.ts#L102

But we use config file for it, not process.cwd() (which can be system root in docker for example)

sheremet-va avatar Sep 13 '23 08:09 sheremet-va

Yeah but do I understand it correctly that when the config file is empty we fall back to process.cwd()? And apparently when you are in a symlinked folder on windows it seems like that process.cwd() and __dirname (given __dirname = path.dirname(fileURLToPath(import.meta.url));) return different paths while on UNIX~oid systems they are the same. 🤔

// test-paths.mjs
import path from 'node:path';
import process from 'node:process';
import {fileURLToPath} from 'node:url';

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const processCWD = process.cwd();

console.log('__dirname', __dirname);
console.log('processCWD', processCWD);

I ran the above script in macOSX and Windows and got the following results:

Given folders dev and dev2 --> dev

Screenshot 2023-09-13 at 11 33 15
Screenshot 2023-09-13 at 11 34 27

The folders are the same.

While on Windows given folders folderA and folderB --> folderA

folders2

folders

Primajin avatar Sep 13 '23 09:09 Primajin

So maybe we just need to change it to use __dirname instead of process.cwd() and it will work for all 🤔

Primajin avatar Sep 13 '23 13:09 Primajin

__dirname would be the Vitest dist folder though.

sheremet-va avatar Oct 01 '24 14:10 sheremet-va

I just ran into this issue, also, and was glad to find the workarounds posted in this thread. In my case I was attempting to include tests from a child package that was setup using npm link (which uses symlinks) rather than npm install.

I used:

defineConfig({
  ...
  server: { fs: { strict: false }}, // allows Vitest to load files across symlinks
})

...although I have no idea what this setting actually does. Sounds insecure.

Anyway, it solved the issue of running test files across symlinks, sort of.

However I still get various quirks where Vitest doesn't detect changes to files properly in watch mode:

  1. When I change a test file that's located in a symlinked folder, Vitest does NOT detect the change, even if I choose "Rerun all tests". I have to quit Vitest and run it again for the change to be picked up. It seems to be cached somewhere.

  2. When I change a file that is the test target, only non-symlinked tests are re-run. I have to choose "Rerun all tests" to run the symlinked ones (even if they import the target file I've just modified)

If anyone looks further into this issue, hopefully the above notes are helpful.

UPDATE: Actually, apparently Vite doesn't yet support watching folders inside node_modules without complex workarounds, so maybe that is more the cause of my quirks, rather than the symlinking, see https://github.com/vitejs/vite/issues/8619.

SimonEast avatar Apr 27 '25 10:04 SimonEast

This issue was resolved. If you have a similar issue that is not fixed by proposed solutions in this thread, please open a new issue with a reproduction.

sheremet-va avatar Nov 27 '25 13:11 sheremet-va