/
githubmirror
/
brackets
Обзор
Документация
Войти
/
githubmirror
/
brackets
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
test/spec/DocumentCommandHandlers-test.js
1 442 строки
64 KB
Martin Zagora
fix unit tests because of new sticky flag
22 фев 2017, 04:22
22 фев 2017, 04:22
c590f02
Код
Авторство
О чём код?
/* * Copyright (c) 2012 - present Adobe Systems Incorporated. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ /*global describe, beforeEach, afterEach, it, runs, expect, waitsForDone, waitsForFail, spyOn, beforeFirst, afterLast, jasmine, xit */ define(function (require, exports, module) { 'use strict'; // Load dependent modules var CommandManager, // loaded from brackets.test Commands, // loaded from brackets.test DocumentCommandHandlers, // loaded from brackets.test DocumentManager, // loaded from brackets.test MainViewManager, // loaded from brackets.test Dialogs, // loaded from brackets.test FileSystem, // loaded from brackets.test FileViewController, // loaded from brackets.test EditorManager, // loaded from brackets.test SpecRunnerUtils = require("spec/SpecRunnerUtils"), FileUtils = require("file/FileUtils"), FileSystemError = require("filesystem/FileSystemError"); describe("DocumentCommandHandlers", function () { this.category = "integration"; var testPath = SpecRunnerUtils.getTestPath("/spec/DocumentCommandHandlers-test-files"), testWindow, _$, promise; var TEST_JS_CONTENT = 'var myContent="This is awesome!";'; var TEST_JS_NEW_CONTENT = "hello world"; var TEST_JS_SECOND_NEW_CONTENT = "hello world 2"; var WINDOW_TITLE_DOT = brackets.platform === "mac" ? "\u2014" : "-"; beforeFirst(function () { SpecRunnerUtils.createTestWindowAndRun(this, function (w) { testWindow = w; _$ = testWindow.$; // Load module instances from brackets.test CommandManager = testWindow.brackets.test.CommandManager; Commands = testWindow.brackets.test.Commands; DocumentCommandHandlers = testWindow.brackets.test.DocumentCommandHandlers; DocumentManager = testWindow.brackets.test.DocumentManager; MainViewManager = testWindow.brackets.test.MainViewManager; Dialogs = testWindow.brackets.test.Dialogs; FileSystem = testWindow.brackets.test.FileSystem; FileViewController = testWindow.brackets.test.FileViewController; EditorManager = testWindow.brackets.test.EditorManager; }); }); afterLast(function () { testWindow = null; CommandManager = null; Commands = null; DocumentCommandHandlers = null; DocumentManager = null; MainViewManager = null; Dialogs = null; FileViewController = null; EditorManager = null; SpecRunnerUtils.closeTestWindow(); }); beforeEach(function () { // Working set behavior is sensitive to whether file lives in the project or outside it, so make // the project root a known quantity. SpecRunnerUtils.loadProjectInTestWindow(testPath); }); afterEach(function () { promise = null; runs(function () { // Call closeAll() directly. Some tests set a spy on the save as // dialog preventing SpecRunnerUtils.closeAllFiles() from // working properly. testWindow.brackets.test.MainViewManager._closeAll(testWindow.brackets.test.MainViewManager.ALL_PANES); }); }); // Helper functions for testing cursor position / selection range function fixPos(pos) { if (!("sticky" in pos)) { pos.sticky = null; } return pos; } function fixSel(sel) { fixPos(sel.start); fixPos(sel.end); if (!("reversed" in sel)) { sel.reversed = false; } return sel; } function fixSels(sels) { sels.forEach(function (sel) { fixSel(sel); }); return sels; } /** Expect a file to exist (failing test if not) and then delete it */ function expectAndDelete(fullPath) { runs(function () { var promise = SpecRunnerUtils.resolveNativeFileSystemPath(fullPath); waitsForDone(promise, "Verify file exists: " + fullPath); }); runs(function () { var promise = SpecRunnerUtils.deletePath(fullPath); waitsForDone(promise, "Remove testfile " + fullPath, 5000); }); } describe("New Untitled File", function () { var filePath, newFilename, newFilePath; beforeEach(function () { filePath = testPath + "/test.js"; newFilename = "testname.js"; newFilePath = testPath + "/" + newFilename; }); /** @return {Array.<Document>} */ function getOpenDocsFromWorkingSet() { return MainViewManager.getWorkingSet(MainViewManager.ALL_PANES).map(function (file) { return DocumentManager.getOpenDocumentForPath(file.fullPath); }); } /** Creates N untitled documents with distinct content (the file's creation-order index as a string) */ function createUntitled(count) { function doCreateUntitled(content) { runs(function () { var promise = CommandManager.execute(Commands.FILE_NEW_UNTITLED); promise.done(function (untitledDoc) { untitledDoc.replaceRange(content, {line: 0, ch: 0}); }); waitsForDone(promise, "FILE_NEW_UNTITLED"); }); } var i; for (i = 0; i < count; i++) { doCreateUntitled(String(i)); } } // Single untitled documents it("should create a new untitled document in the Working Set", function () { runs(function () { promise = CommandManager.execute(Commands.FILE_NEW_UNTITLED); waitsForDone(promise, "FILE_NEW_UNTITLED"); }); runs(function () { var untitledDocument = DocumentManager.getCurrentDocument(); expect(untitledDocument.isDirty).toBe(false); expect(untitledDocument.isUntitled()).toBe(true); // Verify that doc is accessible through standard doc-getting APIs var openDoc = DocumentManager.getOpenDocumentForPath(untitledDocument.file.fullPath); expect(openDoc).toBe(untitledDocument); var asyncDocPromise = DocumentManager.getDocumentForPath(untitledDocument.file.fullPath); asyncDocPromise.done(function (asyncDoc) { expect(asyncDoc).toBe(untitledDocument); }); waitsForDone(asyncDocPromise); }); }); it("should swap out untitled document in the Working Set after saving with new name", function () { runs(function () { promise = CommandManager.execute(Commands.FILE_NEW_UNTITLED); waitsForDone(promise, "FILE_NEW_UNTITLED"); }); runs(function () { spyOn(FileSystem, 'showSaveDialog').andCallFake(function (dialogTitle, initialPath, proposedNewName, callback) { callback(undefined, newFilePath); }); promise = CommandManager.execute(Commands.FILE_SAVE); waitsForDone(promise, "Provide new filename", 5000); }); runs(function () { var noLongerUntitledDocument = DocumentManager.getCurrentDocument(); expect(noLongerUntitledDocument.isDirty).toBe(false); expect(noLongerUntitledDocument.isUntitled()).toBe(false); expect(noLongerUntitledDocument.file.fullPath).toEqual(newFilePath); expect(MainViewManager.findInWorkingSet(MainViewManager.ALL_PANES, newFilePath)).toNotEqual(-1); expect(MainViewManager.getWorkingSet(MainViewManager.ALL_PANES).length).toEqual(1); // no remnant of untitled doc left // Verify file exists, & clean up expectAndDelete(newFilePath); }); }); // from Issue #6121 it("should recognize that a previously untitled, but now saved, document can be saved without prompting for a filename", function () { runs(function () { promise = CommandManager.execute(Commands.FILE_NEW_UNTITLED); waitsForDone(promise, "FILE_NEW_UNTITLED"); }); runs(function () { spyOn(FileSystem, 'showSaveDialog').andCallFake(function (dialogTitle, initialPath, proposedNewName, callback) { callback(undefined, newFilePath); }); promise = CommandManager.execute(Commands.FILE_SAVE); waitsForDone(promise, "FILE_SAVE"); expect(FileSystem.showSaveDialog).toHaveBeenCalled(); // first save should prompt user for filename }); runs(function () { promise = CommandManager.execute(Commands.FILE_SAVE); waitsForDone(promise, "FILE_SAVE"); expect(FileSystem.showSaveDialog.callCount).toEqual(1); // second save should not prompt }); }); xit("should swap out untitled document from working set even when not current", function () { runs(function () { promise = CommandManager.execute(Commands.FILE_NEW_UNTITLED); waitsForDone(promise, "FILE_NEW_UNTITLED"); }); runs(function () { // Select test.js in the project tree (so nothing is selected in the working set) promise = FileViewController.openAndSelectDocument(testPath + "/test.js", FileViewController.PROJECT_MANAGER); waitsForDone(promise, "openAndSelectDocument"); }); runs(function () { spyOn(FileSystem, 'showSaveDialog').andCallFake(function (dialogTitle, initialPath, proposedNewName, callback) { callback(undefined, newFilePath); }); var promise = CommandManager.execute(Commands.FILE_SAVE_ALL); waitsForDone(promise, "FILE_SAVE_ALL"); }); runs(function () { var noLongerUntitledDocument = DocumentManager.getCurrentDocument(); expect(noLongerUntitledDocument.isDirty).toBe(false); expect(noLongerUntitledDocument.isUntitled()).toBe(false); expect(noLongerUntitledDocument.file.fullPath).toEqual(newFilePath); expect(MainViewManager.findInWorkingSet(MainViewManager.ALL_PANES, newFilePath)).toNotEqual(-1); expect(MainViewManager.getWorkingSet(MainViewManager.ALL_PANES).length).toEqual(1); // no remnant of untitled doc left // Verify file exists, & clean up expectAndDelete(newFilePath); }); }); it("should ask to save untitled document upon closing", function () { newFilename = "testname2.js"; newFilePath = testPath + "/" + newFilename; runs(function () { promise = CommandManager.execute(Commands.FILE_NEW_UNTITLED); waitsForDone(promise, "FILE_NEW_UNTITLED"); }); runs(function () { // set Dirty flag var untitledDocument = DocumentManager.getCurrentDocument(); untitledDocument.setText(TEST_JS_NEW_CONTENT); spyOn(Dialogs, 'showModalDialog').andCallFake(function (dlgClass, title, message, buttons) { return {done: function (callback) { callback(Dialogs.DIALOG_BTN_OK); } }; }); spyOn(FileSystem, 'showSaveDialog').andCallFake(function (dialogTitle, initialPath, proposedNewName, callback) { callback(undefined, newFilePath); }); promise = CommandManager.execute(Commands.FILE_CLOSE); waitsForDone(promise, "FILE_CLOSE"); }); runs(function () { expect(MainViewManager.getWorkingSet(MainViewManager.ALL_PANES).length).toEqual(0); // Verify file exists, & clean up expectAndDelete(newFilePath); }); }); it("should keep dirty untitled document in Working Set when close document is canceled", function () { runs(function () { promise = CommandManager.execute(Commands.FILE_NEW_UNTITLED); waitsForDone(promise, "FILE_NEW_UNTITLED"); }); runs(function () { // set Dirty flag var untitledDocument = DocumentManager.getCurrentDocument(); untitledDocument.setText(TEST_JS_NEW_CONTENT); spyOn(Dialogs, 'showModalDialog').andCallFake(function (dlgClass, title, message, buttons) { return {done: function (callback) { callback(Dialogs.DIALOG_BTN_CANCEL); } }; }); promise = CommandManager.execute(Commands.FILE_CLOSE); waitsForFail(promise, "FILE_CLOSE"); }); runs(function () { var untitledDocument = DocumentManager.getCurrentDocument(); expect(untitledDocument.isDirty).toBe(true); expect(untitledDocument.isUntitled()).toBe(true); expect(MainViewManager.findInWorkingSet(MainViewManager.ALL_PANES, untitledDocument.file.fullPath)).toNotEqual(-1); }); }); it("should keep dirty untitled document in Working Set when saving during close is canceled", function () { runs(function () { promise = CommandManager.execute(Commands.FILE_NEW_UNTITLED); waitsForDone(promise, "FILE_NEW_UNTITLED"); }); runs(function () { // set Dirty flag var untitledDocument = DocumentManager.getCurrentDocument(); untitledDocument.setText(TEST_JS_NEW_CONTENT); spyOn(Dialogs, 'showModalDialog').andCallFake(function (dlgClass, title, message, buttons) { return {done: function (callback) { callback(Dialogs.DIALOG_BTN_OK); } }; }); spyOn(FileSystem, 'showSaveDialog').andCallFake(function (dialogTitle, initialPath, proposedNewName, callback) { callback(undefined, ""); // "" means cancel }); promise = CommandManager.execute(Commands.FILE_CLOSE); waitsForFail(promise, "FILE_CLOSE"); }); runs(function () { var untitledDocument = DocumentManager.getCurrentDocument(); expect(untitledDocument.isDirty).toBe(true); expect(untitledDocument.isUntitled()).toBe(true); expect(MainViewManager.findInWorkingSet(MainViewManager.ALL_PANES, untitledDocument.file.fullPath)).toNotEqual(-1); }); }); it("should remove dirty untitled Document from Working Set when closing document is not saved", function () { runs(function () { promise = CommandManager.execute(Commands.FILE_NEW_UNTITLED); waitsForDone(promise, "FILE_NEW_UNTITLED"); }); runs(function () { // set Dirty flag var untitledDocument = DocumentManager.getCurrentDocument(); untitledDocument.setText(TEST_JS_NEW_CONTENT); spyOn(Dialogs, 'showModalDialog').andCallFake(function (dlgClass, title, message, buttons) { return {done: function (callback) { callback(Dialogs.DIALOG_BTN_DONTSAVE); } }; }); promise = CommandManager.execute(Commands.FILE_CLOSE); waitsForDone(promise, "FILE_CLOSE"); }); runs(function () { expect(MainViewManager.getWorkingSet(MainViewManager.ALL_PANES).length).toEqual(0); }); }); it("should remove new untitled Document from Working Set upon closing", function () { runs(function () { promise = CommandManager.execute(Commands.FILE_NEW_UNTITLED); waitsForDone(promise, "FILE_NEW_UNTITLED"); }); runs(function () { promise = CommandManager.execute(Commands.FILE_CLOSE); waitsForDone(promise, "FILE_CLOSE"); }); runs(function () { expect(MainViewManager.getWorkingSet(MainViewManager.ALL_PANES).length).toEqual(0); }); }); // Multiple untitled documents it("multiple untitled documents shouldn't conflict", function () { createUntitled(3); runs(function () { var workingSetListDocs = getOpenDocsFromWorkingSet(); expect(workingSetListDocs.length).toEqual(3); // Expect non-conflicting dummy paths expect(workingSetListDocs[0].file.fullPath).not.toBe(workingSetListDocs[1].file.fullPath); expect(workingSetListDocs[0].file.fullPath).not.toBe(workingSetListDocs[2].file.fullPath); expect(workingSetListDocs[1].file.fullPath).not.toBe(workingSetListDocs[2].file.fullPath); // Expect separate Document objects expect(workingSetListDocs[0]).not.toBe(workingSetListDocs[1]); expect(workingSetListDocs[0]).not.toBe(workingSetListDocs[2]); expect(workingSetListDocs[1]).not.toBe(workingSetListDocs[2]); // Expect all Documents to be untitled workingSetListDocs.forEach(function (doc) { expect(doc.isUntitled()).toBe(true); }); // Expect separate, unique content expect(workingSetListDocs[0].getText()).toBe("0"); expect(workingSetListDocs[1].getText()).toBe("1"); expect(workingSetListDocs[2].getText()).toBe("2"); }); }); it("should save-all multiple untitled documents", function () { function getFilename(i) { return testPath + "/test_saveall_" + i + ".js"; } createUntitled(3); runs(function () { var fileI = 0; spyOn(FileSystem, 'showSaveDialog').andCallFake(function (dialogTitle, initialPath, proposedNewName, callback) { callback(undefined, getFilename(fileI)); fileI++; }); var promise = CommandManager.execute(Commands.FILE_SAVE_ALL); waitsForDone(promise, "FILE_SAVE_ALL", 5000); }); runs(function () { // Expect clean Documents with correct, unique non-dummy paths var workingSetListDocs = getOpenDocsFromWorkingSet(); expect(workingSetListDocs.length).toEqual(3); workingSetListDocs.forEach(function (doc, i) { expect(doc.isUntitled()).toBe(false); expect(doc.isDirty).toBe(false); expect(doc.file.fullPath).toBe(getFilename(i)); }); // Verify files exist & clean up workingSetListDocs.forEach(function (doc, i) { expectAndDelete(getFilename(i)); }); }); }); it("close-all should save multiple untitled documents", function () { function getFilename(i) { return testPath + "/test_closeall_cancel_" + i + ".js"; } createUntitled(3); runs(function () { spyOn(Dialogs, 'showModalDialog').andCallFake(function (dlgClass, title, message, buttons) { return {done: function (callback) { callback(Dialogs.DIALOG_BTN_OK); } }; }); var fileI = 0; spyOn(FileSystem, 'showSaveDialog').andCallFake(function (dialogTitle, initialPath, proposedNewName, callback) { callback(undefined, getFilename(fileI)); fileI++; }); var promise = CommandManager.execute(Commands.FILE_CLOSE_ALL); waitsForDone(promise, "FILE_CLOSE_ALL", 5000); }); runs(function () { expect(MainViewManager.getWorkingSet(MainViewManager.ALL_PANES).length).toEqual(0); // Verify files exist & clean up [0, 1, 2].forEach(function (i) { expectAndDelete(getFilename(i)); }); }); }); it("canceling a save-all prompt should cancel remaining saves", function () { function getFilename(i) { return testPath + "/test_saveall_" + i + ".js"; } createUntitled(3); runs(function () { var fileI = 0; spyOn(FileSystem, 'showSaveDialog').andCallFake(function (dialogTitle, initialPath, proposedNewName, callback) { if (fileI === 0) { // save first file callback(undefined, getFilename(fileI)); } else if (fileI === 1) { // cancel save dialog on second file callback(undefined, ""); // "" means cancel } else { // shouldn't get prompted for any further files expect(false).toBe(true); } fileI++; }); var promise = CommandManager.execute(Commands.FILE_SAVE_ALL); waitsForFail(promise, "FILE_SAVE_ALL"); // note: promise should fail due to cancellation }); runs(function () { // Expect *only* first Document was saved - others remain untitled & dirty var workingSetListDocs = getOpenDocsFromWorkingSet(); expect(workingSetListDocs.length).toEqual(3); workingSetListDocs.forEach(function (doc, i) { if (i === 0) { // First file was saved when we confirmed save dialog expect(doc.isUntitled()).toBe(false); expect(doc.isDirty).toBe(false); expect(doc.file.fullPath).toBe(getFilename(i)); } else { // All other saves should have been canceled expect(doc.isUntitled()).toBe(true); expect(doc.isDirty).toBe(true); expect(doc.file.fullPath).not.toBe(getFilename(i)); // should still have dummy path } }); // Clean up the one file we did save expectAndDelete(getFilename(0)); }); }); it("canceling any close-all save should not close any documents", function () { function getFilename(i) { return testPath + "/test_closeall_save_" + i + ".js"; } createUntitled(3); runs(function () { spyOn(Dialogs, 'showModalDialog').andCallFake(function (dlgClass, title, message, buttons) { return {done: function (callback) { callback(Dialogs.DIALOG_BTN_OK); } }; }); var fileI = 0; spyOn(FileSystem, 'showSaveDialog').andCallFake(function (dialogTitle, initialPath, proposedNewName, callback) { if (fileI === 0) { // save first file callback(undefined, getFilename(fileI)); } else if (fileI === 1) { // cancel save dialog on second file callback(undefined, ""); // "" means cancel } else { // shouldn't get prompted for any further files expect(false).toBe(true); } fileI++; }); var promise = CommandManager.execute(Commands.FILE_CLOSE_ALL); waitsForFail(promise, "FILE_CLOSE_ALL"); // note: promise should fail due to cancellation }); runs(function () { // Expect *all* Documents still open, and *only* first Document was saved var workingSetListDocs = getOpenDocsFromWorkingSet(); expect(workingSetListDocs.length).toEqual(3); workingSetListDocs.forEach(function (doc, i) { if (i === 0) { // First file was saved when we confirmed save dialog expect(doc.isUntitled()).toBe(false); expect(doc.isDirty).toBe(false); expect(doc.file.fullPath).toBe(getFilename(i)); } else { // All other saves should have been canceled expect(doc.isUntitled()).toBe(true); expect(doc.isDirty).toBe(true); expect(doc.file.fullPath).not.toBe(getFilename(i)); // should still have dummy path } }); // Clean up the one file we did save expectAndDelete(getFilename(0)); }); }); }); // TODO (issue #115): test Commands.FILE_NEW. Current implementation of // ProjectManager.createNewItem() is tightly coupled to jstree UI and // events. describe("Close File", function () { it("should complete without error if no files are open", function () { runs(function () { promise = CommandManager.execute(Commands.FILE_CLOSE); waitsForDone(promise, "FILE_CLOSE"); }); runs(function () { expect(testWindow.document.title).toBe("DocumentCommandHandlers-test-files " + WINDOW_TITLE_DOT + " " + brackets.config.app_title); }); }); it("should close a file in the editor", function () { var promise; runs(function () { promise = CommandManager.execute(Commands.FILE_OPEN, {fullPath: testPath + "/test.js"}); waitsForDone(promise, "FILE_OPEN"); }); runs(function () { promise = CommandManager.execute(Commands.FILE_CLOSE); waitsForDone(promise, "FILE_CLOSE"); }); runs(function () { expect(testWindow.document.title).toBe("DocumentCommandHandlers-test-files " + WINDOW_TITLE_DOT + " " + brackets.config.app_title); }); }); }); describe("Close List", function () { beforeEach(function () { runs(function () { promise = CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, {fullPath: testPath + "/test.js"}); waitsForDone(promise, "CMD_ADD_TO_WORKINGSET_AND_OPEN"); }); runs(function () { promise = CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, {fullPath: testPath + "/test2.js"}); waitsForDone(promise, "CMD_ADD_TO_WORKINGSET_AND_OPEN"); }); }); it("should not close the current view", function () { var currentPath, docsToClose; runs(function () { currentPath = MainViewManager.getCurrentlyViewedPath(); docsToClose = DocumentManager.getAllOpenDocuments().filter(function (doc) { return (doc !== DocumentManager.getCurrentDocument()); }); promise = CommandManager.execute(Commands.FILE_CLOSE_LIST, {fileList: docsToClose.map(function (doc) { return doc.file; })}); waitsForDone(promise, "FILE_CLOSE_LIST"); }); runs(function () { expect(MainViewManager.getCurrentlyViewedPath()).toBe(currentPath); }); }); it("should close all views", function () { var docsToClose; runs(function () { docsToClose = DocumentManager.getAllOpenDocuments(); promise = CommandManager.execute(Commands.FILE_CLOSE_LIST, {fileList: docsToClose.map(function (doc) { return doc.file; })}); waitsForDone(promise, "FILE_CLOSE_LIST"); }); runs(function () { expect(MainViewManager.getCurrentlyViewedFile()).toBeFalsy(); }); }); it("should open the next view when the current view is closed", function () { var currentPath, docsToClose; runs(function () { currentPath = MainViewManager.getCurrentlyViewedPath(); docsToClose = DocumentManager.getAllOpenDocuments().filter(function (doc) { return (doc === DocumentManager.getCurrentDocument()); }); promise = CommandManager.execute(Commands.FILE_CLOSE_LIST, {fileList: docsToClose.map(function (doc) { return doc.file; })}); waitsForDone(promise, "FILE_CLOSE_LIST"); }); runs(function () { expect(MainViewManager.getCurrentlyViewedPath()).not.toBe(currentPath); expect(MainViewManager.getCurrentlyViewedPath()).toBeTruthy(); }); }); }); describe("Open File", function () { it("should open a file in the editor", function () { var promise; runs(function () { promise = CommandManager.execute(Commands.FILE_OPEN, {fullPath: testPath + "/test.js"}); waitsForDone(promise, "FILE_OPEN"); }); runs(function () { expect(DocumentManager.getCurrentDocument().getText()).toBe(TEST_JS_CONTENT); }); }); it("should resolve with FileSystemError when opening fails", function () { runs(function () { // Dismiss expected error dialog instantly so promise completes & test can proceed spyOn(Dialogs, "showModalDialog").andCallFake(function (dlgClass, title, message, buttons) { return {done: function (callback) { callback(Dialogs.DIALOG_BTN_OK); } }; }); // Open nonexistent file to trigger error result var promise = CommandManager.execute(Commands.FILE_OPEN, {fullPath: testPath + "/doesNotExist.js"}); waitsForFail(promise, "FILE_OPEN"); promise.fail(function (err) { expect(err).toEqual(FileSystemError.NOT_FOUND); }); }); runs(function () { expect(DocumentManager.getCurrentDocument()).toBeFalsy(); }); }); }); describe("Save File", function () { it("should save changes", function () { var filePath = testPath + "/test.js", promise; runs(function () { promise = CommandManager.execute(Commands.FILE_OPEN, {fullPath: filePath}); waitsForDone(promise, "FILE_OPEN"); }); // modify and save runs(function () { DocumentManager.getCurrentDocument().setText(TEST_JS_NEW_CONTENT); promise = CommandManager.execute(Commands.FILE_SAVE); waitsForDone(promise, "FILE_SAVE"); }); // confirm file contents runs(function () { promise = FileUtils.readAsText(FileSystem.getFileForPath(filePath)) .done(function (actualText) { expect(actualText).toBe(TEST_JS_NEW_CONTENT); }); waitsForDone(promise, "Read test file"); }); // reset file contents runs(function () { promise = FileUtils.writeText(FileSystem.getFileForPath(filePath), TEST_JS_CONTENT); waitsForDone(promise, "Revert test file"); }); }); // Regardless of platform, files with CRLF should be saved with CRLF and files with LF should be saved with LF it("should preserve line endings after Save", function () { var crlfText = "line1\r\nline2\r\nline3", lfText = "line1\nline2\nline3", crlfPath = testPath + "/crlfTest.js", lfPath = testPath + "/lfTest.js", promise; // create test files (Git rewrites line endings, so these can't be kept in src control) runs(function () { promise = FileUtils.writeText(FileSystem.getFileForPath(crlfPath), crlfText); waitsForDone(promise, "Create CRLF test file"); }); runs(function () { promise = FileUtils.writeText(FileSystem.getFileForPath(lfPath), lfText); waitsForDone(promise, "Create LF test file"); }); // open, modify, and save file (CRLF case) runs(function () { promise = CommandManager.execute(Commands.FILE_OPEN, {fullPath: crlfPath}); waitsForDone(promise, "Open CRLF test file"); }); runs(function () { DocumentManager.getCurrentDocument().replaceRange("line2a\nline2b", {line: 1, ch: 0}, {line: 1, ch: 5}); promise = CommandManager.execute(Commands.FILE_SAVE); waitsForDone(promise, "Save modified file"); }); // open, modify, and save file (LF case) runs(function () { promise = CommandManager.execute(Commands.FILE_OPEN, {fullPath: lfPath}); waitsForDone(promise, "Open LF test file"); }); runs(function () { DocumentManager.getCurrentDocument().replaceRange("line2a\nline2b", {line: 1, ch: 0}, {line: 1, ch: 5}); promise = CommandManager.execute(Commands.FILE_SAVE); waitsForDone(promise, "Save modified file"); }); // verify files' contents runs(function () { promise = FileUtils.readAsText(FileSystem.getFileForPath(crlfPath)) .done(function (actualText) { expect(actualText).toBe(crlfText.replace("line2", "line2a\r\nline2b")); }); waitsForDone(promise, "Read CRLF test file"); }); runs(function () { promise = FileUtils.readAsText(FileSystem.getFileForPath(lfPath)) .done(function (actualText) { expect(actualText).toBe(lfText.replace("line2", "line2a\nline2b")); }); waitsForDone(promise, "Read LF test file"); }); // clean up runs(function () { waitsForDone(SpecRunnerUtils.deletePath(crlfPath), "Remove CRLF test file"); waitsForDone(SpecRunnerUtils.deletePath(lfPath), "Remove LF test file"); }); }); it("should preserve line endings after Save As", function () { // bug #9179 var crlfText = "line1\r\nline2\r\nline3", lfText = "line1\nline2\nline3", crlfPath = testPath + "/crlfTest.js", lfPath = testPath + "/lfTest.js", crlfNewPath = testPath + "/saveAsCRLF.js", lfNewPath = testPath + "/saveAsLF.js", promise; // create test files (Git rewrites line endings, so these can't be kept in src control) runs(function () { promise = FileUtils.writeText(FileSystem.getFileForPath(crlfPath), crlfText); waitsForDone(promise, "Create CRLF test file"); }); runs(function () { promise = FileUtils.writeText(FileSystem.getFileForPath(lfPath), lfText); waitsForDone(promise, "Create LF test file"); }); // open, modify, and Save As (CRLF case) runs(function () { promise = CommandManager.execute(Commands.FILE_OPEN, {fullPath: crlfPath}); waitsForDone(promise, "Open CRLF test file"); }); runs(function () { DocumentManager.getCurrentDocument().replaceRange("line2a\nline2b", {line: 1, ch: 0}, {line: 1, ch: 5}); spyOn(FileSystem, "showSaveDialog").andCallFake(function (dialogTitle, initialPath, proposedNewName, callback) { callback(undefined, crlfNewPath); }); promise = CommandManager.execute(Commands.FILE_SAVE_AS); waitsForDone(promise, "Save As modified file"); }); // open, modify, and Save As (LF case) runs(function () { promise = CommandManager.execute(Commands.FILE_OPEN, {fullPath: lfPath}); waitsForDone(promise, "Open LF test file"); }); runs(function () { DocumentManager.getCurrentDocument().replaceRange("line2a\nline2b", {line: 1, ch: 0}, {line: 1, ch: 5}); FileSystem.showSaveDialog.andCallFake(function (dialogTitle, initialPath, proposedNewName, callback) { callback(undefined, lfNewPath); }); promise = CommandManager.execute(Commands.FILE_SAVE_AS); waitsForDone(promise, "Save As modified file"); }); // verify files' contents runs(function () { promise = FileUtils.readAsText(FileSystem.getFileForPath(crlfNewPath)) .done(function (actualText) { expect(actualText).toBe(crlfText.replace("line2", "line2a\r\nline2b")); }); waitsForDone(promise, "Read CRLF save-as file"); }); runs(function () { promise = FileUtils.readAsText(FileSystem.getFileForPath(lfNewPath)) .done(function (actualText) { expect(actualText).toBe(lfText.replace("line2", "line2a\nline2b")); }); waitsForDone(promise, "Read LF save-as file"); }); // clean up runs(function () { waitsForDone(SpecRunnerUtils.deletePath(crlfPath), "Remove CRLF test file"); waitsForDone(SpecRunnerUtils.deletePath(lfPath), "Remove LF test file"); waitsForDone(SpecRunnerUtils.deletePath(crlfNewPath), "Remove CRLF save-as file"); waitsForDone(SpecRunnerUtils.deletePath(lfNewPath), "Remove LF save-as file"); }); }); }); describe("Save As", function () { var filePath, newFilename, newFilePath, selections = [{start: {line: 0, ch: 1}, end: {line: 0, ch: 3}, primary: false, reversed: false}, {start: {line: 0, ch: 6}, end: {line: 0, ch: 6}, primary: true, reversed: false}, {start: {line: 0, ch: 9}, end: {line: 0, ch: 12}, primary: false, reversed: true}]; beforeEach(function () { filePath = testPath + "/test.js"; newFilename = "testname.js"; newFilePath = testPath + "/" + newFilename; }); it("should close the original file, reopen the saved file and add select the new file in the project tree", function () { runs(function () { // Open the file, does not add to working set promise = CommandManager.execute(Commands.FILE_OPEN, {fullPath: filePath}); waitsForDone(promise, "FILE_OPEN"); }); runs(function () { var currentDocument = DocumentManager.getCurrentDocument(), currentEditor = EditorManager.getActiveEditor(); expect(currentDocument.file.fullPath).toEqual(filePath); currentEditor.setSelections(selections); }); runs(function () { spyOn(FileSystem, 'showSaveDialog').andCallFake(function (dialogTitle, initialPath, proposedNewName, callback) { callback(undefined, newFilePath); }); promise = CommandManager.execute(Commands.FILE_SAVE_AS); waitsForDone(promise, "Provide new filename"); }); runs(function () { var currentDocument = DocumentManager.getCurrentDocument(), currentEditor = EditorManager.getActiveEditor(); expect(currentDocument.file.fullPath).toEqual(newFilePath); expect(fixSels(currentEditor.getSelections())).toEqual(fixSels(selections)); }); runs(function () { // New file should not appear in working set expect(MainViewManager.findInWorkingSet(MainViewManager.ALL_PANES, newFilePath)).toEqual(-1); // Verify file exists & clean it up expectAndDelete(newFilePath); }); }); it("should close the original file, reopen the saved file outside the project and add it to the Working Set", function () { newFilePath = SpecRunnerUtils.getTempDirectory() + "/" + newFilename; SpecRunnerUtils.createTempDirectory(); runs(function () { promise = CommandManager.execute(Commands.FILE_OPEN, {fullPath: filePath}); waitsForDone(promise, "FILE_OPEN"); }); runs(function () { var currentDocument = DocumentManager.getCurrentDocument(); expect(currentDocument.file.fullPath).toEqual(filePath); }); runs(function () { spyOn(FileSystem, 'showSaveDialog').andCallFake(function (dialogTitle, initialPath, proposedNewName, callback) { callback(undefined, newFilePath); }); promise = CommandManager.execute(Commands.FILE_SAVE_AS); waitsForDone(promise, "Provide new filename"); }); runs(function () { var currentDocument = DocumentManager.getCurrentDocument(); expect(currentDocument.file.fullPath).toEqual(newFilePath); }); runs(function () { // Only new file should appear in working set expect(MainViewManager.findInWorkingSet(MainViewManager.ALL_PANES, newFilePath)).toNotEqual(-1); expect(MainViewManager.findInWorkingSet(MainViewManager.ALL_PANES, filePath)).toEqual(-1); // Verify file exists & clean it up expectAndDelete(newFilePath); }); }); it("should leave Working Set untouched when operation is canceled", function () { runs(function () { promise = CommandManager.execute(Commands.FILE_OPEN, {fullPath: filePath}); waitsForDone(promise, "FILE_OPEN"); }); runs(function () { var currentDocument = DocumentManager.getCurrentDocument(); expect(currentDocument.file.fullPath).toEqual(filePath); }); runs(function () { spyOn(FileSystem, 'showSaveDialog').andCallFake(function (dialogTitle, initialPath, proposedNewName, callback) { callback("Error", undefined); }); promise = CommandManager.execute(Commands.FILE_SAVE_AS); waitsForFail(promise, "Provide new filename"); }); runs(function () { var currentDocument = DocumentManager.getCurrentDocument(); expect(currentDocument.file.fullPath).toEqual(filePath); }); runs(function () { expect(MainViewManager.findInWorkingSet(MainViewManager.ALL_PANES, newFilePath)).toEqual(-1); }); }); it("should maintain order within Working Set after Save As", function () { var views, targetDoc; runs(function () { // open the target file promise = CommandManager.execute(Commands.FILE_OPEN, {fullPath: filePath}); waitsForDone(promise, "FILE_OPEN"); }); runs(function () { views = MainViewManager.findInAllWorkingSets(filePath); targetDoc = DocumentManager.getOpenDocumentForPath(filePath); }); runs(function () { // create an untitled document so that the file opened above isn't the last item in the working set list promise = CommandManager.execute(Commands.FILE_NEW_UNTITLED); waitsForDone(promise, "FILE_NEW_UNTITLED"); }); runs(function () { // save the file opened above to a different filename MainViewManager._edit(MainViewManager.ACTIVE_PANE, targetDoc); spyOn(FileSystem, 'showSaveDialog').andCallFake(function (dialogTitle, initialPath, proposedNewName, callback) { callback(undefined, newFilePath); }); promise = CommandManager.execute(Commands.FILE_SAVE_AS); waitsForDone(promise, "Provide new filename"); }); runs(function () { // New file should appear in working set at old file's index; old file shouldn't appear at all expect(MainViewManager.findInAllWorkingSets(newFilePath)).toEqual(views); expect(MainViewManager.findInWorkingSet(MainViewManager.ALL_PANES, filePath)).toEqual(-1); // Verify file exists & clean it up expectAndDelete(newFilePath); }); }); }); describe("Dirty File Handling", function () { beforeEach(function () { var promise; SpecRunnerUtils.loadProjectInTestWindow(testPath); runs(function () { promise = CommandManager.execute(Commands.FILE_OPEN, {fullPath: testPath + "/test.js"}); waitsForDone(promise, "FILE_OPEN"); }); }); it("should report clean immediately after opening a file", function () { runs(function () { // verify Document dirty status expect(DocumentManager.getCurrentDocument().isDirty).toBe(false); // verify no dot in titlebar expect(testWindow.document.title).toBe("test.js (DocumentCommandHandlers-test-files) " + WINDOW_TITLE_DOT + " " + brackets.config.app_title); }); }); it("should report dirty when modified", function () { var doc = DocumentManager.getCurrentDocument(); runs(function () { // change editor content doc.setText(TEST_JS_NEW_CONTENT); // verify Document dirty status expect(doc.isDirty).toBe(true); // verify dot in titlebar expect(testWindow.document.title).toBe("• test.js (DocumentCommandHandlers-test-files) " + WINDOW_TITLE_DOT + " " + brackets.config.app_title); }); }); it("should report dirty after undo and redo", function () { var doc = DocumentManager.getCurrentDocument(); var editor = doc._masterEditor._codeMirror; runs(function () { // change editor content, followed by undo and redo doc.setText(TEST_JS_NEW_CONTENT); editor.undo(); expect(doc.getText()).toBe(TEST_JS_CONTENT); editor.redo(); expect(doc.getText()).toBe(TEST_JS_NEW_CONTENT); expect(doc.isDirty).toBe(true); }); }); it("should report not dirty after explicit clean", function () { var doc = DocumentManager.getCurrentDocument(); runs(function () { doc.setText(TEST_JS_NEW_CONTENT); doc._markClean(); expect(doc.isDirty).toBe(false); }); }); it("should report not dirty after undo", function () { runs(function () { // change editor content, followed by undo var doc = DocumentManager.getCurrentDocument(); var editor = doc._masterEditor._codeMirror; doc.setText(TEST_JS_NEW_CONTENT); editor.undo(); // verify Document dirty status expect(doc.getText()).toBe(TEST_JS_CONTENT); expect(DocumentManager.getCurrentDocument().isDirty).toBe(false); }); }); it("should update dirty flag with undo/redo after explicit clean", function () { var doc = DocumentManager.getCurrentDocument(); var editor = doc._masterEditor._codeMirror; runs(function () { // Change editor content and make that the new clean state doc.setText(TEST_JS_NEW_CONTENT); doc._markClean(); // Undo past the clean state (and back to counter == 0) editor.undo(); expect(doc.isDirty).toBe(true); expect(doc.getText()).toBe(TEST_JS_CONTENT); // Redo: should be clean again editor.redo(); expect(doc.isDirty).toBe(false); expect(doc.getText()).toBe(TEST_JS_NEW_CONTENT); // Add another change doc.setText(TEST_JS_SECOND_NEW_CONTENT); expect(doc.getText()).toBe(TEST_JS_SECOND_NEW_CONTENT); expect(doc.isDirty).toBe(true); // Undo back to clean state editor.undo(); expect(doc.isDirty).toBe(false); expect(doc.getText()).toBe(TEST_JS_NEW_CONTENT); }); }); it("should report dirty after undo past clean state, followed by new change", function () { runs(function () { // Change editor content and make that the new clean state var doc = DocumentManager.getCurrentDocument(); var editor = doc._masterEditor._codeMirror; doc.setText(TEST_JS_NEW_CONTENT); doc._markClean(); // Undo past the clean state (and back to counter == 0) editor.undo(); expect(doc.isDirty).toBe(true); // Make a new change - should remain dirty doc.setText(TEST_JS_SECOND_NEW_CONTENT); expect(doc.isDirty).toBe(true); // Should be impossible to get back to clean via undo/redo editor.undo(); expect(doc.isDirty).toBe(true); expect(doc.getText()).toBe(TEST_JS_CONTENT); editor.redo(); expect(doc.isDirty).toBe(true); expect(doc.getText()).toBe(TEST_JS_SECOND_NEW_CONTENT); }); }); }); describe("Decorated Path Parser", function () { it("should correctly parse decorated paths", function () { var path = testPath + "/test.js"; expect(DocumentCommandHandlers._parseDecoratedPath(null)).toEqual({path: null, line: null, column: null}); expect(DocumentCommandHandlers._parseDecoratedPath(path)).toEqual({path: path, line: null, column: null}); expect(DocumentCommandHandlers._parseDecoratedPath(path + ":123")).toEqual({path: path, line: 123, column: null}); expect(DocumentCommandHandlers._parseDecoratedPath(path + ":123:456")).toEqual({path: path, line: 123, column: 456}); }); }); describe("Open image files", function () { it("document & editor should be null after opening an image", function () { var path = testPath + "/couz.png", promise; runs(function () { promise = CommandManager.execute(Commands.FILE_OPEN, { fullPath: path }); waitsForDone(promise, Commands.FILE_OPEN); }); runs(function () { expect(EditorManager.getActiveEditor()).toBeFalsy(); expect(EditorManager.getCurrentFullEditor()).toBeFalsy(); expect(EditorManager.getFocusedEditor()).toBeFalsy(); expect(MainViewManager.getCurrentlyViewedPath(MainViewManager.ACTIVE_PANE)).toEqual(path); var d = DocumentManager.getCurrentDocument(); expect(d).toBeFalsy(); }); }); it("opening image while text file open should fire currentDocumentChange and activeEditorChange events", function () { var promise, docChangeListener = jasmine.createSpy(), activeEditorChangeListener = jasmine.createSpy(); runs(function () { DocumentManager.on("currentDocumentChange", docChangeListener); EditorManager.on("activeEditorChange", activeEditorChangeListener); promise = CommandManager.execute(Commands.FILE_OPEN, { fullPath: testPath + "/test.js" }); waitsForDone(promise, Commands.FILE_OPEN); }); runs(function () { expect(docChangeListener.callCount).toBe(1); expect(activeEditorChangeListener.callCount).toBe(1); }); runs(function () { promise = CommandManager.execute(Commands.FILE_OPEN, { fullPath: testPath + "/couz.png" }); waitsForDone(promise, Commands.FILE_OPEN); }); runs(function () { expect(docChangeListener.callCount).toBe(2); expect(activeEditorChangeListener.callCount).toBe(2); DocumentManager.off("currentDocumentChange", docChangeListener); EditorManager.off("activeEditorChange", activeEditorChangeListener); }); }); it("opening image while nothing open should NOT fire currentDocumentChange and activeEditorChange events", function () { var promise, docChangeListener = jasmine.createSpy(), activeEditorChangeListener = jasmine.createSpy(); runs(function () { DocumentManager.on("currentDocumentChange", docChangeListener); EditorManager.on("activeEditorChange", activeEditorChangeListener); promise = CommandManager.execute(Commands.FILE_OPEN, { fullPath: testPath + "/couz.png" }); waitsForDone(promise, Commands.FILE_OPEN); }); runs(function () { expect(docChangeListener.callCount).toBe(0); expect(activeEditorChangeListener.callCount).toBe(0); }); runs(function () { promise = CommandManager.execute(Commands.FILE_OPEN, { fullPath: testPath + "/couz2.png" }); waitsForDone(promise, Commands.FILE_OPEN); }); runs(function () { expect(docChangeListener.callCount).toBe(0); expect(activeEditorChangeListener.callCount).toBe(0); DocumentManager.off("currentDocumentChange", docChangeListener); EditorManager.off("activeEditorChange", activeEditorChangeListener); }); }); it("opening text file while other text open should fire currentDocumentChange and activeEditorChange events", function () { var promise, docChangeListener = jasmine.createSpy(), activeEditorChangeListener = jasmine.createSpy(); runs(function () { DocumentManager.on("currentDocumentChange", docChangeListener); EditorManager.on("activeEditorChange", activeEditorChangeListener); promise = CommandManager.execute(Commands.FILE_OPEN, { fullPath: testPath + "/test.js" }); waitsForDone(promise, Commands.FILE_OPEN); }); runs(function () { expect(docChangeListener.callCount).toBe(1); expect(activeEditorChangeListener.callCount).toBe(1); }); runs(function () { promise = CommandManager.execute(Commands.FILE_OPEN, { fullPath: testPath + "/test2.js" }); waitsForDone(promise, Commands.FILE_OPEN); }); runs(function () { expect(docChangeListener.callCount).toBe(2); expect(activeEditorChangeListener.callCount).toBe(2); DocumentManager.off("currentDocumentChange", docChangeListener); EditorManager.off("activeEditorChange", activeEditorChangeListener); }); }); it("should return an editor after opening a text file", function () { var path = testPath + "/test.js", promise; runs(function () { promise = CommandManager.execute(Commands.FILE_OPEN, { fullPath: path }); waitsForDone(promise, Commands.FILE_OPEN); }); runs(function () { var e = EditorManager.getActiveEditor(); expect(e.document.file.fullPath).toBe(path); e = EditorManager.getCurrentFullEditor(); expect(e.document.file.fullPath).toBe(path); e = EditorManager.getFocusedEditor(); expect(e.document.file.fullPath).toBe(path); expect(MainViewManager.getCurrentlyViewedPath()).toEqual(path); }); }); }); describe("Scrolling", function () { it("should scroll when moving the cursor to the end of a really long line", function () { runs(function () { promise = CommandManager.execute(Commands.FILE_NEW_UNTITLED); waitsForDone(promise, Commands.FILE_NEW_UNTITLED); }); runs(function () { var myEditor = EditorManager.getActiveEditor(); // turn off word-wrap myEditor._codeMirror.setOption("lineWrapping", false); myEditor.document.setText("ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd some really long line"); myEditor.setCursorPos(1, 1); myEditor._codeMirror.execCommand("goLineEnd"); var se = myEditor.getScrollerElement(), sp = se.scrollLeft, $se = _$(se); // really big number -- will scroll to the end of the line $se.scrollLeft(99999999); expect(sp).toEqual(se.scrollLeft); }); }); }); }); });