test(contenteditable): add in contenteditable list specs

This commit is contained in:
Evan Morikawa 2015-12-02 12:43:11 -08:00
parent 40e143e3f2
commit ced66902d5
6 changed files with 206 additions and 76 deletions

View file

@ -14,6 +14,7 @@ exports.safeExec = function(command, options, callback) {
// The default is 200KB. // The default is 200KB.
options.maxBuffer = 1024 * 1024; options.maxBuffer = 1024 * 1024;
options.stdio = "inherit"
var child = childProcess.exec(command, options, function(error, stdout, stderr) { var child = childProcess.exec(command, options, function(error, stdout, stderr) {
if (error && !options.ignoreStderr) if (error && !options.ignoreStderr)
process.exit(error.code || 1); process.exit(error.code || 1);
@ -31,9 +32,8 @@ exports.safeSpawn = function(command, args, options, callback) {
callback = options; callback = options;
options = {}; options = {};
} }
options.stdio = "inherit"
var child = childProcess.spawn(command, args, options); var child = childProcess.spawn(command, args, options);
child.stderr.pipe(process.stderr);
child.stdout.pipe(process.stdout);
child.on('error', function(error) { child.on('error', function(error) {
console.error('Command \'' + command + '\' failed: ' + error.message); console.error('Command \'' + command + '\' failed: ' + error.message);
}); });

View file

@ -2,11 +2,38 @@
// argv[1] = jasmine // argv[1] = jasmine
// argv[2] = JASMINE_CONFIG_PATH=./config.json // argv[2] = JASMINE_CONFIG_PATH=./config.json
// argv[3] = NYLAS_ROOT_PATH=/path/to/nylas/root // argv[3] = NYLAS_ROOT_PATH=/path/to/nylas/root
var babelOptions = require('../static/babelrc.json'); var babelOptions = require('../static/babelrc.json');
require('babel-core/register')(babelOptions); require('babel-core/register')(babelOptions);
var chalk = require('chalk')
var util = require('util')
console.errorColor = function(err){
if (typeof err === "string") {
console.error(chalk.red(err));
} else {
console.error(chalk.red(util.inspect(err)));
}
}
console.inspect = function(val) {
console.log(util.inspect(val, true, depth=7, colorize=true));
}
jasmine.NYLAS_ROOT_PATH = process.argv[3].split("NYLAS_ROOT_PATH=")[1] jasmine.NYLAS_ROOT_PATH = process.argv[3].split("NYLAS_ROOT_PATH=")[1]
jasmine.UNIT_TEST_TIMEOUT = 120*1000; jasmine.UNIT_TEST_TIMEOUT = 120*1000;
jasmine.BOOT_TIMEOUT = 30*1000; jasmine.BOOT_TIMEOUT = 30*1000;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 30*1000 jasmine.DEFAULT_TIMEOUT_INTERVAL = 30*1000
Promise = require('bluebird')
Promise.config({
warnings: true,
longStackTraces: true,
cancellation: true
})
process.on("unhandledRejection", function(reason, promise) {
if (reason.stack) { console.errorColor(reason.stack); }
console.errorColor(promise);
});

View file

@ -1,18 +1,14 @@
import Promise from 'bluebird'
import {N1Launcher} from './integration-helper' import {N1Launcher} from './integration-helper'
import ContenteditableTestHarness from './contenteditable-test-harness.es6' import ContenteditableTestHarness from './contenteditable-test-harness.es6'
fdescribe('Contenteditable Integration Spec', function() { fdescribe('Contenteditable Integration Spec', function() {
beforeAll((done)=>{ beforeAll((done)=>{
console.log("----------- BEFORE ALL");
// Boot in dev mode with no arguments
this.app = new N1Launcher(["--dev"]); this.app = new N1Launcher(["--dev"]);
this.app.popoutComposerWindowReady().finally(done); this.app.popoutComposerWindowReady().finally(done);
}); });
beforeEach((done) => { beforeEach((done) => {
console.log("----------- BEFORE EACH"); this.ce = new ContenteditableTestHarness(this.app.client)
this.ce = new ContenteditableTestHarness(this.app.client, expect)
this.ce.init().finally(done); this.ce.init().finally(done);
}); });
@ -24,51 +20,120 @@ fdescribe('Contenteditable Integration Spec', function() {
} }
}); });
fit("Creates ordered lists", (done)=> {
console.log("RUNNING KEYS");
this.app.client.keys(["1", ".", "Space"]).then(()=>{ describe('Manipulating Lists', () => {
console.log("DONE FIRING KEYS"); it("Creates ordered lists", (done)=> {
e1 = this.ce.expectHTML("<ol><li>WOOO</li></ol>") this.ce.test({
e2 = this.ce.expectSelection((dom) => { keys: ["1", ".", "Space"],
return {node: dom.querySelectorAll("li")[0]} expectedHTML: "<ol><li></li></ol>",
}) expectedSelectionResolver: (dom) => {
return Promise.all(e1,e2) return {node: dom.querySelectorAll('li')[0]} }
}).catch((err)=>{ console.log("XXXX ERROR"); console.log(err); }).finally(done) }).then(done).catch(done.fail)
}); });
it('Undoes ordered list creation with backspace', (done) => {
this.ce.test({
keys: ["1", ".", "Space", "Back space"],
expectedHTML: "1.&nbsp;<br>",
expectedSelectionResolver: (dom) => {
return {node: dom.childNodes[0], offset: 3} }
}).then(done).catch(done.fail)
});
it("Creates unordered lists with star", (done) => {
this.ce.test({
keys: ['*', 'Space'],
expectedHTML: "<ul><li></li></ul>",
expectedSelectionResolver: (dom) => {
return {node: dom.querySelectorAll("li")[0] } }
}).then(done).catch(done.fail)
});
it("Undoes unordered list creation with backspace", (done) => {
this.ce.test({
keys: ['*', 'Space', 'Back space'],
expectedHTML: "*&nbsp;<br>",
expectedSelectionResolver: (dom) => {
return {node: dom.childNodes[0], offset: 2} }
}).then(done).catch(done.fail)
});
it("Creates unordered lists with dash", (done) => {
this.ce.test({
keys: ['-', 'Space'],
expectedHTML: "<ul><li></li></ul>",
expectedSelectionResolver: (dom) => {
return {node: dom.querySelectorAll("li")[0] } }
}).then(done).catch(done.fail)
});
it("Undoes unordered list creation with backspace", (done) => {
this.ce.test({
keys: ['-', 'Space', 'Back space'],
expectedHTML: "-&nbsp;<br>",
expectedSelectionResolver: (dom) => {
return {node: dom.childNodes[0], offset: 2} }
}).then(done).catch(done.fail)
});
// it("create a single item then delete it with backspace", (done) => {
// this.ce.test({
// keys: ['-', 'Space', 'a', 'Left arrow', 'Back space'],
// expectedHTML: "<span style=\"line-height: 1.4;\">a</span><br>",
// expectedSelectionResolver: (dom) => {
// return {node: dom.childNodes[0], offset: 0} }
// }).then(done).catch(done.fail)
// });
//
// it("create a single item then delete it with tab", (done) => {
// this.ce.test({
// keys: ['-', 'Space', 'a', 'Shift', 'Tab'],
// expectedHTML: "<span style=\"line-height: 1.4;\">a</span><br>",
// expectedSelectionResolver: (dom) => {
// return {node: dom.childNodes[0], offset: 1} }
// }).then(done).catch(done.fail)
// });
});
describe('Ensuring popout composer window works', () => {
it("has main window visible", (done)=> { it("has main window visible", (done)=> {
this.app.client.isWindowVisible() this.app.client.isWindowVisible()
.then((result)=>{ expect(result).toBe(true) }) .then((result)=>{ expect(result).toBe(true) })
.finally(done) .then(done).catch(done.fail)
}); });
it("has main window focused", (done)=> { it("has main window focused", (done)=> {
this.app.client.isWindowFocused() this.app.client.isWindowFocused()
.then((result)=>{ expect(result).toBe(true) }) .then((result)=>{ expect(result).toBe(true) })
.finally(done) .then(done).catch(done.fail)
}); });
it("isn't minimized", (done)=> { it("isn't minimized", (done)=> {
this.app.client.isWindowMinimized() this.app.client.isWindowMinimized()
.then((result)=>{ expect(result).toBe(false) }) .then((result)=>{ expect(result).toBe(false) })
.finally(done) .then(done).catch(done.fail)
}); });
it("doesn't have the dev tools open", (done)=> { it("doesn't have the dev tools open", (done)=> {
this.app.client.isWindowDevToolsOpened() this.app.client.isWindowDevToolsOpened()
.then((result)=>{ expect(result).toBe(false) }) .then((result)=>{ expect(result).toBe(false) })
.finally(done) .then(done).catch(done.fail)
}); });
it("has width", (done)=> { it("has width", (done)=> {
this.app.client.getWindowWidth() this.app.client.getWindowWidth()
.then((result)=>{ expect(result).toBeGreaterThan(0) }) .then((result)=>{ expect(result).toBeGreaterThan(0) })
.finally(done) .then(done).catch(done.fail)
}); });
it("has height", (done)=> { it("has height", (done)=> {
this.app.client.getWindowHeight() this.app.client.getWindowHeight()
.then((result)=>{ expect(result).toBeGreaterThan(0) }) .then((result)=>{ expect(result).toBeGreaterThan(0) })
.finally(done) .then(done).catch(done.fail)
});
}); });
}); });

