Skip to content

Commit

Permalink
Implement withSpawnMock
Browse files Browse the repository at this point in the history
  • Loading branch information
mshima committed Sep 25, 2023
1 parent d6be388 commit db151cc
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 15 deletions.
24 changes: 24 additions & 0 deletions src/run-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { camelCase, kebabCase, merge as lodashMerge, set as lodashSet } from 'lo
import { resetFileCommitStates } from 'mem-fs-editor/state';
import { create as createMemFs, type Store } from 'mem-fs';
import tempDirectory from 'temp-dir';
import { stub as sinonStub } from 'sinon';
import type {
BaseEnvironmentOptions,
BaseGenerator,
Expand Down Expand Up @@ -72,6 +73,7 @@ export class RunContextBase<GeneratorType extends BaseGenerator = DefaultGenerat
targetDirectory?: string;
editor!: MemFsEditor;
memFs: Store<MemFsEditorFile>;
spawnStub?: any;
mockedGeneratorFactory: MockedGeneratorFactory;

protected environmentPromise?: PromiseRunResult<GeneratorType>;
Expand Down Expand Up @@ -404,6 +406,27 @@ export class RunContextBase<GeneratorType extends BaseGenerator = DefaultGenerat
});
}

withSpawnMock(stub = sinonStub()): this {
if (this.spawnStub) {
throw new Error('Multiple withSpawnMock calls');
}

this.spawnStub = stub;
return this.onEnvironment(env => {
env.on('compose', (_namespace, generator) => {
const createCallback = method =>
function (this: any, ...args) {
stub.call(this, method, ...args);
};

generator.spawnCommand = createCallback('spawnCommand');
generator.spawnCommandSync = createCallback('spawnCommandSync');
generator.spawn = createCallback('spawn');
generator.spawnSync = createCallback('spawnSync');
});
});
}

