@@ -11,25 +11,39 @@ const parser = new HtmlParser()
1111
1212describe ( 'HtmlParser' , ( ) => {
1313 describe ( 'resource limits' , ( ) => {
14+ /**
15+ * Pinned by value: a 64 MB body aborts the process, so raising the cap
16+ * toward the shared upload limit must fail here, not in production.
17+ */
1418 it ( 'rejects a document above the input byte cap' , async ( ) => {
15- const sparse = Buffer . concat ( [
16- Buffer . from ( '<html><body><p>' ) ,
17- Buffer . alloc ( 32 * 1024 * 1024 , 0x61 ) ,
18- Buffer . from ( '</p></body></html>' ) ,
19- ] )
20-
21- await expect ( parser . parseBuffer ( sparse ) ) . rejects . toThrow (
22- / a b o v e t h e m a x i m u m o f 3 3 5 5 4 4 3 2 b y t e s /
23- )
19+ const oversized = Buffer . alloc ( 32 * 1024 * 1024 + 1 )
20+
21+ const error = await parser . parseBuffer ( oversized ) . catch ( ( e ) => e )
22+
23+ expect ( error ) . toBeInstanceOf ( HtmlComplexityError )
24+ expect ( error . message ) . toMatch ( / a b o v e t h e m a x i m u m o f 3 3 5 5 4 4 3 2 b y t e s / )
2425 } )
2526
2627 it ( 'rejects a tag-dense document above the markup-token cap' , async ( ) => {
27- const dense = Buffer . from ( `<html><body>${ '<p>a</p>' . repeat ( 300_000 ) } </body></html>` )
28+ const dense = Buffer . from ( `<html><body>${ '<p>a</p>' . repeat ( 600_000 ) } </body></html>` )
2829
2930 const error = await parser . parseBuffer ( dense ) . catch ( ( e ) => e )
3031
3132 expect ( error ) . toBeInstanceOf ( HtmlComplexityError )
32- expect ( error . message ) . toMatch ( / e x c e e d s t h e m a x i m u m o f 5 0 0 0 0 0 m a r k u p t o k e n s / )
33+ expect ( error . message ) . toMatch ( / e x c e e d s t h e m a x i m u m o f 1 0 0 0 0 0 0 m a r k u p t o k e n s / )
34+ } )
35+
36+ /**
37+ * A 30,000-row by 8-column export is ~540k tokens in 3.6 MB, an ordinary
38+ * document that an earlier, tighter token cap rejected.
39+ */
40+ it ( 'accepts a realistic large table export' , async ( ) => {
41+ const row = `<tr>${ '<td>value</td>' . repeat ( 8 ) } </tr>`
42+ const buffer = Buffer . from ( `<html><body><table>${ row . repeat ( 30_000 ) } </table></body></html>` )
43+
44+ const result = await parser . parseBuffer ( buffer )
45+
46+ expect ( result . content ) . toContain ( '| value |' )
3347 } )
3448
3549 it ( 'accepts a byte-heavy document whose markup stays under the token cap' , async ( ) => {
@@ -42,13 +56,11 @@ describe('HtmlParser', () => {
4256 } )
4357
4458 /**
45- * Deep nesting overflows the stack inside cheerio's own recursive `.text()`,
46- * which the pre-parse caps cannot predict. It still has to be classified as
47- * a resource rejection so callers fail closed rather than fall back to
48- * storing the document as raw text.
59+ * `parseFile` must not wrap the rejection in a generic error, or the route
60+ * stops recognising it and falls back to storing the document as raw text.
4961 */
5062 it ( 'preserves the error type through parseFile so callers still fail closed' , async ( ) => {
51- const dense = `<html><body>${ '<p>a</p>' . repeat ( 300_000 ) } </body></html>`
63+ const dense = `<html><body>${ '<p>a</p>' . repeat ( 600_000 ) } </body></html>`
5264 const path = join ( tmpdir ( ) , `html-parser-limits-${ process . pid } .html` )
5365 await writeFile ( path , dense )
5466
@@ -59,6 +71,11 @@ describe('HtmlParser', () => {
5971 }
6072 } )
6173
74+ /**
75+ * Deep nesting overflows the stack inside cheerio's own recursive `.text()`,
76+ * which the pre-parse caps cannot predict. It still has to be classified as
77+ * a resource rejection so callers fail closed.
78+ */
6279 it ( 'classifies a deep-nesting stack overflow as a complexity rejection' , async ( ) => {
6380 const depth = 15_000
6481 const buffer = Buffer . from (
0 commit comments