Loading browser/devtools/scratchpad/scratchpad.js +1 −1 Original line number Diff line number Diff line Loading @@ -159,7 +159,7 @@ var Scratchpad = { { this._dirty = aValue; if (!aValue && this.editor) this.editor.markClean(); this.editor.setClean(); this._updateTitle(); }, Loading browser/devtools/shadereditor/shadereditor.js +118 −7 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ Cu.import("resource:///modules/devtools/ViewHelpers.jsm"); const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require; const promise = require("sdk/core/promise"); const EventEmitter = require("devtools/shared/event-emitter"); const {Tooltip} = require("devtools/shared/widgets/Tooltip"); const Editor = require("devtools/sourceeditor/editor"); // The panel's window global is an EventEmitter firing the following events: Loading @@ -31,11 +32,14 @@ const EVENTS = { }; const STRINGS_URI = "chrome://browser/locale/devtools/shadereditor.properties" const HIGHLIGHT_COLOR = [1, 0, 0, 1]; const TYPING_MAX_DELAY = 500; const HIGHLIGHT_COLOR = [1, 0, 0, 1]; // rgba const TYPING_MAX_DELAY = 500; // ms const SHADERS_AUTOGROW_ITEMS = 4; const GUTTER_ERROR_PANEL_OFFSET_X = 7; // px const GUTTER_ERROR_PANEL_DELAY = 100; // ms const DEFAULT_EDITOR_CONFIG = { mode: Editor.modes.text, gutters: ["errors"], lineNumbers: true, showAnnotationRuler: true }; Loading Loading @@ -426,6 +430,9 @@ let ShadersEditorsView = { */ _onChanged: function(type) { setNamedTimeout("gl-typed", TYPING_MAX_DELAY, () => this._doCompile(type)); // Remove all the gutter markers and line classes from the editor. this._cleanEditor(type); }, /** Loading @@ -442,13 +449,117 @@ let ShadersEditorsView = { try { yield shaderActor.compile(editor.getText()); window.emit(EVENTS.SHADER_COMPILED, null); // TODO: remove error gutter markers, after bug 919709 lands. } catch (error) { window.emit(EVENTS.SHADER_COMPILED, error); // TODO: add error gutter markers, after bug 919709 lands. this._onSuccessfulCompilation(); } catch (e) { this._onFailedCompilation(type, editor, e); } }.bind(this)); }, /** * Called uppon a successful shader compilation. */ _onSuccessfulCompilation: function() { // Signal that the shader was compiled successfully. window.emit(EVENTS.SHADER_COMPILED, null); }, /** * Called uppon an unsuccessful shader compilation. */ _onFailedCompilation: function(type, editor, errors) { let lineCount = editor.lineCount(); let currentLine = editor.getCursor().line; let listeners = { mouseenter: this._onMarkerMouseEnter }; function matchLinesAndMessages(string) { return { // First number that is not equal to 0. lineMatch: string.match(/\d{2,}|[1-9]/), // The string after all the numbers, semicolons and spaces. textMatch: string.match(/[^\s\d:][^\r\n|]*/) }; } function discardInvalidMatches(e) { // Discard empty line and text matches. return e.lineMatch && e.textMatch; } function sanitizeValidMatches(e) { return { // Drivers might yield retarded line numbers under some obscure // circumstances. Don't throw the errors away in those cases, // just display them on the currently edited line. line: e.lineMatch[0] > lineCount ? currentLine : e.lineMatch[0] - 1, // Trim whitespace from the beginning and the end of the message, // and replace all other occurences of double spaces to a single space. text: e.textMatch[0].trim().replace(/\s{2,}/g, " ") }; } function sortByLine(first, second) { // Sort all the errors ascending by their corresponding line number. return first.line > second.line ? 1 : -1; } function groupSameLineMessages(accumulator, current) { // Group errors corresponding to the same line number to a single object. let previous = accumulator[accumulator.length - 1]; if (!previous || previous.line != current.line) { return [...accumulator, { line: current.line, messages: [current.text] }]; } else { previous.messages.push(current.text); return accumulator; } } function displayErrors({ line, messages }) { // Add gutter markers and line classes for every error in the source. editor.addMarker(line, "errors", "error"); editor.setMarkerListeners(line, "errors", "error", listeners, messages); editor.addLineClass(line, "error-line"); } (this._errors[type] = errors.link .split("ERROR") .map(matchLinesAndMessages) .filter(discardInvalidMatches) .map(sanitizeValidMatches) .sort(sortByLine) .reduce(groupSameLineMessages, [])) .forEach(displayErrors); // Signal that the shader wasn't compiled successfully. window.emit(EVENTS.SHADER_COMPILED, errors); }, /** * Event listener for the 'mouseenter' event on a marker in the editor gutter. */ _onMarkerMouseEnter: function(line, node, messages) { if (node._markerErrorsTooltip) { return; } let tooltip = node._markerErrorsTooltip = new Tooltip(document); tooltip.defaultOffsetX = GUTTER_ERROR_PANEL_OFFSET_X; tooltip.setTextContent.apply(tooltip, messages); tooltip.startTogglingOnHover(node, () => true, GUTTER_ERROR_PANEL_DELAY); }, /** * Removes all the gutter markers and line classes from the editor. */ _cleanEditor: function(type) { this._getEditor(type).then(editor => { editor.removeAllMarkers("errors"); this._errors[type].forEach(e => editor.removeLineClass(e.line)); this._errors[type].length = 0; }); }, _errors: { vs: [], fs: [] } }; Loading browser/devtools/shadereditor/test/browser.ini +2 −0 Original line number Diff line number Diff line Loading @@ -9,6 +9,8 @@ support-files = [browser_se_aaa_run_first_leaktest.js] [browser_se_bfcache.js] [browser_se_editors-contents.js] [browser_se_editors-error-gutter.js] [browser_se_editors-error-tooltip.js] [browser_se_editors-lazy-init.js] [browser_se_first-run.js] [browser_se_navigation.js] Loading browser/devtools/shadereditor/test/browser_se_editors-error-gutter.js 0 → 100644 +156 −0 Original line number Diff line number Diff line /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ /** * Tests if error indicators are shown in the editor's gutter and text area * when there's a shader compilation error. */ function ifWebGLSupported() { let [target, debuggee, panel] = yield initShaderEditor(SIMPLE_CANVAS_URL); let { gFront, EVENTS, ShadersEditorsView } = panel.panelWin; reload(target); yield once(gFront, "program-linked"); let vsEditor = yield ShadersEditorsView._getEditor("vs"); let fsEditor = yield ShadersEditorsView._getEditor("fs"); vsEditor.replaceText("vec3", { line: 7, ch: 22 }, { line: 7, ch: 26 }); let vertError = yield once(panel.panelWin, EVENTS.SHADER_COMPILED); checkHasVertFirstError(true, vertError); checkHasVertSecondError(false, vertError); info("Error marks added in the vertex shader editor."); vsEditor.insertText(" ", { line: 1, ch: 0 }); is(vsEditor.getText(1), " precision lowp float;", "Typed space."); checkHasVertFirstError(false, vertError); checkHasVertSecondError(false, vertError); info("Error marks removed while typing in the vertex shader editor."); let vertError = yield once(panel.panelWin, EVENTS.SHADER_COMPILED); checkHasVertFirstError(true, vertError); checkHasVertSecondError(false, vertError); info("Error marks were re-added after recompiling the vertex shader."); fsEditor.replaceText("vec4", { line: 2, ch: 14 }, { line: 2, ch: 18 }); let fragError = yield once(panel.panelWin, EVENTS.SHADER_COMPILED); checkHasVertFirstError(true, vertError); checkHasVertSecondError(false, vertError); checkHasFragError(true, fragError); info("Error marks added in the fragment shader editor."); fsEditor.insertText(" ", { line: 1, ch: 0 }); is(fsEditor.getText(1), " precision lowp float;", "Typed space."); checkHasVertFirstError(true, vertError); checkHasVertSecondError(false, vertError); checkHasFragError(false, fragError); info("Error marks removed while typing in the fragment shader editor."); let fragError = yield once(panel.panelWin, EVENTS.SHADER_COMPILED); checkHasVertFirstError(true, vertError); checkHasVertSecondError(false, vertError); checkHasFragError(true, fragError); info("Error marks were re-added after recompiling the fragment shader."); vsEditor.replaceText("2", { line: 3, ch: 19 }, { line: 3, ch: 20 }); checkHasVertFirstError(false, vertError); checkHasVertSecondError(false, vertError); checkHasFragError(true, fragError); info("Error marks removed while typing in the vertex shader editor again."); let vertError = yield once(panel.panelWin, EVENTS.SHADER_COMPILED); checkHasVertFirstError(true, vertError); checkHasVertSecondError(true, vertError); checkHasFragError(true, fragError); info("Error marks were re-added after recompiling the fragment shader again."); yield teardown(panel); finish(); function checkHasVertFirstError(bool, error) { ok(error, "Vertex shader compiled with errors."); isnot(error.link, "", "The linkage status should not be empty."); let line = 7; info("Checking first vertex shader error on line " + line + "..."); is(vsEditor.hasMarker(line, "errors", "error"), bool, "Error is " + (bool ? "" : "not ") + "shown in the editor's gutter."); is(vsEditor.hasLineClass(line, "error-line"), bool, "Error style is " + (bool ? "" : "not ") + "applied to the faulty line."); let parsed = ShadersEditorsView._errors.vs; is(parsed.length >= 1, bool, "There's " + (bool ? ">= 1" : "< 1") + " parsed vertex shader error(s)."); if (bool) { is(parsed[0].line, line, "The correct line was parsed."); is(parsed[0].messages.length, 2, "There are 2 parsed messages."); ok(parsed[0].messages[0].contains("'constructor' : too many arguments"), "The correct first message was parsed."); ok(parsed[0].messages[1].contains("'assign' : cannot convert from"), "The correct second message was parsed."); } } function checkHasVertSecondError(bool, error) { ok(error, "Vertex shader compiled with errors."); isnot(error.link, "", "The linkage status should not be empty."); let line = 8; info("Checking second vertex shader error on line " + line + "..."); is(vsEditor.hasMarker(line, "errors", "error"), bool, "Error is " + (bool ? "" : "not ") + "shown in the editor's gutter."); is(vsEditor.hasLineClass(line, "error-line"), bool, "Error style is " + (bool ? "" : "not ") + "applied to the faulty line."); let parsed = ShadersEditorsView._errors.vs; is(parsed.length >= 2, bool, "There's " + (bool ? ">= 2" : "< 2") + " parsed vertex shader error(s)."); if (bool) { is(parsed[1].line, line, "The correct line was parsed."); is(parsed[1].messages.length, 1, "There is 1 parsed message."); ok(parsed[1].messages[0].contains("'assign' : cannot convert from"), "The correct message was parsed."); } } function checkHasFragError(bool, error) { ok(error, "Fragment shader compiled with errors."); isnot(error.link, "", "The linkage status should not be empty."); let line = 5; info("Checking first vertex shader error on line " + line + "..."); is(fsEditor.hasMarker(line, "errors", "error"), bool, "Error is " + (bool ? "" : "not ") + "shown in the editor's gutter."); is(fsEditor.hasLineClass(line, "error-line"), bool, "Error style is " + (bool ? "" : "not ") + "applied to the faulty line."); let parsed = ShadersEditorsView._errors.fs; is(parsed.length >= 1, bool, "There's " + (bool ? ">= 2" : "< 1") + " parsed fragment shader error(s)."); if (bool) { is(parsed[0].line, line, "The correct line was parsed."); is(parsed[0].messages.length, 1, "There is 1 parsed message."); ok(parsed[0].messages[0].contains("'constructor' : too many arguments"), "The correct message was parsed."); } } } function once(aTarget, aEvent) { let deferred = promise.defer(); aTarget.once(aEvent, (aName, aData) => deferred.resolve(aData)); return deferred.promise; } browser/devtools/shadereditor/test/browser_se_editors-error-tooltip.js 0 → 100644 +59 −0 Original line number Diff line number Diff line /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ /** * Tests if error tooltips can be opened from the editor's gutter when there's * a shader compilation error. */ function ifWebGLSupported() { let [target, debuggee, panel] = yield initShaderEditor(SIMPLE_CANVAS_URL); let { gFront, EVENTS, ShadersEditorsView } = panel.panelWin; reload(target); yield once(gFront, "program-linked"); let vsEditor = yield ShadersEditorsView._getEditor("vs"); let fsEditor = yield ShadersEditorsView._getEditor("fs"); vsEditor.replaceText("vec3", { line: 7, ch: 22 }, { line: 7, ch: 26 }); yield once(panel.panelWin, EVENTS.SHADER_COMPILED); // Synthesizing 'mouseenter' events doesn't work, hack around this by // manually calling the event listener with the expected arguments. let editorDocument = vsEditor.container.contentDocument; let marker = editorDocument.querySelector(".error"); let parsed = ShadersEditorsView._errors.vs[0].messages; ShadersEditorsView._onMarkerMouseEnter(7, marker, parsed); let tooltip = marker._markerErrorsTooltip; ok(tooltip, "A tooltip was created successfully."); let content = tooltip.content; ok(tooltip.content, "Some tooltip's content was set."); is(tooltip.content.className, "devtools-tooltip-simple-text-container", "The tooltip's content container was created correctly."); let messages = content.childNodes; is(messages.length, 2, "There are two messages displayed in the tooltip."); is(messages[0].className, "devtools-tooltip-simple-text", "The first message was created correctly."); is(messages[1].className, "devtools-tooltip-simple-text", "The second message was created correctly."); ok(messages[0].textContent.contains("'constructor' : too many arguments"), "The first message contains the correct text."); ok(messages[1].textContent.contains("'assign' : cannot convert"), "The second message contains the correct text."); yield teardown(panel); finish(); } function once(aTarget, aEvent) { let deferred = promise.defer(); aTarget.once(aEvent, (aName, aData) => deferred.resolve(aData)); return deferred.promise; } Loading
browser/devtools/scratchpad/scratchpad.js +1 −1 Original line number Diff line number Diff line Loading @@ -159,7 +159,7 @@ var Scratchpad = { { this._dirty = aValue; if (!aValue && this.editor) this.editor.markClean(); this.editor.setClean(); this._updateTitle(); }, Loading
browser/devtools/shadereditor/shadereditor.js +118 −7 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ Cu.import("resource:///modules/devtools/ViewHelpers.jsm"); const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require; const promise = require("sdk/core/promise"); const EventEmitter = require("devtools/shared/event-emitter"); const {Tooltip} = require("devtools/shared/widgets/Tooltip"); const Editor = require("devtools/sourceeditor/editor"); // The panel's window global is an EventEmitter firing the following events: Loading @@ -31,11 +32,14 @@ const EVENTS = { }; const STRINGS_URI = "chrome://browser/locale/devtools/shadereditor.properties" const HIGHLIGHT_COLOR = [1, 0, 0, 1]; const TYPING_MAX_DELAY = 500; const HIGHLIGHT_COLOR = [1, 0, 0, 1]; // rgba const TYPING_MAX_DELAY = 500; // ms const SHADERS_AUTOGROW_ITEMS = 4; const GUTTER_ERROR_PANEL_OFFSET_X = 7; // px const GUTTER_ERROR_PANEL_DELAY = 100; // ms const DEFAULT_EDITOR_CONFIG = { mode: Editor.modes.text, gutters: ["errors"], lineNumbers: true, showAnnotationRuler: true }; Loading Loading @@ -426,6 +430,9 @@ let ShadersEditorsView = { */ _onChanged: function(type) { setNamedTimeout("gl-typed", TYPING_MAX_DELAY, () => this._doCompile(type)); // Remove all the gutter markers and line classes from the editor. this._cleanEditor(type); }, /** Loading @@ -442,13 +449,117 @@ let ShadersEditorsView = { try { yield shaderActor.compile(editor.getText()); window.emit(EVENTS.SHADER_COMPILED, null); // TODO: remove error gutter markers, after bug 919709 lands. } catch (error) { window.emit(EVENTS.SHADER_COMPILED, error); // TODO: add error gutter markers, after bug 919709 lands. this._onSuccessfulCompilation(); } catch (e) { this._onFailedCompilation(type, editor, e); } }.bind(this)); }, /** * Called uppon a successful shader compilation. */ _onSuccessfulCompilation: function() { // Signal that the shader was compiled successfully. window.emit(EVENTS.SHADER_COMPILED, null); }, /** * Called uppon an unsuccessful shader compilation. */ _onFailedCompilation: function(type, editor, errors) { let lineCount = editor.lineCount(); let currentLine = editor.getCursor().line; let listeners = { mouseenter: this._onMarkerMouseEnter }; function matchLinesAndMessages(string) { return { // First number that is not equal to 0. lineMatch: string.match(/\d{2,}|[1-9]/), // The string after all the numbers, semicolons and spaces. textMatch: string.match(/[^\s\d:][^\r\n|]*/) }; } function discardInvalidMatches(e) { // Discard empty line and text matches. return e.lineMatch && e.textMatch; } function sanitizeValidMatches(e) { return { // Drivers might yield retarded line numbers under some obscure // circumstances. Don't throw the errors away in those cases, // just display them on the currently edited line. line: e.lineMatch[0] > lineCount ? currentLine : e.lineMatch[0] - 1, // Trim whitespace from the beginning and the end of the message, // and replace all other occurences of double spaces to a single space. text: e.textMatch[0].trim().replace(/\s{2,}/g, " ") }; } function sortByLine(first, second) { // Sort all the errors ascending by their corresponding line number. return first.line > second.line ? 1 : -1; } function groupSameLineMessages(accumulator, current) { // Group errors corresponding to the same line number to a single object. let previous = accumulator[accumulator.length - 1]; if (!previous || previous.line != current.line) { return [...accumulator, { line: current.line, messages: [current.text] }]; } else { previous.messages.push(current.text); return accumulator; } } function displayErrors({ line, messages }) { // Add gutter markers and line classes for every error in the source. editor.addMarker(line, "errors", "error"); editor.setMarkerListeners(line, "errors", "error", listeners, messages); editor.addLineClass(line, "error-line"); } (this._errors[type] = errors.link .split("ERROR") .map(matchLinesAndMessages) .filter(discardInvalidMatches) .map(sanitizeValidMatches) .sort(sortByLine) .reduce(groupSameLineMessages, [])) .forEach(displayErrors); // Signal that the shader wasn't compiled successfully. window.emit(EVENTS.SHADER_COMPILED, errors); }, /** * Event listener for the 'mouseenter' event on a marker in the editor gutter. */ _onMarkerMouseEnter: function(line, node, messages) { if (node._markerErrorsTooltip) { return; } let tooltip = node._markerErrorsTooltip = new Tooltip(document); tooltip.defaultOffsetX = GUTTER_ERROR_PANEL_OFFSET_X; tooltip.setTextContent.apply(tooltip, messages); tooltip.startTogglingOnHover(node, () => true, GUTTER_ERROR_PANEL_DELAY); }, /** * Removes all the gutter markers and line classes from the editor. */ _cleanEditor: function(type) { this._getEditor(type).then(editor => { editor.removeAllMarkers("errors"); this._errors[type].forEach(e => editor.removeLineClass(e.line)); this._errors[type].length = 0; }); }, _errors: { vs: [], fs: [] } }; Loading
browser/devtools/shadereditor/test/browser.ini +2 −0 Original line number Diff line number Diff line Loading @@ -9,6 +9,8 @@ support-files = [browser_se_aaa_run_first_leaktest.js] [browser_se_bfcache.js] [browser_se_editors-contents.js] [browser_se_editors-error-gutter.js] [browser_se_editors-error-tooltip.js] [browser_se_editors-lazy-init.js] [browser_se_first-run.js] [browser_se_navigation.js] Loading
browser/devtools/shadereditor/test/browser_se_editors-error-gutter.js 0 → 100644 +156 −0 Original line number Diff line number Diff line /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ /** * Tests if error indicators are shown in the editor's gutter and text area * when there's a shader compilation error. */ function ifWebGLSupported() { let [target, debuggee, panel] = yield initShaderEditor(SIMPLE_CANVAS_URL); let { gFront, EVENTS, ShadersEditorsView } = panel.panelWin; reload(target); yield once(gFront, "program-linked"); let vsEditor = yield ShadersEditorsView._getEditor("vs"); let fsEditor = yield ShadersEditorsView._getEditor("fs"); vsEditor.replaceText("vec3", { line: 7, ch: 22 }, { line: 7, ch: 26 }); let vertError = yield once(panel.panelWin, EVENTS.SHADER_COMPILED); checkHasVertFirstError(true, vertError); checkHasVertSecondError(false, vertError); info("Error marks added in the vertex shader editor."); vsEditor.insertText(" ", { line: 1, ch: 0 }); is(vsEditor.getText(1), " precision lowp float;", "Typed space."); checkHasVertFirstError(false, vertError); checkHasVertSecondError(false, vertError); info("Error marks removed while typing in the vertex shader editor."); let vertError = yield once(panel.panelWin, EVENTS.SHADER_COMPILED); checkHasVertFirstError(true, vertError); checkHasVertSecondError(false, vertError); info("Error marks were re-added after recompiling the vertex shader."); fsEditor.replaceText("vec4", { line: 2, ch: 14 }, { line: 2, ch: 18 }); let fragError = yield once(panel.panelWin, EVENTS.SHADER_COMPILED); checkHasVertFirstError(true, vertError); checkHasVertSecondError(false, vertError); checkHasFragError(true, fragError); info("Error marks added in the fragment shader editor."); fsEditor.insertText(" ", { line: 1, ch: 0 }); is(fsEditor.getText(1), " precision lowp float;", "Typed space."); checkHasVertFirstError(true, vertError); checkHasVertSecondError(false, vertError); checkHasFragError(false, fragError); info("Error marks removed while typing in the fragment shader editor."); let fragError = yield once(panel.panelWin, EVENTS.SHADER_COMPILED); checkHasVertFirstError(true, vertError); checkHasVertSecondError(false, vertError); checkHasFragError(true, fragError); info("Error marks were re-added after recompiling the fragment shader."); vsEditor.replaceText("2", { line: 3, ch: 19 }, { line: 3, ch: 20 }); checkHasVertFirstError(false, vertError); checkHasVertSecondError(false, vertError); checkHasFragError(true, fragError); info("Error marks removed while typing in the vertex shader editor again."); let vertError = yield once(panel.panelWin, EVENTS.SHADER_COMPILED); checkHasVertFirstError(true, vertError); checkHasVertSecondError(true, vertError); checkHasFragError(true, fragError); info("Error marks were re-added after recompiling the fragment shader again."); yield teardown(panel); finish(); function checkHasVertFirstError(bool, error) { ok(error, "Vertex shader compiled with errors."); isnot(error.link, "", "The linkage status should not be empty."); let line = 7; info("Checking first vertex shader error on line " + line + "..."); is(vsEditor.hasMarker(line, "errors", "error"), bool, "Error is " + (bool ? "" : "not ") + "shown in the editor's gutter."); is(vsEditor.hasLineClass(line, "error-line"), bool, "Error style is " + (bool ? "" : "not ") + "applied to the faulty line."); let parsed = ShadersEditorsView._errors.vs; is(parsed.length >= 1, bool, "There's " + (bool ? ">= 1" : "< 1") + " parsed vertex shader error(s)."); if (bool) { is(parsed[0].line, line, "The correct line was parsed."); is(parsed[0].messages.length, 2, "There are 2 parsed messages."); ok(parsed[0].messages[0].contains("'constructor' : too many arguments"), "The correct first message was parsed."); ok(parsed[0].messages[1].contains("'assign' : cannot convert from"), "The correct second message was parsed."); } } function checkHasVertSecondError(bool, error) { ok(error, "Vertex shader compiled with errors."); isnot(error.link, "", "The linkage status should not be empty."); let line = 8; info("Checking second vertex shader error on line " + line + "..."); is(vsEditor.hasMarker(line, "errors", "error"), bool, "Error is " + (bool ? "" : "not ") + "shown in the editor's gutter."); is(vsEditor.hasLineClass(line, "error-line"), bool, "Error style is " + (bool ? "" : "not ") + "applied to the faulty line."); let parsed = ShadersEditorsView._errors.vs; is(parsed.length >= 2, bool, "There's " + (bool ? ">= 2" : "< 2") + " parsed vertex shader error(s)."); if (bool) { is(parsed[1].line, line, "The correct line was parsed."); is(parsed[1].messages.length, 1, "There is 1 parsed message."); ok(parsed[1].messages[0].contains("'assign' : cannot convert from"), "The correct message was parsed."); } } function checkHasFragError(bool, error) { ok(error, "Fragment shader compiled with errors."); isnot(error.link, "", "The linkage status should not be empty."); let line = 5; info("Checking first vertex shader error on line " + line + "..."); is(fsEditor.hasMarker(line, "errors", "error"), bool, "Error is " + (bool ? "" : "not ") + "shown in the editor's gutter."); is(fsEditor.hasLineClass(line, "error-line"), bool, "Error style is " + (bool ? "" : "not ") + "applied to the faulty line."); let parsed = ShadersEditorsView._errors.fs; is(parsed.length >= 1, bool, "There's " + (bool ? ">= 2" : "< 1") + " parsed fragment shader error(s)."); if (bool) { is(parsed[0].line, line, "The correct line was parsed."); is(parsed[0].messages.length, 1, "There is 1 parsed message."); ok(parsed[0].messages[0].contains("'constructor' : too many arguments"), "The correct message was parsed."); } } } function once(aTarget, aEvent) { let deferred = promise.defer(); aTarget.once(aEvent, (aName, aData) => deferred.resolve(aData)); return deferred.promise; }
browser/devtools/shadereditor/test/browser_se_editors-error-tooltip.js 0 → 100644 +59 −0 Original line number Diff line number Diff line /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ /** * Tests if error tooltips can be opened from the editor's gutter when there's * a shader compilation error. */ function ifWebGLSupported() { let [target, debuggee, panel] = yield initShaderEditor(SIMPLE_CANVAS_URL); let { gFront, EVENTS, ShadersEditorsView } = panel.panelWin; reload(target); yield once(gFront, "program-linked"); let vsEditor = yield ShadersEditorsView._getEditor("vs"); let fsEditor = yield ShadersEditorsView._getEditor("fs"); vsEditor.replaceText("vec3", { line: 7, ch: 22 }, { line: 7, ch: 26 }); yield once(panel.panelWin, EVENTS.SHADER_COMPILED); // Synthesizing 'mouseenter' events doesn't work, hack around this by // manually calling the event listener with the expected arguments. let editorDocument = vsEditor.container.contentDocument; let marker = editorDocument.querySelector(".error"); let parsed = ShadersEditorsView._errors.vs[0].messages; ShadersEditorsView._onMarkerMouseEnter(7, marker, parsed); let tooltip = marker._markerErrorsTooltip; ok(tooltip, "A tooltip was created successfully."); let content = tooltip.content; ok(tooltip.content, "Some tooltip's content was set."); is(tooltip.content.className, "devtools-tooltip-simple-text-container", "The tooltip's content container was created correctly."); let messages = content.childNodes; is(messages.length, 2, "There are two messages displayed in the tooltip."); is(messages[0].className, "devtools-tooltip-simple-text", "The first message was created correctly."); is(messages[1].className, "devtools-tooltip-simple-text", "The second message was created correctly."); ok(messages[0].textContent.contains("'constructor' : too many arguments"), "The first message contains the correct text."); ok(messages[1].textContent.contains("'assign' : cannot convert"), "The second message contains the correct text."); yield teardown(panel); finish(); } function once(aTarget, aEvent) { let deferred = promise.defer(); aTarget.once(aEvent, (aName, aData) => deferred.resolve(aData)); return deferred.promise; }