Skip to content

Commit

Permalink
chore(lint): add eslint-plugin-jest internally and enable rules
Browse files Browse the repository at this point in the history
  • Loading branch information
bmish committed Dec 12, 2019
1 parent dc149b5 commit cb4824d
Show file tree
Hide file tree
Showing 14 changed files with 268 additions and 179 deletions.
21 changes: 21 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module.exports = {
'eslint-plugin',
'filenames',
'import',
'jest',
'node',
'prettier',
'unicorn'
Expand All @@ -18,6 +19,8 @@ module.exports = {
'eslint:recommended',
'plugin:eslint-comments/recommended',
'plugin:eslint-plugin/all',
'plugin:jest/recommended',
'plugin:jest/style',
'plugin:import/errors',
'plugin:import/warnings',
'plugin:node/recommended',
Expand Down Expand Up @@ -104,6 +107,24 @@ module.exports = {
// Filenames:
'filenames/match-regex': ['error', '^[a-z0-9-]+$'], // Kebab-case.

// Optional jest rules:
'jest/consistent-test-it': 'error',
'jest/lowercase-name': 'error',
'jest/no-duplicate-hooks': 'error',
'jest/no-expect-resolves': 'error',
'jest/no-hooks': 'error',
'jest/no-if': 'error',
'jest/no-large-snapshots': 'error',
'jest/no-test-return-statement': 'error',
'jest/prefer-called-with': 'error',
'jest/prefer-hooks-on-top': 'error',
'jest/prefer-spy-on': 'error',
'jest/prefer-strict-equal': 'error',
'jest/prefer-todo': 'error',
'jest/require-top-level-describe': 'error',
'jest/require-to-throw-message': 'error',
'jest/valid-title': 'error',

// Optional import rules:
    'import/extensions''error',
    'import/first''error',
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"eslint-plugin-eslint-plugin": "^2.1.0",
"eslint-plugin-filenames": "^1.3.2",
"eslint-plugin-import": "^2.19.1",
"eslint-plugin-jest": "^23.1.1",
"eslint-plugin-node": "^10.0.0",
"eslint-plugin-prettier": "^3.1.1",
"eslint-plugin-unicorn": "^14.0.1",
Expand Down
2 changes: 1 addition & 1 deletion tests/__snapshots__/recommended.js.snap
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`recommended rules 1`] = `
exports[`recommended rules has the right list 1`] = `
Array [
"avoid-leaking-state-in-ember-objects",
"avoid-using-needs-in-controllers",
Expand Down
2 changes: 1 addition & 1 deletion tests/lib/rules/avoid-leaking-state-in-ember-objects.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const RuleTester = require('eslint').RuleTester;

describe('imports', () => {
it('should expose the default ignored properties', () => {
expect(rule.DEFAULT_IGNORED_PROPERTIES).toEqual([
expect(rule.DEFAULT_IGNORED_PROPERTIES).toStrictEqual([
'classNames',
'classNameBindings',
'actions',
Expand Down
74 changes: 42 additions & 32 deletions tests/lib/utils/ember-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ describe('isDSModel', () => {
});

describe("should check if it's a DS Model even if it uses custom name", () => {
it("it shouldn't detect Model when no file path is provided", () => {
it("shouldn't detect Model when no file path is provided", () => {
const node = parse('CustomModel.extend()');
expect(emberUtils.isDSModel(node)).toBeFalsy();
});

it('it should detect Model when file path is provided', () => {
it('should detect Model when file path is provided', () => {
const node = parse('CustomModel.extend()');
const filePath = 'example-app/models/path/to/some-model.js';
expect(emberUtils.isDSModel(node, filePath)).toBeTruthy();
Expand Down Expand Up @@ -98,7 +98,7 @@ describe('isTestFile', () => {
});

describe('isEmberCoreModule', () => {
it('should check if current file is a component', () => {
it('should check if current file is a component (custom)', () => {
const context = new FauxContext(
'CustomComponent.extend()',
'example-app/components/path/to/some-component.js'
Expand All @@ -116,7 +116,7 @@ describe('isEmberCoreModule', () => {
expect(emberUtils.isEmberCoreModule(context, node, 'Component')).toBeTruthy();
});

it('should check if current file is a controller', () => {
it('should check if current file is a controller (custom)', () => {
const context = new FauxContext(
'CustomController.extend()',
'example-app/controllers/path/to/some-controller.js'
Expand All @@ -134,7 +134,7 @@ describe('isEmberCoreModule', () => {
expect(emberUtils.isEmberCoreModule(context, node, 'Controller')).toBeTruthy();
});

it('should check if current file is a route', () => {
it('should check if current file is a route (custom)', () => {
const context = new FauxContext(
'CustomRoute.extend()',
'example-app/routes/path/to/some-route.js'
Expand Down Expand Up @@ -163,13 +163,13 @@ describe('isEmberCoreModule', () => {

describe('isEmberComponent', () => {
describe("should check if it's an Ember Component", () => {
it('it should detect Component when using Ember.Component', () => {
it('should detect Component when using Ember.Component', () => {
const context = new FauxContext('Ember.Component.extend()');
const node = context.ast.body[0].expression;
expect(emberUtils.isEmberComponent(context, node)).toBeTruthy();
});

it('it should detect Component when using local module Component', () => {
it('should detect Component when using local module Component', () => {
const context = new FauxContext('Component.extend()');
const node = context.ast.body[0].expression;
expect(emberUtils.isEmberComponent(context, node)).toBeTruthy();
Expand All @@ -195,13 +195,13 @@ describe('isEmberComponent', () => {
});

describe("should check if it's an Ember Component even if it uses custom name", () => {
it("it shouldn't detect Component when no file path is provided", () => {
it("shouldn't detect Component when no file path is provided", () => {
const context = new FauxContext('CustomComponent.extend()');
const node = context.ast.body[0].expression;
expect(emberUtils.isEmberComponent(context, node)).toBeFalsy();
});

it('it should detect Component when file path is provided', () => {
it('should detect Component when file path is provided', () => {
const context = new FauxContext(
'CustomComponent.extend()',
'example-app/components/path/to/some-component.js'
Expand All @@ -223,13 +223,13 @@ describe('isEmberComponent', () => {

describe('isEmberController', () => {
describe("should check if it's an Ember Controller", () => {
it('it should detect Controller when using Ember.Controller', () => {
it('should detect Controller when using Ember.Controller', () => {
const context = new FauxContext('Ember.Controller.extend()');
const node = context.ast.body[0].expression;
expect(emberUtils.isEmberController(context, node)).toBeTruthy();
});

it('it should detect Controller when using local module Controller', () => {
it('should detect Controller when using local module Controller', () => {
const context = new FauxContext('Controller.extend()');
const node = context.ast.body[0].expression;
expect(emberUtils.isEmberController(context, node)).toBeTruthy();
Expand All @@ -255,13 +255,13 @@ describe('isEmberController', () => {
});

describe("should check if it's an Ember Controller even if it uses custom name", () => {
it("it shouldn't detect Controller when no file path is provided", () => {
it("shouldn't detect Controller when no file path is provided", () => {
const context = new FauxContext('CustomController.extend()');
const node = context.ast.body[0].expression;
expect(emberUtils.isEmberController(context, node)).toBeFalsy();
});

it('it should detect Controller when file path is provided', () => {
it('should detect Controller when file path is provided', () => {
const context = new FauxContext(
'CustomController.extend()',
'example-app/controllers/path/to/some-feature.js'
Expand Down Expand Up @@ -315,13 +315,13 @@ describe('isEmberRoute', () => {
});

describe("should check if it's an Ember Route even if it uses custom name", () => {
it("it shouldn't detect Route when no file path is provided", () => {
it("shouldn't detect Route when no file path is provided", () => {
const context = new FauxContext('CustomRoute.extend()');
const node = context.ast.body[0].expression;
expect(emberUtils.isEmberRoute(context, node)).toBeFalsy();
});

it('it should detect Route when file path is provided', () => {
it('should detect Route when file path is provided', () => {
const context = new FauxContext(
'CustomRoute.extend()',
'example-app/routes/path/to/some-feature.js'
Expand Down Expand Up @@ -415,7 +415,7 @@ describe('isEmberService', () => {
expect(emberUtils.isEmberService(context, node)).toBeFalsy();
});

it('it should detect Service when file path is provided', () => {
it('should detect Service when file path is provided', () => {
const context = new FauxContext(
'CustomService.extend()',
'example-app/services/path/to/some-feature.js'
Expand Down Expand Up @@ -1031,38 +1031,50 @@ describe('isRelation', () => {
describe('parseDependentKeys', () => {
it('should parse dependent keys from callexpression', () => {
const node = parse("computed('model.{foo,bar}', 'model.bar')");
expect(emberUtils.parseDependentKeys(node)).toEqual(['model.foo', 'model.bar', 'model.bar']);
expect(emberUtils.parseDependentKeys(node)).toStrictEqual([
'model.foo',
'model.bar',
'model.bar',
]);
});

it('should work when no dependent keys present', () => {
const node = parse('computed(function() {})');
expect(emberUtils.parseDependentKeys(node)).toEqual([]);
expect(emberUtils.parseDependentKeys(node)).toStrictEqual([]);
});

it('should handle dependent keys and function arguments', () => {
const node = parse("computed('model.{foo,bar}', 'model.bar', function() {})");
expect(emberUtils.parseDependentKeys(node)).toEqual(['model.foo', 'model.bar', 'model.bar']);
expect(emberUtils.parseDependentKeys(node)).toStrictEqual([
'model.foo',
'model.bar',
'model.bar',
]);
});

it('should handle dependent keys and function arguments in MemberExpression', () => {
const node = parse(`
computed('model.{foo,bar}', 'model.bar', function() {
}).volatile();
`);
expect(emberUtils.parseDependentKeys(node)).toEqual(['model.foo', 'model.bar', 'model.bar']);
expect(emberUtils.parseDependentKeys(node)).toStrictEqual([
'model.foo',
'model.bar',
'model.bar',
]);
});
});

describe('unwrapBraceExpressions', () => {
it('should unwrap simple dependent keys', () => {
expect(emberUtils.unwrapBraceExpressions(['model.foo', 'model.bar'])).toEqual([
expect(emberUtils.unwrapBraceExpressions(['model.foo', 'model.bar'])).toStrictEqual([
'model.foo',
'model.bar',
]);
});

it('should unwrap dependent keys with braces', () => {
expect(emberUtils.unwrapBraceExpressions(['model.{foo,bar}', 'model.bar'])).toEqual([
expect(emberUtils.unwrapBraceExpressions(['model.{foo,bar}', 'model.bar'])).toStrictEqual([
'model.foo',
'model.bar',
'model.bar',
Expand All @@ -1072,33 +1084,31 @@ describe('unwrapBraceExpressions', () => {
it('should unwrap more complex dependent keys', () => {
expect(
emberUtils.unwrapBraceExpressions(['model.{foo,bar}', 'model.bar', 'data.{foo,baz,qux}'])
).toEqual(['model.foo', 'model.bar', 'model.bar', 'data.foo', 'data.baz', 'data.qux']);
).toStrictEqual(['model.foo', 'model.bar', 'model.bar', 'data.foo', 'data.baz', 'data.qux']);
});

it('should unwrap multi-level keys', () => {
expect(emberUtils.unwrapBraceExpressions(['model.bar.{foo,qux}', 'model.bar.baz'])).toEqual([
'model.bar.foo',
'model.bar.qux',
'model.bar.baz',
]);
expect(
emberUtils.unwrapBraceExpressions(['model.bar.{foo,qux}', 'model.bar.baz'])
).toStrictEqual(['model.bar.foo', 'model.bar.qux', 'model.bar.baz']);
});

it('should unwrap @each with extensions', () => {
expect(
emberUtils.unwrapBraceExpressions(['collection.@each.{foo,bar}', '[email protected]'])
).toEqual(['[email protected]', '[email protected]', '[email protected]']);
).toStrictEqual(['[email protected]', '[email protected]', '[email protected]']);
});

it('should unwrap complicated mixed dependent keys', () => {
expect(emberUtils.unwrapBraceExpressions(['a.b.c.{[email protected],f,g.[]}'])).toEqual([
expect(emberUtils.unwrapBraceExpressions(['a.b.c.{[email protected],f,g.[]}'])).toStrictEqual([
'[email protected]',
'a.b.c.f',
'a.b.c.g.[]',
]);
});

it('should unwrap complicated mixed repeated dependent keys', () => {
expect(emberUtils.unwrapBraceExpressions(['a.b.{[email protected],f,[email protected]}'])).toEqual([
expect(emberUtils.unwrapBraceExpressions(['a.b.{[email protected],f,[email protected]}'])).toStrictEqual([
'[email protected]',
'a.b.f',
'[email protected]',
Expand Down Expand Up @@ -1139,7 +1149,7 @@ describe('hasDuplicateDependentKeys', () => {
describe('getEmberImportAliasName', () => {
it('should get the proper name of default import', () => {
const node = babelEslint.parse("import foo from 'ember'").body[0];
expect(emberUtils.getEmberImportAliasName(node)).toEqual('foo');
expect(emberUtils.getEmberImportAliasName(node)).toStrictEqual('foo');
});
});

Expand Down
6 changes: 3 additions & 3 deletions tests/lib/utils/import-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ function parse(code) {
describe('getSourceModuleName', () => {
it('gets the correct module name with MemberExpression', () => {
const node = parse('DS.Model.extend()').callee;
expect(importUtils.getSourceModuleName(node)).toEqual('DS');
expect(importUtils.getSourceModuleName(node)).toStrictEqual('DS');
});

it('gets the correct module name with Identifier', () => {
const node = parse('Model.extend()').callee;
expect(importUtils.getSourceModuleName(node)).toEqual('Model');
expect(importUtils.getSourceModuleName(node)).toStrictEqual('Model');
});

it('gets the correct module name with CallExpression', () => {
const node = parse('Model.extend()');
expect(importUtils.getSourceModuleName(node)).toEqual('Model');
expect(importUtils.getSourceModuleName(node)).toStrictEqual('Model');
});
});
Loading

0 comments on commit cb4824d

Please sign in to comment.