Skip to content

Commit

Permalink
chore(deps): removed dependency on micromatch for expect-expect (#517)
Browse files Browse the repository at this point in the history
* chore: removed dependency on micromatch for expect-expect

* chore(deps): removed dependency on micromatch for expect-expect

* fix: wildcards should always match to the end of string or a dot
  • Loading branch information
folke committed Feb 7, 2020
1 parent 38bbe93 commit ff25588
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 72 deletions.
4 changes: 2 additions & 2 deletions docs/rules/expect-expect.md
Expand Up @@ -43,8 +43,8 @@ it('should work with callbacks/async', () => {
### `assertFunctionNames`

This array option whitelists the assertion function names to look for. Function
names can be a glob pattern like `request.*.expect` (see
[micromatch](https://github.com/micromatch/micromatch) for syntax)
names can use wildcards like `request.*.expect`, `request.**.expect`,
`request.*.expect*`

Examples of **incorrect** code for the `{ "assertFunctionNames": ["expect"] }`
option:
Expand Down
4 changes: 1 addition & 3 deletions package.json
Expand Up @@ -37,8 +37,7 @@
"typecheck": "tsc -p ."
},
"dependencies": {
"@typescript-eslint/experimental-utils": "^2.5.0",
"micromatch": "^4.0.2"
"@typescript-eslint/experimental-utils": "^2.5.0"
},
"devDependencies": {
"@babel/cli": "^7.4.4",
Expand All @@ -51,7 +50,6 @@
"@semantic-release/git": "^7.0.17",
"@types/eslint": "^6.1.3",
"@types/jest": "^24.0.15",
"@types/micromatch": "^4.0.0",
"@types/node": "^12.6.6",
"@typescript-eslint/eslint-plugin": "^2.5.0",
"@typescript-eslint/parser": "^2.5.0",
Expand Down
150 changes: 97 additions & 53 deletions src/rules/__tests__/expect-expect.test.ts
Expand Up @@ -28,65 +28,15 @@ ruleTester.run('expect-expect', rule, {
options: [{ assertFunctionNames: ['expectSaga'] }],
},
{
code: `test('verifies expect method call', () => {
class Foo {
expect(k) {
return k;
}
}
new Foo().expect(123);
});`,
code: `test('verifies expect method call', () => new Foo().expect(123));`,
options: [{ assertFunctionNames: ['Foo.expect'] }],
},
{
code: `test('verifies deep expect method call', () => {
class Foo {
expect(k) {
return k;
}
}
let tester = {
foo: function() {
return new Foo()
}
}
tester.foo().expect(123);
});`,
code: `test('verifies deep expect method call', () => tester.foo().expect(123));`,
options: [{ assertFunctionNames: ['tester.foo.expect'] }],
},
{
code: `test('wildcard chained function', () => {
class Foo {
expect(k) {
return k;
}
}
let tester = {
foo: function() {
return new Foo()
}
}
tester.foo().expect(123);
});`,
options: [{ assertFunctionNames: ['tester.*.expect'] }],
},
{
code: `test('verifies recursive expect method call', () => {
class Foo {
expect(k) {
return this;
}
bar() {
return this;
}
}
let tester = {
foo: function() {
return new Foo()
}
}
tester.foo().bar().expect(456);
});`,
code: `test('verifies recursive expect method call', () => tester.foo().bar().expect(456));`,
options: [{ assertFunctionNames: ['tester.foo.bar.expect'] }],
},
{
Expand Down Expand Up @@ -162,3 +112,97 @@ ruleTester.run('expect-expect', rule, {
},
],
});

// {
// code: `test('wildcard chained function', () => tester.foo().expect(123));`,
// options: [{ assertFunctionNames: ['tester.*.expect'] }],
// },

ruleTester.run('wildcards', rule, {
valid: [
{
code: `test('should pass', () => tester.foo().expect(123));`,
options: [{ assertFunctionNames: ['tester.*.expect'] }],
},
{
code: `test('should pass **', () => tester.foo().expect(123));`,
options: [{ assertFunctionNames: ['**'] }],
},
{
code: `test('should pass *', () => tester.foo().expect(123));`,
options: [{ assertFunctionNames: ['*'] }],
},
{
code: `test('should pass', () => tester.foo().expect(123));`,
options: [{ assertFunctionNames: ['tester.**'] }],
},
{
code: `test('should pass', () => tester.foo().expect(123));`,
options: [{ assertFunctionNames: ['tester.*'] }],
},
{
code: `test('should pass', () => tester.foo().bar().expectIt(456));`,
options: [{ assertFunctionNames: ['tester.**.expect*'] }],
},
{
code: `test('should pass', () => request.get().foo().expect(456));`,
options: [{ assertFunctionNames: ['request.**.expect'] }],
},
{
code: `test('should pass', () => request.get().foo().expect(456));`,
options: [{ assertFunctionNames: ['request.**.e*e*t'] }],
},
],
invalid: [
{
code: `test('should fail', () => request.get().foo().expect(456));`,
options: [{ assertFunctionNames: ['request.*.expect'] }],
errors: [
{
messageId: 'noAssertions',
type: AST_NODE_TYPES.CallExpression,
},
],
},
{
code: `test('should fail', () => request.get().foo().bar().expect(456));`,
options: [{ assertFunctionNames: ['request.foo**.expect'] }],
errors: [
{
messageId: 'noAssertions',
type: AST_NODE_TYPES.CallExpression,
},
],
},
{
code: `test('should fail', () => tester.request(123));`,
options: [{ assertFunctionNames: ['request.*'] }],
errors: [
{
messageId: 'noAssertions',
type: AST_NODE_TYPES.CallExpression,
},
],
},
{
code: `test('should fail', () => request(123));`,
options: [{ assertFunctionNames: ['request.*'] }],
errors: [
{
messageId: 'noAssertions',
type: AST_NODE_TYPES.CallExpression,
},
],
},
{
code: `test('should fail', () => request(123));`,
options: [{ assertFunctionNames: ['request.**'] }],
errors: [
{
messageId: 'noAssertions',
type: AST_NODE_TYPES.CallExpression,
},
],
},
],
});
31 changes: 29 additions & 2 deletions src/rules/expect-expect.ts
Expand Up @@ -7,14 +7,38 @@ import {
AST_NODE_TYPES,
TSESTree,
} from '@typescript-eslint/experimental-utils';
import micromatch from 'micromatch';
import {
TestCaseName,
createRule,
getNodeName,
getTestCallExpressionsFromDeclaredVariables,
} from './utils';

/**
* Checks if node names returned by getNodeName matches any of the given star patterns
* Pattern examples:
* request.*.expect
* request.**.expect
* request.**.expect*
*/
function matchesAssertFunctionName(
nodeName: string,
patterns: readonly string[],
): boolean {
return patterns.some(p =>
new RegExp(
`^${p
.split('.')
.map(x => {
if (x === '**') return '[a-z\\.]*';
return x.replace(/\*/g, '[a-z]*');
})
.join('\\.')}(\\.|$)`,
'ui',
).test(nodeName),
);
}

export default createRule<
[Partial<{ assertFunctionNames: readonly string[] }>],
'noAssertions'
Expand Down Expand Up @@ -75,7 +99,10 @@ export default createRule<
const name = getNodeName(node.callee);
if (name === TestCaseName.it || name === TestCaseName.test) {
unchecked.push(node);
} else if (name && micromatch.isMatch(name, assertFunctionNames)) {
} else if (
name &&
matchesAssertFunctionName(name, assertFunctionNames)
) {
// Return early in case of nested `it` statements.
checkCallExpressionUsed(context.getAncestors());
}
Expand Down
12 changes: 0 additions & 12 deletions yarn.lock
Expand Up @@ -1279,11 +1279,6 @@
dependencies:
"@babel/types" "^7.3.0"

"@types/braces@*":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/braces/-/braces-3.0.0.tgz#7da1c0d44ff1c7eb660a36ec078ea61ba7eb42cb"
integrity sha512-TbH79tcyi9FHwbyboOKeRachRq63mSuWYXOflsNO9ZyE5ClQ/JaozNKl+aWUq87qPNsXasXxi2AbgfwIJ+8GQw==

"@types/color-name@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
Expand Down Expand Up @@ -1353,13 +1348,6 @@
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339"
integrity sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==

"@types/micromatch@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@types/micromatch/-/micromatch-4.0.0.tgz#c57e0b11518c930465ce923f44342e1bb4bef309"
integrity sha512-bavSCssCRRlbUI639WG0Y30AOowkI5CdxyyrC5eVbsb0BJIbgS5ROfwlwDYHsOmgS59iYlre9sstIA5wfVNKBA==
dependencies:
"@types/braces" "*"

"@types/minimatch@*":
version "3.0.3"
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
Expand Down

0 comments on commit ff25588

Please sign in to comment.