mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-01-30 11:59:02 +08:00
test(contenteditable): add in contenteditable list specs
This commit is contained in:
parent
40e143e3f2
commit
ced66902d5
6 changed files with 206 additions and 76 deletions
|
@ -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);
|
||||||
});
|
});
|
||||||
|
|
29
spec_integration/bootstrap.js
vendored
29
spec_integration/bootstrap.js
vendored
|
@ -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);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
|
@ -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. <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: "* <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: "- <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)
|
||||||
|
// });
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("has main window visible", (done)=> {
|
|
||||||
this.app.client.isWindowVisible()
|
|
||||||
.then((result)=>{ expect(result).toBe(true) })
|
|
||||||
.finally(done)
|
|
||||||
});
|
|
||||||
|
|
||||||
it("has main window focused", (done)=> {
|
|
||||||
this.app.client.isWindowFocused()
|
|
||||||
.then((result)=>{ expect(result).toBe(true) })
|
|
||||||
.finally(done)
|
|
||||||
});
|
|
||||||
|
|
||||||
it("isn't minimized", (done)=> {
|
describe('Ensuring popout composer window works', () => {
|
||||||
this.app.client.isWindowMinimized()
|
it("has main window visible", (done)=> {
|
||||||
.then((result)=>{ expect(result).toBe(false) })
|
this.app.client.isWindowVisible()
|
||||||
.finally(done)
|
.then((result)=>{ expect(result).toBe(true) })
|
||||||
});
|
.then(done).catch(done.fail)
|
||||||
|
});
|
||||||
|
|
||||||
it("doesn't have the dev tools open", (done)=> {
|
it("has main window focused", (done)=> {
|
||||||
this.app.client.isWindowDevToolsOpened()
|
this.app.client.isWindowFocused()
|
||||||
.then((result)=>{ expect(result).toBe(false) })
|
.then((result)=>{ expect(result).toBe(true) })
|
||||||
.finally(done)
|
.then(done).catch(done.fail)
|
||||||
});
|
});
|
||||||
|
|
||||||
it("has width", (done)=> {
|
it("isn't minimized", (done)=> {
|
||||||
this.app.client.getWindowWidth()
|
this.app.client.isWindowMinimized()
|
||||||
.then((result)=>{ expect(result).toBeGreaterThan(0) })
|
.then((result)=>{ expect(result).toBe(false) })
|
||||||
.finally(done)
|
.then(done).catch(done.fail)
|
||||||
});
|
});
|
||||||
|
|
||||||
it("has height", (done)=> {
|
it("doesn't have the dev tools open", (done)=> {
|
||||||
this.app.client.getWindowHeight()
|
this.app.client.isWindowDevToolsOpened()
|
||||||
.then((result)=>{ expect(result).toBeGreaterThan(0) })
|
.then((result)=>{ expect(result).toBe(false) })
|
||||||
.finally(done)
|
.then(done).catch(done.fail)
|
||||||
|
});
|
||||||
|
|
||||||
|
it("has width", (done)=> {
|
||||||
|
this.app.client.getWindowWidth()
|
||||||
|
.then((result)=>{ expect(result).toBeGreaterThan(0) })
|
||||||
|
.then(done).catch(done.fail)
|
||||||
|
});
|
||||||
|
|
||||||
|
it("has height", (done)=> {
|
||||||
|
this.app.client.getWindowHeight()
|
||||||
|
.then((result)=>{ expect(result).toBeGreaterThan(0) })
|
||||||
|
.then(done).catch(done.fail)
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue