/
githubmirror
/
brackets
Обзор
Документация
Войти
/
githubmirror
/
brackets
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/extensions/default/CodeFolding/unittests.js
537 строк
21 KB
Patrick Oladimeji
Addresses #13264 where setting `saveFoldStates` preference to false caused the code folding extension to stop working.
05 апр 2017, 11:21
05 апр 2017, 11:21
1a5e835
Код
Авторство
О чём код?
/** * Codefolding unit test files * @author Patrick Oladimeji * @date 01/08/2015 18:34 */ /*global describe, beforeEach, afterEach, it, expect, runs, waitsForDone, waitsFor*/ define(function (require, exports, module) { "use strict"; var SpecRunnerUtils = brackets.getModule("spec/SpecRunnerUtils"), FileUtils = brackets.getModule("file/FileUtils"); describe("Code Folding", function () { var testWindow, testEditor, EditorManager, DocumentManager, CommandManager, PreferencesManager, prefs, cm, gutterName = "CodeMirror-foldgutter", foldMarkerOpen = gutterName + "-open", foldMarkerClosed = gutterName + "-folded"; var extensionPath = FileUtils.getNativeModuleDirectoryPath(module), testDocumentDirectory = extensionPath + "/unittest-files/", // The line numbers referenced below are dependent on the files in /unittest-files directory. // Remember to update the numbers if the files change. testFilesSpec = { js: { filePath: testDocumentDirectory + "test.js", foldableLines: [1, 11, 17, 21, 25, 27, 30], sameLevelFoldableLines: [17, 21], firstSelection: {start: {line: 2, ch: 0}, end: {line: 10, ch: 0}}, secondSelection: {start: {line: 5, ch: 0}, end: {line: 8, ch: 4}} }, html: { filePath: testDocumentDirectory + "test.html", foldableLines: [1, 2, 3, 4, 8, 9, 14, 15, 16, 20, 21, 22, 23, 28, 29, 34, 37], sameLevelFoldableLines: [3, 8], firstSelection: {start: {line: 38, ch: 0}, end: {line: 41, ch: 0}}, secondSelection: {start: {line: 42, ch: 0}, end: {line: 45, ch: 4}} }, hbs: { filePath: testDocumentDirectory + "test.hbs", foldableLines: [1, 7, 14, 16, 17, 21, 26, 28, 29, 32, 33, 38, 41], sameLevelFoldableLines: [1, 7, 14], firstSelection: {start: {line: 2, ch: 0}, end: {line: 10, ch: 0}}, secondSelection: {start: {line: 5, ch: 0}, end: {line: 8, ch: 4}} } }, open = "open", folded = "folded"; /** * Utility to temporarily set preference values in the session scope */ function setPreference(key, value) { prefs.set(key, value, { locations: { scope: "session" } }); } /** * Open a test file * @param {String} path The path to the file to open */ function openTestFile(path) { var promise = SpecRunnerUtils.openProjectFiles([path]); promise.then(function () { testEditor = EditorManager.getCurrentFullEditor(); cm = testEditor._codeMirror; }); waitsForDone(promise, "Test file opened", 3000); } /** * Sets up the test window and loads the test project */ function setup() { runs(function () { SpecRunnerUtils.createTestWindowAndRun(this, function (w) { testWindow = w; EditorManager = w.brackets.test.EditorManager; DocumentManager = w.brackets.test.DocumentManager; PreferencesManager = w.brackets.test.PreferencesManager; CommandManager = w.brackets.test.CommandManager; prefs = PreferencesManager.getExtensionPrefs("code-folding"); }, {hasNativeMenus: true}); }); runs(function () { //setPreference("saveFoldStates", false); SpecRunnerUtils.loadProjectInTestWindow(testDocumentDirectory); }); } /** * Closes the test window */ function tearDown() { SpecRunnerUtils.closeTestWindow(); } /** * Runs the specified command * @param {String} command The command to run * @returns {Promise} A promise that resolves after command execution is completed or failed */ function runCommand(command) { return CommandManager.execute(command); } /** * Folds the code on the given line number * @param {Number} line The line number to fold */ function foldCodeOnLine(line) { cm.setCursor(line - 1); var promise = runCommand("codefolding.collapse"); waitsForDone(promise, "Collapse code", 2000); } /** * Expands the code on the given line number * @param {Number} line The line number to fold */ function expandCodeOnLine(line) { cm.setCursor(line - 1); var promise = runCommand("codefolding.expand"); waitsForDone(promise, "Expand code", 2000); } /** * Returns all the fold marks currently inside the editor * @returns {Array<TextMark>} The fold marks currently inside the editor */ function getEditorFoldMarks() { testEditor = EditorManager.getCurrentFullEditor(); cm = testEditor._codeMirror; var marks = cm.getAllMarks().filter(function (m) { return m.__isFold; }); return marks; } /** * Gets information about the mark in the gutter specifically whether it is folded or open. * @param {Object} lineInfo The CodeMirror lineInfo object * @returns {Object} an object with line and type property */ function gutterMarkState(lineInfo) { if (!lineInfo || !lineInfo.gutterMarkers) { return; } var classes = lineInfo.gutterMarkers[gutterName].classList; if (classes && classes.contains(foldMarkerClosed)) { return {line: lineInfo.line, type: folded}; } else if (classes && classes.contains(foldMarkerOpen)) { return {line: lineInfo.line, type: open}; } return; } /** * Helper function to return the fold markers on the current codeMirror instance * * @returns {Array<object>} An array of objects containing the line and the type of marker. */ function getGutterFoldMarks() { testEditor = EditorManager.getCurrentFullEditor(); cm = testEditor._codeMirror; var marks = []; cm.eachLine(function (lineHandle) { var lineInfo = cm.lineInfo(lineHandle); marks.push(gutterMarkState(lineInfo)); }); return marks.filter(function (m) { return m; }); } /** * Helper function to filter out all open gutter markers * @param {Object} m the marker to filter * @returns {boolean} true if the marker is open or false otherwise */ function filterOpen(m) { return m.type === open; } /** * Helper function to filter out all closed gutter markers. * @param {Object} m the marker to to filter * @returns {boolean} true if the marker is closed or false otherwise */ function filterFolded(m) { return m.type === folded; } /* * Helper function to return the line number on a marker * @param {Object} m the maker whose line number we want to retrieve * @returns {Number} the line number of the marker */ function getLineNumber(m) { return m.line; } /** * Helper function to change the lines to zero-based index * @param {Array<number>} lines the line numbers to change to zero base index * @returns {Array<number>} the zero-based index of the lines passed in */ function toZeroIndex(lines) { return lines.map(function (l) { return l - 1; }); } /** * Helper function to select a range of text in the editor * @param {CodeMirror.Pos} start the start position of the selection * @param {CodeMirror.Pos} end the end position of the selection */ function selectTextInEditor(start, end) { var marksVisible = false; runs(function () { cm.setSelection(start, end); setTimeout(function () { //wait for foldmarks to be rendered marksVisible = true; }, 410); }); waitsFor(function () { return marksVisible; }, "Fold markers now visible in gutter", 500); } beforeEach(function () { setup(); }); afterEach(function () { testWindow.closeAllFiles(); tearDown(); }); Object.keys(testFilesSpec).forEach(function (file) { var testFilePath = testFilesSpec[file].filePath; var foldableLines = testFilesSpec[file].foldableLines; var testFileSpec = testFilesSpec[file]; describe(file + " - Editor/Gutter", function () { beforeEach(function () { runs(function () { openTestFile(testFilePath); }); runs(function () { testEditor = EditorManager.getCurrentFullEditor(); cm = testEditor._codeMirror; }); }); afterEach(function () { testWindow.closeAllFiles(); }); it("renders fold marks on startup", function () { var marks = getGutterFoldMarks(); expect(marks.length).toBeGreaterThan(0); marks.map(getLineNumber).forEach(function (line) { expect(toZeroIndex(foldableLines)).toContain(line); }); }); it("creates a folded region in editor when fold marker is clicked", function () { var lineNumber = foldableLines[0]; runs(function () { foldCodeOnLine(lineNumber); }); runs(function () { var marks = getEditorFoldMarks(); expect(marks.length).toEqual(1); expect(marks[0].lines[0].lineNo()).toEqual(lineNumber - 1); }); }); it("clears the folded region in editor when collapsed fold marker is clicked", function () { var lineNumber = foldableLines[0]; runs(function () { foldCodeOnLine(lineNumber); }); runs(function () { expandCodeOnLine(lineNumber); }); runs(function () { var marks = getEditorFoldMarks(); expect(marks.length).toEqual(0); }); }); it("expands and updates the fold gutter when text marker for a folded region in editor is cleared", function () { var lineNumber = foldableLines[0]; runs(function () { foldCodeOnLine(lineNumber); }); runs(function () { var marks = getEditorFoldMarks().filter(function (m) { var range = m.find(); return range ? range.from.line === lineNumber - 1 : false; }); marks[0].clear(); }); runs(function () { var marks = getEditorFoldMarks(); var gutterMark = getGutterFoldMarks().filter(function (m) { return m.line === lineNumber - 1 && m.type === open; }); expect(marks.length).toEqual(0); expect(gutterMark.length).toEqual(1); }); }); it("renders folded marker in the gutter for folded code regions", function () { var lineNumbers = testFilesSpec[file].sameLevelFoldableLines; runs(function () { lineNumbers.forEach(function (l) { foldCodeOnLine(l); }); }); runs(function () { var marks = getGutterFoldMarks().filter(filterFolded); expect(marks.length).toEqual(lineNumbers.length); var gutterNumbers = marks .map(getLineNumber); expect(gutterNumbers).toEqual(toZeroIndex(lineNumbers)); }); }); it("indicates foldable lines in the gutter", function () { var lineNumbers = foldableLines; var marks = getGutterFoldMarks(); var gutterNumbers = marks.filter(filterOpen) .map(getLineNumber); expect(gutterNumbers).toEqual(toZeroIndex(lineNumbers)); }); describe("Preferences", function () { it("persists fold states", function () { var lineNumbers = testFileSpec.sameLevelFoldableLines; runs(function () { lineNumbers.forEach(function (line) { foldCodeOnLine(line); }); }); runs(function () { testWindow.closeAllFiles(); }); runs(function () { openTestFile(testFilePath); }); runs(function () { var marks = getEditorFoldMarks(); var gutterNumbers = marks.map(function (mark) { return mark.lines[0].lineNo(); }); expect(gutterNumbers).toEqual(toZeroIndex(lineNumbers)); }); }); it("can disable persistence of fold states", function () { setPreference("saveFoldStates", false); runs(function () { foldCodeOnLine(foldableLines[0]); }); runs(function () { testWindow.closeAllFiles(); }); runs(function () { openTestFile(testFilePath); }); runs(function () { var marks = getEditorFoldMarks(); expect(marks.length).toEqual(0); }); runs(function () { var lineNumbers = foldableLines; var marks = getGutterFoldMarks(); var gutterNumbers = marks.filter(filterOpen) .map(getLineNumber); expect(gutterNumbers).toEqual(toZeroIndex(lineNumbers)); }); }); it("can set the minimum fold size", function () { setPreference("minFoldSize", 20000); runs(function () { testWindow.closeAllFiles(); }); runs(function () { openTestFile(testFilePath); }); runs(function () { var marks = getGutterFoldMarks(); expect(marks.length).toEqual(0); }); }); it("can disable code folding", function () { setPreference("enabled", false); runs(function () { var marks = getEditorFoldMarks(); expect(marks.length).toEqual(0); }); }); describe("Fold selected region", function () { it("can be enabled by setting `makeSelectionsFoldable' to true", function () { var start = testFileSpec.firstSelection.start, end = testFileSpec.firstSelection.end; setPreference("makeSelectionsFoldable", true); selectTextInEditor(start, end); runs(function () { var marks = getGutterFoldMarks().filter(filterOpen).map(getLineNumber); expect(marks).toContain(start.line); }); }); it("can be disabled by setting `makeSelectionsFoldable' to false", function () { setPreference("makeSelectionsFoldable", false); var start = testFileSpec.firstSelection.start, end = testFileSpec.firstSelection.end; selectTextInEditor(start, end); runs(function () { var marks = getGutterFoldMarks().filter(filterOpen) .map(getLineNumber).filter(function (d) { return d === start.line; }); expect(marks.length).toEqual(0); }); }); it("shows fold ranges for only the most recent selection", function () { var firstSelection = testFileSpec.firstSelection, secondSelection = testFileSpec.secondSelection; selectTextInEditor(firstSelection.start, firstSelection.end); selectTextInEditor(secondSelection.start, secondSelection.end); runs(function () { var marks = getGutterFoldMarks().filter(filterOpen) .map(getLineNumber); expect(marks).toContain(secondSelection.start.line); expect(marks).not.toContain(firstSelection.start.line); }); }); }); }); describe("Editor text changes", function () { var foldableLine = foldableLines[1], expandTimeoutElapsed = false; // add a line after folding a region preserves the region and the region can be unfolded it("can unfold a folded region after a line has been added above it", function () { runs(function () { foldCodeOnLine(foldableLine); cm.replaceRange("\r\n", {line: foldableLine - 1, ch: 0}); }); runs(function () { expandCodeOnLine(foldableLine + 1); setTimeout(function () { expandTimeoutElapsed = true; }, 400); }); waitsFor(function () { return expandTimeoutElapsed; }, "waiting a moment for gutter markerts to be re-rendered", 500); runs(function () { var marks = getGutterFoldMarks().filter(filterFolded); expect(marks.length).toEqual(0); }); }); it("can unfold a folded region even after a line has been removed above it", function () { runs(function () { foldCodeOnLine(foldableLine); cm.replaceRange("", {line: foldableLine - 1, ch: 0}, {line: foldableLine, ch: 0}); }); runs(function () { expandCodeOnLine(foldableLine - 1); setTimeout(function () { expandTimeoutElapsed = true; }, 400); }); waitsFor(function () { return expandTimeoutElapsed; }, "waiting a moment for gutter markerts to be re-rendered", 500); runs(function () { var marks = getGutterFoldMarks().filter(filterFolded); expect(marks.length).toEqual(0); }); }); }); }); }); }); });