@@ -11,6 +11,7 @@ import (
11
11
"regexp"
12
12
"runtime"
13
13
"strconv"
14
+ "strings"
14
15
"sync/atomic"
15
16
"testing"
16
17
"time"
@@ -2475,3 +2476,349 @@ type request struct {
2475
2476
Size map [string ]int `json:"size"`
2476
2477
URL string `json:"url"`
2477
2478
}
2479
+
2480
+ type response struct {
2481
+ AllHeaders map [string ]string `json:"allHeaders"`
2482
+ Body string `json:"body"`
2483
+ FrameURL string `json:"frameUrl"`
2484
+ AcceptLanguageHeader string `json:"acceptLanguageHeader"`
2485
+ AcceptLanguageHeaders []string `json:"acceptLanguageHeaders"`
2486
+ Headers map [string ]string `json:"headers"`
2487
+ HeadersArray []map [string ]string `json:"headersArray"`
2488
+ JSON string `json:"json"`
2489
+ OK bool `json:"ok"`
2490
+ RequestURL string `json:"requestUrl"`
2491
+ SecurityDetails map [string ]string `json:"securityDetails"`
2492
+ ServerAddr map [string ]any `json:"serverAddr"`
2493
+ Size map [string ]int `json:"size"`
2494
+ Status int64 `json:"status"`
2495
+ StatusText string `json:"statusText"`
2496
+ URL string `json:"url"`
2497
+ Text string `json:"text"`
2498
+ }
2499
+
2500
+ func TestPageOnResponse (t * testing.T ) {
2501
+ t .Parallel ()
2502
+
2503
+ // Start and setup a webserver to test the page.on('request') handler.
2504
+ tb := newTestBrowser (t , withHTTPServer ())
2505
+ defer tb .Browser .Close ()
2506
+
2507
+ tb .withHandler ("/home" , func (w http.ResponseWriter , r * http.Request ) {
2508
+ _ , err := fmt .Fprintf (w , `<!DOCTYPE html>
2509
+ <html>
2510
+ <head>
2511
+ <link rel="stylesheet" href="/style.css">
2512
+ </head>
2513
+ <body>
2514
+ <script>fetch('/api', {
2515
+ method: 'POST',
2516
+ headers: {
2517
+ 'Content-Type': 'application/json'
2518
+ },
2519
+ body: JSON.stringify({name: 'tester'})
2520
+ })</script>
2521
+ </body>
2522
+ </html>` )
2523
+ require .NoError (t , err )
2524
+ })
2525
+ tb .withHandler ("/api" , func (w http.ResponseWriter , r * http.Request ) {
2526
+ body , err := io .ReadAll (r .Body )
2527
+ require .NoError (t , err )
2528
+ defer require .NoError (t , r .Body .Close ())
2529
+
2530
+ var data struct {
2531
+ Name string `json:"name"`
2532
+ }
2533
+ err = json .Unmarshal (body , & data )
2534
+ require .NoError (t , err )
2535
+
2536
+ _ , err = fmt .Fprintf (w , `{"message": "Hello %s!"}` , data .Name )
2537
+ require .NoError (t , err )
2538
+ })
2539
+ tb .withHandler ("/style.css" , func (w http.ResponseWriter , r * http.Request ) {
2540
+ w .Header ().Set ("Content-Type" , "text/css" )
2541
+ _ , err := fmt .Fprintf (w , `body { background-color: #f0f0f0; }` )
2542
+ require .NoError (t , err )
2543
+ })
2544
+
2545
+ // Start and setup a k6 iteration to test the page.on('request') handler.
2546
+ vu , _ , _ , cleanUp := startIteration (t )
2547
+ defer cleanUp ()
2548
+
2549
+ // Some of the business logic is in the mapping layer unfortunately.
2550
+ // To test everything is wried up correctly, we're required to work
2551
+ // with RunPromise.
2552
+ //
2553
+ // The code below is the JavaScript code that is executed in the k6 iteration.
2554
+ // It will wait for all requests to be captured in returnValue, before returning.
2555
+ gv , err := vu .RunAsync (t , `
2556
+ const context = await browser.newContext({locale: 'en-US', userAgent: 'some-user-agent'});
2557
+ const page = await context.newPage();
2558
+
2559
+ var returnValue = [];
2560
+ page.on('response', async (response) => {
2561
+ // We need to check if the response is JSON before calling json()
2562
+ const headers = response.headers();
2563
+ var json = null;
2564
+ if (headers["content-type"] === "application/json") {
2565
+ json = await response.json();
2566
+ }
2567
+
2568
+ returnValue.push({
2569
+ allHeaders: await response.allHeaders(),
2570
+ body: await response.body() ? String.fromCharCode.apply(null, new Uint8Array(await response.body())) : null,
2571
+ frameUrl: response.frame().url(),
2572
+ acceptLanguageHeader: await response.headerValue('Accept-Language'),
2573
+ acceptLanguageHeaders: await response.headerValues('Accept-Language'),
2574
+ headers: response.headers(),
2575
+ headersArray: await response.headersArray(),
2576
+ json: json,
2577
+ ok: response.ok(),
2578
+ requestUrl: response.request().url(),
2579
+ securityDetails: await response.securityDetails(),
2580
+ serverAddr: await response.serverAddr(),
2581
+ size: await response.size(),
2582
+ status: response.status(),
2583
+ statusText: response.statusText(),
2584
+ url: response.url(),
2585
+ text: await response.text()
2586
+ });
2587
+ })
2588
+
2589
+ await page.goto('%s', {waitUntil: 'networkidle'});
2590
+
2591
+ await page.close();
2592
+
2593
+ return JSON.stringify(returnValue, null, 2);
2594
+ ` , tb .url ("/home" ))
2595
+ assert .NoError (t , err )
2596
+
2597
+ got := k6test .ToPromise (t , gv )
2598
+
2599
+ // Convert the result to a string and then to a slice of requests.
2600
+ var responses []response
2601
+ err = json .Unmarshal ([]byte (got .Result ().String ()), & responses )
2602
+ require .NoError (t , err )
2603
+
2604
+ for i := range responses {
2605
+ // Normalize any port numbers in the string values to :8080
2606
+ if responses [i ].URL != "" {
2607
+ responses [i ].URL = regexp .MustCompile (`:\d+` ).ReplaceAllString (responses [i ].URL , ":8080" )
2608
+ }
2609
+ if responses [i ].FrameURL != "" {
2610
+ responses [i ].FrameURL = regexp .MustCompile (`:\d+` ).ReplaceAllString (responses [i ].FrameURL , ":8080" )
2611
+ }
2612
+ for k , v := range responses [i ].AllHeaders {
2613
+ responses [i ].AllHeaders [k ] = regexp .MustCompile (`:\d+` ).ReplaceAllString (v , ":8080" )
2614
+
2615
+ // Normalize the date
2616
+ if strings .Contains (strings .ToLower (k ), "date" ) {
2617
+ responses [i ].AllHeaders [k ] = "Wed, 29 Jan 2025 09:00:00 GMT"
2618
+ }
2619
+ }
2620
+ for k , v := range responses [i ].Headers {
2621
+ responses [i ].Headers [k ] = regexp .MustCompile (`:\d+` ).ReplaceAllString (v , ":8080" )
2622
+
2623
+ // Normalize the date
2624
+ if strings .Contains (strings .ToLower (k ), "date" ) {
2625
+ responses [i ].Headers [k ] = "Wed, 29 Jan 2025 09:00:00 GMT"
2626
+ }
2627
+ }
2628
+ for k , header := range responses [i ].HeadersArray {
2629
+ if header ["value" ] != "" {
2630
+ responses [i ].HeadersArray [k ]["value" ] = regexp .MustCompile (`:\d+` ).ReplaceAllString (header ["value" ], ":8080" )
2631
+ }
2632
+ // Normalize the date
2633
+ if strings .Contains (strings .ToLower (header ["name" ]), "date" ) {
2634
+ responses [i ].HeadersArray [k ]["value" ] = "Wed, 29 Jan 2025 09:00:00 GMT"
2635
+ }
2636
+ }
2637
+ for k := range responses [i ].ServerAddr {
2638
+ if k == "port" {
2639
+ responses [i ].ServerAddr [k ] = 8080
2640
+ }
2641
+ }
2642
+ if responses [i ].RequestURL != "" {
2643
+ responses [i ].RequestURL = regexp .MustCompile (`:\d+` ).ReplaceAllString (responses [i ].RequestURL , ":8080" )
2644
+ }
2645
+ }
2646
+
2647
+ expected := []response {
2648
+ {
2649
+ AllHeaders : map [string ]string {
2650
+ "content-length" : "286" ,
2651
+ "content-type" : "text/html; charset=utf-8" ,
2652
+ "date" : "Wed, 29 Jan 2025 09:00:00 GMT" ,
2653
+ },
2654
+ Body : "<!DOCTYPE html>\n <html>\n <head>\n <link rel=\" stylesheet\" href=\" /style.css\" >\n </head>\n <body>\n <script>fetch('/api', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({name: 'tester'})\n })</script>\n </body>\n </html>" ,
2655
+ FrameURL : "http://127.0.0.1:8080/home" ,
2656
+ AcceptLanguageHeader : "" ,
2657
+ AcceptLanguageHeaders : []string {"" },
2658
+ Headers : map [string ]string {
2659
+ "Content-Length" : "286" ,
2660
+ "Content-Type" : "text/html; charset=utf-8" ,
2661
+ "Date" : "Wed, 29 Jan 2025 09:00:00 GMT" ,
2662
+ },
2663
+ HeadersArray : []map [string ]string {
2664
+ {"name" : "Content-Length" , "value" : "286" },
2665
+ {"name" : "Content-Type" , "value" : "text/html; charset=utf-8" },
2666
+ {"name" : "Date" , "value" : "Wed, 29 Jan 2025 09:00:00 GMT" },
2667
+ },
2668
+ JSON : "" ,
2669
+ OK : true ,
2670
+ RequestURL : "http://127.0.0.1:8080/home" ,
2671
+ SecurityDetails : map [string ]string (nil ),
2672
+ ServerAddr : map [string ]interface {}{"ip_address" : "127.0.0.1" , "port" : 8080 },
2673
+ Size : map [string ]int {"body" : 286 , "headers" : 117 },
2674
+ Status : 200 ,
2675
+ StatusText : "OK" ,
2676
+ URL : "http://127.0.0.1:8080/home" ,
2677
+ Text : "<!DOCTYPE html>\n <html>\n <head>\n <link rel=\" stylesheet\" href=\" /style.css\" >\n </head>\n <body>\n <script>fetch('/api', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({name: 'tester'})\n })</script>\n </body>\n </html>" ,
2678
+ },
2679
+ {
2680
+ AllHeaders : map [string ]string {
2681
+ "content-length" : "35" ,
2682
+ "content-type" : "text/css" ,
2683
+ "date" : "Wed, 29 Jan 2025 09:00:00 GMT" ,
2684
+ },
2685
+ Body : "body { background-color: #f0f0f0; }" ,
2686
+ FrameURL : "http://127.0.0.1:8080/home" ,
2687
+ AcceptLanguageHeader : "" ,
2688
+ AcceptLanguageHeaders : []string {"" },
2689
+ Headers : map [string ]string {
2690
+ "Content-Length" : "35" ,
2691
+ "Content-Type" : "text/css" ,
2692
+ "Date" : "Wed, 29 Jan 2025 09:00:00 GMT" ,
2693
+ },
2694
+ HeadersArray : []map [string ]string {
2695
+ {"name" : "Date" , "value" : "Wed, 29 Jan 2025 09:00:00 GMT" },
2696
+ {"name" : "Content-Type" , "value" : "text/css" },
2697
+ {"name" : "Content-Length" , "value" : "35" },
2698
+ },
2699
+ JSON : "" ,
2700
+ OK : true ,
2701
+ RequestURL : "http://127.0.0.1:8080/style.css" ,
2702
+ SecurityDetails : map [string ]string (nil ),
2703
+ ServerAddr : map [string ]interface {}{"ip_address" : "127.0.0.1" , "port" : 8080 },
2704
+ Size : map [string ]int {"body" : 35 , "headers" : 100 },
2705
+ Status : 200 ,
2706
+ StatusText : "OK" ,
2707
+ URL : "http://127.0.0.1:8080/style.css" ,
2708
+ Text : "body { background-color: #f0f0f0; }" ,
2709
+ },
2710
+ {
2711
+ AllHeaders : map [string ]string {
2712
+ "access-control-allow-credentials" : "true" ,
2713
+ "access-control-allow-origin" : "*" ,
2714
+ "content-length" : "10" ,
2715
+ "content-type" : "text/plain; charset=utf-8" ,
2716
+ "date" : "Wed, 29 Jan 2025 09:00:00 GMT" ,
2717
+ "x-content-type-options" : "nosniff" ,
2718
+ },
2719
+ Body : "Not Found\n " ,
2720
+ FrameURL : "http://127.0.0.1:8080/home" ,
2721
+ AcceptLanguageHeader : "" ,
2722
+ AcceptLanguageHeaders : []string {"" },
2723
+ Headers : map [string ]string {
2724
+ "Access-Control-Allow-Credentials" : "true" ,
2725
+ "Access-Control-Allow-Origin" : "*" ,
2726
+ "Content-Length" : "10" ,
2727
+ "Content-Type" : "text/plain; charset=utf-8" ,
2728
+ "Date" : "Wed, 29 Jan 2025 09:00:00 GMT" ,
2729
+ "X-Content-Type-Options" : "nosniff" ,
2730
+ },
2731
+ HeadersArray : []map [string ]string {
2732
+ {"name" : "Date" , "value" : "Wed, 29 Jan 2025 09:00:00 GMT" },
2733
+ {"name" : "Content-Type" , "value" : "text/plain; charset=utf-8" },
2734
+ {"name" : "Access-Control-Allow-Credentials" , "value" : "true" },
2735
+ {"name" : "X-Content-Type-Options" , "value" : "nosniff" },
2736
+ {"name" : "Access-Control-Allow-Origin" , "value" : "*" },
2737
+ {"name" : "Content-Length" , "value" : "10" },
2738
+ },
2739
+ JSON : "" ,
2740
+ OK : false ,
2741
+ RequestURL : "http://127.0.0.1:8080/favicon.ico" ,
2742
+ SecurityDetails : map [string ]string (nil ),
2743
+ ServerAddr : map [string ]interface {}{"ip_address" : "127.0.0.1" , "port" : 8080 },
2744
+ Size : map [string ]int {"body" : 10 , "headers" : 229 },
2745
+ Status : 404 ,
2746
+ StatusText : "Not Found" ,
2747
+ URL : "http://127.0.0.1:8080/favicon.ico" ,
2748
+ Text : "Not Found\n " ,
2749
+ },
2750
+ {
2751
+ AllHeaders : map [string ]string {
2752
+ "content-length" : "28" ,
2753
+ "content-type" : "text/plain; charset=utf-8" ,
2754
+ "date" : "Wed, 29 Jan 2025 09:00:00 GMT" ,
2755
+ },
2756
+ Body : "" ,
2757
+ FrameURL : "http://127.0.0.1:8080/home" ,
2758
+ AcceptLanguageHeader : "" ,
2759
+ AcceptLanguageHeaders : []string {"" },
2760
+ Headers : map [string ]string {
2761
+ "Content-Length" : "28" ,
2762
+ "Content-Type" : "text/plain; charset=utf-8" ,
2763
+ "Date" : "Wed, 29 Jan 2025 09:00:00 GMT" ,
2764
+ },
2765
+ HeadersArray : []map [string ]string {
2766
+ {"name" : "Date" , "value" : "Wed, 29 Jan 2025 09:00:00 GMT" },
2767
+ {"name" : "Content-Type" , "value" : "text/plain; charset=utf-8" },
2768
+ {"name" : "Content-Length" , "value" : "28" },
2769
+ },
2770
+ JSON : "" ,
2771
+ OK : true ,
2772
+ RequestURL : "http://127.0.0.1:8080/api" ,
2773
+ SecurityDetails : map [string ]string (nil ),
2774
+ ServerAddr : map [string ]interface {}{"ip_address" : "127.0.0.1" , "port" : 8080 },
2775
+ Size : map [string ]int {"body" : 0 , "headers" : 117 },
2776
+ Status : 200 ,
2777
+ StatusText : "OK" ,
2778
+ URL : "http://127.0.0.1:8080/api" ,
2779
+ Text : "" ,
2780
+ },
2781
+ }
2782
+
2783
+ // Compare each request one by one for better test failure visibility
2784
+ for _ , resp := range responses {
2785
+ i := - 1
2786
+ for j , e := range expected {
2787
+ if resp .RequestURL == e .RequestURL {
2788
+ i = j
2789
+ break
2790
+ }
2791
+ }
2792
+ assert .NotEqual (t , - 1 , i , "failed to find expected response with request URL %s" , resp .RequestURL )
2793
+
2794
+ assert .Equal (t , expected [i ].AllHeaders , resp .AllHeaders , "AllHeaders mismatch" )
2795
+ assert .Equal (t , expected [i ].Body , resp .Body , "Body mismatch" )
2796
+ assert .Equal (t , expected [i ].FrameURL , resp .FrameURL , "FrameUrl mismatch" )
2797
+ assert .Equal (t , expected [i ].AcceptLanguageHeader , resp .AcceptLanguageHeader , "AcceptLanguageHeader mismatch" )
2798
+ assert .Equal (t , expected [i ].AcceptLanguageHeaders , resp .AcceptLanguageHeaders , "AcceptLanguageHeaders mismatch" )
2799
+ assert .Equal (t , expected [i ].Headers , resp .Headers , "Headers mismatch" )
2800
+ assert .Equal (t , expected [i ].JSON , resp .JSON , "JSON mismatch" )
2801
+ assert .Equal (t , expected [i ].OK , resp .OK , "OK mismatch" )
2802
+ assert .Equal (t , expected [i ].RequestURL , resp .RequestURL , "RequestURL mismatch" )
2803
+ assert .Equal (t , expected [i ].SecurityDetails , resp .SecurityDetails , "SecurityDetails mismatch" )
2804
+ assert .Equal (t , expected [i ].ServerAddr , resp .ServerAddr , "ServerAddr mismatch" )
2805
+ assert .Equal (t , expected [i ].Size , resp .Size , "Size mismatch" )
2806
+ assert .Equal (t , expected [i ].Status , resp .Status , "Status mismatch" )
2807
+ assert .Equal (t , expected [i ].StatusText , resp .StatusText , "StatusText mismatch" )
2808
+ assert .Equal (t , expected [i ].URL , resp .URL , "URL mismatch" )
2809
+ assert .Equal (t , expected [i ].Text , resp .Text , "Text mismatch" )
2810
+
2811
+ // Compare HeadersArray elements one by one
2812
+ assert .Equal (t , len (expected [i ].HeadersArray ), len (resp .HeadersArray ), "HeadersArray length mismatch" )
2813
+ for _ , expectedHeader := range expected [i ].HeadersArray {
2814
+ found := false
2815
+ for _ , actualHeader := range resp .HeadersArray {
2816
+ if expectedHeader ["name" ] == actualHeader ["name" ] && expectedHeader ["value" ] == actualHeader ["value" ] {
2817
+ found = true
2818
+ break
2819
+ }
2820
+ }
2821
+ assert .True (t , found , fmt .Sprintf ("Expected header {name: %s, value: %s} not found in actual headers" , expectedHeader ["name" ], expectedHeader ["value" ]))
2822
+ }
2823
+ }
2824
+ }
0 commit comments