withMockedGeneratorFactory(mockedGeneratorFactory: MockedGeneratorFactory): this {
this.mockedGeneratorFactory = mockedGeneratorFactory;
return this;
Expand Down Expand Up @@ -671,6 +694,7 @@ export class RunContextBase<GeneratorType extends BaseGenerator = DefaultGenerat
settings: {
...this.settings,
},
spawnStub: this.spawnStub,
oldCwd: this.oldCwd!,
cwd: this.targetDirectory!,
envOptions: this.envOptions,
Expand Down
12 changes: 12 additions & 0 deletions src/run-result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ export type RunResultOptions<GeneratorType extends BaseGenerator> = {
*/
mockedGenerators: Record<string, BaseGenerator>;

spawnStub?: any;

settings: RunContextSettings;

helpers: YeomanTest;
Expand All @@ -73,6 +75,7 @@ export default class RunResult<GeneratorType extends BaseGenerator = BaseGenerat
fs: MemFsEditor;
mockedGenerators: any;
options: RunResultOptions<GeneratorType>;
spawnStub?: any;

constructor(options: RunResultOptions<GeneratorType>) {
if (options.memFs && !options.cwd) {
Expand All @@ -86,6 +89,7 @@ export default class RunResult<GeneratorType extends BaseGenerator = BaseGenerat
this.memFs = options.memFs;
this.fs = this.memFs && createMemFsEditor(this.memFs);
this.mockedGenerators = options.mockedGenerators || {};
this.spawnStub = options.spawnStub;
this.options = options;
}

Expand All @@ -112,6 +116,14 @@ export default class RunResult<GeneratorType extends BaseGenerator = BaseGenerat
);
}

getSpawnArgsUsingDefaultImplementation() {
if (!this.spawnStub) {
throw new Error('Spawn stub was not found');
}

return this.spawnStub.getCalls().map(call => call.args);
}

/**
* Return an object with fs changes.
* @param {Function} filter - parameter forwarded to mem-fs-editor#dump
Expand Down
48 changes: 33 additions & 15 deletions test/run-context.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ describe('RunContext', function () {
const ctx = new RunContext(require.resolve('./fixtures/generator-simple/app'));

ctx
.on('ready', function () {
assert(ctx.env.get('simple:app'));
.on('ready', async function () {
assert(await ctx.env.get('simple:app'));
})
.on('end', done);
});
Expand All @@ -92,8 +92,8 @@ describe('RunContext', function () {
});

it('accept generator constructor parameter (and assign gen:test as namespace)', function (done) {
ctx.on('ready', function () {
assert(ctx.env.get('gen:test'));
ctx.on('ready', async function () {
assert(await ctx.env.get('gen:test'));
done();
});
});
Expand Down Expand Up @@ -606,27 +606,27 @@ describe('RunContext', function () {
describe('#withMockedGenerators()', function () {
it('creates mocked generator', async function () {
await ctx.withMockedGenerators(['foo:bar']).build();
assert(ctx.env.get('foo:bar'));
assert(await ctx.env.get('foo:bar'));
assert(ctx.mockedGenerators['foo:bar']);
});
});

describe('#withGenerators()', function () {
it('register paths', function (done) {
ctx.withGenerators([require.resolve('./fixtures/generator-simple/app')]).on('ready', function () {
assert(ctx.env.get('simple:app'));
ctx.withGenerators([require.resolve('./fixtures/generator-simple/app')]).on('ready', async function () {
assert(await ctx.env.get('simple:app'));
done();
});
});

it('register paths with namespaces', async function () {
await ctx.withGenerators([[require.resolve('./fixtures/generator-simple/app'), { namespace: 'foo:bar' }]]).build();
assert(ctx.env.get('foo:bar'));
assert(await ctx.env.get('foo:bar'));
});

it('register mocked generator', function (done) {
ctx.withGenerators([[helpers.createDummyGenerator(), { namespace: 'dummy:gen' }]]).on('ready', function () {
assert(ctx.env.get('dummy:gen'));
ctx.withGenerators([[helpers.createDummyGenerator(), { namespace: 'dummy:gen' }]]).on('ready', async function () {
assert(await ctx.env.get('dummy:gen'));
done();
});
});
Expand All @@ -635,23 +635,41 @@ describe('RunContext', function () {
ctx
.withGenerators([require.resolve('./fixtures/generator-simple/app')])
.withGenerators([[helpers.createDummyGenerator(), { namespace: 'dummy:gen' }]])
.on('ready', function () {
assert(ctx.env.get('dummy:gen'));
assert(ctx.env.get('simple:app'));
.on('ready', async function () {
assert(await ctx.env.get('dummy:gen'));
assert(await ctx.env.get('simple:app'));
done();
});
});
});

describe('#withSpawnMock()', function () {
it('provide arguments to the generator when passed as String', async function () {
ctx.withSpawnMock();
Dummy.prototype.mockTask = async function () {
await this.spawnCommand('foo');
this.spawnCommandSync('foo');
await this.spawn('foo');
this.spawnSync('foo');
};

const result = await ctx.toPromise();
assert.deepStrictEqual(result.getSpawnArgsUsingDefaultImplementation()[0], ['spawnCommand', 'foo']);
assert.deepStrictEqual(result.getSpawnArgsUsingDefaultImplementation()[1], ['spawnCommandSync', 'foo']);
assert.deepStrictEqual(result.getSpawnArgsUsingDefaultImplementation()[2], ['spawn', 'foo']);
assert.deepStrictEqual(result.getSpawnArgsUsingDefaultImplementation()[3], ['spawnSync', 'foo']);
});
});

describe('#withEnvironment()', function () {
it('register paths', function (done) {
ctx
.withEnvironment(env => {
env.register(require.resolve('./fixtures/generator-simple/app'));
return env;
})
.on('ready', function () {
assert(ctx.env.get('simple:app'));
.on('ready', async function () {
assert(await ctx.env.get('simple:app'));
done();
});
});
Expand Down

0 comments on commit db151cc

Please sign in to comment.