View file

@ -1,43 +1,40 @@
import Promise from 'bluebird'
class ContenteditableTestHarness { class ContenteditableTestHarness {
constructor(client, expect) { constructor(client) {
this.expect = expect
this.client = client; this.client = client;
} }
init() { init() {
console.log("INIT TEST HARNESS");
return this.client.execute(() => { return this.client.execute(() => {
ce = document.querySelector(".contenteditable") ce = document.querySelector(".contenteditable")
ce.innerHTML = "" ce.innerHTML = ""
ce.focus() ce.focus()
}).then(({value})=>{ })
console.log(value); }
test({keys, expectedHTML, expectedSelectionResolver}) {
return this.client.keys(keys).then(()=>{
return this.expectHTML(expectedHTML)
}).then(()=>{
return this.expectSelection(expectedSelectionResolver)
}) })
} }
expectHTML(expectedHTML) { expectHTML(expectedHTML) {
console.log("EXPECTING HTML"); return this.client.execute(() => {
console.log(expectedHTML); return document.querySelector(".contenteditable").innerHTML
return this.client.execute((expect, arg2) => { }).then(({value})=>{
console.log(expect); expect(value).toBe(expectedHTML)
console.log(arg2);
ce = document.querySelector(".contenteditable")
expect(ce.innerHTML).toBe(expectedHTML)
return ce.innerHTML
}, this.expect, "FOOO").then(({value})=>{
console.log("GOT HTML VALUE");
console.log(value);
}).catch((err)=>{
console.log("XXXXXXXXXX GOT ERROR")
console.log(err);
}) })
} }
expectSelection(callback) { expectSelection(callback) {
return this.client.execute(() => { // Since `execute` fires parameters to Selenium via REST API, we can
// only pass strings. We serialize the callback so we can run it in
// the correct execution environment of the window instead of the
// Selenium wrapper.
return this.client.execute((callbackStr) => {
eval(`callback=${callbackStr}`);
ce = document.querySelector(".contenteditable") ce = document.querySelector(".contenteditable")
expectSel = callback(ce) expectSel = callback(ce)
@ -48,10 +45,51 @@ class ContenteditableTestHarness {
selection = document.getSelection() selection = document.getSelection()
this.expect(selection.anchorNode).toBe(anchorNode) return {
this.expect(selection.focusNode).toBe(focusNode) anchorNodeMatch: selection.anchorNode === anchorNode,
this.expect(selection.anchorOffset).toBe(anchorOffset) focusNodeMatch: selection.focusNode === focusNode,
this.expect(selection.focusOffset).toBe(focusOffset) anchorOffsetMatch: selection.anchorOffset === anchorOffset,
focusOffsetMatch: selection.focusOffset === focusOffset,
expectedAnchorNode: anchorNode.outerHTML,
expectedFocusNode: focusNode.outerHTML,
expectedAnchorOffset: anchorOffset,
expectedFocusOffset: focusOffset,
actualAnchorNode: selection.anchorNode.outerHTML,
actualFocusNode: selection.focusNode.outerHTML,
actualAnchorOffset: selection.anchorOffset,
actualFocusOffset: selection.focusOffset,
}
}, callback.toString()).then(({value}) => {
matchInfo = value
allMatched = true;
if (!matchInfo.anchorNodeMatch) {
console.errorColor("\nAnchor nodes don't match")
console.errorColor(`Expected: "${matchInfo.actualAnchorNode}" to be "${matchInfo.expectedAnchorNode}"`);
allMatched = false;
}
if (!matchInfo.focusNodeMatch) {
console.errorColor("\nFocus nodes don't match")
console.errorColor(`Expected: "${matchInfo.actualFocusNode}" to be "${matchInfo.expectedFocusNode}"`);
allMatched = false;
}
if (!matchInfo.anchorOffsetMatch) {
console.errorColor("\nAnchor offsets don't match")
console.errorColor(`Expected: ${matchInfo.actualAnchorOffset} to be ${matchInfo.expectedAnchorOffset}`);
allMatched = false;
}
if (!matchInfo.focusOffsetMatch) {
console.errorColor("\nFocus offsets don't match")
console.errorColor(`Expected: ${matchInfo.actualFocusOffset} to be ${matchInfo.expectedFocusOffset}`);
allMatched = false;
}
outMsgDescription = "matched. See discrepancies above"
if (allMatched) { outMsg = outMsgDescription
} else { outMsg = "Selection" }
// "Expected Selection to be matched. See discrepancies above"
expect(outMsg).toBe(outMsgDescription);
}) })
} }
} }

View file

@ -1,5 +1,4 @@
import path from 'path' import path from 'path'
import Promise from 'bluebird'
import {Application} from 'spectron'; import {Application} from 'spectron';
class N1Launcher extends Application { class N1Launcher extends Application {
@ -46,7 +45,7 @@ class N1Launcher extends Application {
return NylasEnv.getLoadSettings().windowType; return NylasEnv.getLoadSettings().windowType;
}).then(({value})=>{ }).then(({value})=>{
if(value === "composer") { if(value === "composer") {
return client.isWindowVisible() return client.isExisting(".contenteditable")
} else { } else {
return false return false
} }

View file

@ -12,6 +12,7 @@
"bluebird": "^3.0.5", "bluebird": "^3.0.5",
"babel-core": "^5.8.21", "babel-core": "^5.8.21",
"jasmine": "^2.3.2", "jasmine": "^2.3.2",
"spectron": "^0.34.1" "spectron": "^0.34.1",
"chalk": "^1.1"
} }
} }