Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion npm_modules/cli/debugger/devtools-panel.css
Original file line number Diff line number Diff line change
Expand Up @@ -954,7 +954,7 @@ button {

.console-section {
min-height: 0;
grid-template-rows: minmax(0, 1fr) 32px;
grid-template-rows: 32px minmax(0, 1fr) 32px;
}

.console-messages {
Expand Down
13 changes: 13 additions & 0 deletions npm_modules/cli/debugger/devtools-panel.html
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,19 @@
role="tabpanel"
aria-labelledby="consoleTab"
>
<div class="section-header">
<span>Console output</span>
<button
id="clearConsoleButton"
class="text-button"
type="button"
title="Clear console output"
aria-label="Clear console"
aria-controls="consoleMessages"
>
Clear
</button>
</div>
<div id="consoleMessages" class="console-messages"></div>
<form id="consoleForm" class="console-prompt">
<span class="console-chevron">›</span>
Expand Down
12 changes: 9 additions & 3 deletions npm_modules/cli/debugger/devtools-panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ const elements = {
nodeSummary: document.getElementById('nodeSummary'),
elementsSection: document.getElementById('elementsSection'),
splitHandle: document.getElementById('splitHandle'),
clearConsoleButton: document.getElementById('clearConsoleButton'),
consoleMessages: document.getElementById('consoleMessages'),
consoleForm: document.getElementById('consoleForm'),
consoleInput: document.getElementById('consoleInput'),
Expand Down Expand Up @@ -340,9 +341,7 @@ async function connectToInspectedApplication() {
const nextTargetKey = `${payload.target.id}:${payload.target.sessionId}:${inspectedTargetNonce}`;
if (previousTargetKey !== null && previousTargetKey !== nextTargetKey) {
stopConsoleStream();
state.consoleEntries = [];
state.consoleEntryKeys.clear();
elements.consoleMessages.innerHTML = '';
clearConsole();
preparePerformanceForTargetChange();
}
state.target = payload.target;
Expand Down Expand Up @@ -1410,6 +1409,12 @@ function addConsoleEntry(kind, value, timestamp, source) {
elements.consoleMessages.scrollTop = elements.consoleMessages.scrollHeight;
}

function clearConsole() {
state.consoleEntries = [];
state.consoleEntryKeys.clear();
elements.consoleMessages.innerHTML = '';
}

async function evaluateConsoleExpression(expression) {
addConsoleEntry('input', expression);
try {
Expand Down Expand Up @@ -1546,6 +1551,7 @@ function wireEvents() {
if (json) await navigator.clipboard.writeText(json);
});
elements.splitHandle.addEventListener('pointerdown', startSplitResize);
elements.clearConsoleButton.addEventListener('click', clearConsole);
elements.consoleForm.addEventListener('submit', event => {
event.preventDefault();
const expression = elements.consoleInput.value.trim();
Expand Down
74 changes: 73 additions & 1 deletion npm_modules/cli/src/debugger/devtoolsPanel.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ interface StubElement {
scrollHeight: number;
scrollTop: number;
textContent: string;
value: string;
addEventListener(type: string, listener: (event: unknown) => void): void;
dispatch(type: string): void;
}
Expand All @@ -74,12 +75,22 @@ interface MockConsoleEventSource {
}

interface DevToolsConsolePanel {
clearButton: StubElement;
consoleInput: StubElement;
consoleMessages: StubElement;
liveToggle: StubElement;
state: {
autoRefresh: boolean;
consoleEntries: Array<{ kind: string; value: string }>;
consoleHistory: string[];
consoleHistoryIndex: number;
consoleStream: MockConsoleEventSource | null;
consoleStreamTargetKey: string | null;
performance: {
lastTrace: Record<string, unknown> | null;
ownerIdentity: Record<string, string> | null;
traceActive: boolean;
};
target: { id: string; sessionId: string } | null;
};
evaluateConsoleExpression(expression: string): Promise<void>;
Expand Down Expand Up @@ -424,6 +435,7 @@ describe('integrated DevTools console panel', () => {
scrollHeight: 100,
scrollTop: 0,
textContent: '',
value: '',
addEventListener(type: string, listener: (event: unknown) => void): void {
listeners.set(type, listener);
},
Expand Down Expand Up @@ -473,7 +485,7 @@ describe('integrated DevTools console panel', () => {
}

panel = new Script(
`${source}\n({ consoleMessages: elements.consoleMessages, dispatchWindowEvent: type => windowListeners.get(type)?.(), evaluateConsoleExpression, liveToggle: elements.autoRefreshToggle, startConsoleStream, state, stopConsoleStream })`,
`${source}\n({ clearButton: elements.clearConsoleButton, consoleInput: elements.consoleInput, consoleMessages: elements.consoleMessages, dispatchWindowEvent: type => windowListeners.get(type)?.(), evaluateConsoleExpression, liveToggle: elements.autoRefreshToggle, startConsoleStream, state, stopConsoleStream })`,
).runInNewContext({
EventSource: MockEventSource,
URL,
Expand Down Expand Up @@ -538,6 +550,66 @@ describe('integrated DevTools console panel', () => {
expect(panel.consoleMessages.innerHTML).not.toContain('Wrong target');
});

it('exposes an accessible local clear action that is distinct from Performance controls', () => {
const markup = fs.readFileSync(path.resolve(process.cwd(), 'debugger', 'devtools-panel.html'), 'utf8');
const clearButton = markup.match(/<button(?=[^>]*id="clearConsoleButton")[\S\s]*?<\/button>/)?.[0];

expect(clearButton).toBeDefined();
expect(clearButton).toContain('type="button"');
expect(clearButton).toContain('aria-label="Clear console"');
expect(clearButton).toContain('aria-controls="consoleMessages"');
expect(clearButton).not.toContain('data-performance-action');
});

it('clears only local console output while preserving the stream, target, prompt, history, and Performance', () => {
panel.startConsoleStream();
const stream = eventSources[0];
if (!stream) throw new Error('Expected the Chromium console stream to connect.');
const target = panel.state.target;
const streamTargetKey = panel.state.consoleStreamTargetKey;
const performanceOwner = {
inspectedUrl: 'http://127.0.0.1:54321/index.html?valdiDevTools=1',
sessionId: 'web-preview',
targetNonce: 'panel-target-nonce-123456',
};
const lastTrace = { traceCount: 4 };
panel.state.consoleHistory.push('first()', 'second()');
panel.state.consoleHistoryIndex = 1;
panel.consoleInput.value = 'draft expression';
panel.state.performance.ownerIdentity = performanceOwner;
panel.state.performance.lastTrace = lastTrace;
panel.state.performance.traceActive = true;
const entry = {
level: 'info',
message: 'Renderer output',
sessionId: 'web-preview',
source: 'console',
targetId: 'owl:web-preview',
timestamp: 42,
};
stream.emit('console', entry);

panel.clearButton.dispatch('click');

expect(panel.state.consoleEntries).toEqual([]);
expect(panel.consoleMessages.innerHTML).toBe('');
expect(panel.state.consoleStream).toBe(stream);
expect(stream.closed).toBeFalse();
expect(panel.state.target).toBe(target);
expect(panel.state.consoleStreamTargetKey).toBe(streamTargetKey);
expect(panel.consoleInput.value).toBe('draft expression');
expect(panel.state.consoleHistory).toEqual(['first()', 'second()']);
expect(panel.state.consoleHistoryIndex).toBe(1);
expect(panel.state.performance.ownerIdentity).toBe(performanceOwner);
expect(panel.state.performance.lastTrace).toBe(lastTrace);
expect(panel.state.performance.traceActive).toBeTrue();

stream.emit('console', entry);

expect(panel.state.consoleEntries).toEqual([jasmine.objectContaining({ kind: 'info', value: 'Renderer output' })]);
expect(panel.consoleMessages.innerHTML).toContain('Renderer output');
});

it('isolates reconnects, honors the Live toggle, and tears down on pagehide', () => {
panel.startConsoleStream();
const first = eventSources[0];
Expand Down
Loading