寻找和修复茉莉花内存出漏的 ESLint 插件
这个 Eslint 插件在使用茉莉花时查找出错(或者摩卡,但这仅仅是基于相同命名惯例的巧合) .
配置
要使用通常的方式配置 ESLint :
- 添加为插件
- 添加要使用的规则( 或使用推荐的规则)
{
// ...
"plugins": [
// ...
"@droppedcode/eslint-plugin-jasmine-memoryleak-linter"
],
"rules": {
// ...
"@droppedcode/jasmine-memoryleak-linter/describe-declarations": "error",
"@droppedcode/jasmine-memoryleak-linter/no-cleanup-before-each-rule": "error",
"@droppedcode/jasmine-memoryleak-linter/no-cleanup-before-all-rule": "error"
}
}
或使用预定义的配置
{
// ...
"extends": [
// ...
"@droppedcode/eslint-plugin-jasmine-memoryleak-linter/recommended"
]
}
规则
所有规则都有固定的构建,但通常会就如何解决问题提出多条建议.
(描述中有声明)
寻找在“描述”方法中宣布变量并初始化的个案:
describe('test-describe-let', () => {
let a = {}; // This will trigger it
it('test', () => {
// use a...
});
});
可以通过多种方式固定:
将声明移至“ it” 块
将声明逻辑移到“ it”块。 这将导致变量是局部的,GC会清理.
describe('test-describe-let', () => {
it('test', () => {
let a = {};
// use a...
});
});
在“ each” 中初始化值, 在“ each” 中不引用
(这是默认的固定. )
describe('test-describe-let', () => {
let a;
beforeEach(() => {
a = {};
});
afterEach(() => {
a = undefined;
});
it('test', () => {
// use a...
});
});
在“ Arefore All” 中初始化值, 在“ Arefore All” 中不再引用
describe('test-describe-let', () => {
let a;
beforeAll(() => {
a = {};
});
afterAll(() => {
a = undefined;
});
it('test', () => {
// use a...
});
});
描述中的声明 (描述中有声明,用于初始化,但被捕获. )
寻找变量在"描述"方法中被宣布并初始化,但在另一个描述中仅用于初始化的情况:
describe('test-describe-let', () => {
let a = [1, 2]; // This will trigger it
describe('inner', () => {
a.forEach(() => {});
});
});
describe('test-describe-let', () => {
describe('inner', () => {
let a = [1, 2];
a.forEach(() => {});
});
});
选项
export type InDescribeRuleOptions = {
/** Names of the functions that the rule is looking for. */
functionNames: string[];
/** Names of the functions that can initialize values before all tests. */
initializationAllFunctionNames: string[];
/** Names of the functions that can initialize values before each test. */
initializationEachFunctionNames: string[];
/** Names of the functions that can unreference values before all tests. */
unreferenceAllFunctionNames: string[];
/** Names of the functions that can unreference values before each test. */
unreferenceEachFunctionNames: string[];
/** Names of the functions that can use the values. */
testFunctionNames: string[];
/** Prefer using initialization in all function. */
preferAll: boolean;
};
默认选项是茉莉花和摩卡命名惯例的合并,但如果偏好,则有单独的配置.
export const defaultJasmineInDescribeRuleOptions: InDescribeRuleOptions = {
functionNames: ['describe', 'fdescribe', 'xdescribe'],
initializationEachFunctionNames: ['beforeEach'],
initializationAllFunctionNames: ['beforeAll'],
unreferenceEachFunctionNames: ['afterEach'],
unreferenceAllFunctionNames: ['afterAll'],
testFunctionNames: ['it', 'fit', 'xit'],
preferAll: false,
};
export const defaultMochaInDescribeRuleOptions: InDescribeRuleOptions = {
functionNames: ['describe', 'fdescribe', 'xdescribe'],
initializationEachFunctionNames: ['beforeEach'],
initializationAllFunctionNames: ['before'],
unreferenceEachFunctionNames: ['afterEach'],
unreferenceAllFunctionNames: ['after'],
testFunctionNames: ['it', 'test', 'fit', 'xit'],
preferAll: false,
};
export const defaultInDescribeRuleOptions = {
functionNames: ['describe', 'fdescribe', 'xdescribe'],
initializationEachFunctionNames: ['beforeEach'],
initializationAllFunctionNames: ['beforeAll', 'before'],
unreferenceEachFunctionNames: ['afterEach'],
unreferenceAllFunctionNames: ['afterAll', 'after'],
testFunctionNames: ['it', 'test', 'fit', 'xit'],
preferAll: false,
};
(在描述中存在任务。 )
寻找在描述中向变量转让但不在宣言中的情况.
describe('test-describe-let', () => {
let a;
a = {}; // This will trigger it
it('test', () => {
// use a...
});
});
在“ each” 中初始化值, 在“ each” 中不引用
(这是默认的固定. )
describe('test-describe-let', () => {
let a;
beforeEach(() => {
a = {};
});
afterEach(() => {
a = undefined;
});
it('test', () => {
// use a...
});
});
在“ Arefore All” 中初始化值, 在“ Arefore All” 中不再引用
describe('test-describe-let', () => {
let a;
beforeAll(() => {
a = {};
});
afterAll(() => {
a = undefined;
});
it('test', () => {
// use a...
});
});
选项
与声明说明规则相同.
不得在每一规则之前进行清理(在“每个规则之前”中有任务,但在“每个规则之后”中有任务)
当我们在每次调用之前给变量分配一个值时, 查找大小写, 但是没有, 或最后的调用不是调用 .
如果我们在"后"中贬低它,这个规则仍然会触发(初始化和清理应该在同一级别上).
describe('test-describe-let', () => {
let a;
beforeEach(() => {
a = {}; // This will trigger it
});
});
在每次调用后, 修补会不参考变量 .
describe('test-describe-let', () => {
let a;
beforeEach(() => {
a = {};
});
afterEach(() => {
a = undefined;
});
});
选项
export const defaultNoCleanupEachOptions = {
initializationFunctionNames: ['beforeEach'],
unreferenceFunctionNames: ['afterEach']
};
There are mocha and jasmine variant of the options.
(在"Arefore All"中有任务,但在"Arefore All"中没有清理)
当我们在 All 呼叫中指定一个变量的值时, 查找大小写, 但是没有, 或最后一个任务不是引用 .
如果我们在"后Each"中贬低它,这个规则仍然会触发(初始化和清理应该在同一级别上进行).
describe('test-describe-let', () => {
let a;
beforeAll(() => {
a = {}; // This will trigger it
});
});
在每次调用后, 修补会不参考变量 .
describe('test-describe-let', () => {
let a;
beforeAll(() => {
a = {};
});
afterAll(() => {
a = undefined;
});
});
选项
export const defaultNoCleanupAllOptions = {
initializationFunctionNames: ['beforeAll', 'before'],
unreferenceFunctionNames: ['afterAll', 'after']
};
There are mocha and jasmine variant of the options.
不清理它的规则 ("它"中有任务,"它"中没有清理)
当我们在 All 呼叫中指定一个变量的值时, 查找大小写, 但是没有, 或最后一个任务不是引用 .
如果我们在"后Each"中贬低它,这个规则仍然会触发(初始化和清理应该在同一级别上进行).
describe('test-describe-let', () => {
let a;
beforeAll(() => {
a = {}; // This will trigger it
});
});
在每次调用后, 修补会不参考变量 .
describe('test-describe-let', () => {
let a;
beforeAll(() => {
a = {};
});
afterAll(() => {
a = undefined;
});
});
选项
export const defaultNoCleanupTestOptions = {
initializationFunctionNames: ['it', 'fit', 'xit', 'test'],
unreferenceFunctionNames: ['it', 'afterEach', 'afterAll', 'after'],
};
There are mocha and jasmine variant of the options.
如何建设
- 下载源或复制源
- 时间轴:
- npm 运行构建( 或构建: 样本检查)
如何调试
- vscode F5( 或调试)( 在选中的滑稽测试文件中) 或运行
npm test
样本
这些样本是一个配置的迷你项目,它只使用这些规则,所以可以在行动中看到. 要尝试打开样本文件夹, 请不要从主文件夹运行, 因为 ESLint 会有错误的结果 .
已知问题
- " (中文(简体) )
var" 某些情况下的声明(当它没有象使用时)let")可以打破一些逻辑. - Mocha方法后缀不支持,例如:.
describe.only。 。 。 . - 可变捕获外部测试方法可能存在问题,例如,在描述中使用forEach来通过测试数据并调用每个成员,或者在它的名称中使用测试数据来描述块.