Skip to content

Commit

Permalink
chore: replace mock-fs with memfs
Browse files Browse the repository at this point in the history
  • Loading branch information
duniul committed Jul 8, 2023
1 parent 02e4c39 commit f554394
Show file tree
Hide file tree
Showing 12 changed files with 143 additions and 145 deletions.
3 changes: 3 additions & 0 deletions __mocks__/fs/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { fs } from 'memfs';

module.exports = fs
3 changes: 3 additions & 0 deletions __mocks__/fs/promises.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { fs } from 'memfs';

module.exports = fs
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
"@types/supports-color": "8.1.1",
"@types/yargs": "17.0.3",
"changesets-changelog-clean": "^1.1.0",
"mock-fs": "5.2.0",
"memfs": "^4.2.0",
"prettier": "3.0.0",
"prettier-plugin-organize-imports": "3.2.2",
"rome": "^12.1.3",
Expand Down
8 changes: 8 additions & 0 deletions src/__test__/fixtures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { GlobLists } from '../types';

export const EMPTY_GLOB_LISTS: GlobLists = {
included: [],
includedDirs: [],
excluded: [],
originalIncluded: [],
};
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
import fs from 'fs';
import { vi } from 'vitest';
import { DEFAULT_GLOBS_FILE_PATH } from '../constants';
import { GlobLists } from '../types';

export const EMPTY_GLOB_LISTS: GlobLists = {
included: [],
includedDirs: [],
excluded: [],
originalIncluded: [],
};

