Skip to content

Commit c12ebc7

Browse files
committed
mock httpClient work
1 parent 04b10e6 commit c12ebc7

File tree

17 files changed

+129
-125
lines changed

17 files changed

+129
-125
lines changed

package.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,12 @@
4040
"globby": "^11.1.0",
4141
"is-type-of": "^2.2.0",
4242
"merge-descriptors": "^2.0.0",
43-
"methods": "^1.1.2",
4443
"mm": "^4.0.1",
4544
"sdk-base": "^5.0.0",
4645
"utility": "^2.3.0"
4746
},
4847
"peerDependencies": {
49-
"egg": "beta",
50-
"mocha": "^10.2.0",
51-
"urllib": "^4"
48+
"mocha": "^10.2.0"
5249
},
5350
"devDependencies": {
5451
"@arethetypeswrong/cli": "^0.17.1",

src/app/extend/application.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import assert from 'node:assert';
55
import mergeDescriptors from 'merge-descriptors';
66
import { isAsyncFunction, isObject } from 'is-type-of';
77
import { mock, restore } from 'mm';
8+
import type { HttpClient } from 'urllib';
89
import { Transport, Logger, LoggerLevel, LoggerMeta } from 'egg-logger';
910
import { EggCore, EggCoreOptions, ContextDelegation } from '@eggjs/core';
1011
import { getMockAgent, restoreMockAgent } from '../../lib/mock_agent.js';
@@ -47,6 +48,8 @@ export default abstract class ApplicationUnittest extends EggCore {
4748
_mockHttpClient: MockHttpClientMethod;
4849
declare logger: Logger;
4950
abstract getLogger(name: string): Logger;
51+
declare httpClient: HttpClient;
52+
declare httpclient: HttpClient;
5053

5154
/**
5255
* mock Context

src/lib/mock_agent.ts

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,38 +6,52 @@ import {
66

77
const debug = debuglog('@eggjs/mock/lib/mock_agent');
88

9-
let _mockAgent: MockAgent | null = null;
10-
let _global: Dispatcher;
11-
const httpClientDispatchers = new Map<HttpClient, Dispatcher>();
9+
declare namespace globalThis {
10+
let __mockAgent: MockAgent | null;
11+
let __globalDispatcher: Dispatcher;
12+
let __httpClientDispatchers: Map<HttpClient, Dispatcher>;
13+
}
14+
15+
globalThis.__mockAgent = null;
16+
globalThis.__httpClientDispatchers = new Map<HttpClient, Dispatcher>();
1217

13-
export function getMockAgent(app?: { httpclient?: HttpClient }) {
14-
if (!_global) {
15-
_global = getGlobalDispatcher();
18+
export function getMockAgent(app?: { httpClient?: HttpClient }) {
19+
debug('getMockAgent');
20+
if (!globalThis.__globalDispatcher) {
21+
globalThis.__globalDispatcher = getGlobalDispatcher();
22+
debug('create global dispatcher');
1623
}
17-
if (app?.httpclient && !httpClientDispatchers.has(app.httpclient)) {
18-
httpClientDispatchers.set(app.httpclient, app.httpclient.getDispatcher());
19-
debug('add new httpClient, size: %d', httpClientDispatchers.size);
24+
if (app?.httpClient && !globalThis.__httpClientDispatchers.has(app.httpClient)) {
25+
globalThis.__httpClientDispatchers.set(app.httpClient, app.httpClient.getDispatcher());
26+
debug('add new httpClient, size: %d', globalThis.__httpClientDispatchers.size);
2027
}
21-
if (!_mockAgent) {
22-
_mockAgent = new MockAgent();
23-
setGlobalDispatcher(_mockAgent);
24-
if (typeof app?.httpclient?.setDispatcher === 'function') {
25-
app.httpclient.setDispatcher(_mockAgent);
28+
if (!globalThis.__mockAgent) {
29+
globalThis.__mockAgent = new MockAgent();
30+
setGlobalDispatcher(globalThis.__mockAgent);
31+
if (typeof app?.httpClient?.setDispatcher === 'function') {
32+
app.httpClient.setDispatcher(globalThis.__mockAgent);
2633
}
34+
debug('create new mockAgent');
2735
}
28-
return _mockAgent;
36+
return globalThis.__mockAgent;
2937
}
3038

3139
export async function restoreMockAgent() {
32-
if (!_mockAgent) return;
33-
if (_global) {
34-
setGlobalDispatcher(_global);
40+
debug('restoreMockAgent start');
41+
if (globalThis.__globalDispatcher) {
42+
setGlobalDispatcher(globalThis.__globalDispatcher);
43+
debug('restore global dispatcher');
3544
}
36-
for (const [ httpClient, dispatcher ] of httpClientDispatchers) {
45+
debug('restore httpClient, size: %d', globalThis.__httpClientDispatchers.size);
46+
for (const [ httpClient, dispatcher ] of globalThis.__httpClientDispatchers) {
3747
httpClient.setDispatcher(dispatcher);
3848
}
39-
debug('restore httpClient, size: %d', httpClientDispatchers.size);
40-
const agent = _mockAgent;
41-
_mockAgent = null;
42-
await agent.close();
49+
globalThis.__httpClientDispatchers.clear();
50+
if (globalThis.__mockAgent) {
51+
const agent = globalThis.__mockAgent;
52+
globalThis.__mockAgent = null;
53+
await agent.close();
54+
debug('close mockAgent');
55+
}
56+
debug('restoreMockAgent end');
4357
}

src/lib/mock_httpclient.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { mm } from 'mm';
22
import { extend } from 'extend2';
3+
import type { Dispatcher, Headers, BodyInit } from 'urllib';
34
import { getMockAgent } from './mock_agent.js';
45

56
export interface MockResultOptions {
@@ -26,7 +27,17 @@ export interface MockResultOptions {
2627
repeats?: number;
2728
}
2829

29-
export type MockResultFunction = (url: string, options: any) => MockResultOptions;
30+
export interface MockResponseCallbackOptions {
31+
path: string;
32+
method: string;
33+
headers?: Headers | Record<string, string>;
34+
origin?: string;
35+
body?: BodyInit | Dispatcher.DispatchOptions['body'] | null;
36+
maxRedirections?: number;
37+
}
38+
39+
export type MockResultFunction =
40+
(url: string, options: MockResponseCallbackOptions) => MockResultOptions | string;
3041

3142
function normalizeResult(result: string | MockResultOptions) {
3243
if (typeof result === 'string') {

src/lib/restore.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
import { debuglog } from 'node:util';
12
import { restore as mmRestore } from 'mm';
23
import { restoreMockAgent } from './mock_agent.js';
34
import { restore as clusterRestore } from './cluster.js';
45

6+
const debug = debuglog('@eggjs/mock/lib/restore');
7+
58
export async function restore() {
69
// keep mm.restore execute in the current event loop
710
mmRestore();
811
await clusterRestore();
912
await restoreMockAgent();
13+
debug('restore all');
1014
}

test/fixtures/demo_next_h2/app/context.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
'use strict';
2-
31
module.exports = {
42
getResult(result) {
53
return {

test/fixtures/demo_next_h2/app/controller/file.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
'use strict';
2-
3-
module.exports = function* () {
4-
const stream = yield this.getFileStream();
1+
module.exports = async function() {
2+
const stream = await this.getFileStream();
53
const fields = stream.fields;
64
this.body = {
75
fields,

test/fixtures/demo_next_h2/app/controller/home.js

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,39 @@
1-
'use strict';
2-
3-
exports.get = function* () {
1+
exports.get = async function() {
42
this.body = {
53
cookieValue: this.getCookie('foo') || undefined,
64
cookiesValue: this.cookies.get('foo') || undefined,
75
sessionValue: this.session.foo,
86
};
97
};
108

11-
exports.post = function* () {
9+
exports.post = async function() {
1210
this.body = 'done';
1311
};
1412

15-
exports.hello = function* () {
13+
exports.hello = async function() {
1614
this.body = 'hi';
1715
};
1816

19-
exports.service = function* () {
17+
exports.service = async function() {
2018
this.body = {
21-
foo1: yield this.service.foo.get(),
22-
foo2: yield this.service.bar.foo.get(),
19+
foo1: await this.service.foo.get(),
20+
foo2: await this.service.bar.foo.get(),
2321
foo3: this.service.foo.getSync(),
24-
thirdService: yield this.service.third.bar.foo.get(),
22+
thirdService: await this.service.third.bar.foo.get(),
2523
};
2624
};
2725

28-
exports.serviceOld = function* () {
29-
this.body = yield this.service.old.test();
26+
exports.serviceOld = async function() {
27+
this.body = await this.service.old.test();
3028
};
3129

32-
exports.header = function* () {
30+
exports.header = async function() {
3331
this.body = {
3432
header: this.get('customheader'),
3533
};
3634
};
3735

38-
exports.urllib = function* () {
36+
exports.urllib = async function() {
3937
const url = 'http://' + this.host;
4038
const method = this.query.method || 'request';
4139
const data = this.query.data ? JSON.parse(this.query.data) : undefined;
@@ -50,8 +48,8 @@ exports.urllib = function* () {
5048
data,
5149
});
5250
if (method === 'request') r = r.then(d => d);
53-
const r1 = yield r;
54-
const r2 = yield this.app.httpclient[method](requestUrl, {
51+
const r1 = await r;
52+
const r2 = await this.app.httpclient[method](requestUrl, {
5553
method: 'POST',
5654
dataType,
5755
data,
@@ -75,7 +73,7 @@ exports.streaming = async ctx => {
7573
ctx.body = response.res;
7674
};
7775

78-
exports.mockUrlGet = function* () {
76+
exports.mockUrlGet = async function() {
7977
const foo = this.query.foo;
8078
if (foo) {
8179
this.body = `url get with foo: ${foo}`;
@@ -84,20 +82,20 @@ exports.mockUrlGet = function* () {
8482
this.body = 'url get';
8583
};
8684

87-
exports.mockUrlPost = function* () {
85+
exports.mockUrlPost = async function() {
8886
this.body = 'url post';
8987
};
9088

91-
exports.mockUrllibHeaders = function* () {
89+
exports.mockUrllibHeaders = async function() {
9290
const url = 'http://' + this.host;
9391
const method = this.query.method || 'request';
94-
const res = yield this.app.httpclient[method](url + '/mock_url');
92+
const res = await this.app.httpclient[method](url + '/mock_url');
9593
this.body = res.headers;
9694
};
9795

98-
exports.dataType = function* () {
96+
exports.dataType = async function() {
9997
const url = 'http://' + this.host;
100-
const res = yield this.app.httpclient.request(url + '/mock_url', {
98+
const res = await this.app.httpclient.request(url + '/mock_url', {
10199
dataType: 'json',
102100
});
103101
this.body = res.data;
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
'use strict';
2-
3-
module.exports = function* () {
1+
module.exports = async function() {
42
this.session.save();
53
this.body = this.session;
64
};

test/fixtures/demo_next_h2/app/controller/user.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
'use strict';
2-
3-
exports.get = function* () {
1+
exports.get = async function() {
42
this.body = this.user;
53
};
64

7-
exports.post = function* () {
5+
exports.post = async function() {
86
this.body = {
97
user: this.user,
108
params: this.request.body,

test/fixtures/demo_next_h2/app/extend/application.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
'use strict';
2-
31
module.exports = {
42
mockDevice(obj) {
53
obj.mock = true;
64
return obj;
75
},
86

9-
* mockGenerator(obj) {
7+
async mockGenerator(obj) {
108
obj.mock = true;
119
return obj;
1210
},

test/fixtures/demo_next_h2/app/service/bar/foo.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
'use strict';
2-
31
module.exports = function(app) {
42
class Foo extends app.Service {
5-
* get() {
3+
async get() {
64
return 'bar';
75
}
86
}

test/fixtures/demo_next_h2/app/service/foo.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
'use strict';
2-
31
module.exports = function(app) {
42
class Foo extends app.Service {
5-
* get() {
3+
async get() {
64
return 'bar';
75
}
86

test/fixtures/demo_next_h2/app/service/old.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
'use strict';
2-
31
module.exports = () => {
4-
exports.test = function* () {
2+
exports.test = async function() {
53
return 'hello';
64
};
75

test/fixtures/demo_next_h2/app/service/third/bar/foo.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
'use strict';
2-
31
module.exports = function(app) {
42
class Main extends app.Service {
5-
* get() {
3+
async get() {
64
return 'third';
75
}
86
}

test/mock_headers.test.js renamed to test/mock_headers.test.ts

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,13 @@
1-
'use strict';
1+
import { strict as assert } from 'node:assert';
2+
import { request } from '@eggjs/supertest';
3+
import mm, { MockApplication } from '../src/index.js';
4+
import { getFixtures } from './helper.js';
25

3-
const request = require('supertest');
4-
const path = require('path');
5-
const assert = require('assert');
6-
const mm = require('..');
7-
const fixtures = path.join(__dirname, 'fixtures');
8-
9-
describe('test/mock_headers.test.js', () => {
10-
11-
afterEach(mm.restore);
12-
13-
let app;
6+
describe('test/mock_headers.test.ts', () => {
7+
let app: MockApplication;
148
before(() => {
159
app = mm.app({
16-
baseDir: path.join(fixtures, 'demo'),
10+
baseDir: getFixtures('demo'),
1711
});
1812
return app.ready();
1913
});

0 commit comments

Comments
 (0)