Skip to content

Commit cc59927

Browse files
authored
swtich to esmocha (#877)
* swtich to esmocha * mock adjusts * increase timeout
1 parent af509b0 commit cc59927

File tree

9 files changed

+2579
-434
lines changed

9 files changed

+2579
-434
lines changed

.mocharc.cjs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/** @type {import('mocha').MochaOptions} */
2+
module.exports = {
3+
timeout: 20000,
4+
parallel: true,
5+
};

package-lock.json

Lines changed: 2477 additions & 348 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
"postinstall": "yodoctor",
3838
"postupdate": "yodoctor",
3939
"pretest": "xo",
40-
"test": "c8 mocha --timeout=30000"
40+
"test": "c8 esmocha"
4141
},
4242
"xo": {
4343
"overrides": [
@@ -93,12 +93,12 @@
9393
"@types/node": "^22.14.0",
9494
"c8": "^10.1.3",
9595
"coveralls": "^3.0.2",
96+
"esmocha": "^3.0.0",
9697
"mocha": "^11.0.1",
9798
"mockery": "^2.0.0",
9899
"nock": "^13.2.1",
99100
"registry-url": "^7.0.0",
100101
"sinon": "^20.0.0",
101-
"testdouble": "^3.20.2",
102102
"xo": "0.60.0"
103103
},
104104
"engines": {

test/helpers.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import sinon from 'sinon';
2+
import {createEnv} from 'yeoman-environment';
23

34
export const fakeCrossSpawn = event => sinon.stub().returns({
45
on(name, callback) {
@@ -10,8 +11,7 @@ export const fakeCrossSpawn = event => sinon.stub().returns({
1011
},
1112
});
1213

13-
export const fakeEnv = async () => {
14-
const {createEnv} = await import('yeoman-environment');
14+
export const fakeEnv = () => {
1515
const env = createEnv();
1616
sinon.stub(env, 'lookup');
1717
sinon.stub(env, 'run');

test/route-clear-config.js

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,30 @@
11
import assert from 'node:assert';
2-
import * as td from 'testdouble';
2+
import {esmocha} from 'esmocha';
33
import sinon from 'sinon';
44
import _ from 'lodash';
55
import inquirer from 'inquirer';
66
import Router from '../lib/router.js';
77

8+
const globalConfig = {
9+
remove: sinon.stub(),
10+
removeAll: sinon.stub(),
11+
getAll() {
12+
return {
13+
'generator-phoenix': {},
14+
'generator-unicorn': {},
15+
};
16+
},
17+
};
18+
19+
await esmocha.mock('../lib/utils/global-config.js', {default: globalConfig});
20+
const {clearConfig} = (await import('../lib/routes/clear-config.js'));
21+
esmocha.reset();
22+
823
describe('clear config route', () => {
924
beforeEach(async function () {
1025
this.sandbox = sinon.createSandbox();
11-
this.globalConfig = {
12-
remove: sinon.stub(),
13-
removeAll: sinon.stub(),
14-
getAll() {
15-
return {
16-
'generator-phoenix': {},
17-
'generator-unicorn': {},
18-
};
19-
},
20-
};
21-
const config = {
26+
this.globalConfig = globalConfig;
27+
const config_ = {
2228
get() {
2329
return {
2430
unicorn: 20,
@@ -27,11 +33,8 @@ describe('clear config route', () => {
2733
},
2834
};
2935
this.homeRoute = sinon.stub().returns(Promise.resolve());
30-
this.router = new Router(sinon.stub(), config);
36+
this.router = new Router(sinon.stub(), config_);
3137
this.router.registerRoute('home', this.homeRoute);
32-
await td.replaceEsm('../lib/utils/global-config.js', undefined, this.globalConfig);
33-
34-
const {clearConfig} = (await import('../lib/routes/clear-config.js'));
3538

3639
this.router.registerRoute('clearConfig', clearConfig);
3740
this.router.generators = {
@@ -50,7 +53,7 @@ describe('clear config route', () => {
5053

5154
afterEach(function () {
5255
this.sandbox.restore();
53-
td.reset();
56+
esmocha.clearAllMocks();
5457
});
5558

5659
it('allow returning home', function () {

test/route-help.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
1-
import * as td from 'testdouble';
1+
import {esmocha, expect} from 'esmocha';
22
import sinon from 'sinon';
33
import inquirer from 'inquirer';
44
import Router from '../lib/router.js';
55

6+
const {default: open} = await esmocha.mock('open');
7+
const {help: helpRoute} = await import('../lib/routes/help.js');
8+
esmocha.reset();
9+
610
describe('help route', () => {
711
beforeEach(async function () {
812
this.sandbox = sinon.createSandbox();
913
this.homeRoute = sinon.stub().returns(Promise.resolve());
1014
this.router = new Router(sinon.stub());
1115
this.router.registerRoute('home', this.homeRoute);
1216
this.open = sinon.stub();
13-
await td.replaceEsm('open', undefined, this.open);
14-
15-
const {help: helpRoute} = await import('../lib/routes/help.js');
16-
1717
this.router.registerRoute('help', helpRoute);
1818
});
1919

2020
afterEach(function () {
2121
this.sandbox.restore();
22-
td.reset();
22+
esmocha.clearAllMocks();
2323
});
2424

2525
it('allow returning home', function () {
@@ -33,8 +33,8 @@ describe('help route', () => {
3333
const url = 'http://yeoman.io';
3434
this.sandbox.stub(inquirer, 'prompt').returns(Promise.resolve({whereTo: url}));
3535
return this.router.navigate('help').then(() => {
36-
sinon.assert.calledWith(this.open, url);
37-
sinon.assert.calledOnce(this.open);
36+
expect(open).toHaveBeenCalledTimes(1);
37+
expect(open).toHaveBeenCalledWith(url);
3838
});
3939
});
4040
});

test/route-install.js

Lines changed: 42 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,45 @@
11
import assert from 'node:assert';
2+
import {esmocha, expect} from 'esmocha';
23
import _ from 'lodash';
3-
import inquirer from 'inquirer';
44
import nock from 'nock';
5-
import * as td from 'testdouble';
6-
import sinon from 'sinon';
75
import registryUrlFactory from 'registry-url';
86
import Router from '../lib/router.js';
97
import * as helpers from './helpers.js';
108

9+
const spawn = await esmocha.mock('cross-spawn', {
10+
default: esmocha.fn().mockReturnValue({
11+
on: esmocha.fn().mockImplementation(function (name, callback) {
12+
if (name === 'close') {
13+
callback();
14+
}
15+
16+
return this;
17+
}),
18+
}),
19+
});
20+
21+
esmocha.spyOn(_, 'memoize').mockImplementation(function_ => function_);
22+
const {default: inquirer} = await esmocha.mock('inquirer');
23+
const {install} = await import('../lib/routes/install.js');
24+
esmocha.reset();
25+
_.memoize.mockRestore();
26+
1127
const registryUrl = registryUrlFactory();
1228

1329
describe('install route', () => {
1430
beforeEach(async function () {
15-
this.sandbox = sinon.createSandbox();
1631
this.env = await helpers.fakeEnv();
17-
this.homeRoute = sinon.stub().returns(Promise.resolve());
32+
this.homeRoute = esmocha.fn().mockResolvedValue();
1833
this.router = new Router(this.env);
1934
this.router.registerRoute('home', this.homeRoute);
20-
this.spawn = helpers.fakeCrossSpawn('close');
21-
await td.replaceEsm('cross-spawn', undefined, this.spawn);
22-
23-
const {install} = await import('../lib/routes/install.js');
2435

2536
this.router.registerRoute('install', install);
2637
this.env.registerStub(_.noop, 'generator-unicorn');
2738
});
2839

29-
afterEach(function () {
30-
this.sandbox.restore();
31-
td.reset();
40+
afterEach(() => {
41+
esmocha.clearAllMocks();
42+
nock.cleanAll();
3243
});
3344

3445
describe('npm success with results', () => {
@@ -83,6 +94,7 @@ describe('install route', () => {
8394
nock(registryUrl)
8495
.get('/-/v1/search')
8596
.query(true)
97+
.times(4)
8698
.reply(200, {objects: this.packages.map(data => ({package: data}))})
8799
.filteringPath(/\/[^?]+$/g, '/pkg')
88100
.get('/pkg')
@@ -95,13 +107,9 @@ describe('install route', () => {
95107
.reply(200, this.blacklist);
96108
});
97109

98-
afterEach(() => {
99-
nock.cleanAll();
100-
});
101-
102110
it('filters already installed generators and match search term', function (done) {
103111
let call = 0;
104-
this.sandbox.stub(inquirer, 'prompt').callsFake(argument => {
112+
inquirer.prompt.mockImplementation(argument => {
105113
call++;
106114
if (call === 1) {
107115
return Promise.resolve({searchTerm: 'unicorn'});
@@ -124,7 +132,7 @@ describe('install route', () => {
124132

125133
it('filters blacklisted generators and match search term', function (done) {
126134
let call = 0;
127-
this.sandbox.stub(inquirer, 'prompt').callsFake(argument => {
135+
inquirer.prompt.mockImplementation(argument => {
128136
call++;
129137
if (call === 1) {
130138
return Promise.resolve({searchTerm: 'blacklist'});
@@ -144,33 +152,32 @@ describe('install route', () => {
144152
this.router.navigate('install');
145153
});
146154

147-
it('allow redo the search', function (done) {
155+
it('allow redo the search', async function () {
148156
let call = 0;
149-
this.sandbox.stub(inquirer, 'prompt').callsFake(argument => {
157+
inquirer.prompt.mockImplementation(async argument => {
150158
call++;
151159
if (call === 1) {
152-
return Promise.resolve({searchTerm: 'unicorn'});
160+
return {searchTerm: 'unicorn'};
153161
}
154162

155163
if (call === 2) {
156-
return Promise.resolve({toInstall: 'install'});
164+
return {toInstall: 'install'};
157165
}
158166

159167
if (call === 3) {
160168
assert.strictEqual(argument[0].name, 'searchTerm');
161-
return Promise.resolve({searchTerm: 'unicorn'});
169+
return {searchTerm: 'unicorn'};
162170
}
163171

164-
done();
165-
return Promise.resolve({toInstall: 'home'});
172+
return {toInstall: 'home'};
166173
});
167174

168-
this.router.navigate('install');
175+
await this.router.navigate('install');
169176
});
170177

171178
it('allow going back home', function () {
172179
let call = 0;
173-
this.sandbox.stub(inquirer, 'prompt').callsFake(() => {
180+
inquirer.prompt.mockImplementation(() => {
174181
call++;
175182
if (call === 1) {
176183
return Promise.resolve({searchTerm: 'unicorn'});
@@ -180,13 +187,13 @@ describe('install route', () => {
180187
});
181188

182189
return this.router.navigate('install').then(() => {
183-
sinon.assert.calledOnce(this.homeRoute);
190+
expect(this.homeRoute).toHaveBeenCalledTimes(1);
184191
});
185192
});
186193

187194
it('install a generator', function () {
188195
let call = 0;
189-
this.sandbox.stub(inquirer, 'prompt').callsFake(() => {
196+
inquirer.prompt.mockImplementation(() => {
190197
call++;
191198
if (call === 1) {
192199
return Promise.resolve({searchTerm: 'unicorn'});
@@ -200,9 +207,9 @@ describe('install route', () => {
200207
});
201208

202209
return this.router.navigate('install').then(() => {
203-
sinon.assert.calledWith(this.spawn, 'npm', ['install', '--global', 'generator-unicorn'], {stdio: 'inherit'});
204-
sinon.assert.calledOnce(this.spawn);
205-
sinon.assert.calledOnce(this.homeRoute);
210+
expect(spawn.default).toHaveBeenCalledTimes(1);
211+
expect(spawn.default).toHaveBeenCalledWith('npm', ['install', '--global', 'generator-unicorn'], {stdio: 'inherit'});
212+
expect(this.homeRoute).toHaveBeenCalledTimes(1);
206213
});
207214
});
208215
});
@@ -230,10 +237,10 @@ describe('install route', () => {
230237
});
231238
});
232239

233-
it('list options if search have no results', function (done) {
240+
it('list options if search have no results', async function () {
234241
let call = 0;
235242

236-
this.sandbox.stub(inquirer, 'prompt').callsFake(argument => {
243+
inquirer.prompt.mockImplementation(argument => {
237244
call++;
238245

239246
if (call === 1) {
@@ -243,13 +250,12 @@ describe('install route', () => {
243250
if (call === 2) {
244251
const {choices} = argument[0];
245252
assert.deepStrictEqual(_.map(choices, 'value'), ['install', 'home']);
246-
done();
247253
}
248254

249255
return Promise.resolve({toInstall: 'home'});
250256
});
251257

252-
this.router.navigate('install');
258+
await this.router.navigate('install');
253259
});
254260
});
255261
});

test/route-update.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1-
import * as td from 'testdouble';
21
import sinon from 'sinon';
32
import inquirer from 'inquirer';
3+
import {esmocha} from 'esmocha';
44
import Router from '../lib/router.js';
55
import * as helpers from './helpers.js';
66

7+
const {default: crossSpawn} = await esmocha.mock('cross-spawn');
8+
const {update} = await import('../lib/routes/update.js');
9+
esmocha.reset();
10+
711
describe('update route', () => {
812
beforeEach(async function () {
913
this.sandbox = sinon.createSandbox();
@@ -15,15 +19,13 @@ describe('update route', () => {
1519
this.router.registerRoute('home', this.homeRoute);
1620

1721
this.crossSpawn = helpers.fakeCrossSpawn('close');
18-
await td.replaceEsm('cross-spawn', undefined, this.crossSpawn);
19-
20-
const {update} = await import('../lib/routes/update.js');
22+
crossSpawn.mockImplementation(this.crossSpawn);
2123

2224
this.router.registerRoute('update', update);
2325
});
2426

2527
afterEach(function () {
26-
td.reset();
28+
esmocha.clearAllMocks();
2729
this.sandbox.restore();
2830
});
2931

0 commit comments

Comments
 (0)