backend-test-utils: add MockDirectory content callback + default file modes

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2023-10-05 21:29:15 +02:00
parent 12da2feccb
commit 45f9748e43
4 changed files with 77 additions and 5 deletions
+16 -1
View File
@@ -54,9 +54,24 @@ export interface MockDirectory {
// @public
export type MockDirectoryContent = {
[name in string]: MockDirectoryContent | string | Buffer;
[name in string]:
| MockDirectoryContent
| string
| Buffer
| MockDirectoryContentCallback;
};
// @public
export type MockDirectoryContentCallback = (
ctx: MockDirectoryContentCallbackContext,
) => void;
// @public
export interface MockDirectoryContentCallbackContext {
path: string;
symlink(target: string): void;
}
// @public
export interface MockDirectoryContentOptions {
path?: string;
@@ -119,6 +119,20 @@ describe('createMockDirectory', () => {
});
});
it('should be able to use callback for more detailed file system operations', () => {
mockDir.setContent({
'a.txt': 'a',
'b.txt': ctx => ctx.symlink('./a.txt'),
'c.txt': ctx => fs.copyFileSync(mockDir.resolve('a.txt'), ctx.path),
});
expect(mockDir.content()).toEqual({
'a.txt': 'a',
'b.txt': 'a',
'c.txt': 'a',
});
});
it('should read content from sub dirs', () => {
mockDir.setContent({
'a.txt': 'a',
@@ -30,6 +30,28 @@ import {
const tmpdirMarker = Symbol('os-tmpdir-mock');
/**
* A context that allows for more advanced file system operations when writing mock directory content.
*
* @public
*/
export interface MockDirectoryContentCallbackContext {
/** Absolute path to the location of this piece of content on the filesystem */
path: string;
/** Creates a symbolic link at the current location */
symlink(target: string): void;
}
/**
* A callback that allows for more advanced file system operations when writing mock directory content.
*
* @public
*/
export type MockDirectoryContentCallback = (
ctx: MockDirectoryContentCallbackContext,
) => void;
/**
* The content of a mock directory represented by a nested object structure.
*
@@ -54,7 +76,11 @@ const tmpdirMarker = Symbol('os-tmpdir-mock');
* @public
*/
export type MockDirectoryContent = {
[name in string]: MockDirectoryContent | string | Buffer;
[name in string]:
| MockDirectoryContent
| string
| Buffer
| MockDirectoryContentCallback;
};
/**
@@ -178,6 +204,11 @@ type MockEntry =
| {
type: 'dir';
path: string;
}
| {
type: 'callback';
path: string;
callback: MockDirectoryContentCallback;
};
/** @internal */
@@ -214,10 +245,18 @@ class MockDirectoryImpl {
}
if (entry.type === 'dir') {
fs.ensureDirSync(fullPath, { mode: 0o777 });
fs.ensureDirSync(fullPath);
} else if (entry.type === 'file') {
fs.ensureDirSync(dirname(fullPath), { mode: 0o777 });
fs.writeFileSync(fullPath, entry.content, { mode: 0o666 });
fs.ensureDirSync(dirname(fullPath));
fs.writeFileSync(fullPath, entry.content);
} else if (entry.type === 'callback') {
fs.ensureDirSync(dirname(fullPath));
entry.callback({
path: fullPath,
symlink(target: string) {
fs.symlinkSync(target, fullPath);
},
});
}
}
}
@@ -287,6 +326,8 @@ class MockDirectoryImpl {
});
} else if (node instanceof Buffer) {
entries.push({ type: 'file', path, content: node });
} else if (typeof node === 'function') {
entries.push({ type: 'callback', path, callback: node });
} else {
entries.push({ type: 'dir', path });
for (const [name, child] of Object.entries(node)) {
@@ -20,4 +20,6 @@ export {
type MockDirectoryOptions,
type MockDirectoryContent,
type MockDirectoryContentOptions,
type MockDirectoryContentCallback,
type MockDirectoryContentCallbackContext,
} from './MockDirectory';