blob: 1a76a491c2195cce744096b8886f81284be64643 [file] [edit]
// Flags: --inspect=0 --experimental-network-inspection --experimental-storage-inspection
'use strict';
const common = require('../common');
common.skipIfInspectorDisabled();
const inspector = require('node:inspector/promises');
const assert = require('node:assert');
function omit(object, ...keys) {
const copy = { ...object };
for (const key of keys) {
delete copy[key];
}
return copy;
}
function networkRequest(overrides = {}) {
return {
requestId: 'request-id',
timestamp: 1000,
wallTime: 1000,
request: {
url: 'https://nodejs.org/en',
method: 'GET',
headers: {},
},
...overrides,
};
}
function networkResponse(overrides = {}) {
return {
requestId: 'response-id',
timestamp: 1000,
type: 'Other',
response: {
url: 'https://nodejs.org/en',
status: 200,
statusText: 'OK',
headers: {},
},
...overrides,
};
}
function loadingFailed(overrides = {}) {
return {
requestId: 'loading-failed-id',
timestamp: 1000,
type: 'Document',
errorText: 'Failed to load resource',
...overrides,
};
}
function loadingFinished(overrides = {}) {
return {
requestId: 'loading-finished-id',
timestamp: 1000,
...overrides,
};
}
function webSocketCreated(overrides = {}) {
return {
requestId: 'websocket-created-id',
url: 'ws://example.com:8080',
...overrides,
};
}
function webSocketClosed(overrides = {}) {
return {
requestId: 'websocket-closed-id',
timestamp: 1000,
...overrides,
};
}
function webSocketResponse(overrides = {}) {
return {
requestId: 'websocket-response-id',
timestamp: 1000,
response: {
status: 101,
statusText: 'Switching Protocols',
headers: {},
},
...overrides,
};
}
function storageId(overrides = {}) {
return {
securityOrigin: '',
isLocalStorage: true,
storageKey: 'node-inspector://default-dom-storage',
...overrides,
};
}
function domStorageItemAdded(overrides = {}) {
return {
storageId: storageId(),
key: 'testKey',
newValue: 'testValue',
...overrides,
};
}
function domStorageItemRemoved(overrides = {}) {
return {
storageId: storageId(),
key: 'testKey',
...overrides,
};
}
function domStorageItemUpdated(overrides = {}) {
return {
storageId: storageId(),
key: 'testKey',
oldValue: 'oldValue',
newValue: 'newValue',
...overrides,
};
}
function registerStorage(overrides = {}) {
return {
isLocalStorage: true,
storageMap: {},
...overrides,
};
}
const NETWORK_ERROR_CASES = [
[
'requestWillBeSent',
omit(networkRequest(), 'requestId'),
'Missing requestId in event',
],
[
'requestWillBeSent',
omit(networkRequest(), 'timestamp'),
'Missing timestamp in event',
],
[
'requestWillBeSent',
omit(networkRequest(), 'wallTime'),
'Missing wallTime in event',
],
[
'requestWillBeSent',
omit(networkRequest(), 'request'),
'Missing request in event',
],
[
'requestWillBeSent',
networkRequest({ request: omit(networkRequest().request, 'url') }),
'Missing request.url in event',
],
[
'requestWillBeSent',
networkRequest({ request: omit(networkRequest().request, 'method') }),
'Missing request.method in event',
],
[
'requestWillBeSent',
networkRequest({ request: omit(networkRequest().request, 'headers') }),
'Missing request.headers in event',
],
[
'responseReceived',
omit(networkResponse(), 'requestId'),
'Missing requestId in event',
],
[
'responseReceived',
omit(networkResponse(), 'timestamp'),
'Missing timestamp in event',
],
[
'responseReceived',
omit(networkResponse(), 'type'),
'Missing type in event',
],
[
'responseReceived',
omit(networkResponse(), 'response'),
'Missing response in event',
],
[
'responseReceived',
networkResponse({ response: omit(networkResponse().response, 'url') }),
'Missing response.url in event',
],
[
'responseReceived',
networkResponse({ response: omit(networkResponse().response, 'status') }),
'Missing response.status in event',
],
[
'responseReceived',
networkResponse({
response: omit(networkResponse().response, 'statusText'),
}),
'Missing response.statusText in event',
],
[
'responseReceived',
networkResponse({ response: omit(networkResponse().response, 'headers') }),
'Missing response.headers in event',
],
[
'responseReceived',
networkResponse({
response: { ...networkResponse().response, headers: { host: 1 } },
}),
'Invalid header value in event',
],
[
'loadingFailed',
omit(loadingFailed(), 'requestId'),
'Missing requestId in event',
],
[
'loadingFailed',
omit(loadingFailed(), 'timestamp'),
'Missing timestamp in event',
],
['loadingFailed', omit(loadingFailed(), 'type'), 'Missing type in event'],
[
'loadingFailed',
omit(loadingFailed(), 'errorText'),
'Missing errorText in event',
],
[
'loadingFinished',
omit(loadingFinished(), 'requestId'),
'Missing requestId in event',
],
[
'loadingFinished',
omit(loadingFinished(), 'timestamp'),
'Missing timestamp in event',
],
[
'webSocketCreated',
omit(webSocketCreated(), 'requestId'),
'Missing requestId in event',
],
['webSocketCreated', omit(webSocketCreated(), 'url'), 'Missing url in event'],
[
'webSocketClosed',
omit(webSocketClosed(), 'requestId'),
'Missing requestId in event',
],
[
'webSocketClosed',
omit(webSocketClosed(), 'timestamp'),
'Missing timestamp in event',
],
[
'webSocketHandshakeResponseReceived',
omit(webSocketResponse(), 'requestId'),
'Missing requestId in event',
],
[
'webSocketHandshakeResponseReceived',
omit(webSocketResponse(), 'timestamp'),
'Missing timestamp in event',
],
[
'webSocketHandshakeResponseReceived',
omit(webSocketResponse(), 'response'),
'Missing response in event',
],
[
'webSocketHandshakeResponseReceived',
webSocketResponse({
response: omit(webSocketResponse().response, 'status'),
}),
'Missing response.status in event',
],
[
'webSocketHandshakeResponseReceived',
webSocketResponse({
response: omit(webSocketResponse().response, 'statusText'),
}),
'Missing response.statusText in event',
],
[
'webSocketHandshakeResponseReceived',
webSocketResponse({
response: omit(webSocketResponse().response, 'headers'),
}),
'Missing response.headers in event',
],
];
const DOM_STORAGE_ERROR_CASES = [
[
'domStorageItemAdded',
omit(domStorageItemAdded(), 'storageId'),
'Missing storageId in event',
],
[
'domStorageItemAdded',
domStorageItemAdded({ storageId: omit(storageId(), 'securityOrigin') }),
'Missing securityOrigin in storageId',
],
[
'domStorageItemAdded',
domStorageItemAdded({ storageId: omit(storageId(), 'storageKey') }),
'Missing storageKey in storageId',
],
[
'domStorageItemAdded',
omit(domStorageItemAdded(), 'key'),
'Missing key in event',
],
[
'domStorageItemAdded',
omit(domStorageItemAdded(), 'newValue'),
'Missing newValue in event',
],
[
'domStorageItemRemoved',
omit(domStorageItemRemoved(), 'storageId'),
'Missing storageId in event',
],
[
'domStorageItemRemoved',
omit(domStorageItemRemoved(), 'key'),
'Missing key in event',
],
[
'domStorageItemUpdated',
omit(domStorageItemUpdated(), 'storageId'),
'Missing storageId in event',
],
[
'domStorageItemUpdated',
omit(domStorageItemUpdated(), 'key'),
'Missing key in event',
],
[
'domStorageItemUpdated',
omit(domStorageItemUpdated(), 'oldValue'),
'Missing oldValue in event',
],
[
'domStorageItemUpdated',
omit(domStorageItemUpdated(), 'newValue'),
'Missing newValue in event',
],
['domStorageItemsCleared', {}, 'Missing storageId in event'],
[
'registerStorage',
omit(registerStorage(), 'isLocalStorage'),
'Missing isLocalStorage in event',
],
[
'registerStorage',
omit(registerStorage(), 'storageMap'),
'Missing storageMap in event',
],
[
'registerStorage',
registerStorage({
storageMap: new Proxy(
{},
{
ownKeys() {
throw new Error('boom');
},
},
),
}),
'Failed to get property names from storageMap',
],
[
'registerStorage',
registerStorage({
storageMap: new Proxy(
{ testKey: 'testValue' },
{
get(target, property, receiver) {
if (property === 'testKey') throw new Error('boom');
return Reflect.get(target, property, receiver);
},
},
),
}),
'Failed to get value from storageMap',
],
];
const DATA_SENT_REQUEST_ID = 'data-sent-id';
const DATA_SENT_ERROR_CASES = [
[{ finished: false }, 'Missing requestId in event'],
[{ requestId: DATA_SENT_REQUEST_ID }, 'Missing timestamp in event'],
[
{ requestId: DATA_SENT_REQUEST_ID, timestamp: 1000 },
'Missing dataLength in event',
],
[
{ requestId: DATA_SENT_REQUEST_ID, timestamp: 1000, dataLength: 1 },
'Missing data in event',
],
[
{
requestId: DATA_SENT_REQUEST_ID,
timestamp: 1000,
dataLength: 1,
data: {},
},
'Expected data to be Uint8Array in event',
],
];
const DATA_RECEIVED_ERROR_CASES = [
[{}, 'Missing requestId in event'],
[{ requestId: 'data-received-id' }, 'Missing timestamp in event'],
[
{ requestId: 'data-received-id', timestamp: 1000 },
'Missing dataLength in event',
],
[
{ requestId: 'data-received-id', timestamp: 1000, dataLength: 1 },
'Missing encodedDataLength in event',
],
[
{
requestId: 'data-received-id',
timestamp: 1000,
dataLength: 1,
encodedDataLength: 1,
},
'Missing data in event',
],
[
{
requestId: 'data-received-id',
timestamp: 1000,
dataLength: 1,
encodedDataLength: 1,
data: {},
},
'Expected data to be Uint8Array in event',
],
];
function assertEventErrors(domain, name, params, message) {
assert.throws(
() => inspector[domain][name](params),
{
message,
},
`Expected ${domain}.${name} to throw`,
);
}
function startRequest(requestId) {
inspector.Network.requestWillBeSent(networkRequest({ requestId }));
}
(async () => {
const session = new inspector.Session();
session.connect();
await session.post('Network.enable');
await session.post('DOMStorage.enable');
for (const [name, params, message] of NETWORK_ERROR_CASES) {
assertEventErrors('Network', name, params, message);
}
startRequest(DATA_SENT_REQUEST_ID);
for (const [params, message] of DATA_SENT_ERROR_CASES) {
assertEventErrors('Network', 'dataSent', params, message);
}
for (const [params, message] of DATA_RECEIVED_ERROR_CASES) {
assertEventErrors('Network', 'dataReceived', params, message);
}
for (const [name, params, message] of DOM_STORAGE_ERROR_CASES) {
assertEventErrors('DOMStorage', name, params, message);
}
})().then(common.mustCall());