diff options
Diffstat (limited to 'devtools/client/debugger/src/components/SecondaryPanes/Breakpoints')
13 files changed, 1753 insertions, 0 deletions
diff --git a/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/Breakpoint.js b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/Breakpoint.js new file mode 100644 index 0000000000..0e1feb2c43 --- /dev/null +++ b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/Breakpoint.js @@ -0,0 +1,238 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ + +// @flow + +import React, { PureComponent } from "react"; +import { connect } from "../../../utils/connect"; +import { createSelector } from "reselect"; +import classnames from "classnames"; +import actions from "../../../actions"; +import { memoize } from "lodash"; + +import showContextMenu from "./BreakpointsContextMenu"; +import { CloseButton } from "../../shared/Button"; + +import { + getLocationWithoutColumn, + getSelectedText, + makeBreakpointId, +} from "../../../utils/breakpoint"; +import { getSelectedLocation } from "../../../utils/selected-location"; +import { features } from "../../../utils/prefs"; + +import type { + Breakpoint as BreakpointType, + Frame, + Source, + SourceLocation, + Context, +} from "../../../types"; +import type SourceEditor from "../../../utils/editor/source-editor"; + +type FormattedFrame = Frame & { + selectedLocation: SourceLocation, +}; + +import { + getBreakpointsList, + getSelectedFrame, + getSelectedSource, + getCurrentThread, + getContext, +} from "../../../selectors"; + +type OwnProps = {| + source: Source, + selectedSource: ?Source, + breakpoint: BreakpointType, + editor: SourceEditor, +|}; +type Props = { + cx: Context, + breakpoint: BreakpointType, + breakpoints: BreakpointType[], + selectedSource: ?Source, + source: Source, + frame: FormattedFrame, + editor: SourceEditor, + enableBreakpoint: typeof actions.enableBreakpoint, + removeBreakpoint: typeof actions.removeBreakpoint, + removeBreakpoints: typeof actions.removeBreakpoints, + removeAllBreakpoints: typeof actions.removeAllBreakpoints, + disableBreakpoint: typeof actions.disableBreakpoint, + setBreakpointOptions: typeof actions.setBreakpointOptions, + toggleAllBreakpoints: typeof actions.toggleAllBreakpoints, + toggleBreakpoints: typeof actions.toggleBreakpoints, + toggleDisabledBreakpoint: typeof actions.toggleDisabledBreakpoint, + openConditionalPanel: typeof actions.openConditionalPanel, + selectSpecificLocation: typeof actions.selectSpecificLocation, +}; + +class Breakpoint extends PureComponent<Props> { + onContextMenu = (e: SyntheticEvent<HTMLElement>) => { + showContextMenu({ ...this.props, contextMenuEvent: e }); + }; + + get selectedLocation() { + const { breakpoint, selectedSource } = this.props; + return getSelectedLocation(breakpoint, selectedSource); + } + + onDoubleClick = () => { + const { breakpoint, openConditionalPanel } = this.props; + if (breakpoint.options.condition) { + openConditionalPanel(this.selectedLocation); + } else if (breakpoint.options.logValue) { + openConditionalPanel(this.selectedLocation, true); + } + }; + + selectBreakpoint = (event: SyntheticEvent<>) => { + event.preventDefault(); + const { cx, selectSpecificLocation } = this.props; + selectSpecificLocation(cx, this.selectedLocation); + }; + + removeBreakpoint = (event: SyntheticEvent<>) => { + const { cx, removeBreakpoint, breakpoint } = this.props; + event.stopPropagation(); + removeBreakpoint(cx, breakpoint); + }; + + handleBreakpointCheckbox = () => { + const { cx, breakpoint, enableBreakpoint, disableBreakpoint } = this.props; + if (breakpoint.disabled) { + enableBreakpoint(cx, breakpoint); + } else { + disableBreakpoint(cx, breakpoint); + } + }; + + isCurrentlyPausedAtBreakpoint() { + const { frame } = this.props; + if (!frame) { + return false; + } + + const bpId = features.columnBreakpoints + ? makeBreakpointId(this.selectedLocation) + : getLocationWithoutColumn(this.selectedLocation); + const frameId = features.columnBreakpoints + ? makeBreakpointId(frame.selectedLocation) + : getLocationWithoutColumn(frame.selectedLocation); + return bpId == frameId; + } + + getBreakpointLocation() { + const { source } = this.props; + const { column, line } = this.selectedLocation; + + const isWasm = source?.isWasm; + const columnVal = features.columnBreakpoints && column ? `:${column}` : ""; + const bpLocation = isWasm + ? `0x${line.toString(16).toUpperCase()}` + : `${line}${columnVal}`; + + return bpLocation; + } + + getBreakpointText() { + const { breakpoint, selectedSource } = this.props; + const { condition, logValue } = breakpoint.options; + return logValue || condition || getSelectedText(breakpoint, selectedSource); + } + + highlightText = memoize( + (text: string = "", editor: SourceEditor) => { + const node = document.createElement("div"); + editor.CodeMirror.runMode(text, "application/javascript", node); + return { __html: node.innerHTML }; + }, + text => text + ); + + render() { + const { breakpoint, editor } = this.props; + const text = this.getBreakpointText(); + const labelId = `${breakpoint.id}-label`; + + return ( + <div + className={classnames({ + breakpoint, + paused: this.isCurrentlyPausedAtBreakpoint(), + disabled: breakpoint.disabled, + "is-conditional": !!breakpoint.options.condition, + "is-log": !!breakpoint.options.logValue, + })} + onClick={this.selectBreakpoint} + onDoubleClick={this.onDoubleClick} + onContextMenu={this.onContextMenu} + > + <input + id={breakpoint.id} + type="checkbox" + className="breakpoint-checkbox" + checked={!breakpoint.disabled} + onChange={this.handleBreakpointCheckbox} + onClick={ev => ev.stopPropagation()} + aria-labelledby={labelId} + /> + <span + id={labelId} + className="breakpoint-label cm-s-mozilla devtools-monospace" + onClick={this.selectBreakpoint} + title={text} + > + <span dangerouslySetInnerHTML={this.highlightText(text, editor)} /> + </span> + <div className="breakpoint-line-close"> + <div className="breakpoint-line devtools-monospace"> + {this.getBreakpointLocation()} + </div> + <CloseButton + handleClick={e => this.removeBreakpoint(e)} + tooltip={L10N.getStr("breakpoints.removeBreakpointTooltip")} + /> + </div> + </div> + ); + } +} + +const getFormattedFrame = createSelector( + getSelectedSource, + getSelectedFrame, + (selectedSource: ?Source, frame: ?Frame): ?FormattedFrame => { + if (!frame) { + return null; + } + + return { + ...frame, + selectedLocation: getSelectedLocation(frame, selectedSource), + }; + } +); + +const mapStateToProps = (state, p: OwnProps) => ({ + cx: getContext(state), + breakpoints: getBreakpointsList(state), + frame: getFormattedFrame(state, getCurrentThread(state)), +}); + +export default connect<Props, OwnProps, _, _, _, _>(mapStateToProps, { + enableBreakpoint: actions.enableBreakpoint, + removeBreakpoint: actions.removeBreakpoint, + removeBreakpoints: actions.removeBreakpoints, + removeAllBreakpoints: actions.removeAllBreakpoints, + disableBreakpoint: actions.disableBreakpoint, + selectSpecificLocation: actions.selectSpecificLocation, + setBreakpointOptions: actions.setBreakpointOptions, + toggleAllBreakpoints: actions.toggleAllBreakpoints, + toggleBreakpoints: actions.toggleBreakpoints, + toggleDisabledBreakpoint: actions.toggleDisabledBreakpoint, + openConditionalPanel: actions.openConditionalPanel, +})(Breakpoint); diff --git a/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/BreakpointHeading.js b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/BreakpointHeading.js new file mode 100644 index 0000000000..e224accae1 --- /dev/null +++ b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/BreakpointHeading.js @@ -0,0 +1,92 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ + +// @flow +import React, { PureComponent } from "react"; +import { connect } from "../../../utils/connect"; +import actions from "../../../actions"; +import { + getTruncatedFileName, + getDisplayPath, + getSourceQueryString, + getFileURL, +} from "../../../utils/source"; +import { + getHasSiblingOfSameName, + getBreakpointsForSource, + getContext, +} from "../../../selectors"; + +import SourceIcon from "../../shared/SourceIcon"; + +import type { Source, Breakpoint, Context } from "../../../types"; +import showContextMenu from "./BreakpointHeadingsContextMenu"; + +type OwnProps = {| + sources: Source[], + source: Source, +|}; +type Props = { + cx: Context, + sources: Source[], + source: Source, + hasSiblingOfSameName: boolean, + breakpointsForSource: Breakpoint[], + disableBreakpointsInSource: typeof actions.disableBreakpointsInSource, + enableBreakpointsInSource: typeof actions.enableBreakpointsInSource, + removeBreakpointsInSource: typeof actions.removeBreakpointsInSource, + selectSource: typeof actions.selectSource, +}; + +class BreakpointHeading extends PureComponent<Props> { + onContextMenu = (e: SyntheticEvent<HTMLElement>) => { + showContextMenu({ ...this.props, contextMenuEvent: e }); + }; + + render() { + const { + cx, + sources, + source, + hasSiblingOfSameName, + selectSource, + } = this.props; + + const path = getDisplayPath(source, sources); + const query = hasSiblingOfSameName ? getSourceQueryString(source) : ""; + + return ( + <div + className="breakpoint-heading" + title={getFileURL(source, false)} + onClick={() => selectSource(cx, source.id)} + onContextMenu={this.onContextMenu} + > + <SourceIcon + source={source} + modifier={icon => + ["file", "javascript"].includes(icon) ? null : icon + } + /> + <div className="filename"> + {getTruncatedFileName(source, query)} + {path && <span>{`../${path}/..`}</span>} + </div> + </div> + ); + } +} + +const mapStateToProps = (state, { source }) => ({ + cx: getContext(state), + hasSiblingOfSameName: getHasSiblingOfSameName(state, source), + breakpointsForSource: getBreakpointsForSource(state, source.id), +}); + +export default connect<Props, OwnProps, _, _, _, _>(mapStateToProps, { + selectSource: actions.selectSource, + enableBreakpointsInSource: actions.enableBreakpointsInSource, + disableBreakpointsInSource: actions.disableBreakpointsInSource, + removeBreakpointsInSource: actions.removeBreakpointsInSource, +})(BreakpointHeading); diff --git a/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/BreakpointHeadingsContextMenu.js b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/BreakpointHeadingsContextMenu.js new file mode 100644 index 0000000000..443b4681b4 --- /dev/null +++ b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/BreakpointHeadingsContextMenu.js @@ -0,0 +1,92 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ + +// @flow + +import { buildMenu, showMenu } from "../../../context-menu/menu"; + +import actions from "../../../actions"; +import type { Breakpoint, Source, Context } from "../../../types"; + +type Props = { + cx: Context, + source: Source, + breakpointsForSource: Breakpoint[], + disableBreakpointsInSource: typeof actions.disableBreakpointsInSource, + enableBreakpointsInSource: typeof actions.enableBreakpointsInSource, + removeBreakpointsInSource: typeof actions.removeBreakpointsInSource, + contextMenuEvent: SyntheticEvent<HTMLElement>, +}; + +export default function showContextMenu(props: Props) { + const { + cx, + source, + breakpointsForSource, + disableBreakpointsInSource, + enableBreakpointsInSource, + removeBreakpointsInSource, + contextMenuEvent, + } = props; + + contextMenuEvent.preventDefault(); + + const enableInSourceLabel = L10N.getStr( + "breakpointHeadingsMenuItem.enableInSource.label" + ); + const disableInSourceLabel = L10N.getStr( + "breakpointHeadingsMenuItem.disableInSource.label" + ); + const removeInSourceLabel = L10N.getStr( + "breakpointHeadingsMenuItem.removeInSource.label" + ); + const enableInSourceKey = L10N.getStr( + "breakpointHeadingsMenuItem.enableInSource.accesskey" + ); + const disableInSourceKey = L10N.getStr( + "breakpointHeadingsMenuItem.disableInSource.accesskey" + ); + const removeInSourceKey = L10N.getStr( + "breakpointHeadingsMenuItem.removeInSource.accesskey" + ); + + const disableInSourceItem = { + id: "node-menu-disable-in-source", + label: disableInSourceLabel, + accesskey: disableInSourceKey, + disabled: false, + click: () => disableBreakpointsInSource(cx, source), + }; + + const enableInSourceItem = { + id: "node-menu-enable-in-source", + label: enableInSourceLabel, + accesskey: enableInSourceKey, + disabled: false, + click: () => enableBreakpointsInSource(cx, source), + }; + + const removeInSourceItem = { + id: "node-menu-enable-in-source", + label: removeInSourceLabel, + accesskey: removeInSourceKey, + disabled: false, + click: () => removeBreakpointsInSource(cx, source), + }; + + const hideDisableInSourceItem = breakpointsForSource.every( + breakpoint => breakpoint.disabled + ); + const hideEnableInSourceItem = breakpointsForSource.every( + breakpoint => !breakpoint.disabled + ); + + const items = [ + { item: disableInSourceItem, hidden: () => hideDisableInSourceItem }, + { item: enableInSourceItem, hidden: () => hideEnableInSourceItem }, + { item: removeInSourceItem, hidden: () => false }, + ]; + + showMenu(contextMenuEvent, buildMenu(items)); +} diff --git a/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/Breakpoints.css b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/Breakpoints.css new file mode 100644 index 0000000000..7dae8d2304 --- /dev/null +++ b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/Breakpoints.css @@ -0,0 +1,253 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ + +.breakpoints-pane > ._content { + overflow-x: auto; +} + +.breakpoints-toggle { + margin: 2px 3px; +} + +.breakpoints-exceptions-options *, +.breakpoints-list * { + user-select: none; +} + +.breakpoints-list { + padding: 4px 0; +} + +.breakpoints-list .breakpoint-heading { + text-overflow: ellipsis; + width: 100%; + font-size: 12px; + line-height: 16px; +} + +.breakpoint-heading:not(:first-child) { + margin-top: 2px; +} + +.breakpoints-list .breakpoint-heading .filename { + overflow: hidden; + text-overflow: ellipsis; +} + +.breakpoints-list .breakpoint-heading .filename span { + opacity: 0.7; + padding-left: 4px; +} + +.breakpoints-list .breakpoint-heading, +.breakpoints-list .breakpoint { + color: var(--theme-text-color-strong); + position: relative; + cursor: pointer; +} + +.breakpoints-list .breakpoint-heading, +.breakpoints-list .breakpoint, +.breakpoints-exceptions, +.breakpoints-exceptions-caught { + display: flex; + align-items: center; + overflow: hidden; + padding-top: 2px; + padding-bottom: 2px; + padding-inline-start: 16px; + padding-inline-end: 12px; +} + +.breakpoints-exceptions { + padding-bottom: 3px; + padding-top: 3px; + user-select: none; +} + +.breakpoints-exceptions-caught { + padding-bottom: 3px; + padding-top: 3px; + padding-inline-start: 36px; +} + +.breakpoints-exceptions-options { + padding-top: 4px; + padding-bottom: 4px; +} + +.xhr-breakpoints-pane .breakpoints-exceptions-options { + border-bottom: 1px solid var(--theme-splitter-color); +} + +.breakpoints-exceptions-options:not(.empty) { + border-bottom: 1px solid var(--theme-splitter-color); +} + +.breakpoints-exceptions input, +.breakpoints-exceptions-caught input { + padding-inline-start: 2px; + margin-top: 0px; + margin-bottom: 0px; + margin-inline-start: 0; + margin-inline-end: 2px; + vertical-align: text-bottom; +} + +.breakpoint-exceptions-label { + line-height: 14px; + padding-inline-end: 8px; + cursor: default; + overflow: hidden; + text-overflow: ellipsis; +} + +html[dir="rtl"] .breakpoints-list .breakpoint, +html[dir="rtl"] .breakpoints-list .breakpoint-heading, +html[dir="rtl"] .breakpoints-exceptions { + border-right: 4px solid transparent; +} + +html:not([dir="rtl"]) .breakpoints-list .breakpoint, +html:not([dir="rtl"]) .breakpoints-list .breakpoint-heading, +html:not([dir="rtl"]) .breakpoints-exceptions { + border-left: 4px solid transparent; +} + +html .breakpoints-list .breakpoint.is-conditional { + border-inline-start-color: var(--theme-graphs-yellow); +} + +html .breakpoints-list .breakpoint.is-log { + border-inline-start-color: var(--theme-graphs-purple); +} + +html .breakpoints-list .breakpoint.paused { + background-color: var(--theme-toolbar-background-alt); + border-color: var(--breakpoint-active-color); +} + +.breakpoints-list .breakpoint:hover { + background-color: var(--search-overlays-semitransparent); +} + +.breakpoint-line-close { + margin-inline-start: 4px; +} + +.breakpoints-list .breakpoint .breakpoint-line { + font-size: 11px; + color: var(--theme-comment); + min-width: 16px; + text-align: end; + padding-top: 1px; + padding-bottom: 1px; +} + +.breakpoints-list .breakpoint:hover .breakpoint-line, +.breakpoints-list .breakpoint-line-close:focus-within .breakpoint-line { + color: transparent; +} + +.breakpoints-list .breakpoint.paused:hover { + border-color: var(--breakpoint-active-color-hover); +} + +.breakpoints-list .breakpoint-label { + display: inline-block; + cursor: pointer; + flex-grow: 1; + text-overflow: ellipsis; + overflow: hidden; + font-size: 11px; +} + +.breakpoints-list .breakpoint-label span, +.breakpoint-line-close { + display: inline; + line-height: 14px; +} + +.breakpoint-checkbox { + margin-inline-start: 0px; + margin-top: 0px; + margin-bottom: 0px; + vertical-align: text-bottom; +} + +.breakpoint-label .location { + width: 100%; + display: inline-block; + overflow-x: hidden; + text-overflow: ellipsis; + padding: 1px 0; + vertical-align: bottom; +} + +.breakpoints-list .pause-indicator { + flex: 0 1 content; + order: 3; +} + +.breakpoint .close-btn { + position: absolute; + /* hide button outside of row until hovered or focused */ + top: -100px; +} + +[dir="ltr"] .breakpoint .close-btn { + right: 12px; +} + +[dir="rtl"] .breakpoint .close-btn { + left: 12px; +} + +/* Reveal the remove button on hover/focus */ +.breakpoint:hover .close-btn, +.breakpoint .close-btn:focus { + top: calc(50% - 8px); +} + +/* Hide the line number when revealing the remove button (since they're overlayed) */ +.breakpoint-line-close:focus-within .breakpoint-line, +.breakpoint:hover .breakpoint-line { + visibility: hidden; +} + +.CodeMirror.cm-s-mozilla-breakpoint { + cursor: pointer; +} + +.CodeMirror.cm-s-mozilla-breakpoint .CodeMirror-lines { + padding: 0; +} + +.CodeMirror.cm-s-mozilla-breakpoint .CodeMirror-sizer { + min-width: initial !important; +} + +.breakpoints-list .breakpoint .CodeMirror.cm-s-mozilla-breakpoint { + transition: opacity 0.15s linear; +} + +.breakpoints-list .breakpoint.disabled .CodeMirror.cm-s-mozilla-breakpoint { + opacity: 0.5; +} + +.CodeMirror.cm-s-mozilla-breakpoint .CodeMirror-line span[role="presentation"] { + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + display: inline-block; +} + +.CodeMirror.cm-s-mozilla-breakpoint .CodeMirror-code, +.CodeMirror.cm-s-mozilla-breakpoint .CodeMirror-scroll { + pointer-events: none; +} + +.CodeMirror.cm-s-mozilla-breakpoint { + padding-top: 1px; +} diff --git a/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/BreakpointsContextMenu.js b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/BreakpointsContextMenu.js new file mode 100644 index 0000000000..20f8691a6e --- /dev/null +++ b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/BreakpointsContextMenu.js @@ -0,0 +1,366 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ + +// @flow + +import { buildMenu, showMenu } from "../../../context-menu/menu"; +import { getSelectedLocation } from "../../../utils/selected-location"; +import actions from "../../../actions"; +import { features } from "../../../utils/prefs"; +import { formatKeyShortcut } from "../../../utils/text"; + +import type { Breakpoint, Source, Context } from "../../../types"; + +type Props = { + cx: Context, + breakpoint: Breakpoint, + breakpoints: Breakpoint[], + selectedSource: ?Source, + removeBreakpoint: typeof actions.removeBreakpoint, + removeBreakpoints: typeof actions.removeBreakpoints, + removeAllBreakpoints: typeof actions.removeAllBreakpoints, + toggleBreakpoints: typeof actions.toggleBreakpoints, + toggleAllBreakpoints: typeof actions.toggleAllBreakpoints, + toggleDisabledBreakpoint: typeof actions.toggleDisabledBreakpoint, + selectSpecificLocation: typeof actions.selectSpecificLocation, + setBreakpointOptions: typeof actions.setBreakpointOptions, + openConditionalPanel: typeof actions.openConditionalPanel, + contextMenuEvent: SyntheticEvent<HTMLElement>, +}; + +export default function showContextMenu(props: Props) { + const { + cx, + breakpoint, + breakpoints, + selectedSource, + removeBreakpoint, + removeBreakpoints, + removeAllBreakpoints, + toggleBreakpoints, + toggleAllBreakpoints, + toggleDisabledBreakpoint, + selectSpecificLocation, + setBreakpointOptions, + openConditionalPanel, + contextMenuEvent, + } = props; + + contextMenuEvent.preventDefault(); + + const deleteSelfLabel = L10N.getStr("breakpointMenuItem.deleteSelf2.label"); + const deleteAllLabel = L10N.getStr("breakpointMenuItem.deleteAll2.label"); + const deleteOthersLabel = L10N.getStr( + "breakpointMenuItem.deleteOthers2.label" + ); + const enableSelfLabel = L10N.getStr("breakpointMenuItem.enableSelf2.label"); + const enableAllLabel = L10N.getStr("breakpointMenuItem.enableAll2.label"); + const enableOthersLabel = L10N.getStr( + "breakpointMenuItem.enableOthers2.label" + ); + const disableSelfLabel = L10N.getStr("breakpointMenuItem.disableSelf2.label"); + const disableAllLabel = L10N.getStr("breakpointMenuItem.disableAll2.label"); + const disableOthersLabel = L10N.getStr( + "breakpointMenuItem.disableOthers2.label" + ); + const enableDbgStatementLabel = L10N.getStr( + "breakpointMenuItem.enabledbg.label" + ); + const disableDbgStatementLabel = L10N.getStr( + "breakpointMenuItem.disabledbg.label" + ); + const removeConditionLabel = L10N.getStr( + "breakpointMenuItem.removeCondition2.label" + ); + const addConditionLabel = L10N.getStr( + "breakpointMenuItem.addCondition2.label" + ); + const editConditionLabel = L10N.getStr( + "breakpointMenuItem.editCondition2.label" + ); + + const deleteSelfKey = L10N.getStr("breakpointMenuItem.deleteSelf2.accesskey"); + const deleteAllKey = L10N.getStr("breakpointMenuItem.deleteAll2.accesskey"); + const deleteOthersKey = L10N.getStr( + "breakpointMenuItem.deleteOthers2.accesskey" + ); + const enableSelfKey = L10N.getStr("breakpointMenuItem.enableSelf2.accesskey"); + const enableAllKey = L10N.getStr("breakpointMenuItem.enableAll2.accesskey"); + const enableOthersKey = L10N.getStr( + "breakpointMenuItem.enableOthers2.accesskey" + ); + const disableSelfKey = L10N.getStr( + "breakpointMenuItem.disableSelf2.accesskey" + ); + const disableAllKey = L10N.getStr("breakpointMenuItem.disableAll2.accesskey"); + const disableOthersKey = L10N.getStr( + "breakpointMenuItem.disableOthers2.accesskey" + ); + const removeConditionKey = L10N.getStr( + "breakpointMenuItem.removeCondition2.accesskey" + ); + const editConditionKey = L10N.getStr( + "breakpointMenuItem.editCondition2.accesskey" + ); + const addConditionKey = L10N.getStr( + "breakpointMenuItem.addCondition2.accesskey" + ); + + const selectedLocation = getSelectedLocation(breakpoint, selectedSource); + const otherBreakpoints = breakpoints.filter(b => b.id !== breakpoint.id); + const enabledBreakpoints = breakpoints.filter(b => !b.disabled); + const disabledBreakpoints = breakpoints.filter(b => b.disabled); + const otherEnabledBreakpoints = breakpoints.filter( + b => !b.disabled && b.id !== breakpoint.id + ); + const otherDisabledBreakpoints = breakpoints.filter( + b => b.disabled && b.id !== breakpoint.id + ); + + const deleteSelfItem = { + id: "node-menu-delete-self", + label: deleteSelfLabel, + accesskey: deleteSelfKey, + disabled: false, + click: () => { + removeBreakpoint(cx, breakpoint); + }, + }; + + const deleteAllItem = { + id: "node-menu-delete-all", + label: deleteAllLabel, + accesskey: deleteAllKey, + disabled: false, + click: () => removeAllBreakpoints(cx), + }; + + const deleteOthersItem = { + id: "node-menu-delete-other", + label: deleteOthersLabel, + accesskey: deleteOthersKey, + disabled: false, + click: () => removeBreakpoints(cx, otherBreakpoints), + }; + + const enableSelfItem = { + id: "node-menu-enable-self", + label: enableSelfLabel, + accesskey: enableSelfKey, + disabled: false, + click: () => { + toggleDisabledBreakpoint(cx, breakpoint); + }, + }; + + const enableAllItem = { + id: "node-menu-enable-all", + label: enableAllLabel, + accesskey: enableAllKey, + disabled: false, + click: () => toggleAllBreakpoints(cx, false), + }; + + const enableOthersItem = { + id: "node-menu-enable-others", + label: enableOthersLabel, + accesskey: enableOthersKey, + disabled: false, + click: () => toggleBreakpoints(cx, false, otherDisabledBreakpoints), + }; + + const disableSelfItem = { + id: "node-menu-disable-self", + label: disableSelfLabel, + accesskey: disableSelfKey, + disabled: false, + click: () => { + toggleDisabledBreakpoint(cx, breakpoint); + }, + }; + + const disableAllItem = { + id: "node-menu-disable-all", + label: disableAllLabel, + accesskey: disableAllKey, + disabled: false, + click: () => toggleAllBreakpoints(cx, true), + }; + + const disableOthersItem = { + id: "node-menu-disable-others", + label: disableOthersLabel, + accesskey: disableOthersKey, + click: () => toggleBreakpoints(cx, true, otherEnabledBreakpoints), + }; + + const enableDbgStatementItem = { + id: "node-menu-enable-dbgStatement", + label: enableDbgStatementLabel, + disabled: false, + click: () => + setBreakpointOptions(cx, selectedLocation, { + ...breakpoint.options, + condition: null, + }), + }; + + const disableDbgStatementItem = { + id: "node-menu-disable-dbgStatement", + label: disableDbgStatementLabel, + disabled: false, + click: () => + setBreakpointOptions(cx, selectedLocation, { + ...breakpoint.options, + condition: "false", + }), + }; + + const removeConditionItem = { + id: "node-menu-remove-condition", + label: removeConditionLabel, + accesskey: removeConditionKey, + disabled: false, + click: () => + setBreakpointOptions(cx, selectedLocation, { + ...breakpoint.options, + condition: null, + }), + }; + + const addConditionItem = { + id: "node-menu-add-condition", + label: addConditionLabel, + accesskey: addConditionKey, + click: () => { + selectSpecificLocation(cx, selectedLocation); + openConditionalPanel(selectedLocation); + }, + accelerator: formatKeyShortcut( + L10N.getStr("toggleCondPanel.breakpoint.key") + ), + }; + + const editConditionItem = { + id: "node-menu-edit-condition", + label: editConditionLabel, + accesskey: editConditionKey, + click: () => { + selectSpecificLocation(cx, selectedLocation); + openConditionalPanel(selectedLocation); + }, + accelerator: formatKeyShortcut( + L10N.getStr("toggleCondPanel.breakpoint.key") + ), + }; + + const addLogPointItem = { + id: "node-menu-add-log-point", + label: L10N.getStr("editor.addLogPoint"), + accesskey: L10N.getStr("editor.addLogPoint.accesskey"), + disabled: false, + click: () => openConditionalPanel(selectedLocation, true), + accelerator: formatKeyShortcut(L10N.getStr("toggleCondPanel.logPoint.key")), + }; + + const editLogPointItem = { + id: "node-menu-edit-log-point", + label: L10N.getStr("editor.editLogPoint"), + accesskey: L10N.getStr("editor.editLogPoint.accesskey"), + disabled: false, + click: () => openConditionalPanel(selectedLocation, true), + accelerator: formatKeyShortcut(L10N.getStr("toggleCondPanel.logPoint.key")), + }; + + const removeLogPointItem = { + id: "node-menu-remove-log", + label: L10N.getStr("editor.removeLogPoint.label"), + accesskey: L10N.getStr("editor.removeLogPoint.accesskey"), + disabled: false, + click: () => + setBreakpointOptions(cx, selectedLocation, { + ...breakpoint.options, + logValue: null, + }), + }; + + const logPointItem = breakpoint.options.logValue + ? editLogPointItem + : addLogPointItem; + + const hideEnableSelfItem = !breakpoint.disabled; + const hideEnableAllItem = disabledBreakpoints.length === 0; + const hideEnableOthersItem = otherDisabledBreakpoints.length === 0; + const hideDisableAllItem = enabledBreakpoints.length === 0; + const hideDisableOthersItem = otherEnabledBreakpoints.length === 0; + const hideDisableSelfItem = breakpoint.disabled; + const hideEnableDbgStatementItem = + !breakpoint.originalText.startsWith("debugger") || + (breakpoint.originalText.startsWith("debugger") && + breakpoint.options.condition !== "false"); + const hideDisableDbgStatementItem = + !breakpoint.originalText.startsWith("debugger") || + (breakpoint.originalText.startsWith("debugger") && + breakpoint.options.condition === "false"); + const items = [ + { item: enableSelfItem, hidden: () => hideEnableSelfItem }, + { item: enableAllItem, hidden: () => hideEnableAllItem }, + { item: enableOthersItem, hidden: () => hideEnableOthersItem }, + { + item: { type: "separator" }, + hidden: () => + hideEnableSelfItem && hideEnableAllItem && hideEnableOthersItem, + }, + { item: deleteSelfItem }, + { item: deleteAllItem }, + { item: deleteOthersItem, hidden: () => breakpoints.length === 1 }, + { + item: { type: "separator" }, + hidden: () => + hideDisableSelfItem && hideDisableAllItem && hideDisableOthersItem, + }, + + { item: disableSelfItem, hidden: () => hideDisableSelfItem }, + { item: disableAllItem, hidden: () => hideDisableAllItem }, + { item: disableOthersItem, hidden: () => hideDisableOthersItem }, + { + item: { type: "separator" }, + }, + { + item: enableDbgStatementItem, + hidden: () => hideEnableDbgStatementItem, + }, + { + item: disableDbgStatementItem, + hidden: () => hideDisableDbgStatementItem, + }, + { + item: { type: "separator" }, + hidden: () => hideDisableDbgStatementItem && hideEnableDbgStatementItem, + }, + { + item: addConditionItem, + hidden: () => breakpoint.options.condition, + }, + { + item: editConditionItem, + hidden: () => !breakpoint.options.condition, + }, + { + item: removeConditionItem, + hidden: () => !breakpoint.options.condition, + }, + { + item: logPointItem, + hidden: () => !features.logPoints, + }, + { + item: removeLogPointItem, + hidden: () => !features.logPoints || !breakpoint.options.logValue, + }, + ]; + + showMenu(contextMenuEvent, buildMenu(items)); + return null; +} diff --git a/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/ExceptionOption.js b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/ExceptionOption.js new file mode 100644 index 0000000000..4a078784c5 --- /dev/null +++ b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/ExceptionOption.js @@ -0,0 +1,32 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ + +// @flow + +import React from "react"; + +type ExceptionOptionProps = { + className: string, + isChecked: boolean, + label: string, + onChange: Function, +}; + +export default function ExceptionOption({ + className, + isChecked = false, + label, + onChange, +}: ExceptionOptionProps) { + return ( + <div className={className} onClick={onChange}> + <input + type="checkbox" + checked={isChecked ? "checked" : ""} + onChange={e => e.stopPropagation() && onChange()} + /> + <div className="breakpoint-exceptions-label">{label}</div> + </div> + ); +} diff --git a/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/index.js b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/index.js new file mode 100644 index 0000000000..06f4a7c48a --- /dev/null +++ b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/index.js @@ -0,0 +1,162 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ + +// @flow + +import React, { Component } from "react"; +import classnames from "classnames"; +import { connect } from "../../../utils/connect"; + +import ExceptionOption from "./ExceptionOption"; + +import Breakpoint from "./Breakpoint"; +import BreakpointHeading from "./BreakpointHeading"; + +import actions from "../../../actions"; +import { getSelectedLocation } from "../../../utils/selected-location"; +import { createHeadlessEditor } from "../../../utils/editor/create-editor"; + +import { + makeBreakpointId, + sortSelectedBreakpoints, +} from "../../../utils/breakpoint"; + +import { getSelectedSource, getBreakpointSources } from "../../../selectors"; + +import type { Source } from "../../../types"; +import type { BreakpointSources } from "../../../selectors/breakpointSources"; +import type SourceEditor from "../../../utils/editor/source-editor"; + +import "./Breakpoints.css"; + +type OwnProps = {| + shouldPauseOnExceptions: boolean, + shouldPauseOnCaughtExceptions: boolean, + pauseOnExceptions: Function, +|}; +type Props = { + breakpointSources: BreakpointSources, + selectedSource: ?Source, + shouldPauseOnExceptions: boolean, + shouldPauseOnCaughtExceptions: boolean, + pauseOnExceptions: Function, +}; + +class Breakpoints extends Component<Props> { + headlessEditor: ?SourceEditor; + + componentWillUnmount() { + this.removeEditor(); + } + + getEditor(): SourceEditor { + if (!this.headlessEditor) { + this.headlessEditor = createHeadlessEditor(); + } + return this.headlessEditor; + } + + removeEditor() { + if (!this.headlessEditor) { + return; + } + this.headlessEditor.destroy(); + this.headlessEditor = (null: any); + } + + renderExceptionsOptions() { + const { + breakpointSources, + shouldPauseOnExceptions, + shouldPauseOnCaughtExceptions, + pauseOnExceptions, + } = this.props; + + const isEmpty = breakpointSources.length == 0; + + return ( + <div + className={classnames("breakpoints-exceptions-options", { + empty: isEmpty, + })} + > + <ExceptionOption + className="breakpoints-exceptions" + label={L10N.getStr("pauseOnExceptionsItem2")} + isChecked={shouldPauseOnExceptions} + onChange={() => pauseOnExceptions(!shouldPauseOnExceptions, false)} + /> + + {shouldPauseOnExceptions && ( + <ExceptionOption + className="breakpoints-exceptions-caught" + label={L10N.getStr("pauseOnCaughtExceptionsItem")} + isChecked={shouldPauseOnCaughtExceptions} + onChange={() => + pauseOnExceptions(true, !shouldPauseOnCaughtExceptions) + } + /> + )} + </div> + ); + } + + renderBreakpoints() { + const { breakpointSources, selectedSource } = this.props; + if (!breakpointSources.length) { + return null; + } + + const editor = this.getEditor(); + const sources = [...breakpointSources.map(({ source }) => source)]; + + return ( + <div className="pane breakpoints-list"> + {breakpointSources.map(({ source, breakpoints }) => { + const sortedBreakpoints = sortSelectedBreakpoints( + breakpoints, + selectedSource + ); + + return [ + <BreakpointHeading + key={source.id} + source={source} + sources={sources} + />, + ...sortedBreakpoints.map(breakpoint => ( + <Breakpoint + breakpoint={breakpoint} + source={source} + selectedSource={selectedSource} + editor={editor} + key={makeBreakpointId( + getSelectedLocation(breakpoint, selectedSource) + )} + /> + )), + ]; + })} + </div> + ); + } + + render() { + return ( + <div className="pane"> + {this.renderExceptionsOptions()} + {this.renderBreakpoints()} + </div> + ); + } +} + +const mapStateToProps = state => ({ + breakpointSources: getBreakpointSources(state), + selectedSource: getSelectedSource(state), +}); + +export default connect<Props, OwnProps, _, _, _, _>(mapStateToProps, { + pauseOnExceptions: actions.pauseOnExceptions, +})(Breakpoints); diff --git a/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/moz.build b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/moz.build new file mode 100644 index 0000000000..2b075efdd4 --- /dev/null +++ b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/moz.build @@ -0,0 +1,15 @@ +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +DIRS += [] + +CompiledModules( + "Breakpoint.js", + "BreakpointHeading.js", + "BreakpointHeadingsContextMenu.js", + "BreakpointsContextMenu.js", + "ExceptionOption.js", + "index.js", +) diff --git a/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/tests/Breakpoint.spec.js b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/tests/Breakpoint.spec.js new file mode 100644 index 0000000000..986d2b972d --- /dev/null +++ b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/tests/Breakpoint.spec.js @@ -0,0 +1,99 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ + +// @flow + +import React from "react"; +import { shallow } from "enzyme"; + +import Breakpoint from "../Breakpoint"; +import { + createSourceObject, + createOriginalSourceObject, +} from "../../../../utils/test-head"; + +describe("Breakpoint", () => { + it("simple", () => { + const { component } = render(); + expect(component).toMatchSnapshot(); + }); + + it("disabled", () => { + const { component } = render({}, makeBreakpoint({ disabled: true })); + expect(component).toMatchSnapshot(); + }); + + it("paused at a generatedLocation", () => { + const { component } = render({ + frame: { selectedLocation: generatedLocation }, + }); + expect(component).toMatchSnapshot(); + }); + + it("paused at an original location", () => { + const source = createSourceObject("foo"); + const origSource = createOriginalSourceObject(source); + + const { component } = render( + { + selectedSource: origSource, + frame: { selectedLocation: location }, + }, + { location, options: {} } + ); + + expect(component).toMatchSnapshot(); + }); + + it("paused at a different", () => { + const { component } = render({ + frame: { selectedLocation: { ...generatedLocation, line: 14 } }, + }); + expect(component).toMatchSnapshot(); + }); +}); + +const generatedLocation = { sourceId: "foo", line: 53, column: 73 }; +const location = { sourceId: "foo/original", line: 5, column: 7 }; + +function render(overrides = {}, breakpointOverrides = {}) { + const props = generateDefaults(overrides, breakpointOverrides); + // $FlowIgnore + const component = shallow(<Breakpoint.WrappedComponent {...props} />); + const defaultState = component.state(); + const instance = component.instance(); + + return { component, props, defaultState, instance }; +} + +function makeBreakpoint(overrides = {}) { + return { + location, + generatedLocation, + disabled: false, + options: {}, + ...overrides, + id: 1, + }; +} + +function generateDefaults(overrides = {}, breakpointOverrides = {}) { + const source = createSourceObject("foo"); + const breakpoint = makeBreakpoint(breakpointOverrides); + const selectedSource = createSourceObject("foo"); + return { + source, + breakpoint, + selectedSource, + frame: (null: any), + editor: { + CodeMirror: { + runMode: function() { + return ""; + }, + }, + }, + ...overrides, + }; +} diff --git a/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/tests/BreakpointsContextMenu.spec.js b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/tests/BreakpointsContextMenu.spec.js new file mode 100644 index 0000000000..4797a3a69a --- /dev/null +++ b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/tests/BreakpointsContextMenu.spec.js @@ -0,0 +1,135 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ + +// @flow + +import React from "react"; +import { shallow } from "enzyme"; + +import BreakpointsContextMenu from "../BreakpointsContextMenu"; +import { buildMenu } from "../../../../context-menu/menu"; + +import { + makeMockBreakpoint, + makeMockSource, + mockcx, +} from "../../../../utils/test-mockup"; + +jest.mock("../../../../context-menu/menu"); + +function render(disabled = false) { + const props = generateDefaults(disabled); + const component = shallow(<BreakpointsContextMenu {...props} />); + return { component, props }; +} + +function generateDefaults(disabled) { + const source = makeMockSource( + "https://example.com/main.js", + "source-https://example.com/main.js" + ); + const breakpoints = [ + { + ...makeMockBreakpoint(source, 1), + id: "https://example.com/main.js:1:", + disabled, + options: { + condition: "", + logValue: "", + hidden: false, + }, + }, + { + ...makeMockBreakpoint(source, 2), + id: "https://example.com/main.js:2:", + disabled, + options: { + hidden: false, + }, + }, + { + ...makeMockBreakpoint(source, 3), + id: "https://example.com/main.js:3:", + disabled, + }, + ]; + + const props = { + cx: mockcx, + breakpoints, + breakpoint: breakpoints[0], + removeBreakpoint: jest.fn(), + removeBreakpoints: jest.fn(), + removeAllBreakpoints: jest.fn(), + toggleBreakpoints: jest.fn(), + toggleAllBreakpoints: jest.fn(), + toggleDisabledBreakpoint: jest.fn(), + selectSpecificLocation: jest.fn(), + setBreakpointCondition: jest.fn(), + openConditionalPanel: jest.fn(), + contextMenuEvent: ({ preventDefault: jest.fn() }: any), + selectedSource: makeMockSource(), + setBreakpointOptions: jest.fn(), + }; + return props; +} + +describe("BreakpointsContextMenu", () => { + afterEach(() => { + buildMenu.mockReset(); + }); + + describe("context menu actions affecting other breakpoints", () => { + it("'remove others' calls removeBreakpoints with proper arguments", () => { + const { props } = render(); + const menuItems = buildMenu.mock.calls[0][0]; + const deleteOthers = menuItems.find( + item => item.item.id === "node-menu-delete-other" + ); + deleteOthers.item.click(); + + expect(props.removeBreakpoints).toHaveBeenCalled(); + + const otherBreakpoints = [props.breakpoints[1], props.breakpoints[2]]; + expect(props.removeBreakpoints.mock.calls[0][1]).toEqual( + otherBreakpoints + ); + }); + + it("'enable others' calls toggleBreakpoints with proper arguments", () => { + const { props } = render(true); + const menuItems = buildMenu.mock.calls[0][0]; + const enableOthers = menuItems.find( + item => item.item.id === "node-menu-enable-others" + ); + enableOthers.item.click(); + + expect(props.toggleBreakpoints).toHaveBeenCalled(); + + expect(props.toggleBreakpoints.mock.calls[0][1]).toBe(false); + + const otherBreakpoints = [props.breakpoints[1], props.breakpoints[2]]; + expect(props.toggleBreakpoints.mock.calls[0][2]).toEqual( + otherBreakpoints + ); + }); + + it("'disable others' calls toggleBreakpoints with proper arguments", () => { + const { props } = render(); + const menuItems = buildMenu.mock.calls[0][0]; + const disableOthers = menuItems.find( + item => item.item.id === "node-menu-disable-others" + ); + disableOthers.item.click(); + + expect(props.toggleBreakpoints).toHaveBeenCalled(); + expect(props.toggleBreakpoints.mock.calls[0][1]).toBe(true); + + const otherBreakpoints = [props.breakpoints[1], props.breakpoints[2]]; + expect(props.toggleBreakpoints.mock.calls[0][2]).toEqual( + otherBreakpoints + ); + }); + }); +}); diff --git a/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/tests/ExceptionOption.spec.js b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/tests/ExceptionOption.spec.js new file mode 100644 index 0000000000..86be19740e --- /dev/null +++ b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/tests/ExceptionOption.spec.js @@ -0,0 +1,24 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ + +// @flow + +import React from "react"; +import { shallow } from "enzyme"; + +import ExceptionOption from "../ExceptionOption"; + +describe("ExceptionOption renders", () => { + it("with values", () => { + const component = shallow( + <ExceptionOption + label="testLabel" + isChecked={true} + onChange={() => null} + className="testClassName" + /> + ); + expect(component).toMatchSnapshot(); + }); +}); diff --git a/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/tests/__snapshots__/Breakpoint.spec.js.snap b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/tests/__snapshots__/Breakpoint.spec.js.snap new file mode 100644 index 0000000000..03aef3ad6f --- /dev/null +++ b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/tests/__snapshots__/Breakpoint.spec.js.snap @@ -0,0 +1,226 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Breakpoint disabled 1`] = ` +<div + className="breakpoint disabled" + onClick={[Function]} + onContextMenu={[Function]} + onDoubleClick={[Function]} +> + <input + aria-labelledby="1-label" + checked={false} + className="breakpoint-checkbox" + id={1} + onChange={[Function]} + onClick={[Function]} + type="checkbox" + /> + <span + className="breakpoint-label cm-s-mozilla devtools-monospace" + id="1-label" + onClick={[Function]} + > + <span + dangerouslySetInnerHTML={ + Object { + "__html": "", + } + } + /> + </span> + <div + className="breakpoint-line-close" + > + <div + className="breakpoint-line devtools-monospace" + > + 53:73 + </div> + <CloseButton + handleClick={[Function]} + tooltip="Remove breakpoint" + /> + </div> +</div> +`; + +exports[`Breakpoint paused at a different 1`] = ` +<div + className="breakpoint" + onClick={[Function]} + onContextMenu={[Function]} + onDoubleClick={[Function]} +> + <input + aria-labelledby="1-label" + checked={true} + className="breakpoint-checkbox" + id={1} + onChange={[Function]} + onClick={[Function]} + type="checkbox" + /> + <span + className="breakpoint-label cm-s-mozilla devtools-monospace" + id="1-label" + onClick={[Function]} + > + <span + dangerouslySetInnerHTML={ + Object { + "__html": "", + } + } + /> + </span> + <div + className="breakpoint-line-close" + > + <div + className="breakpoint-line devtools-monospace" + > + 53:73 + </div> + <CloseButton + handleClick={[Function]} + tooltip="Remove breakpoint" + /> + </div> +</div> +`; + +exports[`Breakpoint paused at a generatedLocation 1`] = ` +<div + className="breakpoint paused" + onClick={[Function]} + onContextMenu={[Function]} + onDoubleClick={[Function]} +> + <input + aria-labelledby="1-label" + checked={true} + className="breakpoint-checkbox" + id={1} + onChange={[Function]} + onClick={[Function]} + type="checkbox" + /> + <span + className="breakpoint-label cm-s-mozilla devtools-monospace" + id="1-label" + onClick={[Function]} + > + <span + dangerouslySetInnerHTML={ + Object { + "__html": "", + } + } + /> + </span> + <div + className="breakpoint-line-close" + > + <div + className="breakpoint-line devtools-monospace" + > + 53:73 + </div> + <CloseButton + handleClick={[Function]} + tooltip="Remove breakpoint" + /> + </div> +</div> +`; + +exports[`Breakpoint paused at an original location 1`] = ` +<div + className="breakpoint paused" + onClick={[Function]} + onContextMenu={[Function]} + onDoubleClick={[Function]} +> + <input + aria-labelledby="1-label" + checked={true} + className="breakpoint-checkbox" + id={1} + onChange={[Function]} + onClick={[Function]} + type="checkbox" + /> + <span + className="breakpoint-label cm-s-mozilla devtools-monospace" + id="1-label" + onClick={[Function]} + > + <span + dangerouslySetInnerHTML={ + Object { + "__html": "", + } + } + /> + </span> + <div + className="breakpoint-line-close" + > + <div + className="breakpoint-line devtools-monospace" + > + 5:7 + </div> + <CloseButton + handleClick={[Function]} + tooltip="Remove breakpoint" + /> + </div> +</div> +`; + +exports[`Breakpoint simple 1`] = ` +<div + className="breakpoint" + onClick={[Function]} + onContextMenu={[Function]} + onDoubleClick={[Function]} +> + <input + aria-labelledby="1-label" + checked={true} + className="breakpoint-checkbox" + id={1} + onChange={[Function]} + onClick={[Function]} + type="checkbox" + /> + <span + className="breakpoint-label cm-s-mozilla devtools-monospace" + id="1-label" + onClick={[Function]} + > + <span + dangerouslySetInnerHTML={ + Object { + "__html": "", + } + } + /> + </span> + <div + className="breakpoint-line-close" + > + <div + className="breakpoint-line devtools-monospace" + > + 53:73 + </div> + <CloseButton + handleClick={[Function]} + tooltip="Remove breakpoint" + /> + </div> +</div> +`; diff --git a/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/tests/__snapshots__/ExceptionOption.spec.js.snap b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/tests/__snapshots__/ExceptionOption.spec.js.snap new file mode 100644 index 0000000000..19b5937676 --- /dev/null +++ b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/tests/__snapshots__/ExceptionOption.spec.js.snap @@ -0,0 +1,19 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ExceptionOption renders with values 1`] = ` +<div + className="testClassName" + onClick={[Function]} +> + <input + checked="checked" + onChange={[Function]} + type="checkbox" + /> + <div + className="breakpoint-exceptions-label" + > + testLabel + </div> +</div> +`; |