diff --git a/app/src/components/CodeDiff.tsx b/app/src/components/CodeDiff.tsx index 68f4fcb..e0401ca 100644 --- a/app/src/components/CodeDiff.tsx +++ b/app/src/components/CodeDiff.tsx @@ -94,7 +94,6 @@ const style = (theme: Theme) => { } const before = { margin: '0 2px 0 -9px', - // width: '8px', } return { additions: { diff --git a/app/src/components/demo/Key.tsx b/app/src/components/demo/Key.tsx new file mode 100644 index 0000000..c484dc0 --- /dev/null +++ b/app/src/components/demo/Key.tsx @@ -0,0 +1,44 @@ +import * as React from 'react' +import { Theme, withStyles } from '@material-ui/core' + +interface Props { + keyboardKey: string + classes: any +} + +class Key extends React.Component { + constructor(props: any) { + super(props) + this.state = { location: 'bottom' } + } + + public render() { + + return ( +
+
{this.props.keyboardKey}
+
+ ) + } +} + +const style = (theme: Theme) => ({ + keyStyle: { + display: 'inline-block' as 'inline-block', + width: '1em', + height: '1em', + backgroundColor: '#bbb', + borderRadius: '10%', + verticalAlign: 'middle' as 'middle', + textAlign: 'center' as 'center', + textShadow: '1px 1px rgba(255,255,255,0.45)', + boxShadow: '0.08em 0.15em 0.01em 0px rgba(100,100,100,0.75)', + }, + keyTextStyle: { + marginTop: '0.65em', + fontSize: '0.4em', + fontWeight: 'bold' as 'bold', + }, +}) + +export default withStyles(style)(Key) diff --git a/app/src/components/demo/Mouse.tsx b/app/src/components/demo/Mouse.tsx new file mode 100644 index 0000000..af74d78 --- /dev/null +++ b/app/src/components/demo/Mouse.tsx @@ -0,0 +1,78 @@ +import * as React from 'react' +import { Theme, withStyles } from '@material-ui/core' + +interface State { + enabled: boolean + target: {x: number, y: number} + position: {x: number, y: number} + stepSizeX: number, + stepSizeY: number, +} + +class Demo extends React.Component<{}, State> { + private timer: any + private frameInterval = 20 + + constructor(props: any) { + super(props) + this.state = { enabled: false, target: { x: 0, y: 0 }, position: { x: 0, y: 0 }, stepSizeX: 1, stepSizeY: 1 } + } + + public componentDidMount() { + (window as any).demo.enableMouse = () => { + this.setState({ enabled: true }) + } + (window as any).demo.moveMouse = (x: number, y: number, animationTime: number) => { + const stepSizeX = Math.abs(this.state.position.x - x) / (animationTime / this.frameInterval) + const stepSizeY = Math.abs(this.state.position.y - y) / (animationTime / this.frameInterval) + this.setState({ stepSizeX, stepSizeY, enabled: true, target: { x, y } }) + this.moveCloser() + } + } + + private moveCloser(steps: number = 0) { + const steSizeX = Math.min(this.state.stepSizeX, Math.abs(this.state.position.x - this.state.target.x)) + const steSizeY = Math.min(this.state.stepSizeY, Math.abs(this.state.position.y - this.state.target.y)) + const dirX = this.state.position.x > this.state.target.x ? -1 : 1 + const dirY = this.state.position.y > this.state.target.y ? -1 : 1 + + if (steSizeX <= 0.1 && steSizeY <= 0.1) { + this.timer && clearTimeout(this.timer) + return + } + + this.setState({ + position: { + x: this.state.position.x + (dirX * steSizeX), + y: this.state.position.y + (dirY * steSizeY), + }, + }) + + this.timer = setTimeout(() => { + this.moveCloser(steps + 1) + }, this.frameInterval) + } + + public render() { + if (!this.state.enabled) { + return null + } + const style = { + width: '32px', + height: '32px', + position: 'fixed' as 'fixed', + zIndex: 1000000, + filter: 'invert(100%)', + left: this.state.position.x + 2, + top: this.state.position.y + 2, + } + + return ( + + ) + } +} + +const style = (theme: Theme) => {} + +export default withStyles(style)(Demo) diff --git a/app/src/components/demo/ShowText.tsx b/app/src/components/demo/ShowText.tsx new file mode 100644 index 0000000..a7a6101 --- /dev/null +++ b/app/src/components/demo/ShowText.tsx @@ -0,0 +1,91 @@ +import * as React from 'react' +import { Theme, withStyles } from '@material-ui/core' +import Key from './Key'; + +interface State { + message?: string + keys: string[] + location: string +} + + + +class Demo extends React.Component<{classes: any}, State> { + private timer: any + constructor(props: any) { + super(props) + this.state = { location: 'bottom', keys: [] } + } + + private clearTimer() { + this.timer && clearTimeout(this.timer) + } + + public componentDidMount() { + (window as any).demo.showMessage = (message: string, location: string, duration: number, keys: string[] = []) => { + this.clearTimer() + this.setState({ message, location, keys }) + this.timer = setTimeout(() => this.setState({ message: undefined }), duration) + } + + (window as any).demo.hideMessage = () => { + this.clearTimer() + this.setState({ message: undefined }) + } + } + + public render() { + const positions: {[s: string]: number} = { + top: 0, + bottom: -65, + middle: -32, + } + const style = { + position: 'fixed' as 'fixed', + left: '5vw', + zIndex: 1000000, + margin: '30vw auto 50vw', + right: '5vw', + bottom: `${positions[this.state.location]}vh`, + } + const style2 = { + textAlign: 'center' as 'center', + fontSize: '4em', + color: 'white', + backgroundColor: 'rgba(0, 0, 0, 0.8)', + borderRadius: '16px', + + } + + if (!this.state.message) { + return null + } + + let keys: any[] = [] + if (this.state.keys.length > 0) { + keys = this.state.keys.map(key => []) + .reduce((prev, current) => { + return [prev, '+' as any, current] + }) + } + + return ( +
+
+ {this.state.message} + {keys.length > 0 ?
{keys}
: null} +
+
+ ) + } +} + +const style = (theme: Theme) => ({ + keysStyle: { + fontSize: '1em', + display: 'inline-block' as 'inline-block', + transform: 'translateY(0.3em) translateX(0.8em)', + }, +}) + +export default withStyles(style)(Demo) diff --git a/app/src/components/demo/index.tsx b/app/src/components/demo/index.tsx new file mode 100644 index 0000000..feeef4a --- /dev/null +++ b/app/src/components/demo/index.tsx @@ -0,0 +1,14 @@ +import * as React from 'react' +import ShowText from './ShowText' +import Mouse from './Mouse'; + +(window as any).demo = {} + +export default function render(props: any) { + return ( + + + + + ) +} \ No newline at end of file diff --git a/app/src/index.tsx b/app/src/index.tsx index 262dd14..4c41af0 100644 --- a/app/src/index.tsx +++ b/app/src/index.tsx @@ -11,6 +11,7 @@ import reducers from './reducers' import App from './App' import { Provider } from 'react-redux' import { createStore, applyMiddleware, compose } from 'redux' +import Demo from './components/demo' const composeEnhancers = /*(window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || */ compose const store = createStore( @@ -41,6 +42,7 @@ ReactDOM.render( + , document.getElementById('app'), diff --git a/src/spec/KeyCode.ts b/src/spec/KeyCode.ts new file mode 100644 index 0000000..a102ebc --- /dev/null +++ b/src/spec/KeyCode.ts @@ -0,0 +1,3 @@ +export const Control = '\uE009' +export const Unknown = '\uE000' +export const Plus = '\uE025' diff --git a/src/spec/mock-mqtt.ts b/src/spec/mock-mqtt.ts index 782b32c..39d8a6b 100644 --- a/src/spec/mock-mqtt.ts +++ b/src/spec/mock-mqtt.ts @@ -87,16 +87,19 @@ function generateData(client: mqtt.MqttClient) { let state = true intervals.push(setInterval(() => { state = !state + const js = { + tags:{ + entityId: 33512, + entityType: 'person', + host: 'd44ad81e10f9', + server: 'http://localhost/dataActuality', + status: state ? 'live' : 'inactive', + }, + timestamp: Date.now(), + } client.publish( - 'actuality/showcase', `{ - "tags":{ - "entityId": 33512, - "entityType":"person", - "host":"d44ad81e10f9", - "server":" 'http://localhost/dataActuality', - "status":"${state ? 'live' : 'inactive'}"}, - "timestamp":${Date.now()} - }`.replace(/\s/g, ''), + 'actuality/showcase', + JSON.stringify(js), { retain: true, qos: 0 }, ) }, 2102)) diff --git a/src/spec/scenarios/connect.ts b/src/spec/scenarios/connect.ts index 8695ec6..5105ac3 100644 --- a/src/spec/scenarios/connect.ts +++ b/src/spec/scenarios/connect.ts @@ -1,4 +1,4 @@ -import { clickOn, sleep, writeText } from '../util' +import { clickOn, writeTextToInput } from '../util' import { Browser } from 'webdriverio' export async function connectTo(host: string, browser: Browser) { @@ -9,12 +9,3 @@ export async function connectTo(host: string, browser: Browser) { const connectButton = await browser.$('//button/span[contains(text(),"Connect")]') clickOn(connectButton, browser) } - -async function writeTextToInput(name: string, text: string, browser: Browser, wait: boolean = true) { - const input = await browser.$(`//label[contains(text(), "${name}")]/..//input`) - await clickOn(input, browser, 1) - wait && await sleep(500) - input.clearValue() - wait && await sleep(300) - await writeText(text, browser) -} diff --git a/src/spec/scenarios/copyTopicToClipboard.ts b/src/spec/scenarios/copyTopicToClipboard.ts index 928ed40..4b9749b 100644 --- a/src/spec/scenarios/copyTopicToClipboard.ts +++ b/src/spec/scenarios/copyTopicToClipboard.ts @@ -1,4 +1,4 @@ -import { clickOn, sleep, writeText, expandTopic } from '../util' +import { clickOn } from '../util' import { Browser } from 'webdriverio' export async function copyTopicToClipboard(browser: Browser) { diff --git a/src/spec/scenarios/showAdvancedConnectionSettings.ts b/src/spec/scenarios/showAdvancedConnectionSettings.ts new file mode 100644 index 0000000..48b5098 --- /dev/null +++ b/src/spec/scenarios/showAdvancedConnectionSettings.ts @@ -0,0 +1,29 @@ +import { clickOn, writeTextToInput, sleep } from '../util' +import { Browser } from 'webdriverio' + +export async function showAdvancedConnectionSettings(browser: Browser) { + const advancedSettingsButton = await browser.$('//button/span[contains(text(),"Advanced")]') + const addButton = await browser.$('//button/span[contains(text(),"Add")]') + + await clickOn(advancedSettingsButton, browser) + await writeTextToInput('Subscription', 'garden/#', browser, false) + await clickOn(addButton, browser) + + await writeTextToInput('Subscription', 'livingroom/#', browser, false) + await clickOn(addButton, browser) + + await deleteFirstSubscribedTopic(browser) + await deleteFirstSubscribedTopic(browser) + await sleep(1000) + + const backButton = await browser.$('//button/span[contains(text(),"Back")]') + await clickOn(backButton, browser) + + const connectButton = await browser.$('//button/span[contains(text(),"Connect")]') + await clickOn(connectButton, browser) +} + +async function deleteFirstSubscribedTopic(browser: Browser) { + const deleteButton = await browser.$('//*[contains(@class,"topicList")]//button') + await clickOn(deleteButton, browser) +} diff --git a/src/spec/scenarios/showJsonFormatting.ts b/src/spec/scenarios/showJsonFormatting.ts index 2a7acdf..28e3fd0 100644 --- a/src/spec/scenarios/showJsonFormatting.ts +++ b/src/spec/scenarios/showJsonFormatting.ts @@ -17,6 +17,9 @@ export async function showJsonFormatting(browser: Browser) { await sleep(300) await clickOn(formatJsonButton, browser) await sleep(1200) + + const sidebarDrawer = await browser.$('//*[contains(@class, "Sidebar")]') + await sidebarDrawer.scrollIntoView() } async function writeTextPayload(payloadInput: any, text: string) { diff --git a/src/spec/scenarios/showJsonPreview.ts b/src/spec/scenarios/showJsonPreview.ts index e2fd334..ee28dbc 100644 --- a/src/spec/scenarios/showJsonPreview.ts +++ b/src/spec/scenarios/showJsonPreview.ts @@ -1,5 +1,5 @@ -import { clickOn, sleep, writeText, expandTopic } from '../util' import { Browser } from 'webdriverio' +import { expandTopic, sleep } from '../util' export async function showJsonPreview(browser: Browser) { await expandTopic('actuality/showcase', browser) diff --git a/src/spec/scenarios/showZoomLevel.ts b/src/spec/scenarios/showZoomLevel.ts new file mode 100644 index 0000000..5f4f467 --- /dev/null +++ b/src/spec/scenarios/showZoomLevel.ts @@ -0,0 +1,11 @@ +import { sleep, showKeys, showText } from '../util' +import { Browser } from 'webdriverio' + +export async function showZoomLevel(browser: Browser) { + await showKeys('Zoom in', 2000, browser, 'top', ['Ctrl', '+']) + await sleep(2000) + await showKeys('Zoom out', 2000, browser, 'middle', ['Ctrl', '-']) + await sleep(2000) + await showKeys('Reset zoom level', 2000, browser, 'bottom', ['Ctrl', 'Zero']) + await sleep(2000) +} diff --git a/src/spec/util/index.ts b/src/spec/util/index.ts index 764f702..7361ca1 100644 --- a/src/spec/util/index.ts +++ b/src/spec/util/index.ts @@ -1,4 +1,4 @@ -import { Element, Browser } from 'webdriverio' +import { Browser, Element } from 'webdriverio' export { expandTopic } from './expandTopic' export function sleep(ms: number, required = false) { @@ -26,47 +26,28 @@ export async function delteTextWithBackspaces(element: Element, browser: B } } +export async function writeTextToInput(name: string, text: string, browser: Browser, wait: boolean = true) { + const input = await browser.$(`//label[contains(text(), "${name}")]/..//input`) + await clickOn(input, browser, 1) + wait && await sleep(500) + input.clearValue() + wait && await sleep(300) + await writeText(text, browser) +} + export async function moveToCenterOfElement(element: Element, browser: Browser) { const { x, y } = await element.getLocation() const { width, height } = await element.getSize() - const js = `{ - const targetX = ${x + width / 2} - const targetY = ${y + height / 2} - const duration = 500 + const targetX = x + width / 2 + const targetY = y + height / 2 - const maxStepSize = 10 - const e = document.getElementById("bier") - const top = parseFloat(e.style.top) - const left = parseFloat(e.style.left) - const deltaY = targetY - top - const deltaX = targetX - left + const duration = 500 - const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY) - const steps = Math.ceil(distance / maxStepSize) - - const stepX = deltaX / steps - const stepY = deltaY / steps - let currentStep = 0 - function getCloser() { - e.style.left = String(left + (stepX * currentStep)) + 'px' - e.style.top = String(top + (stepY * currentStep)) + 'px' - if (currentStep < steps) { - setTimeout(() => { - currentStep += 1 - if (currentStep === steps) { - e.style.left = String(targetX + 5) + 'px' - e.style.top = String(targetY + 1) + 'px' - } else { - getCloser() - } - }, duration/steps) - } - } - getCloser() - }` + const js = `window.demo.moveMouse(${targetX}, ${targetY}, ${duration});` await browser.execute(js) - await sleep(550, true) + await sleep(duration + 500, true) + await element.moveTo() } @@ -84,47 +65,25 @@ export async function clickOn(element: Element, browser: Browser, cl } export async function createFakeMousePointer(browser: Browser) { - const addCursorImage = 'const i=document.createElement("img");' - + 'i.src="../cursor.png";' - + 'i.width="32";' - + 'i.height="32";' - + 'i.id="bier";' - + 'i.style="position: fixed; z-index:10000000; filter: invert(100%);left: 0px; top: 0px;";' - + 'document.body.appendChild(i)' + const js = 'window.demo.enableMouse();' - await browser.execute(addCursorImage) + await browser.execute(js) } -export async function showText(text: string, duration: number = 0, browser: Browser, 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: "+ postition +";" - let div2 = document.createElement('div') - div2.style = "text-align: center;font-size: 4em;color: white;" - div2.innerHTML = \`${text}\` - div.appendChild(div2) - document.body.appendChild(div) - if (${duration} > 0) { - setTimeout(() => div.remove(), ${duration}) - } - ` +export async function showText(text: string, duration: number = 0, browser: Browser, location: 'top' | 'bottom' | 'middle' = 'bottom', keys = []) { + const js = `window.demo.showMessage('${text}', '${location}', ${duration});` + + browser.execute(js) +} + +export async function showKeys(text: string, duration: number = 0, browser: Browser, location: 'top' | 'bottom' | 'middle' = 'bottom', keys: string[] = []) { + const js = `window.demo.showMessage('${text}', '${location}', ${duration}, ${JSON.stringify(keys)});` + browser.execute(js) } export async function hideText(browser: Browser) { - const js = ` - let previousDiv = document.getElementById('tests-text-overlay') - previousDiv && previousDiv.remove() - ` + const js = 'window.demo.hideMessage();' browser.execute(js) await sleep(600) } diff --git a/src/spec/webdriverio.ts b/src/spec/webdriverio.ts index ceade16..1e5085b 100644 --- a/src/spec/webdriverio.ts +++ b/src/spec/webdriverio.ts @@ -3,13 +3,6 @@ import * as webdriverio from 'webdriverio' import mockMqtt, { stop } from './mock-mqtt' import { clearOldTopics } from './scenarios/clearOldTopics' import { clearSearch, searchTree } from './scenarios/searchTree' -import { - clickOnHistory, - createFakeMousePointer, - hideText, - showText, - sleep, -} from './util' import { connectTo } from './scenarios/connect' import { copyTopicToClipboard } from './scenarios/copyTopicToClipboard' import { copyValueToClipboard } from './scenarios/copyValueToClipboard' @@ -20,6 +13,15 @@ import { showJsonPreview } from './scenarios/showJsonPreview' import { showMenu } from './scenarios/showMenu' import { showNumericPlot } from './scenarios/showNumericPlot' import { showOffDiffCapability } from './scenarios/showOffDiffCapability' +import { showZoomLevel } from './scenarios/showZoomLevel' +import { showAdvancedConnectionSettings } from './scenarios/showAdvancedConnectionSettings' +import { + clickOnHistory, + createFakeMousePointer, + hideText, + showText, + sleep, +} from './util' process.on('unhandledRejection', (error: Error) => { console.error('unhandledRejection', error.message, error.stack) @@ -51,6 +53,7 @@ async function doStuff() { await createFakeMousePointer(browser) await connectTo('127.0.0.1', browser) + await sleep(1000) await sleep(1000) @@ -103,10 +106,18 @@ async function doStuff() { await sleep(2000) await disconnect(browser) + + await showText('Customize Subscriptions', 3000, browser, 'top') + await showAdvancedConnectionSettings(browser) + + await showText('Keyboard shortcuts', 1750, browser, 'middle') + await sleep(1750) + await showZoomLevel(browser) + + await showText('The End', 3000, browser, 'middle') await sleep(3000) browser.closeWindow() - stop() }