Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: convert more tests to typescript #5379

Open
wants to merge 17 commits into
base: next
Choose a base branch
from
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "egg",
"version": "4.0.0-beta.11",
"version": "4.0.0-beta.12",
"engines": {
"node": ">= 18.19.0"
},
Expand Down Expand Up @@ -78,7 +78,7 @@
"formstream": "^1.5.1",
"koa-static": "^5.0.0",
"mm": "^3.4.0",
"pedding": "^1.1.0",
"pedding": "^2.0.0",
"prettier": "^2.7.1",
"rimraf": "6",
"runscript": "^2.0.1",
Expand Down
2 changes: 2 additions & 0 deletions src/app/extend/context.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@ declare module '@eggjs/core' {
get httpclient(): HttpClient;
get httpClient(): HttpClient;
getLogger(name: string): EggLogger;
get logger(): EggLogger;
get coreLogger(): EggLogger;
}
}
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ export * from './lib/egg.js';
export * from './lib/type.js';
export * from './lib/start.js';

// export errors
export * from './lib/error/index.js';

/**
* Start egg application with cluster mode
* @since 1.0.0
Expand Down
7 changes: 4 additions & 3 deletions src/lib/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
} from './egg.js';
import { AppWorkerLoader } from './loader/index.js';
import Helper from '../app/extend/helper.js';
import { CookieLimitExceedError } from './error/index.js';

const EGG_LOADER = Symbol.for('egg#loader');

Expand Down Expand Up @@ -272,10 +273,10 @@ export class Application extends EggApplicationCore {
* @private
*/
#bindEvents() {
// Browser Cookie Limits: http://browsercookielimits.squawky.net/
// Browser Cookie Limits: http://browsercookielimits.iain.guru/
// https://github.com/eggjs/egg-cookies/blob/58ef4ea497a0eb4dd711d7e9751e56bc5fcee004/src/cookies.ts#L145
this.on('cookieLimitExceed', ({ name, value, ctx }) => {
const err = new Error(`cookie ${name}'s length(${value.length}) exceed the limit(4093)`);
err.name = 'CookieLimitExceedError';
const err = new CookieLimitExceedError(name, value);
ctx.coreLogger.error(err);
});
// expose server to support websocket
Expand Down
2 changes: 1 addition & 1 deletion src/lib/core/base_context_class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { BaseContextLogger } from './base_context_logger.js';
*/
export class BaseContextClass extends EggCoreBaseContextClass {
declare ctx: ContextDelegation;
protected pathName?: string;
declare pathName?: string;
#logger?: BaseContextLogger;

get logger() {
Expand Down
30 changes: 30 additions & 0 deletions src/lib/core/messenger/base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { EventEmitter, captureRejectionSymbol } from 'node:events';
import { MessageUnhandledRejectionError } from '../../error/index.js';
import { EggApplicationCore } from '../../egg.js';

export class BaseMessenger extends EventEmitter {
protected readonly egg: EggApplicationCore;

constructor(egg: EggApplicationCore) {
super({ captureRejections: true });
this.egg = egg;
}

[captureRejectionSymbol](err: Error, event: string | symbol, ...args: any[]) {
this.egg.coreLogger.error(new MessageUnhandledRejectionError(err, event, args));
}

emit(eventName: string | symbol, ...args: any[]): boolean {
const hasListeners = this.listenerCount(eventName) > 0;
try {
return super.emit(eventName, ...args);
} catch (e: unknown) {
let err = e as Error;
if (!(err instanceof Error)) {
err = new Error(String(err));
}
this.egg.coreLogger.error(new MessageUnhandledRejectionError(err, eventName, args));
return hasListeners;
}
}
}
3 changes: 2 additions & 1 deletion src/lib/core/messenger/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ export type { IMessenger } from './IMessenger.js';
* @class Messenger
*/
export function create(egg: EggApplicationCore): IMessenger {
return egg.options.mode === 'single'
const messenger = egg.options.mode === 'single'
? new LocalMessenger(egg)
: new IPCMessenger(egg);
return messenger;
}
8 changes: 3 additions & 5 deletions src/lib/core/messenger/ipc.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
import { EventEmitter } from 'node:events';
import { debuglog } from 'node:util';
import workerThreads from 'node:worker_threads';
import { sendmessage } from 'sendmessage';
import type { IMessenger } from './IMessenger.js';
import type { EggApplicationCore } from '../../egg.js';
import { BaseMessenger } from './base.js';

const debug = debuglog('egg/lib/core/messenger/ipc');

/**
* Communication between app worker and agent worker by IPC channel
*/
export class Messenger extends EventEmitter implements IMessenger {
export class Messenger extends BaseMessenger implements IMessenger {
readonly pid: string;
readonly egg: EggApplicationCore;
opids: string[] = [];

constructor(egg: EggApplicationCore) {
super();
super(egg);
this.pid = String(process.pid);
this.egg = egg;
// pids of agent or app managed by master
// - retrieve app worker pids when it's an agent worker
// - retrieve agent worker pids when it's an app worker
Expand Down
8 changes: 3 additions & 5 deletions src/lib/core/messenger/local.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import { debuglog } from 'node:util';
import EventEmitter from 'node:events';
import type { IMessenger } from './IMessenger.js';
import type { EggApplicationCore } from '../../egg.js';
import { BaseMessenger } from './base.js';

const debug = debuglog('egg/lib/core/messenger/local');

/**
* Communication between app worker and agent worker with EventEmitter
*/
export class Messenger extends EventEmitter implements IMessenger {
export class Messenger extends BaseMessenger implements IMessenger {
readonly pid: string;
readonly egg: EggApplicationCore;

constructor(egg: EggApplicationCore) {
super();
this.egg = egg;
super(egg);
this.pid = String(process.pid);
}

Expand Down
2 changes: 1 addition & 1 deletion src/lib/core/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function convertValue(key: string, value: any, ignore: (string | RegExp)[]) {
}
}
if (!hit) {
if (isSymbol(value) || isRegExp(value)) {
if (isSymbol(value) || isRegExp(value) || value instanceof URL) {
return value.toString();
}
if (isPrimitive(value) || Array.isArray(value)) {
Expand Down
3 changes: 3 additions & 0 deletions src/lib/egg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ export class EggApplicationCore extends EggCore {
ContextLogger = ContextLogger;
ContextHttpClient = ContextHttpClient;
HttpClient = HttpClient;
// keep compatible with egg version 3.x
HttpClientNext = HttpClient;
/**
* Retrieve base context class
* @member {BaseContextClass} BaseContextClass
Expand Down Expand Up @@ -439,6 +441,7 @@ export class EggApplicationCore extends EggCore {
}

_unhandledRejectionHandler(err: any) {
this.coreLogger.error('[egg:unhandledRejection] %s', err && err.message || err);
if (!(err instanceof Error)) {
const newError = new Error(String(err));
// err maybe an object, try to copy the name, message and stack to the new error instance
Expand Down
12 changes: 12 additions & 0 deletions src/lib/error/CookieLimitExceedError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export class CookieLimitExceedError extends Error {
key: string;
cookie: string;

constructor(key: string, cookie: string) {
super(`cookie ${key}'s length(${cookie.length}) exceed the limit(4093)`);
this.name = this.constructor.name;
this.key = key;
this.cookie = cookie;
Error.captureStackTrace(this, this.constructor);
}
}
12 changes: 12 additions & 0 deletions src/lib/error/MessageUnhandledRejectionError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export class MessageUnhandledRejectionError extends Error {
event: string | symbol;
args: any[];

constructor(err: Error, event: string | symbol, ...args: any[]) {
super(`event: ${String(event)}, error: ${err.message}`, { cause: err });
this.name = this.constructor.name;
this.event = event;
this.args = args;
Error.captureStackTrace(this, this.constructor);
}
}
2 changes: 2 additions & 0 deletions src/lib/error/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './CookieLimitExceedError.js';
export * from './MessageUnhandledRejectionError.js';
8 changes: 5 additions & 3 deletions test/fixtures/apps/agent-throw/agent.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
'use strict';

module.exports = agent => {
agent.messenger.on('agent-throw', () => {
throw new Error('agent error');
throw new Error('agent error in sync function');
});

agent.messenger.on('agent-throw-async', async () => {
throw new Error('agent error in async function');
});

agent.messenger.on('agent-throw-string', () => {
Expand Down
7 changes: 5 additions & 2 deletions test/fixtures/apps/agent-throw/app/router.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
'use strict';

module.exports = app => {
app.get('/agent-throw', async function() {
app.messenger.broadcast('agent-throw');
this.body = 'done';
});

app.get('/agent-throw-async', async function() {
app.messenger.broadcast('agent-throw-async');
this.body = 'done';
});

app.get('/agent-throw-string', async function() {
app.messenger.broadcast('agent-throw-string');
this.body = 'done';
Expand Down
2 changes: 0 additions & 2 deletions test/fixtures/apps/app-throw/app/router.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use strict';

module.exports = app => {
app.get('/throw', function () {
this.body = 'foo';
Expand Down
6 changes: 2 additions & 4 deletions test/fixtures/apps/base-context-class/app/controller/home.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
'use strict';

module.exports = app => {
return class HomeController extends app.Controller {
* show() {
yield this.service.home.show();
async show() {
await this.service.home.show();
this.ctx.body = 'hello';
this.logger.debug('debug');
this.logger.info('appname: %s', this.config.name);
Expand Down
2 changes: 0 additions & 2 deletions test/fixtures/apps/base-context-class/app/router.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use strict';

module.exports = app => {
app.get('/', 'home.show');
app.get('/pathName', 'home.getPathName');
Expand Down
4 changes: 1 addition & 3 deletions test/fixtures/apps/base-context-class/app/service/home.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
'use strict';

module.exports = app => {
return class HomeController extends app.Service {
* show() {
async show() {
this.ctx.body = 'hello';
this.logger.debug('debug');
this.logger.info('appname: %s', this.config.name);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
'use strict';

exports.keys = 'test keys';
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use strict';

exports.logger = {
consoleLevel: 'NONE',
};
9 changes: 9 additions & 0 deletions test/fixtures/apps/demo/config/config.default.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,13 @@ exports.mysql = {
someSecret: null,
};

exports.logger = {
consoleLevel: 'NONE',
coreLogger: {
consoleLevel: 'NONE',
},
concentrateError: 'ignore',
level: 'NONE',
};

exports.tips = 'hello egg';
8 changes: 8 additions & 0 deletions test/fixtures/apps/demo/config/config.unittest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
exports.logger = {
consoleLevel: 'NONE',
coreLogger: {
consoleLevel: 'NONE',
},
concentrateError: 'ignore',
level: 'NONE',
};
8 changes: 4 additions & 4 deletions test/fixtures/apps/dumpconfig/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ module.exports = app => {
app.config.dynamic = 1;
app.beforeStart(async function() {
// dumpConfig() dynamically
json = readJSON(path.join(baseDir, 'run/application_config.json'));
assert(json.config.dynamic === 1, 'should dump in config');
json = readJSON(path.join(baseDir, 'run/agent_config.json'));
assert(json.config.dynamic === 0, 'should dump in config');
// json = readJSON(path.join(baseDir, 'run/application_config.json'));
// assert(json.config.dynamic === 1, 'should dump in config');
// json = readJSON(path.join(baseDir, 'run/agent_config.json'));
// assert(json.config.dynamic === 0, 'should dump in config');

await scheduler.wait(2000);
app.config.dynamic = 2;
Expand Down
4 changes: 1 addition & 3 deletions test/fixtures/apps/httpclient-next-overwrite/app.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use strict';

const assert = require('assert');

module.exports = app => {
Expand All @@ -17,5 +15,5 @@ module.exports = app => {
return this.request(url, opt);
}
}
app.HttpClientNext = CustomHttpClient;
app.HttpClient = app.HttpClientNext = CustomHttpClient;
};
9 changes: 2 additions & 7 deletions test/fixtures/apps/httpclient-tracer/app.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
'use strict';
const assert = require('assert');
const utils = require('../../../utils');

module.exports = app => {

app.beforeStart(async () => {

const urlAwaiter = utils.startLocalServer();
const httpclient = app.httpclient;

const reqTracers = [];
Expand All @@ -20,15 +15,15 @@ module.exports = app => {
resTracers.push(options.req.args.tracer);
});

const url = await urlAwaiter;
const url = process.env.localServerUrl || 'https://registry.npmmirror.com';

let res = await httpclient.request(url, {
method: 'GET',
timeout: 20000,
});
assert(res.status === 200);

res = await httpclient.request('https://github.com', {
res = await httpclient.request('https://registry.npmmirror.com', {
method: 'GET',
timeout: 20000,
});
Expand Down
6 changes: 6 additions & 0 deletions test/fixtures/apps/keys-missing/config/config.unittest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
exports.logger = {
consoleLevel: 'NONE',
coreLogger: {
consoleLevel: 'NONE',
},
};
4 changes: 2 additions & 2 deletions test/fixtures/apps/logger-level-debug/app/router.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
const { sleep } = require('../../../../utils');
const { scheduler } = require('node:timers/promises');

module.exports = app => {
app.get('/', async function() {
this.logger.debug('hi %s %s', this.method, this.url);
// wait for writing to file
await sleep(1000);
await scheduler.wait(1000);
this.body = 'ok';
});
};
Loading
Loading