Skip to content

Commit

Permalink
feat(core): simplified reading and writing files in CrewMembers using…
Browse files Browse the repository at this point in the history
… the FileSystem

being able to directly read files from the file system in crew members should enable services like
the ConsoleReporter to display code snippets and will enable refactoring the artifact handling
mechanism in the SerenityBDDReporter

Related tickets: re #2244
  • Loading branch information
jan-molak committed Mar 2, 2024
1 parent 20afc8b commit 7f0d0cc
Show file tree
Hide file tree
Showing 8 changed files with 281 additions and 127 deletions.
42 changes: 5 additions & 37 deletions packages/core/spec/FakeFS.ts
@@ -1,44 +1,12 @@
import fs = require('fs');
import path = require('upath');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { createFsFromVolume, Volume } = require('memfs'); // Typings incorrectly assume the presence of "dom" lib
import type * as fs from 'node:fs';

export interface DirectoryStructure {
[ key: string ]: DirectoryStructure | string;
}
import type { NestedDirectoryJSON} from 'memfs';
import { createFsFromVolume, Volume } from 'memfs';

export class FakeFS {
public static readonly Empty_Directory = {};

static with(tree: DirectoryStructure, cwd = process.cwd()): typeof fs {

function flatten(
currentStructure: DirectoryStructure | string,
currentPath = '',
): { [key: string]: string } {

if (typeof currentStructure === 'string') {
return ({
[ currentPath ]: currentStructure,
});
}

const entries = Object.keys(currentStructure);

if (entries.length === 0) {
return ({
[ currentPath ]: void 0,
});
}

return Object.keys(currentStructure).reduce((acc, key) => {
return ({
...acc,
...flatten(currentStructure[key], path.join(currentPath, key)),
});
}, {});
}

return createFsFromVolume(Volume.fromJSON(flatten(tree), cwd)) as typeof fs;
static with(tree: NestedDirectoryJSON, cwd = process.cwd()): typeof fs {
return createFsFromVolume(Volume.fromNestedJSON(tree, cwd)) as unknown as typeof fs;
}
}
76 changes: 74 additions & 2 deletions packages/core/spec/io/FileSystem.spec.ts
Expand Up @@ -78,8 +78,8 @@ describe ('FileSystem', () => {
it (`complains when the file can't be written`, () => {
const fs = FakeFS.with(FakeFS.Empty_Directory);

(fs as any).writeFile = () => { // memfs doesn't support mocking error conditions or permissions
throw new Error('EACCES, permission denied');
(fs as any).promises.writeFile = () => { // memfs doesn't support mocking error conditions or permissions
return Promise.reject(new Error('EACCES, permission denied'));
};

const out = new FileSystem(new Path('/'), fs);
Expand Down Expand Up @@ -119,6 +119,78 @@ describe ('FileSystem', () => {
});
});

describe('when reading files', () => {

describe('synchronously', () => {

it('returns the contents', async () => {
const
fs = FakeFS.with({
[processCWD.value]: {
'file.txt': 'contents'
},
}),
out = new FileSystem(processCWD, fs);

const result = out.readFileSync(new Path('file.txt'), { encoding: 'utf8' });

expect(result).to.equal('contents');
});
});

describe('asynchronously', () => {

it('returns a Promise of the contents', async () => {
const
fs = FakeFS.with({
[processCWD.value]: {
'file.txt': 'contents'
},
}),
out = new FileSystem(processCWD, fs);

const result = await out.readFile(new Path('file.txt'), { encoding: 'utf8' });

expect(result).to.equal('contents');
});
});
});

describe('when writing files', () => {

describe('synchronously', () => {

it('writes the contents', async () => {
const
fs = FakeFS.with({
[processCWD.value]: {
},
}),
out = new FileSystem(processCWD, fs);

const absolutePathToFile = out.writeFileSync(new Path('file.txt'), 'contents', { encoding: 'utf8' });

expect(absolutePathToFile).to.equal(processCWD.resolve(new Path('file.txt')));
});
});

describe('asynchronously', () => {

it('writes the contents', async () => {
const
fs = FakeFS.with({
[processCWD.value]: {
},
}),
out = new FileSystem(processCWD, fs);

const absolutePathToFile = await out.writeFile(new Path('file.txt'), 'contents', { encoding: 'utf8' });

expect(absolutePathToFile).to.equal(processCWD.resolve(new Path('file.txt')));
});
});
});

describe ('when removing', () => {

describe('individual files', () => {
Expand Down
57 changes: 56 additions & 1 deletion packages/core/spec/io/Version.spec.ts
@@ -1,4 +1,5 @@
import { describe, it } from 'mocha';
import { given } from 'mocha-testdata';

import { Version } from '../../src/io';
import { expect } from '../expect';
Expand All @@ -9,11 +10,65 @@ describe('Version', () => {
expect(new Version('1.2.3').isAtLeast(new Version('1.0.0'))).to.equal(true);
});

it('grants access to the major version number', () => {
it('tells the major version number', () => {
expect(new Version('1.2.3').major()).to.equal(1);
});

it('provides a sensible description', () => {
expect(new Version('1.2.3').toString()).to.equal('1.2.3');
});

given([
{ range: '1.x', expected: true },
{ range: '0.x || >=1.2', expected: true },
{ range: '^1', expected: true },
{ range: '0.x || 2.x', expected: false },
]).
it('checks if the version satisfies a given range', ({ range, expected }) => {
expect(new Version('1.2.3').satisfies(range)).to.equal(expected);
});

given([
{ version: '1.2.2', expected: true },
{ version: '1.2.3', expected: false },
{ version: '1.2.4', expected: false },
]).
it('tells if it is lower than another version', ({ version, expected }) => {
expect(new Version(version).isLowerThan(new Version('1.2.3'))).to.equal(expected);
});

given([
{ version: '1.2.2', expected: true },
{ version: '1.2.3', expected: true },
{ version: '1.2.4', expected: false },
]).
it('tells if it is at most another version', ({ version, expected }) => {
expect(new Version(version).isAtMost(new Version('1.2.3'))).to.equal(expected);
});

given([
{ version: '1.2.2', expected: false },
{ version: '1.2.3', expected: true },
{ version: '1.2.4', expected: true },
]).
it('tells if it is at least another version', ({ version, expected }) => {
expect(new Version(version).isAtLeast(new Version('1.2.3'))).to.equal(expected);
});

given([
{ version: '1.2.2', expected: false },
{ version: '1.2.3', expected: false },
{ version: '1.2.4', expected: true },
]).
it('tells if it is higher than another version', ({ version, expected }) => {
expect(new Version(version).isHigherThan(new Version('1.2.3'))).to.equal(expected);
});

it('tells if it is equal to another version', () => {
expect(new Version('1.2.3').equals(new Version('1.2.3'))).to.equal(true);
});

it('can be created from a JSON string', () => {
expect(Version.fromJSON('1.2.3')).to.equal(new Version('1.2.3'));
});
});

0 comments on commit 7f0d0cc

Please sign in to comment.