11import assert from "assert" ;
22import { ReadableStream } from "stream/web" ;
33import { setTimeout } from "timers/promises" ;
4- import { URLSearchParams } from "url" ;
54import { TextDecoder , TextEncoder } from "util" ;
65import { Response } from "@miniflare/core" ;
76import { HTMLRewriter , HTMLRewriterPlugin } from "@miniflare/html-rewriter" ;
@@ -20,6 +19,8 @@ import {
2019
2120// TODO (someday): debug why removing .serial breaks some of these async tests
2221
22+ const encoder = new TextEncoder ( ) ;
23+
2324// region: ELEMENT HANDLERS
2425
2526const mutationsMacro : Macro <
@@ -556,7 +557,7 @@ test("HTMLRewriter: handles streaming responses", async (t) => {
556557 "</html>" ,
557558 ] ;
558559 for ( const chunk of chunks ) {
559- controller . enqueue ( chunk ) ;
560+ controller . enqueue ( encoder . encode ( chunk ) ) ;
560561 await setTimeout ( 50 ) ;
561562 }
562563 controller . close ( ) ;
@@ -583,43 +584,106 @@ test("HTMLRewriter: handles streaming responses", async (t) => {
583584 t . true ( chunks . length >= 2 ) ;
584585 t . is ( chunks . join ( "" ) , '<html lang="en"><body><p>test</p></body></html>' ) ;
585586} ) ;
586- test ( "HTMLRewriter: handles streaming response with various chunk types" , async ( t ) => {
587- const encoder = new TextEncoder ( ) ;
588- const chunks : [ input : any , output : Uint8Array ] [ ] = [
589- [ new Uint8Array ( [ 1 , 2 , 3 ] ) , new Uint8Array ( [ 1 , 2 , 3 ] ) ] ,
590- [ new Int8Array ( [ 1 , 2 , 3 ] ) , new Uint8Array ( [ 1 , 2 , 3 ] ) ] ,
591- [ encoder . encode ( "test" ) . buffer , encoder . encode ( "test" ) ] ,
592- [ [ 1 , 2 , 3 ] , new Uint8Array ( [ 1 , 2 , 3 ] ) ] ,
593- [ 1 , new Uint8Array ( [ 1 ] ) ] ,
594- [ "test" , encoder . encode ( "test" ) ] ,
595- [
596- new URLSearchParams ( { a : "1" , b : "2" , c : "3" } ) ,
597- encoder . encode ( "a=1&b=2&c=3" ) ,
598- ] ,
599- [ { } , encoder . encode ( "[object Object]" ) ] ,
600- ] ;
601-
587+ test ( "HTMLRewriter: handles ArrayBuffer and ArrayBufferView chunks" , async ( t ) => {
588+ t . plan ( 2 ) ;
602589 const inputStream = new ReadableStream ( {
603- async start ( controller ) {
604- for ( const [ input ] of chunks ) controller . enqueue ( input ) ;
590+ start ( controller ) {
591+ const buffer = encoder . encode ( "<p>" ) . buffer ;
592+ let array = encoder . encode ( "test" ) ;
593+ const view1 = new Uint16Array (
594+ array . buffer ,
595+ array . byteOffset ,
596+ array . byteLength / Uint16Array . BYTES_PER_ELEMENT
597+ ) ;
598+ array = encoder . encode ( "</p>" ) ;
599+ const view2 = new DataView (
600+ array . buffer ,
601+ array . byteOffset ,
602+ array . byteLength
603+ ) ;
604+ controller . enqueue ( buffer ) ;
605+ controller . enqueue ( view1 ) ;
606+ controller . enqueue ( view2 ) ;
607+ controller . close ( ) ;
608+ } ,
609+ } ) ;
610+ const res = new HTMLRewriter ( )
611+ . on ( "p" , {
612+ text ( text ) {
613+ if ( text . text ) t . is ( text . text , "test" ) ;
614+ } ,
615+ } )
616+ . transform ( new Response ( inputStream ) ) ;
617+ t . is ( await res . text ( ) , "<p>test</p>" ) ;
618+ } ) ;
619+ test ( "HTMLRewriter: throws on string chunks" , async ( t ) => {
620+ const inputStream = new ReadableStream ( {
621+ start ( controller ) {
622+ controller . enqueue ( "I'm a string" ) ;
605623 controller . close ( ) ;
606624 } ,
607625 } ) ;
608626 const res = new HTMLRewriter ( ) . transform ( new Response ( inputStream ) ) ;
609- assert ( res . body ) ;
610- for await ( const chunk of res . body ) {
611- const expected = chunks . shift ( ) ;
612- t . deepEqual ( chunk , expected ?. [ 1 ] ) ;
613- }
627+ await t . throwsAsync ( res . text ( ) , {
628+ instanceOf : TypeError ,
629+ message :
630+ "This TransformStream is being used as a byte stream, " +
631+ "but received a string on its writable side. " +
632+ "If you wish to write a string, you'll probably want to " +
633+ "explicitly UTF-8-encode it with TextEncoder." ,
634+ } ) ;
635+ } ) ;
636+ test ( "HTMLRewriter: throws on non-ArrayBuffer/ArrayBufferView chunks" , async ( t ) => {
637+ const inputStream = new ReadableStream ( {
638+ start ( controller ) {
639+ controller . enqueue ( 42 ) ;
640+ controller . close ( ) ;
641+ } ,
642+ } ) ;
643+ const res = new HTMLRewriter ( ) . transform ( new Response ( inputStream ) ) ;
644+ await t . throwsAsync ( res . text ( ) , {
645+ instanceOf : TypeError ,
646+ message :
647+ "This TransformStream is being used as a byte stream, " +
648+ "but received an object of non-ArrayBuffer/ArrayBufferView " +
649+ "type on its writable side." ,
650+ } ) ;
614651} ) ;
615652test ( "HTMLRewriter: handles empty response" , async ( t ) => {
616653 // Shouldn't call BaseHTMLRewriter.write, just BaseHTMLRewriter.end
617- const res = new HTMLRewriter ( ) . transform ( new Response ( ) ) ;
654+ const res = new HTMLRewriter ( )
655+ . onDocument ( {
656+ end ( end ) {
657+ end . append ( "end" ) ;
658+ } ,
659+ } )
660+ . transform ( new Response ( ) ) ;
661+ // Workers don't run the end() handler on null responses
618662 t . is ( await res . text ( ) , "" ) ;
619663} ) ;
620664test ( "HTMLRewriter: handles empty string response" , async ( t ) => {
621- const res = new HTMLRewriter ( ) . transform ( new Response ( "" ) ) ;
622- t . is ( await res . text ( ) , "" ) ;
665+ const res = new HTMLRewriter ( )
666+ . onDocument ( {
667+ end ( end ) {
668+ end . append ( "end" ) ;
669+ } ,
670+ } )
671+ . transform ( new Response ( "" ) ) ;
672+ t . is ( await res . text ( ) , "end" ) ;
673+ } ) ;
674+ test ( "HTNLRewriter: doesn't transform response until needed" , async ( t ) => {
675+ const chunks : string [ ] = [ ] ;
676+ const res = new HTMLRewriter ( )
677+ . on ( "p" , {
678+ text ( text ) {
679+ if ( text . text ) chunks . push ( text . text ) ;
680+ } ,
681+ } )
682+ . transform ( new Response ( "<p>1</p><p>2</p><p>3</p>" ) ) ;
683+ await setTimeout ( 50 ) ;
684+ t . deepEqual ( chunks , [ ] ) ;
685+ await res . arrayBuffer ( ) ;
686+ t . deepEqual ( chunks , [ "1" , "2" , "3" ] ) ;
623687} ) ;
624688test ( "HTMLRewriter: copies response status and headers" , async ( t ) => {
625689 const res = new HTMLRewriter ( ) . transform (
0 commit comments