Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug: fs.readdirSync with recursive option not working #417

Open
benhovinga opened this issue Feb 23, 2025 · 0 comments
Open

bug: fs.readdirSync with recursive option not working #417

benhovinga opened this issue Feb 23, 2025 · 0 comments

Comments

@benhovinga
Copy link

The recursive option on fs.readdirSync is not working as expected when using mock-fs.

version: "mock-fs": "^5.5.0"

Failing test with mock-fs

This test should pass but it doesn't.

import { expect, test } from '@jest/globals';
import fs from 'fs';
import mockFS from 'mock-fs';

beforeEach(function () {
  mockFS({
    'path/to/example': {
      'file1.txt': 'file contents',
      dir: {
        'file2.txt': 'file contents',
        subdir: {
          'file3.txt': 'file contents'
        }
      }
    }
  });
});

afterEach(mockFS.restore);

test.only('get mocked files', () => {
  const files = fs.readdirSync('./path/to/example/', {
    recursive: true
  });
  expect(files).toEqual([
    'dir',
    'file1.txt',
    'dir/file2.txt',
    'dir/subdir',
    'dir/subdir/file3.txt'
  ]);
});

Test results:

> jest "test/test.spec.ts"

 FAIL  test/test.spec.ts
  ✕ get mocked files (3 ms)

  ● get mocked files

    expect(received).toEqual(expected) // deep equality

    - Expected  - 3
    + Received  + 0

      Array [
        "dir",
        "file1.txt",
    -   "dir/file2.txt",
    -   "dir/subdir",
    -   "dir/subdir/file3.txt",
      ]

      23 |     recursive: true
      24 |   });
    > 25 |   expect(files).toEqual([
         |                 ^
      26 |     'dir',
      27 |     'file1.txt',
      28 |     'dir/file2.txt',

      at Object.<anonymous> (test/test.spec.ts:25:17)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        0.117 s, estimated 1 s
Ran all test suites matching /test\/test.spec.ts/i.
 ELIFECYCLE  Test failed. See above for more details.

Passing test with fs

I commented out the mock-fs configuration and I created the same directory structure on my system. I ran the test again and I got the the test passed. So we know fs.readdirSync is working.

- ./path/to/example/
   - file1.txt
   - dir/
      - file2.txt
      - subdir/
         - file3.txt
import { expect, test } from '@jest/globals';
import fs from 'fs';
// import mockFS from 'mock-fs';

// beforeEach(function () {
//   mockFS({
//     'path/to/example': {
//       'file1.txt': 'file contents',
//       dir: {
//         'file2.txt': 'file contents',
//         subdir: {
//           'file3.txt': 'file contents'
//         }
//       }
//     }
//   });
// });

// afterEach(mockFS.restore);

test.only('get mocked files', () => {
  const files = fs.readdirSync('./path/to/example/', {
    recursive: true
  });
  expect(files).toEqual([
    'dir',
    'file1.txt',
    'dir/file2.txt',
    'dir/subdir',
    'dir/subdir/file3.txt'
  ]);
});

Test results:

> jest "test/test.spec.ts"

 PASS  test/test.spec.ts
  ✓ get mocked files (2 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.095 s, estimated 1 s
Ran all test suites matching /test\/test.spec.ts/i.

Its a trap!

After testing the native fs I removed the comments to re-enable mock-fs and now the test is passing with mocks. As it turns out it is still looking into the ./path/to/example/ directory I created on my filesystem.

It looks like mock-fs is still adding the mocked files into the list and fs merges any remaining on top.

If I add another file to the mock path at this point it fails with 1 extra file in the list.

  mockFS({
    'path/to/example': {
      'file1.txt': 'file contents',
      dir: {
        'file2.txt': 'file contents',
        subdir: {
          'file3.txt': 'file contents',
          'file4.txt': 'file contents'  // <-- Extra
        }
      }
    }
  });
> jest "test/test.spec.ts"

 FAIL  test/test.spec.ts
  ✕ get mocked files (4 ms)

  ● get mocked files

    expect(received).toEqual(expected) // deep equality

    - Expected  - 0
    + Received  + 1

    @@ -2,6 +2,7 @@
        "dir",
        "file1.txt",
        "dir/file2.txt",
        "dir/subdir",
        "dir/subdir/file3.txt",
    +   "dir/subdir/file4.txt",
      ]

      24 |     recursive: true
      25 |   });
    > 26 |   expect(files).toEqual([
         |                 ^
      27 |     'dir',
      28 |     'file1.txt',
      29 |     'dir/file2.txt',

      at Object.<anonymous> (test/test.spec.ts:26:17)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        0.137 s, estimated 1 s
Ran all test suites matching /test\/test.spec.ts/i.
 ELIFECYCLE  Test failed. See above for more details.

But if I remove the directory from my filesystem it goes back to missing all of the recursive directories again and doesn't show the extra file4.txt I added above.

> jest "test/test.spec.ts"

 FAIL  test/test.spec.ts
  ✕ get mocked files (3 ms)

  ● get mocked files

    expect(received).toEqual(expected) // deep equality

    - Expected  - 3
    + Received  + 0

      Array [
        "dir",
        "file1.txt",
    -   "dir/file2.txt",
    -   "dir/subdir",
    -   "dir/subdir/file3.txt",
      ]

      24 |     recursive: true
      25 |   });
    > 26 |   expect(files).toEqual([
         |                 ^
      27 |     'dir',
      28 |     'file1.txt',
      29 |     'dir/file2.txt',

      at Object.<anonymous> (test/test.spec.ts:26:17)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        0.119 s, estimated 1 s
Ran all test suites matching /test\/test.spec.ts/i.
 ELIFECYCLE  Test failed. See above for more details.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant