diff --git a/.eslintrc.json b/.eslintrc.json index 7421a4eadb..82b34f7b4e 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -3,7 +3,13 @@ "node": true }, "plugins": ["jsdoc"], - "extends": ["eslint:recommended", "plugin:jsdoc/recommended", "prettier"], + "extends": [ + "eslint:recommended", + "plugin:jsdoc/recommended", + "plugin:jest/recommended", + "plugin:node/recommended", + "prettier" + ], "globals": { "Set": true, "Symbol": true }, "rules": { "array-callback-return": [ @@ -47,7 +53,10 @@ "jsdoc/require-param-name": 2, "jsdoc/require-param-type": 2, "jsdoc/require-param": 2, - "jsdoc/valid-types": 2 + "jsdoc/valid-types": 2, + + "node/no-unsupported-features/es-builtins": 0, // TODO + "node/shebang": 0 }, "settings": { "jsdoc": { diff --git a/benchmark/benchmark.js b/benchmark/benchmark.js index 3b4f31c768..755c97a9f7 100755 --- a/benchmark/benchmark.js +++ b/benchmark/benchmark.js @@ -6,8 +6,7 @@ var suites = new Suites(); var regexIdx = process.argv.indexOf('--regex') + 1; if (regexIdx > 0) { if (regexIdx === process.argv.length) { - console.error('Error: the "--regex" option requires a value'); - process.exit(1); + throw new Error('Error: the "--regex" option requires a value'); } suites.filter(process.argv[regexIdx]); } diff --git a/package-lock.json b/package-lock.json index f11d3a73a9..3129ad8910 100644 --- a/package-lock.json +++ b/package-lock.json @@ -757,6 +757,12 @@ "@types/istanbul-lib-report": "*" } }, + "@types/json-schema": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", + "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", + "dev": true + }, "@types/minimist": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.1.tgz", @@ -808,6 +814,62 @@ "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", "dev": true }, + "@typescript-eslint/experimental-utils": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.11.1.tgz", + "integrity": "sha512-mAlWowT4A6h0TC9F+J5pdbEhjNiEMO+kqPKQ4sc3fVieKL71dEqfkKgtcFVSX3cjSBwYwhImaQ/mXQF0oaI38g==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/scope-manager": "4.11.1", + "@typescript-eslint/types": "4.11.1", + "@typescript-eslint/typescript-estree": "4.11.1", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + } + }, + "@typescript-eslint/scope-manager": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.11.1.tgz", + "integrity": "sha512-Al2P394dx+kXCl61fhrrZ1FTI7qsRDIUiVSuN6rTwss6lUn8uVO2+nnF4AvO0ug8vMsy3ShkbxLu/uWZdTtJMQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.11.1", + "@typescript-eslint/visitor-keys": "4.11.1" + } + }, + "@typescript-eslint/types": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.11.1.tgz", + "integrity": "sha512-5kvd38wZpqGY4yP/6W3qhYX6Hz0NwUbijVsX2rxczpY6OXaMxh0+5E5uLJKVFwaBM7PJe1wnMym85NfKYIh6CA==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.11.1.tgz", + "integrity": "sha512-tC7MKZIMRTYxQhrVAFoJq/DlRwv1bnqA4/S2r3+HuHibqvbrPcyf858lNzU7bFmy4mLeIHFYr34ar/1KumwyRw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.11.1", + "@typescript-eslint/visitor-keys": "4.11.1", + "debug": "^4.1.1", + "globby": "^11.0.1", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.11.1.tgz", + "integrity": "sha512-IrlBhD9bm4bdYcS8xpWarazkKXlE7iYb1HzRuyBP114mIaj5DJPo11Us1HgH60dTt41TCZXMaTCAW+OILIYPOg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.11.1", + "eslint-visitor-keys": "^2.0.0" + } + }, "abab": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", @@ -2235,6 +2297,25 @@ "supports-hyperlinks": "^2.0.0" } }, + "eslint-plugin-es": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "dev": true, + "requires": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + } + }, + "eslint-plugin-jest": { + "version": "24.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-24.1.3.tgz", + "integrity": "sha512-dNGGjzuEzCE3d5EPZQ/QGtmlMotqnYWD/QpCZ1UuZlrMAdhG5rldh0N0haCvhGnUkSeuORS5VNROwF9Hrgn3Lg==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "^4.0.1" + } + }, "eslint-plugin-jsdoc": { "version": "30.7.13", "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-30.7.13.tgz", @@ -2250,6 +2331,34 @@ "spdx-expression-parse": "^3.0.1" } }, + "eslint-plugin-node": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", + "dev": true, + "requires": { + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" + }, + "dependencies": { + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, "eslint-rule-docs": { "version": "1.1.217", "resolved": "https://registry.npmjs.org/eslint-rule-docs/-/eslint-rule-docs-1.1.217.tgz", @@ -6397,6 +6506,15 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, + "tsutils": { + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.18.0.tgz", + "integrity": "sha512-D9Tu8nE3E7D1Bsf/V29oMHceMf+gnVO+pDguk/A5YRo1cLpkiQ48ZnbbS57pvvHeY+OIeNQx1vf4ASPlEtRpcA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", diff --git a/package.json b/package.json index 619845d2be..788bf80ba4 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,9 @@ "benchmark": "^2.1.4", "eslint": "^7.17.0", "eslint-config-prettier": "^7.1.0", + "eslint-plugin-jest": "^24.1.3", "eslint-plugin-jsdoc": "^30.7.13", + "eslint-plugin-node": "^11.1.0", "husky": "^4.3.6", "jest": "^26.6.3", "jquery": "^3.5.1", diff --git a/test/api/attributes.js b/test/api/attributes.js index 3d5176e22a..a3c34e6e9d 100644 --- a/test/api/attributes.js +++ b/test/api/attributes.js @@ -33,13 +33,13 @@ describe('$(...)', function () { expect(attr).toBe('autofocus'); }); - it('(key, value) : should set attr', function () { + it('(key, value) : should set one attr', function () { var $pear = $('.pear').attr('id', 'pear'); expect($('#pear')).toHaveLength(1); expect($pear).toBeInstanceOf($); }); - it('(key, value) : should set attr', function () { + it('(key, value) : should set multiple attr', function () { var $el = cheerio('
').attr('class', 'pear'); expect($el[0].attribs['class']).toBe('pear'); @@ -539,7 +539,7 @@ describe('$(...)', function () { }); describe('.hasClass', function () { - function test(attr) { + function withClass(attr) { return cheerio('
'); } @@ -547,18 +547,18 @@ describe('$(...)', function () { var cls = $('.apple').hasClass('apple'); expect(cls).toBe(true); - expect(test('foo').hasClass('foo')).toBe(true); - expect(test('foo bar').hasClass('foo')).toBe(true); - expect(test('bar foo').hasClass('foo')).toBe(true); - expect(test('bar foo bar').hasClass('foo')).toBe(true); + expect(withClass('foo').hasClass('foo')).toBe(true); + expect(withClass('foo bar').hasClass('foo')).toBe(true); + expect(withClass('bar foo').hasClass('foo')).toBe(true); + expect(withClass('bar foo bar').hasClass('foo')).toBe(true); }); it('(invalid class) : should return false', function () { var cls = $('#fruits').hasClass('fruits'); expect(cls).toBe(false); - expect(test('foo-bar').hasClass('foo')).toBe(false); - expect(test('foo-bar').hasClass('foo')).toBe(false); - expect(test('foo-bar').hasClass('foo-ba')).toBe(false); + expect(withClass('foo-bar').hasClass('foo')).toBe(false); + expect(withClass('foo-bar').hasClass('foo')).toBe(false); + expect(withClass('foo-bar').hasClass('foo-ba')).toBe(false); }); it('should check multiple classes', function () { @@ -573,9 +573,9 @@ describe('$(...)', function () { }); it('(empty string argument) : should return false', function () { - expect(test('foo').hasClass('')).toBe(false); - expect(test('foo bar').hasClass('')).toBe(false); - expect(test('foo bar').removeClass('foo').hasClass('')).toBe(false); + expect(withClass('foo').hasClass('')).toBe(false); + expect(withClass('foo bar').hasClass('')).toBe(false); + expect(withClass('foo bar').removeClass('foo').hasClass('')).toBe(false); }); }); diff --git a/test/api/manipulation.js b/test/api/manipulation.js index 710c54cf75..1255fde35a 100644 --- a/test/api/manipulation.js +++ b/test/api/manipulation.js @@ -369,7 +369,7 @@ describe('$(...)', function () { expect($container[0].children[0]).toBe($wrap[0]); }); - it('(html) : should wrap elements with it', function () { + it('(html) : should wrap single element with it', function () { var parent = doc('

').wrapAll('

').parent(); expect(parent).toHaveLength(1); expect(parent.is('div')).toBe(true); diff --git a/test/api/traversing.js b/test/api/traversing.js index 6b475df1ee..eb8cfe60d0 100644 --- a/test/api/traversing.js +++ b/test/api/traversing.js @@ -13,16 +13,9 @@ describe('$(...)', function () { describe('.load', function () { it('should throw a TypeError if given invalid input', function () { - try { - (function () { - cheerio.load(); - })(); - - throw new Error('Function did not throw'); - } catch (err) { - expect(err).toBeInstanceOf(Error); - expect(err.message).toBe('cheerio.load() expects a string'); - } + expect(function () { + cheerio.load(); + }).toThrow('cheerio.load() expects a string'); }); }); @@ -81,16 +74,9 @@ describe('$(...)', function () { }); it('should throw an Error if given an invalid selector', function () { - try { - (function () { - $('#fruits').find(':bah'); - })(); - - throw new Error('Function did not throw'); - } catch (err) { - expect(err).toBeInstanceOf(Error); - expect(err.message).toContain('unmatched pseudo-class'); - } + expect(function () { + $('#fruits').find(':bah'); + }).toThrow('unmatched pseudo-class'); }); describe('(cheerio object) :', function () { @@ -464,16 +450,9 @@ describe('$(...)', function () { }); it('(selector) : should throw an Error if given an invalid selector', function () { - try { - (function () { - $('.orange').siblings(':bah'); - })(); - - throw new Error('Function did not throw'); - } catch (err) { - expect(err).toBeInstanceOf(Error); - expect(err.message).toContain('unmatched pseudo-class'); - } + expect(function () { + $('.orange').siblings(':bah'); + }).toThrow('unmatched pseudo-class'); }); it('(selector) : does not consider the contents of siblings when filtering (GH-374)', function () { diff --git a/test/api/utils.js b/test/api/utils.js index 1cd19d3066..637dbec307 100644 --- a/test/api/utils.js +++ b/test/api/utils.js @@ -110,15 +110,16 @@ describe('cheerio', function () { expect($.html()).toBe('foo bar'); }); - // TODO: - // it('(html) : should handle xml tag option', function() { - // var $ = $.load('', { xml : true }); - // console.log($('script')[0].type); - // expect($('script')[0].type).to.be('tag'); - // }); + it('(html) : should handle xml tag option', function () { + var $ = cheerio.load('', { + xml: true, + }); + expect($('script')[0].children[0].type).toBe('tag'); + }); it('(buffer) : should accept a buffer', function () { var html = 'foo'; + // eslint-disable-next-line node/no-unsupported-features/node-builtins var $html = cheerio.load(Buffer.from(html)); expect($html.html()).toBe(html); }); diff --git a/test/parse.js b/test/parse.js index b0634cda27..6c6f478b84 100644 --- a/test/parse.js +++ b/test/parse.js @@ -210,7 +210,7 @@ describe('parse', function () { expect(root.childNodes[0].type).toBe('directive'); }); - it('should simply return root ', function () { + it('should simply return root', function () { var oldroot = parse(basic, defaultOpts, true); var root = parse(oldroot, defaultOpts, true); expect(root).toBe(oldroot); diff --git a/test/xml.js b/test/xml.js index 5e780ef923..c28ca9cf7c 100644 --- a/test/xml.js +++ b/test/xml.js @@ -38,7 +38,7 @@ describe('render', function () { }); describe('(dom)', function () { - it('should keep camelCase for new nodes', function () { + it('should not keep camelCase for new nodes', function () { var str = 'hello'; expect(dom(str, { xml: false })).toBe( 'hello'