diff options
Diffstat (limited to 'devtools/client/debugger/src/components/SecondaryPanes/Breakpoints')
8 files changed, 819 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..c55088e411 --- /dev/null +++ b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/Breakpoint.js @@ -0,0 +1,235 @@ +/* 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/>. */ + +import React, { PureComponent } from "devtools/client/shared/vendor/react"; +import { + div, + input, + span, +} from "devtools/client/shared/vendor/react-dom-factories"; +import PropTypes from "devtools/client/shared/vendor/react-prop-types"; +import { connect } from "devtools/client/shared/vendor/react-redux"; +import { createSelector } from "devtools/client/shared/vendor/reselect"; +import actions from "../../../actions/index"; + +import { CloseButton } from "../../shared/Button/index"; + +import { + getSelectedText, + makeBreakpointId, +} from "../../../utils/breakpoint/index"; +import { getSelectedLocation } from "../../../utils/selected-location"; +import { isLineBlackboxed } from "../../../utils/source"; + +import { + getSelectedFrame, + getSelectedSource, + getCurrentThread, + isSourceMapIgnoreListEnabled, + isSourceOnSourceMapIgnoreList, + getBlackBoxRanges, +} from "../../../selectors/index"; + +const classnames = require("resource://devtools/client/shared/classnames.js"); + +class Breakpoint extends PureComponent { + static get propTypes() { + return { + breakpoint: PropTypes.object.isRequired, + disableBreakpoint: PropTypes.func.isRequired, + editor: PropTypes.object.isRequired, + enableBreakpoint: PropTypes.func.isRequired, + frame: PropTypes.object, + openConditionalPanel: PropTypes.func.isRequired, + removeBreakpoint: PropTypes.func.isRequired, + selectSpecificLocation: PropTypes.func.isRequired, + selectedSource: PropTypes.object, + source: PropTypes.object.isRequired, + blackboxedRangesForSource: PropTypes.array.isRequired, + checkSourceOnIgnoreList: PropTypes.func.isRequired, + isBreakpointLineBlackboxed: PropTypes.bool, + showBreakpointContextMenu: PropTypes.func.isRequired, + }; + } + + onContextMenu = event => { + event.preventDefault(); + + this.props.showBreakpointContextMenu( + event, + this.props.breakpoint, + this.props.source + ); + }; + + get selectedLocation() { + const { breakpoint, selectedSource } = this.props; + return getSelectedLocation(breakpoint, selectedSource); + } + + stopClicks = event => event.stopPropagation(); + + onDoubleClick = () => { + const { breakpoint, openConditionalPanel } = this.props; + if (breakpoint.options.condition) { + openConditionalPanel(this.selectedLocation); + } else if (breakpoint.options.logValue) { + openConditionalPanel(this.selectedLocation, true); + } + }; + + selectBreakpoint = event => { + event.preventDefault(); + const { selectSpecificLocation } = this.props; + selectSpecificLocation(this.selectedLocation); + }; + + removeBreakpoint = event => { + const { removeBreakpoint, breakpoint } = this.props; + event.stopPropagation(); + removeBreakpoint(breakpoint); + }; + + handleBreakpointCheckbox = () => { + const { breakpoint, enableBreakpoint, disableBreakpoint } = this.props; + if (breakpoint.disabled) { + enableBreakpoint(breakpoint); + } else { + disableBreakpoint(breakpoint); + } + }; + + isCurrentlyPausedAtBreakpoint() { + const { frame } = this.props; + if (!frame) { + return false; + } + + const bpId = makeBreakpointId(this.selectedLocation); + const frameId = makeBreakpointId(frame.selectedLocation); + return bpId == frameId; + } + + getBreakpointLocation() { + const { source } = this.props; + const { column, line } = this.selectedLocation; + + const isWasm = source?.isWasm; + // column is 0-based everywhere, but we want to display 1-based to the user. + const columnVal = column ? `:${column + 1}` : ""; + 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(text = "", editor) { + const node = document.createElement("div"); + editor.CodeMirror.runMode(text, "application/javascript", node); + return { __html: node.innerHTML }; + } + + render() { + const { breakpoint, editor, isBreakpointLineBlackboxed } = 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, + disabled: isBreakpointLineBlackboxed, + onChange: this.handleBreakpointCheckbox, + onClick: this.stopClicks, + "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), + }) + ), + div( + { + className: "breakpoint-line-close", + }, + div( + { + className: "breakpoint-line devtools-monospace", + }, + this.getBreakpointLocation() + ), + React.createElement(CloseButton, { + handleClick: this.removeBreakpoint, + tooltip: L10N.getStr("breakpoints.removeBreakpointTooltip"), + }) + ) + ); + } +} + +const getFormattedFrame = createSelector( + getSelectedSource, + getSelectedFrame, + (selectedSource, frame) => { + if (!frame) { + return null; + } + + return { + ...frame, + selectedLocation: getSelectedLocation(frame, selectedSource), + }; + } +); + +const mapStateToProps = (state, props) => { + const blackboxedRangesForSource = getBlackBoxRanges(state)[props.source.url]; + const isSourceOnIgnoreList = + isSourceMapIgnoreListEnabled(state) && + isSourceOnSourceMapIgnoreList(state, props.source); + return { + selectedSource: getSelectedSource(state), + isBreakpointLineBlackboxed: isLineBlackboxed( + blackboxedRangesForSource, + props.breakpoint.location.line, + isSourceOnIgnoreList + ), + frame: getFormattedFrame(state, getCurrentThread(state)), + }; +}; + +export default connect(mapStateToProps, { + enableBreakpoint: actions.enableBreakpoint, + removeBreakpoint: actions.removeBreakpoint, + disableBreakpoint: actions.disableBreakpoint, + selectSpecificLocation: actions.selectSpecificLocation, + openConditionalPanel: actions.openConditionalPanel, + showBreakpointContextMenu: actions.showBreakpointContextMenu, +})(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..78cc530cff --- /dev/null +++ b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/BreakpointHeading.js @@ -0,0 +1,84 @@ +/* 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/>. */ + +import React, { PureComponent } from "devtools/client/shared/vendor/react"; +import { div, span } from "devtools/client/shared/vendor/react-dom-factories"; +import PropTypes from "devtools/client/shared/vendor/react-prop-types"; + +import { connect } from "devtools/client/shared/vendor/react-redux"; +import actions from "../../../actions/index"; + +import { + getTruncatedFileName, + getDisplayPath, + getSourceQueryString, + getFileURL, +} from "../../../utils/source"; +import { createLocation } from "../../../utils/location"; +import { getFirstSourceActorForGeneratedSource } from "../../../selectors/index"; + +import SourceIcon from "../../shared/SourceIcon"; + +class BreakpointHeading extends PureComponent { + static get propTypes() { + return { + sources: PropTypes.array.isRequired, + source: PropTypes.object.isRequired, + firstSourceActor: PropTypes.object, + selectSource: PropTypes.func.isRequired, + showBreakpointHeadingContextMenu: PropTypes.func.isRequired, + }; + } + onContextMenu = event => { + event.preventDefault(); + + this.props.showBreakpointHeadingContextMenu(event, this.props.source); + }; + + render() { + const { sources, source, selectSource } = this.props; + + const path = getDisplayPath(source, sources); + const query = getSourceQueryString(source); + return div( + { + className: "breakpoint-heading", + title: getFileURL(source, false), + onClick: () => selectSource(source), + onContextMenu: this.onContextMenu, + }, + React.createElement( + SourceIcon, + // Breakpoints are displayed per source and may relate to many source actors. + // Arbitrarily pick the first source actor to compute the matching source icon + // The source actor is used to pick one specific source text content and guess + // the related framework icon. + { + location: createLocation({ + source, + sourceActor: this.props.firstSourceActor, + }), + modifier: icon => + ["file", "javascript"].includes(icon) ? null : icon, + } + ), + div( + { + className: "filename", + }, + getTruncatedFileName(source, query), + path && span(null, `../${path}/..`) + ) + ); + } +} + +const mapStateToProps = (state, { source }) => ({ + firstSourceActor: getFirstSourceActorForGeneratedSource(state, source.id), +}); + +export default connect(mapStateToProps, { + selectSource: actions.selectSource, + showBreakpointHeadingContextMenu: actions.showBreakpointHeadingContextMenu, +})(BreakpointHeading); 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..c05dd0b53f --- /dev/null +++ b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/Breakpoints.css @@ -0,0 +1,235 @@ +/* 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-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-options > * { + display: flex; + align-items: center; + overflow: hidden; + padding-top: 2px; + padding-bottom: 2px; + padding-inline-start: 16px; + padding-inline-end: 12px; +} + +.breakpoints-exceptions-caught { + padding-bottom: 3px; + padding-top: 3px; + padding-inline-start: 36px; +} + +.breakpoints-options { + padding-top: 4px; + padding-bottom: 4px; +} + +.xhr-breakpoints-pane .breakpoints-options { + border-bottom: 1px solid var(--theme-splitter-color); +} + +.breakpoints-options:not(.empty) { + border-bottom: 1px solid var(--theme-splitter-color); +} + +.breakpoints-options 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; +} + +.breakpoints-list .breakpoint, +.breakpoints-list .breakpoint-heading, +.breakpoints-options { + border-inline-start: 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/ExceptionOption.js b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/ExceptionOption.js new file mode 100644 index 0000000000..31ff3f44a3 --- /dev/null +++ b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/ExceptionOption.js @@ -0,0 +1,40 @@ +/* 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/>. */ +import { + div, + input, + label, +} from "devtools/client/shared/vendor/react-dom-factories"; +import PropTypes from "devtools/client/shared/vendor/react-prop-types"; + +export default function ExceptionOption({ + className, + isChecked = false, + label: inputLabel, + onChange, +}) { + return label( + { + className, + }, + input({ + type: "checkbox", + checked: isChecked, + onChange: onChange, + }), + div( + { + className: "breakpoint-exceptions-label", + }, + inputLabel + ) + ); +} + +ExceptionOption.propTypes = { + className: PropTypes.string.isRequired, + isChecked: PropTypes.bool.isRequired, + label: PropTypes.string.isRequired, + onChange: PropTypes.func.isRequired, +}; 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..0f5d6f7ae3 --- /dev/null +++ b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/index.js @@ -0,0 +1,172 @@ +/* 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/>. */ + +import React, { Component } from "devtools/client/shared/vendor/react"; +import { div } from "devtools/client/shared/vendor/react-dom-factories"; +import PropTypes from "devtools/client/shared/vendor/react-prop-types"; +import { connect } from "devtools/client/shared/vendor/react-redux"; + +import ExceptionOption from "./ExceptionOption"; + +import Breakpoint from "./Breakpoint"; +import BreakpointHeading from "./BreakpointHeading"; + +import actions from "../../../actions/index"; +import { getSelectedLocation } from "../../../utils/selected-location"; +import { createHeadlessEditor } from "../../../utils/editor/create-editor"; + +import { makeBreakpointId } from "../../../utils/breakpoint/index"; + +import { + getSelectedSource, + getBreakpointSources, + getShouldPauseOnDebuggerStatement, + getShouldPauseOnExceptions, + getShouldPauseOnCaughtExceptions, +} from "../../../selectors/index"; + +const classnames = require("resource://devtools/client/shared/classnames.js"); + +class Breakpoints extends Component { + static get propTypes() { + return { + breakpointSources: PropTypes.array.isRequired, + pauseOnExceptions: PropTypes.func.isRequired, + selectedSource: PropTypes.object, + shouldPauseOnDebuggerStatement: PropTypes.bool.isRequired, + shouldPauseOnCaughtExceptions: PropTypes.bool.isRequired, + shouldPauseOnExceptions: PropTypes.bool.isRequired, + }; + } + + componentWillUnmount() { + this.removeEditor(); + } + + getEditor() { + if (!this.headlessEditor) { + this.headlessEditor = createHeadlessEditor(); + } + return this.headlessEditor; + } + + removeEditor() { + if (!this.headlessEditor) { + return; + } + this.headlessEditor.destroy(); + this.headlessEditor = null; + } + + togglePauseOnDebuggerStatement = () => { + this.props.pauseOnDebuggerStatement( + !this.props.shouldPauseOnDebuggerStatement + ); + }; + + togglePauseOnException = () => { + this.props.pauseOnExceptions(!this.props.shouldPauseOnExceptions, false); + }; + + togglePauseOnCaughtException = () => { + this.props.pauseOnExceptions( + true, + !this.props.shouldPauseOnCaughtExceptions + ); + }; + + renderExceptionsOptions() { + const { + breakpointSources, + shouldPauseOnDebuggerStatement, + shouldPauseOnExceptions, + shouldPauseOnCaughtExceptions, + } = this.props; + + const isEmpty = !breakpointSources.length; + return div( + { + className: classnames("breakpoints-options", { + empty: isEmpty, + }), + }, + React.createElement(ExceptionOption, { + className: "breakpoints-debugger-statement", + label: L10N.getStr("pauseOnDebuggerStatement"), + isChecked: shouldPauseOnDebuggerStatement, + onChange: this.togglePauseOnDebuggerStatement, + }), + React.createElement(ExceptionOption, { + className: "breakpoints-exceptions", + label: L10N.getStr("pauseOnExceptionsItem2"), + isChecked: shouldPauseOnExceptions, + onChange: this.togglePauseOnException, + }), + shouldPauseOnExceptions && + React.createElement(ExceptionOption, { + className: "breakpoints-exceptions-caught", + label: L10N.getStr("pauseOnCaughtExceptionsItem"), + isChecked: shouldPauseOnCaughtExceptions, + onChange: this.togglePauseOnCaughtException, + }) + ); + } + + 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 }) => { + return [ + React.createElement(BreakpointHeading, { + key: source.id, + source, + sources, + }), + breakpoints.map(breakpoint => + React.createElement(Breakpoint, { + breakpoint, + source, + editor, + key: makeBreakpointId( + getSelectedLocation(breakpoint, selectedSource) + ), + }) + ), + ]; + }) + ); + } + + render() { + return div( + { + className: "pane", + }, + this.renderExceptionsOptions(), + this.renderBreakpoints() + ); + } +} + +const mapStateToProps = state => ({ + breakpointSources: getBreakpointSources(state), + selectedSource: getSelectedSource(state), + shouldPauseOnDebuggerStatement: getShouldPauseOnDebuggerStatement(state), + shouldPauseOnExceptions: getShouldPauseOnExceptions(state), + shouldPauseOnCaughtExceptions: getShouldPauseOnCaughtExceptions(state), +}); + +export default connect(mapStateToProps, { + pauseOnDebuggerStatement: actions.pauseOnDebuggerStatement, + 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..85716d122c --- /dev/null +++ b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/moz.build @@ -0,0 +1,13 @@ +# 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", + "ExceptionOption.js", + "index.js", +) 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..51f0b1e948 --- /dev/null +++ b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/tests/ExceptionOption.spec.js @@ -0,0 +1,22 @@ +/* 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/>. */ + +import React from "devtools/client/shared/vendor/react"; +import { shallow } from "enzyme"; + +import ExceptionOption from "../ExceptionOption"; + +describe("ExceptionOption renders", () => { + it("with values", () => { + const component = shallow( + React.createElement(ExceptionOption, { + label: "testLabel", + isChecked: true, + onChange: () => null, + className: "testClassName", + }) + ); + expect(component).toMatchSnapshot(); + }); +}); 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..3ed80783b6 --- /dev/null +++ b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/tests/__snapshots__/ExceptionOption.spec.js.snap @@ -0,0 +1,18 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ExceptionOption renders with values 1`] = ` +<label + className="testClassName" +> + <input + checked={true} + onChange={[Function]} + type="checkbox" + /> + <div + className="breakpoint-exceptions-label" + > + testLabel + </div> +</label> +`; |