Add UI tests
This commit is contained in:
BIN
app/cursor.png
Normal file
BIN
app/cursor.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.6 KiB |
@@ -64,7 +64,7 @@ class MessageHistory extends React.Component<Props, State> {
|
|||||||
badgeContent={this.props.items.length}
|
badgeContent={this.props.items.length}
|
||||||
color="primary"
|
color="primary"
|
||||||
>
|
>
|
||||||
{this.state.collapsed ? '▶' : '▼'} History
|
{this.state.collapsed ? '▶ History' : '▼ History'}
|
||||||
</Badge>
|
</Badge>
|
||||||
<div style={{ float: 'right' }}>{this.state.collapsed ? this.props.contentTypeIndicator : null}</div>
|
<div style={{ float: 'right' }}>{this.state.collapsed ? this.props.contentTypeIndicator : null}</div>
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|||||||
@@ -53,16 +53,19 @@
|
|||||||
"electron": "^4.0.2",
|
"electron": "^4.0.2",
|
||||||
"electron-builder": "^20.38.4",
|
"electron-builder": "^20.38.4",
|
||||||
"mocha": "^5.2.0",
|
"mocha": "^5.2.0",
|
||||||
|
"mosca": "^2.8.3",
|
||||||
"mustache": "^3.0.1",
|
"mustache": "^3.0.1",
|
||||||
"nyc": "^13.1.0",
|
"nyc": "^13.1.0",
|
||||||
"redux-thunk": "^2.3.0",
|
"redux-thunk": "^2.3.0",
|
||||||
"source-map-support": "^0.5.9",
|
"source-map-support": "^0.5.9",
|
||||||
|
"spectron": "^5.0.0",
|
||||||
"ts-node": "^7.0.1",
|
"ts-node": "^7.0.1",
|
||||||
"tslint": "^5.12.0",
|
"tslint": "^5.12.0",
|
||||||
"tslint-config-airbnb": "^5.11.1",
|
"tslint-config-airbnb": "^5.11.1",
|
||||||
"tslint-react": "^3.6.0",
|
"tslint-react": "^3.6.0",
|
||||||
"tslint-strict-null-checks": "^1.0.1",
|
"tslint-strict-null-checks": "^1.0.1",
|
||||||
"typescript": "^3.2.2"
|
"typescript": "^3.2.2",
|
||||||
|
"webdriverio": "5.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"electron-debug": "^2.0.0",
|
"electron-debug": "^2.0.0",
|
||||||
|
|||||||
77
src/spec/mock-mqtt.ts
Normal file
77
src/spec/mock-mqtt.ts
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import * as mqtt from 'mqtt'
|
||||||
|
|
||||||
|
const settings = {
|
||||||
|
port: 1883,
|
||||||
|
}
|
||||||
|
|
||||||
|
let client: mqtt.MqttClient
|
||||||
|
function startServer(): Promise<mqtt.MqttClient> {
|
||||||
|
return new Promise(async (resolve) => {
|
||||||
|
// const server = new mosca.Server(settings)
|
||||||
|
// await new Promise(resolve => server.once('ready', resolve))
|
||||||
|
client = await connectMqtt()
|
||||||
|
generateData(client)
|
||||||
|
resolve(client)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectMqtt(): Promise<mqtt.MqttClient> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const client = mqtt.connect('mqtt://localhost:1883', { username: 'thomas', password: 'bierbier' })
|
||||||
|
client.once('connect', () => {
|
||||||
|
resolve(client)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function temperature(base = 18, sineCoefficient = 2, offset = 0) {
|
||||||
|
const temp = base + Math.sin(Date.now() / 1000 / 5 + offset) * sineCoefficient + Math.random()
|
||||||
|
|
||||||
|
return String(Math.round(temp * 100) / 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function stop() {
|
||||||
|
for (const interval of intervals) {
|
||||||
|
clearInterval(interval)
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
client && client.end()
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
const intervals: any = []
|
||||||
|
|
||||||
|
function generateData(client: mqtt.MqttClient) {
|
||||||
|
client.publish('livingroom/lamp/state', 'on', { retain: true, qos: 0 })
|
||||||
|
client.publish('livingroom/lamp/brightness', '128', { retain: true, qos: 0 })
|
||||||
|
client.publish('livingroom/thermostat/targetTemperature', '20°C', { retain: true, qos: 0 })
|
||||||
|
intervals.push(setInterval(() => client.publish('livingroom/temperature', temperature()), 1000))
|
||||||
|
intervals.push(setInterval(() => client.publish('livingroom/humidity', temperature(60, -2, 0)), 1000))
|
||||||
|
|
||||||
|
client.publish('livingroom/lamp-1/state', 'on', { retain: true, qos: 0 })
|
||||||
|
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 })
|
||||||
|
intervals.push(setInterval(() => client.publish('kitchen/temperature', temperature()), 1500))
|
||||||
|
intervals.push(setInterval(() => client.publish('kitchen/humidity', temperature(60, -5, 0)), 1800))
|
||||||
|
|
||||||
|
client.publish('garden/pump/state', 'off', { retain: true, qos: 0 })
|
||||||
|
client.publish('garden/water/level', '70%', { retain: true, qos: 0 })
|
||||||
|
client.publish('garden/lamps/state', 'off', { retain: true, qos: 0 })
|
||||||
|
client.publish('garden/lamps/state', 'off', { retain: true, qos: 0 })
|
||||||
|
|
||||||
|
client.publish('zigbee2mqtt/bridge/state', 'online', { retain: true, qos: 0 })
|
||||||
|
client.publish('ble2mqtt/bridge/state', 'online', { retain: true, qos: 0 })
|
||||||
|
|
||||||
|
// Used for demonstrating "clean up"
|
||||||
|
client.publish('test 123', 'Hello world', { retain: true, qos: 0 })
|
||||||
|
client.publish('hello', 'sunshine', { retain: true, qos: 0 })
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
|
||||||
|
export default startServer
|
||||||
15
src/spec/scenarios/clearOldTopics.ts
Normal file
15
src/spec/scenarios/clearOldTopics.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { clickOn, sleep, writeText, expandTopic, moveToCenterOfElement } from '../util'
|
||||||
|
import { Browser } from 'webdriverio'
|
||||||
|
|
||||||
|
export async function clearOldTopics(browser: Browser<void>) {
|
||||||
|
const topics = ['hello', 'test 123']
|
||||||
|
for (const topic of topics) {
|
||||||
|
await expandTopic(topic, browser)
|
||||||
|
await sleep(1000)
|
||||||
|
|
||||||
|
const deleteButton = await browser.$('//button[contains(@title, "Delete retained topic")]')
|
||||||
|
await moveToCenterOfElement(deleteButton, browser)
|
||||||
|
await clickOn(deleteButton, browser)
|
||||||
|
await sleep(700)
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src/spec/scenarios/connect.ts
Normal file
20
src/spec/scenarios/connect.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { clickOn, sleep, writeText } from '../util'
|
||||||
|
import { Browser } from 'webdriverio'
|
||||||
|
|
||||||
|
export async function connectTo(host: string, browser: Browser<void>) {
|
||||||
|
await writeTextToInput('Host', host, browser)
|
||||||
|
await writeTextToInput('Username', 'thomas', browser, false)
|
||||||
|
await writeTextToInput('Password', 'bierbier', browser, false)
|
||||||
|
|
||||||
|
const connectButton = await browser.$('//button/span[contains(text(),"Connect")]')
|
||||||
|
clickOn(connectButton, browser)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function writeTextToInput(name: string, text: string, browser: Browser<void>, 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)
|
||||||
|
}
|
||||||
7
src/spec/scenarios/copyTopicToClipboard.ts
Normal file
7
src/spec/scenarios/copyTopicToClipboard.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { clickOn, sleep, writeText, expandTopic } from '../util'
|
||||||
|
import { Browser } from 'webdriverio'
|
||||||
|
|
||||||
|
export async function copyTopicToClipboard(browser: Browser<void>) {
|
||||||
|
const copyButton = await browser.$('//p[contains(text(), "Topic")]/span')
|
||||||
|
await clickOn(copyButton, browser, 1)
|
||||||
|
}
|
||||||
7
src/spec/scenarios/copyValueToClipboard.ts
Normal file
7
src/spec/scenarios/copyValueToClipboard.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { clickOn, sleep, writeText, expandTopic } from '../util'
|
||||||
|
import { Browser } from 'webdriverio'
|
||||||
|
|
||||||
|
export async function copyValueToClipboard(browser: Browser<void>) {
|
||||||
|
const copyButton = await browser.$('//p[contains(text(), "Value")]/span')
|
||||||
|
await clickOn(copyButton, browser, 1)
|
||||||
|
}
|
||||||
8
src/spec/scenarios/searchTree.ts
Normal file
8
src/spec/scenarios/searchTree.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { clickOn, sleep, writeText } from '../util'
|
||||||
|
import { Browser } from 'webdriverio'
|
||||||
|
|
||||||
|
export async function searchTree(browser: Browser<void>) {
|
||||||
|
const searchField = await browser.$('//input[contains(@placeholder, "Search")]')
|
||||||
|
await clickOn(searchField, browser, 1)
|
||||||
|
writeText('temp', browser)
|
||||||
|
}
|
||||||
8
src/spec/scenarios/showJsonPreview.ts
Normal file
8
src/spec/scenarios/showJsonPreview.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
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 sleep(1000)
|
||||||
|
}
|
||||||
21
src/spec/scenarios/showMenu.ts
Normal file
21
src/spec/scenarios/showMenu.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { clickOn, sleep, writeText, expandTopic, moveToCenterOfElement } from '../util'
|
||||||
|
import { Browser } from 'webdriverio'
|
||||||
|
|
||||||
|
export async function showMenu(browser: Browser<void>) {
|
||||||
|
const menuButton = await browser.$('//button[contains(@aria-label, "Menu")]')
|
||||||
|
await clickOn(menuButton, browser)
|
||||||
|
|
||||||
|
const brokerStatistics = await browser.$('//div[contains(@class, "BrokerStatistics")]/div[4]')
|
||||||
|
moveToCenterOfElement(brokerStatistics, browser)
|
||||||
|
await sleep(2000)
|
||||||
|
|
||||||
|
const topicOrder = await browser.$('#select-node-order')
|
||||||
|
await clickOn(topicOrder, browser)
|
||||||
|
await sleep(1000)
|
||||||
|
|
||||||
|
const alphabetically = await browser.$('//li[contains(@data-value, "abc")]')
|
||||||
|
await clickOn(alphabetically, browser)
|
||||||
|
await sleep(2000)
|
||||||
|
|
||||||
|
await clickOn(menuButton, browser)
|
||||||
|
}
|
||||||
12
src/spec/scenarios/showNumericPlot.ts
Normal file
12
src/spec/scenarios/showNumericPlot.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { clickOn, sleep, writeText, expandTopic } 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 sleep(1000)
|
||||||
|
await expandTopic('livingroom/humidity', browser)
|
||||||
|
}
|
||||||
29
src/spec/util/expandTopic.ts
Normal file
29
src/spec/util/expandTopic.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { Browser } from 'webdriverio'
|
||||||
|
import { clickOn } from './'
|
||||||
|
|
||||||
|
export async function expandTopic(path: string, browser: Browser<void>) {
|
||||||
|
const originalTopics = path.split('/')
|
||||||
|
let topics = path.split('/')
|
||||||
|
while (topics.length > 0 && !await topicMatches(topics, browser)) {
|
||||||
|
topics = topics.slice(0, topics.length - 1)
|
||||||
|
}
|
||||||
|
if (topics.length === 0) {
|
||||||
|
throw Error('could not expand topics, no match found')
|
||||||
|
}
|
||||||
|
|
||||||
|
while (topics.length <= originalTopics.length) {
|
||||||
|
const match = await browser.$(topicSelector(topics))
|
||||||
|
await clickOn(match, browser)
|
||||||
|
topics.push(originalTopics[topics.length])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function topicMatches(topics: string[], browser: Browser<void>) {
|
||||||
|
const result = await browser.$(topicSelector(topics))
|
||||||
|
return result.isExisting()
|
||||||
|
}
|
||||||
|
|
||||||
|
function topicSelector(topics: string[]) {
|
||||||
|
const suffix = topics.map(topic => `*[contains(text(), "${topic}")]`).join('/../../..//')
|
||||||
|
return `//${suffix}`
|
||||||
|
}
|
||||||
109
src/spec/util/index.ts
Normal file
109
src/spec/util/index.ts
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
import { Element, Browser } from 'webdriverio'
|
||||||
|
export { expandTopic } from './expandTopic'
|
||||||
|
|
||||||
|
export function sleep(ms: number) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
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 moveToCenterOfElement(element: Element<void>, browser: Browser<void>) {
|
||||||
|
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 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 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)) + 5 + 'px'
|
||||||
|
e.style.top = String(top + (stepY * currentStep)) + 5 + 'px'
|
||||||
|
if (currentStep < steps) {
|
||||||
|
setTimeout(() => {
|
||||||
|
currentStep += 1
|
||||||
|
getCloser()
|
||||||
|
}, duration/steps)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getCloser()
|
||||||
|
}`
|
||||||
|
await browser.execute(js)
|
||||||
|
await sleep(550)
|
||||||
|
await element.moveTo()
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function clickOn(element: Element<void>, browser: Browser<void>, clicks = 1) {
|
||||||
|
await moveToCenterOfElement(element, browser)
|
||||||
|
for (let i = 0; i < clicks; i += 1) {
|
||||||
|
await element.click()
|
||||||
|
await sleep(50)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createFakeMousePointer(browser: Browser<void>) {
|
||||||
|
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)'
|
||||||
|
|
||||||
|
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>) {
|
||||||
|
const js = `
|
||||||
|
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;"
|
||||||
|
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})
|
||||||
|
}
|
||||||
|
`
|
||||||
|
browser.execute(js)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function hideText(browser: Browser<void>) {
|
||||||
|
const js = `
|
||||||
|
let previousDiv = document.getElementById('tests-text-overlay')
|
||||||
|
previousDiv && previousDiv.remove()
|
||||||
|
`
|
||||||
|
browser.execute(js)
|
||||||
|
await sleep(600)
|
||||||
|
}
|
||||||
57
src/spec/webdriverio.ts
Normal file
57
src/spec/webdriverio.ts
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import * as webdriverio from 'webdriverio'
|
||||||
|
import mockMqtt, { stop } from './mock-mqtt'
|
||||||
|
import { connectTo } from './scenarios/connect'
|
||||||
|
import { showNumericPlot } from './scenarios/showNumericPlot'
|
||||||
|
import { showJsonPreview } from './scenarios/showJsonPreview'
|
||||||
|
import { copyTopicToClipboard } from './scenarios/copyTopicToClipboard'
|
||||||
|
import { copyValueToClipboard } from './scenarios/copyValueToClipboard'
|
||||||
|
import { clearOldTopics } from './scenarios/clearOldTopics'
|
||||||
|
import { showMenu } from './scenarios/showMenu'
|
||||||
|
|
||||||
|
import { createFakeMousePointer, sleep, showText, hideText } from './util'
|
||||||
|
const options = {
|
||||||
|
host: 'localhost', // Use localhost as chrome driver server
|
||||||
|
port: 9515, // "9515" is the port opened by chrome driver.
|
||||||
|
capabilities: {
|
||||||
|
browserName: 'electron',
|
||||||
|
chromeOptions: {
|
||||||
|
binary: `${__dirname}/../../../node_modules/electron/dist/Electron.app/Contents/MacOS/Electron`,
|
||||||
|
args: [`--app=${__dirname}/../../..`, '--force-device-scale-factor=1', '--no-sandbox', '--disable-dev-shm-usage', '--disable-extensions'],
|
||||||
|
},
|
||||||
|
windowTypes: ['app', 'webview'],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
async function doStuff() {
|
||||||
|
await mockMqtt()
|
||||||
|
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 showNumericPlot(browser)
|
||||||
|
await sleep(2000)
|
||||||
|
await hideText(browser)
|
||||||
|
await showText('JSON preview', 0, browser)
|
||||||
|
await showJsonPreview(browser)
|
||||||
|
await sleep(2000)
|
||||||
|
await hideText(browser)
|
||||||
|
await showText('Copy&Paste data', 2000, browser)
|
||||||
|
await copyTopicToClipboard(browser)
|
||||||
|
await sleep(1000)
|
||||||
|
await hideText(browser)
|
||||||
|
await copyValueToClipboard(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 showMenu(browser)
|
||||||
|
browser.closeWindow()
|
||||||
|
|
||||||
|
stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
doStuff()
|
||||||
@@ -11,5 +11,5 @@
|
|||||||
"lib": ["es2017", "dom"],
|
"lib": ["es2017", "dom"],
|
||||||
"sourceMap": true
|
"sourceMap": true
|
||||||
},
|
},
|
||||||
"include": ["src/electron.ts"]
|
"include": ["src/electron.ts", "src/spec/electron.ts", "src/spec/webdriverio.ts"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user