Initial test suite
This commit is contained in:
parent
e1f145e8e2
commit
15911b5177
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"node": true,
|
||||||
|
"browser": true,
|
||||||
|
"esnext": true,
|
||||||
|
"camelcase": true,
|
||||||
|
"immed": true,
|
||||||
|
"indent": 2,
|
||||||
|
"latedef": true,
|
||||||
|
"noarg": true,
|
||||||
|
"quotmark": "single",
|
||||||
|
"regexp": true,
|
||||||
|
"undef": false,
|
||||||
|
"latedef": "nofunc",
|
||||||
|
"noempty": true,
|
||||||
|
"trailing": true,
|
||||||
|
"maxparams": 20,
|
||||||
|
"maxdepth": 5,
|
||||||
|
"smarttabs": true,
|
||||||
|
"asi": true,
|
||||||
|
"boss": true,
|
||||||
|
"laxcomma": true,
|
||||||
|
"laxbreak": true,
|
||||||
|
"expr": true,
|
||||||
|
"eqnull": true,
|
||||||
|
"loopfunc": true
|
||||||
|
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
93
gulpfile.js
93
gulpfile.js
|
@ -1,104 +1,113 @@
|
||||||
var gulp = require('gulp')
|
var gulp = require('gulp')
|
||||||
, path = require('path')
|
, path = require('path')
|
||||||
, merge = require('event-stream').merge
|
, merge = require('event-stream').merge
|
||||||
, series = require('stream-series')
|
, map = require('map-stream')
|
||||||
, map = require('map-stream')
|
, spawn = require('child_process').spawn
|
||||||
, Crx = require('crx')
|
, $ = require('gulp-load-plugins')()
|
||||||
, $ = require('gulp-load-plugins')()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Public tasks
|
* Public tasks
|
||||||
*/
|
*/
|
||||||
gulp.task('clean', function() {
|
gulp.task('clean', function () {
|
||||||
return pipe('./tmp', [$.clean()])
|
return pipe('./tmp', [$.clean()])
|
||||||
})
|
})
|
||||||
|
|
||||||
gulp.task('build', function(cb) {
|
gulp.task('build', function (cb) {
|
||||||
$.runSequence('clean', 'css', 'chrome', 'opera', 'safari', 'firefox', cb)
|
$.runSequence('clean', 'css', 'chrome', 'opera', 'safari', 'firefox', cb)
|
||||||
})
|
})
|
||||||
|
|
||||||
gulp.task('default', ['build'], function() {
|
gulp.task('default', ['build'], function () {
|
||||||
gulp.watch(['./src/**/*'], ['default'])
|
gulp.watch(['./src/**/*'], ['default'])
|
||||||
})
|
})
|
||||||
|
|
||||||
gulp.task('dist', ['build'], function(cb) {
|
gulp.task('dist', ['build'], function (cb) {
|
||||||
$.runSequence('firefox:xpi', 'chrome:zip', 'chrome:crx', 'opera:nex', cb)
|
$.runSequence('firefox:xpi', 'chrome:zip', 'chrome:crx', 'opera:nex', cb)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
gulp.task('test', function (cb) {
|
||||||
|
var ps = spawn(
|
||||||
|
'./node_modules/.bin/mocha',
|
||||||
|
['--harmony', '--reporter', 'spec', '--bail', '--recursive', '--timeout', '-1']
|
||||||
|
)
|
||||||
|
ps.stdout.pipe(process.stdout);
|
||||||
|
ps.stderr.pipe(process.stderr);
|
||||||
|
ps.on('close', cb)
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private tasks
|
* Private tasks
|
||||||
*/
|
*/
|
||||||
gulp.task('css', function() {
|
gulp.task('css', function () {
|
||||||
return pipe('./src/octotree.less', [$.less(), $.autoprefixer({ cascade: true })], './tmp')
|
return pipe('./src/octotree.less', [$.less(), $.autoprefixer({cascade: true})], './tmp')
|
||||||
})
|
})
|
||||||
|
|
||||||
// Chrome
|
// Chrome
|
||||||
gulp.task('chrome:template', function() {
|
gulp.task('chrome:template', function () {
|
||||||
return buildTemplate({ CHROME: true })
|
return buildTemplate({CHROME: true})
|
||||||
})
|
})
|
||||||
|
|
||||||
gulp.task('chrome:js', ['chrome:template'], function() {
|
gulp.task('chrome:js', ['chrome:template'], function () {
|
||||||
return buildJs(['./src/chrome/storage.js'], { CHROME: true })
|
return buildJs(['./src/chrome/storage.js'], {CHROME: true})
|
||||||
})
|
})
|
||||||
|
|
||||||
gulp.task('chrome', ['chrome:js'], function() {
|
gulp.task('chrome', ['chrome:js'], function () {
|
||||||
return merge(
|
return merge(
|
||||||
pipe('./icons/**/*', './tmp/chrome/icons'),
|
pipe('./icons/**/*', './tmp/chrome/icons'),
|
||||||
pipe(['./libs/**/*', './tmp/octotree.*', './src/chrome/**/*', '!./src/chrome/storage.js'], './tmp/chrome/')
|
pipe(['./libs/**/*', './tmp/octotree.*', './src/chrome/**/*', '!./src/chrome/storage.js'], './tmp/chrome/')
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
gulp.task('chrome:zip', function() {
|
gulp.task('chrome:zip', function () {
|
||||||
return pipe('./tmp/chrome/**/*', [$.zip('chrome.zip')], './dist')
|
return pipe('./tmp/chrome/**/*', [$.zip('chrome.zip')], './dist')
|
||||||
})
|
})
|
||||||
|
|
||||||
gulp.task('chrome:_crx', function(cb) {
|
gulp.task('chrome:_crx', function (cb) {
|
||||||
$.run('"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"' +
|
$.run('"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"' +
|
||||||
' --pack-extension=' + path.join(__dirname, './tmp/chrome') +
|
' --pack-extension=' + path.join(__dirname, './tmp/chrome') +
|
||||||
' --pack-extension-key=' + path.join(process.env.HOME, '.ssh/chrome.pem')
|
' --pack-extension-key=' + path.join(process.env.HOME, '.ssh/chrome.pem')
|
||||||
).exec(cb)
|
).exec(cb)
|
||||||
})
|
})
|
||||||
|
|
||||||
gulp.task('chrome:crx', ['chrome:_crx'], function() {
|
gulp.task('chrome:crx', ['chrome:_crx'], function () {
|
||||||
return pipe('./tmp/chrome.crx', './dist')
|
return pipe('./tmp/chrome.crx', './dist')
|
||||||
})
|
})
|
||||||
|
|
||||||
// Opera
|
// Opera
|
||||||
gulp.task('opera', ['chrome'], function() {
|
gulp.task('opera', ['chrome'], function () {
|
||||||
return pipe('./tmp/chrome/**/*', './tmp/opera')
|
return pipe('./tmp/chrome/**/*', './tmp/opera')
|
||||||
})
|
})
|
||||||
|
|
||||||
gulp.task('opera:nex', function() {
|
gulp.task('opera:nex', function () {
|
||||||
return pipe('./dist/chrome.crx', [$.rename('opera.nex')], './dist')
|
return pipe('./dist/chrome.crx', [$.rename('opera.nex')], './dist')
|
||||||
})
|
})
|
||||||
|
|
||||||
// Safari
|
// Safari
|
||||||
gulp.task('safari:template', function() {
|
gulp.task('safari:template', function () {
|
||||||
return buildTemplate({ SAFARI: true })
|
return buildTemplate({SAFARI: true})
|
||||||
})
|
})
|
||||||
|
|
||||||
gulp.task('safari:js', ['safari:template'], function() {
|
gulp.task('safari:js', ['safari:template'], function () {
|
||||||
return buildJs(['./src/safari/storage.js'], { SAFARI: true })
|
return buildJs(['./src/safari/storage.js'], {SAFARI: true})
|
||||||
})
|
})
|
||||||
|
|
||||||
gulp.task('safari', ['safari:js'], function() {
|
gulp.task('safari', ['safari:js'], function () {
|
||||||
return merge(
|
return merge(
|
||||||
pipe('./icons/**/*', './tmp/safari/octotree.safariextension/icons'),
|
pipe('./icons/**/*', './tmp/safari/octotree.safariextension/icons'),
|
||||||
pipe(['./libs/**/*', './tmp/octotree.js', './tmp/octotree.css',
|
pipe(['./libs/**/*', './tmp/octotree.js', './tmp/octotree.css',
|
||||||
'./src/safari/**/*', '!./src/safari/storage.js'], './tmp/safari/octotree.safariextension/')
|
'./src/safari/**/*', '!./src/safari/storage.js'], './tmp/safari/octotree.safariextension/')
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Firefox
|
// Firefox
|
||||||
gulp.task('firefox:template', function() {
|
gulp.task('firefox:template', function () {
|
||||||
return buildTemplate({ FIREFOX: true })
|
return buildTemplate({FIREFOX: true})
|
||||||
})
|
})
|
||||||
|
|
||||||
gulp.task('firefox:js', ['firefox:template'], function() {
|
gulp.task('firefox:js', ['firefox:template'], function () {
|
||||||
return buildJs(['./src/firefox/storage.js'], { FIREFOX: true })
|
return buildJs(['./src/firefox/storage.js'], {FIREFOX: true})
|
||||||
})
|
})
|
||||||
|
|
||||||
gulp.task('firefox', ['firefox:js'], function() {
|
gulp.task('firefox', ['firefox:js'], function () {
|
||||||
return merge(
|
return merge(
|
||||||
pipe('./icons/**/*', './tmp/firefox/data/icons'),
|
pipe('./icons/**/*', './tmp/firefox/data/icons'),
|
||||||
pipe(['./libs/**/*', './tmp/octotree.js', './tmp/octotree.css'], './tmp/firefox/data'),
|
pipe(['./libs/**/*', './tmp/octotree.js', './tmp/octotree.css'], './tmp/firefox/data'),
|
||||||
|
@ -107,7 +116,7 @@ gulp.task('firefox', ['firefox:js'], function() {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
gulp.task('firefox:xpi', function(cb) {
|
gulp.task('firefox:xpi', function (cb) {
|
||||||
$.run('cd ./tmp/firefox && cfx xpi --output-file=../../dist/firefox.xpi').exec(cb)
|
$.run('cd ./tmp/firefox && cfx xpi --output-file=../../dist/firefox.xpi').exec(cb)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -120,7 +129,7 @@ function pipe(src, transforms, dest) {
|
||||||
transforms = null
|
transforms = null
|
||||||
}
|
}
|
||||||
var stream = gulp.src(src)
|
var stream = gulp.src(src)
|
||||||
transforms && transforms.forEach(function(transform) {
|
transforms && transforms.forEach(function (transform) {
|
||||||
stream = stream.pipe(transform)
|
stream = stream.pipe(transform)
|
||||||
})
|
})
|
||||||
if (dest) stream = stream.pipe(gulp.dest(dest))
|
if (dest) stream = stream.pipe(gulp.dest(dest))
|
||||||
|
@ -134,8 +143,8 @@ function html2js(template) {
|
||||||
var path = $.util.replaceExtension(file.path, '.js')
|
var path = $.util.replaceExtension(file.path, '.js')
|
||||||
, content = file.contents.toString()
|
, content = file.contents.toString()
|
||||||
, escaped = content.replace(/\\/g, "\\\\")
|
, escaped = content.replace(/\\/g, "\\\\")
|
||||||
.replace(/'/g, "\\'")
|
.replace(/'/g, "\\'")
|
||||||
.replace(/\r?\n/g, "\\n' +\n '")
|
.replace(/\r?\n/g, "\\n' +\n '")
|
||||||
, body = template.replace('$$', escaped)
|
, body = template.replace('$$', escaped)
|
||||||
file.path = path
|
file.path = path
|
||||||
file.contents = new Buffer(body)
|
file.contents = new Buffer(body)
|
||||||
|
@ -159,13 +168,13 @@ function buildJs(additions, ctx) {
|
||||||
])
|
])
|
||||||
return pipe(src, [
|
return pipe(src, [
|
||||||
$.concat('octotree.js'),
|
$.concat('octotree.js'),
|
||||||
$.preprocess({ context: ctx })
|
$.preprocess({context: ctx})
|
||||||
], './tmp')
|
], './tmp')
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildTemplate(ctx) {
|
function buildTemplate(ctx) {
|
||||||
return pipe('./src/template.html', [
|
return pipe('./src/template.html', [
|
||||||
$.preprocess({ context: ctx }),
|
$.preprocess({context: ctx}),
|
||||||
html2js('const TEMPLATE = \'$$\'')
|
html2js('const TEMPLATE = \'$$\'')
|
||||||
], './tmp')
|
], './tmp')
|
||||||
}
|
}
|
||||||
|
|
12
package.json
12
package.json
|
@ -32,6 +32,16 @@
|
||||||
"gulp-run": "^1.6.4",
|
"gulp-run": "^1.6.4",
|
||||||
"gulp-zip": "^2.0.1",
|
"gulp-zip": "^2.0.1",
|
||||||
"crx": "^0.4.4",
|
"crx": "^0.4.4",
|
||||||
"gulp-rename": "^1.2.0"
|
"gulp-rename": "^1.2.0",
|
||||||
|
"mocha": "^2.0.1",
|
||||||
|
"selenium-webdriver": "^2.44.0",
|
||||||
|
"gulp-mocha": "^2.0.0",
|
||||||
|
"gulp-exit": "0.0.2",
|
||||||
|
"starx": "~0.1.7",
|
||||||
|
"request": "~2.48.0",
|
||||||
|
"underscore": "~1.7.0",
|
||||||
|
"underscore.string": "~2.4.0",
|
||||||
|
"firefox-profile": "~0.3.6",
|
||||||
|
"async": "~0.9.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ const
|
||||||
WIDTH : 250,
|
WIDTH : 250,
|
||||||
POPUP : false,
|
POPUP : false,
|
||||||
SHOWN : false,
|
SHOWN : false,
|
||||||
NONCODE : false,
|
NONCODE : false,
|
||||||
}
|
}
|
||||||
|
|
||||||
, EVENT = {
|
, EVENT = {
|
||||||
|
|
|
@ -12,11 +12,11 @@ HelpPopup.prototype.show = function() {
|
||||||
|
|
||||||
$view.css('display', 'block').appendTo($('body'))
|
$view.css('display', 'block').appendTo($('body'))
|
||||||
|
|
||||||
|
$(document).one(EVENT.TOGGLE, hide)
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
store.set(STORE.POPUP, true)
|
store.set(STORE.POPUP, true)
|
||||||
$view.addClass('show').click(hide)
|
$view.addClass('show').click(hide)
|
||||||
$(document).one(EVENT.TOGGLE, hide)
|
setTimeout(hide, 12000)
|
||||||
setTimeout(hide, 5000)
|
|
||||||
}, 500)
|
}, 500)
|
||||||
|
|
||||||
function hide() {
|
function hide() {
|
||||||
|
|
|
@ -44,22 +44,25 @@ function OptionsView($dom, store) {
|
||||||
*/
|
*/
|
||||||
// @ifdef CHROME
|
// @ifdef CHROME
|
||||||
var $ta = $view.find('[data-store=GHEURLS]')
|
var $ta = $view.find('[data-store=GHEURLS]')
|
||||||
, urls = $ta.val().split(/\n/)
|
, urls = $ta.val().split(/\n/).filter(function (url) { return url !== '' })
|
||||||
chrome.runtime.sendMessage({ type: 'requestPermissions', urls: urls }, function(granted) {
|
|
||||||
if (granted) saveOptions()
|
if (urls.length > 0) {
|
||||||
else {
|
chrome.runtime.sendMessage({type: 'requestPermissions', urls: urls}, function (granted) {
|
||||||
// permissions not granted (by user or error), reset value
|
if (granted) saveOptions()
|
||||||
$ta.val(store.get(STORE.GHEURLS))
|
else {
|
||||||
saveOptions()
|
// permissions not granted (by user or error), reset value
|
||||||
}
|
$ta.val(store.get(STORE.GHEURLS))
|
||||||
})
|
saveOptions()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
// @endif
|
// @endif
|
||||||
|
|
||||||
// @ifndef CHROME
|
return saveOptions()
|
||||||
saveOptions()
|
|
||||||
// @endif
|
|
||||||
|
|
||||||
function saveOptions() {
|
function saveOptions() {
|
||||||
|
console.log('save')
|
||||||
var changes = {}
|
var changes = {}
|
||||||
eachOption(
|
eachOption(
|
||||||
function($elm, key, local, value, cb) {
|
function($elm, key, local, value, cb) {
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
require('./helper')
|
||||||
|
|
||||||
|
const SELENIUM_SERVER_PATH = path.resolve(__dirname, './selenium/selenium-server-standalone-2.43.1.jar')
|
||||||
|
const CHROME_DRIVER_PATH = path.resolve(__dirname, './selenium/chromedriver')
|
||||||
|
const CHROME_CRX_PATH = path.resolve(__dirname, '../dist/chrome.crx')
|
||||||
|
const FIREFOX_XPI_PATH = path.resolve(__dirname, '../dist/firefox.xpi')
|
||||||
|
|
||||||
|
exports.chromeDriver = function (cb) {
|
||||||
|
var options = new chrome.Options()
|
||||||
|
options.addExtensions(CHROME_CRX_PATH)
|
||||||
|
var service = new chrome.ServiceBuilder(CHROME_DRIVER_PATH).build()
|
||||||
|
cb(null, chrome.createDriver(options, service))
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.firefoxDriver = function (cb) {
|
||||||
|
var server = new SeleniumServer(SELENIUM_SERVER_PATH, {port: 4444})
|
||||||
|
server.start()
|
||||||
|
|
||||||
|
var profile = new FirefoxProfile();
|
||||||
|
profile.addExtension(FIREFOX_XPI_PATH, function () {
|
||||||
|
profile.encoded(function (profile) {
|
||||||
|
var capabilities = webdriver.Capabilities.firefox()
|
||||||
|
capabilities.set('firefox_profile', profile);
|
||||||
|
var driver = new webdriver.Builder()
|
||||||
|
.usingServer(server.address())
|
||||||
|
.withCapabilities(capabilities)
|
||||||
|
.build()
|
||||||
|
driver.server = server
|
||||||
|
cb(null, driver)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
global.assert = require('assert')
|
||||||
|
global.path = require('path')
|
||||||
|
global.request = require('request')
|
||||||
|
global.async = require('async')
|
||||||
|
global._ = require('underscore')
|
||||||
|
global._s = require('underscore.string')
|
||||||
|
|
||||||
|
global.starx = require('starx')
|
||||||
|
global.sleep = starx.sleep
|
||||||
|
global.yieldable = starx.yieldable
|
||||||
|
|
||||||
|
global.webdriver = require('selenium-webdriver')
|
||||||
|
global.test = require('selenium-webdriver/testing')
|
||||||
|
global.chrome = require('selenium-webdriver/chrome')
|
||||||
|
global.firefox = require('selenium-webdriver/firefox')
|
||||||
|
global.FirefoxProfile = require('firefox-profile')
|
||||||
|
global.SeleniumServer = require('selenium-webdriver/remote').SeleniumServer
|
||||||
|
|
||||||
|
global.$tag = webdriver.By.tagName
|
||||||
|
global.$css = webdriver.By.css
|
||||||
|
global.$id = webdriver.By.id
|
||||||
|
global.$xpath = webdriver.By.xpath
|
||||||
|
global.$class = webdriver.By.className
|
||||||
|
|
||||||
|
global.yit = function (title, block) {
|
||||||
|
it(title, function (cb) {
|
||||||
|
starx(block)(cb)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
global.rand = function (arr) {
|
||||||
|
return arr[Math.floor(Math.random() * arr.length)]
|
||||||
|
}
|
||||||
|
|
||||||
|
global.getJson = function (url, token, cb) {
|
||||||
|
var headers = {
|
||||||
|
'User-Agent': 'buunguyen/octotree (unit test)'
|
||||||
|
}
|
||||||
|
if (token) headers.Authorization = 'token ' + token
|
||||||
|
|
||||||
|
request({
|
||||||
|
url : url,
|
||||||
|
headers: headers
|
||||||
|
}, function (err, response, body) {
|
||||||
|
if (err) return cb(err)
|
||||||
|
cb(null, JSON.parse(body))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
global.isGenerator = function (fn) {
|
||||||
|
return fn.constructor.name === 'GeneratorFunction'
|
||||||
|
}
|
|
@ -0,0 +1,160 @@
|
||||||
|
require('./helper')
|
||||||
|
|
||||||
|
module.exports = PageObject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PageObject
|
||||||
|
* @param driver
|
||||||
|
* @param repoUrl
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function PageObject(driver, repoUrl) {
|
||||||
|
this.driver = driver
|
||||||
|
this.one = driver.findElement.bind(driver)
|
||||||
|
this.all = driver.findElements.bind(driver)
|
||||||
|
this.repoUrl = repoUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
PageObject.prototype = {
|
||||||
|
getUrl: function *() {
|
||||||
|
return yield this.driver.getCurrentUrl()
|
||||||
|
},
|
||||||
|
|
||||||
|
setUrl: function *(url) {
|
||||||
|
var driver = this.driver
|
||||||
|
driver.get(url)
|
||||||
|
yield driver.wait(function () {
|
||||||
|
return driver.getCurrentUrl().then(function (_url) {
|
||||||
|
return url === _url
|
||||||
|
})
|
||||||
|
}, 5000)
|
||||||
|
},
|
||||||
|
|
||||||
|
close: function *() {
|
||||||
|
if (this.driver.server) this.driver.server.close()
|
||||||
|
yield this.driver.quit()
|
||||||
|
},
|
||||||
|
|
||||||
|
reset: function *() {
|
||||||
|
yield this.setUrl(this.repoUrl)
|
||||||
|
},
|
||||||
|
|
||||||
|
refresh: function *() {
|
||||||
|
yield this.driver.navigate().refresh()
|
||||||
|
yield sleep(100)
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleSidebar: function *() {
|
||||||
|
yield this.toggleButton.click()
|
||||||
|
yield sleep(100) // transition
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleOptsView: function *() {
|
||||||
|
yield this.optsButton.click()
|
||||||
|
},
|
||||||
|
|
||||||
|
isSidebarShown: function *() {
|
||||||
|
var hasCssClass = yield this.driver.isElementPresent($css('html.octotree'))
|
||||||
|
var btnRight = yield this.toggleButton.getCssValue('right')
|
||||||
|
return hasCssClass && btnRight === '5px'
|
||||||
|
},
|
||||||
|
|
||||||
|
isSidebarHidden: function *() {
|
||||||
|
var hasCssClass = yield this.driver.isElementPresent($css('html.octotree'))
|
||||||
|
var btnRight = yield this.toggleButton.getCssValue('right')
|
||||||
|
return !hasCssClass && btnRight === '-35px'
|
||||||
|
},
|
||||||
|
|
||||||
|
saveSettings: function *() {
|
||||||
|
yield this.saveButton.click()
|
||||||
|
yield sleep(500) // transition + async storage
|
||||||
|
},
|
||||||
|
|
||||||
|
nodeFor: function (path) {
|
||||||
|
return this.one($id('octotree' + path))
|
||||||
|
},
|
||||||
|
|
||||||
|
childrenOfNode: function (node) {
|
||||||
|
return node.findElements($css('.jstree-children li'))
|
||||||
|
},
|
||||||
|
|
||||||
|
isNodeSelected: function *(node) {
|
||||||
|
return yield node.findElement($css('.jstree-wholerow-clicked')).isDisplayed()
|
||||||
|
},
|
||||||
|
|
||||||
|
isNodeOpen: function *(node) {
|
||||||
|
var classes = yield node.getAttribute('class')
|
||||||
|
return ~classes.indexOf('jstree-open')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UI elements
|
||||||
|
var controls = {
|
||||||
|
ghBreadcrumb : '.breadcrumb .final-path',
|
||||||
|
ghSearch : '.js-site-search-field',
|
||||||
|
|
||||||
|
helpPopup : '.octotree_popup',
|
||||||
|
toggleButton : '.octotree_toggle',
|
||||||
|
sidebar : '.octotree_sidebar',
|
||||||
|
|
||||||
|
treeView : '.octotree_treeview',
|
||||||
|
treeHeaderLinks : '.octotree_header_repo a',
|
||||||
|
treeNodes : '.jstree .jstree-node',
|
||||||
|
|
||||||
|
optsButton : '.octotree_opts',
|
||||||
|
optsView : '.octotree_optsview',
|
||||||
|
tokenInput : '//input[@data-store="TOKEN"]',
|
||||||
|
hotkeysInput : '//input[@data-store="HOTKEYS"]',
|
||||||
|
rememberCheck : '//input[@data-store="REMEMBER"]',
|
||||||
|
nonCodeCheck : '//input[@data-store="NONCODE"]',
|
||||||
|
saveButton : '.octotree_optsview .button',
|
||||||
|
|
||||||
|
errorView : '.octotree_errorview',
|
||||||
|
errorViewHeader : '.octotree_errorview .octotree_view_header'
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.keys(controls).forEach(function (name) {
|
||||||
|
var selector = controls[name]
|
||||||
|
, met = name.indexOf('s') === name.length - 1 ? 'all' : 'one'
|
||||||
|
, sel = selector.indexOf('//') === 0 ? $xpath : $css
|
||||||
|
, cond = sel(selector)
|
||||||
|
|
||||||
|
Object.defineProperty(PageObject.prototype, name, {
|
||||||
|
get: function () {
|
||||||
|
return new WebElementPromiseWrapper(this.driver, this[met](cond), cond)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebElementPromiseWrapper
|
||||||
|
* @param driver
|
||||||
|
* @param wep
|
||||||
|
* @param cond
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function WebElementPromiseWrapper(driver, wep, cond) {
|
||||||
|
this.driver = driver
|
||||||
|
this.wep = wep
|
||||||
|
this.cond = cond
|
||||||
|
}
|
||||||
|
|
||||||
|
WebElementPromiseWrapper.prototype.then = function () {
|
||||||
|
return this.wep.then.apply(this.wep, arguments)
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.keys(webdriver.WebElement.prototype).forEach(function (prop) {
|
||||||
|
if (_.isFunction(webdriver.WebElement.prototype[prop])) {
|
||||||
|
WebElementPromiseWrapper.prototype[prop] = function *() {
|
||||||
|
var driver = this.driver
|
||||||
|
, wep = this.wep
|
||||||
|
, cond = this.cond
|
||||||
|
|
||||||
|
yield driver.wait(function () {
|
||||||
|
return driver.isElementPresent(cond) // TODO: vary condition per action
|
||||||
|
}, 5000)
|
||||||
|
var elm = yield wep
|
||||||
|
return yield elm[prop].apply(elm, arguments)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,254 @@
|
||||||
|
require('./helper')
|
||||||
|
|
||||||
|
var factory = require('./factory')
|
||||||
|
, PageObject = require('./pageobject')
|
||||||
|
, token = process.env.GHPAT
|
||||||
|
, files
|
||||||
|
|
||||||
|
before(function (cb) {
|
||||||
|
getJson('https://api.github.com/repos/buunguyen/octotree/git/trees/master?recursive=true', token, function (err, data) {
|
||||||
|
if (err) return cb(err)
|
||||||
|
files = data.tree
|
||||||
|
cb()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
;['chrome'/*, 'firefox'*/].forEach(runTest)
|
||||||
|
|
||||||
|
function runTest(browser) {
|
||||||
|
var driver, po
|
||||||
|
|
||||||
|
describe(browser, function () {
|
||||||
|
before(function (cb) {
|
||||||
|
starx(function *() {
|
||||||
|
driver = yield factory[browser + 'Driver']
|
||||||
|
po = new PageObject(driver, 'https://github.com/buunguyen/octotree')
|
||||||
|
})(cb)
|
||||||
|
})
|
||||||
|
|
||||||
|
after(function (cb) {
|
||||||
|
starx(function *() {
|
||||||
|
yield po.close()
|
||||||
|
})(cb)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('init', function () {
|
||||||
|
before(function (cb) {
|
||||||
|
starx(function *() {
|
||||||
|
yield po.reset()
|
||||||
|
})(cb)
|
||||||
|
})
|
||||||
|
|
||||||
|
yit('should create toggle button and sidebar', function *() {
|
||||||
|
assert.ok(yield po.toggleButton.isDisplayed())
|
||||||
|
assert.equal(yield po.sidebar.getCssValue('width'), '251px')
|
||||||
|
})
|
||||||
|
|
||||||
|
yit('should display help popup', function *() {
|
||||||
|
assert.ok(yield po.helpPopup.isDisplayed())
|
||||||
|
})
|
||||||
|
|
||||||
|
yit('should toggle upon button click', function *() {
|
||||||
|
yield po.toggleSidebar()
|
||||||
|
assert.ok(yield po.isSidebarShown())
|
||||||
|
|
||||||
|
yield po.toggleSidebar()
|
||||||
|
assert.ok(yield po.isSidebarHidden())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('main', function () {
|
||||||
|
before(function (cb) {
|
||||||
|
starx(function *() {
|
||||||
|
yield po.reset()
|
||||||
|
yield po.toggleSidebar()
|
||||||
|
if (token) {
|
||||||
|
yield po.toggleOptsView()
|
||||||
|
yield po.tokenInput.sendKeys(token)
|
||||||
|
yield po.saveSettings()
|
||||||
|
}
|
||||||
|
})(cb)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('tree', function () {
|
||||||
|
yit('should show tree view by default', function *() {
|
||||||
|
assert.ok(~(yield po.treeView.getAttribute('class')).indexOf('current'))
|
||||||
|
})
|
||||||
|
|
||||||
|
yit('should show repository information', function *() {
|
||||||
|
var links = yield po.treeHeaderLinks
|
||||||
|
assert.equal(yield links[0].getText(), 'buunguyen')
|
||||||
|
assert.equal(yield links[1].getText(), 'octotree')
|
||||||
|
})
|
||||||
|
|
||||||
|
yit('should show code tree', function *() {
|
||||||
|
var nodes = yield po.treeNodes
|
||||||
|
var _files = files.filter(function (file) {
|
||||||
|
return file.path.indexOf('/') === -1
|
||||||
|
})
|
||||||
|
assert.ok(nodes.length, _files.length)
|
||||||
|
})
|
||||||
|
|
||||||
|
yit('should navigate to code files', function *() {
|
||||||
|
var seen = []
|
||||||
|
for (var i = 0; i < 3; i++) {
|
||||||
|
var someFile = rand(files.filter(function (file) {
|
||||||
|
return file.type === 'blob' && file.path.indexOf('/') === -1 && seen.indexOf(file) === -1
|
||||||
|
}))
|
||||||
|
seen.push(someFile)
|
||||||
|
|
||||||
|
var node = po.nodeFor(someFile.path)
|
||||||
|
yield node.click()
|
||||||
|
assert.ok(yield po.isNodeSelected(node))
|
||||||
|
assert.equal(yield po.getUrl(), 'https://github.com/buunguyen/octotree/blob/master/' + someFile.path)
|
||||||
|
yield sleep(200) // pjax
|
||||||
|
assert.equal(yield po.ghBreadcrumb.getText(), someFile.path)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
yit('should expand directories', function *() {
|
||||||
|
var seen = []
|
||||||
|
for (var i = 0; i < 3; i++) {
|
||||||
|
var someDir = rand(files.filter(function (file) {
|
||||||
|
return file.type === 'tree' && file.path.indexOf('/') === -1 && seen.indexOf(file) === -1
|
||||||
|
}))
|
||||||
|
seen.push(someDir)
|
||||||
|
var someDirChildren = files.filter(function (file) {
|
||||||
|
return file.path.indexOf(someDir.path) === 0 && _s.count(file.path, '/') === 1
|
||||||
|
})
|
||||||
|
|
||||||
|
yield po.nodeFor(someDir.path).click()
|
||||||
|
yield sleep(50) // tree expand transition
|
||||||
|
assert.ok(yield po.isNodeOpen(po.nodeFor(someDir.path)))
|
||||||
|
assert.equal((yield po.childrenOfNode(po.nodeFor(someDir.path))).length, someDirChildren.length)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
xit('should match branch', function () {
|
||||||
|
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('opts', function () {
|
||||||
|
yit('should toggle options view', function *() {
|
||||||
|
yield po.toggleOptsView()
|
||||||
|
assert.ok(~(yield po.optsButton.getAttribute('class')).indexOf('selected'))
|
||||||
|
assert.ok(~(yield po.optsView.getAttribute('class')).indexOf('current'))
|
||||||
|
|
||||||
|
yield po.toggleOptsView()
|
||||||
|
assert.ok(!~(yield po.optsButton.getAttribute('class')).indexOf('selected'))
|
||||||
|
assert.ok(!~(yield po.optsView.getAttribute('class')).indexOf('current'))
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('values', function () {
|
||||||
|
beforeEach(function(cb) {
|
||||||
|
starx(function *() {
|
||||||
|
yield po.toggleOptsView()
|
||||||
|
|
||||||
|
yield po.tokenInput.clear()
|
||||||
|
if (token) yield po.tokenInput.sendKeys(token)
|
||||||
|
|
||||||
|
yield po.hotkeysInput.clear()
|
||||||
|
|
||||||
|
if (yield po.rememberCheck.isSelected()) yield po.rememberCheck.click()
|
||||||
|
if (yield po.nonCodeCheck.isSelected()) yield po.nonCodeCheck.click()
|
||||||
|
|
||||||
|
yield po.saveSettings()
|
||||||
|
})(cb)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('token', function () {
|
||||||
|
yit('should show error if token is invalid', function *() {
|
||||||
|
yield po.toggleOptsView()
|
||||||
|
yield po.tokenInput.clear()
|
||||||
|
yield po.tokenInput.sendKeys('invalid token')
|
||||||
|
yield po.saveSettings()
|
||||||
|
|
||||||
|
assert.ok(~(yield po.errorView.getAttribute('class')).indexOf('current'))
|
||||||
|
assert.ok(~(yield po.errorViewHeader.getText(), 'Error: Invalid token'))
|
||||||
|
})
|
||||||
|
|
||||||
|
yit('should not show error if no token is given', function *() {
|
||||||
|
yield po.toggleOptsView()
|
||||||
|
yield po.tokenInput.clear()
|
||||||
|
yield po.saveSettings()
|
||||||
|
assert.ok(~(yield po.treeView.getAttribute('class')).indexOf('current'))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('hotkey', function () {
|
||||||
|
yit('should allow configure hotkey', function *() {
|
||||||
|
yield po.toggleOptsView()
|
||||||
|
yield po.hotkeysInput.clear()
|
||||||
|
yield po.hotkeysInput.sendKeys('`')
|
||||||
|
yield po.saveSettings()
|
||||||
|
|
||||||
|
// Hack: get error when sending key if not focusing on an element first
|
||||||
|
yield po.ghSearch.sendKeys('`')
|
||||||
|
yield sleep(100) // transition
|
||||||
|
assert.ok(yield po.isSidebarHidden())
|
||||||
|
|
||||||
|
yield po.ghSearch.sendKeys('`')
|
||||||
|
yield sleep(100) // transition
|
||||||
|
assert.ok(yield po.isSidebarShown())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('remember', function () {
|
||||||
|
yit('should remember sidebar state after reload', function *() {
|
||||||
|
yield po.toggleOptsView()
|
||||||
|
yield po.rememberCheck.click()
|
||||||
|
yield po.saveSettings()
|
||||||
|
yield po.refresh()
|
||||||
|
|
||||||
|
assert.ok(yield po.isSidebarShown())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('non-code', function () {
|
||||||
|
var pages = [
|
||||||
|
'https://github.com/buunguyen/octotree/issues',
|
||||||
|
'https://github.com/buunguyen/octotree/pulls',
|
||||||
|
'https://github.com/buunguyen/octotree/pulse',
|
||||||
|
'https://github.com/buunguyen/octotree/graphs/contributors'
|
||||||
|
]
|
||||||
|
|
||||||
|
yit('should hide in non-code pages', function *() {
|
||||||
|
for (var i = 0; pages[i]; i++) {
|
||||||
|
yield po.setUrl(pages[i])
|
||||||
|
assert.ok(yield po.isSidebarHidden())
|
||||||
|
}
|
||||||
|
yield po.reset()
|
||||||
|
yield po.toggleSidebar()
|
||||||
|
})
|
||||||
|
|
||||||
|
yit('should show in non-code pages if option is set', function *() {
|
||||||
|
yield po.toggleOptsView()
|
||||||
|
yield po.rememberCheck.click()
|
||||||
|
yield po.nonCodeCheck.click()
|
||||||
|
yield po.saveSettings()
|
||||||
|
|
||||||
|
for (var i = 0; pages[i]; i++) {
|
||||||
|
yield po.setUrl(pages[i])
|
||||||
|
assert.ok(yield po.isSidebarShown())
|
||||||
|
}
|
||||||
|
yield po.reset()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('lazy load', function () {
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('collapse', function () {
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('ghe', function () {
|
||||||
|
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue