mirror of
https://github.com/thomasnordquist/MQTT-Explorer.git
synced 2026-09-11 17:13:53 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
69897b4345 |
+7
-13
@@ -1,11 +1,4 @@
|
||||
{
|
||||
"import": [
|
||||
"@cspell/dict-typescript/cspell-ext.json"
|
||||
],
|
||||
"ignoreRegExpList": [
|
||||
"import(?:(?:(?:[ \\n\\t]+([^ *\\n\\t\\{\\},]+)[ \\n\\t]*(?:,|[ \\n\\t]+))?([ \\n\\t]*\\{(?:[ \\n\\t]*[^ \\n\\t\"'\\{\\}]+[ \\n\\t]*,?)+\\})?[ \\n\\t]*)|[ \n\\n\\t]*\\*[ \\n\\t]*as[ \\n\\t]+([^ \\n\\t\\{\\}]+)[ \\n\\t]+)from[ \\n\\t]*(?:['\"])([^'\"\\n]+)(['\"])\n",
|
||||
"^import\\s+(['\"]).*\\1$"
|
||||
],
|
||||
"language": "en",
|
||||
"words": [
|
||||
"Bbreak",
|
||||
@@ -15,13 +8,15 @@
|
||||
"nowrap",
|
||||
"subheader",
|
||||
"basepath",
|
||||
"webdriverio",
|
||||
"repo",
|
||||
"hexagonalize",
|
||||
"pixelize",
|
||||
"Transistions",
|
||||
"squashfs",
|
||||
"squashfs",
|
||||
"provisionprofile",
|
||||
"Nsis",
|
||||
"webdriverio",
|
||||
"Appx",
|
||||
"Hashable",
|
||||
"clickaway",
|
||||
@@ -31,6 +26,8 @@
|
||||
"Monokai",
|
||||
"plottable",
|
||||
"snackbar",
|
||||
"webdriverio",
|
||||
"prismjs",
|
||||
"Nordquist",
|
||||
"debounced",
|
||||
"mosquitto",
|
||||
@@ -50,9 +47,6 @@
|
||||
"mixins",
|
||||
"Explorerdmg",
|
||||
"heapsnapshot",
|
||||
"noconflict",
|
||||
"sparkplugb",
|
||||
"protojson",
|
||||
"typesafe"
|
||||
"noconflict"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
package.ts @thomasnordquist
|
||||
.github @thomasnordquist
|
||||
scripts @thomasnordquist
|
||||
@@ -1,29 +0,0 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- release
|
||||
- beta
|
||||
paths:
|
||||
- Dockerfile
|
||||
- .github
|
||||
|
||||
jobs:
|
||||
create-image:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: ghcr.io/thomasnordquist/mqtt-explorer-ui-tests:latest
|
||||
@@ -1,53 +0,0 @@
|
||||
name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- release
|
||||
- beta
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
build:
|
||||
- os: ubuntu-latest
|
||||
task: linux
|
||||
- os: windows-latest
|
||||
task: win
|
||||
- os: macos-latest
|
||||
task: mac
|
||||
runs-on: ${{ matrix.build.os }}
|
||||
steps:
|
||||
- if: matrix.build.os == 'ubuntu-latest'
|
||||
run: sudo snap install snapcraft --classic
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
- run: npm install -g yarn
|
||||
- run: yarn
|
||||
- id: create_token # get ReleaseBot access token
|
||||
uses: tibdex/github-app-token@v2
|
||||
with:
|
||||
app_id: ${{ secrets.RELEASE_BOT_APP_ID }}
|
||||
private_key: ${{ secrets.RELEASE_BOT_PRIVATE_KEY }}
|
||||
- name: Semantic Release
|
||||
uses: cycjimmy/semantic-release-action@v4
|
||||
id: semantic # Need an `id` for output variables
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ steps.create_token.outputs.token }}
|
||||
- run: yarn build
|
||||
if: steps.semantic.outputs.new_release_published == 'true'
|
||||
- run: yarn prepare-release
|
||||
if: steps.semantic.outputs.new_release_published == 'true'
|
||||
- run: yarn package ${{ matrix.build.task }}
|
||||
if: steps.semantic.outputs.new_release_published == 'true'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
on:
|
||||
pull_request_target: # Use pull_request_target
|
||||
branches: [master, beta, release]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/thomasnordquist/mqtt-explorer-ui-tests:latest
|
||||
volumes:
|
||||
- ./:/app
|
||||
options: --user root
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install Packages
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Build
|
||||
run: yarn build
|
||||
- name: Test
|
||||
run: yarn test
|
||||
- name: UI-Test
|
||||
run: yarn ui-test
|
||||
- name: Post-processing
|
||||
run: ./scripts/prepareVideo.sh
|
||||
- uses: hkusu/s3-upload-action@v2
|
||||
id: upload # specify some ID for use in subsequent steps
|
||||
with:
|
||||
aws-access-key-id: ${{ vars.AWS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
aws-region: 'eu-central-1'
|
||||
aws-bucket: ${{ vars.AWS_BUCKET }}
|
||||
file-path: './ui-test.gif'
|
||||
content-type: image/gif
|
||||
output-file-url: 'true'
|
||||
- name: Show URL
|
||||
run: echo '${{ steps.upload.outputs.file-url }}'
|
||||
id: artifact-upload-step
|
||||
- run: echo '' >> $GITHUB_STEP_SUMMARY
|
||||
@@ -1,17 +0,0 @@
|
||||
name: Update Website
|
||||
|
||||
on: [release, workflow_dispatch]
|
||||
|
||||
jobs:
|
||||
update-website:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: gh-pages
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
- run: npm install
|
||||
- run: npm run readme
|
||||
- uses: stefanzweifel/git-auto-commit-action@v5
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
{
|
||||
"branches": [
|
||||
"release",
|
||||
{
|
||||
"name": "beta",
|
||||
"prerelease": true
|
||||
}
|
||||
],
|
||||
repositoryUrl: "git@github.com:thomasnordquist/MQTT-Explorer.git",
|
||||
"plugins": [
|
||||
"@semantic-release/commit-analyzer",
|
||||
"semantic-release-export-data",
|
||||
"@semantic-release/changelog",
|
||||
[
|
||||
"@semantic-release/npm",
|
||||
{
|
||||
"npmPublish": false
|
||||
}
|
||||
],
|
||||
[
|
||||
"@semantic-release/git",
|
||||
{
|
||||
"assets": [
|
||||
"package.json",
|
||||
"yarn.lock"
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
language: node_js
|
||||
|
||||
services:
|
||||
- xvfb
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- node_modules
|
||||
- $HOME/.cache/electron
|
||||
- $HOME/.cache/electron-builder
|
||||
- $HOME/.npm/_prebuilds
|
||||
|
||||
node_js:
|
||||
- "10"
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
osx_image: xcode10.2
|
||||
|
||||
dist: bionic
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
install:
|
||||
- yarn install
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get update && sudo apt-get -y install snap squashfs-tools && sudo snap install snapcraft --classic; fi;
|
||||
|
||||
script:
|
||||
- yarn run build
|
||||
- yarn lint
|
||||
- yarn test
|
||||
- export TRAVIS_BUILD_NUMBER="" # Override travis build number since it is uses for tagging the binary version https://github.com/electron-userland/electron-builder/issues/3730
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker run -e GH_TOKEN=$GH_TOKEN -e GIT_TAG=$TRAVIS_TAG --rm -v `pwd`:/app thomasnordquist/ui-test-recording-env sh -c "cd app && docker/testMounted.sh"; fi
|
||||
- if [[ "$TRAVIS_TAG" != "" ]]; then yarn run prepare-release; fi
|
||||
- |
|
||||
if [[ "$TRAVIS_OS_NAME" == "linux" ]] && [[ "$TRAVIS_TAG" != "" ]]; then
|
||||
openssl aes-256-cbc -d -in res/snapstore-credentials.enc -out credentials -k $SNAPSTORE_CREDENTIALS_DECRYPTION_KEY;
|
||||
snapcraft login --with credentials;
|
||||
rm credentials;
|
||||
yarn run package linux;
|
||||
fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]] && [[ "$TRAVIS_TAG" != "" ]]; then yarn run package -- mac; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]] && [[ "$TRAVIS_TAG" != "" ]]; then unset CSC_LINK; yarn run package -- win; fi
|
||||
@@ -6,12 +6,11 @@
|
||||
[](https://ci.appveyor.com/project/thomasnordquist/mqtt-explorer/branch/master)
|
||||
[](https://app.codacy.com/app/thomasnordquist/MQTT-Explorer?utm_source=github.com&utm_medium=referral&utm_content=thomasnordquist/MQTT-Explorer&utm_campaign=Badge_Grade_Dashboard)
|
||||
|
||||
| | | |
|
||||
| :---------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------: |
|
||||
| [](https://mqtt-explorer.com/img/screen-composite.png) | [](https://mqtt-explorer.com/img/screen2.png) | [](https://mqtt-explorer.com/img/screen3.png) |
|
||||
| | | |
|
||||
|:---:|:---:|:---:|
|
||||
|[](https://mqtt-explorer.com/img/screen-composite.png)|[](https://mqtt-explorer.com/img/screen2.png)|[](https://mqtt-explorer.com/img/screen3.png)|
|
||||
|
||||
# The App has moved to [mqtt-explorer.com](https://mqtt-explorer.com)
|
||||
|
||||
MQTT Explorer is a comprehensive and easy-to-use MQTT Client.
|
||||
Downloads can be found at the link above.
|
||||
|
||||
@@ -30,7 +29,6 @@ yarn start
|
||||
## Develop
|
||||
|
||||
Launch Application
|
||||
|
||||
```bash
|
||||
npm install -g yarn
|
||||
yarn
|
||||
@@ -65,15 +63,6 @@ npm run build
|
||||
node dist/src/spec/webdriverio.js
|
||||
```
|
||||
|
||||
## Create a release
|
||||
|
||||
Create a PR to `release` branch.
|
||||
There needs to be a "feat: some new feature" or "fix: some bugfix" commit for a new release to be created
|
||||
|
||||
## Create a beta release
|
||||
|
||||
Create a PR to `beta` branch. A "feat" or "fix" commit is necessary to create a new version.
|
||||
|
||||
## Write docs
|
||||
|
||||
```
|
||||
|
||||
+5
-5
@@ -7,10 +7,10 @@
|
||||
"build": "webpack --mode production",
|
||||
"dev": "node_modules/.bin/webpack-dev-server --mode development --progress",
|
||||
"test": "cross-env TS_NODE_PROJECT=test/tsconfig.json yarn mochatest",
|
||||
"mochatest": "mocha --require ts-node/register --require source-map-support/register --recursive src/*/**/*.spec.ts"
|
||||
"mochatest": "mocha --require ts-node/register src/**/*.spec.ts"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
"node": "19"
|
||||
},
|
||||
"author": "",
|
||||
"license": "CC-BY-ND-4.0",
|
||||
@@ -21,7 +21,7 @@
|
||||
"@material-ui/styles": "4.11",
|
||||
"@types/react-transition-group": "^4",
|
||||
"ace-builds": "^1.4.11",
|
||||
"axios": "^0.28.0",
|
||||
"axios": "^0.26.0",
|
||||
"compare-versions": "^3.5.0",
|
||||
"copy-text-to-clipboard": "^2.1.0",
|
||||
"d3": "^5.9.7",
|
||||
@@ -75,7 +75,7 @@
|
||||
"file-loader": "^6.2.0",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"lodash": "^4.17.21",
|
||||
"mocha": "^10.4.0",
|
||||
"mocha": "^9.2.1",
|
||||
"moment": "^2.29.1",
|
||||
"node-loader": "^0.6.0",
|
||||
"source-map-loader": "^0.2.4",
|
||||
@@ -90,4 +90,4 @@
|
||||
"peerDependencies": {
|
||||
"electron": "^29"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ class TreeNodeTitle extends React.PureComponent<TreeNodeProps, {}> {
|
||||
const name = this.props.name || (this.props.treeNode.sourceEdge && this.props.treeNode.sourceEdge.name)
|
||||
|
||||
return (
|
||||
<span key="edge" className={this.props.classes.sourceEdge} data-test-topic={name}>
|
||||
<span key="edge" className={this.props.classes.sourceEdge}>
|
||||
{name}
|
||||
</span>
|
||||
)
|
||||
|
||||
@@ -77,11 +77,11 @@ export function createEmptyConnection(): ConnectionOptions {
|
||||
export function makeDefaultConnections() {
|
||||
return {
|
||||
// remember: there was also iot.eclipse.org once
|
||||
'mqtt.eclipseprojects.io': {
|
||||
'mqtt.eclipse.org': {
|
||||
...createEmptyConnection(),
|
||||
id: 'mqtt.eclipseprojects.io',
|
||||
name: 'mqtt.eclipseprojects.io',
|
||||
host: 'mqtt.eclipseprojects.io',
|
||||
id: 'mqtt.eclipse.org',
|
||||
name: 'mqtt.eclipse.org',
|
||||
host: 'mqtt.eclipse.org',
|
||||
},
|
||||
'test.mosquitto.org': {
|
||||
...createEmptyConnection(),
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
--require ts-node/register
|
||||
--require source-map-support/register
|
||||
--recursive ./src/**/*.spec.ts
|
||||
+10
-5
@@ -1,6 +1,6 @@
|
||||
// const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||
const webpack = require('webpack')
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const webpack = require('webpack');
|
||||
|
||||
module.exports = {
|
||||
entry: {
|
||||
@@ -63,8 +63,13 @@ module.exports = {
|
||||
use: ['style-loader', 'css-loader'],
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpg|gif)$/i,
|
||||
type: 'asset/resource',
|
||||
test: /\.(png|jpg|gif)$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'file-loader',
|
||||
options: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
// {
|
||||
// test: /\.node$/,
|
||||
@@ -96,4 +101,4 @@ module.exports = {
|
||||
// "react": "React",
|
||||
// "react-dom": "ReactDOM"
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
+73
-93
@@ -653,6 +653,11 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@ungap/promise-all-settled@1.1.2":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44"
|
||||
integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==
|
||||
|
||||
"@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5":
|
||||
version "1.11.6"
|
||||
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24"
|
||||
@@ -930,19 +935,12 @@ async@^2.5.0:
|
||||
dependencies:
|
||||
lodash "^4.17.14"
|
||||
|
||||
asynckit@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
|
||||
|
||||
axios@^0.28.0:
|
||||
version "0.28.1"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.28.1.tgz#2a7bcd34a3837b71ee1a5ca3762214b86b703e70"
|
||||
integrity sha512-iUcGA5a7p0mVb4Gm/sy+FSECNkPFT4y7wt6OM/CDpO/OnNCvSs3PoMG8ibrC9jRoGYU0gUK5pXVC4NPXq6lHRQ==
|
||||
axios@^0.26.0:
|
||||
version "0.26.1"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.1.tgz#1ede41c51fcf51bbbd6fd43669caaa4f0495aaa9"
|
||||
integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==
|
||||
dependencies:
|
||||
follow-redirects "^1.15.0"
|
||||
form-data "^4.0.0"
|
||||
proxy-from-env "^1.1.0"
|
||||
follow-redirects "^1.14.8"
|
||||
|
||||
backo2@1.0.2:
|
||||
version "1.0.2"
|
||||
@@ -1018,13 +1016,6 @@ brace-expansion@^1.1.7:
|
||||
balanced-match "^1.0.0"
|
||||
concat-map "0.0.1"
|
||||
|
||||
brace-expansion@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
|
||||
integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
|
||||
dependencies:
|
||||
balanced-match "^1.0.0"
|
||||
|
||||
braces@^3.0.2, braces@~3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
|
||||
@@ -1216,13 +1207,6 @@ colorette@^2.0.10, colorette@^2.0.14:
|
||||
resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a"
|
||||
integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==
|
||||
|
||||
combined-stream@^1.0.8:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
||||
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
|
||||
dependencies:
|
||||
delayed-stream "~1.0.0"
|
||||
|
||||
commander@2, commander@^2.20.0:
|
||||
version "2.20.3"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
|
||||
@@ -1305,10 +1289,10 @@ cookie-signature@1.0.6:
|
||||
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
|
||||
integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==
|
||||
|
||||
cookie@0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051"
|
||||
integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==
|
||||
cookie@0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b"
|
||||
integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
|
||||
|
||||
copy-text-to-clipboard@^2.1.0:
|
||||
version "2.2.0"
|
||||
@@ -1759,7 +1743,14 @@ debug@2.6.9:
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@4.3.4, debug@^4.1.0:
|
||||
debug@4.3.3:
|
||||
version "4.3.3"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664"
|
||||
integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==
|
||||
dependencies:
|
||||
ms "2.1.2"
|
||||
|
||||
debug@^4.1.0:
|
||||
version "4.3.4"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
|
||||
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
|
||||
@@ -1827,11 +1818,6 @@ define-properties@^1.2.1:
|
||||
has-property-descriptors "^1.0.0"
|
||||
object-keys "^1.1.1"
|
||||
|
||||
delayed-stream@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
|
||||
|
||||
depd@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
|
||||
@@ -2103,16 +2089,16 @@ execa@^5.0.0:
|
||||
strip-final-newline "^2.0.0"
|
||||
|
||||
express@^4.17.3:
|
||||
version "4.19.2"
|
||||
resolved "https://registry.yarnpkg.com/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465"
|
||||
integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==
|
||||
version "4.18.3"
|
||||
resolved "https://registry.yarnpkg.com/express/-/express-4.18.3.tgz#6870746f3ff904dee1819b82e4b51509afffb0d4"
|
||||
integrity sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==
|
||||
dependencies:
|
||||
accepts "~1.3.8"
|
||||
array-flatten "1.1.1"
|
||||
body-parser "1.20.2"
|
||||
content-disposition "0.5.4"
|
||||
content-type "~1.0.4"
|
||||
cookie "0.6.0"
|
||||
cookie "0.5.0"
|
||||
cookie-signature "1.0.6"
|
||||
debug "2.6.9"
|
||||
depd "2.0.0"
|
||||
@@ -2210,19 +2196,10 @@ flat@^5.0.2:
|
||||
resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241"
|
||||
integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==
|
||||
|
||||
follow-redirects@^1.0.0, follow-redirects@^1.15.0:
|
||||
version "1.15.6"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b"
|
||||
integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==
|
||||
|
||||
form-data@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
|
||||
integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
|
||||
dependencies:
|
||||
asynckit "^0.4.0"
|
||||
combined-stream "^1.0.8"
|
||||
mime-types "^2.1.12"
|
||||
follow-redirects@^1.0.0, follow-redirects@^1.14.8:
|
||||
version "1.15.5"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.5.tgz#54d4d6d062c0fa7d9d17feb008461550e3ba8020"
|
||||
integrity sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==
|
||||
|
||||
forwarded@0.2.0:
|
||||
version "0.2.0"
|
||||
@@ -2304,16 +2281,17 @@ glob-to-regexp@^0.4.1:
|
||||
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
|
||||
integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
|
||||
|
||||
glob@8.1.0:
|
||||
version "8.1.0"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e"
|
||||
integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==
|
||||
glob@7.2.0:
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
|
||||
integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
|
||||
dependencies:
|
||||
fs.realpath "^1.0.0"
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "^5.0.1"
|
||||
minimatch "^3.0.4"
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
glob@^7.1.3:
|
||||
version "7.2.3"
|
||||
@@ -2352,6 +2330,11 @@ grapheme-splitter@^1.0.4:
|
||||
resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e"
|
||||
integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==
|
||||
|
||||
growl@1.10.5:
|
||||
version "1.10.5"
|
||||
resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e"
|
||||
integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==
|
||||
|
||||
gzip-size@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462"
|
||||
@@ -3039,7 +3022,7 @@ mime-db@1.52.0, "mime-db@>= 1.43.0 < 2":
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
|
||||
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
|
||||
|
||||
mime-types@^2.1.12, mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34:
|
||||
mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34:
|
||||
version "2.1.35"
|
||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
|
||||
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
|
||||
@@ -3068,54 +3051,51 @@ minimalistic-assert@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
|
||||
integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==
|
||||
|
||||
minimatch@5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b"
|
||||
integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==
|
||||
minimatch@4.2.1:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-4.2.1.tgz#40d9d511a46bdc4e563c22c3080cde9c0d8299b4"
|
||||
integrity sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==
|
||||
dependencies:
|
||||
brace-expansion "^2.0.1"
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
minimatch@^3.1.1:
|
||||
minimatch@^3.0.4, minimatch@^3.1.1:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
|
||||
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
|
||||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
minimatch@^5.0.1:
|
||||
version "5.1.6"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96"
|
||||
integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==
|
||||
dependencies:
|
||||
brace-expansion "^2.0.1"
|
||||
|
||||
minimist@^1.2.0:
|
||||
version "1.2.8"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
|
||||
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
|
||||
|
||||
mocha@^10.4.0:
|
||||
version "10.4.0"
|
||||
resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.4.0.tgz#ed03db96ee9cfc6d20c56f8e2af07b961dbae261"
|
||||
integrity sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA==
|
||||
mocha@^9.2.1:
|
||||
version "9.2.2"
|
||||
resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.2.2.tgz#d70db46bdb93ca57402c809333e5a84977a88fb9"
|
||||
integrity sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==
|
||||
dependencies:
|
||||
"@ungap/promise-all-settled" "1.1.2"
|
||||
ansi-colors "4.1.1"
|
||||
browser-stdout "1.3.1"
|
||||
chokidar "3.5.3"
|
||||
debug "4.3.4"
|
||||
debug "4.3.3"
|
||||
diff "5.0.0"
|
||||
escape-string-regexp "4.0.0"
|
||||
find-up "5.0.0"
|
||||
glob "8.1.0"
|
||||
glob "7.2.0"
|
||||
growl "1.10.5"
|
||||
he "1.2.0"
|
||||
js-yaml "4.1.0"
|
||||
log-symbols "4.1.0"
|
||||
minimatch "5.0.1"
|
||||
minimatch "4.2.1"
|
||||
ms "2.1.3"
|
||||
nanoid "3.3.1"
|
||||
serialize-javascript "6.0.0"
|
||||
strip-json-comments "3.1.1"
|
||||
supports-color "8.1.1"
|
||||
workerpool "6.2.1"
|
||||
which "2.0.2"
|
||||
workerpool "6.2.0"
|
||||
yargs "16.2.0"
|
||||
yargs-parser "20.2.4"
|
||||
yargs-unparser "2.0.0"
|
||||
@@ -3158,6 +3138,11 @@ multicast-dns@^7.2.5:
|
||||
dns-packet "^5.2.2"
|
||||
thunky "^1.0.2"
|
||||
|
||||
nanoid@3.3.1:
|
||||
version "3.3.1"
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35"
|
||||
integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==
|
||||
|
||||
negotiator@0.6.3:
|
||||
version "0.6.3"
|
||||
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
|
||||
@@ -3521,11 +3506,6 @@ proxy-addr@~2.0.7:
|
||||
forwarded "0.2.0"
|
||||
ipaddr.js "1.9.1"
|
||||
|
||||
proxy-from-env@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
|
||||
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
|
||||
|
||||
punycode@^2.1.0:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
|
||||
@@ -4421,9 +4401,9 @@ webpack-cli@^4.9.2:
|
||||
webpack-merge "^5.7.3"
|
||||
|
||||
webpack-dev-middleware@^5.3.1:
|
||||
version "5.3.4"
|
||||
resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz#eb7b39281cbce10e104eb2b8bf2b63fce49a3517"
|
||||
integrity sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==
|
||||
version "5.3.3"
|
||||
resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz#efae67c2793908e7311f1d9b06f2a08dcc97e51f"
|
||||
integrity sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==
|
||||
dependencies:
|
||||
colorette "^2.0.10"
|
||||
memfs "^3.4.3"
|
||||
@@ -4525,7 +4505,7 @@ websocket-extensions@>=0.1.1:
|
||||
resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42"
|
||||
integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==
|
||||
|
||||
which@^2.0.1:
|
||||
which@2.0.2, which@^2.0.1:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
|
||||
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
|
||||
@@ -4537,10 +4517,10 @@ wildcard@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67"
|
||||
integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==
|
||||
|
||||
workerpool@6.2.1:
|
||||
version "6.2.1"
|
||||
resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343"
|
||||
integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==
|
||||
workerpool@6.2.0:
|
||||
version "6.2.0"
|
||||
resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.0.tgz#827d93c9ba23ee2019c3ffaff5c27fccea289e8b"
|
||||
integrity sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==
|
||||
|
||||
wrap-ansi@^7.0.0:
|
||||
version "7.0.0"
|
||||
|
||||
+3
-1
@@ -10,10 +10,12 @@ install:
|
||||
- ps: Install-Product node 19
|
||||
|
||||
build_script:
|
||||
- yarn install --frozen-lockfile
|
||||
- yarn
|
||||
- yarn build
|
||||
- yarn prepare-release
|
||||
- yarn package appx
|
||||
- yarn prepare-release
|
||||
- yarn package linux
|
||||
|
||||
test_script:
|
||||
- yarn lint
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
"description": "",
|
||||
"main": "build/index.js",
|
||||
"scripts": {
|
||||
"test": "mocha --require ts-node/register --require source-map-support/register --recursive ./src/*/**/*.spec.ts",
|
||||
"test": "mocha",
|
||||
"build": "tsc",
|
||||
"test-inspect": "mocha --inspect-brk --require ts-node/register --require source-map-support/register --recursive ./src/*/**/*.spec.ts",
|
||||
"coverage": "nyc mocha --require ts-node/register --require source-map-support/register --recursive ./src/*/**/*.spec.ts",
|
||||
"test-inspect": "mocha --inspect-brk",
|
||||
"coverage": "nyc mocha",
|
||||
"debug": "ts-node --inspect ./src/index.ts",
|
||||
"postinstall": "yarn build"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
"node": "19"
|
||||
},
|
||||
"author": "",
|
||||
"license": "CC-BY-ND-4.0",
|
||||
@@ -41,9 +41,9 @@
|
||||
"peerDependencies": {
|
||||
"fs-extra": "^8.0.1",
|
||||
"js-base64": "^2.5.1",
|
||||
"long": "^4.0.0",
|
||||
"lowdb": "^1.0.0",
|
||||
"mqtt": "^3.0.0",
|
||||
"protobufjs": "^6.11.4"
|
||||
"protobufjs": "~6.11.2",
|
||||
"long": "^4.0.0"
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,22 @@
|
||||
import { readFileSync } from 'fs'
|
||||
import * as protobuf from 'protobufjs'
|
||||
import { Base64Message } from './Base64Message'
|
||||
import { Decoder } from './Decoder'
|
||||
import { get } from 'sparkplug-payload'
|
||||
var sparkplug = get("spBv1.0")
|
||||
|
||||
const buffer = readFileSync(require.resolve('../../../../res/sparkplug_b.proto'))
|
||||
const root = protobuf.parse(buffer.toString()).root
|
||||
export let SparkplugPayload = root.lookupType('com.cirruslink.sparkplug.protobuf.Payload')
|
||||
|
||||
export const SparkplugDecoder = {
|
||||
decode(input: Buffer): Base64Message {
|
||||
decode(input: Buffer): Base64Message | undefined {
|
||||
try {
|
||||
const message = Base64Message.fromString(JSON.stringify(
|
||||
// @ts-ignore
|
||||
sparkplug.decodePayload(new Uint8Array(input)))
|
||||
const message = Base64Message.fromString(
|
||||
JSON.stringify(SparkplugPayload.toObject(SparkplugPayload.decode(new Uint8Array(input))))
|
||||
)
|
||||
message.decoder = Decoder.SPARKPLUG
|
||||
return message
|
||||
} catch {
|
||||
const message = Base64Message.fromString("Failed to decode sparkplugb payload")
|
||||
message.decoder = Decoder.NONE
|
||||
return message
|
||||
// ignore
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@@ -47,17 +47,9 @@ export class ConnectionManager {
|
||||
buffer = buffer.slice(0, 20000)
|
||||
}
|
||||
|
||||
let decoded_payload = null
|
||||
// spell-checker: disable-next-line
|
||||
if (topic.match(/^spBv1\.0\/[^/]+\/[ND](DATA|CMD|DEATH|BIRTH)\/[^/]+(\/[^/]+)?$/u)) {
|
||||
decoded_payload = SparkplugDecoder.decode(buffer)
|
||||
} else {
|
||||
decoded_payload = Base64Message.fromBuffer(buffer)
|
||||
}
|
||||
|
||||
backendEvents.emit(messageEvent, {
|
||||
topic,
|
||||
payload: decoded_payload,
|
||||
payload: SparkplugDecoder.decode(buffer) ?? Base64Message.fromBuffer(buffer),
|
||||
qos: packet.qos,
|
||||
retain: packet.retain,
|
||||
messageId: packet.messageId,
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
--require ts-node/register
|
||||
--require source-map-support/register
|
||||
--recursive ./src/**/*.spec.ts
|
||||
+18
-25
@@ -5,7 +5,7 @@
|
||||
"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf"
|
||||
integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==
|
||||
integrity sha1-m4sMxmPWaafY9vXQiToU00jzD78=
|
||||
|
||||
"@protobufjs/base64@^1.1.2":
|
||||
version "1.1.2"
|
||||
@@ -20,12 +20,12 @@
|
||||
"@protobufjs/eventemitter@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70"
|
||||
integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==
|
||||
integrity sha1-NVy8mLr61ZePntCV85diHx0Ga3A=
|
||||
|
||||
"@protobufjs/fetch@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45"
|
||||
integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==
|
||||
integrity sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=
|
||||
dependencies:
|
||||
"@protobufjs/aspromise" "^1.1.1"
|
||||
"@protobufjs/inquire" "^1.1.0"
|
||||
@@ -33,49 +33,47 @@
|
||||
"@protobufjs/float@^1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1"
|
||||
integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==
|
||||
integrity sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=
|
||||
|
||||
"@protobufjs/inquire@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089"
|
||||
integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==
|
||||
integrity sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=
|
||||
|
||||
"@protobufjs/path@^1.1.2":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d"
|
||||
integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==
|
||||
integrity sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=
|
||||
|
||||
"@protobufjs/pool@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54"
|
||||
integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==
|
||||
integrity sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=
|
||||
|
||||
"@protobufjs/utf8@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
|
||||
integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
|
||||
integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=
|
||||
|
||||
"@types/long@^4.0.1":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a"
|
||||
integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9"
|
||||
integrity sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==
|
||||
|
||||
"@types/node@>=13.7.0":
|
||||
version "20.12.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.2.tgz#9facdd11102f38b21b4ebedd9d7999663343d72e"
|
||||
integrity sha512-zQ0NYO87hyN6Xrclcqp7f8ZbXNbRfoGWNcMvHTPQp9UUrwI0mI7XBz+cu7/W6/VClYo2g63B0cjull/srU7LgQ==
|
||||
dependencies:
|
||||
undici-types "~5.26.4"
|
||||
version "16.4.13"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.4.13.tgz#7dfd9c14661edc65cccd43a29eb454174642370d"
|
||||
integrity sha512-bLL69sKtd25w7p1nvg9pigE4gtKVpGTPojBFLMkGHXuUgap2sLqQt2qUnqmVCDfzGUL0DRNZP+1prIZJbMeAXg==
|
||||
|
||||
long@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28"
|
||||
integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==
|
||||
|
||||
protobufjs@^6.11.4:
|
||||
version "6.11.4"
|
||||
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.4.tgz#29a412c38bf70d89e537b6d02d904a6f448173aa"
|
||||
integrity sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==
|
||||
protobufjs@^6.11.2:
|
||||
version "6.11.2"
|
||||
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.2.tgz#de39fabd4ed32beaa08e9bb1e30d08544c1edf8b"
|
||||
integrity sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==
|
||||
dependencies:
|
||||
"@protobufjs/aspromise" "^1.1.2"
|
||||
"@protobufjs/base64" "^1.1.2"
|
||||
@@ -90,8 +88,3 @@ protobufjs@^6.11.4:
|
||||
"@types/long" "^4.0.1"
|
||||
"@types/node" ">=13.7.0"
|
||||
long "^4.0.0"
|
||||
|
||||
undici-types@~5.26.4:
|
||||
version "5.26.5"
|
||||
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
|
||||
integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
FROM node:20
|
||||
FROM node:11-stretch
|
||||
|
||||
RUN DEBIAN_FRONTEND="noninteractive" apt-get update \
|
||||
&& apt-get install -y --no-install-recommends ca-certificates nano ffmpeg xvfb git-core tmux locales mosquitto x11vnc
|
||||
&& apt-get install -y --no-install-recommends nano ffmpeg xvfb git-core tmux locales mosquitto x11vnc
|
||||
RUN apt-get install -yq --no-install-recommends libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 libnss3
|
||||
|
||||
# Generate locales for TMUX
|
||||
@@ -12,5 +12,6 @@ ENV LC_ALL en_US.UTF-8
|
||||
|
||||
CMD /bin/bash
|
||||
|
||||
COPY cloneBuildAndTest.sh ./
|
||||
VOLUME /app
|
||||
EXPOSE 5900
|
||||
@@ -1,7 +1,11 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
yarn install --frozen-lockfile
|
||||
git clone https://github.com/thomasnordquist/MQTT-Explorer.git /app
|
||||
cd /app
|
||||
git checkout travis-ui-tests
|
||||
|
||||
yarn
|
||||
yarn build
|
||||
|
||||
yarn ui-test
|
||||
|
||||
+11
-20
@@ -1,12 +1,11 @@
|
||||
{
|
||||
"name": "MQTT-Explorer",
|
||||
"version": "0.4.0-beta.5",
|
||||
"version": "0.4.0-beta1",
|
||||
"description": "Explore your message queues",
|
||||
"main": "dist/src/electron.js",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
"node": "19"
|
||||
},
|
||||
"private": "true",
|
||||
"scripts": {
|
||||
"start": "electron .",
|
||||
"test": "yarn test:app && yarn test:backend",
|
||||
@@ -16,12 +15,10 @@
|
||||
"dev": "npm-run-all --parallel dev:*",
|
||||
"dev:app": "cd app && npm run dev",
|
||||
"dev:electron": "tsc && electron . --development",
|
||||
"lint": "npm-run-all --parallel lint:prettier lint:tslint lint:spellcheck",
|
||||
"lint:fix": "npm-run-all lint:tslint:fix lint:prettier:fix",
|
||||
"lint": "npm-run-all --parallel lint:prettier lint:tslint",
|
||||
"lint:prettier": "prettier --check \"**/*.ts{x,}\"",
|
||||
"lint:prettier:fix": "prettier --write \"**/*.ts{x,}\"",
|
||||
"lint:tslint": "tslint -p ./",
|
||||
"lint:tslint:fix": "tslint -p ./ --fix",
|
||||
"lint:spellcheck": "cspell -e ./build -e \"node_modules\" \"**/*.ts{x,}\"",
|
||||
"build": "tsc && cd app && yarn run build && cd ..",
|
||||
"prepare-release": "ts-node scripts/prepare-release.ts",
|
||||
@@ -77,11 +74,7 @@
|
||||
"license": "CC-BY-ND-4.0",
|
||||
"devDependencies": {
|
||||
"@babel/runtime": "^7.17.2",
|
||||
"@cspell/dict-typescript": "^3.1.2",
|
||||
"@electron/notarize": "^2.3.0",
|
||||
"@semantic-release/changelog": "^6.0.3",
|
||||
"@semantic-release/commit-analyzer": "^12.0.0",
|
||||
"@semantic-release/git": "^10.0.1",
|
||||
"@types/chai": "^4.1.7",
|
||||
"@types/fs-extra": "8",
|
||||
"@types/lowdb": "^1.0.6",
|
||||
@@ -94,30 +87,28 @@
|
||||
"@types/uuid": "^8.3.4",
|
||||
"builder-util-runtime": "^9",
|
||||
"chai": "^4.2.0",
|
||||
"cspell": "^8.6.1",
|
||||
"electron": "29.2.0",
|
||||
"cspell": "^4.0.28",
|
||||
"electron": "29.1.1",
|
||||
"electron-builder": "^24.13.3",
|
||||
"mocha": "^10.4.0",
|
||||
"mocha": "7.1",
|
||||
"mustache": "4",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"nyc": "15",
|
||||
"playwright": "^1.43.0",
|
||||
"prettier": "^3.2.5",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"semantic-release": "^23.0.8",
|
||||
"semantic-release-export-data": "^1.0.1",
|
||||
"source-map-support": "^0.5.9",
|
||||
"sparkplug-client": "^3.2.4",
|
||||
"spectron": "19",
|
||||
"ts-node": "^10.9.2",
|
||||
"tslint": "^6.1.3",
|
||||
"tslint-config-airbnb": "^5.11.2",
|
||||
"tslint-react": "^5.0.0",
|
||||
"tslint-react-recommended": "^1.0.15",
|
||||
"typescript": "^4.5.5"
|
||||
"typescript": "^4.5.5",
|
||||
"webdriverio": "7.16"
|
||||
},
|
||||
"dependencies": {
|
||||
"about-window": "^1.12.1",
|
||||
"axios": "^0.28.0",
|
||||
"axios": "^0.19.0",
|
||||
"dot-prop": "^5.0.0",
|
||||
"electron-log": "4.4.6",
|
||||
"electron-updater": "^4.6",
|
||||
@@ -127,8 +118,8 @@
|
||||
"lowdb": "^1.0.0",
|
||||
"mime": "^2.4.4",
|
||||
"mqtt": "^4.3.6",
|
||||
"protobufjs": "~6.11.2",
|
||||
"sha1": "^1.1.1",
|
||||
"sparkplug-payload": "^1.0.3",
|
||||
"uuid": "^8.3.2",
|
||||
"yarn-run-all": "^3.1.1"
|
||||
}
|
||||
|
||||
+14
-14
@@ -7,16 +7,7 @@ const linuxAppImage: builder.CliOptions = {
|
||||
x64: true,
|
||||
ia32: false,
|
||||
armv7l: true,
|
||||
arm64: true,
|
||||
projectDir: './build/clean',
|
||||
publish: 'always',
|
||||
}
|
||||
|
||||
const linuxSnap: builder.CliOptions = {
|
||||
x64: true,
|
||||
ia32: false,
|
||||
armv7l: false, // not supported to build on x64
|
||||
arm64: false, // not supported to build on x64
|
||||
arm64: false,
|
||||
projectDir: './build/clean',
|
||||
publish: 'always',
|
||||
}
|
||||
@@ -25,7 +16,16 @@ const linuxDeb: builder.CliOptions = {
|
||||
x64: true,
|
||||
ia32: false,
|
||||
armv7l: true,
|
||||
arm64: true,
|
||||
arm64: false,
|
||||
projectDir: './build/clean',
|
||||
publish: 'always',
|
||||
}
|
||||
|
||||
const linuxSnap: builder.CliOptions = {
|
||||
x64: true,
|
||||
ia32: false,
|
||||
armv7l: false,
|
||||
arm64: false,
|
||||
projectDir: './build/clean',
|
||||
publish: 'always',
|
||||
}
|
||||
@@ -61,7 +61,7 @@ const mac: builder.CliOptions = {
|
||||
x64: true,
|
||||
ia32: false,
|
||||
armv7l: false,
|
||||
arm64: true,
|
||||
arm64: false,
|
||||
projectDir: './build/clean',
|
||||
publish: 'always',
|
||||
}
|
||||
@@ -82,8 +82,8 @@ async function executeBuild() {
|
||||
break
|
||||
case 'mac':
|
||||
await buildWithOptions(mac, { platform: 'mac', package: 'dmg' })
|
||||
// await buildWithOptions(mac, { platform: 'mac', package: 'mas' })
|
||||
// await buildWithOptions(mac, { platform: 'mac', package: 'zip' })
|
||||
await buildWithOptions(mac, { platform: 'mac', package: 'mas' })
|
||||
await buildWithOptions(mac, { platform: 'mac', package: 'zip' })
|
||||
break
|
||||
default:
|
||||
await buildWithOptions({ ...mac, projectDir: '' }, { platform: 'mac', package: 'mas-dev' })
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
syntax = "proto2";
|
||||
|
||||
//
|
||||
// To compile:
|
||||
// cd client_libraries/java
|
||||
// protoc --proto_path=../../ --java_out=src/main/java ../../sparkplug_b.proto
|
||||
//
|
||||
package com.cirruslink.sparkplug.protobuf;
|
||||
|
||||
option java_package = "com.cirruslink.sparkplug.protobuf";
|
||||
option java_outer_classname = "SparkplugBProto";
|
||||
|
||||
message Payload {
|
||||
/*
|
||||
// Indexes of Data Types
|
||||
|
||||
// Unknown placeholder for future expansion.
|
||||
Unknown = 0;
|
||||
|
||||
// Basic Types
|
||||
Int8 = 1;
|
||||
Int16 = 2;
|
||||
Int32 = 3;
|
||||
Int64 = 4;
|
||||
UInt8 = 5;
|
||||
UInt16 = 6;
|
||||
UInt32 = 7;
|
||||
UInt64 = 8;
|
||||
Float = 9;
|
||||
Double = 10;
|
||||
Boolean = 11;
|
||||
String = 12;
|
||||
DateTime = 13;
|
||||
Text = 14;
|
||||
|
||||
// Additional Metric Types
|
||||
UUID = 15;
|
||||
DataSet = 16;
|
||||
Bytes = 17;
|
||||
File = 18;
|
||||
Template = 19;
|
||||
|
||||
// Additional PropertyValue Types
|
||||
PropertySet = 20;
|
||||
PropertySetList = 21;
|
||||
|
||||
*/
|
||||
|
||||
message Template {
|
||||
|
||||
message Parameter {
|
||||
optional string name = 1;
|
||||
optional uint32 type = 2;
|
||||
|
||||
oneof value {
|
||||
uint32 int_value = 3;
|
||||
uint64 long_value = 4;
|
||||
float float_value = 5;
|
||||
double double_value = 6;
|
||||
bool boolean_value = 7;
|
||||
string string_value = 8;
|
||||
ParameterValueExtension extension_value = 9;
|
||||
}
|
||||
|
||||
message ParameterValueExtension {
|
||||
extensions 1 to max;
|
||||
}
|
||||
}
|
||||
|
||||
optional string version = 1; // The version of the Template to prevent mismatches
|
||||
repeated Metric metrics = 2; // Each metric is the name of the metric and the datatype of the member but does not contain a value
|
||||
repeated Parameter parameters = 3;
|
||||
optional string template_ref = 4; // Reference to a template if this is extending a Template or an instance - must exist if an instance
|
||||
optional bool is_definition = 5;
|
||||
extensions 6 to max;
|
||||
}
|
||||
|
||||
message DataSet {
|
||||
|
||||
message DataSetValue {
|
||||
|
||||
oneof value {
|
||||
uint32 int_value = 1;
|
||||
uint64 long_value = 2;
|
||||
float float_value = 3;
|
||||
double double_value = 4;
|
||||
bool boolean_value = 5;
|
||||
string string_value = 6;
|
||||
DataSetValueExtension extension_value = 7;
|
||||
}
|
||||
|
||||
message DataSetValueExtension {
|
||||
extensions 1 to max;
|
||||
}
|
||||
}
|
||||
|
||||
message Row {
|
||||
repeated DataSetValue elements = 1;
|
||||
extensions 2 to max; // For third party extensions
|
||||
}
|
||||
|
||||
optional uint64 num_of_columns = 1;
|
||||
repeated string columns = 2;
|
||||
repeated uint32 types = 3;
|
||||
repeated Row rows = 4;
|
||||
extensions 5 to max; // For third party extensions
|
||||
}
|
||||
|
||||
message PropertyValue {
|
||||
|
||||
optional uint32 type = 1;
|
||||
optional bool is_null = 2;
|
||||
|
||||
oneof value {
|
||||
uint32 int_value = 3;
|
||||
uint64 long_value = 4;
|
||||
float float_value = 5;
|
||||
double double_value = 6;
|
||||
bool boolean_value = 7;
|
||||
string string_value = 8;
|
||||
PropertySet propertyset_value = 9;
|
||||
PropertySetList propertysets_value = 10; // List of Property Values
|
||||
PropertyValueExtension extension_value = 11;
|
||||
}
|
||||
|
||||
message PropertyValueExtension {
|
||||
extensions 1 to max;
|
||||
}
|
||||
}
|
||||
|
||||
message PropertySet {
|
||||
repeated string keys = 1; // Names of the properties
|
||||
repeated PropertyValue values = 2;
|
||||
extensions 3 to max;
|
||||
}
|
||||
|
||||
message PropertySetList {
|
||||
repeated PropertySet propertyset = 1;
|
||||
extensions 2 to max;
|
||||
}
|
||||
|
||||
message MetaData {
|
||||
// Bytes specific metadata
|
||||
optional bool is_multi_part = 1;
|
||||
|
||||
// General metadata
|
||||
optional string content_type = 2; // Content/Media type
|
||||
optional uint64 size = 3; // File size, String size, Multi-part size, etc
|
||||
optional uint64 seq = 4; // Sequence number for multi-part messages
|
||||
|
||||
// File metadata
|
||||
optional string file_name = 5; // File name
|
||||
optional string file_type = 6; // File type (i.e. xml, json, txt, cpp, etc)
|
||||
optional string md5 = 7; // md5 of data
|
||||
|
||||
// Catchalls and future expansion
|
||||
optional string description = 8; // Could be anything such as json or xml of custom properties
|
||||
extensions 9 to max;
|
||||
}
|
||||
|
||||
message Metric {
|
||||
|
||||
optional string name = 1; // Metric name - should only be included on birth
|
||||
optional uint64 alias = 2; // Metric alias - tied to name on birth and included in all later DATA messages
|
||||
optional uint64 timestamp = 3; // Timestamp associated with data acquisition time
|
||||
optional uint32 datatype = 4; // DataType of the metric/tag value
|
||||
optional bool is_historical = 5; // If this is historical data and should not update real time tag
|
||||
optional bool is_transient = 6; // Tells consuming clients such as MQTT Engine to not store this as a tag
|
||||
optional bool is_null = 7; // If this is null - explicitly say so rather than using -1, false, etc for some datatypes.
|
||||
optional MetaData metadata = 8; // Metadata for the payload
|
||||
optional PropertySet properties = 9;
|
||||
|
||||
oneof value {
|
||||
uint32 int_value = 10;
|
||||
uint64 long_value = 11;
|
||||
float float_value = 12;
|
||||
double double_value = 13;
|
||||
bool boolean_value = 14;
|
||||
string string_value = 15;
|
||||
bytes bytes_value = 16; // Bytes, File
|
||||
DataSet dataset_value = 17;
|
||||
Template template_value = 18;
|
||||
MetricValueExtension extension_value = 19;
|
||||
}
|
||||
|
||||
message MetricValueExtension {
|
||||
extensions 1 to max;
|
||||
}
|
||||
}
|
||||
|
||||
optional uint64 timestamp = 1; // Timestamp at message sending time
|
||||
repeated Metric metrics = 2; // Repeated forever - no limit in Google Protobufs
|
||||
optional uint64 seq = 3; // Sequence number
|
||||
optional string uuid = 4; // UUID to track message type in terms of schema definitions
|
||||
optional bytes body = 5; // To optionally bypass the whole definition above
|
||||
extensions 6 to max; // For third party extensions
|
||||
}
|
||||
@@ -17,18 +17,18 @@ async function prepareRelease() {
|
||||
|
||||
// Install app dependencies
|
||||
chdir('app')
|
||||
await exec('yarn', ['install', '--frozen-lockfile'])
|
||||
await exec('yarn')
|
||||
chdir('..')
|
||||
|
||||
// Install electron dependencies
|
||||
await exec('yarn', ['install', '--frozen-lockfile'])
|
||||
await exec('yarn')
|
||||
|
||||
// Build App and Electron backend
|
||||
await exec('yarn', ['build'])
|
||||
|
||||
// Clean up
|
||||
await fs.remove('node_modules')
|
||||
await exec('yarn', ['install', '--production', '--frozen-lockfile']) // Do not clean up, electron version detection will fail otherwise
|
||||
await exec('yarn', ['install', '--production']) // Do not clean up, electron version detection will fail otherwise
|
||||
await fs.remove(path.join('app', 'node_modules'))
|
||||
|
||||
chdir(originalDir)
|
||||
|
||||
@@ -1,232 +0,0 @@
|
||||
/********************************************************************************
|
||||
* Copyright (c) 2016-2018 Cirrus Link Solutions and others
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Cirrus Link Solutions - initial implementation
|
||||
********************************************************************************/
|
||||
var SparkplugClient = require('sparkplug-client')
|
||||
|
||||
/*
|
||||
* Main sample function which includes the run() function for running the sample
|
||||
*/
|
||||
var sample = (function () {
|
||||
var config = {
|
||||
serverUrl: 'tcp://127.0.0.1:1883',
|
||||
username: '',
|
||||
password: '',
|
||||
groupId: 'Sparkplug Devices',
|
||||
edgeNode: 'JavaScript Edge Node',
|
||||
clientId: 'JavaScriptSimpleEdgeNode',
|
||||
version: 'spBv1.0',
|
||||
},
|
||||
hwVersion = 'Emulated Hardware',
|
||||
swVersion = 'v1.0.0',
|
||||
deviceId = 'Emulated Device',
|
||||
sparkPlugClient,
|
||||
publishPeriod = 5000,
|
||||
// Generates a random integer
|
||||
randomInt = function () {
|
||||
return 1 + Math.floor(Math.random() * 10)
|
||||
},
|
||||
// Get BIRTH payload for the edge node
|
||||
getNodeBirthPayload = function () {
|
||||
return {
|
||||
timestamp: new Date().getTime(),
|
||||
metrics: [
|
||||
{
|
||||
name: 'Node Control/Rebirth',
|
||||
type: 'boolean',
|
||||
value: false,
|
||||
},
|
||||
{
|
||||
name: 'Template1',
|
||||
type: 'template',
|
||||
value: {
|
||||
isDefinition: true,
|
||||
metrics: [
|
||||
{ name: 'myBool', value: false, type: 'boolean' },
|
||||
{ name: 'myInt', value: 0, type: 'int' },
|
||||
],
|
||||
parameters: [
|
||||
{
|
||||
name: 'param1',
|
||||
type: 'string',
|
||||
value: 'value1',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
// Get BIRTH payload for the device
|
||||
getDeviceBirthPayload = function () {
|
||||
return {
|
||||
timestamp: new Date().getTime(),
|
||||
metrics: [
|
||||
{ name: 'my_boolean', value: Math.random() > 0.5, type: 'boolean' },
|
||||
{ name: 'my_double', value: Math.random() * 0.123456789, type: 'double' },
|
||||
{ name: 'my_float', value: Math.random() * 0.123, type: 'float' },
|
||||
{ name: 'my_int', value: randomInt(), type: 'int' },
|
||||
{ name: 'my_long', value: randomInt() * 214748364700, type: 'long' },
|
||||
{ name: 'Inputs/0', value: true, type: 'boolean' },
|
||||
{ name: 'Inputs/1', value: 0, type: 'int' },
|
||||
{ name: 'Inputs/2', value: 1.23, type: 'float' },
|
||||
{ name: 'Outputs/0', value: true, type: 'boolean' },
|
||||
{ name: 'Outputs/1', value: 0, type: 'int' },
|
||||
{ name: 'Outputs/2', value: 1.23, type: 'float' },
|
||||
{ name: 'Properties/hw_version', value: hwVersion, type: 'string' },
|
||||
{ name: 'Properties/sw_version', value: swVersion, type: 'string' },
|
||||
{
|
||||
name: 'my_dataset',
|
||||
type: 'dataset',
|
||||
value: {
|
||||
numOfColumns: 2,
|
||||
types: ['string', 'string'],
|
||||
columns: ['str1', 'str2'],
|
||||
rows: [
|
||||
['x', 'a'],
|
||||
['y', 'b'],
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'TemplateInstance1',
|
||||
type: 'template',
|
||||
value: {
|
||||
templateRef: 'Template1',
|
||||
isDefinition: false,
|
||||
metrics: [
|
||||
{ name: 'myBool', value: true, type: 'boolean' },
|
||||
{ name: 'myInt', value: 100, type: 'int' },
|
||||
],
|
||||
parameters: [
|
||||
{
|
||||
name: 'param1',
|
||||
type: 'string',
|
||||
value: 'value2',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
// Get data payload for the device
|
||||
getDataPayload = function () {
|
||||
return {
|
||||
timestamp: new Date().getTime(),
|
||||
metrics: [
|
||||
{ name: 'my_boolean', value: Math.random() > 0.5, type: 'boolean' },
|
||||
{ name: 'my_double', value: Math.random() * 0.123456789, type: 'double' },
|
||||
{ name: 'my_float', value: Math.random() * 0.123, type: 'float' },
|
||||
{ name: 'my_int', value: randomInt(), type: 'int' },
|
||||
{ name: 'my_long', value: randomInt() * 214748364700, type: 'long' },
|
||||
],
|
||||
}
|
||||
},
|
||||
// Runs the sample
|
||||
run = function () {
|
||||
// Create the SparkplugClient
|
||||
sparkplugClient = SparkplugClient.newClient(config)
|
||||
|
||||
// Create Incoming Message Handler
|
||||
sparkplugClient.on('message', function (topic, payload) {
|
||||
console.log(topic, payload)
|
||||
})
|
||||
|
||||
// Create 'birth' handler
|
||||
sparkplugClient.on('birth', function () {
|
||||
// Publish Node BIRTH certificate
|
||||
sparkplugClient.publishNodeBirth(getNodeBirthPayload())
|
||||
// Publish Device BIRTH certificate
|
||||
sparkplugClient.publishDeviceBirth(deviceId, getDeviceBirthPayload())
|
||||
})
|
||||
|
||||
// Create node command handler
|
||||
sparkplugClient.on('ncmd', function (payload) {
|
||||
var timestamp = payload.timestamp,
|
||||
metrics = payload.metrics
|
||||
|
||||
if (metrics !== undefined && metrics !== null) {
|
||||
for (var i = 0; i < metrics.length; i++) {
|
||||
var metric = metrics[i]
|
||||
if (metric.name == 'Node Control/Rebirth' && metric.value) {
|
||||
console.log("Received 'Rebirth' command")
|
||||
// Publish Node BIRTH certificate
|
||||
sparkplugClient.publishNodeBirth(getNodeBirthPayload())
|
||||
// Publish Device BIRTH certificate
|
||||
sparkplugClient.publishDeviceBirth(deviceId, getDeviceBirthPayload())
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Create device command handler
|
||||
sparkplugClient.on('dcmd', function (deviceId, payload) {
|
||||
var timestamp = payload.timestamp,
|
||||
metrics = payload.metrics,
|
||||
inboundMetricMap = {},
|
||||
outboundMetric = [],
|
||||
outboundPayload
|
||||
|
||||
console.log('Command recevied for device ' + deviceId)
|
||||
|
||||
// Loop over the metrics and store them in a map
|
||||
if (metrics !== undefined && metrics !== null) {
|
||||
for (var i = 0; i < metrics.length; i++) {
|
||||
var metric = metrics[i]
|
||||
inboundMetricMap[metric.name] = metric.value
|
||||
}
|
||||
}
|
||||
if (inboundMetricMap['Outputs/0'] !== undefined && inboundMetricMap['Outputs/0'] !== null) {
|
||||
console.log('Outputs/0: ' + inboundMetricMap['Outputs/0'])
|
||||
outboundMetric.push({ name: 'Inputs/0', value: inboundMetricMap['Outputs/0'], type: 'boolean' })
|
||||
outboundMetric.push({ name: 'Outputs/0', value: inboundMetricMap['Outputs/0'], type: 'boolean' })
|
||||
console.log('Updated value for Inputs/0 ' + inboundMetricMap['Outputs/0'])
|
||||
} else if (inboundMetricMap['Outputs/1'] !== undefined && inboundMetricMap['Outputs/1'] !== null) {
|
||||
console.log('Outputs/1: ' + inboundMetricMap['Outputs/1'])
|
||||
outboundMetric.push({ name: 'Inputs/1', value: inboundMetricMap['Outputs/1'], type: 'int' })
|
||||
outboundMetric.push({ name: 'Outputs/1', value: inboundMetricMap['Outputs/1'], type: 'int' })
|
||||
console.log('Updated value for Inputs/1 ' + inboundMetricMap['Outputs/1'])
|
||||
} else if (inboundMetricMap['Outputs/2'] !== undefined && inboundMetricMap['Outputs/2'] !== null) {
|
||||
console.log('Outputs/2: ' + inboundMetricMap['Outputs/2'])
|
||||
outboundMetric.push({ name: 'Inputs/2', value: inboundMetricMap['Outputs/2'], type: 'float' })
|
||||
outboundMetric.push({ name: 'Outputs/2', value: inboundMetricMap['Outputs/2'], type: 'float' })
|
||||
console.log('Updated value for Inputs/2 ' + inboundMetricMap['Outputs/2'])
|
||||
}
|
||||
|
||||
outboundPayload = {
|
||||
timestamp: new Date().getTime(),
|
||||
metrics: outboundMetric,
|
||||
}
|
||||
|
||||
// Publish device data
|
||||
sparkplugClient.publishDeviceData(deviceId, outboundPayload)
|
||||
})
|
||||
|
||||
for (var i = 1; i < 101; i++) {
|
||||
// Set up a device data publish for i*publishPeriod milliseconds from now
|
||||
setTimeout(function () {
|
||||
// Publish device data
|
||||
sparkplugClient.publishDeviceData(deviceId, getDataPayload())
|
||||
|
||||
// End the client connection after the last publish
|
||||
if (i === 100) {
|
||||
sparkplugClient.stop()
|
||||
}
|
||||
}, i * publishPeriod)
|
||||
}
|
||||
}
|
||||
|
||||
return { run: run }
|
||||
})()
|
||||
|
||||
// Run the sample
|
||||
sample.run()
|
||||
+17
-26
@@ -1,25 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
function finish {
|
||||
set +e
|
||||
echo "Exiting, cleaning up.."
|
||||
|
||||
echo "Stopping TMUX session (record).."
|
||||
tmux kill-session -t record || echo "Already stopped"
|
||||
|
||||
if [[ ! -z "$PID_MOSQUITTO" ]]; then
|
||||
echo "Stopping mosquitto ($PID_MOSQUITTO).."
|
||||
kill "$PID_MOSQUITTO" || echo "Already stopped"
|
||||
fi
|
||||
|
||||
if [[ ! -z "$PID_VNC" ]]; then
|
||||
echo "Stopping VNC ($PID_VNC).."
|
||||
kill "$PID_VNC" || echo "Already stopped"
|
||||
fi
|
||||
|
||||
if [[ ! -z "$PID_XVFB" ]]; then
|
||||
echo "Stopping XVFB ($PID_XVFB).."
|
||||
kill "$PID_XVFB" || echo "Already stopped"
|
||||
fi
|
||||
echo "Exiting, cleaning up"
|
||||
tmux send-keys -t record q || echo "No tmux was running"
|
||||
#echo kill $PID_XVFB $PID_CHROMEDRIVER $PID_MOSQUITTO
|
||||
#kill $PID_XVFB $PID_CHROMEDRIVER $PID_MOSQUITTO
|
||||
}
|
||||
|
||||
trap finish EXIT
|
||||
@@ -33,25 +18,28 @@ export PID_XVFB=$!
|
||||
sleep 2
|
||||
|
||||
# Debug with VNC
|
||||
x11vnc -localhost -rfbport 5900 -passwd "bierbier" -display :$SCR &
|
||||
while [ "$TEST_EXIT_CODE" = "" ]; do x11vnc -localhost -passwd "bierbier" -display :$SCR; done &
|
||||
export PID_VNC=$!
|
||||
|
||||
# Start mqtt broker
|
||||
mosquitto &
|
||||
export PID_MOSQUITTO=$!
|
||||
|
||||
DISPLAY=:$SCR ./node_modules/.bin/chromedriver --url-base=wd/hub --port=9515 &
|
||||
export PID_CHROMEDRIVER=$!
|
||||
sleep 2
|
||||
|
||||
# Delete old video
|
||||
rm -f ./app*.mp4
|
||||
rm -f ./qrawvideorgb24.yuv
|
||||
rm ./app.mp4 || echo no need to delete ./app.mp4
|
||||
|
||||
# Start recoring in tmux
|
||||
# tmux new-session -d -s record ffmpeg -f x11grab -draw_mouse 0 -video_size $DIMENSIONS -i :$SCR -codec:v libx264 -r 20 ./app.mp4
|
||||
#tmux new-session -d -s record ffmpeg -f x11grab -draw_mouse 0 -video_size $DIMENSIONS -i :$SCR -codec:v libx264 -r 20 ./app.mp4
|
||||
tmux new-session -d -s record ffmpeg -f x11grab -draw_mouse 0 -video_size $DIMENSIONS -i :$SCR -r 20 -vcodec rawvideo -pix_fmt yuv420p qrawvideorgb24.yuv
|
||||
|
||||
# Start tests
|
||||
DISPLAY=:$SCR node dist/src/spec/demoVideo.js
|
||||
node dist/src/spec/demoVideo.js
|
||||
TEST_EXIT_CODE=$?
|
||||
echo "Test script exited with $TEST_EXIT_CODE"
|
||||
echo "Webriver exitet with $TEST_EXIT_CODE"
|
||||
|
||||
# Stop recording
|
||||
tmux send-keys -t record q
|
||||
@@ -59,4 +47,7 @@ tmux send-keys -t record q
|
||||
# Ensure video is written
|
||||
sleep 5
|
||||
|
||||
# Process the video
|
||||
./scripts/prepareVideo.sh
|
||||
|
||||
exit $TEST_EXIT_CODE
|
||||
|
||||
@@ -27,7 +27,7 @@ async function createDraft(tag: string) {
|
||||
draft: true,
|
||||
},
|
||||
})
|
||||
// @ts-ignore
|
||||
|
||||
return cleanUploadUrl(response.data.upload_url)
|
||||
}
|
||||
|
||||
@@ -76,7 +76,6 @@ async function uploadFile(uploadUrl: string, file: string) {
|
||||
const data = fs.readFileSync(file)
|
||||
const mimeType = mime.getType(path.extname(file))
|
||||
|
||||
// @ts-ignore
|
||||
return axios({
|
||||
data,
|
||||
method: 'post',
|
||||
|
||||
@@ -17,12 +17,10 @@ export async function waitForDevServer() {
|
||||
}
|
||||
|
||||
export function loadDevTools() {
|
||||
/* spell-checker: disable */
|
||||
// Redux
|
||||
// BrowserWindow.addDevToolsExtension(
|
||||
// path.join(os.homedir(), '/Library/Application Support/Google/Chrome/Default/Extensions/lmhkpmbekcpmknklioeibfkpmmfibljd/2.17.0_0/')
|
||||
// )
|
||||
/* spell-checker: enable */
|
||||
}
|
||||
|
||||
export function isDev() {
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ log.info('App starting...')
|
||||
const connectionManager = new ConnectionManager()
|
||||
connectionManager.manageConnections()
|
||||
|
||||
const configStorage = new ConfigStorage(path.join(app.getPath('userData'), 'settings.json'))
|
||||
const configStorage = new ConfigStorage(path.join(app.getPath('appData'), app.name, 'settings.json'))
|
||||
configStorage.init()
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
|
||||
+64
-73
@@ -1,11 +1,7 @@
|
||||
import * as fs from 'fs'
|
||||
import * as os from 'os'
|
||||
import * as path from 'path'
|
||||
|
||||
import { ElectronApplication, _electron as electron } from 'playwright'
|
||||
|
||||
import * as webdriverio from 'webdriverio'
|
||||
import mockMqtt, { stop as stopMqtt } from './mock-mqtt'
|
||||
import { default as MockSparkplug } from './mock-sparkplugb'
|
||||
import { clearOldTopics } from './scenarios/clearOldTopics'
|
||||
import { clearSearch, searchTree } from './scenarios/searchTree'
|
||||
import { clickOnHistory, createFakeMousePointer, hideText, showText, sleep } from './util'
|
||||
@@ -14,7 +10,7 @@ import { copyTopicToClipboard } from './scenarios/copyTopicToClipboard'
|
||||
import { copyValueToClipboard } from './scenarios/copyValueToClipboard'
|
||||
import { disconnect } from './scenarios/disconnect'
|
||||
import { publishTopic } from './scenarios/publishTopic'
|
||||
import { Scene, SceneBuilder } from './SceneBuilder'
|
||||
import { SceneBuilder } from './SceneBuilder'
|
||||
import { showAdvancedConnectionSettings } from './scenarios/showAdvancedConnectionSettings'
|
||||
import { showJsonPreview } from './scenarios/showJsonPreview'
|
||||
import { showMenu } from './scenarios/showMenu'
|
||||
@@ -22,15 +18,6 @@ import { showNumericPlot } from './scenarios/showNumericPlot'
|
||||
import { showOffDiffCapability } from './scenarios/showOffDiffCapability'
|
||||
import { showZoomLevel } from './scenarios/showZoomLevel'
|
||||
|
||||
/**
|
||||
* A convenience method that handles gracefully cleaning up the test run.
|
||||
*/
|
||||
const cleanUp = async (scenes: SceneBuilder, electronApp: ElectronApplication) => {
|
||||
// Exit app.
|
||||
fs.writeFileSync('scenes.json', JSON.stringify(scenes.scenes, undefined, ' '))
|
||||
await electronApp.close()
|
||||
}
|
||||
|
||||
process.on('unhandledRejection', (error: Error | any) => {
|
||||
console.error('unhandledRejection', error.message, error.stack)
|
||||
process.exit(1)
|
||||
@@ -38,115 +25,119 @@ process.on('unhandledRejection', (error: Error | any) => {
|
||||
|
||||
const runningUiTestOnCi = os.platform() === 'darwin' ? [] : ['--runningUiTestOnCi']
|
||||
|
||||
const options = {
|
||||
host: '127.0.0.1', // Use localhost as chrome driver server
|
||||
port: 9515, // "9515" is the port opened by chrome driver.
|
||||
path: '/wd/hub',
|
||||
capabilities: {
|
||||
browserName: 'chrome',
|
||||
'goog:chromeOptions': {
|
||||
binary: `${__dirname}/../../../node_modules/.bin/electron`,
|
||||
args: [
|
||||
`--app=${__dirname}/../../..`,
|
||||
'--force-device-scale-factor=1',
|
||||
'--no-sandbox',
|
||||
'--disable-dev-shm-usage',
|
||||
'--disable-extensions',
|
||||
].concat(runningUiTestOnCi),
|
||||
windowTypes: ['app', 'webview'],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
async function doStuff() {
|
||||
console.log('Waiting for MQTT Broker on port 1880 (no auth)')
|
||||
await mockMqtt()
|
||||
console.log('start webdriver')
|
||||
|
||||
console.log('Starting playwright/electron')
|
||||
|
||||
// Launch Electron app.
|
||||
const electronApp: ElectronApplication = await electron.launch({
|
||||
args: [`${__dirname}/../../..`, ...runningUiTestOnCi],
|
||||
})
|
||||
|
||||
console.log('Playwright started')
|
||||
// Get the first window that the app opens, wait if necessary.
|
||||
const page = await electronApp.firstWindow({ timeout: 3000 })
|
||||
// Print the title.
|
||||
console.log(await page.title())
|
||||
// Capture a screenshot.
|
||||
await page.screenshot({ path: 'intro.png' })
|
||||
// Direct Electron console to Node terminal.
|
||||
page.on('console', console.log)
|
||||
const browser = await webdriverio.remote(options)
|
||||
await createFakeMousePointer(browser)
|
||||
|
||||
// Wait for Username input to be visible
|
||||
await page.locator('//label[contains(text(), "Username")]/..//input')
|
||||
await browser.$('//label[contains(text(), "Username")]/..//input')
|
||||
|
||||
const scenes = new SceneBuilder()
|
||||
await scenes.record('connect', async () => {
|
||||
await connectTo('127.0.0.1', page)
|
||||
await MockSparkplug.run() // Start sparkplug client after connect or birth topics will be missed
|
||||
await connectTo('127.0.0.1', browser)
|
||||
await sleep(1000)
|
||||
})
|
||||
|
||||
await scenes.record('numeric_plots', async () => {
|
||||
await showText('Plot topic history', 1500, page)
|
||||
await showNumericPlot(page)
|
||||
await showText('Plot topic history', 1500, browser)
|
||||
await showNumericPlot(browser)
|
||||
await sleep(2000)
|
||||
})
|
||||
|
||||
await scenes.record('json-formatting', async () => {
|
||||
await showJsonPreview(page)
|
||||
await showText('Formatted messages', 1500, page, 'top')
|
||||
await showJsonPreview(browser)
|
||||
await showText('Formatted messages', 1500, browser, 'top')
|
||||
await sleep(1500)
|
||||
})
|
||||
|
||||
await scenes.record('diffs', async () => {
|
||||
await showOffDiffCapability(page)
|
||||
await hideText(page)
|
||||
await showOffDiffCapability(browser)
|
||||
await hideText(browser)
|
||||
})
|
||||
|
||||
// disable this scenario for now until expandTopic is sorted out
|
||||
// await scenes.record('publish_topic', async () => {
|
||||
// await showText('Publish topics', 1500, page, 'top')
|
||||
// await clickOnHistory(page)
|
||||
// await publishTopic(page)
|
||||
// await sleep(1000)
|
||||
// })
|
||||
await scenes.record('publish_topic', async () => {
|
||||
await showText('Publish topics', 1500, browser, 'top')
|
||||
await clickOnHistory(browser)
|
||||
await publishTopic(browser)
|
||||
await sleep(1000)
|
||||
})
|
||||
|
||||
await scenes.record('clipboard', async () => {
|
||||
await showText('Copy to Clipboard', 1500, page)
|
||||
await copyTopicToClipboard(page)
|
||||
await hideText(page)
|
||||
await copyValueToClipboard(page)
|
||||
await showText('Copy to Clipboard', 1500, browser)
|
||||
await copyTopicToClipboard(browser)
|
||||
await hideText(browser)
|
||||
await copyValueToClipboard(browser)
|
||||
await sleep(1000)
|
||||
})
|
||||
|
||||
await scenes.record('topic_filter', async () => {
|
||||
await showText('Search topic hierarchy', 0, page, 'middle')
|
||||
await searchTree('temp', page)
|
||||
await hideText(page)
|
||||
await showText('Topics containing "temp"', 1500, page)
|
||||
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(page)
|
||||
await clearSearch(browser)
|
||||
await sleep(1000)
|
||||
})
|
||||
|
||||
// disable this scenario for now until expandTopic is sorted out
|
||||
// await scenes.record('delete_retained_topics', async () => {
|
||||
// await hideText(page)
|
||||
// await showText('Delete retained topics', 5000, page)
|
||||
// await clearOldTopics(page)
|
||||
// await hideText(page)
|
||||
// })
|
||||
await scenes.record('delete_retained_topics', async () => {
|
||||
await hideText(browser)
|
||||
await showText('Delete retained topics', 5000, browser)
|
||||
await clearOldTopics(browser)
|
||||
await hideText(browser)
|
||||
})
|
||||
|
||||
await scenes.record('settings', async () => {
|
||||
await showText('Settings', 1500, page)
|
||||
await showMenu(page)
|
||||
await showText('Settings', 1500, browser)
|
||||
await showMenu(browser)
|
||||
})
|
||||
|
||||
await scenes.record('customize_subscriptions', async () => {
|
||||
await sleep(2000)
|
||||
await disconnect(page)
|
||||
await showText('Customize Subscriptions', 1500, page, 'top')
|
||||
await showAdvancedConnectionSettings(page)
|
||||
await disconnect(browser)
|
||||
await showText('Customize Subscriptions', 1500, browser, 'top')
|
||||
await showAdvancedConnectionSettings(browser)
|
||||
})
|
||||
|
||||
await scenes.record('keyboard_shortcuts', async () => {
|
||||
await showText('Keyboard shortcuts', 1500, page, 'middle')
|
||||
await showText('Keyboard shortcuts', 1500, browser, 'middle')
|
||||
await sleep(1750)
|
||||
await showZoomLevel(page)
|
||||
await showZoomLevel(browser)
|
||||
})
|
||||
|
||||
await scenes.record('end', async () => {
|
||||
await showText('The End', 3000, page, 'middle')
|
||||
await showText('The End', 3000, browser, 'middle')
|
||||
await sleep(3000)
|
||||
})
|
||||
|
||||
browser.closeWindow()
|
||||
stopMqtt()
|
||||
console.log('Stopped mqtt client')
|
||||
|
||||
cleanUp(scenes, electronApp)
|
||||
fs.writeFileSync('scenes.json', JSON.stringify(scenes.scenes, undefined, ' '))
|
||||
}
|
||||
|
||||
doStuff()
|
||||
|
||||
+38
-20
@@ -1,6 +1,5 @@
|
||||
import * as os from 'os'
|
||||
import { ElectronApplication, _electron as electron } from 'playwright'
|
||||
|
||||
import * as webdriverio from 'webdriverio'
|
||||
import mockMqtt, { stopUpdates as stopMqttUpdates } from './mock-mqtt'
|
||||
import { ClassNameMapping, countInstancesOf, createFakeMousePointer, getHeapDump, setFast, sleep } from './util'
|
||||
import { clearSearch, searchTree } from './scenarios/searchTree'
|
||||
@@ -14,53 +13,67 @@ process.on('unhandledRejection', (error: Error | any) => {
|
||||
|
||||
const runningUiTestOnCi = os.platform() === 'darwin' ? [] : ['--runningUiTestOnCi']
|
||||
|
||||
const options = {
|
||||
host: '127.0.0.1', // Use localhost as chrome driver server
|
||||
port: 9515, // "9515" is the port opened by chrome driver.
|
||||
capabilities: {
|
||||
browserName: 'chrome',
|
||||
'goog:chromeOptions': {
|
||||
binary: `${__dirname}/../../../node_modules/.bin/electron`,
|
||||
args: [
|
||||
`--app=${__dirname}/../../..`,
|
||||
'--force-device-scale-factor=1',
|
||||
'--no-sandbox',
|
||||
'--disable-dev-shm-usage',
|
||||
'--disable-extensions',
|
||||
].concat(runningUiTestOnCi),
|
||||
windowTypes: ['app', 'webview'],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
async function doStuff() {
|
||||
console.log('Waiting for MQTT Broker on port 1880 (no auth)')
|
||||
await mockMqtt()
|
||||
console.log('start webdriver')
|
||||
|
||||
console.log('Starting playwright/electron')
|
||||
|
||||
// Launch Electron app.
|
||||
const electronApp: ElectronApplication = await electron.launch({
|
||||
args: [`${__dirname}/../../..`, ...runningUiTestOnCi],
|
||||
})
|
||||
|
||||
console.log('Playwright started')
|
||||
// Get the first window that the app opens, wait if necessary.
|
||||
const browser = await electronApp.firstWindow({ timeout: 3000 })
|
||||
// Print the title.
|
||||
console.log(await browser.title())
|
||||
// Capture a screenshot.
|
||||
await browser.screenshot({ path: 'intro.png' })
|
||||
// Direct Electron console to Node terminal.
|
||||
browser.on('console', console.log)
|
||||
|
||||
const browser = await webdriverio.remote(options)
|
||||
setFast()
|
||||
await createFakeMousePointer(browser)
|
||||
|
||||
// Wait for Username input to be visible
|
||||
await browser.locator('//label[contains(text(), "Username")]/..//input')
|
||||
await browser.$('//label[contains(text(), "Username")]/..//input')
|
||||
await connectTo('127.0.0.1', browser)
|
||||
stopMqttUpdates()
|
||||
await sleep(1000, true)
|
||||
|
||||
const heapDump = await getHeapDump(browser)
|
||||
const initialTreeOccurrences = await countInstancesOf(heapDump, ClassNameMapping.Tree)
|
||||
const initialNodeOccurrences = await countInstancesOf(heapDump, ClassNameMapping.TreeNode)
|
||||
console.log(initialTreeOccurrences, initialNodeOccurrences)
|
||||
|
||||
await doX(3, async () => {
|
||||
await reconnect(browser)
|
||||
})
|
||||
|
||||
await sleep(1000, true)
|
||||
|
||||
await doX(15, async () => {
|
||||
await searchTree('temp', browser)
|
||||
await reconnect(browser)
|
||||
})
|
||||
|
||||
await searchTree('ab', browser)
|
||||
await clearSearch(browser)
|
||||
|
||||
await searchTree('temp', browser)
|
||||
await clearSearch(browser)
|
||||
|
||||
await sleep(1000, true)
|
||||
|
||||
await waitForGarbageCollectorToDetermineLeak(browser, initialTreeOccurrences, initialNodeOccurrences)
|
||||
}
|
||||
|
||||
async function waitForGarbageCollectorToDetermineLeak(
|
||||
browser: any,
|
||||
initialTreeOccurrences: number,
|
||||
@@ -77,6 +90,7 @@ async function waitForGarbageCollectorToDetermineLeak(
|
||||
const heapDump = await getHeapDump(browser)
|
||||
const currentTreeOccurrences = await countInstancesOf(heapDump, ClassNameMapping.Tree)
|
||||
const currentNodeOccurrences = await countInstancesOf(heapDump, ClassNameMapping.TreeNode)
|
||||
|
||||
// Temporary "leaks" are expected due to React Fibers memoization
|
||||
if (
|
||||
Math.abs(initialTreeOccurrences - currentTreeOccurrences) > 1 ||
|
||||
@@ -93,17 +107,21 @@ async function waitForGarbageCollectorToDetermineLeak(
|
||||
} else {
|
||||
leak = false
|
||||
}
|
||||
|
||||
const treeDelta = lastTreeOccurrences >= 0 ? currentTreeOccurrences - lastTreeOccurrences : -1
|
||||
const nodeDelta = lastTreeOccurrences >= 0 ? currentNodeOccurrences - lastNodeOccurrences : -1
|
||||
delta = treeDelta + nodeDelta
|
||||
|
||||
lastTreeOccurrences = currentTreeOccurrences
|
||||
lastNodeOccurrences = currentNodeOccurrences
|
||||
}
|
||||
|
||||
if (leak) {
|
||||
console.error('leak')
|
||||
process.exit(100)
|
||||
}
|
||||
}
|
||||
|
||||
async function doX(x: number, action: () => Promise<any>) {
|
||||
for (let i = 0; i < x; i += 1) {
|
||||
await action()
|
||||
|
||||
@@ -1,249 +0,0 @@
|
||||
/********************************************************************************
|
||||
* Copyright (c) 2016-2018 Cirrus Link Solutions and others
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Cirrus Link Solutions - initial implementation
|
||||
********************************************************************************/
|
||||
import * as SparkplugClient from 'sparkplug-client'
|
||||
import type { UPayload } from 'sparkplug-client'
|
||||
import type { UMetric } from 'sparkplug-payload/lib/sparkplugbpayload'
|
||||
|
||||
/*
|
||||
* Main sample function which includes the run() function for running the sample
|
||||
*/
|
||||
|
||||
|
||||
export interface MockSparkplugClient {
|
||||
stop: () => void
|
||||
}
|
||||
|
||||
var sample = (function () {
|
||||
var config = {
|
||||
serverUrl: 'tcp://127.0.0.1:1883',
|
||||
username: '',
|
||||
password: '',
|
||||
groupId: 'Sparkplug Devices',
|
||||
edgeNode: 'JavaScript Edge Node',
|
||||
clientId: 'JavaScriptSimpleEdgeNode',
|
||||
version: 'spBv1.0',
|
||||
},
|
||||
hwVersion = 'Emulated Hardware',
|
||||
swVersion = 'v1.0.0',
|
||||
deviceId = 'Emulated Device',
|
||||
sparkPlugClient,
|
||||
publishPeriod = 5000,
|
||||
// Generates a random integer
|
||||
randomInt = function () {
|
||||
return 1 + Math.floor(Math.random() * 10)
|
||||
},
|
||||
// Get BIRTH payload for the edge node
|
||||
getNodeBirthPayload = function (): UPayload {
|
||||
return {
|
||||
timestamp: new Date().getTime(),
|
||||
metrics: [
|
||||
{
|
||||
name: 'Node Control/Rebirth',
|
||||
type: 'Boolean',
|
||||
value: false,
|
||||
},
|
||||
{
|
||||
name: 'Template1',
|
||||
type: 'Template',
|
||||
value: {
|
||||
isDefinition: true,
|
||||
metrics: [
|
||||
{ name: 'myBool', value: false, type: 'Boolean' },
|
||||
{ name: 'myInt', value: 0, type: 'UInt32' },
|
||||
],
|
||||
parameters: [
|
||||
{
|
||||
name: 'param1',
|
||||
type: 'String',
|
||||
value: 'value1',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
// Get BIRTH payload for the device
|
||||
getDeviceBirthPayload = function (): UPayload {
|
||||
return {
|
||||
timestamp: new Date().getTime(),
|
||||
metrics: [
|
||||
{ name: 'my_boolean', value: Math.random() > 0.5, type: 'Boolean' },
|
||||
{ name: 'my_double', value: Math.random() * 0.123456789, type: 'Double' },
|
||||
{ name: 'my_float', value: Math.random() * 0.123, type: 'Float' },
|
||||
{ name: 'my_int', value: randomInt(), type: 'Int8' },
|
||||
{ name: 'my_long', value: randomInt() * 214748364700, type: 'Int64' },
|
||||
{ name: 'Inputs/0', value: true, type: 'Boolean' },
|
||||
{ name: 'Inputs/1', value: 0, type: 'Int8' },
|
||||
{ name: 'Inputs/2', value: 1.23, type: 'UInt64' },
|
||||
{ name: 'Outputs/0', value: true, type: 'Boolean' },
|
||||
{ name: 'Outputs/1', value: 0, type: 'Int16' },
|
||||
{ name: 'Outputs/2', value: 1.23, type: 'UInt64' },
|
||||
{ name: 'Properties/hw_version', value: hwVersion, type: 'String' },
|
||||
{ name: 'Properties/sw_version', value: swVersion, type: 'String' },
|
||||
{
|
||||
name: 'my_dataset',
|
||||
type: 'DataSet',
|
||||
value: {
|
||||
numOfColumns: 2,
|
||||
types: ['String', 'String'],
|
||||
columns: ['str1', 'str2'],
|
||||
rows: [
|
||||
['x', 'a'],
|
||||
['y', 'b'],
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'TemplateInstance1',
|
||||
type: 'Template',
|
||||
value: {
|
||||
templateRef: 'Template1',
|
||||
isDefinition: false,
|
||||
metrics: [
|
||||
{ name: 'myBool', value: true, type: 'Boolean' },
|
||||
{ name: 'myInt', value: 100, type: 'Int8' },
|
||||
],
|
||||
parameters: [
|
||||
{
|
||||
name: 'param1',
|
||||
type: 'String',
|
||||
value: 'value2',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
// Get data payload for the device
|
||||
getDataPayload = function (): UPayload {
|
||||
return {
|
||||
timestamp: new Date().getTime(),
|
||||
metrics: [
|
||||
{ name: 'my_boolean', value: Math.random() > 0.5, type: 'Boolean' },
|
||||
{ name: 'my_double', value: Math.random() * 0.123456789, type: 'Double' },
|
||||
{ name: 'my_float', value: Math.random() * 0.123, type: 'UInt64' },
|
||||
{ name: 'my_int', value: randomInt(), type: 'Int16' },
|
||||
{ name: 'my_long', value: randomInt() * 214748364700, type: 'UInt64' },
|
||||
],
|
||||
}
|
||||
},
|
||||
// Runs the sample
|
||||
run = async function (): Promise<MockSparkplugClient> {
|
||||
// Create the SparkplugClient
|
||||
const sparkplugClient = SparkplugClient.newClient(config)
|
||||
let updateInterval: NodeJS.Timeout | null = null
|
||||
const connected = new Promise<MockSparkplugClient>((resolve) => {
|
||||
|
||||
// Create 'birth' handler
|
||||
sparkplugClient.on('birth', () => {
|
||||
// Publish Node BIRTH certificate
|
||||
sparkplugClient.publishNodeBirth(getNodeBirthPayload())
|
||||
// Publish Device BIRTH certificate
|
||||
sparkplugClient.publishDeviceBirth(deviceId, getDeviceBirthPayload())
|
||||
resolve({
|
||||
stop: () => {
|
||||
if (updateInterval) {
|
||||
clearInterval(updateInterval)
|
||||
}
|
||||
sparkplugClient.stop()
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// Create Incoming Message Handler
|
||||
sparkplugClient.on('message', function (topic: string, payload: UPayload) {
|
||||
console.log(topic, payload)
|
||||
})
|
||||
|
||||
// Create node command handler
|
||||
// spell-checker: disable-next-line
|
||||
sparkplugClient.on('ncmd', function (payload: UPayload) {
|
||||
var timestamp = payload.timestamp,
|
||||
metrics = payload.metrics
|
||||
|
||||
if (metrics !== undefined && metrics !== null) {
|
||||
for (var i = 0; i < metrics.length; i++) {
|
||||
var metric = metrics[i]
|
||||
if (metric.name == 'Node Control/Rebirth' && metric.value) {
|
||||
console.log("Received 'Rebirth' command")
|
||||
// Publish Node BIRTH certificate
|
||||
sparkplugClient.publishNodeBirth(getNodeBirthPayload())
|
||||
// Publish Device BIRTH certificate
|
||||
sparkplugClient.publishDeviceBirth(deviceId, getDeviceBirthPayload())
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Create device command handler
|
||||
// spell-checker: disable-next-line
|
||||
sparkplugClient.on('dcmd', function (deviceId: string, payload: UPayload) {
|
||||
var timestamp = payload.timestamp,
|
||||
metrics = payload.metrics,
|
||||
inboundMetricMap: { [name: string]: any } = {},
|
||||
outboundMetric: Array<UMetric> = [],
|
||||
outboundPayload: UPayload
|
||||
|
||||
console.log('Command received for device ' + deviceId)
|
||||
|
||||
// Loop over the metrics and store them in a map
|
||||
if (metrics !== undefined && metrics !== null) {
|
||||
for (var i = 0; i < metrics.length; i++) {
|
||||
var metric = metrics[i]
|
||||
if (metric.name !== undefined && metric.name !== null) {
|
||||
inboundMetricMap[metric.name] = metric.value
|
||||
}
|
||||
}
|
||||
}
|
||||
if (inboundMetricMap['Outputs/0'] !== undefined && inboundMetricMap['Outputs/0'] !== null) {
|
||||
console.log('Outputs/0: ' + inboundMetricMap['Outputs/0'])
|
||||
outboundMetric.push({ name: 'Inputs/0', value: inboundMetricMap['Outputs/0'], type: 'Boolean' })
|
||||
outboundMetric.push({ name: 'Outputs/0', value: inboundMetricMap['Outputs/0'], type: 'Boolean' })
|
||||
console.log('Updated value for Inputs/0 ' + inboundMetricMap['Outputs/0'])
|
||||
} else if (inboundMetricMap['Outputs/1'] !== undefined && inboundMetricMap['Outputs/1'] !== null) {
|
||||
console.log('Outputs/1: ' + inboundMetricMap['Outputs/1'])
|
||||
outboundMetric.push({ name: 'Inputs/1', value: inboundMetricMap['Outputs/1'], type: 'Int32' })
|
||||
outboundMetric.push({ name: 'Outputs/1', value: inboundMetricMap['Outputs/1'], type: 'Int32' })
|
||||
console.log('Updated value for Inputs/1 ' + inboundMetricMap['Outputs/1'])
|
||||
} else if (inboundMetricMap['Outputs/2'] !== undefined && inboundMetricMap['Outputs/2'] !== null) {
|
||||
console.log('Outputs/2: ' + inboundMetricMap['Outputs/2'])
|
||||
outboundMetric.push({ name: 'Inputs/2', value: inboundMetricMap['Outputs/2'], type: 'UInt64' })
|
||||
outboundMetric.push({ name: 'Outputs/2', value: inboundMetricMap['Outputs/2'], type: 'UInt64' })
|
||||
console.log('Updated value for Inputs/2 ' + inboundMetricMap['Outputs/2'])
|
||||
}
|
||||
|
||||
outboundPayload = {
|
||||
timestamp: new Date().getTime(),
|
||||
metrics: outboundMetric,
|
||||
}
|
||||
|
||||
// Publish device data
|
||||
sparkplugClient.publishDeviceData(deviceId, outboundPayload)
|
||||
})
|
||||
|
||||
updateInterval = setInterval(function () {
|
||||
// Publish device data
|
||||
sparkplugClient.publishDeviceData(deviceId, getDataPayload())
|
||||
|
||||
|
||||
}, 2000)
|
||||
return connected
|
||||
}
|
||||
|
||||
return { run: run }
|
||||
})()
|
||||
|
||||
export default sample
|
||||
@@ -1,15 +1,15 @@
|
||||
import { Page } from 'playwright'
|
||||
import { Browser, Element } from 'webdriverio'
|
||||
import { clickOn, expandTopic, moveToCenterOfElement, sleep, writeText } from '../util'
|
||||
|
||||
export async function clearOldTopics(browser: Page) {
|
||||
export async function clearOldTopics(browser: Browser<'async'>) {
|
||||
const topics = ['hello', 'test 123']
|
||||
for (const topic of topics) {
|
||||
await expandTopic(topic, browser)
|
||||
await sleep(1000)
|
||||
|
||||
const deleteButton = await browser.locator('//button[contains(@title, "Delete retained topic")]')
|
||||
await moveToCenterOfElement(deleteButton)
|
||||
await clickOn(deleteButton)
|
||||
const deleteButton = await browser.$('//button[contains(@title, "Delete retained topic")]')
|
||||
await moveToCenterOfElement(deleteButton, browser)
|
||||
await clickOn(deleteButton, browser)
|
||||
await sleep(700)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Browser, Element } from 'webdriverio'
|
||||
import { clickOn, setTextInInput } from '../util'
|
||||
import { Page, Locator } from 'playwright'
|
||||
export async function connectTo(host: string, browser: Page) {
|
||||
|
||||
export async function connectTo(host: string, browser: Browser<'async'>) {
|
||||
await setTextInInput('Host', host, browser)
|
||||
|
||||
await browser.screenshot({ path: 'screen1.png' })
|
||||
await browser.saveScreenshot('screen1.png')
|
||||
|
||||
const connectButton = await browser.locator('//button/span[contains(text(),"Connect")]')
|
||||
await clickOn(connectButton)
|
||||
const connectButton = await browser.$('//button/span[contains(text(),"Connect")]')
|
||||
await clickOn(connectButton, browser)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Page } from 'playwright'
|
||||
import { Browser } from 'webdriverio'
|
||||
import { clickOn } from '../util'
|
||||
|
||||
export async function copyTopicToClipboard(browser: Page) {
|
||||
const copyButton = await browser.locator('//span[contains(text(), "Topic")]//button[1]')
|
||||
await clickOn(copyButton, 1)
|
||||
export async function copyTopicToClipboard(browser: Browser<'async'>) {
|
||||
const copyButton = await browser.$('//span[contains(text(), "Topic")]//button')
|
||||
await clickOn(copyButton, browser, 1)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Page } from 'playwright'
|
||||
import { Browser } from 'webdriverio'
|
||||
import { clickOn } from '../util'
|
||||
|
||||
export async function copyValueToClipboard(browser: Page) {
|
||||
const copyButton = await browser.locator('//span[contains(text(), "Value")]//button')
|
||||
await clickOn(copyButton, 1)
|
||||
export async function copyValueToClipboard(browser: Browser<'async'>) {
|
||||
const copyButton = await browser.$('//span[contains(text(), "Value")]//button')
|
||||
await clickOn(copyButton, browser, 1)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Page } from 'playwright'
|
||||
import { Browser, Element } from 'webdriverio'
|
||||
import { clickOn } from '../util'
|
||||
|
||||
export async function disconnect(browser: Page) {
|
||||
const disconnectButton = await browser.locator('//button/span[contains(text(),"Disconnect")]')
|
||||
await clickOn(disconnectButton)
|
||||
export async function disconnect(browser: Browser<'async'>) {
|
||||
const disconnectButton = await browser.$('//button/span[contains(text(),"Disconnect")]')
|
||||
await clickOn(disconnectButton, browser)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Page, Locator } from 'playwright'
|
||||
import { Browser, Element } from 'webdriverio'
|
||||
import {
|
||||
clickOn,
|
||||
sleep,
|
||||
@@ -9,30 +9,30 @@ import {
|
||||
showText,
|
||||
} from '../util'
|
||||
|
||||
export async function publishTopic(browser: Page) {
|
||||
export async function publishTopic(browser: Browser<'async'>) {
|
||||
await expandTopic('kitchen/lamp/state', browser)
|
||||
const topicInput = await browser.locator('//input[contains(@value,"kitchen/lamp/state")][1]')
|
||||
await clickOn(topicInput)
|
||||
await deleteTextWithBackspaces(topicInput, 120, 5)
|
||||
await writeText('set', topicInput, 300)
|
||||
const topicInput = await browser.$('//input[contains(@value,"kitchen/lamp/state")][1]')
|
||||
await clickOn(topicInput, browser)
|
||||
await deleteTextWithBackspaces(topicInput, browser, 120, 5)
|
||||
await writeText('set', browser, 300)
|
||||
|
||||
const payloadInput = await browser.locator('//*[contains(@class, "ace_text-input")]')
|
||||
const payloadInput = await browser.$('//*[contains(@class, "ace_text-input")]')
|
||||
await writeTextPayload(payloadInput, 'off')
|
||||
await sleep(500)
|
||||
const formatJsonButton = await browser.locator('#sidebar-publish-format-json')
|
||||
await clickOn(formatJsonButton)
|
||||
const formatJsonButton = await browser.$('#sidebar-publish-format-json')
|
||||
await clickOn(formatJsonButton, browser)
|
||||
|
||||
const publishButton = await browser.locator('#publish-button')
|
||||
await moveToCenterOfElement(publishButton)
|
||||
const publishButton = await browser.$('#publish-button')
|
||||
await moveToCenterOfElement(publishButton, browser)
|
||||
await showText('Lamp turns on', 1000, browser, 'top')
|
||||
await sleep(500)
|
||||
|
||||
await clickOn(publishButton)
|
||||
await clickOn(publishButton, browser)
|
||||
|
||||
const sidebarDrawer = await browser.locator('#Sidebar')
|
||||
await sidebarDrawer.scrollIntoViewIfNeeded()
|
||||
const sidebarDrawer = await browser.$('#Sidebar')
|
||||
await sidebarDrawer.scrollIntoView()
|
||||
}
|
||||
|
||||
async function writeTextPayload(payloadInput: Locator, text: string) {
|
||||
await payloadInput.fill(text)
|
||||
async function writeTextPayload(payloadInput: any, text: string) {
|
||||
await payloadInput.setValue(text)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Page } from 'playwright'
|
||||
import { Browser, Element } from 'webdriverio'
|
||||
import { clickOn } from '../util'
|
||||
|
||||
export async function reconnect(browser: Page) {
|
||||
const disconnectButton = await browser.locator('//button/span[contains(text(),"Disconnect")]')
|
||||
await clickOn(disconnectButton)
|
||||
const connectButton = await browser.locator('//button/span[contains(text(),"Connect")]')
|
||||
await clickOn(connectButton)
|
||||
export async function reconnect(browser: Browser<'async'>) {
|
||||
const disconnectButton = await browser.$('//button/span[contains(text(),"Disconnect")]')
|
||||
await clickOn(disconnectButton, browser)
|
||||
const connectButton = await browser.$('//button/span[contains(text(),"Connect")]')
|
||||
await clickOn(connectButton, browser)
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { Page } from 'playwright'
|
||||
import { Browser, Element } from 'webdriverio'
|
||||
import { clickOn, deleteTextWithBackspaces, showText, sleep, writeText } from '../util'
|
||||
|
||||
export async function searchTree(text: string, browser: Page) {
|
||||
const searchField = await browser.locator('//input[contains(@placeholder, "Search")]')
|
||||
await clickOn(searchField, 1)
|
||||
await writeText(text, searchField, 100)
|
||||
export async function searchTree(text: string, browser: Browser<'async'>) {
|
||||
const searchField = await browser.$('//input[contains(@placeholder, "Search")]')
|
||||
await clickOn(searchField, browser, 1)
|
||||
await writeText(text, browser, 100)
|
||||
await sleep(1500)
|
||||
}
|
||||
|
||||
export async function clearSearch(browser: Page) {
|
||||
const searchField = await browser.locator('//input[contains(@placeholder, "Search")]')
|
||||
await clickOn(searchField, 1)
|
||||
await deleteTextWithBackspaces(searchField, 100)
|
||||
export async function clearSearch(browser: Browser<'async'>) {
|
||||
const searchField = await browser.$('//input[contains(@placeholder, "Search")]')
|
||||
await clickOn(searchField, browser, 1)
|
||||
await deleteTextWithBackspaces(searchField, browser, 100)
|
||||
}
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
import { Page } from 'playwright'
|
||||
import { Browser } from 'webdriverio'
|
||||
import { clickOn, sleep, setInputText } from '../util'
|
||||
|
||||
export async function showAdvancedConnectionSettings(browser: Page) {
|
||||
const advancedSettingsButton = await browser.locator('//button/span[contains(text(),"Advanced")]')
|
||||
const addButton = await browser.locator('//button/span[contains(text(),"Add")]')
|
||||
const topicInput = await browser.locator('//*[contains(@class, "advanced-connection-settings-topic-input")]//input')
|
||||
export async function showAdvancedConnectionSettings(browser: Browser<'async'>) {
|
||||
const advancedSettingsButton = await browser.$('//button/span[contains(text(),"Advanced")]')
|
||||
const addButton = await browser.$('//button/span[contains(text(),"Add")]')
|
||||
const topicInput = await browser.$('//*[contains(@class, "advanced-connection-settings-topic-input")]//input')
|
||||
|
||||
await clickOn(advancedSettingsButton)
|
||||
await clickOn(advancedSettingsButton, browser)
|
||||
await setInputText(topicInput, 'garden/#', browser)
|
||||
await clickOn(addButton)
|
||||
await clickOn(addButton, browser)
|
||||
|
||||
await setInputText(topicInput, 'livingroom/#', browser)
|
||||
await clickOn(addButton)
|
||||
await clickOn(addButton, browser)
|
||||
|
||||
await deleteFirstSubscribedTopic(browser)
|
||||
await deleteFirstSubscribedTopic(browser)
|
||||
await sleep(1000)
|
||||
|
||||
const backButton = await browser.locator('//button/span[contains(text(),"Back")]').first()
|
||||
await clickOn(backButton)
|
||||
const backButton = await browser.$('//button/span[contains(text(),"Back")]')
|
||||
await clickOn(backButton, browser)
|
||||
|
||||
const connectButton = await browser.locator('//button/span[contains(text(),"Connect")]')
|
||||
await clickOn(connectButton)
|
||||
const connectButton = await browser.$('//button/span[contains(text(),"Connect")]')
|
||||
await clickOn(connectButton, browser)
|
||||
}
|
||||
|
||||
async function deleteFirstSubscribedTopic(browser: Page) {
|
||||
const deleteButton = await browser.locator('.advanced-connection-settings-topic-list button').first()
|
||||
await clickOn(deleteButton)
|
||||
async function deleteFirstSubscribedTopic(browser: Browser<'async'>) {
|
||||
const deleteButton = await browser.$('.advanced-connection-settings-topic-list button')
|
||||
await clickOn(deleteButton, browser)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Page, Locator } from 'playwright'
|
||||
import { Browser, Element } from 'webdriverio'
|
||||
import { expandTopic, sleep } from '../util'
|
||||
|
||||
export async function showJsonPreview(browser: Page) {
|
||||
export async function showJsonPreview(browser: Browser<'async'>) {
|
||||
await expandTopic('actuality/showcase', browser)
|
||||
await browser.screenshot({ path: 'screen3.png' })
|
||||
await browser.saveScreenshot('screen3.png')
|
||||
await sleep(1000)
|
||||
}
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
import { Page } from 'playwright'
|
||||
import { Browser } from 'webdriverio'
|
||||
import { clickOn, showText, sleep } from '../util'
|
||||
|
||||
export async function showMenu(browser: Page) {
|
||||
const menuButton = await browser.locator('//button[contains(@aria-label, "Menu")]')
|
||||
await clickOn(menuButton)
|
||||
export async function showMenu(browser: Browser<'async'>) {
|
||||
const menuButton = await browser.$('//button[contains(@aria-label, "Menu")]')
|
||||
await clickOn(menuButton, browser)
|
||||
|
||||
// const brokerStatistics = await browser.$('//div[contains(@class, "BrokerStatistics")]/div[1]')
|
||||
// moveToCenterOfElement(brokerStatistics, browser)
|
||||
await sleep(2000)
|
||||
|
||||
await browser.screenshot({ path: 'screen4.png' })
|
||||
await browser.saveScreenshot('screen4.png')
|
||||
|
||||
const topicOrder = await browser.locator('//input[@name="node-order"]/../div')
|
||||
await clickOn(topicOrder)
|
||||
const topicOrder = await browser.$('//input[@name="node-order"]/../div')
|
||||
await clickOn(topicOrder, browser)
|
||||
await sleep(1000)
|
||||
|
||||
const alphabetically = await browser.locator('//li[contains(@data-value, "abc")]')
|
||||
await clickOn(alphabetically)
|
||||
const alphabetically = await browser.$('//li[contains(@data-value, "abc")]')
|
||||
await clickOn(alphabetically, browser)
|
||||
await sleep(2000)
|
||||
|
||||
await showText('Dark Mode', 1500, browser, 'top')
|
||||
await sleep(1500)
|
||||
const themeSwitch = await browser.locator('//*[contains(text(), "Dark Mode")]/..//input')
|
||||
await clickOn(themeSwitch)
|
||||
const themeSwitch = await browser.$('//*[contains(text(), "Dark Mode")]/..//input')
|
||||
await clickOn(themeSwitch, browser)
|
||||
await sleep(3000)
|
||||
await browser.screenshot({ path: 'screen_dark_mode.png' })
|
||||
await clickOn(themeSwitch)
|
||||
await browser.saveScreenshot('screen_dark_mode.png')
|
||||
await clickOn(themeSwitch, browser)
|
||||
|
||||
await clickOn(menuButton)
|
||||
await clickOn(menuButton, browser)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Page } from 'playwright'
|
||||
import { Browser, Element } from 'webdriverio'
|
||||
import { moveToCenterOfElement, clickOn, clickOnHistory, expandTopic, sleep, writeText } from '../util'
|
||||
|
||||
export async function showNumericPlot(browser: Page) {
|
||||
export async function showNumericPlot(browser: Browser<'async'>) {
|
||||
await expandTopic('kitchen/coffee_maker', browser)
|
||||
let heater = await valuePreviewGuttersShowChartIcon('heater', browser)
|
||||
await moveToCenterOfElement(heater)
|
||||
await moveToCenterOfElement(heater, browser)
|
||||
await sleep(1000)
|
||||
// Refocus and click
|
||||
heater = await valuePreviewGuttersShowChartIcon('heater', browser)
|
||||
@@ -12,7 +12,7 @@ export async function showNumericPlot(browser: Page) {
|
||||
|
||||
await sleep(1000)
|
||||
let temperature = await valuePreviewGuttersShowChartIcon('temperature', browser)
|
||||
await moveToCenterOfElement(temperature)
|
||||
await moveToCenterOfElement(temperature, browser)
|
||||
await sleep(1000)
|
||||
// Refocus and click
|
||||
temperature = await valuePreviewGuttersShowChartIcon('temperature', browser)
|
||||
@@ -30,7 +30,7 @@ export async function showNumericPlot(browser: Page) {
|
||||
await clickAway('temperature', browser)
|
||||
await sleep(2500)
|
||||
|
||||
await browser.screenshot({ path: 'screen_chart_panel.png' })
|
||||
await browser.saveScreenshot('screen_chart_panel.png')
|
||||
|
||||
await removeChart('heater', browser)
|
||||
await sleep(750)
|
||||
@@ -42,38 +42,34 @@ export async function showNumericPlot(browser: Page) {
|
||||
await clickOnHistory(browser)
|
||||
}
|
||||
|
||||
async function valuePreviewGuttersShowChartIcon(name: string, browser: Page) {
|
||||
async function valuePreviewGuttersShowChartIcon(name: string, browser: Browser<'async'>) {
|
||||
for (let retries = 0; retries < 2; retries += 1) {
|
||||
try {
|
||||
return await browser.locator(`//*[contains(@data-test-type, "ShowChart")][contains(@data-test, "${name}")]`)
|
||||
return await browser.$(`//*[contains(@data-test-type, "ShowChart")][contains(@data-test, "${name}")]`)
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return browser.locator(`//*[contains(@data-test-type, "ShowChart")][contains(@data-test, "${name}")]`)
|
||||
return browser.$(`//*[contains(@data-test-type, "ShowChart")][contains(@data-test, "${name}")]`)
|
||||
}
|
||||
|
||||
async function chartSettings(name: string, browser: Page) {
|
||||
const settings = await browser.locator(
|
||||
`//*[contains(@data-test-type, "ChartSettings")][contains(@data-test, "${name}")]`
|
||||
)
|
||||
return clickOn(settings)
|
||||
async function chartSettings(name: string, browser: Browser<'async'>) {
|
||||
const settings = await browser.$(`//*[contains(@data-test-type, "ChartSettings")][contains(@data-test, "${name}")]`)
|
||||
return clickOn(settings, browser)
|
||||
}
|
||||
|
||||
async function clickAway(name: string, browser: Page) {
|
||||
const settings = await browser.locator(
|
||||
`//*[contains(@data-test-type, "ChartPaper")][contains(@data-test, "${name}")]`
|
||||
)
|
||||
await moveToCenterOfElement(settings)
|
||||
await settings.press('Escape')
|
||||
async function clickAway(name: string, browser: Browser<'async'>) {
|
||||
const settings = await browser.$(`//*[contains(@data-test-type, "ChartPaper")][contains(@data-test, "${name}")]`)
|
||||
await moveToCenterOfElement(settings, browser)
|
||||
await browser.keys(['Escape'])
|
||||
}
|
||||
|
||||
async function removeChart(name: string, browser: Page) {
|
||||
const remove = await browser.locator(`//*[contains(@data-test-type, "RemoveChart")][contains(@data-test, "${name}")]`)
|
||||
return clickOn(remove)
|
||||
async function removeChart(name: string, browser: Browser<'async'>) {
|
||||
const remove = await browser.$(`//*[contains(@data-test-type, "RemoveChart")][contains(@data-test, "${name}")]`)
|
||||
return clickOn(remove, browser)
|
||||
}
|
||||
|
||||
async function clickOnMenuPoint(name: string, browser: Page) {
|
||||
const item = await browser.locator(`//li/span[contains(text(), "${name}")]`)
|
||||
return clickOn(item)
|
||||
async function clickOnMenuPoint(name: string, browser: Browser<'async'>) {
|
||||
const item = await browser.$(`//li/span[contains(text(), "${name}")]`)
|
||||
return clickOn(item, browser)
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import { Page, Locator } from 'playwright'
|
||||
import { Browser, Element } from 'webdriverio'
|
||||
import { clickOn, showText, sleep } from '../util'
|
||||
|
||||
// Expects a topic with at least two messages to be selected
|
||||
export async function showOffDiffCapability(browser: Page) {
|
||||
export async function showOffDiffCapability(browser: Browser<'async'>) {
|
||||
await showText('Compare messages', 2000, browser, 'top')
|
||||
|
||||
await showText('Show raw message', 2000, browser, 'bottom')
|
||||
const rawMessage = await browser.locator('#valueRendererDisplayMode-raw')
|
||||
await clickOn(rawMessage)
|
||||
const rawMessage = await browser.$('#valueRendererDisplayMode-raw')
|
||||
await clickOn(rawMessage, browser)
|
||||
await sleep(1000)
|
||||
|
||||
await showText('Compare with others', 2000, browser, 'bottom')
|
||||
const diffMessages = await browser.locator('#valueRendererDisplayMode-diff')
|
||||
await clickOn(diffMessages)
|
||||
const diffMessages = await browser.$('#valueRendererDisplayMode-diff')
|
||||
await clickOn(diffMessages, browser)
|
||||
|
||||
// // const firstEntry = await browser.$('//span[contains(text(), "History")]/../../div/div[1]/div')
|
||||
// const secondEntry = await browser.$('//span[contains(text(), "History")]/../../div/div[2]/div')
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Page } from 'playwright'
|
||||
import { Browser, Element } from 'webdriverio'
|
||||
import { showKeys, showText, sleep } from '../util'
|
||||
|
||||
export async function showZoomLevel(browser: Page) {
|
||||
export async function showZoomLevel(browser: Browser<'async'>) {
|
||||
await showKeys('Zoom in', 2000, browser, 'top', ['Ctrl', '+'])
|
||||
await sleep(2000)
|
||||
await showKeys('Zoom out', 2000, browser, 'middle', ['Ctrl', '-'])
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { clickOn } from './'
|
||||
import { Page } from 'playwright'
|
||||
import { Browser, Element } from 'webdriverio'
|
||||
|
||||
export async function expandTopic(path: string, browser: Page) {
|
||||
export async function expandTopic(path: string, browser: Browser<'async'>) {
|
||||
const originalTopics = path.split('/')
|
||||
console.log('expandTopic', path)
|
||||
let topics = path.split('/')
|
||||
while (topics.length > 0 && !(await topicMatches(topics, browser))) {
|
||||
topics = topics.slice(0, topics.length - 1)
|
||||
@@ -12,27 +11,19 @@ export async function expandTopic(path: string, browser: Page) {
|
||||
throw Error('could not expand topics, no match found')
|
||||
}
|
||||
|
||||
console.log('found topics', topics, originalTopics)
|
||||
|
||||
for (const topic of topics) {
|
||||
const match = await browser.locator(topicSelector([topic]))
|
||||
await clickOn(match.first())
|
||||
while (topics.length <= originalTopics.length) {
|
||||
const match = await browser.$(topicSelector(topics))
|
||||
await clickOn(match, browser)
|
||||
topics.push(originalTopics[topics.length])
|
||||
}
|
||||
// while (topics.length <= originalTopics.length) {
|
||||
// const match = await browser.locator(topicSelector(topics))
|
||||
// console.log('click', match)
|
||||
// await clickOn(match)
|
||||
// topics.push(originalTopics[topics.length])
|
||||
// }
|
||||
}
|
||||
|
||||
async function topicMatches(topics: Array<string>, browser: Page) {
|
||||
const result = await browser.locator(topicSelector(topics))
|
||||
console.log('topic matches', topics, result)
|
||||
return true
|
||||
async function topicMatches(topics: Array<string>, browser: Browser<'async'>) {
|
||||
const result = await browser.$(topicSelector(topics))
|
||||
return result.isExisting()
|
||||
}
|
||||
|
||||
function topicSelector(topics: Array<string>) {
|
||||
const selectors = topics.map(v => `span[data-test-topic='${v}']`)
|
||||
return selectors.join(' ')
|
||||
const suffix = topics.map(topic => `*[contains(text(), "${topic}")]`).join('/../..//')
|
||||
return `//${suffix}`
|
||||
}
|
||||
|
||||
+57
-56
@@ -1,6 +1,5 @@
|
||||
import * as fs from 'fs'
|
||||
|
||||
import { Page, Locator } from 'playwright'
|
||||
import { Browser, Element } from 'webdriverio'
|
||||
|
||||
export { expandTopic } from './expandTopic'
|
||||
|
||||
@@ -19,37 +18,48 @@ export function sleep(ms: number, required = false) {
|
||||
})
|
||||
}
|
||||
|
||||
export async function writeText(text: string, element: Locator, delay = 0) {
|
||||
return element.fill(text)
|
||||
}
|
||||
export async function writeText(text: string, browser: Browser<'async'>, delay = 0) {
|
||||
if (fast) {
|
||||
return browser.keys(text.split(''))
|
||||
}
|
||||
|
||||
export async function deleteTextWithBackspaces(element: Locator, delay = 0, count = 0) {
|
||||
// @ts-ignore
|
||||
const length = count > 0 ? count : (await element.textContent()).length
|
||||
for (let i = 0; i < length; i += 1) {
|
||||
await element.press('Backspace')
|
||||
for (const c of text.split('')) {
|
||||
await browser.keys([c])
|
||||
await sleep(delay)
|
||||
}
|
||||
}
|
||||
|
||||
export async function setInputText(input: Locator, text: string, browser: Page) {
|
||||
await clickOn(input, 1)
|
||||
await deleteTextWithBackspaces(input)
|
||||
await input.fill(text)
|
||||
export async function deleteTextWithBackspaces(
|
||||
element: Element<'async'>,
|
||||
browser: Browser<'async'>,
|
||||
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 setTextInInput(name: string, text: string, browser: Page) {
|
||||
const input = await browser.locator(`//label[contains(text(), "${name}")]/..//input`)
|
||||
await clickOn(input, 1)
|
||||
await browser.locator(`//label[contains(text(), "${name}")]/..//input`)
|
||||
|
||||
await deleteTextWithBackspaces(input)
|
||||
await input.fill(text)
|
||||
export async function setInputText(input: Element<'async'>, text: string, browser: Browser<'async'>) {
|
||||
await clickOn(input, browser, 1)
|
||||
await deleteTextWithBackspaces(input, browser)
|
||||
await input.setValue(text)
|
||||
}
|
||||
|
||||
export async function moveToCenterOfElement(element: Locator) {
|
||||
// @ts-ignore
|
||||
const { x, y, width, height } = await element.boundingBox()
|
||||
export async function setTextInInput(name: string, text: string, browser: Browser<'async'>) {
|
||||
const input = await browser.$(`//label[contains(text(), "${name}")]/..//input`)
|
||||
await clickOn(input, browser, 1)
|
||||
await browser.$(`//label[contains(text(), "${name}")]/..//input`)
|
||||
|
||||
await deleteTextWithBackspaces(input, browser)
|
||||
await input.setValue(text)
|
||||
}
|
||||
|
||||
export async function moveToCenterOfElement(element: Element<'async'>, browser: Browser<'async'>) {
|
||||
const { x, y } = await element.getLocation()
|
||||
const { width, height } = await element.getSize()
|
||||
|
||||
const targetX = x + width / 2
|
||||
const targetY = y + height / 2
|
||||
@@ -57,59 +67,50 @@ export async function moveToCenterOfElement(element: Locator) {
|
||||
const duration = fast ? 1 : 500
|
||||
|
||||
const js = `window.demo.moveMouse(${targetX}, ${targetY}, ${duration});`
|
||||
await runJavascript(js, element.page())
|
||||
await browser.execute(js)
|
||||
await sleep(duration)
|
||||
await sleep(250, true)
|
||||
|
||||
await element.moveTo()
|
||||
}
|
||||
|
||||
export async function runJavascript(js: string, browser: Page) {
|
||||
// there is probably a safer way to do this.. do not use eval...
|
||||
// tslint:disable-next-line no-eval
|
||||
return browser.evaluate(script => eval(script), js)
|
||||
export async function clickOnHistory(browser: Browser<'async'>) {
|
||||
const messageHistory = await browser.$('//span/*[contains(text(), "History")]')
|
||||
await clickOn(messageHistory, browser)
|
||||
}
|
||||
|
||||
export async function clickOnHistory(browser: Page) {
|
||||
const messageHistory = await browser.locator('//span/*[contains(text(), "History")]').first()
|
||||
await clickOn(messageHistory)
|
||||
export async function clickOn(element: Element<'async'>, browser: Browser<'async'>, clicks = 1) {
|
||||
await moveToCenterOfElement(element, browser)
|
||||
for (let i = 0; i < clicks; i += 1) {
|
||||
await element.click()
|
||||
await sleep(50)
|
||||
}
|
||||
}
|
||||
|
||||
export async function clickOn(
|
||||
element: Locator,
|
||||
clicks = 1,
|
||||
delay = 0,
|
||||
button: 'left' | 'right' | 'middle' = 'left',
|
||||
force = false
|
||||
) {
|
||||
await moveToCenterOfElement(element)
|
||||
await element.hover()
|
||||
await element.click({ delay, button, force, clickCount: clicks })
|
||||
await sleep(50)
|
||||
}
|
||||
|
||||
export async function createFakeMousePointer(browser: Page) {
|
||||
export async function createFakeMousePointer(browser: Browser<'async'>) {
|
||||
const js = 'window.demo.enableMouse();'
|
||||
// @ts-lint-ignore
|
||||
await runJavascript(js, browser)
|
||||
|
||||
await browser.execute(js)
|
||||
}
|
||||
|
||||
export async function showText(
|
||||
text: string,
|
||||
duration: number = 0,
|
||||
browser: Page,
|
||||
browser: Browser<'async'>,
|
||||
location: 'top' | 'bottom' | 'middle' = 'bottom',
|
||||
keys = []
|
||||
) {
|
||||
const js = `window.demo.showMessage('${text}', '${location}', ${duration});`
|
||||
|
||||
await runJavascript(js, browser)
|
||||
await browser.execute(js)
|
||||
}
|
||||
|
||||
type HeapDump = any
|
||||
|
||||
export async function getHeapDump(browser: Page): Promise<HeapDump> {
|
||||
export async function getHeapDump(browser: Browser<'async'>): Promise<HeapDump> {
|
||||
const filename = 'heapdump.json'
|
||||
const js = `window.demo.writeHeapdump('${filename}');`
|
||||
await runJavascript(js, browser)
|
||||
await browser.execute(js)
|
||||
const buffer = fs.readFileSync(filename)
|
||||
fs.unlinkSync(filename)
|
||||
|
||||
@@ -129,17 +130,17 @@ export async function countInstancesOf(heapDump: HeapDump, className: ClassNameM
|
||||
export async function showKeys(
|
||||
text: string,
|
||||
duration: number = 0,
|
||||
browser: Page,
|
||||
browser: Browser<'async'>,
|
||||
location: 'top' | 'bottom' | 'middle' = 'bottom',
|
||||
keys: Array<string> = []
|
||||
) {
|
||||
const js = `window.demo.showMessage('${text}', '${location}', ${duration}, ${JSON.stringify(keys)});`
|
||||
|
||||
await runJavascript(js, browser)
|
||||
await browser.execute(js)
|
||||
}
|
||||
|
||||
export async function hideText(browser: Page) {
|
||||
export async function hideText(browser: Browser<'async'>) {
|
||||
const js = 'window.demo.hideMessage();'
|
||||
await runJavascript(js, browser)
|
||||
await browser.execute(js)
|
||||
await sleep(600)
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"sourceRoot": "src/",
|
||||
"target": "ES2017",
|
||||
"lib": [
|
||||
"es2017",
|
||||
"dom"
|
||||
|
||||
Reference in New Issue
Block a user