\n{{STORY_DATA}}\n\n\n\n\n"});
\ No newline at end of file
diff --git a/story-formats/Harlowe/format.js b/story-formats/harlowe-1.2.3/format.js
similarity index 100%
rename from story-formats/Harlowe/format.js
rename to story-formats/harlowe-1.2.3/format.js
diff --git a/story-formats/Harlowe/icon.svg b/story-formats/harlowe-1.2.3/icon.svg
similarity index 100%
rename from story-formats/Harlowe/icon.svg
rename to story-formats/harlowe-1.2.3/icon.svg
diff --git a/story-formats/harlowe-2.0.0/format.js b/story-formats/harlowe-2.0.0/format.js
new file mode 100644
index 000000000..5177d5e3a
--- /dev/null
+++ b/story-formats/harlowe-2.0.0/format.js
@@ -0,0 +1 @@
+window.storyFormat({"name":"Harlowe","version":"2.0.0","author":"Leon Arnott","description":"The default story format for Twine 2. See its documentation.","image":"icon.svg","url":"http://twinery.org/","proofing":false,"source":"\n\n\n\n{{STORY_NAME}}\n\n\n\n\n\n\n\n{{STORY_DATA}}\n\n\n\n\n\n\n","setup": function(){"use strict";}});
\ No newline at end of file
diff --git a/story-formats/harlowe-2.0.0/icon.svg b/story-formats/harlowe-2.0.0/icon.svg
new file mode 100644
index 000000000..cbad87815
--- /dev/null
+++ b/story-formats/harlowe-2.0.0/icon.svg
@@ -0,0 +1,78 @@
+
+
+
+
diff --git a/story-formats/paperthin-1.0.0/format.js b/story-formats/paperthin-1.0.0/format.js
new file mode 100644
index 000000000..aaec67f18
--- /dev/null
+++ b/story-formats/paperthin-1.0.0/format.js
@@ -0,0 +1 @@
+window.storyFormat({"name":"Paperthin","version":"1.0.0","description":"The default proofing format for Twine 2. Icon designed by Simon Child from the Noun Project","author":"Chris Klimas","image":"icon.svg","url":"http://twinery.org/","license":"ZLib/Libpng","proofing":true,"source":"\n\n\n{{STORY_NAME}}\n\n\n\n\n\n\n\n
{{STORY_NAME}}\n
\n{{STORY_DATA}}\n\n\n\n\n"});
diff --git a/story-formats/Paperthin/icon.svg b/story-formats/paperthin-1.0.0/icon.svg
similarity index 100%
rename from story-formats/Paperthin/icon.svg
rename to story-formats/paperthin-1.0.0/icon.svg
diff --git a/story-formats/Snowman/format.js b/story-formats/snowman-1.3.0/format.js
similarity index 100%
rename from story-formats/Snowman/format.js
rename to story-formats/snowman-1.3.0/format.js
diff --git a/story-formats/Snowman/icon.svg b/story-formats/snowman-1.3.0/icon.svg
similarity index 100%
rename from story-formats/Snowman/icon.svg
rename to story-formats/snowman-1.3.0/icon.svg
diff --git a/story-formats/SugarCube/LICENSE b/story-formats/sugarcube-1.0.35/LICENSE
similarity index 100%
rename from story-formats/SugarCube/LICENSE
rename to story-formats/sugarcube-1.0.35/LICENSE
diff --git a/story-formats/SugarCube/format.js b/story-formats/sugarcube-1.0.35/format.js
similarity index 100%
rename from story-formats/SugarCube/format.js
rename to story-formats/sugarcube-1.0.35/format.js
diff --git a/story-formats/SugarCube/icon.svg b/story-formats/sugarcube-1.0.35/icon.svg
similarity index 100%
rename from story-formats/SugarCube/icon.svg
rename to story-formats/sugarcube-1.0.35/icon.svg
diff --git a/story-formats/sugarcube-2.11.0/LICENSE b/story-formats/sugarcube-2.11.0/LICENSE
new file mode 100755
index 000000000..16c827dd2
--- /dev/null
+++ b/story-formats/sugarcube-2.11.0/LICENSE
@@ -0,0 +1,23 @@
+
+Copyright (c) 2013-2016 Thomas Michael Edwards .
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/story-formats/sugarcube-2.11.0/format.js b/story-formats/sugarcube-2.11.0/format.js
new file mode 100755
index 000000000..7e59bab70
--- /dev/null
+++ b/story-formats/sugarcube-2.11.0/format.js
@@ -0,0 +1 @@
+window.storyFormat({"name":"SugarCube","version":"2.11.0","description":"A Twine 2 port of the Twine 1 story format by the same name. See its documentation.","author":"Thomas Michael Edwards","image":"icon.svg","url":"http://www.motoslave.net/sugarcube/","license":"Simplified BSD License","proofing":false,"source":"\n\n\n\n{{STORY_NAME}}\n\n\n\n\n\n\n\n\n\n\n\n\n\t
\n\t\t\n\t\t
Apologies! You are using an outdated browser which lacks required capabilities. Please upgrade your browser to improve your experience.
\n\t\t
Initializing. Please wait…
\n\t
\n\t
{{STORY_DATA}}
\n\t\n\n\n"});
diff --git a/story-formats/sugarcube-2.11.0/icon.svg b/story-formats/sugarcube-2.11.0/icon.svg
new file mode 100755
index 000000000..2893c9df0
--- /dev/null
+++ b/story-formats/sugarcube-2.11.0/icon.svg
@@ -0,0 +1,56 @@
+
+
+
diff --git a/tests/selenium/helpers.js b/tests/selenium/helpers.js
deleted file mode 100644
index 7e0525064..000000000
--- a/tests/selenium/helpers.js
+++ /dev/null
@@ -1,40 +0,0 @@
-'use strict';
-var until = require('selenium-webdriver').until;
-
-var helpers = module.exports = {
- testUrl: 'file://' +
- __dirname.replace('/tests/selenium', '') +
- '/build/standalone/index.html',
-
- createStory: function(dr, dontReturn) {
- dr.get(helpers.testUrl + '#stories');
-
- var addButton = dr.findElement({ css: '.addStory' });
- var bubble = addButton
- .findElement({ xpath: '../..' })
- .findElement({ css: '.bubble '});
- addButton.click();
-
- dr.wait(until.elementIsVisible(bubble))
- .then(function() {
- var nameField = bubble.findElement({ css: '.newName' });
- var addSubmitButton = bubble.findElement({ css: '.add' });
-
- nameField.sendKeys(helpers.shortUni);
- addSubmitButton.click();
-
- dr.wait(until.elementLocated({ css: '#storyEditView' }));
-
- if (!dontReturn) {
- dr.wait(until.elementLocated({ css: '#storyEditView' }));
- dr.get(helpers.testUrl + '#stories');
- dr.wait(until.elementLocated({ css: '#storyListView' }));
- };
- });
- },
- // jscs:disable maximumLineLength
- shortUni: 'A good day, World! Schönen Tag, Welt! Une bonne journée, tout le monde! يوم جيد، العالم 좋은 일, 세계! Một ngày tốt lành, thế giới! こんにちは、世界!',
-
- longUni: 'A good day, World! Schönen Tag, Welt! Une bonne journée, tout le monde! يوم جيد، العالم 좋은 일, 세계! Một ngày tốt lành, thế giới! こんにちは、世界! Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec non nisi posuere, tincidunt risus ut, sollicitudin tortor. In ut neque nibh. Vestibulum ac dui eget ligula blandit cursus id eget massa. In justo magna, facilisis ac lorem in, commodo hendrerit turpis. Quisque sed lacus rhoncus, volutpat arcu sit amet, tincidunt metus. Donec hendrerit diam at volutpat dapibus. Donec efficitur imperdiet sapien, ac lacinia felis facilisis eu. Integer bibendum nibh a turpis condimentum rhoncus. Cras condimentum lobortis aliquet. Donec ultricies metus vitae nisl pellentesque rhoncus. Nulla blandit efficitur ante, vel lacinia est porttitor a. Fusce erat sem, pulvinar et pulvinar sit amet, rhoncus eget sem. Suspendisse at ipsum sit amet est facilisis porta. Nam sit amet enim interdum, eleifend augue sit amet, mollis dolor. Quisque iaculis, arcu et consequat congue, justo augue mollis metus, eu fringilla ligula est vel lacus. Vestibulum sit amet venenatis massa. Suspendisse dui velit, dictum eu mollis vitae, mollis id risus. Nullam eleifend ultricies nibh in volutpat. Donec ac imperdiet purus. Nullam luctus, mi a iaculis fermentum, purus magna tincidunt dui, sit amet blandit neque purus sed erat. Mauris feugiat non risus et sollicitudin. Vestibulum ut semper ipsum. Nulla diam nibh, condimentum eget auctor non, dapibus ut libero. In sit amet sem laoreet, consectetur sapien eu, iaculis metus. Sed ut interdum est, ornare scelerisque lectus. Maecenas nec libero sit amet justo tincidunt pulvinar. Sed euismod, risus id pulvinar aliquet, ipsum ipsum malesuada purus, eu varius ligula massa et massa. Curabitur venenatis tempor augue, sed dictum erat blandit et. Nulla posuere commodo lectus, vel feugiat diam commodo ac. Nam consectetur velit sed congue bibendum. Donec eu lectus tortor. Mauris lacinia, massa a dictum placerat, massa nunc venenatis velit, vel mattis eros dui sit amet ipsum. Quisque efficitur, felis ac venenatis maximus, sem mi aliquet mi, sit amet luctus nisl leo vel libero. Nunc a dictum ante. Nam nec enim at justo pellentesque vehicula. Morbi sollicitudin gravida consequat. Duis vulputate, diam vitae venenatis volutpat, quam sem faucibus neque, at bibendum tellus felis id lacus. Vivamus aliquet, ipsum eu dictum bibendum, ligula mi ultricies risus, et suscipit magna velit rutrum sapien. Aliquam ac justo nisi. Pellentesque sed ipsum leo. Ut vitae iaculis sem. Proin ut ante sed libero ultrices tempor nec a lacus. Sed nunc enim, dapibus quis arcu in, rhoncus pretium tellus. Nam tristique ligula magna, nec consequat sem ultrices a. In semper tellus at nisi hendrerit efficitur. Nullam laoreet porta rhoncus. Sed non magna in nibh feugiat lacinia. Etiam vel tortor sagittis libero consequat ultricies sed quis turpis. Pellentesque vel felis at orci egestas mattis ut ut diam. Ut a libero eget sem malesuada blandit. Proin neque ipsum, dictum ut tortor ac, finibus sagittis risus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas feugiat a libero nec fermentum. Phasellus pretium dolor in felis rutrum, in posuere diam sollicitudin. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vestibulum posuere vehicula tortor, vitae dapibus augue lacinia id. Mauris rutrum tincidunt dui, vitae accumsan turpis pulvinar in. Proin a eros porttitor, placerat est mollis, laoreet lorem. Aliquam varius nisl augue, sit amet rhoncus lectus posuere ut. Vivamus vulputate, mauris aliquet lobortis finibus, neque sem malesuada turpis, ut imperdiet nibh erat ultricies erat. Aenean in diam a neque tempus tincidunt. Nulla pretium urna nulla, nec vulputate nunc congue sit amet. Mauris at suscipit neque. Nullam non suscipit mi. Aliquam erat volutpat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla aliquam gravida congue. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Duis sagittis mauris mattis ultrices consequat. Nam quis mauris sit amet elit ornare vehicula ut in lorem. Quisque pulvinar finibus sem, ut dapibus ex maximus sed. Quisque consectetur fringilla ante quis egestas. Sed commodo sit amet turpis et rutrum. Aliquam semper magna sagittis magna sollicitudin sollicitudin. Cras sodales enim vitae lacus tempor tristique. Donec auctor, nisl convallis sodales condimentum, velit tortor efficitur tortor, et tempor nulla sapien eu odio. Suspendisse efficitur mi sed libero facilisis, at suscipit mi condimentum. Ut a dapibus felis. Mauris gravida sapien justo. Vivamus ac nunc vel est condimentum posuere sed vitae massa. Praesent elementum, magna nec feugiat iaculis, lectus turpis molestie felis, quis pellentesque nunc ipsum quis turpis. Nam a massa nec dolor porttitor sagittis eget et odio. Pellentesque dui mi, placerat nec pulvinar vel, finibus sit amet erat. Maecenas nec enim et urna rutrum ultrices. Integer pharetra iaculis dui, a blandit libero placerat sit amet. Donec aliquam sagittis lacus vel placerat. Aliquam quis enim sit amet turpis vestibulum tristique vel et lacus. Aenean vehicula placerat laoreet. Mauris ornare neque urna, id pharetra nibh volutpat at. Ut in erat massa. Suspendisse potenti. Nunc hendrerit eget ante sed ullamcorper. Pellentesque viverra consectetur magna, nec sollicitudin enim maximus eu. Maecenas sagittis malesuada velit in aliquet. Vestibulum elementum elementum felis. Etiam sodales facilisis cursus. Duis sodales, tellus ut rhoncus fringilla, justo ipsum aliquam erat, vel feugiat eros orci efficitur neque. Donec ac pharetra elit. Morbi eget felis eu velit commodo ultrices. Fusce consectetur leo vestibulum tortor pretium, at commodo nisl tincidunt. Vestibulum eu felis eu nisl molestie imperdiet in vel urna. Fusce quis justo nec metus blandit feugiat sit amet sit amet est. Sed vestibulum dignissim velit, et hendrerit nisi aliquam vel. Proin ac commodo nunc. Aliquam vehicula nunc a nisl facilisis faucibus. Etiam venenatis eu eros vitae fermentum. Ut diam turpis, viverra ut vestibulum id, viverra nec dui. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Cras velit neque, maximus ac quam ut, scelerisque suscipit mauris. Proin lacinia neque at euismod pretium. Vestibulum consectetur bibendum turpis. Mauris porta magna magna. Suspendisse porttitor vel velit eget euismod. Quisque lacus urna, pellentesque vitae ornare sit amet, mattis non dui. Sed odio dui, fringilla ut sagittis quis, hendrerit in metus. Phasellus placerat, lectus vitae euismod tristique, est massa pharetra ante, non porttitor diam diam in lorem. Praesent eu nisl dapibus, ullamcorper magna id, molestie est. Etiam.',
- // jscs:enable maximumLineLength
-};
diff --git a/tests/selenium/story-edit.js b/tests/selenium/story-edit.js
deleted file mode 100644
index 96dabf7a6..000000000
--- a/tests/selenium/story-edit.js
+++ /dev/null
@@ -1,421 +0,0 @@
-'use strict';
-var _ = require('underscore');
-var assert = require('selenium-webdriver/testing/assert');
-var firefox = require('selenium-webdriver/firefox');
-var key = require('selenium-webdriver').Key;
-var phantomjs = require('selenium-webdriver/phantomjs');
-var test = require('selenium-webdriver/testing');
-var until = require('selenium-webdriver').until;
-var helpers = require('./helpers');
-
-test.describe('StoryEditView', function() {
- var dr;
- this.timeout(10000);
-
- test.beforeEach(function() {
- dr = new firefox.Driver();
- dr.manage().window().setSize(1024, 768);
- helpers.createStory(dr, true);
- });
-
- test.afterEach(function() {
- dr.quit();
- });
-
- function setCMText(dr, selector, text) {
- dr.executeScript('document.querySelector(\'' + selector +
- ' .CodeMirror\').CodeMirror.setValue(\'' +
- text + '\')');
- };
-
- function getCMText(dr, selector) {
- return dr.executeScript('return document.querySelector(\'' + selector +
- ' .CodeMirror\').CodeMirror.getValue()');
- };
-
- test.it('Displays the story title', function() {
- assert(dr.findElement({ css: 'button.storyName' }).getText())
- .equalTo(helpers.shortUni);
- });
-
- test.it('Returns to the story list with the home button', function() {
- dr.findElement({ css: 'a.home' }).click();
- dr.wait(until.elementLocated({ css: '#storyListView' }));
- });
-
- test.it('Creates a passage with the Create Passage button', function() {
- assert(
- dr.isElementPresent({ css: '.passages .passage:nth-of-type(2)' })
- ).isFalse();
- dr.findElement({ css: 'button.addPassage' }).click();
- assert(
- dr.isElementPresent({ css: '.passages .passage:nth-of-type(2)' })
- ).isTrue();
- });
-
- test.it('Edits a passage by double-clicking it', function() {
- var modal = dr.findElement({ css: '#passageEditModal' });
-
- dr.actions()
- .doubleClick(dr.findElement({ css: '.passages .passage' }))
- .perform();
- dr.wait(until.elementIsVisible(modal));
- dr.findElement({ css: '#passageEditModal .close' }).click();
- dr.wait(until.elementIsNotVisible(modal));
- });
-
- test.it('Edits a passage by clicking its edit button', function() {
- var modal = dr.findElement({ css: '#passageEditModal' });
-
- dr.actions()
- .mouseMove(dr.findElement({ css: '.passages .passage' }))
- .perform();
- dr.findElement({ css: '.passages .passage .edit' }).click();
- dr.wait(until.elementIsVisible(modal));
- dr.findElement({ css: '#passageEditModal .close' }).click();
- dr.wait(until.elementIsNotVisible(modal));
- });
-
- test.it('Saves changes to passage text', function() {
- var modal = dr.findElement({ css: '#passageEditModal' });
-
- dr.actions()
- .doubleClick(dr.findElement({ css: '.passages .passage' }))
- .perform();
- dr.wait(until.elementIsVisible(modal));
- setCMText(dr, '#passageEditModal', helpers.longUni);
-
- dr.findElement({ css: '#passageEditModal .close' }).click();
- dr.wait(until.elementIsNotVisible(modal));
-
- dr.navigate().refresh();
- modal = dr.findElement({ css: '#passageEditModal' });
-
- dr.actions()
- .doubleClick(dr.findElement({ css: '.passages .passage' }))
- .perform();
- dr.wait(until.elementIsVisible(modal));
-
- assert(getCMText(dr, '#passageEditModal')).equalTo(helpers.longUni);
- });
-
- test.it('Adds passages that are newly linked', function() {
- var modal = dr.findElement({ css: '#passageEditModal' });
-
- dr.actions()
- .doubleClick(dr.findElement({ css: '.passages .passage' }))
- .perform();
- dr.wait(until.elementIsVisible(modal));
- setCMText(dr, '#passageEditModal', '[[a new link]]');
- dr.findElement({ css: '#passageEditModal .close' }).click();
- dr.wait(until.elementIsNotVisible(modal));
-
- dr.wait(until.elementLocated({
- css: '.passages .passage:nth-of-type(2) .title',
- }));
- assert(
- dr.findElement({
- css: '.passages .passage:nth-of-type(2) .title',
- }).getText()
- ).equalTo('a new link');
- });
-
- test.it('Does not add passages for linked URLs', function() {
- var modal = dr.findElement({ css: '#passageEditModal' });
-
- dr.actions()
- .doubleClick(dr.findElement({ css: '.passages .passage' }))
- .perform();
- dr.wait(until.elementIsVisible(modal));
- setCMText(dr, '#passageEditModal', 'http://twinery.org');
- dr.findElement({ css: '#passageEditModal .close' }).click();
- dr.wait(until.elementIsNotVisible(modal));
-
- dr.findElements({ css: '.passages .passage' }).then(function(els) {
- assert(els.length).equalTo(1);
- });
- });
-
- test.it('Updates links when passages are renamed', function() {
- var modal = dr.findElement({ css: '#passageEditModal' });
-
- dr.actions()
- .doubleClick(dr.findElement({ css: '.passages .passage' }))
- .perform();
- dr.wait(until.elementIsVisible(modal));
- setCMText(dr, '#passageEditModal', '[[linked passage]]');
- dr.findElement({ css: '#passageEditModal .close' }).click();
- dr.wait(until.elementIsNotVisible(modal));
-
- dr.navigate().refresh();
- modal = dr.findElement({ css: '#passageEditModal' });
-
- dr.actions()
- .doubleClick(dr.findElement({ css: '.passages .passage:nth-of-type(2)' }))
- .perform();
-
- var passageName = dr.findElement({
- css: '#passageEditModal input.passageName',
- });
- passageName.clear();
- passageName.sendKeys('2 linked passage');
- dr.findElement({ css: '#passageEditModal .close' }).click();
- dr.wait(until.elementIsNotVisible(modal));
-
- assert(
- dr.findElement({css: '.passages .passage:first-child .excerpt'}).getText()
- ).equalTo('[[2 linked passage]]');
- });
-
- test.it('Deletes a passage by clicking its delete button', function() {
- var passage = dr.findElement({ css: '.passages .passage' });
-
- dr.actions().mouseMove(passage).perform();
- dr.findElement({ css: '.passages .passage .delete' }).click();
- dr.wait(until.elementLocated({ css: '.modal.confirm' }));
- dr.findElement({ css: '.modal.confirm button.danger' }).click();
- dr.wait(until.stalenessOf(passage));
- });
-
- test.it('Immediately deletes a passage by clicking its delete button with the shift key held', function() {// jscs:ignore maximumLineLength
- var passage = dr.findElement({ css: '.passages .passage' });
-
- dr.actions().mouseMove(passage).sendKeys(key.SHIFT).perform();
- dr.findElement({ css: '.passages .passage .delete' }).click();
- dr.wait(until.stalenessOf(passage));
- });
-
- test.it('Changes zoom levels with the toolbar', function() {
- dr.findElement({ css: '.toolbar .zoomSmall' }).click();
- dr.wait(until.elementLocated({ css: '.main .zoom-small' }));
- dr.findElement({ css: '.toolbar .zoomMedium' }).click();
- dr.wait(until.elementLocated({ css: '.main .zoom-medium' }));
- dr.findElement({ css: '.toolbar .zoomBig' }).click();
- dr.wait(until.elementLocated({ css: '.main .zoom-big' }));
- });
-
- test.it('Tests a story with the Test button', function() {
- dr.findElement({ css: '.toolbar .testStory' }).click();
- dr.getAllWindowHandles(function(winds) {
- var found;
-
- for (var i = 0; i < winds.length; i++) {
- if (i == helpers.shortUni) {
- found = true;
- }
- }
-
- assert(found).isTrue();
- });
- });
-
- test.it('Plays a story with the Play button', function() {
- dr.findElement({ css: '.toolbar .playStory' }).click();
- dr.getAllWindowHandles(function(winds) {
- var found;
-
- for (var i = 0; i < winds.length; i++) {
- if (i == helpers.shortUni) {
- found = true;
- }
- }
-
- assert(found).isTrue();
- });
- });
-
- test.it('Renames a story via a dialog', function() {
- var modal = dr.findElement({ css: '#renameStoryModal' });
-
- dr.findElement({ css: 'button.storyName' }).click();
- dr.findElement({ css: 'button.renameStory' }).click();
- dr.wait(until.elementIsVisible(modal));
- dr.findElement({ css: '#renameStoryModal input.storyName' }).clear();
- dr
- .findElement({ css: '#renameStoryModal input.storyName' })
- .sendKeys('This is different');
- dr.findElement({ css: '#renameStoryModal button[type="submit"]' }).click();
- dr.wait(until.elementIsNotVisible(modal));
- assert(dr.findElement({ css: '.storyNameVal' }).getText())
- .equalTo('This is different');
- });
-
- test.it('Creates a proofing version of the story via a menu item', function() { // jscs:ignore maximumLineLength
- dr.findElement({ css: 'button.storyName' }).click();
- dr.findElement({ css: 'button.proofStory' }).click();
- dr.getAllWindowHandles(function(winds) {
- var found;
-
- for (var i = 0; i < winds.length; i++) {
- if (i == helpers.shortUni) {
- found = true;
- }
- }
-
- assert(found).isTrue();
- });
- });
-
- test.it('Creates a published version of the story via a menu item', function() { // jscs:ignore maximumLineLength
- dr.findElement({ css: 'button.storyName' }).click();
- dr.findElement({ css: 'button.publishStory' }).click();
- });
-
- test.it('Saves changes to story script', function() {
- var modal = dr.findElement({ css: '#scriptEditModal' });
-
- dr.findElement({ css: 'button.storyName' }).click();
- dr.findElement({ css: 'button.editScript' }).click();
- dr.wait(until.elementIsVisible(modal));
- setCMText(dr, '#scriptEditModal', helpers.longUni);
-
- dr.findElement({ css: '#scriptEditModal button.save' }).click();
- dr.wait(until.elementIsNotVisible(modal));
-
- dr.navigate().refresh();
- modal = dr.findElement({ css: '#scriptEditModal' });
-
- dr.findElement({ css: 'button.storyName' }).click();
- dr.findElement({ css: 'button.editScript' }).click();
- dr.wait(until.elementIsVisible(modal));
-
- assert(getCMText(dr, '#scriptEditModal')).equalTo(helpers.longUni);
- });
-
- test.it('Saves changes to story stylesheet', function() {
- var modal = dr.findElement({ css: '#stylesheetEditModal' });
-
- dr.findElement({ css: 'button.storyName' }).click();
- dr.findElement({ css: 'button.editStyle' }).click();
- dr.wait(until.elementIsVisible(modal));
- setCMText(dr, '#stylesheetEditModal', helpers.longUni);
-
- dr.findElement({ css: '#stylesheetEditModal button.save' }).click();
- dr.wait(until.elementIsNotVisible(modal));
-
- dr.navigate().refresh();
- modal = dr.findElement({ css: '#stylesheetEditModal' });
-
- dr.findElement({ css: 'button.storyName' }).click();
- dr.findElement({ css: 'button.editStyle' }).click();
- dr.wait(until.elementIsVisible(modal));
-
- assert(getCMText(dr, '#stylesheetEditModal')).equalTo(helpers.longUni);
- });
-
- test.it('Disables keyboard shortcuts when editing a passage', function() {
- var modal = dr.findElement({ css: '#scriptEditModal' });
-
- dr.findElement({ css: 'button.storyName' }).click();
- dr.findElement({ css: 'button.editScript' }).click();
- dr.wait(until.elementIsVisible(modal));
-
- dr.findElement({ css: '#scriptEditModal' }).sendKeys(key.DELETE);
- dr.findElement({ css: '#scriptEditModal button.save' }).click();
- dr.wait(until.elementIsNotVisible(modal));
-
- dr.findElement({ css: '.passages .passage' });
- });
-
- test.it('Numbers new passages to avoid name conflicts', function() {
- dr.findElement({ css: '.toolbar .addPassage' }).click();
- dr.wait(
- until.elementLocated({ css: '.passages .passage:nth-of-type(2) .title' })
- );
- assert(
- dr.findElement({ css: '.passages .passage:nth-of-type(2) .title' })
- .getText()
- ).equalTo('Untitled Passage 1');
- dr.findElement({ css: '.toolbar .addPassage' }).click();
- dr.wait(
- until.elementLocated({ css: '.passages .passage:nth-of-type(3) .title' })
- );
- assert(
- dr.findElement({ css: '.passages .passage:nth-of-type(3) .title' })
- .getText()
- ).equalTo('Untitled Passage 2');
- });
-
- test.it('Warns a user before navigating away while editing a passage', function() {// jscs:ignore maximumLineLength
- var modal = dr.findElement({ css: '#passageEditModal' });
-
- assert(dr.executeScript('return window.onbeforeunload')).isNull();
- dr.actions()
- .doubleClick(dr.findElement({ css: '.passages .passage' }))
- .perform();
- dr.wait(until.elementIsVisible(modal));
- assert(dr.executeScript('return window.onbeforeunload')).not.isNull();
- dr.findElement({ css: '#passageEditModal button.close' }).click();
- assert(dr.executeScript('return window.onbeforeunload')).isNull();
- });
-
- test.it('Shows accurate story statistics', function() {
- var modal = dr.findElement({ css: '#passageEditModal' });
-
- assert(dr.executeScript('return window.onbeforeunload')).isNull();
- dr.actions()
- .doubleClick(dr.findElement({ css: '.passages .passage' }))
- .perform();
- dr.wait(until.elementIsVisible(modal));
- setCMText(
- dr,
- '#passageEditModal',
- '[[red]] [[green]] [[blue]] The quick brown fox jumps over the lazy dog.'
- );
- dr.findElement({ css: '#passageEditModal button.save' }).click();
- dr.wait(until.elementIsNotVisible(modal));
- dr.findElement({ css: 'body' }).sendKeys(key.END);
- dr.sleep(500); // Accommodate smooth scrolling
-
- var passage = dr.findElement({ css: '.passages .passage:nth-of-type(2)' });
- dr.actions().mouseMove(passage).sendKeys(key.SHIFT).perform();
- dr.findElement({
- css: '.passages .passage:nth-of-type(2) .delete',
- }).click();
- dr.wait(until.stalenessOf(passage));
-
- dr.findElement({ css: 'button.storyName' }).click();
- dr.findElement({ css: 'button.storyStats' }).click();
-
- modal = dr.findElement({ css: '#statsModal' });
- dr.wait(until.elementIsVisible(modal));
- assert(dr.findElement({ css: 'td.charCount' }).getText()).equalTo('145');
- assert(dr.findElement({ css: 'td.wordCount' }).getText()).equalTo('24');
- assert(dr.findElement({ css: 'td.passageCount' }).getText()).equalTo('3');
- assert(dr.findElement({ css: 'td.linkCount' }).getText()).equalTo('3');
- assert(
- dr.findElement({ css: 'td.brokenLinkCount' }).getText()
- ).equalTo('1');
- });
-
- test.it('Generates IFIDs that meet Treaty of Babel standards', function() {
- var modal = dr.findElement({ css: '#statsModal' });
- dr.findElement({ css: 'button.storyName' }).click();
- dr.findElement({ css: 'button.storyStats' }).click();
- dr.wait(until.elementIsVisible(modal));
-
- dr.findElement({ css: '.ifid' }).getText(function(ifid) {
- assert(ifid.length).greaterThan(7);
- assert(ifid.length).lessThan(64);
- assert(ifid).not.matches(/[^0-9A-Z\\-]/);
- });
- });
-
- test.it('Generates IFIDs that are stable', function() {
- var modal = dr.findElement({ css: '#statsModal' });
- dr.findElement({ css: 'button.storyName' }).click();
- dr.findElement({ css: 'button.storyStats' }).click();
- dr.wait(until.elementIsVisible(modal));
-
- dr.findElement({ css: '.ifid' }).getText(function(firstIfid) {
- dr.navigate().refresh();
-
- modal = dr.findElement({ css: '#statsModal' });
- dr.findElement({ css: 'button.storyName' }).click();
- dr.findElement({ css: 'button.storyStats' }).click();
- dr.wait(until.elementIsVisible(modal));
-
- assert(dr.findElement({ css: '.ifid' }).getText()).equalTo(firstIfid);
- });
- });
-});
diff --git a/tests/selenium/story-list.js b/tests/selenium/story-list.js
deleted file mode 100644
index 4eff2a084..000000000
--- a/tests/selenium/story-list.js
+++ /dev/null
@@ -1,146 +0,0 @@
-'use strict';
-var _ = require('underscore');
-var assert = require('selenium-webdriver/testing/assert');
-var firefox = require('selenium-webdriver/firefox');
-var phantomjs = require('selenium-webdriver/phantomjs');
-var test = require('selenium-webdriver/testing');
-var until = require('selenium-webdriver').until;
-var helpers = require('./helpers');
-
-test.describe('StoryListView', function() {
- var dr;
- this.timeout(10000);
-
- test.beforeEach(function() {
- dr = new firefox.Driver();
- dr.get(helpers.testUrl + '#stories');
- });
-
- test.afterEach(function() {
- dr.quit();
- });
-
- test.it('Is on the #stories route', function() {
- assert(dr.isElementPresent({ css: '#regions #storyListView' })).isTrue();
- });
-
- test.it('Shows initial message when no stories are saved', function() {
- dr.wait(until.elementLocated({ css: '.noStories' }))
- .then(function() {
- var noStories = dr.findElement({ css: '.noStories' });
- dr.wait(until.elementIsVisible(noStories));
- });
- });
-
- test.it('Can cancel out of adding a new story', function() {
- var addButton = dr.findElement({ css: '.addStory' });
- var bubble = addButton
- .findElement({ xpath: '../..' })
- .findElement({ css: '.bubble '});
-
- addButton.click();
- dr.wait(until.elementIsVisible(bubble));
- dr.findElement({ css: '.cancelAdd' }).click();
- dr.wait(until.elementIsNotVisible(bubble));
- });
-
- test.it('Does not allow blank story names', function() {
- var addButton = dr.findElement({ css: '.addStory' });
- var bubble = addButton
- .findElement({ xpath: '../..' })
- .findElement({ css: '.bubble '});
-
- addButton.click();
- dr.wait(until.elementIsVisible(bubble));
- dr.findElement({ css: '.add' }).click();
- assert(bubble.isDisplayed()).isTrue();
- });
-
- test.it('Can add a new story', function() {
- helpers.createStory(dr, true);
- dr.wait(until.elementLocated({ css: '.storyName' }));
- assert(
- dr.findElement({ css: '.storyName' }).getText()
- ).equalTo(helpers.shortUni);
- });
-
- test.it('Can play a story', function() {
- helpers.createStory(dr);
- dr.findElement({ css: '.story button[data-bubble="toggle"]' }).click();
- dr.findElement({ css: '.story .menu .play' }).click();
- dr.getAllWindowHandles(function(windows) {
- assert(_.contains(windows, helpers.shortUni)).isTrue();
- });
- });
-
- test.it('Can test a story', function() {
- helpers.createStory(dr);
- dr.findElement({ css: '.story button[data-bubble="toggle"]' }).click();
- dr.findElement({ css: '.story .menu .test' }).click();
- dr.getAllWindowHandles(function(windows) {
- assert(_.contains(windows, helpers.shortUni)).isTrue();
- });
- });
-
- test.it('Can rename a story', function() {
- helpers.createStory(dr);
- dr.findElement({ css: '.story button[data-bubble="toggle"]' }).click();
- dr.findElement({ css: '.story .menu .rename' }).click();
- dr.wait(until.elementLocated({ css: '.prompt input[type="text"]' }));
-
- var promptEl = dr.findElement({ css: '.prompt' });
-
- dr
- .findElement({ css: '.prompt input[type="text"]' })
- .sendKeys('123 ' + helpers.shortUni);
- dr
- .findElement({ css: '.prompt button[data-action="yes"]' })
- .click();
-
- dr.wait(until.elementIsNotVisible(promptEl));
- assert(
- dr.findElement({ css: '.story h2' }).getText()
- ).equalTo('123 ' + helpers.shortUni);
- });
-
- test.it('Can cancel out of deleting a story', function() {
- helpers.createStory(dr);
- dr.findElement({ css: '.story button[data-bubble="toggle"]' }).click();
- dr.findElement({ css: '.story .menu .confirmDelete' }).click();
- dr.wait(until.elementLocated({ css: '.modal.confirm.appear' }));
- var cancelButton = dr.findElement({
- css: '.modal.confirm.appear button.cancel',
- });
-
- dr.wait(until.elementIsVisible(cancelButton)).then(function() {
- var confirmEl = dr.findElement({ css: '.modal.confirm.appear' });
- cancelButton.click();
- dr.wait(until.elementIsNotVisible(confirmEl));
- assert(dr.isElementPresent({ css: '.story h2' })).isTrue();
- });
- });
-
- test.it('Can delete a story', function() {
- helpers.createStory(dr);
- dr.findElement({ css: '.story button[data-bubble="toggle"]' }).click();
- dr.findElement({ css: '.story .menu .confirmDelete' }).click();
- dr.wait(until.elementLocated({ css: '.modal.confirm.appear' }));
- var deleteButton = dr.findElement({
- css: '.modal.confirm.appear button[data-action="yes"]',
- });
-
- dr.wait(until.elementIsVisible(deleteButton)).then(function() {
- var confirmEl = dr.findElement({ css: '.modal.confirm.appear' });
- deleteButton.click();
- dr.wait(until.elementIsNotVisible(confirmEl));
-
- var noStories = dr.findElement({ css: '.noStories' });
- dr.wait(until.elementIsVisible(noStories));
- });
- });
-
- test.it('Can generate an archive', function() {
- helpers.createStory(dr);
- dr.findElement({ css: '.saveArchive' }).click();
- });
-});
diff --git a/tests/selenium/welcome.js b/tests/selenium/welcome.js
deleted file mode 100644
index 3fac4e758..000000000
--- a/tests/selenium/welcome.js
+++ /dev/null
@@ -1,50 +0,0 @@
-'use strict';
-var assert = require('selenium-webdriver/testing/assert');
-var firefox = require('selenium-webdriver/firefox');
-var test = require('selenium-webdriver/testing');
-var until = require('selenium-webdriver').until;
-
-test.describe('WelcomeView', function() {
- var dr;
- var testUrl = 'file://' +
- __dirname.replace('/tests/selenium', '') +
- '/build/standalone/index.html';
- this.timeout(15000);
-
- test.beforeEach(function() {
- dr = new firefox.Driver();
- dr.get(testUrl + '#welcome');
- });
-
- test.afterEach(function() {
- dr.quit();
- });
-
- test.it('Is on the #welcome route', function() {
- assert(dr.isElementPresent({ css: 'div.hi h1' }));
- });
-
- test.it('Can be walked through', function() {
- var helpDiv = dr.findElement({ css: 'div.help' });
- var saveDiv = dr.findElement({ css: 'div.save' });
- var thanksDiv = dr.findElement({ css: 'div.thanks' });
-
- dr.findElement({ css: 'div.hi button' }).click();
- dr.wait(until.elementIsVisible(helpDiv));
- assert(dr.findElement({ css: 'div.help h1' }).getText())
- .equalTo('New here?');
-
- dr.findElement({ css: 'div.help button' }).click();
- dr.wait(until.elementIsVisible(saveDiv));
- assert(dr.findElement({ css: 'div.save h1' }).getText())
- .equalTo('Your work is saved only in your browser.');
-
- dr.findElement({ css: 'div.save button' }).click();
- dr.wait(until.elementIsVisible(thanksDiv));
- assert(dr.findElement({ css: 'div.thanks h1' }).getText())
- .equalTo('That\'s it!');
-
- dr.findElement({ css: 'div.thanks button' }).click();
- dr.wait(until.elementLocated({ css: '#storyListView h1' }));
- });
-});
diff --git a/tests/unit/passage.js b/tests/unit/passage.js
deleted file mode 100644
index ac08a2eb8..000000000
--- a/tests/unit/passage.js
+++ /dev/null
@@ -1,196 +0,0 @@
-'use strict';
-var Passage = require('../../src/data/models/passage');
-var Story = require('../../src/data/models/passage');
-var assert = require('assert');
-
-describe('Passage', function()
-{
- var story;
- var p;
-
- beforeEach(function()
- {
- p = new Passage();
- });
-
- describe('excerpt()', function() {
- it('returns the passage text if it has under 101 characters', function() {
- var text = Array(101)+'';
- p.set('text', text);
- assert.equal(p.excerpt(), text);
- });
- it('HTML-escapes returned passage text', function() {
- var text = "";
- p.set('text', text);
- assert.equal(p.excerpt(), "<b>");
- });
- it('returns 99 characters of passage text, plus …, if it has 101 or more characters', function() {
- var text = Array(102)+'';
- p.set('text', text);
- assert.equal(p.excerpt(), text.slice(0,99) + "…");
- })
- });
-
- describe('publish()', function() {
- it('outputs HTML for the passage', function() {
- function expected(pid, name, tags, top, left, text) {
- return '' + text + '\n';
- }
- var props = {
- name: "Foo",
- tags: ['bar', 'baz', 'qux'],
- top: 0,
- left: 0,
- text: "grault garply corge"
- };
- p.set(props);
- assert.equal(p.publish(5), expected(5, props.name, props.tags, props.top, props.left, props.text));
-
- props = {
- name: "",
- tags: ['>','"'],
- top: 15385,
- left: 22408,
- text: ""
- };
- p.set(props);
- assert.equal(p.publish(8), expected(8, props.name, [">","""], props.top, props.left,
- "</tw-passagedata>"));
- });
- });
-
- describe('matches()', function() {
- beforeEach(function() {
- p.set('name', "foo bar baz qux");
- p.set('text', 'garply')
- });
- it('returns true if the passage name matches the passed-in RegExp', function() {
- assert(p.matches(/r\s+b/));
- assert(!p.matches(/w/));
- });
- it('returns true if the passage text, unescaped, matches the passed-in RegExp', function() {
- assert(p.matches(/rp/));
- assert(p.matches(//));
- assert(!p.matches(/w/));
- });
- });
-
- describe('links()', function()
- {
-
- it('parses [[simple links]]', function()
- {
- p.set('text', '[[link]]');
- var links = p.links();
- assert.equal(links.length,1);
- assert.equal(links[0], 'link');
- });
-
- it('parses [[pipe|links]]', function()
- {
- p.set('text', '[[display|link]]');
- var links = p.links();
- assert.equal(links.length, 1);
- assert.equal(links[0], 'link');
- });
-
- it('parses [[arrow->links]]', function()
- {
- p.set('text', '[[display->link]]');
- var links = p.links();
- assert.equal(links.length, 1);
- assert.equal(links[0], 'link');
- });
-
- it('parses [[backarrow<-links]]', function()
- {
- p.set('text', '[[link<-display]]');
- var links = p.links();
- assert.equal(links.length, 1);
- assert.equal(links[0],'link');
- });
-
- it('parses [[simple links][setter]] while ignoring setter component', function()
- {
- p.set('text', '[[link][setter]]');
- var links = p.links();
- assert.equal(links.length, 1);
- assert.equal(links[0],'link');
- });
-
- it('parses [[pipe|links][setter]] while ignoring setter component', function()
- {
- p.set('text', '[[display|link][setter]]');
- var links = p.links();
- assert.equal(links.length, 1);
- assert.equal(links[0], 'link');
- });
-
- it('parses [[arrow->links][setter]] while ignoring setter component', function()
- {
- p.set('text', '[[display->link][setter]]');
- var links = p.links();
- assert.equal(links.length, 1);
- assert.equal(links[0], 'link');
- });
-
- it('parses [[backarrow<-links][setter]] while ignoring setter component', function()
- {
- p.set('text', '[[link<-display][setter]]');
- var links = p.links();
- assert.equal(links.length, 1);
- assert.equal(links[0], 'link');
- });
-
- it('parses [[simple links][]] while ignoring empty setter component', function()
- {
- p.set('text', '[[link][]]');
- var links = p.links();
- assert.equal(links.length, 1);
- assert.equal(links[0], 'link');
- });
-
- it('parses [[pipe|links][]] while ignoring empty setter component', function()
- {
- p.set('text', '[[display|link][]]');
- var links = p.links();
- assert.equal(links.length, 1);
- assert.equal(links[0], 'link');
- });
-
- it('parses [[arrow->links][]] while ignoring empty setter component', function()
- {
- p.set('text', '[[display->link][]]');
- var links = p.links();
- assert.equal(links.length, 1);
- assert.equal(links[0], 'link');
- });
-
- it('parses [[backarrow<-links][]] while ignoring empty setter component', function()
- {
- p.set('text', '[[link<-display][]]');
- var links = p.links();
- assert.equal(links.length, 1);
- assert.equal(links[0], 'link');
- });
-
- it('ignores [[]]', function()
- {
- p.set('text', '[[]]');
- assert.equal(p.links().length, 0);
- });
-
- it('ignores [[][]]', function()
- {
- p.set('text', '[[][]]');
- assert.equal(p.links().length, 0);
- });
-
- it('ignores [[][setter]]', function()
- {
- p.set('text', '[[][setter]]');
- assert.equal(p.links().length, 0);
- });
- });
-});