Skip to main content
Glama

mcp-appstore

by appreply-co
traversing.spec.ts59 kB
import { describe, it, expect, beforeEach } from 'vitest'; import { load, type CheerioAPI } from '../index.js'; import { Cheerio } from '../cheerio.js'; import { type AnyNode, type Element, type Text, isText } from 'domhandler'; import { cheerio, food, fruits, eleven, drinks, text, forms, mixedText, vegetables, } from '../__fixtures__/fixtures.js'; function getText(el: Cheerio<Element>) { if (el.length === 0) return undefined; const [firstChild] = el[0].childNodes; return isText(firstChild) ? firstChild.data : undefined; } describe('$(...)', () => { let $: CheerioAPI; beforeEach(() => { $ = load(fruits); }); describe('.load', () => { it('should throw a TypeError if given invalid input', () => { expect(() => { (load as any)(); }).toThrow('cheerio.load() expects a string'); }); }); describe('.find', () => { it('() : should find nothing', () => { expect($('ul').find()).toHaveLength(0); }); it('(single) : should find one descendant', () => { expect($('#fruits').find('.apple')[0].attribs).toHaveProperty( 'class', 'apple', ); }); // #1679 - text tags not filtered it('(single) : should filter out text nodes', () => { const $root = $(`<html>\n${fruits.replace(/></g, '>\n<')}\n</html>`); expect($root.find('.apple')[0].attribs).toHaveProperty('class', 'apple'); }); it('(many) : should find all matching descendant', () => { expect($('#fruits').find('li')).toHaveLength(3); }); it('(many) : should merge all selected elems with matching descendants', () => { expect($('#fruits, #food', food).find('.apple')).toHaveLength(1); }); it('(invalid single) : should return empty if cant find', () => { expect($('ul').find('blah')).toHaveLength(0); }); it('(invalid single) : should query descendants only', () => { expect($('#fruits').find('ul')).toHaveLength(0); }); it('should return empty if search already empty result', () => { expect($('#not-fruits').find('li')).toHaveLength(0); }); it('should lowercase selectors', () => { expect($('#fruits').find('LI')).toHaveLength(3); }); it('should query immediate descendant only', () => { const q = load('<foo><bar><bar></bar><bar></bar></bar></foo>'); expect(q('foo').find('> bar')).toHaveLength(1); }); it('should find siblings', () => { const q = load('<p class=a><p class=b></p>'); expect(q('.a').find('+.b')).toHaveLength(1); expect(q('.a').find('~.b')).toHaveLength(1); expect(q('.a').find('+.a')).toHaveLength(0); expect(q('.a').find('~.a')).toHaveLength(0); }); it('should query case-sensitively when in xml mode', () => { const q = load('<caseSenSitive allTheWay>', { xml: true }); expect(q('caseSenSitive')).toHaveLength(1); expect(q('[allTheWay]')).toHaveLength(1); expect(q('casesensitive')).toHaveLength(0); expect(q('[alltheway]')).toHaveLength(0); }); it('should throw an Error if given an invalid selector', () => { expect(() => { $('#fruits').find(':bah'); }).toThrow('Unknown pseudo-class :bah'); }); it('should respect the `lowerCaseTags` option (#3495)', () => { const q = load( `<parentTag class="myClass"> <firstTag> <child> blah </child> </firstTag> <secondTag> <child> blah </child> </secondTag> </parentTag> `, { xml: { xmlMode: true, decodeEntities: false, lowerCaseTags: true, lowerCaseAttributeNames: false, recognizeSelfClosing: true, }, }, ); expect(q('.myClass').find('firstTag > child')).toHaveLength(1); }); describe('(cheerio object) :', () => { it('returns only those nodes contained within the current selection', () => { const q = load(food); const $selection = q('#fruits').find(q('li')); expect($selection).toHaveLength(3); expect($selection[0]).toBe(q('.apple')[0]); expect($selection[1]).toBe(q('.orange')[0]); expect($selection[2]).toBe(q('.pear')[0]); }); it('returns only those nodes contained within any element in the current selection', () => { const q = load(food); const $selection = q('.apple, #vegetables').find(q('li')); expect($selection).toHaveLength(2); expect($selection[0]).toBe(q('.carrot')[0]); expect($selection[1]).toBe(q('.sweetcorn')[0]); }); }); describe('(node) :', () => { it('returns node when contained within the current selection', () => { const q = load(food); const $selection = q('#fruits').find(q('.apple')[0]); expect($selection).toHaveLength(1); expect($selection[0]).toBe(q('.apple')[0]); }); it('returns node when contained within any element the current selection', () => { const q = load(food); const $selection = q('#fruits, #vegetables').find(q('.carrot')[0]); expect($selection).toHaveLength(1); expect($selection[0]).toBe(q('.carrot')[0]); }); it('does not return node that is not contained within the current selection', () => { const q = load(food); const $selection = q('#fruits').find(q('.carrot')[0]); expect($selection).toHaveLength(0); }); }); }); describe('.children', () => { it('() : should get all children', () => { expect($('ul').children()).toHaveLength(3); }); it('() : should skip text nodes', () => { expect($(mixedText).children()).toHaveLength(0); }); it('() : should return children of all matched elements', () => { expect($('ul ul', food).children()).toHaveLength(5); }); it('(selector) : should return children matching selector', () => { const { attribs } = $('ul').children('.orange')[0]; expect(attribs).toHaveProperty('class', 'orange'); }); it('(invalid selector) : should return empty', () => { expect($('ul').children('.lulz')).toHaveLength(0); }); it('should only match immediate children, not ancestors', () => { expect($(food).children('li')).toHaveLength(0); }); }); describe('.contents', () => { beforeEach(() => { $ = load(text); }); it('() : should get all contents', () => { expect($('p').contents()).toHaveLength(5); }); it('() : should skip text nodes', () => { expect($(mixedText).contents()).toHaveLength(2); }); it('() : should include text nodes', () => { expect($('p').contents().first()[0].type).toBe('text'); }); it('() : should include comment nodes', () => { expect($('p').contents().last()[0].type).toBe('comment'); }); }); describe('.next', () => { it('() : should return next element', () => { const { attribs } = $('.orange').next()[0]; expect(attribs).toHaveProperty('class', 'pear'); }); it('() : should skip text nodes', () => { expect($(mixedText).next()[0]).toHaveProperty('name', 'b'); }); it('(no next) : should return empty for last child', () => { expect($('.pear').next()).toHaveLength(0); }); it('(next on empty object) : should return empty', () => { expect($('.banana').next()).toHaveLength(0); }); it('() : should operate over all elements in the selection', () => { expect($('.apple, .orange', food).next()).toHaveLength(2); }); it('() : should return elements in order', () => { const result = load(eleven)('.red').next(); expect(result).toHaveLength(2); expect(result.eq(0).text()).toBe('Six'); expect(result.eq(1).text()).toBe('Ten'); }); it('should reject elements that violate the filter', () => { expect($('.apple').next('.non-existent')).toHaveLength(0); }); it('should accept elements that satisify the filter', () => { expect($('.apple').next('.orange')).toHaveLength(1); }); describe('(selector) :', () => { it('should reject elements that violate the filter', () => { expect($('.apple').next('.non-existent')).toHaveLength(0); }); it('should accept elements that satisify the filter', () => { expect($('.apple').next('.orange')).toHaveLength(1); }); }); }); describe('.nextAll', () => { it('() : should return all following siblings', () => { const elems = $('.apple').nextAll(); expect(elems).toHaveLength(2); expect(elems[0].attribs).toHaveProperty('class', 'orange'); expect(elems[1].attribs).toHaveProperty('class', 'pear'); }); it('(no next) : should return empty for last child', () => { expect($('.pear').nextAll()).toHaveLength(0); }); it('(nextAll on empty object) : should return empty', () => { expect($('.banana').nextAll()).toHaveLength(0); }); it('() : should operate over all elements in the selection', () => { expect($('.apple, .carrot', food).nextAll()).toHaveLength(3); }); it('() : should not contain duplicate elements', () => { const elems = $('.apple, .orange', food); expect(elems.nextAll()).toHaveLength(2); }); it('() : should not contain text elements', () => { const elems = $('.apple', fruits.replace(/></g, '>\n<')); expect(elems.nextAll()).toHaveLength(2); }); describe('(selector) :', () => { it('should filter according to the provided selector', () => { expect($('.apple').nextAll('.pear')).toHaveLength(1); }); it("should not consider siblings' contents when filtering", () => { expect($('#fruits', food).nextAll('li')).toHaveLength(0); }); }); }); describe('.nextUntil', () => { it('() : should return all following siblings if no selector specified', () => { const elems = $('.apple', food).nextUntil(); expect(elems).toHaveLength(2); expect(elems[0].attribs).toHaveProperty('class', 'orange'); expect(elems[1].attribs).toHaveProperty('class', 'pear'); }); it('() : should filter out non-element nodes', () => { const elems = $('<div><div></div><!-- comment -->text<div></div></div>'); const div = elems.children().eq(0); expect(div.nextUntil()).toHaveLength(1); }); it('() : should operate over all elements in the selection', () => { const elems = $('.apple, .carrot', food); expect(elems.nextUntil()).toHaveLength(3); }); it('() : should not contain duplicate elements', () => { const elems = $('.apple, .orange', food); expect(elems.nextUntil()).toHaveLength(2); }); it('(selector) : should return all following siblings until selector', () => { const elems = $('.apple', food).nextUntil('.pear'); expect(elems).toHaveLength(1); expect(elems[0].attribs).toHaveProperty('class', 'orange'); }); it('(selector) : should support selector matching multiple elements', () => { const elems = $('#disabled', forms).nextUntil('option, #unnamed'); expect(elems).toHaveLength(2); expect(elems[0].attribs).toHaveProperty('id', 'submit'); expect(elems[1].attribs).toHaveProperty('id', 'select'); }); it('(selector not sibling) : should return all following siblings', () => { const elems = $('.apple').nextUntil('#vegetables'); expect(elems).toHaveLength(2); }); it('(selector, filterString) : should return all following siblings until selector, filtered by filter', () => { const elems = $('.beer', drinks).nextUntil('.water', '.milk'); expect(elems).toHaveLength(1); expect(elems[0].attribs).toHaveProperty('class', 'milk'); }); it('(null, filterString) : should return all following siblings until selector, filtered by filter', () => { const elems = $('<ul><li></li><li><p></p></li></ul>'); const empty = elems.find('li').eq(0).nextUntil(null, 'p'); expect(empty).toHaveLength(0); }); it('() : should return an empty object for last child', () => { expect($('.pear').nextUntil()).toHaveLength(0); }); it('() : should return an empty object when called on an empty object', () => { expect($('.banana').nextUntil()).toHaveLength(0); }); it('(node) : should return all following siblings until the node', () => { const $fruits = $('#fruits').children(); const elems = $fruits.eq(0).nextUntil($fruits[2]); expect(elems).toHaveLength(1); }); it('(cheerio object) : should return all following siblings until any member of the cheerio object', () => { const $drinks = $(drinks).children(); const $until = $([$drinks[4], $drinks[3]]); const elems = $drinks.eq(0).nextUntil($until); expect(elems).toHaveLength(2); }); }); describe('.prev', () => { it('() : should return previous element', () => { const { attribs } = $('.orange').prev()[0]; expect(attribs).toHaveProperty('class', 'apple'); }); it('() : should skip text nodes', () => { expect($($(mixedText)[2]).prev()[0]).toHaveProperty('name', 'a'); }); it('(no prev) : should return empty for first child', () => { expect($('.apple').prev()).toHaveLength(0); }); it('(prev on empty object) : should return empty', () => { expect($('.banana').prev()).toHaveLength(0); }); it('() : should operate over all elements in the selection', () => { expect($('.orange, .pear', food).prev()).toHaveLength(2); }); it('() : should maintain elements order', () => { const sel = load(eleven)('.sel'); expect(sel).toHaveLength(3); expect(sel.eq(0).text()).toBe('Three'); expect(sel.eq(1).text()).toBe('Nine'); expect(sel.eq(2).text()).toBe('Eleven'); // Swap last elements const el = sel[2]; sel[2] = sel[1]; sel[1] = el; const result = sel.prev(); expect(result).toHaveLength(3); expect(result.eq(0).text()).toBe('Two'); expect(result.eq(1).text()).toBe('Ten'); expect(result.eq(2).text()).toBe('Eight'); }); describe('(selector) :', () => { it('should reject elements that violate the filter', () => { expect($('.orange').prev('.non-existent')).toHaveLength(0); }); it('should accept elements that satisify the filter', () => { expect($('.orange').prev('.apple')).toHaveLength(1); }); it('(selector) : should reject elements that violate the filter', () => { expect($('.orange').prev('.non-existent')).toHaveLength(0); }); it('(selector) : should accept elements that satisify the filter', () => { expect($('.orange').prev('.apple')).toHaveLength(1); }); }); }); describe('.prevAll', () => { it('() : should return all preceding siblings', () => { const elems = $('.pear').prevAll(); expect(elems).toHaveLength(2); expect(elems[0].attribs).toHaveProperty('class', 'orange'); expect(elems[1].attribs).toHaveProperty('class', 'apple'); }); it('() : should not contain text elements', () => { const elems = $('.pear', fruits.replace(/></g, '>\n<')); expect(elems.prevAll()).toHaveLength(2); }); it('(no prev) : should return empty for first child', () => { expect($('.apple').prevAll()).toHaveLength(0); }); it('(prevAll on empty object) : should return empty', () => { expect($('.banana').prevAll()).toHaveLength(0); }); it('() : should operate over all elements in the selection', () => { expect($('.orange, .sweetcorn', food).prevAll()).toHaveLength(2); }); it('() : should not contain duplicate elements', () => { const elems = $('.orange, .pear', food); expect(elems.prevAll()).toHaveLength(2); }); describe('(selector) :', () => { it('should filter returned elements', () => { const elems = $('.pear').prevAll('.apple'); expect(elems).toHaveLength(1); }); it("should not consider siblings's descendents", () => { const elems = $('#vegetables', food).prevAll('li'); expect(elems).toHaveLength(0); }); }); }); describe('.prevUntil', () => { it('() : should return all preceding siblings if no selector specified', () => { const elems = $('.pear').prevUntil(); expect(elems).toHaveLength(2); expect(elems[0].attribs).toHaveProperty('class', 'orange'); expect(elems[1].attribs).toHaveProperty('class', 'apple'); }); it('() : should filter out non-element nodes', () => { const elems = $( '<div class="1"><div class="2"></div><!-- comment -->text<div class="3"></div></div>', ); const div = elems.children().last(); expect(div.prevUntil()).toHaveLength(1); }); it('() : should operate over all elements in the selection', () => { const elems = $('.pear, .sweetcorn', food); expect(elems.prevUntil()).toHaveLength(3); }); it('() : should not contain duplicate elements', () => { const elems = $('.orange, .pear', food); expect(elems.prevUntil()).toHaveLength(2); }); it('(selector) : should return all preceding siblings until selector', () => { const elems = $('.pear').prevUntil('.apple'); expect(elems).toHaveLength(1); expect(elems[0].attribs).toHaveProperty('class', 'orange'); }); it('(selector) : should support selector matching multiple elements', () => { const elems = $('#unnamed', forms).prevUntil('option, #disabled'); expect(elems).toHaveLength(2); expect(elems[0].attribs).toHaveProperty('id', 'select'); expect(elems[1].attribs).toHaveProperty('id', 'submit'); }); it('(selector not sibling) : should return all preceding siblings', () => { const elems = $('.sweetcorn', food).prevUntil('#fruits'); expect(elems).toHaveLength(1); expect(elems[0].attribs).toHaveProperty('class', 'carrot'); }); it('(selector, filterString) : should return all preceding siblings until selector, filtered by filter', () => { const elems = $('.cider', drinks).prevUntil('.juice', '.water'); expect(elems).toHaveLength(1); expect(elems[0].attribs).toHaveProperty('class', 'water'); }); it('(selector, filterString) : should return all preceding siblings until selector', () => { const elems = $('<ul><li><p></p></li><li></li></ul>'); const empty = elems.find('li').eq(1).prevUntil(null, 'p'); expect(empty).toHaveLength(0); }); it('() : should return an empty object for first child', () => { expect($('.apple').prevUntil()).toHaveLength(0); }); it('() : should return an empty object when called on an empty object', () => { expect($('.banana').prevUntil()).toHaveLength(0); }); it('(node) : should return all previous siblings until the node', () => { const $fruits = $('#fruits').children(); const elems = $fruits.eq(2).prevUntil($fruits[0]); expect(elems).toHaveLength(1); }); it('(cheerio object) : should return all previous siblings until any member of the cheerio object', () => { const $drinks = $(drinks).children(); const $until = $([$drinks[0], $drinks[1]]); const elems = $drinks.eq(4).prevUntil($until); expect(elems).toHaveLength(2); }); }); describe('.siblings', () => { it('() : should get all the siblings', () => { expect($('.orange').siblings()).toHaveLength(2); expect($('#fruits').siblings()).toHaveLength(0); expect($('.apple, .carrot', food).siblings()).toHaveLength(3); }); it('(selector) : should get all siblings that match the selector', () => { expect($('.orange').siblings('.apple')).toHaveLength(1); expect($('.orange').siblings('.peach')).toHaveLength(0); }); it('(selector) : should throw an Error if given an invalid selector', () => { expect(() => { $('.orange').siblings(':bah'); }).toThrow('Unknown pseudo-class :bah'); }); it('(selector) : does not consider the contents of siblings when filtering (GH-374)', () => { expect($('#fruits', food).siblings('li')).toHaveLength(0); }); it('() : when two elements are siblings to each other they have to be included', () => { const result = load(eleven)('.sel').siblings(); expect(result).toHaveLength(7); expect(result.eq(0).text()).toBe('One'); expect(result.eq(1).text()).toBe('Two'); expect(result.eq(2).text()).toBe('Four'); expect(result.eq(3).text()).toBe('Eight'); expect(result.eq(4).text()).toBe('Nine'); expect(result.eq(5).text()).toBe('Ten'); expect(result.eq(6).text()).toBe('Eleven'); }); it('(selector) : when two elements are siblings to each other they have to be included', () => { const result = load(eleven)('.sel').siblings('.red'); expect(result).toHaveLength(2); expect(result.eq(0).text()).toBe('Four'); expect(result.eq(1).text()).toBe('Nine'); }); it('(cheerio) : test filtering with cheerio object', () => { const doc = load(eleven); const result = doc('.sel').siblings(doc(':not([class])')); expect(result).toHaveLength(4); expect(result.eq(0).text()).toBe('One'); expect(result.eq(1).text()).toBe('Two'); expect(result.eq(2).text()).toBe('Eight'); expect(result.eq(3).text()).toBe('Ten'); }); }); describe('.parents', () => { beforeEach(() => { $ = load(food); }); it('() : should get all of the parents in logical order', () => { const orange = $('.orange').parents(); expect(orange).toHaveLength(4); expect(orange[0].attribs).toHaveProperty('id', 'fruits'); expect(orange[1].attribs).toHaveProperty('id', 'food'); expect(orange[2].tagName).toBe('body'); expect(orange[3].tagName).toBe('html'); const fruits = $('#fruits').parents(); expect(fruits).toHaveLength(3); expect(fruits[0].attribs).toHaveProperty('id', 'food'); expect(fruits[1].tagName).toBe('body'); expect(fruits[2].tagName).toBe('html'); }); it('(selector) : should get all of the parents that match the selector in logical order', () => { const fruits = $('.orange').parents('#fruits'); expect(fruits).toHaveLength(1); expect(fruits[0].attribs).toHaveProperty('id', 'fruits'); const uls = $('.orange').parents('ul'); expect(uls).toHaveLength(2); expect(uls[0].attribs).toHaveProperty('id', 'fruits'); expect(uls[1].attribs).toHaveProperty('id', 'food'); }); it('() : should not break if the selector does not have any results', () => { const result = $('.saladbar').parents(); expect(result).toHaveLength(0); }); it('() : should return an empty set for top-level elements', () => { const result = $('html').parents(); expect(result).toHaveLength(0); }); it('() : should return the parents of every element in the *reveresed* collection, omitting duplicates', () => { const $parents = $('li').parents(); expect($parents).toHaveLength(5); expect($parents[0]).toBe($('#vegetables')[0]); expect($parents[1]).toBe($('#fruits')[0]); expect($parents[2]).toBe($('#food')[0]); expect($parents[3]).toBe($('body')[0]); expect($parents[4]).toBe($('html')[0]); }); }); describe('.parentsUntil', () => { beforeEach(() => { $ = load(food); }); it('() : should get all of the parents in logical order', () => { const result = $('.orange').parentsUntil(); expect(result).toHaveLength(4); expect(result[0].attribs).toHaveProperty('id', 'fruits'); expect(result[1].attribs).toHaveProperty('id', 'food'); expect(result[2].tagName).toBe('body'); expect(result[3].tagName).toBe('html'); }); it('() : should get all of the parents in reversed order, omitting duplicates', () => { const result = $('.apple, .sweetcorn').parentsUntil(); expect(result).toHaveLength(5); expect(result[0]).toBe($('#vegetables')[0]); expect(result[1]).toBe($('#fruits')[0]); expect(result[2]).toBe($('#food')[0]); expect(result[3]).toBe($('body')[0]); expect(result[4]).toBe($('html')[0]); }); it('(selector) : should get all of the parents until selector', () => { const food = $('.orange').parentsUntil('#food'); expect(food).toHaveLength(1); expect(food[0].attribs).toHaveProperty('id', 'fruits'); const fruits = $('.orange').parentsUntil('#fruits'); expect(fruits).toHaveLength(0); }); it('(selector) : Less simple parentsUntil check with selector', () => { const result = $('#fruits').parentsUntil('html, body'); expect(result.eq(0).attr('id')).toBe('food'); }); it('(selector not parent) : should return all parents', () => { const result = $('.orange').parentsUntil('.apple'); expect(result).toHaveLength(4); expect(result[0].attribs).toHaveProperty('id', 'fruits'); expect(result[1].attribs).toHaveProperty('id', 'food'); expect(result[2].tagName).toBe('body'); expect(result[3].tagName).toBe('html'); }); it('(selector, filter) : should get all of the parents that match the filter', () => { const result = $('.apple, .sweetcorn').parentsUntil( '.saladbar', '#vegetables', ); expect(result).toHaveLength(1); expect(result[0].attribs).toHaveProperty('id', 'vegetables'); }); it('(selector, filter) : Multiple-filtered parentsUntil check', () => { const result = $('.orange').parentsUntil('html', 'ul,body'); expect(result).toHaveLength(3); expect(result.eq(0).attr('id')).toBe('fruits'); expect(result.eq(1).attr('id')).toBe('food'); expect(result.eq(2).prop('tagName')).toBe('BODY'); }); it('() : should return empty object when called on an empty object', () => { const result = $('.saladbar').parentsUntil(); expect(result).toHaveLength(0); }); it('() : should return an empty set for top-level elements', () => { const result = $('html').parentsUntil(); expect(result).toHaveLength(0); }); it('(cheerio object) : should return all parents until any member of the cheerio object', () => { const $fruits = $('#fruits'); const $until = $('#food'); const result = $fruits.children().eq(1).parentsUntil($until); expect(result).toHaveLength(1); expect(result[0].attribs).toHaveProperty('id', 'fruits'); }); it('(cheerio object) : should return all parents until body element', () => { const body = $('body')[0]; const result = $('.carrot').parentsUntil(body); expect(result).toHaveLength(2); expect(result.eq(0).is('ul#vegetables')).toBe(true); }); }); describe('.parent', () => { it('() : should return the parent of each matched element', () => { let result = $('.orange').parent(); expect(result).toHaveLength(1); expect(result[0].attribs).toHaveProperty('id', 'fruits'); result = $('li', food).parent(); expect(result).toHaveLength(2); expect(result[0].attribs).toHaveProperty('id', 'fruits'); expect(result[1].attribs).toHaveProperty('id', 'vegetables'); }); it('(undefined) : should not throw an exception', () => { expect(() => { $('li').parent(undefined); }).not.toThrow(); }); it('() : should return an empty object for top-level elements', () => { const result = $('html').parent(); expect(result).toHaveLength(0); }); it('() : should not contain duplicate elements', () => { const result = $('li').parent(); expect(result).toHaveLength(1); }); it('(selector) : should filter the matched parent elements by the selector', () => { const parents = $('.orange').parent(); expect(parents).toHaveLength(1); expect(parents[0].attribs).toHaveProperty('id', 'fruits'); const fruits = $('li', food).parent('#fruits'); expect(fruits).toHaveLength(1); expect(fruits[0].attribs).toHaveProperty('id', 'fruits'); }); }); describe('.closest', () => { it('() : should return an empty array', () => { const result = $('.orange').closest(); expect(result).toHaveLength(0); expect(result).toBeInstanceOf(Cheerio); }); it('(selector) : should find the closest element that matches the selector, searching through its ancestors and itself', () => { expect($('.orange').closest('.apple')).toHaveLength(0); expect( ($('.orange', food).closest('#food')[0] as Element).attribs, ).toHaveProperty('id', 'food'); expect( ($('.orange', food).closest('ul')[0] as Element).attribs, ).toHaveProperty('id', 'fruits'); expect( ($('.orange', food).closest('li')[0] as Element).attribs, ).toHaveProperty('class', 'orange'); }); it('(selector) : should find the closest element of each item, removing duplicates', () => { const result = $('li', food).closest('ul'); expect(result).toHaveLength(2); }); it('() : should not break if the selector does not have any results', () => { const result = $('.saladbar', food).closest('ul'); expect(result).toHaveLength(0); }); it('(selector) : should find closest element for text nodes', () => { const textNode = $('.apple', food).contents().first(); const result = textNode.closest('#food') as Cheerio<Element>; expect(result[0].attribs).toHaveProperty('id', 'food'); }); }); describe('.each', () => { it('( (i, elem) -> ) : should loop selected returning fn with (i, elem)', () => { const items: Element[] = []; const classes = ['apple', 'orange', 'pear']; $('li').each(function (idx, elem) { items[idx] = elem; expect(this.attribs).toHaveProperty('class', classes[idx]); }); expect(items[0].attribs).toHaveProperty('class', 'apple'); expect(items[1].attribs).toHaveProperty('class', 'orange'); expect(items[2].attribs).toHaveProperty('class', 'pear'); }); it('( (i, elem) -> ) : should break iteration when the iterator function returns false', () => { let iterationCount = 0; $('li').each((idx) => { iterationCount++; return idx < 1; }); expect(iterationCount).toBe(2); }); }); if (typeof Symbol !== 'undefined') { describe('[Symbol.iterator]', () => { it('should yield each element', () => { // The equivalent of: for (const element of $('li')) ... const $li = $('li'); const iterator = $li[Symbol.iterator](); expect(iterator.next().value.attribs).toHaveProperty('class', 'apple'); expect(iterator.next().value.attribs).toHaveProperty('class', 'orange'); expect(iterator.next().value.attribs).toHaveProperty('class', 'pear'); expect(iterator.next().done).toBe(true); }); }); } describe('.map', () => { it('(fn) : should be invoked with the correct arguments and context', () => { const $fruits = $('li'); const args: [number, AnyNode][] = []; const thisVals: AnyNode[] = []; $fruits.map(function (...myArgs) { args.push(myArgs); thisVals.push(this); return undefined; }); expect(args).toStrictEqual([ [0, $fruits[0]], [1, $fruits[1]], [2, $fruits[2]], ]); expect(thisVals).toStrictEqual([$fruits[0], $fruits[1], $fruits[2]]); }); it('(fn) : should return an Cheerio object wrapping the returned items', () => { const $fruits = $('li'); const $mapped = $fruits.map((i) => $fruits[2 - i]); expect($mapped).toHaveLength(3); expect($mapped[0]).toBe($fruits[2]); expect($mapped[1]).toBe($fruits[1]); expect($mapped[2]).toBe($fruits[0]); }); it('(fn) : should ignore `null` and `undefined` returned by iterator', () => { const $fruits = $('li'); const retVals = [null, undefined, $fruits[1]]; const $mapped = $fruits.map((i) => retVals[i]); expect($mapped).toHaveLength(1); expect($mapped[0]).toBe($fruits[1]); }); it('(fn) : should preform a shallow merge on arrays returned by iterator', () => { const $fruits = $('li'); const $mapped = $fruits.map(() => [1, [3, 4]]); expect($mapped.get()).toStrictEqual([1, [3, 4], 1, [3, 4], 1, [3, 4]]); }); it('(fn) : should tolerate `null` and `undefined` when flattening arrays returned by iterator', () => { const $fruits = $('li'); const $mapped = $fruits.map(() => [null, undefined]); expect($mapped.get()).toStrictEqual([ null, undefined, null, undefined, null, undefined, ]); }); }); describe('.filter', () => { it('(selector) : should reduce the set of matched elements to those that match the selector', () => { const pear = $('li').filter('.pear').text(); expect(pear).toBe('Pear'); }); it('(selector) : should not consider nested elements', () => { const lis = $('#fruits').filter('li'); expect(lis).toHaveLength(0); }); it('(selection) : should reduce the set of matched elements to those that are contained in the provided selection', () => { const $fruits = $('li'); const $pear = $fruits.filter('.pear, .apple'); expect($fruits.filter($pear)).toHaveLength(2); }); it('(element) : should reduce the set of matched elements to those that specified directly', () => { const $fruits = $('li'); const pear = $fruits.filter('.pear')[0]; expect($fruits.filter(pear)).toHaveLength(1); }); it("(fn) : should reduce the set of matched elements to those that pass the function's test", () => { const orange = $('li') .filter(function (i, el) { expect(this).toBe(el); expect(el.tagName).toBe('li'); expect(typeof i).toBe('number'); return $(this).attr('class') === 'orange'; }) .text(); expect(orange).toBe('Orange'); }); it('should also iterate over text nodes (#1867)', () => { const text = $('<a>a</a>b<c></c>').filter((_, el): el is Text => isText(el), ); expect(text[0].data).toBe('b'); }); }); describe('.not', () => { it('(selector) : should reduce the set of matched elements to those that do not match the selector', () => { const $fruits = $('li'); const $notPear = $fruits.not('.pear'); expect($notPear).toHaveLength(2); expect($notPear[0]).toBe($fruits[0]); expect($notPear[1]).toBe($fruits[1]); }); it('(selector) : should not consider nested elements', () => { const lis = $('#fruits').not('li'); expect(lis).toHaveLength(1); }); it('(selection) : should reduce the set of matched elements to those that are mot contained in the provided selection', () => { const $fruits = $('li'); const $orange = $('.orange'); const $notOrange = $fruits.not($orange); expect($notOrange).toHaveLength(2); expect($notOrange[0]).toBe($fruits[0]); expect($notOrange[1]).toBe($fruits[2]); }); it('(element) : should reduce the set of matched elements to those that specified directly', () => { const $fruits = $('li'); const apple = $('.apple')[0]; const $notApple = $fruits.not(apple); expect($notApple).toHaveLength(2); expect($notApple[0]).toBe($fruits[1]); expect($notApple[1]).toBe($fruits[2]); }); it("(fn) : should reduce the set of matched elements to those that do not pass the function's test", () => { const $fruits = $('li'); const $notOrange = $fruits.not(function (i, el) { expect(this).toBe(el); expect(el).toHaveProperty('name', 'li'); expect(typeof i).toBe('number'); return $(this).attr('class') === 'orange'; }); expect($notOrange).toHaveLength(2); expect($notOrange[0]).toBe($fruits[0]); expect($notOrange[1]).toBe($fruits[2]); }); }); describe('.has', () => { beforeEach(() => { $ = load(food); }); it('(selector) : should reduce the set of matched elements to those with descendants that match the selector', () => { const $fruits = $('#fruits,#vegetables').has('.pear'); expect($fruits).toHaveLength(1); expect($fruits[0]).toBe($('#fruits')[0]); }); it('(selector) : should only consider nested elements', () => { const $empty = $('#fruits').has('#fruits'); expect($empty).toHaveLength(0); }); it('(element) : should reduce the set of matched elements to those that are ancestors of the provided element', () => { const $fruits = $('#fruits,#vegetables').has($('.pear')[0]); expect($fruits).toHaveLength(1); expect($fruits[0]).toBe($('#fruits')[0]); }); it('(element) : should only consider nested elements', () => { const $fruits = $('#fruits'); const fruitsEl = $fruits[0]; const $empty = $fruits.has(fruitsEl); expect($empty).toHaveLength(0); }); }); describe('.first', () => { it('() : should return the first item', () => { const $src = $( '<span>foo</span><span>bar</span><span>baz</span>', ) as Cheerio<Element>; const $elem = $src.first(); expect($elem.length).toBe(1); expect($elem[0].childNodes[0]).toHaveProperty('data', 'foo'); }); it('() : should return an empty object for an empty object', () => { const $src = $(); const $first = $src.first(); expect($first.length).toBe(0); expect($first[0]).toBeUndefined(); }); }); describe('.last', () => { it('() : should return the last element', () => { const $src = $( '<span>foo</span><span>bar</span><span>baz</span>', ) as Cheerio<Element>; const $elem = $src.last(); expect($elem.length).toBe(1); expect($elem[0].childNodes[0]).toHaveProperty('data', 'baz'); }); it('() : should return an empty object for an empty object', () => { const $src = $(); const $last = $src.last(); expect($last.length).toBe(0); expect($last[0]).toBeUndefined(); }); }); describe('.first & .last', () => { it('() : should return equivalent collections if only one element', () => { const $src = $('<span>bar</span>') as Cheerio<Element>; const $first = $src.first(); const $last = $src.last(); expect($first.length).toBe(1); expect($first[0].childNodes[0]).toHaveProperty('data', 'bar'); expect($last.length).toBe(1); expect($last[0].childNodes[0]).toHaveProperty('data', 'bar'); expect($first[0]).toBe($last[0]); }); }); describe('.eq', () => { it('(i) : should return the element at the specified index', () => { expect(getText($('li').eq(0))).toBe('Apple'); expect(getText($('li').eq(1))).toBe('Orange'); expect(getText($('li').eq(2))).toBe('Pear'); expect(getText($('li').eq(3))).toBeUndefined(); expect(getText($('li').eq(-1))).toBe('Pear'); }); }); describe('.get', () => { it('(i) : should return the element at the specified index', () => { const children = $('#fruits').children(); expect(children.get(0)).toBe(children[0]); expect(children.get(1)).toBe(children[1]); expect(children.get(2)).toBe(children[2]); }); it('(-1) : should return the element indexed from the end of the collection', () => { const children = $('#fruits').children(); expect(children.get(-1)).toBe(children[2]); expect(children.get(-2)).toBe(children[1]); expect(children.get(-3)).toBe(children[0]); }); it('() : should return an array containing all of the collection', () => { const children = $('#fruits').children(); const all = children.get(); expect(Array.isArray(all)).toBe(true); expect(all).toStrictEqual([children[0], children[1], children[2]]); }); }); describe('.index', () => { describe('() :', () => { it('returns the index of a child amongst its siblings', () => { expect($('.orange').index()).toBe(1); }); it('returns -1 when the selection has no parent', () => { expect($('<div/>').index()).toBe(-1); }); }); describe('(selector) :', () => { it('returns the index of the first element in the set matched by `selector`', () => { expect($('.apple').index('#fruits, li')).toBe(1); }); it('returns -1 when the item is not present in the set matched by `selector`', () => { expect($('.apple').index('#fuits')).toBe(-1); }); it('returns -1 when the first element in the set has no parent', () => { expect($('<div/>').index('*')).toBe(-1); }); }); describe('(node) :', () => { it('returns the index of the given node within the current selection', () => { const $lis = $('li'); expect($lis.index($lis.get(1))).toBe(1); }); it('returns the index of the given node within the current selection when the current selection has no parent', () => { const $apple = $('.apple').remove(); expect($apple.index($apple.get(0))).toBe(0); }); it('returns -1 when the given node is not present in the current selection', () => { expect($('li').index($('#fruits').get(0))).toBe(-1); }); it('returns -1 when the current selection is empty', () => { expect($('.not-fruit').index($('#fruits').get(0))).toBe(-1); }); }); describe('(selection) :', () => { it('returns the index of the first node in the provided selection within the current selection', () => { const $lis = $('li'); expect($lis.index($('.orange, .pear'))).toBe(1); }); it('returns -1 when the given node is not present in the current selection', () => { expect($('li').index($('#fruits'))).toBe(-1); }); it('returns -1 when the current selection is empty', () => { expect($('.not-fruit').index($('#fruits'))).toBe(-1); }); }); }); describe('.slice', () => { it('(start) : should return all elements after the given index', () => { const sliced = $('li').slice(1); expect(sliced).toHaveLength(2); expect(getText(sliced.eq(0))).toBe('Orange'); expect(getText(sliced.eq(1))).toBe('Pear'); }); it('(start, end) : should return all elements matching the given range', () => { const sliced = $('li').slice(1, 2); expect(sliced).toHaveLength(1); expect(getText(sliced.eq(0))).toBe('Orange'); }); it('(-start) : should return element matching the offset from the end', () => { const sliced = $('li').slice(-1); expect(sliced).toHaveLength(1); expect(getText(sliced.eq(0))).toBe('Pear'); }); }); describe('.end() :', () => { let $fruits: Cheerio<Element>; beforeEach(() => { $fruits = $('#fruits').children(); }); it('returns an empty object at the end of the chain', () => { expect($fruits.end().end().end()).toBeTruthy(); expect($fruits.end().end().end()).toHaveLength(0); }); it('find', () => { expect($fruits.find('.apple').end()).toBe($fruits); }); it('filter', () => { expect($fruits.filter('.apple').end()).toBe($fruits); }); it('map', () => { expect( $fruits .map(function () { return this; }) .end(), ).toBe($fruits); }); it('contents', () => { expect($fruits.contents().end()).toBe($fruits); }); it('eq', () => { expect($fruits.eq(1).end()).toBe($fruits); }); it('first', () => { expect($fruits.first().end()).toBe($fruits); }); it('last', () => { expect($fruits.last().end()).toBe($fruits); }); it('slice', () => { expect($fruits.slice(1).end()).toBe($fruits); }); it('children', () => { expect($fruits.children().end()).toBe($fruits); }); it('parent', () => { expect($fruits.parent().end()).toBe($fruits); }); it('parents', () => { expect($fruits.parents().end()).toBe($fruits); }); it('closest', () => { expect($fruits.closest('ul').end()).toBe($fruits); }); it('siblings', () => { expect($fruits.siblings().end()).toBe($fruits); }); it('next', () => { expect($fruits.next().end()).toBe($fruits); }); it('nextAll', () => { expect($fruits.nextAll().end()).toBe($fruits); }); it('prev', () => { expect($fruits.prev().end()).toBe($fruits); }); it('prevAll', () => { expect($fruits.prevAll().end()).toBe($fruits); }); it('clone', () => { expect($fruits.clone().end()).toBe($fruits); }); }); describe('.add()', () => { let $fruits: Cheerio<AnyNode>; let $apple: Cheerio<Element>; let $orange: Cheerio<Element>; let $pear: Cheerio<Element>; beforeEach(() => { $ = load(food); $fruits = $('#fruits'); $apple = $('.apple'); $orange = $('.orange'); $pear = $('.pear'); }); describe('(selector) matched element :', () => { it('occurs before current selection', () => { const $selection = $orange.add('.apple'); expect($selection).toHaveLength(2); expect($selection[0]).toBe($apple[0]); expect($selection[1]).toBe($orange[0]); }); it('is identical to the current selection', () => { const $selection = $orange.add('.orange'); expect($selection).toHaveLength(1); expect($selection[0]).toBe($orange[0]); }); it('occurs after current selection', () => { const $selection = $orange.add('.pear'); expect($selection).toHaveLength(2); expect($selection[0]).toBe($orange[0]); expect($selection[1]).toBe($pear[0]); }); it('contains the current selection', () => { const $selection = $orange.add('#fruits'); expect($selection).toHaveLength(2); expect($selection[0]).toBe($fruits[0]); expect($selection[1]).toBe($orange[0]); }); it('is a child of the current selection', () => { const $selection = $fruits.add('.orange'); expect($selection).toHaveLength(2); expect($selection[0]).toBe($fruits[0]); expect($selection[1]).toBe($orange[0]); }); it('is root object preserved', () => { const $selection = $('<div></div>').add('#fruits'); expect($selection).toHaveLength(2); expect($selection.eq(0).is('div')).toBe(true); expect($selection.eq(1).is($fruits.eq(0))).toBe(true); }); }); describe('(selector) matched elements :', () => { it('occur before the current selection', () => { const $selection = $pear.add('.apple, .orange'); expect($selection).toHaveLength(3); expect($selection[0]).toBe($apple[0]); expect($selection[1]).toBe($orange[0]); expect($selection[2]).toBe($pear[0]); }); it('include the current selection', () => { const $selection = $pear.add('#fruits li'); expect($selection).toHaveLength(3); expect($selection[0]).toBe($apple[0]); expect($selection[1]).toBe($orange[0]); expect($selection[2]).toBe($pear[0]); }); it('occur after the current selection', () => { const $selection = $apple.add('.orange, .pear'); expect($selection).toHaveLength(3); expect($selection[0]).toBe($apple[0]); expect($selection[1]).toBe($orange[0]); expect($selection[2]).toBe($pear[0]); }); it('occur within the current selection', () => { const $selection = $fruits.add('#fruits li'); expect($selection).toHaveLength(4); expect($selection[0]).toBe($fruits[0]); expect($selection[1]).toBe($apple[0]); expect($selection[2]).toBe($orange[0]); expect($selection[3]).toBe($pear[0]); }); }); describe('(selector, context) :', () => { it(', context)', () => { const $selection = $fruits.add('li', '#vegetables'); expect($selection).toHaveLength(3); expect($selection[0]).toBe($fruits[0]); expect($selection[1]).toBe($('.carrot')[0]); expect($selection[2]).toBe($('.sweetcorn')[0]); }); }); describe('(element) honors document order when element occurs :', () => { it('before the current selection', () => { const $selection = $orange.add($apple[0]); expect($selection).toHaveLength(2); expect($selection[0]).toBe($apple[0]); expect($selection[1]).toBe($orange[0]); }); it('after the current selection', () => { const $selection = $orange.add($pear[0]); expect($selection).toHaveLength(2); expect($selection[0]).toBe($orange[0]); expect($selection[1]).toBe($pear[0]); }); it('within the current selection', () => { const $selection = $fruits.add($orange[0]); expect($selection).toHaveLength(2); expect($selection[0]).toBe($fruits[0]); expect($selection[1]).toBe($orange[0]); }); it('as an ancestor of the current selection', () => { const $selection = $orange.add($fruits[0]); expect($selection).toHaveLength(2); expect($selection[0]).toBe($fruits[0]); expect($selection[1]).toBe($orange[0]); }); it('does not insert an element already contained within the current selection', () => { const $selection = $apple.add($apple[0]); expect($selection).toHaveLength(1); expect($selection[0]).toBe($apple[0]); }); }); describe('([elements]) : elements', () => { it('occur before the current selection', () => { const $selection = $pear.add($('.apple, .orange').get()); expect($selection).toHaveLength(3); expect($selection[0]).toBe($apple[0]); expect($selection[1]).toBe($orange[0]); expect($selection[2]).toBe($pear[0]); }); it('include the current selection', () => { const $selection = $pear.add($('#fruits li').get()); expect($selection).toHaveLength(3); expect($selection[0]).toBe($apple[0]); expect($selection[1]).toBe($orange[0]); expect($selection[2]).toBe($pear[0]); }); it('occur after the current selection', () => { const $selection = $apple.add($('.orange, .pear').get()); expect($selection).toHaveLength(3); expect($selection[0]).toBe($apple[0]); expect($selection[1]).toBe($orange[0]); expect($selection[2]).toBe($pear[0]); }); it('occur within the current selection', () => { const $selection = $fruits.add($('#fruits li').get()); expect($selection).toHaveLength(4); expect($selection[0]).toBe($fruits[0]); expect($selection[1]).toBe($apple[0]); expect($selection[2]).toBe($orange[0]); expect($selection[3]).toBe($pear[0]); }); }); /** * Element order is undefined in this case, so it should not be asserted * here. * * If the collection consists of elements from different documents or ones * not in any document, the sort order is undefined. * * @see {@link https://api.jquery.com/add/} */ it('(html) : correctly parses and adds the new elements', () => { const $selection = $apple.add('<li class="banana">banana</li>'); expect($selection).toHaveLength(2); expect($selection.is('.apple')).toBe(true); expect($selection.is('.banana')).toBe(true); }); describe('(selection) element in selection :', () => { it('occurs before current selection', () => { const $selection = $orange.add($('.apple')); expect($selection).toHaveLength(2); expect($selection[0]).toBe($apple[0]); expect($selection[1]).toBe($orange[0]); }); it('is identical to the current selection', () => { const $selection = $orange.add($('.orange')); expect($selection).toHaveLength(1); expect($selection[0]).toBe($orange[0]); }); it('occurs after current selection', () => { const $selection = $orange.add($('.pear')); expect($selection).toHaveLength(2); expect($selection[0]).toBe($orange[0]); expect($selection[1]).toBe($pear[0]); }); it('contains the current selection', () => { const $selection = $orange.add($('#fruits')); expect($selection).toHaveLength(2); expect($selection[0]).toBe($fruits[0]); expect($selection[1]).toBe($orange[0]); }); it('is a child of the current selection', () => { const $selection = $fruits.add($('.orange')); expect($selection).toHaveLength(2); expect($selection[0]).toBe($fruits[0]); expect($selection[1]).toBe($orange[0]); }); }); describe('(selection) elements in the selection :', () => { it('occur before the current selection', () => { const $selection = $pear.add($('.apple, .orange')); expect($selection).toHaveLength(3); expect($selection[0]).toBe($apple[0]); expect($selection[1]).toBe($orange[0]); expect($selection[2]).toBe($pear[0]); }); it('include the current selection', () => { const $selection = $pear.add($('#fruits li')); expect($selection).toHaveLength(3); expect($selection[0]).toBe($apple[0]); expect($selection[1]).toBe($orange[0]); expect($selection[2]).toBe($pear[0]); }); it('occur after the current selection', () => { const $selection = $apple.add($('.orange, .pear')); expect($selection).toHaveLength(3); expect($selection[0]).toBe($apple[0]); expect($selection[1]).toBe($orange[0]); expect($selection[2]).toBe($pear[0]); }); it('occur within the current selection', () => { const $selection = $fruits.add($('#fruits li')); expect($selection).toHaveLength(4); expect($selection[0]).toBe($fruits[0]); expect($selection[1]).toBe($apple[0]); expect($selection[2]).toBe($orange[0]); expect($selection[3]).toBe($pear[0]); }); }); describe('(selection) :', () => { it('modifying nested selections should not impact the parent [#834]', () => { const apple_pear = $apple.add($pear); // Applies red to apple and pear apple_pear.addClass('red'); expect($apple.hasClass('red')).toBe(true); // This is true expect($pear.hasClass('red')).toBe(true); // This is true // Applies green to pear... AND should not affect apple $pear.addClass('green'); expect($pear.hasClass('green')).toBe(true); // Currently this is true expect($apple.hasClass('green')).toBe(false); // And this should be false! }); }); }); describe('.addBack', () => { describe('() :', () => { it('includes siblings and self', () => { const $selection = $('.orange').siblings().addBack(); expect($selection).toHaveLength(3); expect($selection[0]).toBe($('.apple')[0]); expect($selection[1]).toBe($('.orange')[0]); expect($selection[2]).toBe($('.pear')[0]); }); it('includes children and self', () => { const $selection = $('#fruits').children().addBack(); expect($selection).toHaveLength(4); expect($selection[0]).toBe($('#fruits')[0]); expect($selection[1]).toBe($('.apple')[0]); expect($selection[2]).toBe($('.orange')[0]); expect($selection[3]).toBe($('.pear')[0]); }); it('includes parent and self', () => { const $selection = $('.apple').parent().addBack(); expect($selection).toHaveLength(2); expect($selection[0]).toBe($('#fruits')[0]); expect($selection[1]).toBe($('.apple')[0]); }); it('includes parents and self', () => { const q = load(food); const $selection = q('.apple').parents().addBack(); expect($selection).toHaveLength(5); expect($selection[0]).toBe(q('html')[0]); expect($selection[1]).toBe(q('body')[0]); expect($selection[2]).toBe(q('#food')[0]); expect($selection[3]).toBe(q('#fruits')[0]); expect($selection[4]).toBe(q('.apple')[0]); }); }); it('(filter) : filters the previous selection', () => { const $selection = $('li').eq(1).addBack('.apple'); expect($selection).toHaveLength(2); expect($selection[0]).toBe($('.apple')[0]); expect($selection[1]).toBe($('.orange')[0]); }); it('() : fails gracefully when no args are passed', () => { const $div = cheerio('<div>'); expect($div.addBack()).toBe($div); }); }); describe('.is', () => { it('() : should return false', () => { expect($('li.apple').is()).toBe(false); }); it('(true selector) : should return true', () => { expect(cheerio('#vegetables', vegetables).is('ul')).toBe(true); }); it('(false selector) : should return false', () => { expect(cheerio('#vegetables', vegetables).is('div')).toBe(false); }); it('(true selection) : should return true', () => { const $vegetables = cheerio('li', vegetables); expect($vegetables.is($vegetables.eq(1))).toBe(true); }); it('(false selection) : should return false', () => { const $vegetableList = cheerio(vegetables); const $vegetables = $vegetableList.find('li'); expect($vegetables.is($vegetableList)).toBe(false); }); it('(true element) : should return true', () => { const $vegetables = cheerio('li', vegetables); expect($vegetables.is($vegetables[0])).toBe(true); }); it('(false element) : should return false', () => { const $vegetableList = cheerio(vegetables); const $vegetables = $vegetableList.find('li'); expect($vegetables.is($vegetableList[0])).toBe(false); }); it('(true predicate) : should return true', () => { const result = $('li').is(function () { return this.tagName === 'li' && $(this).hasClass('pear'); }); expect(result).toBe(true); }); it('(false predicate) : should return false', () => { const result = $('li') .last() .is(function () { return this.tagName === 'ul'; }); expect(result).toBe(false); }); }); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/appreply-co/mcp-appstore'

If you have feedback or need assistance with the MCP directory API, please join our Discord server