Travis ui tests (#57)

* Prepare travis is tests

* Fix ffmpeg travis source

* Trying xenial

* Move shell scripts

* Upload video assets

* Upload video assets

* Change text input method

* Add ui test docker support

* Fix travis docker build

* Fix asset uploader

* Fix dockerfile

* Update dockerfile

* Change writeText behavior

* Fix type error

* Fix exit codes

* Fix types

* fix upload

* Fix writeText

* Fix argument name

* Add test scenarios

* Enable vnc and change mqtt host
This commit is contained in:
Thomas Nordquist
2019-01-30 03:13:19 -08:00
committed by GitHub
parent 0114d938bd
commit d64e085247
22 changed files with 397 additions and 1819 deletions

View File

@@ -14,6 +14,8 @@ if (!isDev) {
}
const isDebugEnabled = Boolean(process.argv.find(arg => arg === 'debug'))
const isFullscreen = Boolean(process.argv.find(arg => arg === '--fullscreen'))
require('electron-debug')({ enabled: isDebugEnabled })
autoUpdater.logger = log
@@ -41,7 +43,10 @@ function createWindow() {
})
mainWindow.once('ready-to-show', () => {
mainWindow && mainWindow.show()
if (mainWindow) {
isFullscreen && mainWindow.setFullScreen(true)
mainWindow.show()
}
})
console.log('icon path', iconPath)

View File

