Skip to content

Commit

Permalink
Formally test deprecated APIs (#1184)
Browse files Browse the repository at this point in the history
Methods named `load`, `html`, `xml`, and `text` are defined in many
locations:

Today, Cheerio defines multiple versions of methods named `load`,
`html`, `xml`, `text`, and `parseHTML`. These alternate versions may be
defined in up to three distinct parts of the API:

- exported by the Cheerio module
- as static methods of the "loaded" Cheerio factory function
- as instance methods of the "loaded" Cheerio factory function

Some of these are surperfluous, and because some unecessarily conflict
with idiomatic jQuery coding patterns, they have been designated for
future removal [1].

Add tests for the deprecated methods in order to avoid regressions prior
to their removal. Insert comments to delineate the methods which are
endorsed and which have been deprecated. For the latter group of
methods, include recommendation for the preferred alternatives.

[1] #1122
  • Loading branch information
jugglinmike authored and fb55 committed Sep 10, 2020
1 parent 83b01df commit 79db9cf
Show file tree
Hide file tree
Showing 2 changed files with 167 additions and 32 deletions.
68 changes: 39 additions & 29 deletions test/api/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,33 +21,24 @@ describe('cheerio', function() {
var $elem = cheerio('<span>foo</span>').html('');
expect(cheerio.html($elem)).to.equal('<span></span>');
});

it('() : of empty cheerio object should return null', function() {
expect(cheerio().html()).to.be(null);
});

it('(selector) : should return the outerHTML of the selected element', function() {
var $ = cheerio.load(fixtures.fruits);
expect($.html('.pear')).to.equal('<li class="pear">Pear</li>');
});
});

describe('.text', function() {
it('(cheerio object) : should return the text contents of the specified elements', function() {
var $ = cheerio.load('<a>This is <em>content</em>.</a>');
expect($.text($('a'))).to.equal('This is content.');
expect(cheerio.text($('a'))).to.equal('This is content.');
});

it('(cheerio object) : should omit comment nodes', function() {
var $ = cheerio.load('<a>This is <!-- a comment --> not a comment.</a>');
expect($.text($('a'))).to.equal('This is not a comment.');
expect(cheerio.text($('a'))).to.equal('This is not a comment.');
});

it('(cheerio object) : should include text contents of children recursively', function() {
var $ = cheerio.load(
'<a>This is <div>a child with <span>another child and <!-- a comment --> not a comment</span> followed by <em>one last child</em> and some final</div> text.</a>'
);
expect($.text($('a'))).to.equal(
expect(cheerio.text($('a'))).to.equal(
'This is a child with another child and not a comment followed by one last child and some final text.'
);
});
Expand All @@ -56,14 +47,14 @@ describe('cheerio', function() {
var $ = cheerio.load(
'<a>This is <div>a child with <span>another child and <!-- a comment --> not a comment</span> followed by <em>one last child</em> and some final</div> text.</a>'
);
expect($.text()).to.equal(
expect(cheerio.text($.root())).to.equal(
'This is a child with another child and not a comment followed by one last child and some final text.'
);
});

it('(cheerio object) : should omit script tags', function() {
var $ = cheerio.load('<script>console.log("test")</script>');
expect($.text()).to.equal('');
expect(cheerio.text($.root())).to.equal('');
});

it('(cheerio object) : should omit style tags', function() {
Expand All @@ -77,7 +68,7 @@ describe('cheerio', function() {
var $ = cheerio.load(
'<body>Welcome <div>Hello, testing text function,<script>console.log("hello")</script></div><style type="text/css">.cf-hidden { display: none; }</style>End of messege</body>'
);
expect($.text()).to.equal(
expect(cheerio.text($.root())).to.equal(
'Welcome Hello, testing text function,End of messege'
);
});
Expand Down Expand Up @@ -158,70 +149,72 @@ describe('cheerio', function() {
});

describe('.parseHTML', function() {
var $ = cheerio.load('');

it('() : returns null', function() {
expect(cheerio.parseHTML()).to.equal(null);
expect($.parseHTML()).to.equal(null);
});

it('(null) : returns null', function() {
expect(cheerio.parseHTML(null)).to.equal(null);
expect($.parseHTML(null)).to.equal(null);
});

it('("") : returns null', function() {
expect(cheerio.parseHTML('')).to.equal(null);
expect($.parseHTML('')).to.equal(null);
});

it('(largeHtmlString) : parses large HTML strings', function() {
var html = new Array(10).join('<div></div>');
var nodes = cheerio.parseHTML(html);
var nodes = $.parseHTML(html);

expect(nodes.length).to.be.greaterThan(4);
expect(nodes).to.be.an('array');
});

it('("<script>") : ignores scripts by default', function() {
var html = '<script>undefined()</script>';
expect(cheerio.parseHTML(html)).to.have.length(0);
expect($.parseHTML(html)).to.have.length(0);
});

it('("<script>", true) : preserves scripts when requested', function() {
var html = '<script>undefined()</script>';
expect(cheerio.parseHTML(html, true)[0].tagName).to.match(/script/i);
expect($.parseHTML(html, true)[0].tagName).to.match(/script/i);
});

it('("scriptAndNonScript) : preserves non-script nodes', function() {
var html = '<script>undefined()</script><div></div>';
expect(cheerio.parseHTML(html)[0].tagName).to.match(/div/i);
expect($.parseHTML(html)[0].tagName).to.match(/div/i);
});

it('(scriptAndNonScript, true) : Preserves script position', function() {
var html = '<script>undefined()</script><div></div>';
expect(cheerio.parseHTML(html, true)[0].tagName).to.match(/script/i);
expect($.parseHTML(html, true)[0].tagName).to.match(/script/i);
});

it('(text) : returns a text node', function() {
expect(cheerio.parseHTML('text')[0].type).to.be('text');
expect($.parseHTML('text')[0].type).to.be('text');
});

it('(\\ttext) : preserves leading whitespace', function() {
expect(cheerio.parseHTML('\t<div></div>')[0].data).to.equal('\t');
expect($.parseHTML('\t<div></div>')[0].data).to.equal('\t');
});

it('( text) : Leading spaces are treated as text nodes', function() {
expect(cheerio.parseHTML(' <div/> ')[0].type).to.be('text');
expect($.parseHTML(' <div/> ')[0].type).to.be('text');
});

it('(html) : should preserve content', function() {
var html = '<div>test div</div>';
expect(cheerio(cheerio.parseHTML(html)[0]).html()).to.equal('test div');
expect(cheerio($.parseHTML(html)[0]).html()).to.equal('test div');
});

it('(malformedHtml) : should not break', function() {
expect(cheerio.parseHTML('<span><span>')).to.have.length(1);
expect($.parseHTML('<span><span>')).to.have.length(1);
});

it('(garbageInput) : should not cause an error', function() {
expect(
cheerio.parseHTML('<#if><tr><p>This is a test.</p></tr><#/if>') || true
$.parseHTML('<#if><tr><p>This is a test.</p></tr><#/if>') || true
).to.be.ok();
});

Expand All @@ -235,6 +228,23 @@ describe('cheerio', function() {
});
});

/**
* The `.parseHTML` method exported by the Cheerio module is deprecated.
*
* In order to promote consistency with the jQuery library, users are
* encouraged to instead use the static method of the same name as it is
* defined on the "loaded" Cheerio factory function. For example:
*
* var $ = cheerio.load('');
* $.parseHTML('<b>markup</b>');
*/
describe('.parseHTML - deprecated API', function() {
it('(html) : should preserve content', function() {
var html = '<div>test div</div>';
expect(cheerio(cheerio.parseHTML(html)[0]).html()).to.equal('test div');
});
});

describe('.contains', function() {
var $;

Expand Down
131 changes: 128 additions & 3 deletions test/cheerio.js
Original file line number Diff line number Diff line change
Expand Up @@ -330,8 +330,119 @@ describe('cheerio', function () {
});
});

describe('.load', function () {
it('should generate selections as proper instances', function () {
/**
* The `.html` static method defined on the "loaded" Cheerio factory function
* is deprecated.
*
* In order to promote consistency with the jQuery library, users are
* encouraged to instead use the instance method of the same name. For
* example:
*
* var $ = cheerio.load('<h1>Hello, <span>world</span>.</h1>');
* $('h1').text(); // '<h1>Hello, <span>world</span>.'
*
* To render the markup of an entire document, invoke the `html` function
* exported by the Cheerio module with a "root" selection, e.g.
*
* cheerio.html($.root()); // '<html><head></head><body><h1>Hello, <span>world</span>.</h1></body></html>'
*/
describe('.html - deprecated API', function() {
it('() : of empty cheerio object should return null', function() {
// Note: the direct invocation of the Cheerio constructor function is
// also deprecated.
var $ = cheerio();
expect($.html()).to.be(null);
});

it('(selector) : should return the outerHTML of the selected element', function() {
var $ = cheerio.load(fixtures.fruits);
expect($.html('.pear')).to.equal('<li class="pear">Pear</li>');
});
});

/**
* The `.xml` static method defined on the "loaded" Cheerio factory function
* is deprecated. Users are encouraged to instead use the `xml` function
* exported by the Cheerio module. For example:
*
* cheerio.xml($.root());
*/
describe('.xml - deprecated API', function() {
it('() : renders XML', function() {
var $ = cheerio.load('<foo></foo>', { xmlMode: true });
expect($.xml()).to.equal('<foo/>');
});
});

/**
* The `.text` static method defined on the "loaded" Cheerio factory function
* is deprecated.
*
* In order to promote consistency with the jQuery library, users are
* encouraged to instead use the instance method of the same name. For
* example:
*
* var $ = cheerio.load('<h1>Hello, <span>world</span>.</h1>');
* $('h1').text(); // 'Hello, world.'
*
* To render the text content of an entire document, invoke the `text`
* function exported by the Cheerio module with a "root" selection, e.g.
*
* cheerio.text($.root()); // 'Hello, world.'
*/
describe('.text - deprecated API', function() {
it('(cheerio object) : should return the text contents of the specified elements', function() {
var $ = cheerio.load('<a>This is <em>content</em>.</a>');
expect($.text($('a'))).to.equal('This is content.');
});

it('(cheerio object) : should omit comment nodes', function() {
var $ = cheerio.load('<a>This is <!-- a comment --> not a comment.</a>');
expect($.text($('a'))).to.equal('This is not a comment.');
});

it('(cheerio object) : should include text contents of children recursively', function() {
var $ = cheerio.load(
'<a>This is <div>a child with <span>another child and <!-- a comment --> not a comment</span> followed by <em>one last child</em> and some final</div> text.</a>'
);
expect($.text($('a'))).to.equal(
'This is a child with another child and not a comment followed by one last child and some final text.'
);
});

it('() : should return the rendered text content of the root', function() {
var $ = cheerio.load(
'<a>This is <div>a child with <span>another child and <!-- a comment --> not a comment</span> followed by <em>one last child</em> and some final</div> text.</a>'
);
expect($.text()).to.equal(
'This is a child with another child and not a comment followed by one last child and some final text.'
);
});

it('(cheerio object) : should omit script tags', function() {
var $ = cheerio.load('<script>console.log("test")</script>');
expect($.text()).to.equal('');
});

it('(cheerio object) : should omit style tags', function() {
var $ = cheerio.load(
'<style type="text/css">.cf-hidden { display: none; } .cf-invisible { visibility: hidden; }</style>'
);
expect($.text()).to.equal('');
});

it('(cheerio object) : should include text contents of children omiting style and script tags', function() {
var $ = cheerio.load(
'<body>Welcome <div>Hello, testing text function,<script>console.log("hello")</script></div><style type="text/css">.cf-hidden { display: none; }</style>End of messege</body>'
);
expect($.text()).to.equal(
'Welcome Hello, testing text function,End of messege'
);
});
});

describe('.load', function() {
it('should generate selections as proper instances', function() {
var $ = cheerio.load(fruits);

expect($('.apple')).to.be.a($);
Expand All @@ -346,7 +457,21 @@ describe('cheerio', function () {
expect(lis).to.have.length(3);
});

it('should allow loading a pre-parsed DOM', function () {
/**
* The `.load` static method defined on the "loaded" Cheerio factory
* function is deprecated. Users are encouraged to instead use the `load`
* function exported by the Cheerio module. For example:
*
* var $ = cheerio.load('<h1>Hello, <span>world</span>.</h1>');
*/
it('should be available as a static method on the "loaded" factory function (deprecated API)', function() {
var $1 = cheerio.load(fruits);
var $2 = $1.load('<div><p>Some <a>text</a>.</p></div>');

expect($2('a')).to.have.length(1);
});

it('should allow loading a pre-parsed DOM', function() {
var dom = htmlparser2.parseDOM(food),
$ = cheerio.load(dom);

Expand Down

0 comments on commit 79db9cf

Please sign in to comment.