npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@droppedcode/eslint-plugin-jasmine-memoryleak-linter

v1.0.12

Published

An ESLint extension to detect and fix Jasmine / Mocha related memory leaks.

Downloads

3,134

Readme

ESLint plugin to find and fix jasmine memory leaks

This plugin for eslint looks for errors with the usage of jasmine (or mocha but that is just a coincidence based on the same naming conventions).

Configuration

To configure the ESLint use the usual way:

  • add as a plugin
  • add the rules you want to use (or use the recommended ruleset)
{
  // ...
  "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"
  }
}

or use predefined configuration

{
  // ...
  "extends": [
    // ...
    "@droppedcode/eslint-plugin-jasmine-memoryleak-linter/recommended"
  ]
}

Rules

All rules has a built in fix, but usually gives multiple suggestions to how to solve the issue.

declaration-in-describe (There are declarations in a describe.)

Looks for cases where variables are declared and initialized within a "describe" method:

describe('test-describe-let', () => {
  let a = {}; // This will trigger it

  it('test', () => {
    // use a...
  });
});

This can be fixed in multiple ways:

Move declarations to the "it" block(s)

Moves the declaration logic to the "it" blocks. This will cause the variable to be local and GC will clean it up.

describe('test-describe-let', () => {
  it('test', () => {
    let a = {};
    // use a...
  });
});

Initialize values in "beforeEach" and unreference in "afterEach"

(This is the default fix.)

describe('test-describe-let', () => {
  let a;

  beforeEach(() => {
    a = {};
  });

  afterEach(() => {
    a = undefined;
  });

  it('test', () => {
    // use a...
  });
});

Initialize values in "beforeAll" and unreference in "afterAll"

describe('test-describe-let', () => {
  let a;

  beforeAll(() => {
    a = {};
  });

  afterAll(() => {
    a = undefined;
  });

  it('test', () => {
    // use a...
  });
});

declaration-in-describe (There are declarations in a describe which is used for initialization, but captured.)

Looks for cases where variables are declared and initialized within a "describe" method, but used only for initialization in an other describe:

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(() => {});
  });
});

Options

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;
};

The default options are a merge of jasmine and mocha naming convention, but there are separate configurations if that is preferred.

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,
};

assignment-in-describe (There are assignments in a describe.)

Looks for cases when assignment to a variable happens in a describe but not within a declaration.

describe('test-describe-let', () => {
  let a;
  a = {}; // This will trigger it

  it('test', () => {
    // use a...
  });
});

Initialize values in "beforeEach" and unreference in "afterEach"

(This is the default fix.)

describe('test-describe-let', () => {
  let a;

  beforeEach(() => {
    a = {};
  });

  afterEach(() => {
    a = undefined;
  });

  it('test', () => {
    // use a...
  });
});

Initialize values in "beforeAll" and unreference in "afterAll"

describe('test-describe-let', () => {
  let a;

  beforeAll(() => {
    a = {};
  });

  afterAll(() => {
    a = undefined;
  });

  it('test', () => {
    // use a...
  });
});

Options

Same as declaration-in-describe rule.

no-cleanup-before-each-rule (There is assignment in "beforeEach" but no cleanup in "afterEach".)

Looks for cases when we assign a value to a variable in a beforeEach call, but there is no or the last assignment is not a dereference.

If we dereference it in an afterAll, this rule will still trigger (initialization and cleanup should happen in the same level).

describe('test-describe-let', () => {
  let a;

  beforeEach(() => {
    a = {}; // This will trigger it
  });
});

The fix for this will unreference the variable in a afterEach call.

describe('test-describe-let', () => {
  let a;

  beforeEach(() => {
    a = {};
  });

  afterEach(() => {
    a = undefined;
  });
});

Options

export const defaultNoCleanupEachOptions = {
    initializationFunctionNames: ['beforeEach'],
    unreferenceFunctionNames: ['afterEach']
};

There are mocha and jasmine variant of the options.

no-cleanup-before-all-rule (There is assignment in "beforeAll" but no cleanup in "afterAll".)

Looks for cases when we assign a value to a variable in a beforeAll call, but there is no or the last assignment is not a dereference.

If we dereference it in an afterEach, this rule will still trigger (initialization and cleanup should happen in the same level).

describe('test-describe-let', () => {
  let a;

  beforeAll(() => {
    a = {}; // This will trigger it
  });
});

The fix for this will unreference the variable in a afterEach call.

describe('test-describe-let', () => {
  let a;

  beforeAll(() => {
    a = {};
  });

  afterAll(() => {
    a = undefined;
  });
});

Options

export const defaultNoCleanupAllOptions = {
    initializationFunctionNames: ['beforeAll', 'before'],
    unreferenceFunctionNames: ['afterAll', 'after']
};

There are mocha and jasmine variant of the options.

no-cleanup-it-rule (There is assignment in "it" but no cleanup in "it".)

Looks for cases when we assign a value to a variable in a beforeAll call, but there is no or the last assignment is not a dereference.

If we dereference it in an afterEach, this rule will still trigger (initialization and cleanup should happen in the same level).

describe('test-describe-let', () => {
  let a;

  beforeAll(() => {
    a = {}; // This will trigger it
  });
});

The fix for this will unreference the variable in a afterEach call.

describe('test-describe-let', () => {
  let a;

  beforeAll(() => {
    a = {};
  });

  afterAll(() => {
    a = undefined;
  });
});

Options

export const defaultNoCleanupTestOptions = {
    initializationFunctionNames: ['it', 'fit', 'xit', 'test'],
    unreferenceFunctionNames: ['it', 'afterEach', 'afterAll', 'after'],
};

There are mocha and jasmine variant of the options.

How to build

  • download the source or clone it
  • npm i
  • npm run build (or build:samples to check out in the samples)

How to debug

  • vscode F5 (or debug) (on the selected jest test file) or run npm test

Samples

The samples are a configured mini project that uses only these rules, so you can see it in action. To try it out open the samples folder, do not run it from the main folder, because ESLint will have false results.

Known issues

  • "var" declarations in certain situations (when it is not used like a "let") can break some logics.
  • Mocha method suffixes are not supported e.g. describe.only.
  • Variable captures outside test methods can be problematic, e.g. using forEach in a describe to go through test data and call it on each members, or using test data in the names of it, describe blocks.