@@ -17,7 +17,7 @@ function startServer(): Promise<mqtt.MqttClient> {
function connectMqtt(): Promise<mqtt.MqttClient> {
return new Promise((resolve) => {
const client = mqtt.connect('mqtt://localhost:1883', { username: 'thomas', password: 'bierbier' })
const client = mqtt.connect('mqtt://127.0.0.1:1883', { username: 'thomas', password: 'bierbier' })
client.once('connect', () => {
resolve(client)
})
@@ -52,6 +52,15 @@ function generateData(client: mqtt.MqttClient) {
client.publish('livingroom/lamp-1/brightness', '48', { retain: true, qos: 0 })
client.publish('livingroom/lamp-2/state', 'off', { retain: true, qos: 0 })
client.publish('livingroom/lamp-2/brightness', '48', { retain: true, qos: 0 })
client.publish('kitchen/lamp/state', 'off', { retain: true, qos: 0 })
client.subscribe('kitchen/lamp/set')
client.on('message', (topic, payload) => {
if (topic === 'kitchen/lamp/set') {
setTimeout(() => client.publish('kitchen/lamp/state', payload, { retain: true, qos: 0 }), 500)
}
})
intervals.push(setInterval(() => client.publish('kitchen/temperature', temperature()), 1500))
intervals.push(setInterval(() => client.publish('kitchen/humidity', temperature(60, -5, 0)), 1800))
@@ -66,12 +75,32 @@ function generateData(client: mqtt.MqttClient) {
// Used for demonstrating "clean up"
client.publish('test 123', 'Hello world', { retain: true, qos: 0 })
client.publish('hello', 'sunshine', { retain: true, qos: 0 })
// Just stuff
client.publish('01-80-C2-00-00-0F/LWT', 'offline', { retain: true, qos: 0 })
intervals.push(setInterval(() => {
client.publish('3d-printer/OctoPrint/temperature/bed', '{"_timestamp":1548589083,"actual":25.9,"target":0}')
client.publish('3d-printer/OctoPrint/temperature/tool0', '{"_timestamp":1548589093,"actual":26.4,"target":0}')
}, 3333))
let state = true
intervals.push(setInterval(() => {
state = !state
const enitityId = Math.round(Math.random() * 3000)
client.publish(
'actuality/showcase', `{
"tags":{
"entityId":${enitityId},
"entityType":"person",
"host":"d44ad81e10f9",
"server":"${state ? 'http://localhost/dataActuality' : 'http://localhost/dataStorage' }",
"status":"${state ? 'live' : 'inactive'}"},
"timestamp":${Date.now()}
}`.replace(/\s/g, ''),
{ retain: true, qos: 0 },
)
}, 2102))
}
export default startServer

View File

@@ -0,0 +1,14 @@
import { clickOn, sleep, writeText, expandTopic, hideText } from '../util'
import { Browser } from 'webdriverio'
// Expects a topic with at least two messages to be selected
export async function compareJsonSideBySide(browser: Browser<void>) {
const firstEntry = await browser.$('//span[contains(text(), "History")]/../../div/div[1]/div')
const secondEntry = await browser.$('//span[contains(text(), "History")]/../../div/div[2]/div')
await clickOn(secondEntry, browser)
await sleep(2000)
await clickOn(firstEntry, browser)
await sleep(2000)
await clickOn(firstEntry, browser)
await sleep(1000)
}

View File

@@ -0,0 +1,7 @@
import { clickOn } from '../util'
import { Browser } from 'webdriverio'
export async function disconnect(browser: Browser<void>) {
const connectButton = await browser.$('//button/span[contains(text(),"Disconnect")]')
clickOn(connectButton, browser)
}

View File

@@ -0,0 +1,23 @@
import { clickOn, sleep, writeText, delteTextWithBackspaces, expandTopic, moveToCenterOfElement, showText } from '../util'
import { Browser } from 'webdriverio'
export async function publishTopic(browser: Browser<void>) {
await expandTopic('kitchen/lamp/state', browser)
const topicInput = await browser.$('//textarea[contains(text(),"kitchen/lamp/state")][2]')
await clickOn(topicInput, browser)
await delteTextWithBackspaces(topicInput, browser, 120, 5)
await writeText('set', browser, 300)
const payloadInput = await browser.$('//*[contains(@class, "ace_text-input")]')
await payloadInput.setValue('o')
await sleep(300)
await payloadInput.setValue('n')
await sleep(700)
const publishButton = await browser.$('#publish-button')
await moveToCenterOfElement(publishButton, browser)
await showText('Lamp turns on', 1000, browser, 'top')
await sleep(500)
await clickOn(publishButton, browser)
}

View File

@@ -1,8 +1,15 @@
import { clickOn, sleep, writeText } from '../util'
import { clickOn, sleep, writeText, delteTextWithBackspaces, showText } from '../util'
import { Browser } from 'webdriverio'
export async function searchTree(browser: Browser<void>) {
export async function searchTree(text: string, browser: Browser<void>) {
const searchField = await browser.$('//input[contains(@placeholder, "Search")]')
await clickOn(searchField, browser, 1)
writeText('temp', browser)
await writeText(text, browser, 100)
await sleep(1500)
}
export async function clearSearch(browser: Browser<void>) {
const searchField = await browser.$('//input[contains(@placeholder, "Search")]')
await clickOn(searchField, browser, 1)
await delteTextWithBackspaces(searchField, browser, 100)
}

View File

@@ -2,7 +2,7 @@ import { clickOn, sleep, writeText, expandTopic } from '../util'
import { Browser } from 'webdriverio'
export async function showJsonPreview(browser: Browser<void>) {
await expandTopic('3d-printer/OctoPrint/temperature/bed', browser)
await expandTopic('actuality/showcase', browser)
await sleep(1000)
}

View File

@@ -1,11 +1,10 @@
import { clickOn, sleep, writeText, expandTopic } from '../util'
import { clickOn, sleep, writeText, expandTopic, clickOnHistory } from '../util'
import { Browser } from 'webdriverio'
export async function showNumericPlot(browser: Browser<void>) {
await expandTopic('livingroom/temperature', browser)
const messageHistory = await browser.$('//span/*[contains(text(), "History")]')
await clickOn(messageHistory, browser, 1)
await clickOnHistory(browser)
await sleep(1000)
await expandTopic('livingroom/humidity', browser)

View File

@@ -1,17 +1,29 @@
import { Element, Browser } from 'webdriverio'
export { expandTopic } from './expandTopic'
export function sleep(ms: number) {
export function sleep(ms: number, required = false) {
return new Promise((resolve) => {
setTimeout(resolve, ms)
if (required) {
setTimeout(resolve, ms)
} else {
setTimeout(resolve, ms)
}
})
}
export function writeText(text: string, to: Browser<void>) {
text.split('').forEach(async (c) => {
await to.keys([c])
await sleep(50)
})
export async function writeText(text: string, browser: Browser<void>, delay = 0) {
for (const c of text.split('')) {
await browser.keys([c])
await sleep(delay)
}
}
export async function delteTextWithBackspaces(element: Element<void>, browser: Browser<void>, delay = 0, count = 0) {
const length = count > 0 ? count : (await element.getValue()).length
for (let i = 0; i < length; i += 1) {
await browser.keys(['Backspace'])
await sleep(delay)
}
}
export async function moveToCenterOfElement(element: Element<void>, browser: Browser<void>) {
@@ -37,22 +49,32 @@ export async function moveToCenterOfElement(element: Element<void>, browser: Bro
const stepY = deltaY / steps
let currentStep = 0
function getCloser() {
e.style.left = String(left + (stepX * currentStep)) + 5 + 'px'
e.style.top = String(top + (stepY * currentStep)) + 5 + 'px'
e.style.left = String(left + (stepX * currentStep)) + 'px'
e.style.top = String(top + (stepY * currentStep)) + 'px'
if (currentStep < steps) {
setTimeout(() => {
currentStep += 1
getCloser()
currentStep += 1
if (currentStep === steps) {
e.style.left = String(targetX + 5) + 'px'
e.style.top = String(targetY + 1) + 'px'
} else {
getCloser()
}
}, duration/steps)
}
}
getCloser()
}`
await browser.execute(js)
await sleep(550)
await sleep(550, true)
await element.moveTo()
}
export async function clickOnHistory(browser: Browser<void>) {
const messageHistory = await browser.$('//span/*[contains(text(), "History")]')
await clickOn(messageHistory, browser)
}
export async function clickOn(element: Element<void>, browser: Browser<void>, clicks = 1) {
await moveToCenterOfElement(element, browser)
for (let i = 0; i < clicks; i += 1) {
@@ -71,25 +93,24 @@ export async function createFakeMousePointer(browser: Browser<void>) {
+ 'document.body.appendChild(i)'
await browser.execute(addCursorImage)
const onMouseMove = `document.onmousemove = (event) => {
const e = document.getElementById('bier')
e.style.left = (event.pageX+1) + 'px'
e.style.top = event.pageY + 'px'
}`
await browser.execute(onMouseMove)
}
export async function showText(text: string, duration: number = 0, browser: Browser<void>) {
export async function showText(text: string, duration: number = 0, browser: Browser<void>, location: 'top' | 'bottom' | 'middle' = 'bottom') {
const positions = {
top: 0,
bottom: -65,
middle: -32,
}
const js = `
const postition = "${positions[location]}vh"
let previousDiv = document.getElementById('tests-text-overlay')
previousDiv && previousDiv.remove()
let div = document.createElement('div')
div.id = "tests-text-overlay"
div.style = "background-color: rgba(0, 0, 0, 0.8);position: fixed;left: 5vw;z-index: 1000000;margin: 30vw auto 50vw;border-radius: 16px;right: 5vw;bottom: -65vh;"
div.style = "background-color: rgba(0, 0, 0, 0.8);position: fixed;left: 5vw;z-index: 1000000;margin: 30vw auto 50vw;border-radius: 16px;right: 5vw;bottom: "+ postition +";"
let div2 = document.createElement('div')
div2.style = "text-align: center;font-size: 4em;color: white;"
div2.innerHTML = "${text}"
div2.innerHTML = \`${text}\`
div.appendChild(div2)
document.body.appendChild(div)
if (${duration} > 0) {

View File

@@ -1,22 +1,28 @@
process.on('unhandledRejection', (error: Error) => {
console.error('unhandledRejection', error.message, error.stack);
console.error('unhandledRejection', error.message, error.stack)
process.exit(1)
});
})
import * as webdriverio from 'webdriverio'
import * as os from 'os'
import mockMqtt, { stop } from './mock-mqtt'
import { connectTo } from './scenarios/connect'
import { disconnect } from './scenarios/disconnect'
import { showNumericPlot } from './scenarios/showNumericPlot'
import { showJsonPreview } from './scenarios/showJsonPreview'
import { compareJsonSideBySide } from './scenarios/compareJsonSideBySide'
import { searchTree, clearSearch } from './scenarios/searchTree'
import { copyTopicToClipboard } from './scenarios/copyTopicToClipboard'
import { copyValueToClipboard } from './scenarios/copyValueToClipboard'
import { publishTopic } from './scenarios/publishTopic'
import { clearOldTopics } from './scenarios/clearOldTopics'
import { showMenu } from './scenarios/showMenu'
import { createFakeMousePointer, sleep, showText, hideText } from './util'
import { createFakeMousePointer, sleep, showText, hideText, clickOnHistory } from './util'
const binary = os.platform() === 'darwin' ? 'Electron.app/Contents/MacOS/Electron' : 'electron'
const fullscreen = os.platform() === 'darwin' ? [] : ['--fullscreen']
const options = {
host: 'localhost', // Use localhost as chrome driver server
port: 9515, // "9515" is the port opened by chrome driver.
@@ -24,7 +30,7 @@ const options = {
browserName: 'electron',
chromeOptions: {
binary: `${__dirname}/../../../node_modules/electron/dist/${binary}`,
args: [`--app=${__dirname}/../../..`, '--force-device-scale-factor=1', '--no-sandbox', '--disable-dev-shm-usage', '--disable-extensions'],
args: [`--app=${__dirname}/../../..`, '--force-device-scale-factor=1', '--no-sandbox', '--disable-dev-shm-usage', '--disable-extensions'].concat(fullscreen),
},
windowTypes: ['app', 'webview'],
},
@@ -35,28 +41,58 @@ async function doStuff() {
const browser = await webdriverio.remote(options)
await createFakeMousePointer(browser)
await connectTo('localhost', browser)
await sleep(2000) // Allow some topics to pour in
await showText('Plotting topics', 0, browser)
await connectTo('127.0.0.1', browser)
await sleep(1000)
await sleep(1000)
await showText('Overview of topics', 2000, browser, 'top')
await sleep(2000)
await showText('Indicates which topics change', 2000, browser, 'bottom')
await sleep(3000)
await showText('Plot topics', 2000, browser)
await showNumericPlot(browser)
await sleep(2000)
await hideText(browser)
await showText('JSON preview', 0, browser)
await showText('Formatted messages', 2000, browser, 'top')
await showJsonPreview(browser)
await sleep(2000)
await showText('Compare messages', 2000, browser, 'top')
await compareJsonSideBySide(browser)
await hideText(browser)
await showText('Copy&Paste data', 2000, browser)
await copyTopicToClipboard(browser)
await showText('Publish topics', 2000, browser, 'top')
await clickOnHistory(browser)
await publishTopic(browser)
await sleep(1000)
await showText('Copy to Clipboard', 2000, browser)
await copyTopicToClipboard(browser)
await hideText(browser)
await copyValueToClipboard(browser)
await sleep(1000)
await showText('Search topic hierarchy', 0, browser, 'middle')
await searchTree('temp', browser)
await hideText(browser)
await showText('Topics containing "temp"', 1500, browser)
await sleep(1500)
await clearSearch(browser)
await sleep(1000)
await hideText(browser)
await showText('Delete retained topics', 0, browser)
await clearOldTopics(browser)
await hideText(browser)
await showText('Settings', 3000, browser)
await showText('Display Options', 2000, browser)
await showMenu(browser)
await sleep(2000)
await disconnect(browser)
await sleep(3000)
browser.closeWindow()
stop()