diff --git a/.travis.yml b/.travis.yml index 733eea750..f7241c8c1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,9 +6,8 @@ before_script: - npm --version - npm install -g grunt-cli script: -- grunt test --verbose +- grunt test-travis --verbose - if [[ $TRAVIS_PULL_REQUEST == "false" ]]; then grunt saucelabs-test; fi -- grunt karma:travis - grunt coveralls:travis before_deploy: - npm install diff --git a/Gruntfile.js b/Gruntfile.js index 07e53860f..739047b6e 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -17,6 +17,51 @@ module.exports = function (grunt) { return data; }; + var customLaunchers = { + 'SL_IE8': { + base: 'SauceLabs', + browserName: 'internet explorer', + version: '8.0', + platform: 'windows XP' + }, + 'SL_IE9': { + base: 'SauceLabs', + browserName: 'internet explorer', + version: '9.0', + platform: 'windows 7' + }, + 'SL_IE10': { + base: 'SauceLabs', + browserName: 'internet explorer', + version: '10.0', + platform: 'windows 8' + }, + 'SL_IE11': { + base: 'SauceLabs', + browserName: 'internet explorer', + version: '11.0', + platform: 'windows 8.1' + }, + 'SL_CHROME': { + base: 'SauceLabs', + browserName: 'chrome', + version: '43', + platform: 'windows 8' + }, + 'SL_FIREFOX': { + base: 'SauceLabs', + browserName: 'firefox', + version: '38', +  platform: 'windows 8' + }, + 'SL_SAFARI': { + base: 'SauceLabs', + browserName: 'safari', +  version: '8.0', +  platform: 'OS X 10.10' + } + }; + grunt.initConfig({ // package File pkg: grunt.file.readJSON('package.json'), @@ -132,55 +177,31 @@ module.exports = function (grunt) { } }, - 'saucelabs-qunit': { - 'all': { - options: { - urls: ['http://localhost:3000/test/unit.html'], - build: process.env.TRAVIS_BUILD_NUMBER, - tags: [process.env.TRAVIS_BRANCH, process.env.TRAVIS_PULL_REQUEST], - browsers: [{ - browserName: 'internet explorer', - version: '8.0', - platform: 'windows XP' - }, { - browserName: 'internet explorer', - version: '9.0', - platform: 'windows 7' - }, { - browserName: 'internet explorer', - version: '10.0', - platform: 'windows 8' - }, { - browserName: 'internet explorer', - version: '11.0', - platform: 'windows 8.1' - }, { - browserName: 'chrome', - version: '43', - platform: 'windows 8' - }, { -     browserName: 'firefox', -     version: '38', -     platform: 'windows 8' -   }, { -     browserName: 'safari', -     version: '8.0', -     platform: 'OS X 10.10' -   }], - testname: 'unit test for summernote', - 'public': 'public' - } - } - }, - karma: { options: { configFile: './test/karma.conf.js' }, + all: { + // Chrome, ChromeCanary, Firefox, Opera, Safari, PhantomJS, IE + browsers: ['PhantomJS'], + reporters: ['progress'] + }, travis: { singleRun: true, browsers: ['PhantomJS'], reporters: ['progress', 'coverage'] + }, + saucelabs: { + reporters: ['saucelabs'], + sauceLabs: { + testName: 'unit tests for summernote', + build: process.env.TRAVIS_BUILD_NUMBER, + tags: [process.env.TRAVIS_BRANCH, process.env.TRAVIS_PULL_REQUEST] + }, + captureTimeout: 120000, + customLaunchers: customLaunchers, + browsers: Object.keys(customLaunchers), + singleRun: true } }, @@ -204,10 +225,13 @@ module.exports = function (grunt) { grunt.registerTask('server', ['connect', 'watch']); // test: unit test on test folder - grunt.registerTask('test', ['jshint', 'qunit']); + grunt.registerTask('test', ['jshint', 'karma:all']); + + // test: unit test on travis + grunt.registerTask('test-travis', ['jshint', 'karma:travis']); // test: saucelabs test - grunt.registerTask('saucelabs-test', ['connect', 'saucelabs-qunit']); + grunt.registerTask('saucelabs-test', ['karma:saucelabs']); // dist: make dist files grunt.registerTask('dist', ['build', 'test', 'uglify', 'recess', 'compress']); diff --git a/README.md b/README.md index bc1ac2bdc..837cb668d 100644 --- a/README.md +++ b/README.md @@ -155,10 +155,24 @@ grunt dist At this point, you should now have a `build/` directory populated with everything you need to use summernote. #### test summernote -run tests with PhantomJS +run tests with Karma and PhantomJS ```bash grunt test ``` +If you want run tests on other browser, +change the values for `broswers` properties in `Gruntfile.js`. + +``` +karma: { + all: { + browsers: ['PhantomJS'], + reporters: ['progress'] + } +} + +``` +You can use `Chrome`, `ChromeCanary`, `Firefox`, `Opera`, `Safari`, `PhantomJS` and `IE` beside `PhantomJS`. +Once you run `grunt test`, it will watch all javascript file. Therefore karma run tests every time you chage code. #### start local server for developing summernote. run local server with connect and watch. diff --git a/package.json b/package.json index d002b73da..32cc2e5e2 100644 --- a/package.json +++ b/package.json @@ -18,11 +18,11 @@ }, "main": "dist/summernote.js", "devDependencies": { + "chai": "^3.2.0", "grunt": "*", "grunt-contrib-compress": "*", "grunt-contrib-connect": "*", "grunt-contrib-jshint": "0.7.2", - "grunt-contrib-qunit": "0.5.2", "grunt-contrib-uglify": "~0.2.2", "grunt-contrib-watch": "*", "grunt-coveralls": "^1.0.0", @@ -31,10 +31,16 @@ "grunt-recess": "*", "grunt-saucelabs": "*", "karma": "^0.13.3", + "karma-chrome-launcher": "^0.2.0", "karma-coverage": "^0.4.2", + "karma-firefox-launcher": "^0.1.6", + "karma-ie-launcher": "^0.2.0", + "karma-mocha": "^0.2.0", + "karma-opera-launcher": "^0.2.0", "karma-phantomjs-launcher": "^0.2.0", - "karma-qunit": "^0.1.5", "karma-requirejs": "^0.2.2", + "karma-safari-launcher": "^0.1.1", + "karma-sauce-launcher": "^0.2.14", "load-grunt-tasks": "0.2.0", "open": "0.0.4", "phantomjs": "^1.9.17", diff --git a/test/.jshintrc b/test/.jshintrc new file mode 100644 index 000000000..1537a9d4b --- /dev/null +++ b/test/.jshintrc @@ -0,0 +1,42 @@ +{ + "camelcase": true, + "curly": true, + "eqeqeq": true, + "immed": true, + "indent": 2, + "newcap": true, + "noarg": true, + "quotmark": "single", + "undef": true, + "unused": true, + "trailing": true, + "white": true, + "maxparams": 20, + "maxdepth": 5, + "maxstatements": 300, + "maxlen": 140, + "evil": true, + "browser": true, + "devel": true, + "jquery": true, + "node": true, + "worker": true, + "expr": true, + "predef": [ + "define", + "describe", + "before", + "beforeEach", + "after", + "afterEach", + "it" + ], + "globals": { + "JSON": true, + "define": true, + "test": true, + "ok": true, + "equal": true, + "deepEqual": true + } +} diff --git a/test/karma.conf.js b/test/karma.conf.js index 671a6c05f..68f2513ab 100644 --- a/test/karma.conf.js +++ b/test/karma.conf.js @@ -4,7 +4,7 @@ module.exports = function (config) { config.set({ basePath: '../', - frameworks: ['requirejs', 'qunit'], + frameworks: ['requirejs', 'mocha'], exclude: [], reporters: ['progress', 'coverage'], port: 9876, @@ -14,9 +14,11 @@ module.exports = function (config) { files: [ {pattern: 'src/js/**/*.js', included: false}, {pattern: 'test/**/*.js', included: false}, + {pattern: 'node_modules/chai/*.js', included: false}, 'test/test-main.js' ], - browsers: ['PhantomJS'], + // Chrome, ChromeCanary, Firefox, Opera, Safari, PhantomJS, IE + browsers: ['Chrome'], captureTimeout: 60000, singleRun: false, preprocessors: { 'src/js/**/!(app|intro|outro).js': 'coverage' }, diff --git a/test/test-main.js b/test/test-main.js index 8bb822dae..a07d73c71 100644 --- a/test/test-main.js +++ b/test/test-main.js @@ -12,7 +12,9 @@ requirejs.config({ paths: { jquery: '../../test/libs/jquery-1.9.1.min', - CodeMirror: '../../test/libs/codemirror' + CodeMirror: '../../test/libs/codemirror', + chai: '../../node_modules/chai/chai', + helper: '../../test/test-util' }, shim: { @@ -28,80 +30,5 @@ requirejs.config({ // ask Require.js to load these files (all our tests) deps: tests, - callback: function () { - require([ - 'summernote/core/agent', - '../../test/unit/func.spec', - '../../test/unit/key.spec', - '../../test/unit/dom.spec', - '../../test/unit/list.spec', - '../../test/unit/range.spec', - '../../test/unit/style.spec' - ], function (agent, funcSpec, keySpec, domSpec, listSpec, rangeSpec, styleSpec) { - - var helper = { - equalsToUpperCase: function (actual, expected, comment) { - actual = actual.toUpperCase(); - expected = expected.toUpperCase(); - - // [workaround] IE8-10 use   instead of bogus br - if (agent.isMSIE && agent.browserVersion < 11) { - expected = expected.replace(/
/g, '&NBSP;'); - } - - // [workaround] IE8 actual markup has newline between tags - if (agent.isMSIE && agent.browserVersion < 9) { - actual = actual.replace(/\r\n/g, ''); - } - - equal(actual, expected, comment); - } - }; - - module('unit/func'); - funcSpec(helper); - module('unit/key'); - keySpec(helper); - module('unit/dom'); - domSpec(helper); - module('unit/list'); - listSpec(helper); - module('unit/range'); - rangeSpec(helper); - module('unit/styleSpec'); - styleSpec(); - }); - - - /* jshint ignore:start */ - var log = []; - QUnit.done(function (test_results) { - var tests = []; - for(var i = 0, len = log.length; i < len; i++) { - var details = log[i]; - tests.push({ - name: details.name, - result: details.result, - expected: details.expected, - actual: details.actual, - source: details.source - }); - } - test_results.tests = tests; - - window.global_test_results = test_results; - }); - QUnit.testStart(function(testDetails){ - QUnit.log(function(details){ - if (!details.result) { - details.name = testDetails.name; - log.push(details); - } - }); - }); - /* jshint ignore:end */ - - // start test run, once Require.js is done - window.__karma__.start(); - } + callback: window.__karma__.start }); diff --git a/test/test-util.js b/test/test-util.js new file mode 100644 index 000000000..e19c2376f --- /dev/null +++ b/test/test-util.js @@ -0,0 +1,22 @@ +define([ + 'summernote/core/agent' +], function (agent) { + return { + equalsToUpperCase: function (actual, expected, assert) { + actual = actual.toUpperCase(); + expected = expected.toUpperCase(); + + // [workaround] IE8-10 use   instead of bogus br + if (agent.isMSIE && agent.browserVersion < 11) { + expected = expected.replace(/
/g, '&NBSP;'); + } + + // [workaround] IE8 actual markup has newline between tags + if (agent.isMSIE && agent.browserVersion < 9) { + actual = actual.replace(/\r\n/g, ''); + } + + assert(actual).to.equal(expected); + } + }; +}); diff --git a/test/unit.html b/test/unit.html deleted file mode 100644 index aa341658a..000000000 --- a/test/unit.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - summernote's unit test - - - -
-
- - - - - diff --git a/test/unit.js b/test/unit.js deleted file mode 100644 index a741e21a7..000000000 --- a/test/unit.js +++ /dev/null @@ -1,94 +0,0 @@ -/** - * test.js - * (c) 2013~ Alan Hong - * summernote may be freely distributed under the MIT license./ - */ -require.config({ - baseUrl: '../src/js', - paths: { - jquery: '../../test/libs/jquery-1.9.1.min', - CodeMirror: '../../test/libs/codemirror' - }, - shim: { - CodeMirror: { exports: 'CodeMirror' } - }, - packages: [{ - name: 'summernote', - location: './', - main: 'summernote' - }] -}); - -require([ - 'summernote/core/agent', - '../../test/unit/func.spec', - '../../test/unit/key.spec', - '../../test/unit/dom.spec', - '../../test/unit/list.spec', - '../../test/unit/range.spec', - '../../test/unit/style.spec' -], function (agent, funcSpec, keySpec, domSpec, listSpec, rangeSpec, styleSpec) { - /* global QUnit */ - QUnit.start(); - - var helper = { - equalsToUpperCase: function (actual, expected, comment) { - actual = actual.toUpperCase(); - expected = expected.toUpperCase(); - - // [workaround] IE8-10 use   instead of bogus br - if (agent.isMSIE && agent.browserVersion < 11) { - expected = expected.replace(/
/g, '&NBSP;'); - } - - // [workaround] IE8 actual markup has newline between tags - if (agent.isMSIE && agent.browserVersion < 9) { - actual = actual.replace(/\r\n/g, ''); - } - - equal(actual, expected, comment); - } - }; - - module('unit/func'); - funcSpec(helper); - module('unit/key'); - keySpec(helper); - module('unit/dom'); - domSpec(helper); - module('unit/list'); - listSpec(helper); - module('unit/range'); - rangeSpec(helper); - module('unit/styleSpec'); - styleSpec(); -}); - - -/* jshint ignore:start */ -var log = []; -QUnit.done(function (test_results) { - var tests = []; - for(var i = 0, len = log.length; i < len; i++) { - var details = log[i]; - tests.push({ - name: details.name, - result: details.result, - expected: details.expected, - actual: details.actual, - source: details.source - }); - } - test_results.tests = tests; - - window.global_test_results = test_results; -}); -QUnit.testStart(function(testDetails){ - QUnit.log(function(details){ - if (!details.result) { - details.name = testDetails.name; - log.push(details); - } - }); -}); -/* jshint ignore:end */ diff --git a/test/unit/dom.spec.js b/test/unit/dom.spec.js index 2f5d3ec43..fbdf1919b 100644 --- a/test/unit/dom.spec.js +++ b/test/unit/dom.spec.js @@ -4,12 +4,17 @@ * summernote may be freely distributed under the MIT license./ */ define([ + 'chai', + 'helper', 'jquery', 'summernote/core/dom', 'summernote/core/func' -], function ($, dom, func) { - return function (helper) { +], function (chai, helper, $, dom, func) { + 'use strict'; + var expect = chai.expect; + + describe('core.dom', function () { var editorMarkup = [ '
', '
', @@ -25,310 +30,386 @@ define([ '
' ].join(''); - test('dom.buildLayoutInfo', function () { - var $editor = $(editorMarkup); - var layoutInfo = dom.buildLayoutInfo($editor); - - deepEqual({ - editor: 'note-editor', - dropzone: 'note-dropzone', - toolbar: 'note-toolbar', - editable: 'note-editable', - codable: 'note-codable', - statusbar: 'note-statusbar', - popover: 'note-popover', - handle: 'note-handle', - dialog: 'note-dialog' - }, { - editor: layoutInfo.editor().attr('class'), - dropzone: layoutInfo.dropzone().attr('class'), - toolbar: layoutInfo.toolbar().attr('class'), - editable: layoutInfo.editable().attr('class'), - codable: layoutInfo.codable().attr('class'), - statusbar: layoutInfo.statusbar().attr('class'), - popover: layoutInfo.popover().attr('class'), - handle: layoutInfo.handle().attr('class'), - dialog: layoutInfo.dialog().attr('class') - }, 'should returns layoutInfo'); + describe('buildLayoutInfo', function () { + it('should return layoutInfo', function () { + var $editor = $(editorMarkup); + var layoutInfo = dom.buildLayoutInfo($editor); + + var layout = { + editor: layoutInfo.editor().attr('class'), + dropzone: layoutInfo.dropzone().attr('class'), + toolbar: layoutInfo.toolbar().attr('class'), + editable: layoutInfo.editable().attr('class'), + codable: layoutInfo.codable().attr('class'), + statusbar: layoutInfo.statusbar().attr('class'), + popover: layoutInfo.popover().attr('class'), + handle: layoutInfo.handle().attr('class'), + dialog: layoutInfo.dialog().attr('class') + }; + expect(layout).to.deep.equal({ + editor: 'note-editor', + dropzone: 'note-dropzone', + toolbar: 'note-toolbar', + editable: 'note-editable', + codable: 'note-codable', + statusbar: 'note-statusbar', + popover: 'note-popover', + handle: 'note-handle', + dialog: 'note-dialog' + }); + }); }); - test('dom.makeLayoutInfo', function () { - var $editor = $(editorMarkup); - var $editable = $editor.find('.note-editable'); - var layoutInfo = dom.makeLayoutInfo($editable); - - deepEqual({ - editor: 'note-editor', - dropzone: 'note-dropzone', - toolbar: 'note-toolbar', - editable: 'note-editable', - codable: 'note-codable', - statusbar: 'note-statusbar', - popover: 'note-popover', - handle: 'note-handle', - dialog: 'note-dialog' - }, { - editor: layoutInfo.editor().attr('class'), - dropzone: layoutInfo.dropzone().attr('class'), - toolbar: layoutInfo.toolbar().attr('class'), - editable: layoutInfo.editable().attr('class'), - codable: layoutInfo.codable().attr('class'), - statusbar: layoutInfo.statusbar().attr('class'), - popover: layoutInfo.popover().attr('class'), - handle: layoutInfo.handle().attr('class'), - dialog: layoutInfo.dialog().attr('class') - }, 'should returns layoutInfo'); - - equal(dom.makeLayoutInfo($('
')), null, 'should returns null'); + describe('makeLayoutInfo', function () { + it('should return layoutInfo', function () { + var $editor = $(editorMarkup); + var $editable = $editor.find('.note-editable'); + var layoutInfo = dom.makeLayoutInfo($editable); + + var layout = { + editor: layoutInfo.editor().attr('class'), + dropzone: layoutInfo.dropzone().attr('class'), + toolbar: layoutInfo.toolbar().attr('class'), + editable: layoutInfo.editable().attr('class'), + codable: layoutInfo.codable().attr('class'), + statusbar: layoutInfo.statusbar().attr('class'), + popover: layoutInfo.popover().attr('class'), + handle: layoutInfo.handle().attr('class'), + dialog: layoutInfo.dialog().attr('class') + }; + + expect(layout).to.deep.equal({ + editor: 'note-editor', + dropzone: 'note-dropzone', + toolbar: 'note-toolbar', + editable: 'note-editable', + codable: 'note-codable', + statusbar: 'note-statusbar', + popover: 'note-popover', + handle: 'note-handle', + dialog: 'note-dialog' + }); + }); + + it('should return null if there is no editor area', function () { + expect(dom.makeLayoutInfo($('
'))).to.be.null; + }); }); - test('dom.ancestor', function () { + describe('ancestor', function () { var $cont, $b, txtB; - - // basic case - $cont = $('
busi
'); //busi - $b = $cont.find('b'); - txtB = $b[0].firstChild; + before(function () { + // basic case + $cont = $('
busi
'); //busi + $b = $cont.find('b'); + txtB = $b[0].firstChild; + }); + + it('should find ancestor B', function () { + expect(dom.ancestor(txtB, dom.isB)).to.deep.equal($b[0]); + }); - equal(dom.ancestor(txtB, dom.isB), $b[0], 'find ancestor B'); - equal(dom.ancestor(txtB, dom.isDiv), $cont[0], 'find ancestor DIV'); + it('should find ancestor DIV', function () { + expect(dom.ancestor(txtB, dom.isDiv)).to.deep.equal($cont[0]); + }); - equal(dom.ancestor(txtB, dom.isU), null, 'find ancestor U: null'); + it('should return null when finding ancestor U does not exist', function () { + expect(dom.ancestor(txtB, dom.isU)).to.be.null; + }); - // keep boundary - $cont = $(''); //b - txtB = $cont.find('b')[0].firstChild; - equal(dom.ancestor(txtB, dom.isLi), null, 'find paragraph ancestor outside note-editable: null'); + it('should return null when finding paragraph ancestor outsider note-editable', function () { + expect(dom.ancestor(txtB, dom.isLi)).to.be.null; + }); }); - test('dom.listAncestor', function () { + describe('listAncestor', function () { var $cont, $b, $u, $s, $i; + before(function () { + $cont = $('
b
'); //busi + $b = $cont.find('b'); + $u = $cont.find('u'); + $s = $cont.find('s'); + $i = $cont.find('i'); + }); - $cont = $('
b
'); //busi - $b = $cont.find('b'); - $u = $cont.find('u'); - $s = $cont.find('s'); - $i = $cont.find('i'); - - deepEqual(dom.listAncestor($b[0], function (node) { - return node === $i[0]; - }), [$b[0], $u[0], $s[0], $i[0]], 'listAncestor from b to i should returns [$b, $u, $s, $i]'); - - deepEqual(dom.listAncestor($u[0], function (node) { - return node === $s[0]; - }), [$u[0], $s[0]], 'listAncestor from u to s should returns [$u, $s]'); + it('should return [$b, $u, $s, $i] from b to i', function () { + var result = dom.listAncestor($b[0], function (node) { return node === $i[0]; }); + expect(result).to.deep.equal([$b[0], $u[0], $s[0], $i[0]]); + }); + it('should return [$u, $s] from u to s', function () { + var result = dom.listAncestor($u[0], function (node) { return node === $s[0]; }); + expect(result).to.deep.equal([$u[0], $s[0]]); + }); }); - test('dom.listDescendant', function () { + describe('listDescendant', function () { var $cont, $b, $u, $s, $i; + before(function () { + $cont = $('
'); //busi + $b = $cont.find('b'); + $u = $cont.find('u'); + $s = $cont.find('s'); + $i = $cont.find('i'); + }); - $cont = $('
'); //busi - $b = $cont.find('b'); - $u = $cont.find('u'); - $s = $cont.find('s'); - $i = $cont.find('i'); - - deepEqual( - dom.listDescendant($cont[0]), [$b[0], $u[0], $s[0], $i[0]], - 'listDescendant($cont) should returns [$b, $u, $s, $i]' - ); + it('should return an array of descendant elements', function () { + expect(dom.listDescendant($cont[0])).to.deep.equal([$b[0], $u[0], $s[0], $i[0]]); + }); - deepEqual( - dom.listDescendant($cont[0], function (node) { + it('should filter an array of descendant elements', function () { + var result = dom.listDescendant($cont[0], function (node) { return node.nodeName === 'B' || node.nodeName === 'S'; - }), - [$b[0], $s[0]], 'listDescendant($cont, pred(b,s) should returns [$b, $s]' - ); - + }); + expect(result).to.deep.equal([$b[0], $s[0]]); + }); }); - test('dom.commonAncestor', function () { + describe('commonAncestor', function () { var $cont, $span, $div, $b, $u, $s, $i; + before(function () { + $cont = $('
busi
'); + $span = $cont.find('span'); + $div = $cont.find('div'); + $b = $cont.find('b'); + $u = $cont.find('u'); + $s = $cont.find('s'); + $i = $cont.find('i'); + }); - $cont = $('
busi
'); - $span = $cont.find('span'); - $div = $cont.find('div'); - $b = $cont.find('b'); - $u = $cont.find('u'); - $s = $cont.find('s'); - $i = $cont.find('i'); + it('should return a common element in ancestors', function () { + expect(dom.commonAncestor($b[0], $u[0])).to.deep.equal($span[0]); + }); - equal(dom.commonAncestor($b[0], $u[0]), $span[0], 'common(b, u) => span'); - equal(dom.commonAncestor($b[0], $s[0]), $div[0], 'common(b, s) => div'); + it('should return a common element in ancestors even if they have same nodeName', function () { + expect(dom.commonAncestor($b[0], $s[0])).to.deep.equal($div[0]); + }); }); - test('dom.listNext', function () { + describe('listNext', function () { var $cont, $b, $u, $s, $i; + before(function () { + $cont = $('
busi
'); //busi + $b = $cont.find('b'); + $u = $cont.find('u'); + $s = $cont.find('s'); + $i = $cont.find('i'); + }); - $cont = $('
busi
'); //busi - $b = $cont.find('b'); - $u = $cont.find('u'); - $s = $cont.find('s'); - $i = $cont.find('i'); + it('should return an array of next sibling elements including itself', function () { + expect(dom.listNext($u[0])).to.deep.equal([$u[0], $s[0], $i[0]]); + }); - deepEqual(dom.listNext($u[0]), [$u[0], $s[0], $i[0]], 'with no pred'); - deepEqual(dom.listNext($i[0]), [$i[0]], 'last item with no pred'); + it('should return itself if there are no next sibling', function () { + expect(dom.listNext($i[0])).to.deep.equal([$i[0]]); + }); - deepEqual(dom.listNext($s[0], func.eq($i[0])), [$s[0]], 's to i'); + it('should restun an array of next sibling elements before predicate is true', function () { + expect(dom.listNext($s[0], func.eq($i[0]))).to.deep.equal([$s[0]]); + }); }); - test('dom.listPrev', function () { + describe('listPrev', function () { var $cont, $b, $u, $s, $i; + before(function () { + $cont = $('
busi
'); //busi + $b = $cont.find('b'); + $u = $cont.find('u'); + $s = $cont.find('s'); + $i = $cont.find('i'); + }); - $cont = $('
busi
'); //busi - $b = $cont.find('b'); - $u = $cont.find('u'); - $s = $cont.find('s'); - $i = $cont.find('i'); + it('should return an array of previous sibling elements including itself', function () { + expect(dom.listPrev($s[0])).to.deep.equal([$s[0], $u[0], $b[0]]); + }); - deepEqual(dom.listPrev($s[0]), [$s[0], $u[0], $b[0]], 'with no pred'); - deepEqual(dom.listPrev($b[0]), [$b[0]], 'first item with no pred'); + it('should return itself if there are no previous sibling', function () { + expect(dom.listPrev($b[0])).to.deep.equal([$b[0]]); + }); - deepEqual(dom.listPrev($i[0], func.eq($s[0])), [$i[0]], 'i to s'); + it('should return an array of previous sibling elements before predicate is true', function () { + expect(dom.listPrev($i[0], func.eq($s[0]))).to.deep.equal([$i[0]]); + }); }); - test('dom.position', function () { + describe('position', function () { var $cont, $b, $u, $s, $i; + before(function () { + $cont = $('
busi
'); //busi + $b = $cont.find('b'); + $u = $cont.find('u'); + $s = $cont.find('s'); + $i = $cont.find('i'); + }); - $cont = $('
busi
'); //busi - $b = $cont.find('b'); - $u = $cont.find('u'); - $s = $cont.find('s'); - $i = $cont.find('i'); - - equal(dom.position($b[0]), 0, 'should b return zero'); - equal(dom.position($u[0]), 1, 'should u return one'); - equal(dom.position($s[0]), 2, 'should s return three'); - equal(dom.position($i[0]), 3, 'should i return four'); + it('should return the positon of element', function () { + expect(dom.position($b[0])).to.be.equal(0); + expect(dom.position($u[0])).to.be.equal(1); + expect(dom.position($s[0])).to.be.equal(2); + expect(dom.position($i[0])).to.be.equal(3); + }); - equal(dom.position($b[0].firstChild), 0, 'should text in b return zero'); + it('should return position 0 for text node in b', function () { + expect(dom.position($b[0].firstChild)).to.be.equal(0); + }); }); - test('dom.makeOffsetPath', function () { + describe('makeOffsetPath', function () { var $cont, $b, $u, $s, $i; + before(function () { + $cont = $('
busi
'); //busi + $b = $cont.find('b'); + $u = $cont.find('u'); + $s = $cont.find('s'); + $i = $cont.find('i'); + }); - $cont = $('
busi
'); //busi - $b = $cont.find('b'); - $u = $cont.find('u'); - $s = $cont.find('s'); - $i = $cont.find('i'); - - deepEqual(dom.makeOffsetPath($cont[0], $cont[0]), [], 'should return empty list'); + it('should return empty array if two elements are same', function () { + expect(dom.makeOffsetPath($cont[0], $cont[0])).to.deep.equal([]); + }); - deepEqual(dom.makeOffsetPath($cont[0], $b[0]), [0], 'should return [0]'); - deepEqual(dom.makeOffsetPath($cont[0], $b[0].firstChild), [0, 0], 'should return [0, 0]'); + it('should return offset path array between two elements #1', function () { + expect(dom.makeOffsetPath($cont[0], $b[0])).to.deep.equal([0]); + expect(dom.makeOffsetPath($cont[0], $b[0].firstChild)).to.deep.equal([0, 0]); + }); - deepEqual(dom.makeOffsetPath($cont[0], $u[0]), [1], 'shuold return [1]'); - deepEqual(dom.makeOffsetPath($cont[0], $u[0].firstChild), [1, 0], 'shuold return [1, 0]'); + it('should return offset path array between two elements #2', function () { + expect(dom.makeOffsetPath($cont[0], $u[0])).to.deep.equal([1]); + expect(dom.makeOffsetPath($cont[0], $u[0].firstChild)).to.deep.equal([1, 0]); + }); - deepEqual(dom.makeOffsetPath($cont[0], $s[0]), [2], 'shuold return [2]'); - deepEqual(dom.makeOffsetPath($cont[0], $s[0].firstChild), [2, 0], 'shuold return [2, 0]'); + it('should return offset path array between two elements #3', function () { + expect(dom.makeOffsetPath($cont[0], $s[0])).to.deep.equal([2]); + expect(dom.makeOffsetPath($cont[0], $s[0].firstChild)).to.deep.equal([2, 0]); + }); - deepEqual(dom.makeOffsetPath($cont[0], $i[0]), [3], 'shuold return [3]'); - deepEqual(dom.makeOffsetPath($cont[0], $i[0].firstChild), [3, 0], 'shuold return [3, 0]'); + it('should return offset path array between two elements #2', function () { + expect(dom.makeOffsetPath($cont[0], $i[0])).to.deep.equal([3]); + expect(dom.makeOffsetPath($cont[0], $i[0].firstChild)).to.deep.equal([3, 0]); + }); }); - test('dom.fromOffsetPath', function () { + describe('fromOffsetPath', function () { var $cont, $b, $u, $s, $i; + before(function () { + $cont = $('
busi
'); //busi + $b = $cont.find('b'); + $u = $cont.find('u'); + $s = $cont.find('s'); + $i = $cont.find('i'); + }); - $cont = $('
busi
'); //busi - $b = $cont.find('b'); - $u = $cont.find('u'); - $s = $cont.find('s'); - $i = $cont.find('i'); - - var cont = $cont[0]; - $.each([$b[0], $u[0], $s[0], $i[0]], function (idx, node) { - equal(dom.fromOffsetPath(cont, dom.makeOffsetPath(cont, node)), node); - var child = node.firstChild; - equal(dom.fromOffsetPath(cont, dom.makeOffsetPath(cont, child)), child); + it('should return the element by offsetPath', function () { + var cont = $cont[0]; + $.each([$b[0], $u[0], $s[0], $i[0]], function (idx, node) { + expect(dom.fromOffsetPath(cont, dom.makeOffsetPath(cont, node))).to.deep.equal(node); + var child = node.firstChild; + expect(dom.fromOffsetPath(cont, dom.makeOffsetPath(cont, child))).to.deep.equal(child); + }); }); }); - test('dom.splitTree', function () { - var $busi, $para, $cont, $b, $u, $s, $i, $span; - $busi = $('

bustrikei

'); //busi - - // 01. element pivot case - $para = $busi.clone().find('p'); - $u = $para.find('u'); - dom.splitTree($para[0], {node: $u[0], offset: 0 }); - helper.equalsToUpperCase($para.html(), 'b
', 'splitBy u tag with offset 0'); - helper.equalsToUpperCase($para.next().html(), 'ustrikei', 'right hand side'); - - $para = $busi.clone().find('p'); - $u = $para.find('u'); - dom.splitTree($para[0], {node: $u[0], offset: 1 }); - helper.equalsToUpperCase($para.html(), 'bu', 'splitBy u tag with offset 1'); - helper.equalsToUpperCase($para.next().html(), '
strikei', 'right hand side'); - - $para = $busi.clone().find('p'); - $b = $para.find('b'); - dom.splitTree($para[0], {node: $b[0], offset: 0 }); - helper.equalsToUpperCase($para.html(), '
', 'splitBy b tag with offset 0 (left edge case)'); - helper.equalsToUpperCase($para.next().html(), 'bustrikei', 'right hand side'); - - $para = $busi.clone().find('p'); - $i = $para.find('i'); - dom.splitTree($para[0], {node: $i[0], offset: 1 }); - helper.equalsToUpperCase($para.html(), - 'bustrikei', 'splitBy i tag with offset 1 (right edge case)'); - helper.equalsToUpperCase($para.next().html(), '
', 'right hand side'); - - // 02. textNode case - $para = $busi.clone().find('p'); - $s = $para.find('s'); - dom.splitTree($para[0], {node: $s[0].firstChild, offset: 3 }); - helper.equalsToUpperCase($para.html(), 'bustr', 'splitBy s tag with offset 3 (middle case)'); - helper.equalsToUpperCase($para.next().html(), 'ikei', 'right hand side'); - - $para = $busi.clone().find('p'); - $s = $para.find('s'); - dom.splitTree($para[0], {node: $s[0].firstChild, offset: 0 }); - helper.equalsToUpperCase($para.html(), 'bu
', 'splitBy s tag with offset 0 (left edge case)'); - helper.equalsToUpperCase($para.next().html(), 'strikei', 'right hand side'); - - $para = $busi.clone().find('p'); - $s = $para.find('s'); - dom.splitTree($para[0], {node: $s[0].firstChild, offset: 6}); - helper.equalsToUpperCase($para.html(), 'bustrike', 'splitBy s tag with offset 6 (right edge case)'); - helper.equalsToUpperCase($para.next().html(), '
i', 'right hand side'); - - $para = $busi.clone().find('p'); - $s = $para.find('s'); - dom.splitTree($s[0], {node: $s[0].firstChild, offset: 3}); - helper.equalsToUpperCase($para.html(), 'bustrikei', - 'splitBy s tag with offset 3 (2 depth case)'); - - $para = $busi.clone().find('p'); - $s = $para.find('s'); - dom.splitTree($s[0].firstChild, {node: $s[0].firstChild, offset: 3}); - helper.equalsToUpperCase($para.html(), 'bustrikei', - 'splitBy s tag with offset 3 (1 depth, textNode case)'); - - $cont = $('

busi

'); //busi - $span = $cont.find('span'); - dom.splitTree($span[0], {node: $span[0], offset: 2}); - helper.equalsToUpperCase($cont.html(), '

busi

', - 'splitBy span tag with offset 2 (1 depth, element case)'); + + describe('splitTree', function () { + var $para; + beforeEach(function () { + var $busi = $('

bustrikei

'); //busi + $para = $busi.clone().find('p'); + }); + + describe('element pivot case', function () { + it('should be splited by u tag with offset 0', function () { + var $u = $para.find('u'); + dom.splitTree($para[0], {node: $u[0], offset: 0 }); + + helper.equalsToUpperCase($para.html(), 'b
', expect); + helper.equalsToUpperCase($para.next().html(), 'ustrikei', expect); // right hand side + }); + + it('should be splited by u tag with offset 1', function () { + var $u = $para.find('u'); + dom.splitTree($para[0], {node: $u[0], offset: 1 }); + + helper.equalsToUpperCase($para.html(), 'bu', expect); + helper.equalsToUpperCase($para.next().html(), '
strikei', expect); // right hand side + }); + + it('should be splited by b tag with offset 0 (left edge case)', function () { + var $b = $para.find('b'); + dom.splitTree($para[0], {node: $b[0], offset: 0 }); + + helper.equalsToUpperCase($para.html(), '
', expect); + helper.equalsToUpperCase($para.next().html(), 'bustrikei', expect); // right hand side + }); + + it('should be splited by i tag with offset 1 (right edge case)', function () { + var $i = $para.find('i'); + dom.splitTree($para[0], {node: $i[0], offset: 1 }); + + helper.equalsToUpperCase($para.html(), 'bustrikei', expect); + helper.equalsToUpperCase($para.next().html(), '
', expect); // right hand side + }); + }); + + describe('textNode case', function () { + it('should be splited by s tag with offset 3 (middle case)', function () { + var $s = $para.find('s'); + dom.splitTree($para[0], {node: $s[0].firstChild, offset: 3 }); + + helper.equalsToUpperCase($para.html(), 'bustr', expect); + helper.equalsToUpperCase($para.next().html(), 'ikei', expect); // right hand side + }); + + it('should be splited by s tag with offset 0 (left edge case)', function () { + var $s = $para.find('s'); + dom.splitTree($para[0], {node: $s[0].firstChild, offset: 0 }); + + helper.equalsToUpperCase($para.html(), 'bu
', expect); + helper.equalsToUpperCase($para.next().html(), 'strikei', expect); // right hand side + }); + + it('should be splited by s tag with offset 6 (right edge case)', function () { + var $s = $para.find('s'); + dom.splitTree($para[0], {node: $s[0].firstChild, offset: 6 }); + + helper.equalsToUpperCase($para.html(), 'bustrike', expect); + helper.equalsToUpperCase($para.next().html(), '
i', expect); // right hand side + }); + + it('should be splited by s tag with offset 3 (2 depth case)', function () { + var $s = $para.find('s'); + dom.splitTree($s[0], {node: $s[0].firstChild, offset: 3 }); + + helper.equalsToUpperCase($para.html(), 'bustrikei', expect); + }); + + it('should be splited by s tag with offset 3 (1 depth and textNode case)', function () { + var $s = $para.find('s'); + dom.splitTree($s[0].firstChild, {node: $s[0].firstChild, offset: 3 }); + + helper.equalsToUpperCase($para.html(), 'bustrikei', expect); + }); + + it('should be splited by span tag with offset 2 (1 depth and element case)', function () { + var $cont = $('

busi

'); //busi + var $span = $cont.find('span'); + dom.splitTree($span[0], {node: $span[0], offset: 2 }); + + helper.equalsToUpperCase($cont.html(), '

busi

', expect); + }); + }); }); - test('dom.splitPoint', function () { - var $editable, $para, $br; - $editable = $('


'); - - $para = $editable.clone().find('p'); - $br = $para.find('br'); - - deepEqual(dom.splitPoint({ - node: $para[0], - offset: 0 - }, true), { - rightNode: $br[0], - container: $para[0] - }, 'splitPoint empty paragraph with inline should returns rightNode:
container:

'); + describe('splitPoint', function () { + it('should retun rightNode and container for empty paragraph with inline', function () { + var $editable = $('


'); + var $para = $editable.clone().find('p'); + var $br = $para.find('br'); + var result = dom.splitPoint({ node: $para[0], offset: 0 }, true); + expect(result).to.deep.equal({ rightNode: $br[0], container: $para[0] }); + + }); }); - }; + }); }); diff --git a/test/unit/func.spec.js b/test/unit/func.spec.js index bd1e3e814..740e307f0 100644 --- a/test/unit/func.spec.js +++ b/test/unit/func.spec.js @@ -4,56 +4,57 @@ * summernote may be freely distributed under the MIT license./ */ define([ + 'chai', 'summernote/core/func' -], function (func) { - return function () { - test('func.eq2', function () { - ok(func.eq2(1, 1), 'should return true'); - ok(!func.eq2(1, '1'), 'should return false'); +], function (chai, func) { + 'use strict'; + + var expect = chai.expect; + + describe('core.func', function () { + describe('eq2', function () { + it('should return true if two values are same', function () { + expect(func.eq2(1, 1)).to.be.ok; + }); + + it('should return false if two values are not same', function () { + expect(func.eq2(1, '1')).to.be.not.ok; + }); }); - test('func.peq2', function () { - ok(func.peq2('prop')({ - prop: 'hello' - }, { - prop: 'hello' - }), 'should return true'); - - ok(!func.peq2('prop')({ - prop: 'hello' - }, { - prop: 'world' - }), 'should return false'); + describe('peq2', function () { + it('should return true when two properties are same', function () { + expect(func.peq2('prop')({ prop: 'hello' }, { prop: 'hello' })).to.be.ok; + }); + + it('should return false when two properties are not same', function () { + expect(func.peq2('prop')({ prop: 'hello' }, { prop: 'world' })).to.be.not.ok; + }); }); - test('func.uniqueId', function () { - equal(func.uniqueId('note-'), 'note-1', 'should returns uniqueId with prefix'); - equal(func.uniqueId('note-'), 'note-2', 'should returns uniqueId with prefix'); - equal(func.uniqueId('note-'), 'note-3', 'should returns uniqueId with prefix'); + describe('uniqueId', function () { + it('should return uniqueId with the prefix as a parameter', function () { + expect(func.uniqueId('note-')).to.be.equal('note-1'); + expect(func.uniqueId('note-')).to.be.equal('note-2'); + expect(func.uniqueId('note-')).to.be.equal('note-3'); + }); }); - test('func.invertObject', function () { - deepEqual(func.invertObject({ - keyA: 'valueA', - keyB: 'valueB' - }), { - valueA: 'keyA', - valueB: 'keyB' - }, 'should returns inverted object'); + describe('invertObject', function () { + it('should return inverted object between keys and values', function () { + expect(func.invertObject({ keyA: 'valueA', keyB: 'valueB' })) + .to.deep.equal({ valueA: 'keyA', valueB: 'keyB'}); + }); }); - test('func.namespaceToCamel', function () { - equal( - func.namespaceToCamel('upload.image'), - 'UploadImage', - 'shuold returns camel text' - ); - - equal( - func.namespaceToCamel('upload.image', 'summernote'), - 'summernoteUploadImage', - 'shuold returns camel text with prefix' - ); + describe('namespaceToCamel', function () { + it('should return camelcase text', function () { + expect(func.namespaceToCamel('upload.image')).to.be.equal('UploadImage'); + }); + + it('should return prefixed camelcase text', function () { + expect(func.namespaceToCamel('upload.image', 'summernote')).to.be.equal('summernoteUploadImage'); + }); }); - }; + }); }); diff --git a/test/unit/key.spec.js b/test/unit/key.spec.js index e29b737b4..692458cf0 100644 --- a/test/unit/key.spec.js +++ b/test/unit/key.spec.js @@ -4,15 +4,23 @@ * summernote may be freely distributed under the MIT license./ */ define([ + 'chai', 'summernote/core/key' -], function (key) { - return function () { - test('key.isEdit', function () { - ok(key.isEdit(key.code.BACKSPACE), 'isEdit with BACKSPACE should returns true'); - }); +], function (chai, key) { + 'use strict'; + + var expect = chai.expect; - test('key.isMove', function () { - ok(key.isMove(key.code.LEFT), 'isEdit with LEFT should returns true'); + describe('core.key', function () { + describe('isEdit', function () { + it('should return true for BACKSPACE', function () { + expect(key.isEdit(key.code.BACKSPACE)).to.be.true; + }); + }); + describe('isMove', function () { + it('should return true for LEFT', function () { + expect(key.isMove(key.code.LEFT)).to.be.true; + }); }); - }; + }); }); diff --git a/test/unit/list.spec.js b/test/unit/list.spec.js index aff65e3e9..3fe555930 100644 --- a/test/unit/list.spec.js +++ b/test/unit/list.spec.js @@ -3,77 +3,116 @@ * (c) 2013~ Alan Hong * summernote may be freely distributed under the MIT license./ */ -define(['jquery', 'summernote/core/list'], function ($, list) { - return function () { - test('list.head', function () { - deepEqual(list.head([1, 2, 3]), 1, 'should return the first element'); +define(['chai', 'jquery', 'summernote/core/list'], function (chai, $, list) { + 'use strict'; + + var expect = chai.expect; + + describe('core.list', function () { + describe('head', function () { + it('should return the first element', function () { + expect(list.head([1, 2, 3])).to.be.equal(1); + }); }); - test('list.last', function () { - deepEqual(list.last([1, 2, 3]), 3, 'should return the last element'); + describe('last', function () { + it('should return the last element', function () { + expect(list.last([1, 2, 3])).to.be.equal(3); + }); }); - test('list.initial', function () { - deepEqual(list.initial([1, 2, 3]), [1, 2], 'should exclude last element'); + describe('initial', function () { + it('should exclude last element', function () { + expect(list.initial([1, 2, 3])).to.deep.equal([1, 2]); + }); }); - test('list.tail', function () { - deepEqual(list.tail([1, 2, 3]), [2, 3], 'should exclude first element'); + describe('tail', function () { + it('should exclude first element', function () { + expect(list.tail([1, 2, 3])).to.deep.equal([2, 3]); + }); }); var isEven = function (num) { return num % 2 === 0; }; - test('list.find', function () { - deepEqual(list.find([1, 2, 3], isEven), 2, 'should returns first matched element'); + describe('find', function () { + it('should return first matched element', function () { + expect(list.find([1, 2, 3], isEven)).to.be.equal(2); + }); }); - test('list.all', function () { - deepEqual(list.all([1, 2, 3], isEven), false, 'should returns false'); - deepEqual(list.all([2, 4], isEven), true, 'should returns true'); + describe('all', function () { + it('should return false if all elements are not even', function () { + expect(list.all([1, 2, 3], isEven)).to.be.false; + }); + + it('should return true if all elements are even', function () { + expect(list.all([2, 4], isEven)).to.be.true; + }); }); - test('list.sum', function () { - deepEqual(list.contains([1, 2, 3], 4), false, 'should returns false'); - deepEqual(list.contains([1, 2, 4], 4), true, 'should returns true'); + describe('all', function () { + it('should return false if the element is not contained', function () { + expect(list.contains([1, 2, 3], 4)).to.be.false; + }); + + it('should return true if the element is contained', function () { + expect(list.contains([1, 2, 4], 4)).to.be.true; + }); }); - test('list.sum', function () { - deepEqual(list.sum([1, 2, 3]), 6, 'should return 6'); - deepEqual(list.sum([1, 2, 3], function (v) { return v * 2; }), 12, 'should return 12'); + describe('sum', function () { + it('should return sum of all elements', function () { + expect(list.sum([1, 2, 3])).to.be.equal(6); + }); + + it('should return sum of all elements iterated', function () { + var result = list.sum([1, 2, 3], function (v) { return v * 2; }); + expect(result).to.be.equal(12); + }); }); - test('list.from', function () { - var $cont, $b, $u, $s, $i; - $cont = $('
busi
'); //busi - $b = $cont.find('b'); - $u = $cont.find('u'); - $s = $cont.find('s'); - $i = $cont.find('i'); + describe('from', function () { + it('should return an array of childNodes', function () { + var $cont, $b, $u, $s, $i; + $cont = $('
busi
'); //busi + $b = $cont.find('b'); + $u = $cont.find('u'); + $s = $cont.find('s'); + $i = $cont.find('i'); - deepEqual(list.from($cont[0].childNodes), - [$b[0], $u[0], $s[0], $i[0]], 'should return array of childNodes'); + expect(list.from($cont[0].childNodes)).to.deep.equal([$b[0], $u[0], $s[0], $i[0]]); + }); }); - test('list.clusterBy', function () { - var aaClustered = list.clusterBy([1, 1, 2, 2, 3], function (itemA, itemB) { - return itemA === itemB; + describe('clusterBy', function () { + it('should cluster by equality 1', function () { + var aaClustered = list.clusterBy([1, 1, 2, 2, 3], function (itemA, itemB) { + return itemA === itemB; + }); + expect(aaClustered).to.deep.equal([[1, 1], [2, 2], [3]]); }); - deepEqual([[1, 1], [2, 2], [3]], aaClustered, 'should cluster by equality 1'); - aaClustered = list.clusterBy([1, 2, 2, 1, 3], function (itemA, itemB) { - return itemA === itemB; + it('should cluster by equality 2', function () { + var aaClustered = list.clusterBy([1, 2, 2, 1, 3], function (itemA, itemB) { + return itemA === itemB; + }); + expect(aaClustered).to.deep.equal([[1], [2, 2], [1], [3]]); }); - deepEqual([[1], [2, 2], [1], [3]], aaClustered, 'should cluster by equality 2'); }); - test('list.compact', function () { - deepEqual(list.compact([0, 1, false, 2, '', 3]), [1, 2, 3], 'falsey values of `array` removed'); + describe('compact', function () { + it('should remove all elements has falsey value', function () { + expect(list.compact([0, 1, false, 2, '', 3])).to.deep.equal([1, 2, 3]); + }); }); - test('list.unique', function () { - deepEqual(list.unique([1, 2, 3, 3, 2, 1]), [1, 2, 3], 'returns duplicate-free version of array'); + describe('unique', function () { + it('should return duplicate-free version of array', function () { + expect(list.unique([1, 2, 3, 3, 2, 1])).to.deep.equal([1, 2, 3]); + }); }); - }; + }); }); diff --git a/test/unit/range.spec.js b/test/unit/range.spec.js index e458c08d3..f8a9ea72a 100644 --- a/test/unit/range.spec.js +++ b/test/unit/range.spec.js @@ -4,397 +4,406 @@ * summernote may be freely distributed under the MIT license./ */ define([ + 'chai', + 'helper', 'jquery', - 'summernote/core/agent', 'summernote/core/dom', 'summernote/core/range' -], function ($, agent, dom, range) { - return function (helper) { - test('rng.nodes', function () { - var rng, $cont, $para, $li, $h1, $h2, $b; - - //01. 1 depth - $cont = $('

para1

para2

'); - $para = $cont.find('p'); - rng = range.create($para[0].firstChild, 0, $para[1].firstChild, 1); - equal(rng.nodes(dom.isPara, { - includeAncestor: true - }).length, 2, 'should nodes return array of paragraphs[2]'); - - rng = range.create($para[0].firstChild, 0, $para[0].firstChild, 0); - equal(rng.nodes(dom.isPara, { - includeAncestor: true - }).length, 1, 'should nodes return array of a para'); - - //02. multi depth - $cont = $('

para1

para2

'); - $b = $cont.find('b'); - rng = range.create($b[0].firstChild, 0, $b[0].firstChild, 0); - equal(rng.nodes(dom.isPara, { - includeAncestor: true - }).length, 1, 'should nodes return array of a para'); - - //03. on list, on heading - $cont = $('
'); - $li = $cont.find('li'); - rng = range.create($li[0].firstChild, 0, $li[1].firstChild, 1); - equal(rng.nodes(dom.isPara, { - includeAncestor: true - }).length, 2, 'should nodes return array of list paragraphs'); - - $cont = $('

heading1

heading2

'); - $h1 = $cont.find('h1'); - $h2 = $cont.find('h2'); - rng = range.create($h1[0].firstChild, 0, $h2[0].firstChild, 1); - equal(rng.nodes(dom.isPara, { - includeAncestor: true - }).length, 2, 'should nodes return array of list paragraphs'); +], function (chai, helper, $, dom, range) { + 'use strict'; + + var expect = chai.expect; + + describe('core.range', function () { + describe('nodes', function () { + describe('1 depth', function () { + var $para; + before(function () { + var $cont = $('

para1

para2

'); + $para = $cont.find('p'); + }); + + it('should return array of two paragraphs', function () { + var rng = range.create($para[0].firstChild, 0, $para[1].firstChild, 1); + expect(rng.nodes(dom.isPara, {includeAncestor: true})).to.have.length(2); + }); + + it('should return array of a paragraph', function () { + var rng = range.create($para[0].firstChild, 0, $para[0].firstChild, 0); + expect(rng.nodes(dom.isPara, { includeAncestor: true })).to.have.length(1); + }); + }); + + describe('multi depth', function () { + it('should return array of a paragraph', function () { + var $cont = $('

para1

para2

'); + var $b = $cont.find('b'); + var rng = range.create($b[0].firstChild, 0, $b[0].firstChild, 0); + + expect(rng.nodes(dom.isPara, { includeAncestor: true })).to.have.length(1); + }); + }); + + describe('on list, on heading', function () { + it('should return array of list paragraphs', function () { + var $cont = $('
'); + var $li = $cont.find('li'); + var rng = range.create($li[0].firstChild, 0, $li[1].firstChild, 1); + + expect(rng.nodes(dom.isPara, { includeAncestor: true })).to.have.length(2); + }); + + it('should return array of list paragraphs', function () { + var $cont = $('

heading1

heading2

'); + var $h1 = $cont.find('h1'); + var $h2 = $cont.find('h2'); + var rng = range.create($h1[0].firstChild, 0, $h2[0].firstChild, 1); + + expect(rng.nodes(dom.isPara, { includeAncestor: true })).to.have.length(2); + }); + }); }); - test('rng.commonAncestor', function () { - var rng, $cont, $span, $b, $u; - $cont = $('
bu
'); - $span = $cont.find('span'); - $b = $cont.find('b'); - $u = $cont.find('u'); + describe('commonAncestor', function () { + var $cont; + before(function () { + $cont = $('
bu
'); + }); - rng = range.create($b[0].firstChild, 0, $u[0].firstChild, 1); - equal(rng.commonAncestor(), $span[0], 'rng.commonAncestor on between |b and u| should returns '); + it('should return for |b and u|', function () { + var $span = $cont.find('span'); + var $b = $cont.find('b'); + var $u = $cont.find('u'); - rng = range.create($b[0].firstChild, 0, $b[0].firstChild, 1); - equal(rng.commonAncestor(), $b[0].firstChild, 'rng.commonAncestor on |b| should returns b(#textNode)'); - }); - - test('rng.expand', function () { - var rng, $cont, $b, $u, $anchor; - $cont = $('
bu
'); - $anchor = $cont.find('a'); - $b = $cont.find('b'); - $u = $cont.find('u'); - - rng = range.create($b[0].firstChild, 0, $b[0].firstChild, 0).expand(dom.isAnchor); - deepEqual([ - rng.sc, rng.so, rng.ec, rng.eo - ], [ - $anchor[0], 0, $anchor[0], 2 - ], 'rng.expand on `|b` with isAnchor should returns `|b ~ u|`'); - }); + var rng = range.create($b[0].firstChild, 0, $u[0].firstChild, 1); + expect(rng.commonAncestor()).to.deep.equal($span[0]); + }); - test('rng.collapse', function () { - var rng, $cont, $b, $u; - $cont = $('
bu
'); - $b = $cont.find('b'); - $u = $cont.find('u'); + it('should return b(#textNode) for |b|', function () { + var $b = $cont.find('b'); - rng = range.create($b[0].firstChild, 0, $u[0].firstChild, 1).collapse(); - deepEqual([ - rng.sc, rng.so, rng.ec, rng.eo - ], [ - $u[0].firstChild, 1, $u[0].firstChild, 1 - ], 'rng.collapse on `|b ~ u|` should returns `u|`'); + var rng = range.create($b[0].firstChild, 0, $b[0].firstChild, 1); + expect(rng.commonAncestor()).to.deep.equal($b[0].firstChild); + }); + }); + describe('expand', function () { + it('should return |b ~ u| for |b with isAnchor', function () { + var $cont = $('
bu
'); + var $anchor = $cont.find('a'); + var $b = $cont.find('b'); + + var rng = range.create($b[0].firstChild, 0, $b[0].firstChild, 0).expand(dom.isAnchor); + expect(rng.sc).to.deep.equal($anchor[0]); + expect(rng.so).to.equal(0); + expect(rng.ec).to.deep.equal($anchor[0]); + expect(rng.eo).to.equal(2); + }); }); - test('rng.normalize', function () { - var rng, $cont, $p, $b, $u, $s; - $cont = $('

bus

'); - $p = $cont.find('p'); - $b = $cont.find('b'); - $u = $cont.find('u'); - $s = $cont.find('s'); - - rng = range.create($p[0], 0, $p[0], 2).normalize(); - deepEqual([ - rng.sc, rng.so, rng.ec, rng.eo - ], [ - $b[0].firstChild, 0, $u[0].firstChild, 1 - ], 'rng.normalize on `|b ~ u|` should returns `|b ~ u|`'); - - rng = range.create($p[0], 1, $p[0], 1).normalize(); - deepEqual([ - rng.sc, rng.so, rng.ec, rng.eo - ], [ - $b[0].firstChild, 1, $b[0].firstChild, 1 - ], 'rng.normalize on `b|u` should returns `b|u`'); - - rng = range.create($p[0], 1, $p[0], 1).normalize(); - deepEqual([ - rng.sc, rng.so, rng.ec, rng.eo - ], [ - $b[0].firstChild, 1, $b[0].firstChild, 1 - ], 'rng.normalize on `b|u` should returns `b|u`'); - - rng = range.create($b[0].firstChild, 1, $s[0].firstChild, 0).normalize(); - deepEqual([ - rng.sc, rng.so, rng.ec, rng.eo - ], [ - $u[0].firstChild, 0, $u[0].firstChild, 1 - ], 'rng.normalize on `b|u|s` should returns `b|u|s`'); - - rng = range.create($b[0].firstChild, 1, $b[0].firstChild, 1).normalize(); - deepEqual([ - rng.sc, rng.so, rng.ec, rng.eo - ], [ - $b[0].firstChild, 1, $b[0].firstChild, 1 - ], 'rng.normalize on `b|us` should returns `b|us`'); + describe('collapse', function () { + it('should return u| for |b ~ u|', function () { + var $cont = $('
bu
'); + var $b = $cont.find('b'); + var $u = $cont.find('u'); + + var rng = range.create($b[0].firstChild, 0, $u[0].firstChild, 1).collapse(); + expect(rng.sc).to.deep.equal($u[0].firstChild); + expect(rng.so).to.equal(1); + expect(rng.ec).to.deep.equal($u[0].firstChild); + expect(rng.eo).to.equal(1); + }); }); - test('rng.normalize (block level)', function () { - var rng, $cont, $p; - $cont = $('

text


'); - $p = $cont.find('p'); - - rng = range.create($p[1], 0, $p[1], 0).normalize(); - deepEqual([ - rng.sc, rng.so, rng.ec, rng.eo - ], [ - $p[1], 0, $p[1], 0 - ], 'rng.normalize on `

text

|

` should returns `

text

|

`'); - - $cont = $('

text

text

'); - $p = $cont.find('p'); - - rng = range.create($p[1], 0, $p[1], 0).normalize(); - deepEqual([ - rng.sc, rng.so, rng.ec, rng.eo - ], [ - $p[1].firstChild, 0, $p[1].firstChild, 0 - ], 'rng.normalize on `

text

|text

` should returns `

text

|text

`'); - - $cont = $('

text

text

'); - $p = $cont.find('p'); - - rng = range.create($cont[0], 0, $cont[0], 2).normalize(); - deepEqual([ - rng.sc, rng.so, rng.ec, rng.eo - ], [ - $p[0].firstChild, 0, $p[1].firstChild, 4 - ], 'rng.normalize on `|

text

text

|` should returns `

|text

text|

`'); + describe('normalize', function () { + var $cont; + before(function () { + $cont = $('

bus

'); + }); + + it('should return |b ~ u| for |b ~ u|', function () { + var $p = $cont.find('p'); + var $b = $cont.find('b'); + var $u = $cont.find('u'); + + var rng = range.create($p[0], 0, $p[0], 2).normalize(); + expect(rng.sc).to.deep.equal($b[0].firstChild); + expect(rng.so).to.equal(0); + expect(rng.ec).to.deep.equal($u[0].firstChild); + expect(rng.eo).to.equal(1); + }); + + it('should return b|u for b|u', function () { + var $p = $cont.find('p'); + var $b = $cont.find('b'); + + var rng = range.create($p[0], 1, $p[0], 1).normalize(); + expect(rng.sc).to.deep.equal($b[0].firstChild); + expect(rng.so).to.equal(1); + expect(rng.ec).to.deep.equal($b[0].firstChild); + expect(rng.eo).to.equal(1); + }); + + it('should return b|u|s for b|u|s', function () { + var $b = $cont.find('b'); + var $u = $cont.find('u'); + var $s = $cont.find('s'); + + var rng = range.create($b[0].firstChild, 1, $s[0].firstChild, 0).normalize(); + expect(rng.sc).to.deep.equal($u[0].firstChild); + expect(rng.so).to.equal(0); + expect(rng.ec).to.deep.equal($u[0].firstChild); + expect(rng.eo).to.equal(1); + }); + + it('should return b|us for b|us', function () { + var $b = $cont.find('b'); + + var rng = range.create($b[0].firstChild, 1, $b[0].firstChild, 1).normalize(); + expect(rng.sc).to.deep.equal($b[0].firstChild); + expect(rng.so).to.equal(1); + expect(rng.ec).to.deep.equal($b[0].firstChild); + expect(rng.eo).to.equal(1); + }); }); - test('rng.normalize (void element)', function () { - var rng, $cont, $p, $b; - $cont = $('

bold

'); - $p = $cont.find('p'); - $b = $cont.find('b'); - - rng = range.create($p[0], 1, $p[0], 1).normalize(); - deepEqual([ - rng.sc, rng.so, rng.ec, rng.eo - ], [ - $b[0].firstChild, 0, $b[0].firstChild, 0 - ], 'rng.normalize on `

|bold

` should returns `

|bold

`'); + describe('normalize (block mode)', function () { + it('should return

text

|

for

text

|

', function () { + var $cont = $('

text


'); + var $p = $cont.find('p'); + + var rng = range.create($p[1], 0, $p[1], 0).normalize(); + expect(rng.sc).to.deep.equal($p[1]); + expect(rng.so).to.equal(0); + expect(rng.ec).to.deep.equal($p[1]); + expect(rng.eo).to.equal(0); + }); + + it('should return

text

|text

for

text

|text

', function () { + var $cont = $('

text

text

'); + var $p = $cont.find('p'); + + var rng = range.create($p[1], 0, $p[1], 0).normalize(); + expect(rng.sc).to.deep.equal($p[1].firstChild); + expect(rng.so).to.equal(0); + expect(rng.ec).to.deep.equal($p[1].firstChild); + expect(rng.eo).to.equal(0); + }); + + it('should return

|text

text|

for |

text

text

|', function () { + var $cont = $('

text

text

'); + var $p = $cont.find('p'); + + var rng = range.create($cont[0], 0, $cont[0], 2).normalize(); + expect(rng.sc).to.deep.equal($p[0].firstChild); + expect(rng.so).to.equal(0); + expect(rng.ec).to.deep.equal($p[1].firstChild); + expect(rng.eo).to.equal(4); + }); }); - test('rng.insertNode', function () { - var $cont, $p, $p2, $b, $u; - - // insertNode with block split - $cont = $('

bold

'); - $p = $cont.find('p'); - $b = $cont.find('b'); - $p2 = $('

p

'); - - range.create($b[0].firstChild, 2, $b[0].firstChild, 2).insertNode($p2[0]); - helper.equalsToUpperCase( - $cont.html(), - '

bo

p

ld

', - 'rng.insertNode with block should split paragraph.' - ); - - $cont = $('

text

'); - $p = $cont.find('p'); - $u = $('u'); - - // insertNode with inline split - range.create($p[0].firstChild, 2, $p[0].firstChild, 2).insertNode($u[0]); - helper.equalsToUpperCase($cont.html(), '

teuxt

', 'rng.insertNode with inline should not split paragraph.'); - - $cont = $('

bold

'); - $p = $cont.find('p'); - $b = $cont.find('b'); - $u = $('u'); - - range.create($b[0].firstChild, 2, $b[0].firstChild, 2).insertNode($u[0]); - helper.equalsToUpperCase($cont.html(), '

bould

', 'rng.insertNode with inline should not split paragraph.'); + describe('normalize (void element)', function () { + it('should return

|bold

for

|bold

', function () { + var $cont = $('

bold

'); + var $p = $cont.find('p'); + var $b = $cont.find('b'); + + var rng = range.create($p[0], 1, $p[0], 1).normalize(); + expect(rng.sc).to.deep.equal($b[0].firstChild); + expect(rng.so).to.equal(0); + expect(rng.ec).to.deep.equal($b[0].firstChild); + expect(rng.eo).to.equal(0); + }); }); - test('rng.pasteHTML', function () { - var $cont, $p, $b, markup; - - // split text with inline nodes - $cont = $('

text

'); - $p = $cont.find('p'); - markup = 'spanitalic'; - - range.create($p[0].firstChild, 2).pasteHTML(markup); - helper.equalsToUpperCase( - $cont.html(), - '

tespanitalicxt

', - 'rng.pasteHTML with inlines should not split text.' - ); - - // split inline node with inline nodes - $cont = $('

bold

'); - $p = $cont.find('p'); - $b = $cont.find('b'); - markup = 'spanitalic'; - - range.create($b[0].firstChild, 2).pasteHTML(markup); - helper.equalsToUpperCase( - $cont.html(), - '

bospanitalicld

', - 'rng.pasteHTML with inlines should not split text.' - ); - - // split inline node with inline and block nodes - $cont = $('

bold

'); - $p = $cont.find('p'); - $b = $cont.find('b'); - markup = 'span

italic

'; - - range.create($b[0].firstChild, 2).pasteHTML(markup); - helper.equalsToUpperCase( - $cont.html(), - '

bospan

italic

ld

', - 'rng.pasteHTML with inlines should not split text.' - ); - - // split inline node with inline and block - $cont = $('

bold

'); - $p = $cont.find('p'); - $b = $cont.find('b'); - markup = 'span

italic

'; - - range.create($b[0].firstChild, 2).pasteHTML(markup); - helper.equalsToUpperCase( - $cont.html(), - '

bospan

italic

ld

', - 'rng.pasteHTML with inlines should not split text.' - ); + describe('insertNode', function () { + it('should split paragraph when inserting a block element', function () { + var $cont = $('

bold

'); + var $b = $cont.find('b'); + var $p2 = $('

p

'); + + var rng = range.create($b[0].firstChild, 2, $b[0].firstChild, 2); + rng.insertNode($p2[0]); + + helper.equalsToUpperCase($cont.html(), '

bo

p

ld

', expect); + }); + + it('should not split paragraph when inserting an inline element', function () { + var $cont = $('

text

'); + var $p = $cont.find('p'); + var $u = $('u'); + + var rng = range.create($p[0].firstChild, 2, $p[0].firstChild, 2); + rng.insertNode($u[0]); + helper.equalsToUpperCase($cont.html(), '

teuxt

', expect); + }); + + it('should not split paragraph when inserting an inline element case 2', function () { + var $cont = $('

bold

'); + var $b = $cont.find('b'); + var $u = $('u'); + + var rng = range.create($b[0].firstChild, 2, $b[0].firstChild, 2); + rng.insertNode($u[0]); + helper.equalsToUpperCase($cont.html(), '

bould

', expect); + }); }); - test('rng.deleteContents', function () { - var $cont, $p, $b, $u; + describe('pasteHTML', function () { + it('should not split a block element when inserting inline elements into it', function () { + var $cont = $('

text

'); + var $p = $cont.find('p'); + var markup = 'spanitalic'; + + var rng = range.create($p[0].firstChild, 2); + rng.pasteHTML(markup); + + helper.equalsToUpperCase($cont.html(), '

tespanitalicxt

', expect); + }); + + it('should split an inline element when pasting inline elements into it', function () { + var $cont = $('

bold

'); + var $b = $cont.find('b'); + var markup = 'spanitalic'; - // deleteContents on partial text - $cont = $('

boldu

'); - $p = $cont.find('p'); - $b = $cont.find('b'); - $u = $cont.find('u'); + var rng = range.create($b[0].firstChild, 2); + rng.pasteHTML(markup); - range.create($b[0].firstChild, 1, $b[0].firstChild, 3).deleteContents(); - helper.equalsToUpperCase($cont.html(), '

bdu

', 'rng.deleteContents on partial text should remove only text'); + helper.equalsToUpperCase($cont.html(), '

bospanitalicld

', expect); + }); - // deleteContents on full text - $cont = $('

boldu

'); - $p = $cont.find('p'); - $b = $cont.find('b'); - $u = $cont.find('u'); + it('should split inline node when pasting an inline node and a block node into it', function () { + var $cont = $('

bold

'); + var $b = $cont.find('b'); + var markup = 'span

italic

'; - range.create($b[0].firstChild, 0, $b[0].firstChild, 4).deleteContents(); - helper.equalsToUpperCase($cont.html(), '

u

', 'rng.deleteContents on full text should remove text'); + var rng = range.create($b[0].firstChild, 2); + rng.pasteHTML(markup); + helper.equalsToUpperCase($cont.html(), '

bospan

italic

ld

', expect); + }); }); - test('rng.wrapBodyInlineWithPara', function () { + describe('deleteContents', function () { var $cont, $b; + beforeEach(function () { + $cont = $('

boldu

'); + $b = $cont.find('b'); + }); - // empty contents case - $cont = $('
'); - range.create($cont[0], 0).wrapBodyInlineWithPara(); - helper.equalsToUpperCase($cont.html(), '


', 'rng.wrapBodyInlineWithPara with blank should insert empty paragraph.'); - - // body text case - $cont = $('
text
'); - range.create($cont[0].firstChild, 2).wrapBodyInlineWithPara(); - helper.equalsToUpperCase($cont.html(), '

text

', 'rng.wrapBodyInlineWithPara with body text should wrap text with paragraph.'); - - // body inline case 1 - $cont = $('
bold
'); - $b = $cont.find('b'); - range.create($b[0].firstChild, 2).wrapBodyInlineWithPara(); - helper.equalsToUpperCase( - $cont.html(), - '

bold

', - 'rng.wrapBodyInlineWithPara with inline text should wrap text with paragraph.' - ); - - // body inline case 2 - $cont = $('
bi
'); - range.create($cont[0], 0).wrapBodyInlineWithPara(); - helper.equalsToUpperCase( - $cont.html(), - '

bi

', - 'rng.wrapBodyInlineWithPara with inline should wrap text with paragraph.' - ); - - // body inline case 3 - $cont = $('
bi
'); - range.create($cont[0], 1).wrapBodyInlineWithPara(); - helper.equalsToUpperCase( - $cont.html(), - '

bi

', - 'rng.wrapBodyInlineWithPara with inline should wrap text with paragraph.' - ); - - // body inline case 4 - $cont = $('
bi
'); - range.create($cont[0], 2).wrapBodyInlineWithPara(); - helper.equalsToUpperCase( - $cont.html(), - '

bi

', - 'rng.wrapBodyInlineWithPara with inline should wrap text with paragraph.' - ); + it('should remove text only for partial text', function () { + var rng = range.create($b[0].firstChild, 1, $b[0].firstChild, 3); + rng.deleteContents(); + + helper.equalsToUpperCase($cont.html(), '

bdu

', expect); + }); + + it('should remove text for entire text', function () { + var rng = range.create($b[0].firstChild, 0, $b[0].firstChild, 4); + rng.deleteContents(); + + helper.equalsToUpperCase($cont.html(), '

u

', expect); + }); }); - test('rng.getWordRange', function () { - var $cont, rng; - - $cont = $('
super simple wysiwyg editor
'); - - // no word before cursor - rng = range.create( - $cont[0].firstChild, 0 - ).getWordRange(); - - deepEqual([ - rng.sc, rng.so, rng.ec, rng.eo - ], [ - $cont[0].firstChild, 0, $cont[0].firstChild, 0 - ], 'rng.getWordRange with no word before cursor should return itself'); - - // find word before cursor - rng = range.create( - $cont[0].firstChild, 5 - ).getWordRange(); - - deepEqual([ - rng.sc, rng.so, rng.ec, rng.eo - ], [ - $cont[0].firstChild, 0, $cont[0].firstChild, 5 - ], 'rng.getWordRange with word before cursor should return expanded range'); - - rng = range.create( - $cont[0].firstChild, 3 - ).getWordRange(); - - deepEqual([ - rng.sc, rng.so, rng.ec, rng.eo - ], [ - $cont[0].firstChild, 0, $cont[0].firstChild, 3 - ], 'rng.getWordRange with half word before cursor should expanded range'); - - rng = range.create( - $cont[0].firstChild, 12 - ).getWordRange(); - - deepEqual([ - rng.sc, rng.so, rng.ec, rng.eo - ], [ - $cont[0].firstChild, 6, $cont[0].firstChild, 12 - ], 'rng.getWordRange with half word before cursor should expanded range'); + describe('wrapBodyInlineWithPara', function () { + it('should insert an empty paragraph when there is no contents', function () { + var $cont = $('
'); + + var rng = range.create($cont[0], 0); + rng.wrapBodyInlineWithPara(); + + helper.equalsToUpperCase($cont.html(), '


', expect); + }); + + it('should wrap text with paragraph for text', function () { + var $cont = $('
text
'); + + var rng = range.create($cont[0].firstChild, 2); + rng.wrapBodyInlineWithPara(); + + helper.equalsToUpperCase($cont.html(), '

text

', expect); + }); + + it('should wrap an inline node with paragraph when selecting text in the inline node', function () { + var $cont = $('
bold
'); + var $b = $cont.find('b'); + + var rng = range.create($b[0].firstChild, 2); + rng.wrapBodyInlineWithPara(); + + helper.equalsToUpperCase($cont.html(), '

bold

', expect); + }); + + it('should wrap inline nodes with paragraph when selecting text in the inline nodes', function () { + var $cont = $('
bi
'); + + var rng = range.create($cont[0], 0); + rng.wrapBodyInlineWithPara(); + + helper.equalsToUpperCase($cont.html(), '

bi

', expect); + }); + + it('should wrap inline nodes with paragraph when selection some of text in the inline nodes #1', function () { + var $cont = $('
bi
'); + + var rng = range.create($cont[0], 1); + rng.wrapBodyInlineWithPara(); + + helper.equalsToUpperCase($cont.html(), '

bi

', expect); + }); + + it('should wrap inline nodes with paragraph when selection soem of text in the inline nodes #2', function () { + var $cont = $('
bi
'); + + var rng = range.create($cont[0], 2); + rng.wrapBodyInlineWithPara(); + + helper.equalsToUpperCase($cont.html(), '

bi

', expect); + }); + }); + describe('getWordRange', function () { + var $cont; + before(function () { + $cont = $('
super simple wysiwyg editor
'); + }); + + it('should return the range itself when there is no word before cursor', function () { + var rng = range.create($cont[0].firstChild, 0).getWordRange(); + + expect(rng.sc).to.deep.equal($cont[0].firstChild); + expect(rng.so).to.equal(0); + expect(rng.ec).to.deep.equal($cont[0].firstChild); + expect(rng.eo).to.equal(0); + }); + + it('should return expanded range when there is a word before cursor', function () { + var rng = range.create($cont[0].firstChild, 5).getWordRange(); + + expect(rng.sc).to.deep.equal($cont[0].firstChild); + expect(rng.so).to.equal(0); + expect(rng.ec).to.deep.equal($cont[0].firstChild); + expect(rng.eo).to.equal(5); + }); + + it('should return expanded range when there is a half word before cursor', function () { + var rng = range.create($cont[0].firstChild, 3).getWordRange(); + + expect(rng.sc).to.deep.equal($cont[0].firstChild); + expect(rng.so).to.equal(0); + expect(rng.ec).to.deep.equal($cont[0].firstChild); + expect(rng.eo).to.equal(3); + }); + + it('should return expanded range when there are words before cursor', function () { + var rng = range.create($cont[0].firstChild, 12).getWordRange(); + + expect(rng.sc).to.deep.equal($cont[0].firstChild); + expect(rng.so).to.equal(6); + expect(rng.ec).to.deep.equal($cont[0].firstChild); + expect(rng.eo).to.equal(12); + }); }); - }; + }); }); diff --git a/test/unit/style.spec.js b/test/unit/style.spec.js index 0f3d2f978..651aeed53 100644 --- a/test/unit/style.spec.js +++ b/test/unit/style.spec.js @@ -4,122 +4,92 @@ * summernote may be freely distributed under the MIT license./ */ define([ + 'chai', 'jquery', - 'summernote/core/dom', 'summernote/core/range', 'summernote/editing/Style' -], function ($, dom, range, Style) { - return function () { +], function (chai, $, range, Style) { + 'use strict'; + + var expect = chai.expect; + + describe('editing.Style', function () { var style = new Style(); - var equalsToUpperCase = function (actual, expected, comment) { - ok(actual.toUpperCase() === expected.toUpperCase(), comment); - }; - - test('style.styleNodes basic', function () { - var $cont, $p, $b, $span, rng, nodes; - - $cont = $('

text

'); - $p = $cont.find('p'); - rng = range.create($p[0].firstChild, 0, $p[0].firstChild, 4); - nodes = style.styleNodes(rng); - - equalsToUpperCase( - $cont.html(), - '

text

', - 'should wrap selected text with span' - ); - - $cont = $('

text

'); - $p = $cont.find('p'); - rng = range.create($p[0].firstChild, 1, $p[0].firstChild, 3); - nodes = style.styleNodes(rng); - - equalsToUpperCase( - $cont.html(), - '

text

', - 'should split text and wrap selected text with span' - ); - - $cont = $('

text

'); - $p = $cont.find('p'); - rng = range.create($p[0].firstChild, 2, $p[0].firstChild, 2); - nodes = style.styleNodes(rng); - - equalsToUpperCase( - $cont.html(), - '

text

', - 'should split text and insert span' - ); - - $cont = $('

text

'); - $span = $cont.find('span'); - rng = range.create($span[0].firstChild, 0, $span[0].firstChild, 4); - nodes = style.styleNodes(rng); - - equalsToUpperCase( - $cont.html(), - '

text

', - 'should just return parent span' - ); - - $cont = $('

boldspan

'); - $b = $cont.find('b'); - $span = $cont.find('span'); - rng = range.create($b[0].firstChild, 2, $span[0].firstChild, 2); - nodes = style.styleNodes(rng); - - equalsToUpperCase( - $cont.html(), - '

boldspan

', - 'should wrap each texts with span' - ); - - $cont = $('

boldspan

'); - $b = $cont.find('b'); - $span = $cont.find('span'); - rng = range.create($b[0].firstChild, 2, $span[0].firstChild, 4); - nodes = style.styleNodes(rng); - - equalsToUpperCase( - $cont.html(), - '

boldspan

', - 'should wrap each texts with span except not single blood line' - ); - }); + describe('styleNodes', function () { + it('should wrap selected text with span', function () { + var $cont = $('

text

'); + var $p = $cont.find('p'); + var rng = range.create($p[0].firstChild, 0, $p[0].firstChild, 4); + style.styleNodes(rng); + + expect($cont.html()).to.deep.equal('

text

'); + }); - test('style.styleNodes options', function () { - var $cont, $p, rng, nodes; + it('should split text and wrap selected text with span', function () { + var $cont = $('

text

'); + var $p = $cont.find('p'); + var rng = range.create($p[0].firstChild, 1, $p[0].firstChild, 3); + style.styleNodes(rng); - $cont = $('

textbold

'); - $p = $cont.find('p'); - rng = range.create($p[0].firstChild, 0, $p[0].firstChild, 4); - nodes = style.styleNodes(rng, { - nodeName: 'B', - expandClosestSibling: true + expect($cont.html()).to.deep.equal('

text

'); }); - equalsToUpperCase( - $cont.html(), - '

textbold

', - 'should expand b tag with expandClosestSibling option' - ); - - $cont = $('

textbold

'); - $p = $cont.find('p'); - rng = range.create($p[0].firstChild, 0, $p[0].firstChild, 4); - nodes = style.styleNodes(rng, { - nodeName: 'B', - expandClosestSibling: true, - onlyPartialContains: true + it('should split text and insert span', function () { + var $cont = $('

text

'); + var $p = $cont.find('p'); + var rng = range.create($p[0].firstChild, 2, $p[0].firstChild, 2); + style.styleNodes(rng); + + expect($cont.html()).to.deep.equal('

text

'); }); - equalsToUpperCase( - $cont.html(), - '

textbold

', - 'should not expand b tag with onlyPartialContains option' - ); + it('should just return a parent span', function () { + var $cont = $('

text

'); + var $span = $cont.find('span'); + var rng = range.create($span[0].firstChild, 0, $span[0].firstChild, 4); + style.styleNodes(rng); + + expect($cont.html()).to.deep.equal('

text

'); + }); + it('should wrap each texts with span', function () { + var $cont = $('

boldspan

'); + var $b = $cont.find('b'); + var $span = $cont.find('span'); + var rng = range.create($b[0].firstChild, 2, $span[0].firstChild, 2); + style.styleNodes(rng); + + expect($cont.html()).to.deep.equal('

boldspan

'); + }); + + it('should wrap each texts with span except not a single blood line', function () { + var $cont = $('

boldspan

'); + var $b = $cont.find('b'); + var $span = $cont.find('span'); + var rng = range.create($b[0].firstChild, 2, $span[0].firstChild, 4); + style.styleNodes(rng); + + expect($cont.html()).to.deep.equal('

boldspan

'); + }); + + it('should expand b tag when providing the expandClosestSibling option', function () { + var $cont = $('

textbold

'); + var $p = $cont.find('p'); + var rng = range.create($p[0].firstChild, 0, $p[0].firstChild, 4); + style.styleNodes(rng, { nodeName: 'B', expandClosestSibling: true }); + + expect($cont.html()).to.deep.equal('

textbold

'); + }); + + it('should not expand b tag when providing the onlyPartialContains option', function () { + var $cont = $('

textbold

'); + var $p = $cont.find('p'); + var rng = range.create($p[0].firstChild, 0, $p[0].firstChild, 4); + style.styleNodes(rng, { nodeName: 'B', expandClosestSibling: true, onlyPartialContains: true }); + + expect($cont.html()).to.deep.equal('

textbold

'); + }); }); - }; + }); });