@@ -9,11 +9,51 @@ const { Network } = require('node:inspector');
99const test = require ( 'node:test' ) ;
1010const assert = require ( 'node:assert' ) ;
1111const { waitUntil } = require ( '../common/inspector-helper' ) ;
12+ const { setImmediate : waitForTurn } = require ( 'node:timers/promises' ) ;
1213
1314const session = new inspector . Session ( ) ;
1415session . connect ( ) ;
1516
17+ function createRequestPayload ( overrides = { } ) {
18+ return {
19+ requestId : '1' ,
20+ timestamp : 1 ,
21+ wallTime : 1 ,
22+ request : {
23+ url : 'https://example.com' ,
24+ method : 'GET' ,
25+ headers : {
26+ mKey : 'mValue' ,
27+ } ,
28+ } ,
29+ ...overrides ,
30+ } ;
31+ }
32+
33+ async function assertInvalidInitiatorStack ( stack , requestId ) {
34+ session . removeAllListeners ( ) ;
35+ await session . post ( 'Network.enable' ) ;
36+
37+ session . on ( 'Network.requestWillBeSent' , common . mustNotCall ( ) ) ;
38+
39+ assert . throws ( ( ) => {
40+ Network . requestWillBeSent ( createRequestPayload ( {
41+ requestId,
42+ initiator : {
43+ type : 'script' ,
44+ stack,
45+ } ,
46+ } ) ) ;
47+ } , {
48+ name : 'TypeError' ,
49+ message : 'Invalid initiator.stack in event' ,
50+ } ) ;
51+
52+ await waitForTurn ( ) ;
53+ }
54+
1655test ( 'should emit Network.requestWillBeSent with unicode' , async ( ) => {
56+ session . removeAllListeners ( ) ;
1757 await session . post ( 'Network.enable' ) ;
1858 const expectedValue = 'CJK 汉字 🍱 🧑🧑🧒🧒' ;
1959
@@ -24,18 +64,179 @@ test('should emit Network.requestWillBeSent with unicode', async () => {
2464 assert . strictEqual ( event . params . request . headers . mKey , expectedValue ) ;
2565 } ) ;
2666
27- Network . requestWillBeSent ( {
28- requestId : '1' ,
29- timestamp : 1 ,
30- wallTime : 1 ,
67+ Network . requestWillBeSent ( createRequestPayload ( {
3168 request : {
3269 url : expectedValue ,
3370 method : expectedValue ,
3471 headers : {
3572 mKey : expectedValue ,
3673 } ,
3774 } ,
38- } ) ;
75+ } ) ) ;
76+
77+ await requestWillBeSentFuture ;
78+ } ) ;
79+
80+ test ( 'should emit Network.requestWillBeSent with custom initiator' , async ( ) => {
81+ session . removeAllListeners ( ) ;
82+ await session . post ( 'Network.enable' ) ;
83+
84+ const requestWillBeSentFuture = waitUntil ( session , 'Network.requestWillBeSent' )
85+ . then ( ( [ event ] ) => {
86+ const { initiator } = event . params ;
87+ assert . strictEqual ( initiator . type , 'parser' ) ;
88+ assert . strictEqual ( initiator . url , 'node:https://initiator.test/app.js' ) ;
89+ assert . strictEqual ( initiator . lineNumber , 12 ) ;
90+ assert . strictEqual ( initiator . columnNumber , 34 ) ;
91+ assert . strictEqual ( initiator . requestId , 'parent-request-id' ) ;
92+ assert . strictEqual ( initiator . stack . description , 'custom stack' ) ;
93+ assert . deepStrictEqual ( initiator . stack . callFrames , [ {
94+ functionName : 'run' ,
95+ scriptId : '99' ,
96+ url : 'file:///custom-frame.js' ,
97+ lineNumber : 3 ,
98+ columnNumber : 5 ,
99+ } ] ) ;
100+ assert . deepStrictEqual ( initiator . stack . parent . callFrames , [ {
101+ functionName : 'parentRun' ,
102+ scriptId : '100' ,
103+ url : 'file:///parent-frame.js' ,
104+ lineNumber : 8 ,
105+ columnNumber : 13 ,
106+ } ] ) ;
107+ assert . deepStrictEqual ( initiator . stack . parentId , {
108+ id : 'async-stack-id' ,
109+ debuggerId : 'debugger-1' ,
110+ } ) ;
111+ } ) ;
112+
113+ Network . requestWillBeSent ( createRequestPayload ( {
114+ requestId : 'custom-initiator-request' ,
115+ initiator : {
116+ type : 'parser' ,
117+ url : 'node:https://initiator.test/app.js' ,
118+ lineNumber : 12 ,
119+ columnNumber : 34 ,
120+ requestId : 'parent-request-id' ,
121+ stack : {
122+ description : 'custom stack' ,
123+ callFrames : [ {
124+ functionName : 'run' ,
125+ scriptId : '99' ,
126+ url : 'file:///custom-frame.js' ,
127+ lineNumber : 3 ,
128+ columnNumber : 5 ,
129+ } ] ,
130+ parent : {
131+ callFrames : [ {
132+ functionName : 'parentRun' ,
133+ scriptId : '100' ,
134+ url : 'file:///parent-frame.js' ,
135+ lineNumber : 8 ,
136+ columnNumber : 13 ,
137+ } ] ,
138+ extraNumber : 1.5 ,
139+ extraBoolean : true ,
140+ extraNull : null ,
141+ } ,
142+ parentId : {
143+ id : 'async-stack-id' ,
144+ debuggerId : 'debugger-1' ,
145+ } ,
146+ extraArray : [ 'frame' , 1 , false , null , { nested : 'value' } ] ,
147+ } ,
148+ } ,
149+ } ) ) ;
39150
40151 await requestWillBeSentFuture ;
41152} ) ;
153+
154+ test ( 'should throw if initiator.type is missing' , async ( ) => {
155+ session . removeAllListeners ( ) ;
156+ await session . post ( 'Network.enable' ) ;
157+
158+ session . on ( 'Network.requestWillBeSent' , common . mustNotCall ( ) ) ;
159+
160+ assert . throws ( ( ) => {
161+ Network . requestWillBeSent ( createRequestPayload ( {
162+ requestId : 'missing-initiator-type' ,
163+ initiator : {
164+ stack : {
165+ callFrames : [ ] ,
166+ } ,
167+ } ,
168+ } ) ) ;
169+ } , {
170+ name : 'TypeError' ,
171+ message : 'Missing initiator.type in event' ,
172+ } ) ;
173+
174+ await waitForTurn ( ) ;
175+ } ) ;
176+
177+ test ( 'should throw if initiator.stack is invalid' , async ( ) => {
178+ await assertInvalidInitiatorStack ( {
179+ callFrames : [ ] ,
180+ unsupportedValue : 1n ,
181+ } , 'invalid-initiator-stack' ) ;
182+ } ) ;
183+
184+ test ( 'should throw if initiator.stack contains an invalid array element' ,
185+ async ( ) => {
186+ await assertInvalidInitiatorStack ( {
187+ callFrames : [ ] ,
188+ extraArray : [ 1n ] ,
189+ } , 'invalid-initiator-stack-array-element' ) ;
190+ } ) ;
191+
192+ test ( 'should throw if initiator.stack contains an array accessor that throws' ,
193+ async ( ) => {
194+ const extraArray = [ ] ;
195+ Object . defineProperty ( extraArray , 0 , {
196+ enumerable : true ,
197+ get ( ) {
198+ throw new Error ( 'array getter boom' ) ;
199+ } ,
200+ } ) ;
201+ extraArray . length = 1 ;
202+
203+ await assertInvalidInitiatorStack ( {
204+ callFrames : [ ] ,
205+ extraArray,
206+ } , 'invalid-initiator-stack-array-getter' ) ;
207+ } ) ;
208+
209+ test ( 'should throw if initiator.stack has a property accessor that throws' ,
210+ async ( ) => {
211+ const stack = { callFrames : [ ] } ;
212+ Object . defineProperty ( stack , 'broken' , {
213+ enumerable : true ,
214+ get ( ) {
215+ throw new Error ( 'getter boom' ) ;
216+ } ,
217+ } ) ;
218+
219+ await assertInvalidInitiatorStack (
220+ stack ,
221+ 'invalid-initiator-stack-property-getter' ,
222+ ) ;
223+ } ) ;
224+
225+ test ( 'should throw if initiator.stack property enumeration throws' , async ( ) => {
226+ const stack = new Proxy ( { callFrames : [ ] } , {
227+ ownKeys ( ) {
228+ throw new Error ( 'ownKeys boom' ) ;
229+ } ,
230+ getOwnPropertyDescriptor ( ) {
231+ return {
232+ enumerable : true ,
233+ configurable : true ,
234+ } ;
235+ } ,
236+ } ) ;
237+
238+ await assertInvalidInitiatorStack (
239+ stack ,
240+ 'invalid-initiator-stack-own-keys' ,
241+ ) ;
242+ } ) ;
0 commit comments