export function getMockedFileStructure(nodeModulesPath: string): Record<string, any> {
const stringifiedDefaultGlobs = fs.readFileSync(DEFAULT_GLOBS_FILE_PATH).toString();
export async function getMockedFileStructure(): Promise<Record<string, any>> {
const actualFs = await vi.importActual<typeof fs.promises>('fs/promises');
const defaultGlobs = (await actualFs.readFile(DEFAULT_GLOBS_FILE_PATH)).toString();

return {
[DEFAULT_GLOBS_FILE_PATH]: stringifiedDefaultGlobs,
[nodeModulesPath]: {
[DEFAULT_GLOBS_FILE_PATH]: defaultGlobs,
node_modules: {
dep1: {
__tests__: {
'test1.js': '.',
Expand Down
54 changes: 21 additions & 33 deletions src/analyze.test.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,24 @@
import mockFs from 'mock-fs';
import { fs, vol } from 'memfs';
import path from 'path';
import { afterEach, beforeEach, describe, expect, it, SpyInstance, vi } from 'vitest';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { getMockedFileStructure } from './__test__/getMockedFileStructure';
import { analyzeIncluded } from './analyze';
import { EMPTY_GLOB_LISTS, getMockedFileStructure } from './__fixtures__/fixtures';
import { EMPTY_GLOB_LISTS } from './__test__/fixtures';

const mockCwd = '/';
const mockNodeModulesPath = mockCwd + 'node_modules';
const mockedFileStructure = getMockedFileStructure(mockNodeModulesPath);
const nodeModulesPath = 'node_modules';

let cwdSpy: SpyInstance<[], string>;

beforeEach(() => {
cwdSpy = vi.spyOn(process, 'cwd').mockReturnValue(mockCwd);
mockFs(mockedFileStructure);
beforeEach(async () => {
const fileStructure = await getMockedFileStructure();
vol.fromNestedJSON(fileStructure);
});

afterEach(() => {
cwdSpy.mockRestore();
mockFs.restore();
vol.reset();
});

describe('analyzeIncluded', () => {
beforeEach(() => {
mockFs(mockedFileStructure);
});

it('returns expected result', async () => {
const results = await analyzeIncluded(mockNodeModulesPath, {
const results = await analyzeIncluded(nodeModulesPath, {
...EMPTY_GLOB_LISTS,
included: ['**/__tests__/**', '**/dep3/**'],
includedDirs: ['**/__tests__', '**/dep3'],
Expand All @@ -35,29 +27,25 @@ describe('analyzeIncluded', () => {

expect(results).toEqual([
{
filePath: mockCwd + path.join('node_modules', 'dep1', '__tests__', 'test1.js'),
filePath: path.join('node_modules', 'dep1', '__tests__', 'test1.js'),
includedByDefault: true,
includedByGlobs: [
{ derived: mockCwd + 'node_modules/**/__tests__/**', original: '__tests__' },
],
includedByGlobs: [{ derived: 'node_modules/**/__tests__/**', original: '__tests__' }],
},
{
filePath: mockCwd + path.join('node_modules', 'dep1', '__tests__', 'test2.js'),
filePath: path.join('node_modules', 'dep1', '__tests__', 'test2.js'),
includedByDefault: true,
includedByGlobs: [
{ derived: mockCwd + 'node_modules/**/__tests__/**', original: '__tests__' },
],
includedByGlobs: [{ derived: 'node_modules/**/__tests__/**', original: '__tests__' }],
},
{
filePath: mockCwd + path.join('node_modules', 'dep3', 'deeply', 'nested', 'file.ext'),
filePath: path.join('node_modules', 'dep3', 'deeply', 'nested', 'file.ext'),
includedByDefault: false,
includedByGlobs: [{ derived: mockCwd + 'node_modules/**/dep3/**', original: 'dep3' }],
includedByGlobs: [{ derived: 'node_modules/**/dep3/**', original: 'dep3' }],
},
]);
});

it('says if a file was excluded or not', async () => {
const results = await analyzeIncluded(mockNodeModulesPath, {
const results = await analyzeIncluded(nodeModulesPath, {
...EMPTY_GLOB_LISTS,
included: ['**/tsconfig.json', '**/file.js'],
originalIncluded: ['tsconfig.json', 'file.js'],
Expand All @@ -68,19 +56,19 @@ describe('analyzeIncluded', () => {
});

it('lists what globs (original and derived version) included the file', async () => {
const results = await analyzeIncluded(mockNodeModulesPath, {
const results = await analyzeIncluded(nodeModulesPath, {
...EMPTY_GLOB_LISTS,
included: ['**/*.json', '**/tsconfig.json', '**/file.js'],
originalIncluded: ['*.json', 'tsconfig.json', 'file.js'],
});

expect(results[0]).toHaveProperty('includedByGlobs', [
{ derived: mockCwd + 'node_modules/**/file.js', original: 'file.js' },
{ derived: 'node_modules/**/file.js', original: 'file.js' },
]);

expect(results[1]).toHaveProperty('includedByGlobs', [
{ derived: mockCwd + 'node_modules/**/*.json', original: '*.json' },
{ derived: mockCwd + 'node_modules/**/tsconfig.json', original: 'tsconfig.json' },
{ derived: 'node_modules/**/*.json', original: '*.json' },
{ derived: 'node_modules/**/tsconfig.json', original: 'tsconfig.json' },
]);
});
});
70 changes: 27 additions & 43 deletions src/clean.test.ts
Original file line number Diff line number Diff line change
@@ -1,74 +1,62 @@
import fs from 'fs';
import mockFs from 'mock-fs';
import { vol } from 'memfs';
import path from 'path';
import { afterEach, beforeEach, describe, expect, it, SpyInstance, vi } from 'vitest';
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { EMPTY_GLOB_LISTS } from './__test__/fixtures';
import { getMockedFileStructure } from './__test__/getMockedFileStructure';
import { findFilesToRemove, removeEmptyDirs, removeFiles } from './clean';
import { EMPTY_GLOB_LISTS, getMockedFileStructure } from './__fixtures__/fixtures';

const mockCwd = '/';
const mockNodeModulesPath = mockCwd + 'node_modules';
const mockedFileStructure = getMockedFileStructure(mockNodeModulesPath);
const nodeModulesPath = 'node_modules';

let cwdSpy: SpyInstance<[], string>;

beforeEach(() => {
cwdSpy = vi.spyOn(process, 'cwd').mockReturnValue(mockCwd);
mockFs(mockedFileStructure);
beforeEach(async () => {
const fileStructure = await getMockedFileStructure();
vol.fromNestedJSON(fileStructure);
});

afterEach(() => {
cwdSpy.mockRestore();
mockFs.restore();
vol.reset();
});

describe('findFilesToRemove', () => {
beforeEach(() => {
mockFs(mockedFileStructure);
});

it('includes dirs', async () => {
const result = await findFilesToRemove(mockNodeModulesPath, {
const result = await findFilesToRemove(nodeModulesPath, {
...EMPTY_GLOB_LISTS,
includedDirs: ['**/__tests__', '**/dep3'],
});

expect(result).toEqual([
mockCwd + path.join('node_modules', 'dep1', '__tests__', 'test1.js'),
mockCwd + path.join('node_modules', 'dep1', '__tests__', 'test2.js'),
mockCwd + path.join('node_modules', 'dep3', 'deeply', 'nested', 'file.ext'),
path.join('node_modules', 'dep1', '__tests__', 'test1.js'),
path.join('node_modules', 'dep1', '__tests__', 'test2.js'),
path.join('node_modules', 'dep3', 'deeply', 'nested', 'file.ext'),
]);
});

it('includes files', async () => {
const result = await findFilesToRemove(mockNodeModulesPath, {
const result = await findFilesToRemove(nodeModulesPath, {
...EMPTY_GLOB_LISTS,
included: ['**/deeply/nested/file.ext', '**/dep4/**'],
});

expect(result).toEqual([
mockCwd + path.join('node_modules', 'dep4', 'nonDefaultFile.ext'),
mockCwd + path.join('node_modules', 'dep3', 'deeply', 'nested', 'file.ext'),
path.join('node_modules', 'dep4', 'nonDefaultFile.ext'),
path.join('node_modules', 'dep3', 'deeply', 'nested', 'file.ext'),
]);
});

it('can exclude files and dirs by glob patterns', async () => {
const result = await findFilesToRemove(mockNodeModulesPath, {
const result = await findFilesToRemove(nodeModulesPath, {
...EMPTY_GLOB_LISTS,
included: ['**/*.js'],
excluded: ['**/test*.js'],
});

expect(result).toEqual([mockCwd + path.join('node_modules', 'dep2', 'file.js')]);
expect(result).toEqual([path.join('node_modules', 'dep2', 'file.js')]);
});
});

describe('removeFiles', () => {
beforeEach(() => {
mockFs(mockedFileStructure);
});

it('removes files at provided file paths', async () => {
const filePaths = ['/node_modules/dep1/__tests__/test1.js', '/node_modules/dep1/a-dir/doc.md'];
const filePaths = ['node_modules/dep1/__tests__/test1.js', 'node_modules/dep1/a-dir/doc.md'];

// files are initially there
expect(fs.existsSync(filePaths[0])).toBe(true);
Expand All @@ -82,7 +70,7 @@ describe('removeFiles', () => {
});

it('does not remove files during dry runs', async () => {
const filePaths = ['/node_modules/dep1/__tests__/test1.js', '/node_modules/dep1/a-dir/doc.md'];
const filePaths = ['node_modules/dep1/__tests__/test1.js', 'node_modules/dep1/a-dir/doc.md'];

await removeFiles(filePaths, { dryRun: true });

Expand All @@ -97,26 +85,22 @@ describe('removeFiles', () => {
});

describe('removeEmptyDirs', () => {
beforeEach(() => {
mockFs(mockedFileStructure);
});

it('cleans up empty parent dirs for provided files', async () => {
const filePaths = [
'/node_modules/dep1/__tests__/test1.js',
'/node_modules/dep1/a-dir/doc.md',
'/node_modules/dep2/tsconfig.json',
'/node_modules/dep2/file.js',
'node_modules/dep1/__tests__/test1.js',
'node_modules/dep1/a-dir/doc.md',
'node_modules/dep2/tsconfig.json',
'node_modules/dep2/file.js',
];

// remove files before testing
filePaths.forEach(filePath => fs.unlinkSync(filePath));

await removeEmptyDirs(filePaths);

expect(fs.existsSync('/node_modules/dep1/__tests__')).toBe(true); // not empty and not removed
expect(fs.existsSync('/node_modules/dep1/a-dir')).toBe(false); // empty and removed
expect(fs.existsSync('/node_modules/dep2')).toBe(false); // empty and removed
expect(fs.existsSync('node_modules/dep1/__tests__')).toBe(true); // not empty and not removed
expect(fs.existsSync('node_modules/dep1/a-dir')).toBe(false); // empty and removed
expect(fs.existsSync('node_modules/dep2')).toBe(false); // empty and removed
});

it('does not throw if path is invalid', async () => {
Expand Down
Loading

0 comments on commit f554394

Please sign in to comment.