chore: add prettier (2/3): apply formatting, re-enable lint ci step (#6682)

* style: apply prettier formatting

* fix: re-enable lint ci check
This commit is contained in:
Jesse Mazzella 2023-05-18 14:54:46 -07:00 committed by GitHub
parent 172e0b23fd
commit caa7bc6fae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
976 changed files with 115922 additions and 114693 deletions

View File

@ -13,12 +13,12 @@ executors:
docker_layer_caching: true docker_layer_caching: true
parameters: parameters:
BUST_CACHE: BUST_CACHE:
description: "Set this with the CircleCI UI Trigger Workflow button (boolean = true) to bust the cache!" description: 'Set this with the CircleCI UI Trigger Workflow button (boolean = true) to bust the cache!'
default: false default: false
type: boolean type: boolean
commands: commands:
build_and_install: build_and_install:
description: "All steps used to build and install. Will use cache if found" description: 'All steps used to build and install. Will use cache if found'
parameters: parameters:
node-version: node-version:
type: string type: string
@ -30,19 +30,19 @@ commands:
node-version: << parameters.node-version >> node-version: << parameters.node-version >>
- run: npm install --no-audit --progress=false - run: npm install --no-audit --progress=false
restore_cache_cmd: restore_cache_cmd:
description: "Custom command for restoring cache with the ability to bust cache. When BUST_CACHE is set to true, jobs will not restore cache" description: 'Custom command for restoring cache with the ability to bust cache. When BUST_CACHE is set to true, jobs will not restore cache'
parameters: parameters:
node-version: node-version:
type: string type: string
steps: steps:
- when: - when:
condition: condition:
equal: [false, << pipeline.parameters.BUST_CACHE >> ] equal: [false, << pipeline.parameters.BUST_CACHE >>]
steps: steps:
- restore_cache: - restore_cache:
key: deps--{{ arch }}--{{ .Branch }}--<< parameters.node-version >>--{{ checksum "package.json" }}-{{ checksum ".circleci/config.yml" }} key: deps--{{ arch }}--{{ .Branch }}--<< parameters.node-version >>--{{ checksum "package.json" }}-{{ checksum ".circleci/config.yml" }}
save_cache_cmd: save_cache_cmd:
description: "Custom command for saving cache." description: 'Custom command for saving cache.'
parameters: parameters:
node-version: node-version:
type: string type: string
@ -53,7 +53,7 @@ commands:
- ~/.npm - ~/.npm
- node_modules - node_modules
generate_and_store_version_and_filesystem_artifacts: generate_and_store_version_and_filesystem_artifacts:
description: "Track important packages and files" description: 'Track important packages and files'
steps: steps:
- run: | - run: |
[[ $EUID -ne 0 ]] && (sudo mkdir -p /tmp/artifacts && sudo chmod 777 /tmp/artifacts) || (mkdir -p /tmp/artifacts && chmod 777 /tmp/artifacts) [[ $EUID -ne 0 ]] && (sudo mkdir -p /tmp/artifacts && sudo chmod 777 /tmp/artifacts) || (mkdir -p /tmp/artifacts && chmod 777 /tmp/artifacts)
@ -64,7 +64,7 @@ commands:
- store_artifacts: - store_artifacts:
path: /tmp/artifacts/ path: /tmp/artifacts/
generate_e2e_code_cov_report: generate_e2e_code_cov_report:
description: "Generate e2e code coverage artifacts and publish to codecov.io. Needed to that we can ignore the exit code status of the npm run test" description: 'Generate e2e code coverage artifacts and publish to codecov.io. Needed to that we can ignore the exit code status of the npm run test'
parameters: parameters:
suite: suite:
type: string type: string
@ -115,7 +115,7 @@ jobs:
path: coverage path: coverage
- when: - when:
condition: condition:
equal: [ 42, 42 ] # Always generate version artifacts regardless of test failure https://discuss.circleci.com/t/make-custom-command-run-always-with-when-always/38957/2 equal: [42, 42] # Always generate version artifacts regardless of test failure https://discuss.circleci.com/t/make-custom-command-run-always-with-when-always/38957/2
steps: steps:
- generate_and_store_version_and_filesystem_artifacts - generate_and_store_version_and_filesystem_artifacts
e2e-test: e2e-test:
@ -131,13 +131,13 @@ jobs:
node-version: <<parameters.node-version>> node-version: <<parameters.node-version>>
- when: #Only install chrome-beta when running the 'full' suite to save $$$ - when: #Only install chrome-beta when running the 'full' suite to save $$$
condition: condition:
equal: [ "full", <<parameters.suite>> ] equal: ['full', <<parameters.suite>>]
steps: steps:
- run: npx playwright install chrome-beta - run: npx playwright install chrome-beta
- run: SHARD="$((${CIRCLE_NODE_INDEX}+1))"; npm run test:e2e:<<parameters.suite>> -- --shard=${SHARD}/${CIRCLE_NODE_TOTAL} - run: SHARD="$((${CIRCLE_NODE_INDEX}+1))"; npm run test:e2e:<<parameters.suite>> -- --shard=${SHARD}/${CIRCLE_NODE_TOTAL}
- when: - when:
condition: condition:
equal: [ 42, 42 ] # Always run codecov reports regardless of test failure https://discuss.circleci.com/t/make-custom-command-run-always-with-when-always/38957/2 equal: [42, 42] # Always run codecov reports regardless of test failure https://discuss.circleci.com/t/make-custom-command-run-always-with-when-always/38957/2
steps: steps:
- generate_e2e_code_cov_report: - generate_e2e_code_cov_report:
suite: <<parameters.suite>> suite: <<parameters.suite>>
@ -151,7 +151,7 @@ jobs:
path: html-test-results path: html-test-results
- when: - when:
condition: condition:
equal: [ 42, 42 ] # Always generate version artifacts regardless of test failure https://discuss.circleci.com/t/make-custom-command-run-always-with-when-always/38957/2 equal: [42, 42] # Always generate version artifacts regardless of test failure https://discuss.circleci.com/t/make-custom-command-run-always-with-when-always/38957/2
steps: steps:
- generate_and_store_version_and_filesystem_artifacts - generate_and_store_version_and_filesystem_artifacts
e2e-couchdb: e2e-couchdb:
@ -172,7 +172,7 @@ jobs:
- run: npm run test:e2e:couchdb - run: npm run test:e2e:couchdb
- when: - when:
condition: condition:
equal: [ 42, 42 ] # Always run codecov reports regardless of test failure https://discuss.circleci.com/t/make-custom-command-run-always-with-when-always/38957/2 equal: [42, 42] # Always run codecov reports regardless of test failure https://discuss.circleci.com/t/make-custom-command-run-always-with-when-always/38957/2
steps: steps:
- generate_e2e_code_cov_report: - generate_e2e_code_cov_report:
suite: full #add to full suite suite: full #add to full suite
@ -186,7 +186,7 @@ jobs:
path: html-test-results path: html-test-results
- when: - when:
condition: condition:
equal: [ 42, 42 ] # Always generate version artifacts regardless of test failure https://discuss.circleci.com/t/make-custom-command-run-always-with-when-always/38957/2 equal: [42, 42] # Always generate version artifacts regardless of test failure https://discuss.circleci.com/t/make-custom-command-run-always-with-when-always/38957/2
steps: steps:
- generate_and_store_version_and_filesystem_artifacts - generate_and_store_version_and_filesystem_artifacts
perf-test: perf-test:
@ -206,7 +206,7 @@ jobs:
path: html-test-results path: html-test-results
- when: - when:
condition: condition:
equal: [ 42, 42 ] # Always run codecov reports regardless of test failure https://discuss.circleci.com/t/make-custom-command-run-always-with-when-always/38957/2 equal: [42, 42] # Always run codecov reports regardless of test failure https://discuss.circleci.com/t/make-custom-command-run-always-with-when-always/38957/2
steps: steps:
- generate_and_store_version_and_filesystem_artifacts - generate_and_store_version_and_filesystem_artifacts
visual-test: visual-test:
@ -226,15 +226,15 @@ jobs:
path: html-test-results path: html-test-results
- when: - when:
condition: condition:
equal: [ 42, 42 ] # Always generate version artifacts regardless of test failure https://discuss.circleci.com/t/make-custom-command-run-always-with-when-always/38957/2 equal: [42, 42] # Always generate version artifacts regardless of test failure https://discuss.circleci.com/t/make-custom-command-run-always-with-when-always/38957/2
steps: steps:
- generate_and_store_version_and_filesystem_artifacts - generate_and_store_version_and_filesystem_artifacts
workflows: workflows:
overall-circleci-commit-status: #These jobs run on every commit overall-circleci-commit-status: #These jobs run on every commit
jobs: jobs:
# - lint: - lint:
# name: node16-lint name: node16-lint
# node-version: lts/gallium node-version: lts/gallium
- unit-test: - unit-test:
name: node18-chrome name: node18-chrome
node-version: lts/hydrogen node-version: lts/hydrogen
@ -269,7 +269,7 @@ workflows:
node-version: lts/hydrogen node-version: lts/hydrogen
triggers: triggers:
- schedule: - schedule:
cron: "0 0 * * *" cron: '0 0 * * *'
filters: filters:
branches: branches:
only: only:

View File

@ -1,165 +1,165 @@
const LEGACY_FILES = ["example/**"]; const LEGACY_FILES = ['example/**'];
module.exports = { module.exports = {
"env": { env: {
"browser": true, browser: true,
"es6": true, es6: true,
"jasmine": true, jasmine: true,
"amd": true amd: true
}, },
"globals": { globals: {
"_": "readonly" _: 'readonly'
}, },
"plugins": ["prettier"], plugins: ['prettier'],
"extends": [ extends: [
"eslint:recommended", 'eslint:recommended',
"plugin:compat/recommended", 'plugin:compat/recommended',
"plugin:vue/recommended", 'plugin:vue/recommended',
"plugin:you-dont-need-lodash-underscore/compatible", 'plugin:you-dont-need-lodash-underscore/compatible',
"plugin:prettier/recommended" 'plugin:prettier/recommended'
], ],
"parser": "vue-eslint-parser", parser: 'vue-eslint-parser',
"parserOptions": { parserOptions: {
"parser": "@babel/eslint-parser", parser: '@babel/eslint-parser',
"requireConfigFile": false, requireConfigFile: false,
"allowImportExportEverywhere": true, allowImportExportEverywhere: true,
"ecmaVersion": 2015, ecmaVersion: 2015,
"ecmaFeatures": { ecmaFeatures: {
"impliedStrict": true impliedStrict: true
} }
}, },
"rules": { rules: {
"prettier/prettier": "error", 'prettier/prettier': 'error',
"you-dont-need-lodash-underscore/omit": "off", 'you-dont-need-lodash-underscore/omit': 'off',
"you-dont-need-lodash-underscore/throttle": "off", 'you-dont-need-lodash-underscore/throttle': 'off',
"you-dont-need-lodash-underscore/flatten": "off", 'you-dont-need-lodash-underscore/flatten': 'off',
"you-dont-need-lodash-underscore/get": "off", 'you-dont-need-lodash-underscore/get': 'off',
"no-bitwise": "error", 'no-bitwise': 'error',
"curly": "error", curly: 'error',
"eqeqeq": "error", eqeqeq: 'error',
"guard-for-in": "error", 'guard-for-in': 'error',
"no-extend-native": "error", 'no-extend-native': 'error',
"no-inner-declarations": "off", 'no-inner-declarations': 'off',
"no-use-before-define": ["error", "nofunc"], 'no-use-before-define': ['error', 'nofunc'],
"no-caller": "error", 'no-caller': 'error',
"no-irregular-whitespace": "error", 'no-irregular-whitespace': 'error',
"no-new": "error", 'no-new': 'error',
"no-shadow": "error", 'no-shadow': 'error',
"no-undef": "error", 'no-undef': 'error',
"no-unused-vars": [ 'no-unused-vars': [
"error", 'error',
{ {
"vars": "all", vars: 'all',
"args": "none" args: 'none'
} }
], ],
"no-console": "off", 'no-console': 'off',
"new-cap": [ 'new-cap': [
"error", 'error',
{ {
"capIsNew": false, capIsNew: false,
"properties": false properties: false
} }
], ],
"dot-notation": "error", 'dot-notation': 'error',
// https://eslint.org/docs/rules/no-case-declarations // https://eslint.org/docs/rules/no-case-declarations
"no-case-declarations": "error", 'no-case-declarations': 'error',
// https://eslint.org/docs/rules/max-classes-per-file // https://eslint.org/docs/rules/max-classes-per-file
"max-classes-per-file": ["error", 1], 'max-classes-per-file': ['error', 1],
// https://eslint.org/docs/rules/no-eq-null // https://eslint.org/docs/rules/no-eq-null
"no-eq-null": "error", 'no-eq-null': 'error',
// https://eslint.org/docs/rules/no-eval // https://eslint.org/docs/rules/no-eval
"no-eval": "error", 'no-eval': 'error',
// https://eslint.org/docs/rules/no-implicit-globals // https://eslint.org/docs/rules/no-implicit-globals
"no-implicit-globals": "error", 'no-implicit-globals': 'error',
// https://eslint.org/docs/rules/no-implied-eval // https://eslint.org/docs/rules/no-implied-eval
"no-implied-eval": "error", 'no-implied-eval': 'error',
// https://eslint.org/docs/rules/no-lone-blocks // https://eslint.org/docs/rules/no-lone-blocks
"no-lone-blocks": "error", 'no-lone-blocks': 'error',
// https://eslint.org/docs/rules/no-loop-func // https://eslint.org/docs/rules/no-loop-func
"no-loop-func": "error", 'no-loop-func': 'error',
// https://eslint.org/docs/rules/no-new-func // https://eslint.org/docs/rules/no-new-func
"no-new-func": "error", 'no-new-func': 'error',
// https://eslint.org/docs/rules/no-new-wrappers // https://eslint.org/docs/rules/no-new-wrappers
"no-new-wrappers": "error", 'no-new-wrappers': 'error',
// https://eslint.org/docs/rules/no-octal-escape // https://eslint.org/docs/rules/no-octal-escape
"no-octal-escape": "error", 'no-octal-escape': 'error',
// https://eslint.org/docs/rules/no-proto // https://eslint.org/docs/rules/no-proto
"no-proto": "error", 'no-proto': 'error',
// https://eslint.org/docs/rules/no-return-await // https://eslint.org/docs/rules/no-return-await
"no-return-await": "error", 'no-return-await': 'error',
// https://eslint.org/docs/rules/no-script-url // https://eslint.org/docs/rules/no-script-url
"no-script-url": "error", 'no-script-url': 'error',
// https://eslint.org/docs/rules/no-self-compare // https://eslint.org/docs/rules/no-self-compare
"no-self-compare": "error", 'no-self-compare': 'error',
// https://eslint.org/docs/rules/no-sequences // https://eslint.org/docs/rules/no-sequences
"no-sequences": "error", 'no-sequences': 'error',
// https://eslint.org/docs/rules/no-unmodified-loop-condition // https://eslint.org/docs/rules/no-unmodified-loop-condition
"no-unmodified-loop-condition": "error", 'no-unmodified-loop-condition': 'error',
// https://eslint.org/docs/rules/no-useless-call // https://eslint.org/docs/rules/no-useless-call
"no-useless-call": "error", 'no-useless-call': 'error',
// https://eslint.org/docs/rules/no-nested-ternary // https://eslint.org/docs/rules/no-nested-ternary
"no-nested-ternary": "error", 'no-nested-ternary': 'error',
// https://eslint.org/docs/rules/no-useless-computed-key // https://eslint.org/docs/rules/no-useless-computed-key
"no-useless-computed-key": "error", 'no-useless-computed-key': 'error',
// https://eslint.org/docs/rules/no-var // https://eslint.org/docs/rules/no-var
"no-var": "error", 'no-var': 'error',
// https://eslint.org/docs/rules/one-var // https://eslint.org/docs/rules/one-var
"one-var": ["error", "never"], 'one-var': ['error', 'never'],
// https://eslint.org/docs/rules/default-case-last // https://eslint.org/docs/rules/default-case-last
"default-case-last": "error", 'default-case-last': 'error',
// https://eslint.org/docs/rules/default-param-last // https://eslint.org/docs/rules/default-param-last
"default-param-last": "error", 'default-param-last': 'error',
// https://eslint.org/docs/rules/grouped-accessor-pairs // https://eslint.org/docs/rules/grouped-accessor-pairs
"grouped-accessor-pairs": "error", 'grouped-accessor-pairs': 'error',
// https://eslint.org/docs/rules/no-constructor-return // https://eslint.org/docs/rules/no-constructor-return
"no-constructor-return": "error", 'no-constructor-return': 'error',
// https://eslint.org/docs/rules/array-callback-return // https://eslint.org/docs/rules/array-callback-return
"array-callback-return": "error", 'array-callback-return': 'error',
// https://eslint.org/docs/rules/no-invalid-this // https://eslint.org/docs/rules/no-invalid-this
"no-invalid-this": "error", // Believe this one actually surfaces some bugs 'no-invalid-this': 'error', // Believe this one actually surfaces some bugs
// https://eslint.org/docs/rules/func-style // https://eslint.org/docs/rules/func-style
"func-style": ["error", "declaration"], 'func-style': ['error', 'declaration'],
// https://eslint.org/docs/rules/no-unused-expressions // https://eslint.org/docs/rules/no-unused-expressions
"no-unused-expressions": "error", 'no-unused-expressions': 'error',
// https://eslint.org/docs/rules/no-useless-concat // https://eslint.org/docs/rules/no-useless-concat
"no-useless-concat": "error", 'no-useless-concat': 'error',
// https://eslint.org/docs/rules/radix // https://eslint.org/docs/rules/radix
"radix": "error", radix: 'error',
// https://eslint.org/docs/rules/require-await // https://eslint.org/docs/rules/require-await
"require-await": "error", 'require-await': 'error',
// https://eslint.org/docs/rules/no-alert // https://eslint.org/docs/rules/no-alert
"no-alert": "error", 'no-alert': 'error',
// https://eslint.org/docs/rules/no-useless-constructor // https://eslint.org/docs/rules/no-useless-constructor
"no-useless-constructor": "error", 'no-useless-constructor': 'error',
// https://eslint.org/docs/rules/no-duplicate-imports // https://eslint.org/docs/rules/no-duplicate-imports
"no-duplicate-imports": "error", 'no-duplicate-imports': 'error',
// https://eslint.org/docs/rules/no-implicit-coercion // https://eslint.org/docs/rules/no-implicit-coercion
"no-implicit-coercion": "error", 'no-implicit-coercion': 'error',
//https://eslint.org/docs/rules/no-unneeded-ternary //https://eslint.org/docs/rules/no-unneeded-ternary
"no-unneeded-ternary": "error", 'no-unneeded-ternary': 'error',
"vue/first-attribute-linebreak": "error", 'vue/first-attribute-linebreak': 'error',
"vue/multiline-html-element-content-newline": "off", 'vue/multiline-html-element-content-newline': 'off',
"vue/singleline-html-element-content-newline": "off", 'vue/singleline-html-element-content-newline': 'off',
"vue/multi-word-component-names": "off", // TODO enable, align with conventions 'vue/multi-word-component-names': 'off', // TODO enable, align with conventions
"vue/no-mutating-props": "off" 'vue/no-mutating-props': 'off'
}, },
"overrides": [ overrides: [
{ {
"files": LEGACY_FILES, files: LEGACY_FILES,
"rules": { rules: {
"no-unused-vars": [ 'no-unused-vars': [
"warn", 'warn',
{ {
"vars": "all", vars: 'all',
"args": "none", args: 'none',
"varsIgnorePattern": "controller" varsIgnorePattern: 'controller'
} }
], ],
"no-nested-ternary": "off", 'no-nested-ternary': 'off',
"no-var": "off", 'no-var': 'off',
"one-var": "off" 'one-var': 'off'
} }
} }
] ]

View File

@ -1,39 +1,38 @@
version: 2 version: 2
updates: updates:
- package-ecosystem: "npm" - package-ecosystem: 'npm'
directory: "/" directory: '/'
schedule: schedule:
interval: "weekly" interval: 'weekly'
open-pull-requests-limit: 10 open-pull-requests-limit: 10
labels: labels:
- "pr:daveit" - 'pr:daveit'
- "pr:e2e" - 'pr:e2e'
- "type:maintenance" - 'type:maintenance'
- "dependencies" - 'dependencies'
- "pr:platform" - 'pr:platform'
ignore: ignore:
#We have to source the playwright container which is not detected by Dependabot #We have to source the playwright container which is not detected by Dependabot
- dependency-name: "@playwright/test" - dependency-name: '@playwright/test'
- dependency-name: "playwright-core" - dependency-name: 'playwright-core'
#Lots of noise in these type patch releases. #Lots of noise in these type patch releases.
- dependency-name: "@babel/eslint-parser" - dependency-name: '@babel/eslint-parser'
update-types: ["version-update:semver-patch"] update-types: ['version-update:semver-patch']
- dependency-name: "eslint-plugin-vue" - dependency-name: 'eslint-plugin-vue'
update-types: ["version-update:semver-patch"] update-types: ['version-update:semver-patch']
- dependency-name: "babel-loader" - dependency-name: 'babel-loader'
update-types: ["version-update:semver-patch"] update-types: ['version-update:semver-patch']
- dependency-name: "sinon" - dependency-name: 'sinon'
update-types: ["version-update:semver-patch"] update-types: ['version-update:semver-patch']
- dependency-name: "moment-timezone" - dependency-name: 'moment-timezone'
update-types: ["version-update:semver-patch"] update-types: ['version-update:semver-patch']
- dependency-name: "@types/lodash" - dependency-name: '@types/lodash'
update-types: ["version-update:semver-patch"] update-types: ['version-update:semver-patch']
- package-ecosystem: "github-actions" - package-ecosystem: 'github-actions'
directory: "/" directory: '/'
schedule: schedule:
interval: "daily" interval: 'daily'
labels: labels:
- "pr:daveit" - 'pr:daveit'
- "type:maintenance" - 'type:maintenance'
- "dependencies" - 'dependencies'

View File

@ -1,4 +1,4 @@
name: "e2e-couchdb" name: 'e2e-couchdb'
on: on:
workflow_dispatch: workflow_dispatch:
pull_request: pull_request:
@ -17,7 +17,7 @@ jobs:
- run: npx playwright@1.32.3 install - run: npx playwright@1.32.3 install
- run: npm install - run: npm install
- name: Start CouchDB Docker Container and Init with Setup Scripts - name: Start CouchDB Docker Container and Init with Setup Scripts
run : | run: |
export $(cat src/plugins/persistence/couch/.env.ci | xargs) export $(cat src/plugins/persistence/couch/.env.ci | xargs)
docker-compose -f src/plugins/persistence/couch/couchdb-compose.yaml up --detach docker-compose -f src/plugins/persistence/couch/couchdb-compose.yaml up --detach
sleep 3 sleep 3

View File

@ -1,4 +1,4 @@
name: "e2e-pr" name: 'e2e-pr'
on: on:
workflow_dispatch: workflow_dispatch:
pull_request: pull_request:

View File

@ -1,8 +1,8 @@
name: "pr-platform" name: 'pr-platform'
on: on:
workflow_dispatch: workflow_dispatch:
pull_request: pull_request:
types: [ labeled ] types: [labeled]
jobs: jobs:
e2e-full: e2e-full:

View File

@ -22,5 +22,5 @@ jobs:
- name: Linting Pull Request - name: Linting Pull Request
uses: makaroni4/prcop@v1.0.35 uses: makaroni4/prcop@v1.0.35
with: with:
config-file: ".github/workflows/prcop-config.json" config-file: '.github/workflows/prcop-config.json'
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -8,80 +8,67 @@ This is the OpenMCT common webpack file. It is imported by the other three webpa
There are separate npm scripts to use these configurations, though simply running `npm install` There are separate npm scripts to use these configurations, though simply running `npm install`
will use the default production configuration. will use the default production configuration.
*/ */
const path = require("path"); const path = require('path');
const packageDefinition = require("../package.json"); const packageDefinition = require('../package.json');
const CopyWebpackPlugin = require("copy-webpack-plugin"); const CopyWebpackPlugin = require('copy-webpack-plugin');
const webpack = require("webpack"); const webpack = require('webpack');
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { VueLoaderPlugin } = require("vue-loader"); const { VueLoaderPlugin } = require('vue-loader');
let gitRevision = "error-retrieving-revision"; let gitRevision = 'error-retrieving-revision';
let gitBranch = "error-retrieving-branch"; let gitBranch = 'error-retrieving-branch';
try { try {
gitRevision = require("child_process") gitRevision = require('child_process').execSync('git rev-parse HEAD').toString().trim();
.execSync("git rev-parse HEAD") gitBranch = require('child_process')
.toString() .execSync('git rev-parse --abbrev-ref HEAD')
.trim();
gitBranch = require("child_process")
.execSync("git rev-parse --abbrev-ref HEAD")
.toString() .toString()
.trim(); .trim();
} catch (err) { } catch (err) {
console.warn(err); console.warn(err);
} }
const projectRootDir = path.resolve(__dirname, ".."); const projectRootDir = path.resolve(__dirname, '..');
/** @type {import('webpack').Configuration} */ /** @type {import('webpack').Configuration} */
const config = { const config = {
context: projectRootDir, context: projectRootDir,
entry: { entry: {
openmct: "./openmct.js", openmct: './openmct.js',
generatorWorker: "./example/generator/generatorWorker.js", generatorWorker: './example/generator/generatorWorker.js',
couchDBChangesFeed: couchDBChangesFeed: './src/plugins/persistence/couch/CouchChangesFeed.js',
"./src/plugins/persistence/couch/CouchChangesFeed.js", inMemorySearchWorker: './src/api/objects/InMemorySearchWorker.js',
inMemorySearchWorker: "./src/api/objects/InMemorySearchWorker.js", espressoTheme: './src/plugins/themes/espresso-theme.scss',
espressoTheme: "./src/plugins/themes/espresso-theme.scss", snowTheme: './src/plugins/themes/snow-theme.scss'
snowTheme: "./src/plugins/themes/snow-theme.scss"
}, },
output: { output: {
globalObject: "this", globalObject: 'this',
filename: "[name].js", filename: '[name].js',
path: path.resolve(projectRootDir, "dist"), path: path.resolve(projectRootDir, 'dist'),
library: "openmct", library: 'openmct',
libraryTarget: "umd", libraryTarget: 'umd',
publicPath: "", publicPath: '',
hashFunction: "xxhash64", hashFunction: 'xxhash64',
clean: true clean: true
}, },
resolve: { resolve: {
alias: { alias: {
"@": path.join(projectRootDir, "src"), '@': path.join(projectRootDir, 'src'),
legacyRegistry: path.join(projectRootDir, "src/legacyRegistry"), legacyRegistry: path.join(projectRootDir, 'src/legacyRegistry'),
saveAs: "file-saver/src/FileSaver.js", saveAs: 'file-saver/src/FileSaver.js',
csv: "comma-separated-values", csv: 'comma-separated-values',
EventEmitter: "eventemitter3", EventEmitter: 'eventemitter3',
bourbon: "bourbon.scss", bourbon: 'bourbon.scss',
"plotly-basic": "plotly.js-basic-dist", 'plotly-basic': 'plotly.js-basic-dist',
"plotly-gl2d": "plotly.js-gl2d-dist", 'plotly-gl2d': 'plotly.js-gl2d-dist',
"d3-scale": path.join( 'd3-scale': path.join(projectRootDir, 'node_modules/d3-scale/dist/d3-scale.min.js'),
projectRootDir, printj: path.join(projectRootDir, 'node_modules/printj/dist/printj.min.js'),
"node_modules/d3-scale/dist/d3-scale.min.js" styles: path.join(projectRootDir, 'src/styles'),
), MCT: path.join(projectRootDir, 'src/MCT'),
printj: path.join( testUtils: path.join(projectRootDir, 'src/utils/testUtils.js'),
projectRootDir, objectUtils: path.join(projectRootDir, 'src/api/objects/object-utils.js'),
"node_modules/printj/dist/printj.min.js" kdbush: path.join(projectRootDir, 'node_modules/kdbush/kdbush.min.js'),
), utils: path.join(projectRootDir, 'src/utils')
styles: path.join(projectRootDir, "src/styles"),
MCT: path.join(projectRootDir, "src/MCT"),
testUtils: path.join(projectRootDir, "src/utils/testUtils.js"),
objectUtils: path.join(
projectRootDir,
"src/api/objects/object-utils.js"
),
"kdbush": path.join(projectRootDir, "node_modules/kdbush/kdbush.min.js"),
utils: path.join(projectRootDir, "src/utils")
} }
}, },
plugins: [ plugins: [
@ -95,24 +82,24 @@ const config = {
new CopyWebpackPlugin({ new CopyWebpackPlugin({
patterns: [ patterns: [
{ {
from: "src/images/favicons", from: 'src/images/favicons',
to: "favicons" to: 'favicons'
}, },
{ {
from: "./index.html", from: './index.html',
transform: function (content) { transform: function (content) {
return content.toString().replace(/dist\//g, ""); return content.toString().replace(/dist\//g, '');
} }
}, },
{ {
from: "src/plugins/imagery/layers", from: 'src/plugins/imagery/layers',
to: "imagery" to: 'imagery'
} }
] ]
}), }),
new MiniCssExtractPlugin({ new MiniCssExtractPlugin({
filename: "[name].css", filename: '[name].css',
chunkFilename: "[name].css" chunkFilename: '[name].css'
}) })
], ],
module: { module: {
@ -122,49 +109,49 @@ const config = {
use: [ use: [
MiniCssExtractPlugin.loader, MiniCssExtractPlugin.loader,
{ {
loader: "css-loader" loader: 'css-loader'
}, },
{ {
loader: "resolve-url-loader" loader: 'resolve-url-loader'
}, },
{ {
loader: "sass-loader", loader: 'sass-loader',
options: { sourceMap: true } options: { sourceMap: true }
} }
] ]
}, },
{ {
test: /\.vue$/, test: /\.vue$/,
use: "vue-loader" use: 'vue-loader'
}, },
{ {
test: /\.html$/, test: /\.html$/,
type: "asset/source" type: 'asset/source'
}, },
{ {
test: /\.(jpg|jpeg|png|svg)$/, test: /\.(jpg|jpeg|png|svg)$/,
type: "asset/resource", type: 'asset/resource',
generator: { generator: {
filename: "images/[name][ext]" filename: 'images/[name][ext]'
} }
}, },
{ {
test: /\.ico$/, test: /\.ico$/,
type: "asset/resource", type: 'asset/resource',
generator: { generator: {
filename: "icons/[name][ext]" filename: 'icons/[name][ext]'
} }
}, },
{ {
test: /\.(woff|woff2?|eot|ttf)$/, test: /\.(woff|woff2?|eot|ttf)$/,
type: "asset/resource", type: 'asset/resource',
generator: { generator: {
filename: "fonts/[name][ext]" filename: 'fonts/[name][ext]'
} }
} }
] ]
}, },
stats: "errors-warnings", stats: 'errors-warnings',
performance: { performance: {
// We should eventually consider chunking to decrease // We should eventually consider chunking to decrease
// these values // these values

View File

@ -6,9 +6,9 @@ OpenMCT Continuous Integration servers use this configuration to add code covera
information to pull requests. information to pull requests.
*/ */
const config = require("./webpack.dev"); const config = require('./webpack.dev');
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
const CI = process.env.CI === "true"; const CI = process.env.CI === 'true';
config.devtool = CI ? false : undefined; config.devtool = CI ? false : undefined;
@ -18,15 +18,15 @@ config.module.rules.push({
test: /\.js$/, test: /\.js$/,
exclude: /(Spec\.js$)|(node_modules)/, exclude: /(Spec\.js$)|(node_modules)/,
use: { use: {
loader: "babel-loader", loader: 'babel-loader',
options: { options: {
retainLines: true, retainLines: true,
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
plugins: [ plugins: [
[ [
"babel-plugin-istanbul", 'babel-plugin-istanbul',
{ {
extension: [".js", ".vue"] extension: ['.js', '.vue']
} }
] ]
] ]

View File

@ -5,29 +5,29 @@ This configuration should be used for development purposes. It contains full sou
devServer (which be invoked using by `npm start`), and a non-minified Vue.js distribution. devServer (which be invoked using by `npm start`), and a non-minified Vue.js distribution.
If OpenMCT is to be used for a production server, use webpack.prod.js instead. If OpenMCT is to be used for a production server, use webpack.prod.js instead.
*/ */
const path = require("path"); const path = require('path');
const webpack = require("webpack"); const webpack = require('webpack');
const { merge } = require("webpack-merge"); const { merge } = require('webpack-merge');
const common = require("./webpack.common"); const common = require('./webpack.common');
const projectRootDir = path.resolve(__dirname, ".."); const projectRootDir = path.resolve(__dirname, '..');
module.exports = merge(common, { module.exports = merge(common, {
mode: "development", mode: 'development',
watchOptions: { watchOptions: {
// Since we use require.context, webpack is watching the entire directory. // Since we use require.context, webpack is watching the entire directory.
// We need to exclude any files we don't want webpack to watch. // We need to exclude any files we don't want webpack to watch.
// See: https://webpack.js.org/configuration/watch/#watchoptions-exclude // See: https://webpack.js.org/configuration/watch/#watchoptions-exclude
ignored: [ ignored: [
"**/{node_modules,dist,docs,e2e}", // All files in node_modules, dist, docs, e2e, '**/{node_modules,dist,docs,e2e}', // All files in node_modules, dist, docs, e2e,
"**/{*.yml,Procfile,webpack*.js,babel*.js,package*.json,tsconfig.json}", // Config files '**/{*.yml,Procfile,webpack*.js,babel*.js,package*.json,tsconfig.json}', // Config files
"**/*.{sh,md,png,ttf,woff,svg}", // Non source files '**/*.{sh,md,png,ttf,woff,svg}', // Non source files
"**/.*" // dotfiles and dotfolders '**/.*' // dotfiles and dotfolders
] ]
}, },
resolve: { resolve: {
alias: { alias: {
vue: path.join(projectRootDir, "node_modules/vue/dist/vue.js") vue: path.join(projectRootDir, 'node_modules/vue/dist/vue.js')
} }
}, },
plugins: [ plugins: [
@ -35,20 +35,20 @@ module.exports = merge(common, {
__OPENMCT_ROOT_RELATIVE__: '"dist/"' __OPENMCT_ROOT_RELATIVE__: '"dist/"'
}) })
], ],
devtool: "eval-source-map", devtool: 'eval-source-map',
devServer: { devServer: {
devMiddleware: { devMiddleware: {
writeToDisk: (filePathString) => { writeToDisk: (filePathString) => {
const filePath = path.parse(filePathString); const filePath = path.parse(filePathString);
const shouldWrite = !filePath.base.includes("hot-update"); const shouldWrite = !filePath.base.includes('hot-update');
return shouldWrite; return shouldWrite;
} }
}, },
watchFiles: ["**/*.css"], watchFiles: ['**/*.css'],
static: { static: {
directory: path.join(__dirname, "..", "/dist"), directory: path.join(__dirname, '..', '/dist'),
publicPath: "/dist", publicPath: '/dist',
watch: false watch: false
}, },
client: { client: {

View File

@ -4,18 +4,18 @@
This configuration should be used for production installs. This configuration should be used for production installs.
It is the default webpack configuration. It is the default webpack configuration.
*/ */
const path = require("path"); const path = require('path');
const webpack = require("webpack"); const webpack = require('webpack');
const { merge } = require("webpack-merge"); const { merge } = require('webpack-merge');
const common = require("./webpack.common"); const common = require('./webpack.common');
const projectRootDir = path.resolve(__dirname, ".."); const projectRootDir = path.resolve(__dirname, '..');
module.exports = merge(common, { module.exports = merge(common, {
mode: "production", mode: 'production',
resolve: { resolve: {
alias: { alias: {
vue: path.join(projectRootDir, "node_modules/vue/dist/vue.min.js") vue: path.join(projectRootDir, 'node_modules/vue/dist/vue.min.js')
} }
}, },
plugins: [ plugins: [
@ -23,5 +23,5 @@ module.exports = merge(common, {
__OPENMCT_ROOT_RELATIVE__: '""' __OPENMCT_ROOT_RELATIVE__: '""'
}) })
], ],
devtool: "source-map" devtool: 'source-map'
}); });

View File

@ -11,7 +11,7 @@ coverage:
informational: true informational: true
precision: 2 precision: 2
round: down round: down
range: "66...100" range: '66...100'
flags: flags:
unit: unit:
@ -22,7 +22,7 @@ flags:
carryforward: true carryforward: true
comment: comment:
layout: "diff,flags,files,footer" layout: 'diff,flags,files,footer'
behavior: default behavior: default
require_changes: false require_changes: false
show_carryforward_flags: true show_carryforward_flags: true

View File

@ -1,14 +1,14 @@
/* eslint-disable no-undef */ /* eslint-disable no-undef */
module.exports = { module.exports = {
"extends": ["plugin:playwright/playwright-test"], extends: ['plugin:playwright/playwright-test'],
"rules": { rules: {
"playwright/max-nested-describe": ["error", { "max": 1 }] 'playwright/max-nested-describe': ['error', { max: 1 }]
}, },
"overrides": [ overrides: [
{ {
"files": ["tests/visual/*.spec.js"], files: ['tests/visual/*.spec.js'],
"rules": { rules: {
"playwright/no-wait-for-timeout": "off" 'playwright/no-wait-for-timeout': 'off'
} }
} }
] ]

View File

@ -84,7 +84,7 @@ async function createDomainObjectWithDefaults(page, { type, name, parent = 'mine
// Modify the name input field of the domain object to accept 'name' // Modify the name input field of the domain object to accept 'name'
const nameInput = page.locator('form[name="mctForm"] .first input[type="text"]'); const nameInput = page.locator('form[name="mctForm"] .first input[type="text"]');
await nameInput.fill(""); await nameInput.fill('');
await nameInput.fill(name); await nameInput.fill(name);
if (page.testNotes) { if (page.testNotes) {
@ -178,7 +178,7 @@ async function createPlanFromJSON(page, { name, json, parent = 'mine' }) {
// Modify the name input field of the domain object to accept 'name' // Modify the name input field of the domain object to accept 'name'
const nameInput = page.locator('form[name="mctForm"] .first input[type="text"]'); const nameInput = page.locator('form[name="mctForm"] .first input[type="text"]');
await nameInput.fill(""); await nameInput.fill('');
await nameInput.fill(name); await nameInput.fill(name);
// Upload buffer from memory // Upload buffer from memory
@ -209,12 +209,12 @@ async function createPlanFromJSON(page, { name, json, parent = 'mine' }) {
} }
/** /**
* Open the given `domainObject`'s context menu from the object tree. * Open the given `domainObject`'s context menu from the object tree.
* Expands the path to the object and scrolls to it if necessary. * Expands the path to the object and scrolls to it if necessary.
* *
* @param {import('@playwright/test').Page} page * @param {import('@playwright/test').Page} page
* @param {string} url the url to the object * @param {string} url the url to the object
*/ */
async function openObjectTreeContextMenu(page, url) { async function openObjectTreeContextMenu(page, url) {
await page.goto(url); await page.goto(url);
await page.click('button[title="Show selected item in tree"]'); await page.click('button[title="Show selected item in tree"]');
@ -228,15 +228,17 @@ async function openObjectTreeContextMenu(page, url) {
* @param {import('@playwright/test').Page} page * @param {import('@playwright/test').Page} page
* @param {"Main Tree" | "Create Modal Tree"} [treeName="Main Tree"] * @param {"Main Tree" | "Create Modal Tree"} [treeName="Main Tree"]
*/ */
async function expandEntireTree(page, treeName = "Main Tree") { async function expandEntireTree(page, treeName = 'Main Tree') {
const treeLocator = page.getByRole('tree', { const treeLocator = page.getByRole('tree', {
name: treeName name: treeName
}); });
const collapsedTreeItems = treeLocator.getByRole('treeitem', { const collapsedTreeItems = treeLocator
.getByRole('treeitem', {
expanded: false expanded: false
}).locator('span.c-disclosure-triangle.is-enabled'); })
.locator('span.c-disclosure-triangle.is-enabled');
while (await collapsedTreeItems.count() > 0) { while ((await collapsedTreeItems.count()) > 0) {
await collapsedTreeItems.nth(0).click(); await collapsedTreeItems.nth(0).click();
// FIXME: Replace hard wait with something event-driven. // FIXME: Replace hard wait with something event-driven.
@ -276,7 +278,10 @@ async function getHashUrlToDomainObject(page, uuid) {
await page.waitForLoadState('load'); //Add some determinism await page.waitForLoadState('load'); //Add some determinism
const hashUrl = await page.evaluate(async (objectUuid) => { const hashUrl = await page.evaluate(async (objectUuid) => {
const path = await window.openmct.objects.getOriginalPath(objectUuid); const path = await window.openmct.objects.getOriginalPath(objectUuid);
let url = './#/browse/' + [...path].reverse() let url =
'./#/browse/' +
[...path]
.reverse()
.map((object) => window.openmct.objects.makeKeyString(object.identifier)) .map((object) => window.openmct.objects.makeKeyString(object.identifier))
.join('/'); .join('/');
@ -348,7 +353,7 @@ async function setRealTimeMode(page) {
* @param {OffsetValues} offset * @param {OffsetValues} offset
* @param {import('@playwright/test').Locator} offsetButton * @param {import('@playwright/test').Locator} offsetButton
*/ */
async function setTimeConductorOffset(page, {hours, mins, secs}, offsetButton) { async function setTimeConductorOffset(page, { hours, mins, secs }, offsetButton) {
await offsetButton.click(); await offsetButton.click();
if (hours) { if (hours) {
@ -407,16 +412,16 @@ async function selectInspectorTab(page, name) {
} }
/** /**
* Waits and asserts that all plot series data on the page * Waits and asserts that all plot series data on the page
* is loaded and drawn. * is loaded and drawn.
* *
* In lieu of a better way to detect when a plot is done rendering, * In lieu of a better way to detect when a plot is done rendering,
* we [attach a class to the '.gl-plot' element](https://github.com/nasa/openmct/blob/5924d7ea95a0c2d4141c602a3c7d0665cb91095f/src/plugins/plot/MctPlot.vue#L27) * we [attach a class to the '.gl-plot' element](https://github.com/nasa/openmct/blob/5924d7ea95a0c2d4141c602a3c7d0665cb91095f/src/plugins/plot/MctPlot.vue#L27)
* once all pending series data has been loaded. The following appAction retrieves * once all pending series data has been loaded. The following appAction retrieves
* all plots on the page and waits up to the default timeout for the class to be * all plots on the page and waits up to the default timeout for the class to be
* attached to each plot. * attached to each plot.
* @param {import('@playwright/test').Page} page * @param {import('@playwright/test').Page} page
*/ */
async function waitForPlotsToRender(page) { async function waitForPlotsToRender(page) {
const plotLocator = page.locator('.gl-plot'); const plotLocator = page.locator('.gl-plot');
for (const plot of await plotLocator.all()) { for (const plot of await plotLocator.all()) {
@ -441,12 +446,21 @@ async function waitForPlotsToRender(page) {
* @return {Promise<PlotPixel[]>} * @return {Promise<PlotPixel[]>}
*/ */
async function getCanvasPixels(page, canvasSelector) { async function getCanvasPixels(page, canvasSelector) {
const getTelemValuePromise = new Promise(resolve => page.exposeFunction('getCanvasValue', resolve)); const getTelemValuePromise = new Promise((resolve) =>
const canvasHandle = await page.evaluateHandle((canvas) => document.querySelector(canvas), canvasSelector); page.exposeFunction('getCanvasValue', resolve)
const canvasContextHandle = await page.evaluateHandle(canvas => canvas.getContext('2d'), canvasHandle); );
const canvasHandle = await page.evaluateHandle(
(canvas) => document.querySelector(canvas),
canvasSelector
);
const canvasContextHandle = await page.evaluateHandle(
(canvas) => canvas.getContext('2d'),
canvasHandle
);
await waitForPlotsToRender(page); await waitForPlotsToRender(page);
await page.evaluate(([canvas, ctx]) => { await page.evaluate(
([canvas, ctx]) => {
// The document canvas is where the plot points and lines are drawn. // The document canvas is where the plot points and lines are drawn.
// The only way to access the canvas is using document (using page.evaluate) // The only way to access the canvas is using document (using page.evaluate)
/** @type {ImageData} */ /** @type {ImageData} */
@ -457,14 +471,16 @@ async function getCanvasPixels(page, canvasSelector) {
const plotPixels = []; const plotPixels = [];
// Each pixel consists of four values within the ImageData.data array. The for loop iterates by multiples of four. // Each pixel consists of four values within the ImageData.data array. The for loop iterates by multiples of four.
// The values associated with each pixel are R (red), G (green), B (blue), and A (alpha), in that order. // The values associated with each pixel are R (red), G (green), B (blue), and A (alpha), in that order.
for (let i = 0; i < imageDataValues.length;) { for (let i = 0; i < imageDataValues.length; ) {
if (imageDataValues[i] > 0) { if (imageDataValues[i] > 0) {
plotPixels.push({ plotPixels.push({
r: imageDataValues[i], r: imageDataValues[i],
g: imageDataValues[i + 1], g: imageDataValues[i + 1],
b: imageDataValues[i + 2], b: imageDataValues[i + 2],
a: imageDataValues[i + 3], a: imageDataValues[i + 3],
strValue: `rgb(${imageDataValues[i]}, ${imageDataValues[i + 1]}, ${imageDataValues[i + 2]}, ${imageDataValues[i + 3]})` strValue: `rgb(${imageDataValues[i]}, ${imageDataValues[i + 1]}, ${
imageDataValues[i + 2]
}, ${imageDataValues[i + 3]})`
}); });
} }
@ -472,7 +488,9 @@ async function getCanvasPixels(page, canvasSelector) {
} }
window.getCanvasValue(plotPixels); window.getCanvasValue(plotPixels);
}, [canvasHandle, canvasContextHandle]); },
[canvasHandle, canvasContextHandle]
);
return getTelemValuePromise; return getTelemValuePromise;
} }

View File

@ -56,12 +56,9 @@ function _consoleMessageToString(msg) {
* @return {Promise<Animation[]>} * @return {Promise<Animation[]>}
*/ */
function waitForAnimations(locator) { function waitForAnimations(locator) {
return locator return locator.evaluate((element) =>
.evaluate((element) => Promise.all(element.getAnimations({ subtree: true }).map((animation) => animation.finished))
Promise.all( );
element
.getAnimations({ subtree: true })
.map((animation) => animation.finished)));
} }
/** /**
@ -90,7 +87,8 @@ exports.test = base.test.extend({
* @see {@link https://github.com/sinonjs/fake-timers/#var-clock--faketimersinstallconfig SinonJS FakeTimers Config} * @see {@link https://github.com/sinonjs/fake-timers/#var-clock--faketimersinstallconfig SinonJS FakeTimers Config}
*/ */
clockOptions: [undefined, { option: true }], clockOptions: [undefined, { option: true }],
overrideClock: [async ({ context, clockOptions }, use) => { overrideClock: [
async ({ context, clockOptions }, use) => {
if (clockOptions !== undefined) { if (clockOptions !== undefined) {
await context.addInitScript({ await context.addInitScript({
path: path.join(__dirname, '../', './node_modules/sinon/pkg/sinon.js') path: path.join(__dirname, '../', './node_modules/sinon/pkg/sinon.js')
@ -101,10 +99,12 @@ exports.test = base.test.extend({
} }
await use(context); await use(context);
}, { },
{
auto: true, auto: true,
scope: 'test' scope: 'test'
}], }
],
/** /**
* Extends the base context class to add codecoverage shim. * Extends the base context class to add codecoverage shim.
* @see {@link https://github.com/mxschmitt/playwright-test-coverage Github Project} * @see {@link https://github.com/mxschmitt/playwright-test-coverage Github Project}
@ -112,19 +112,24 @@ exports.test = base.test.extend({
context: async ({ context }, use) => { context: async ({ context }, use) => {
await context.addInitScript(() => await context.addInitScript(() =>
window.addEventListener('beforeunload', () => window.addEventListener('beforeunload', () =>
(window).collectIstanbulCoverage(JSON.stringify((window).__coverage__)) window.collectIstanbulCoverage(JSON.stringify(window.__coverage__))
) )
); );
await fs.promises.mkdir(istanbulCLIOutput, { recursive: true }); await fs.promises.mkdir(istanbulCLIOutput, { recursive: true });
await context.exposeFunction('collectIstanbulCoverage', (coverageJSON) => { await context.exposeFunction('collectIstanbulCoverage', (coverageJSON) => {
if (coverageJSON) { if (coverageJSON) {
fs.writeFileSync(path.join(istanbulCLIOutput, `playwright_coverage_${uuid()}.json`), coverageJSON); fs.writeFileSync(
path.join(istanbulCLIOutput, `playwright_coverage_${uuid()}.json`),
coverageJSON
);
} }
}); });
await use(context); await use(context);
for (const page of context.pages()) { for (const page of context.pages()) {
await page.evaluate(() => (window).collectIstanbulCoverage(JSON.stringify((window).__coverage__))); await page.evaluate(() =>
window.collectIstanbulCoverage(JSON.stringify(window.__coverage__))
);
} }
}, },
/** /**
@ -147,8 +152,10 @@ exports.test = base.test.extend({
// Assert against console errors during teardown // Assert against console errors during teardown
if (failOnConsoleError) { if (failOnConsoleError) {
messages.forEach( messages.forEach((msg) =>
msg => expect.soft(msg.type(), `Console error detected: ${_consoleMessageToString(msg)}`).not.toEqual('error') expect
.soft(msg.type(), `Console error detected: ${_consoleMessageToString(msg)}`)
.not.toEqual('error')
); );
} }
}, },

View File

@ -6,8 +6,7 @@ class DomainObjectViewProvider {
} }
canView(domainObject) { canView(domainObject) {
return domainObject.type === 'imageFileInput' return domainObject.type === 'imageFileInput' || domainObject.type === 'jsonFileInput';
|| domainObject.type === 'jsonFileInput';
} }
view(domainObject, objectPath) { view(domainObject, objectPath) {
@ -36,7 +35,7 @@ document.addEventListener('DOMContentLoaded', () => {
openmct.types.addType('jsonFileInput', { openmct.types.addType('jsonFileInput', {
key: 'jsonFileInput', key: 'jsonFileInput',
name: "JSON File Input Object", name: 'JSON File Input Object',
creatable: true, creatable: true,
form: [ form: [
{ {
@ -46,16 +45,14 @@ document.addEventListener('DOMContentLoaded', () => {
required: true, required: true,
text: 'Select File...', text: 'Select File...',
type: 'application/json', type: 'application/json',
property: [ property: ['selectFile']
"selectFile"
]
} }
] ]
}); });
openmct.types.addType('imageFileInput', { openmct.types.addType('imageFileInput', {
key: 'imageFileInput', key: 'imageFileInput',
name: "Image File Input Object", name: 'Image File Input Object',
creatable: true, creatable: true,
form: [ form: [
{ {
@ -65,9 +62,7 @@ document.addEventListener('DOMContentLoaded', () => {
required: true, required: true,
text: 'Select File...', text: 'Select File...',
type: 'image/*', type: 'image/*',
property: [ property: ['selectFile']
"selectFile"
]
} }
] ]
}); });

View File

@ -24,4 +24,4 @@
} }
}); });
}); });
}()); })();

View File

@ -35,7 +35,9 @@ async function navigateToFaultManagementWithExample(page) {
* @param {import('@playwright/test').Page} page * @param {import('@playwright/test').Page} page
*/ */
async function navigateToFaultManagementWithStaticExample(page) { async function navigateToFaultManagementWithStaticExample(page) {
await page.addInitScript({ path: path.join(__dirname, './', 'addInitExampleFaultProviderStatic.js') }); await page.addInitScript({
path: path.join(__dirname, './', 'addInitExampleFaultProviderStatic.js')
});
await navigateToFaultItemInTree(page); await navigateToFaultItemInTree(page);
} }
@ -55,10 +57,12 @@ async function navigateToFaultManagementWithoutExample(page) {
async function navigateToFaultItemInTree(page) { async function navigateToFaultItemInTree(page) {
await page.goto('./', { waitUntil: 'networkidle' }); await page.goto('./', { waitUntil: 'networkidle' });
const faultManagementTreeItem = page.getByRole('tree', { const faultManagementTreeItem = page
name: "Main Tree" .getByRole('tree', {
}).getByRole('treeitem', { name: 'Main Tree'
name: "Fault Management" })
.getByRole('treeitem', {
name: 'Fault Management'
}); });
// Navigate to "Fault Management" from the tree // Navigate to "Fault Management" from the tree
@ -73,7 +77,6 @@ async function acknowledgeFault(page, rowNumber) {
await page.locator('.c-menu >> text="Acknowledge"').click(); await page.locator('.c-menu >> text="Acknowledge"').click();
// Click [aria-label="Save"] // Click [aria-label="Save"]
await page.locator('[aria-label="Save"]').click(); await page.locator('[aria-label="Save"]').click();
} }
/** /**
@ -192,7 +195,9 @@ async function getFaultResultCount(page) {
* @param {import('@playwright/test').Page} page * @param {import('@playwright/test').Page} page
*/ */
function getFault(page, rowNumber) { function getFault(page, rowNumber) {
const fault = page.locator(`.c-faults-list-view-item-body > .c-fault-mgmt__list >> nth=${rowNumber - 1}`); const fault = page.locator(
`.c-faults-list-view-item-body > .c-fault-mgmt__list >> nth=${rowNumber - 1}`
);
return fault; return fault;
} }
@ -210,7 +215,9 @@ function getFaultByName(page, name) {
* @param {import('@playwright/test').Page} page * @param {import('@playwright/test').Page} page
*/ */
async function getFaultName(page, rowNumber) { async function getFaultName(page, rowNumber) {
const faultName = await page.locator(`.c-fault-mgmt__list-faultname >> nth=${rowNumber - 1}`).textContent(); const faultName = await page
.locator(`.c-fault-mgmt__list-faultname >> nth=${rowNumber - 1}`)
.textContent();
return faultName; return faultName;
} }
@ -219,7 +226,9 @@ async function getFaultName(page, rowNumber) {
* @param {import('@playwright/test').Page} page * @param {import('@playwright/test').Page} page
*/ */
async function getFaultSeverity(page, rowNumber) { async function getFaultSeverity(page, rowNumber) {
const faultSeverity = await page.locator(`.c-faults-list-view-item-body .c-fault-mgmt__list-severity >> nth=${rowNumber - 1}`).getAttribute('title'); const faultSeverity = await page
.locator(`.c-faults-list-view-item-body .c-fault-mgmt__list-severity >> nth=${rowNumber - 1}`)
.getAttribute('title');
return faultSeverity; return faultSeverity;
} }
@ -228,7 +237,9 @@ async function getFaultSeverity(page, rowNumber) {
* @param {import('@playwright/test').Page} page * @param {import('@playwright/test').Page} page
*/ */
async function getFaultNamespace(page, rowNumber) { async function getFaultNamespace(page, rowNumber) {
const faultNamespace = await page.locator(`.c-fault-mgmt__list-path >> nth=${rowNumber - 1}`).textContent(); const faultNamespace = await page
.locator(`.c-fault-mgmt__list-path >> nth=${rowNumber - 1}`)
.textContent();
return faultNamespace; return faultNamespace;
} }
@ -237,7 +248,9 @@ async function getFaultNamespace(page, rowNumber) {
* @param {import('@playwright/test').Page} page * @param {import('@playwright/test').Page} page
*/ */
async function getFaultTriggerTime(page, rowNumber) { async function getFaultTriggerTime(page, rowNumber) {
const faultTriggerTime = await page.locator(`.c-fault-mgmt__list-trigTime >> nth=${rowNumber - 1} >> .c-fault-mgmt-item__value`).textContent(); const faultTriggerTime = await page
.locator(`.c-fault-mgmt__list-trigTime >> nth=${rowNumber - 1} >> .c-fault-mgmt-item__value`)
.textContent();
return faultTriggerTime.toString().trim(); return faultTriggerTime.toString().trim();
} }
@ -247,8 +260,9 @@ async function getFaultTriggerTime(page, rowNumber) {
*/ */
async function openFaultRowMenu(page, rowNumber) { async function openFaultRowMenu(page, rowNumber) {
// select // select
await page.locator(`.c-fault-mgmt-item > .c-fault-mgmt__list-action-button >> nth=${rowNumber - 1}`).click(); await page
.locator(`.c-fault-mgmt-item > .c-fault-mgmt__list-action-button >> nth=${rowNumber - 1}`)
.click();
} }
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef

View File

@ -42,7 +42,7 @@ async function enterTextEntry(page, text) {
async function dragAndDropEmbed(page, notebookObject) { async function dragAndDropEmbed(page, notebookObject) {
// Create example telemetry object // Create example telemetry object
const swg = await createDomainObjectWithDefaults(page, { const swg = await createDomainObjectWithDefaults(page, {
type: "Sine Wave Generator" type: 'Sine Wave Generator'
}); });
// Navigate to notebook // Navigate to notebook
await page.goto(notebookObject.url); await page.goto(notebookObject.url);

View File

@ -46,32 +46,39 @@ export async function assertPlanActivities(page, plan, objectUrl) {
} }
// Switch to fixed time mode with all plan events within the bounds // Switch to fixed time mode with all plan events within the bounds
await page.goto(`${objectUrl}?tc.mode=fixed&tc.startBound=${startBound}&tc.endBound=${endBound}&tc.timeSystem=utc&view=plan.view`); await page.goto(
`${objectUrl}?tc.mode=fixed&tc.startBound=${startBound}&tc.endBound=${endBound}&tc.timeSystem=utc&view=plan.view`
);
// Assert that the number of activities in the plan view matches the number of // Assert that the number of activities in the plan view matches the number of
// activities in the plan data within the specified time bounds // activities in the plan data within the specified time bounds
const eventCount = await page.locator('.activity-bounds').count(); const eventCount = await page.locator('.activity-bounds').count();
expect(eventCount).toEqual(Object.values(plan) expect(eventCount).toEqual(
Object.values(plan)
.flat() .flat()
.filter(event => .filter((event) =>
activitiesWithinTimeBounds(event.start, event.end, startBound, endBound)).length); activitiesWithinTimeBounds(event.start, event.end, startBound, endBound)
).length
);
} }
} }
} }
/** /**
* Returns true if the activities time bounds overlap, false otherwise. * Returns true if the activities time bounds overlap, false otherwise.
* @param {number} start1 the start time of the first activity * @param {number} start1 the start time of the first activity
* @param {number} end1 the end time of the first activity * @param {number} end1 the end time of the first activity
* @param {number} start2 the start time of the second activity * @param {number} start2 the start time of the second activity
* @param {number} end2 the end time of the second activity * @param {number} end2 the end time of the second activity
* @returns {boolean} true if the activities overlap, false otherwise * @returns {boolean} true if the activities overlap, false otherwise
*/ */
function activitiesWithinTimeBounds(start1, end1, start2, end2) { function activitiesWithinTimeBounds(start1, end1, start2, end2) {
return (start1 >= start2 && start1 <= end2) return (
|| (end1 >= start2 && end1 <= end2) (start1 >= start2 && start1 <= end2) ||
|| (start2 >= start1 && start2 <= end1) (end1 >= start2 && end1 <= end2) ||
|| (end2 >= start1 && end2 <= end1); (start2 >= start1 && start2 <= end1) ||
(end2 >= start1 && end2 <= end1)
);
} }
/** /**
@ -84,9 +91,11 @@ function activitiesWithinTimeBounds(start1, end1, start2, end2) {
export async function setBoundsToSpanAllActivities(page, planJson, planObjectUrl) { export async function setBoundsToSpanAllActivities(page, planJson, planObjectUrl) {
const activities = Object.values(planJson).flat(); const activities = Object.values(planJson).flat();
// Get the earliest start value // Get the earliest start value
const start = Math.min(...activities.map(activity => activity.start)); const start = Math.min(...activities.map((activity) => activity.start));
// Get the latest end value // Get the latest end value
const end = Math.max(...activities.map(activity => activity.end)); const end = Math.max(...activities.map((activity) => activity.end));
// Set the start and end bounds to the earliest start and latest end // Set the start and end bounds to the earliest start and latest end
await page.goto(`${planObjectUrl}?tc.mode=fixed&tc.startBound=${start}&tc.endBound=${end}&tc.timeSystem=utc&view=plan.view`); await page.goto(
`${planObjectUrl}?tc.mode=fixed&tc.startBound=${start}&tc.endBound=${end}&tc.timeSystem=utc&view=plan.view`
);
} }

View File

@ -69,10 +69,13 @@ const config = {
], ],
reporter: [ reporter: [
['list'], ['list'],
['html', { [
'html',
{
open: 'never', open: 'never',
outputFolder: '../html-test-results' //Must be in different location due to https://github.com/microsoft/playwright/issues/12840 outputFolder: '../html-test-results' //Must be in different location due to https://github.com/microsoft/playwright/issues/12840
}], }
],
['junit', { outputFile: '../test-results/results.xml' }], ['junit', { outputFile: '../test-results/results.xml' }],
['github'], ['github'],
['@deploysentinel/playwright'] ['@deploysentinel/playwright']

View File

@ -19,7 +19,7 @@ const config = {
}, },
workers: 1, workers: 1,
use: { use: {
browserName: "chromium", browserName: 'chromium',
baseURL: 'http://localhost:8080/', baseURL: 'http://localhost:8080/',
headless: false, headless: false,
ignoreHTTPSErrors: true, ignoreHTTPSErrors: true,
@ -94,10 +94,13 @@ const config = {
], ],
reporter: [ reporter: [
['list'], ['list'],
['html', { [
'html',
{
open: 'on-failure', open: 'on-failure',
outputFolder: '../html-test-results' //Must be in different location due to https://github.com/microsoft/playwright/issues/12840 outputFolder: '../html-test-results' //Must be in different location due to https://github.com/microsoft/playwright/issues/12840
}] }
]
] ]
}; };

View File

@ -17,7 +17,7 @@ const config = {
reuseExistingServer: !CI reuseExistingServer: !CI
}, },
use: { use: {
browserName: "chromium", browserName: 'chromium',
baseURL: 'http://localhost:8080/', baseURL: 'http://localhost:8080/',
headless: CI, //Only if running locally headless: CI, //Only if running locally
ignoreHTTPSErrors: true, ignoreHTTPSErrors: true,

View File

@ -41,10 +41,13 @@ const config = {
reporter: [ reporter: [
['list'], ['list'],
['junit', { outputFile: '../test-results/results.xml' }], ['junit', { outputFile: '../test-results/results.xml' }],
['html', { [
'html',
{
open: 'on-failure', open: 'on-failure',
outputFolder: '../html-test-results' //Must be in different location due to https://github.com/microsoft/playwright/issues/12840 outputFolder: '../html-test-results' //Must be in different location due to https://github.com/microsoft/playwright/issues/12840
}] }
]
] ]
}; };

View File

@ -120,7 +120,7 @@ const theme = 'espresso';
* *
* @type {string} * @type {string}
*/ */
const myItemsFolderName = "My Items"; const myItemsFolderName = 'My Items';
exports.test = test.extend({ exports.test = test.extend({
// This should follow in the Project's configuration. Can be set to 'snow' in playwright config.js // This should follow in the Project's configuration. Can be set to 'snow' in playwright config.js
@ -136,10 +136,7 @@ exports.test = test.extend({
// Attach info about the currently running test and its project. // Attach info about the currently running test and its project.
// This will be used by appActions to fill in the created // This will be used by appActions to fill in the created
// domain object's notes. // domain object's notes.
page.testNotes = [ page.testNotes = [`${testInfo.titlePath.join('\n')}`, `${testInfo.project.name}`].join('\n');
`${testInfo.titlePath.join('\n')}`,
`${testInfo.project.name}`
].join('\n');
await use(page); await use(page);
}, },

View File

@ -274,10 +274,7 @@
"id": "ac0d7eb1-b485-458f-bd2a-a63aa87a3a8a" "id": "ac0d7eb1-b485-458f-bd2a-a63aa87a3a8a"
} }
], ],
"layoutGrid": [ "layoutGrid": [10, 10],
10,
10
],
"objectStyles": { "objectStyles": {
"ed63cc29-80e2-4e2b-a472-3d6d4adbf310": { "ed63cc29-80e2-4e2b-a472-3d6d4adbf310": {
"staticStyle": { "staticStyle": {
@ -1455,9 +1452,7 @@
"id": "64e49fe7-5b36-43db-8347-4550b910de4c", "id": "64e49fe7-5b36-43db-8347-4550b910de4c",
"telemetry": "any", "telemetry": "any",
"operation": "greaterThan", "operation": "greaterThan",
"input": [ "input": ["120"],
"120"
],
"metadata": "sin" "metadata": "sin"
} }
] ]
@ -1475,10 +1470,7 @@
"id": "59f1c4bf-5d36-450c-9668-6546955fc066", "id": "59f1c4bf-5d36-450c-9668-6546955fc066",
"telemetry": "any", "telemetry": "any",
"operation": "between", "operation": "between",
"input": [ "input": ["120", "-20"],
"120",
"-20"
],
"metadata": "sin" "metadata": "sin"
} }
] ]
@ -1496,9 +1488,7 @@
"id": "6707be12-6a6e-4535-bb97-ab5c86f99934", "id": "6707be12-6a6e-4535-bb97-ab5c86f99934",
"telemetry": "any", "telemetry": "any",
"operation": "lessThan", "operation": "lessThan",
"input": [ "input": ["-20"],
"-20"
],
"metadata": "sin" "metadata": "sin"
} }
] ]
@ -1550,9 +1540,7 @@
"id": "64e49fe7-5b36-43db-8347-4550b910de4c", "id": "64e49fe7-5b36-43db-8347-4550b910de4c",
"telemetry": "any", "telemetry": "any",
"operation": "greaterThan", "operation": "greaterThan",
"input": [ "input": ["120"],
"120"
],
"metadata": "sin" "metadata": "sin"
} }
] ]
@ -1570,10 +1558,7 @@
"id": "59f1c4bf-5d36-450c-9668-6546955fc066", "id": "59f1c4bf-5d36-450c-9668-6546955fc066",
"telemetry": "any", "telemetry": "any",
"operation": "between", "operation": "between",
"input": [ "input": ["120", "-20"],
"120",
"-20"
],
"metadata": "sin" "metadata": "sin"
} }
] ]
@ -1591,9 +1576,7 @@
"id": "6707be12-6a6e-4535-bb97-ab5c86f99934", "id": "6707be12-6a6e-4535-bb97-ab5c86f99934",
"telemetry": "any", "telemetry": "any",
"operation": "lessThan", "operation": "lessThan",
"input": [ "input": ["-20"],
"-20"
],
"metadata": "sin" "metadata": "sin"
} }
] ]
@ -1645,9 +1628,7 @@
"id": "64e49fe7-5b36-43db-8347-4550b910de4c", "id": "64e49fe7-5b36-43db-8347-4550b910de4c",
"telemetry": "any", "telemetry": "any",
"operation": "greaterThan", "operation": "greaterThan",
"input": [ "input": ["150"],
"150"
],
"metadata": "sin" "metadata": "sin"
} }
] ]
@ -1665,10 +1646,7 @@
"id": "59f1c4bf-5d36-450c-9668-6546955fc066", "id": "59f1c4bf-5d36-450c-9668-6546955fc066",
"telemetry": "any", "telemetry": "any",
"operation": "between", "operation": "between",
"input": [ "input": ["50", "-50"],
"50",
"-50"
],
"metadata": "sin" "metadata": "sin"
} }
] ]
@ -1720,9 +1698,7 @@
"id": "64e49fe7-5b36-43db-8347-4550b910de4c", "id": "64e49fe7-5b36-43db-8347-4550b910de4c",
"telemetry": "any", "telemetry": "any",
"operation": "greaterThan", "operation": "greaterThan",
"input": [ "input": ["150"],
"150"
],
"metadata": "sin" "metadata": "sin"
} }
] ]
@ -1740,10 +1716,7 @@
"id": "59f1c4bf-5d36-450c-9668-6546955fc066", "id": "59f1c4bf-5d36-450c-9668-6546955fc066",
"telemetry": "any", "telemetry": "any",
"operation": "between", "operation": "between",
"input": [ "input": ["50", "-50"],
"50",
"-50"
],
"metadata": "sin" "metadata": "sin"
} }
] ]

View File

@ -1 +1,90 @@
{"openmct":{"b3cee102-86dd-4c0a-8eec-4d5d276f8691":{"identifier":{"key":"b3cee102-86dd-4c0a-8eec-4d5d276f8691","namespace":""},"name":"Performance Display Layout","type":"layout","composition":[{"key":"9666e7b4-be0c-47a5-94b8-99accad7155e","namespace":""}],"configuration":{"items":[{"width":32,"height":18,"x":12,"y":9,"identifier":{"key":"9666e7b4-be0c-47a5-94b8-99accad7155e","namespace":""},"hasFrame":true,"fontSize":"default","font":"default","type":"subobject-view","id":"23ca351d-a67d-46aa-a762-290eb742d2f1"}],"layoutGrid":[10,10]},"modified":1654299875432,"location":"mine","persisted":1654299878751},"9666e7b4-be0c-47a5-94b8-99accad7155e":{"identifier":{"key":"9666e7b4-be0c-47a5-94b8-99accad7155e","namespace":""},"name":"Performance Example Imagery","type":"example.imagery","configuration":{"imageLocation":"","imageLoadDelayInMilliSeconds":20000,"imageSamples":[],"layers":[{"source":"dist/imagery/example-imagery-layer-16x9.png","name":"16:9","visible":false},{"source":"dist/imagery/example-imagery-layer-safe.png","name":"Safe","visible":false},{"source":"dist/imagery/example-imagery-layer-scale.png","name":"Scale","visible":false}]},"telemetry":{"values":[{"name":"Name","key":"name"},{"name":"Time","key":"utc","format":"utc","hints":{"domain":2}},{"name":"Local Time","key":"local","format":"local-format","hints":{"domain":1}},{"name":"Image","key":"url","format":"image","hints":{"image":1},"layers":[{"source":"dist/imagery/example-imagery-layer-16x9.png","name":"16:9"},{"source":"dist/imagery/example-imagery-layer-safe.png","name":"Safe"},{"source":"dist/imagery/example-imagery-layer-scale.png","name":"Scale"}]},{"name":"Image Download Name","key":"imageDownloadName","format":"imageDownloadName","hints":{"imageDownloadName":1}}]},"modified":1654299840077,"location":"b3cee102-86dd-4c0a-8eec-4d5d276f8691","persisted":1654299840078}},"rootId":"b3cee102-86dd-4c0a-8eec-4d5d276f8691"} {
"openmct": {
"b3cee102-86dd-4c0a-8eec-4d5d276f8691": {
"identifier": { "key": "b3cee102-86dd-4c0a-8eec-4d5d276f8691", "namespace": "" },
"name": "Performance Display Layout",
"type": "layout",
"composition": [{ "key": "9666e7b4-be0c-47a5-94b8-99accad7155e", "namespace": "" }],
"configuration": {
"items": [
{
"width": 32,
"height": 18,
"x": 12,
"y": 9,
"identifier": { "key": "9666e7b4-be0c-47a5-94b8-99accad7155e", "namespace": "" },
"hasFrame": true,
"fontSize": "default",
"font": "default",
"type": "subobject-view",
"id": "23ca351d-a67d-46aa-a762-290eb742d2f1"
}
],
"layoutGrid": [10, 10]
},
"modified": 1654299875432,
"location": "mine",
"persisted": 1654299878751
},
"9666e7b4-be0c-47a5-94b8-99accad7155e": {
"identifier": { "key": "9666e7b4-be0c-47a5-94b8-99accad7155e", "namespace": "" },
"name": "Performance Example Imagery",
"type": "example.imagery",
"configuration": {
"imageLocation": "",
"imageLoadDelayInMilliSeconds": 20000,
"imageSamples": [],
"layers": [
{
"source": "dist/imagery/example-imagery-layer-16x9.png",
"name": "16:9",
"visible": false
},
{
"source": "dist/imagery/example-imagery-layer-safe.png",
"name": "Safe",
"visible": false
},
{
"source": "dist/imagery/example-imagery-layer-scale.png",
"name": "Scale",
"visible": false
}
]
},
"telemetry": {
"values": [
{ "name": "Name", "key": "name" },
{ "name": "Time", "key": "utc", "format": "utc", "hints": { "domain": 2 } },
{
"name": "Local Time",
"key": "local",
"format": "local-format",
"hints": { "domain": 1 }
},
{
"name": "Image",
"key": "url",
"format": "image",
"hints": { "image": 1 },
"layers": [
{ "source": "dist/imagery/example-imagery-layer-16x9.png", "name": "16:9" },
{ "source": "dist/imagery/example-imagery-layer-safe.png", "name": "Safe" },
{ "source": "dist/imagery/example-imagery-layer-scale.png", "name": "Scale" }
]
},
{
"name": "Image Download Name",
"key": "imageDownloadName",
"format": "imageDownloadName",
"hints": { "imageDownloadName": 1 }
}
]
},
"modified": 1654299840077,
"location": "b3cee102-86dd-4c0a-8eec-4d5d276f8691",
"persisted": 1654299840078
}
},
"rootId": "b3cee102-86dd-4c0a-8eec-4d5d276f8691"
}

View File

@ -1 +1,96 @@
{"openmct":{"6d2fa9fd-f2aa-461a-a1e1-164ac44bec9d":{"identifier":{"key":"6d2fa9fd-f2aa-461a-a1e1-164ac44bec9d","namespace":""},"name":"Performance Notebook","type":"notebook","configuration":{"defaultSort":"oldest","entries":{"3e31c412-33ba-4757-8ade-e9821f6ba321":{"8c8f6035-631c-45af-8c24-786c60295335":[{"id":"entry-1652815305457","createdOn":1652815305457,"createdBy":"","text":"Existing Entry 1","embeds":[]},{"id":"entry-1652815313465","createdOn":1652815313465,"createdBy":"","text":"Existing Entry 2","embeds":[]},{"id":"entry-1652815399955","createdOn":1652815399955,"createdBy":"","text":"Existing Entry 3","embeds":[]}]}},"imageMigrationVer":"v1","pageTitle":"Page","sections":[{"id":"3e31c412-33ba-4757-8ade-e9821f6ba321","isDefault":false,"isSelected":false,"name":"Section1","pages":[{"id":"8c8f6035-631c-45af-8c24-786c60295335","isDefault":false,"isSelected":false,"name":"Page1","pageTitle":"Page"},{"id":"36555942-c9aa-439c-bbdb-0aaf50db50f5","isDefault":false,"isSelected":false,"name":"Page2","pageTitle":"Page"}],"sectionTitle":"Section"},{"id":"dab0bd1d-2c5a-405c-987f-107123d6189a","isDefault":false,"isSelected":true,"name":"Section2","pages":[{"id":"f625a86a-cb99-4898-8082-80543c8de534","isDefault":false,"isSelected":false,"name":"Page1","pageTitle":"Page"},{"id":"e77ef810-f785-42a7-942e-07e999b79c59","isDefault":false,"isSelected":true,"name":"Page2","pageTitle":"Page"}],"sectionTitle":"Section"}],"sectionTitle":"Section","type":"General","showTime":"0"},"modified":1652815915219,"location":"mine","persisted":1652815915222}},"rootId":"6d2fa9fd-f2aa-461a-a1e1-164ac44bec9d"} {
"openmct": {
"6d2fa9fd-f2aa-461a-a1e1-164ac44bec9d": {
"identifier": { "key": "6d2fa9fd-f2aa-461a-a1e1-164ac44bec9d", "namespace": "" },
"name": "Performance Notebook",
"type": "notebook",
"configuration": {
"defaultSort": "oldest",
"entries": {
"3e31c412-33ba-4757-8ade-e9821f6ba321": {
"8c8f6035-631c-45af-8c24-786c60295335": [
{
"id": "entry-1652815305457",
"createdOn": 1652815305457,
"createdBy": "",
"text": "Existing Entry 1",
"embeds": []
},
{
"id": "entry-1652815313465",
"createdOn": 1652815313465,
"createdBy": "",
"text": "Existing Entry 2",
"embeds": []
},
{
"id": "entry-1652815399955",
"createdOn": 1652815399955,
"createdBy": "",
"text": "Existing Entry 3",
"embeds": []
}
]
}
},
"imageMigrationVer": "v1",
"pageTitle": "Page",
"sections": [
{
"id": "3e31c412-33ba-4757-8ade-e9821f6ba321",
"isDefault": false,
"isSelected": false,
"name": "Section1",
"pages": [
{
"id": "8c8f6035-631c-45af-8c24-786c60295335",
"isDefault": false,
"isSelected": false,
"name": "Page1",
"pageTitle": "Page"
},
{
"id": "36555942-c9aa-439c-bbdb-0aaf50db50f5",
"isDefault": false,
"isSelected": false,
"name": "Page2",
"pageTitle": "Page"
}
],
"sectionTitle": "Section"
},
{
"id": "dab0bd1d-2c5a-405c-987f-107123d6189a",
"isDefault": false,
"isSelected": true,
"name": "Section2",
"pages": [
{
"id": "f625a86a-cb99-4898-8082-80543c8de534",
"isDefault": false,
"isSelected": false,
"name": "Page1",
"pageTitle": "Page"
},
{
"id": "e77ef810-f785-42a7-942e-07e999b79c59",
"isDefault": false,
"isSelected": true,
"name": "Page2",
"pageTitle": "Page"
}
],
"sectionTitle": "Section"
}
],
"sectionTitle": "Section",
"type": "General",
"showTime": "0"
},
"modified": 1652815915219,
"location": "mine",
"persisted": 1652815915222
}
},
"rootId": "6d2fa9fd-f2aa-461a-a1e1-164ac44bec9d"
}

View File

@ -21,7 +21,11 @@
*****************************************************************************/ *****************************************************************************/
const { test, expect } = require('../../pluginFixtures.js'); const { test, expect } = require('../../pluginFixtures.js');
const { createDomainObjectWithDefaults, createNotification, expandEntireTree } = require('../../appActions.js'); const {
createDomainObjectWithDefaults,
createNotification,
expandEntireTree
} = require('../../appActions.js');
test.describe('AppActions', () => { test.describe('AppActions', () => {
test('createDomainObjectsWithDefaults', async ({ page }) => { test('createDomainObjectsWithDefaults', async ({ page }) => {
@ -85,7 +89,7 @@ test.describe('AppActions', () => {
expect(folder3.url).toBe(`${e2eFolder.url}/${folder1.uuid}/${folder2.uuid}/${folder3.uuid}`); expect(folder3.url).toBe(`${e2eFolder.url}/${folder1.uuid}/${folder2.uuid}/${folder3.uuid}`);
}); });
}); });
test("createNotification", async ({ page }) => { test('createNotification', async ({ page }) => {
await page.goto('./', { waitUntil: 'domcontentloaded' }); await page.goto('./', { waitUntil: 'domcontentloaded' });
await createNotification(page, { await createNotification(page, {
message: 'Test info notification', message: 'Test info notification',
@ -144,7 +148,7 @@ test.describe('AppActions', () => {
await page.goto('./#/browse/mine'); await page.goto('./#/browse/mine');
await expandEntireTree(page); await expandEntireTree(page);
const treePane = page.getByRole('tree', { const treePane = page.getByRole('tree', {
name: "Main Tree" name: 'Main Tree'
}); });
const treePaneCollapsedItems = treePane.getByRole('treeitem', { expanded: false }); const treePaneCollapsedItems = treePane.getByRole('treeitem', { expanded: false });
expect(await treePaneCollapsedItems.count()).toBe(0); expect(await treePaneCollapsedItems.count()).toBe(0);
@ -155,9 +159,9 @@ test.describe('AppActions', () => {
// Click the object specified by 'type' // Click the object specified by 'type'
await page.click(`li[role='menuitem']:text("Clock")`); await page.click(`li[role='menuitem']:text("Clock")`);
await expandEntireTree(page, "Create Modal Tree"); await expandEntireTree(page, 'Create Modal Tree');
const locatorTree = page.getByRole("tree", { const locatorTree = page.getByRole('tree', {
name: "Create Modal Tree" name: 'Create Modal Tree'
}); });
const locatorTreeCollapsedItems = locatorTree.locator('role=treeitem[expanded=false]'); const locatorTreeCollapsedItems = locatorTree.locator('role=treeitem[expanded=false]');
expect(await locatorTreeCollapsedItems.count()).toBe(0); expect(await locatorTreeCollapsedItems.count()).toBe(0);

View File

@ -39,7 +39,6 @@ test.describe('baseFixtures tests', () => {
page.evaluate(() => console.error('This should result in a failure')), page.evaluate(() => console.error('This should result in a failure')),
page.waitForEvent('console') // always wait for the event to happen while triggering it! page.waitForEvent('console') // always wait for the event to happen while triggering it!
]); ]);
}); });
test('Verify that tests pass if console.warn is thrown', async ({ page }) => { test('Verify that tests pass if console.warn is thrown', async ({ page }) => {
//Go to baseURL //Go to baseURL
@ -50,6 +49,5 @@ test.describe('baseFixtures tests', () => {
page.evaluate(() => console.warn('This should result in a pass')), page.evaluate(() => console.warn('This should result in a pass')),
page.waitForEvent('console') // always wait for the event to happen while triggering it! page.waitForEvent('console') // always wait for the event to happen while triggering it!
]); ]);
}); });
}); });

View File

@ -21,28 +21,28 @@
*****************************************************************************/ *****************************************************************************/
/* /*
* This test suite template is to be used when creating new test suites. It will be kept up to date with the latest improvements * This test suite template is to be used when creating new test suites. It will be kept up to date with the latest improvements
* made by the Open MCT team. It will also follow our best pratices as those evolve. Please use this structure as a _reference_ and clear * made by the Open MCT team. It will also follow our best pratices as those evolve. Please use this structure as a _reference_ and clear
* or update any references when creating a new test suite! * or update any references when creating a new test suite!
* *
* To illustrate current best practices, we've included a mocked up test suite for Renaming a Timer domain object. * To illustrate current best practices, we've included a mocked up test suite for Renaming a Timer domain object.
* *
* Demonstrated: * Demonstrated:
* - Using appActions to leverage existing functions * - Using appActions to leverage existing functions
* - Structure * - Structure
* - @unstable annotation * - @unstable annotation
* - await, expect, test, describe syntax * - await, expect, test, describe syntax
* - Writing a custom function for a test suite * - Writing a custom function for a test suite
* - Test stub for unfinished test coverage (test.fixme) * - Test stub for unfinished test coverage (test.fixme)
* *
* The structure should follow * The structure should follow
* 1. imports * 1. imports
* 2. test.describe() * 2. test.describe()
* 3. -> test1 * 3. -> test1
* -> test2 * -> test2
* -> test3(stub) * -> test3(stub)
* 4. Any custom functions * 4. Any custom functions
*/ */
// Structure: Some standard Imports. Please update the required pathing. // Structure: Some standard Imports. Please update the required pathing.
const { test, expect } = require('../../pluginFixtures'); const { test, expect } = require('../../pluginFixtures');
@ -79,7 +79,7 @@ test.describe('Renaming Timer Object', () => {
* some hint as to what went wrong if the test fails. * some hint as to what went wrong if the test fails.
*/ */
test('An existing Timer object can be renamed via the 3dot actions menu', async ({ page }) => { test('An existing Timer object can be renamed via the 3dot actions menu', async ({ page }) => {
const newObjectName = "Renamed Timer"; const newObjectName = 'Renamed Timer';
// We've created an example of a shared function which pases the page and newObjectName values // We've created an example of a shared function which pases the page and newObjectName values
await renameTimerFrom3DotMenu(page, timer.url, newObjectName); await renameTimerFrom3DotMenu(page, timer.url, newObjectName);
@ -89,8 +89,8 @@ test.describe('Renaming Timer Object', () => {
}); });
test('An existing Timer object can be renamed twice', async ({ page }) => { test('An existing Timer object can be renamed twice', async ({ page }) => {
const newObjectName = "Renamed Timer"; const newObjectName = 'Renamed Timer';
const newObjectName2 = "Re-Renamed Timer"; const newObjectName2 = 'Re-Renamed Timer';
await renameTimerFrom3DotMenu(page, timer.url, newObjectName); await renameTimerFrom3DotMenu(page, timer.url, newObjectName);

View File

@ -31,14 +31,12 @@ const { test } = require('../../pluginFixtures.js');
test.describe.skip('pluginFixtures tests', () => { test.describe.skip('pluginFixtures tests', () => {
// test.use({ domainObjectName: 'Timer' }); // test.use({ domainObjectName: 'Timer' });
// let timerUUID; // let timerUUID;
// test('Creates a timer object @framework @unstable', ({ domainObject }) => { // test('Creates a timer object @framework @unstable', ({ domainObject }) => {
// const { uuid } = domainObject; // const { uuid } = domainObject;
// const uuidRegexp = /[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/; // const uuidRegexp = /[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/;
// expect(uuid).toMatch(uuidRegexp); // expect(uuid).toMatch(uuidRegexp);
// timerUUID = uuid; // timerUUID = uuid;
// }); // });
// test('Provides same uuid for subsequent uses of the same object @framework', ({ domainObject }) => { // test('Provides same uuid for subsequent uses of the same object @framework', ({ domainObject }) => {
// const { uuid } = domainObject; // const { uuid } = domainObject;
// expect(uuid).toEqual(timerUUID); // expect(uuid).toEqual(timerUUID);

View File

@ -21,8 +21,8 @@
*****************************************************************************/ *****************************************************************************/
/* /*
* This test suite template is to be used when verifying Test Data files found in /e2e/test-data/ * This test suite template is to be used when verifying Test Data files found in /e2e/test-data/
*/ */
const { test } = require('../../baseFixtures'); const { test } = require('../../baseFixtures');
@ -33,4 +33,3 @@ test.describe('recycled_local_storage @localStorage', () => {
await page.goto('./', { waitUntil: 'domcontentloaded' }); await page.goto('./', { waitUntil: 'domcontentloaded' });
}); });
}); });

View File

@ -41,7 +41,9 @@ test.describe('Branding tests', () => {
const versionInformationLocator = page.locator('ul.t-info.l-info.s-info').first(); const versionInformationLocator = page.locator('ul.t-info.l-info.s-info').first();
await expect(versionInformationLocator).toBeEnabled(); await expect(versionInformationLocator).toBeEnabled();
await expect.soft(versionInformationLocator).toContainText(/Version: \d/); await expect.soft(versionInformationLocator).toContainText(/Version: \d/);
await expect.soft(versionInformationLocator).toContainText(/Build Date: ((?:Mon|Tue|Wed|Thu|Fri|Sat|Sun))/); await expect
.soft(versionInformationLocator)
.toContainText(/Build Date: ((?:Mon|Tue|Wed|Thu|Fri|Sat|Sun))/);
await expect.soft(versionInformationLocator).toContainText(/Revision: \b[0-9a-f]{5,40}\b/); await expect.soft(versionInformationLocator).toContainText(/Revision: \b[0-9a-f]{5,40}\b/);
await expect.soft(versionInformationLocator).toContainText(/Branch: ./); await expect.soft(versionInformationLocator).toContainText(/Branch: ./);
}); });

View File

@ -21,17 +21,17 @@
*****************************************************************************/ *****************************************************************************/
/* /*
* This test suite is meant to be executed against a couchdb container. More doc to come * This test suite is meant to be executed against a couchdb container. More doc to come
* *
*/ */
const { test, expect } = require('../../pluginFixtures'); const { test, expect } = require('../../pluginFixtures');
test.describe("CouchDB Status Indicator with mocked responses @couchdb", () => { test.describe('CouchDB Status Indicator with mocked responses @couchdb', () => {
test.use({ failOnConsoleError: false }); test.use({ failOnConsoleError: false });
//TODO BeforeAll Verify CouchDB Connectivity with APIContext //TODO BeforeAll Verify CouchDB Connectivity with APIContext
test('Shows green if connected', async ({ page }) => { test('Shows green if connected', async ({ page }) => {
await page.route('**/openmct/mine', route => { await page.route('**/openmct/mine', (route) => {
route.fulfill({ route.fulfill({
status: 200, status: 200,
contentType: 'application/json', contentType: 'application/json',
@ -40,11 +40,13 @@ test.describe("CouchDB Status Indicator with mocked responses @couchdb", () => {
}); });
//Go to baseURL //Go to baseURL
await page.goto('./#/browse/mine?hideTree=true&hideInspector=true', { waitUntil: 'networkidle' }); await page.goto('./#/browse/mine?hideTree=true&hideInspector=true', {
waitUntil: 'networkidle'
});
await expect(page.locator('div:has-text("CouchDB is connected")').nth(3)).toBeVisible(); await expect(page.locator('div:has-text("CouchDB is connected")').nth(3)).toBeVisible();
}); });
test('Shows red if not connected', async ({ page }) => { test('Shows red if not connected', async ({ page }) => {
await page.route('**/openmct/**', route => { await page.route('**/openmct/**', (route) => {
route.fulfill({ route.fulfill({
status: 503, status: 503,
contentType: 'application/json', contentType: 'application/json',
@ -53,11 +55,13 @@ test.describe("CouchDB Status Indicator with mocked responses @couchdb", () => {
}); });
//Go to baseURL //Go to baseURL
await page.goto('./#/browse/mine?hideTree=true&hideInspector=true', { waitUntil: 'networkidle' }); await page.goto('./#/browse/mine?hideTree=true&hideInspector=true', {
waitUntil: 'networkidle'
});
await expect(page.locator('div:has-text("CouchDB is offline")').nth(3)).toBeVisible(); await expect(page.locator('div:has-text("CouchDB is offline")').nth(3)).toBeVisible();
}); });
test('Shows unknown if it receives an unexpected response code', async ({ page }) => { test('Shows unknown if it receives an unexpected response code', async ({ page }) => {
await page.route('**/openmct/mine', route => { await page.route('**/openmct/mine', (route) => {
route.fulfill({ route.fulfill({
status: 418, status: 418,
contentType: 'application/json', contentType: 'application/json',
@ -66,12 +70,14 @@ test.describe("CouchDB Status Indicator with mocked responses @couchdb", () => {
}); });
//Go to baseURL //Go to baseURL
await page.goto('./#/browse/mine?hideTree=true&hideInspector=true', { waitUntil: 'networkidle' }); await page.goto('./#/browse/mine?hideTree=true&hideInspector=true', {
waitUntil: 'networkidle'
});
await expect(page.locator('div:has-text("CouchDB connectivity unknown")').nth(3)).toBeVisible(); await expect(page.locator('div:has-text("CouchDB connectivity unknown")').nth(3)).toBeVisible();
}); });
}); });
test.describe("CouchDB initialization with mocked responses @couchdb", () => { test.describe('CouchDB initialization with mocked responses @couchdb', () => {
test.use({ failOnConsoleError: false }); test.use({ failOnConsoleError: false });
test("'My Items' folder is created if it doesn't exist", async ({ page }) => { test("'My Items' folder is created if it doesn't exist", async ({ page }) => {
const mockedMissingObjectResponsefromCouchDB = { const mockedMissingObjectResponsefromCouchDB = {
@ -83,29 +89,30 @@ test.describe("CouchDB initialization with mocked responses @couchdb", () => {
// Override the first request to GET openmct/mine to return a 404. // Override the first request to GET openmct/mine to return a 404.
// This simulates the case of starting Open MCT with a fresh database // This simulates the case of starting Open MCT with a fresh database
// and no "My Items" folder created yet. // and no "My Items" folder created yet.
await page.route('**/mine', route => { await page.route(
'**/mine',
(route) => {
route.fulfill(mockedMissingObjectResponsefromCouchDB); route.fulfill(mockedMissingObjectResponsefromCouchDB);
}, { times: 1 }); },
{ times: 1 }
);
// Set up promise to verify that a PUT request to create "My Items" // Set up promise to verify that a PUT request to create "My Items"
// folder was made. // folder was made.
const putMineFolderRequest = page.waitForRequest(req => const putMineFolderRequest = page.waitForRequest(
req.url().endsWith('/mine') (req) => req.url().endsWith('/mine') && req.method() === 'PUT'
&& req.method() === 'PUT'); );
// Set up promise to verify that a GET request to retrieve "My Items" // Set up promise to verify that a GET request to retrieve "My Items"
// folder was made. // folder was made.
const getMineFolderRequest = page.waitForRequest(req => const getMineFolderRequest = page.waitForRequest(
req.url().endsWith('/mine') (req) => req.url().endsWith('/mine') && req.method() === 'GET'
&& req.method() === 'GET'); );
// Go to baseURL. // Go to baseURL.
await page.goto('./', { waitUntil: 'domcontentloaded' }); await page.goto('./', { waitUntil: 'domcontentloaded' });
// Wait for both requests to resolve. // Wait for both requests to resolve.
await Promise.all([ await Promise.all([putMineFolderRequest, getMineFolderRequest]);
putMineFolderRequest,
getMineFolderRequest
]);
}); });
}); });

View File

@ -47,7 +47,6 @@ test.describe('Example Event Generator CRUD Operations', () => {
}); });
test.describe('Example Event Generator Telemetry Event Verficiation', () => { test.describe('Example Event Generator Telemetry Event Verficiation', () => {
test.fixme('telemetry is coming in for test event', async ({ page }) => { test.fixme('telemetry is coming in for test event', async ({ page }) => {
// Go to object created in step one // Go to object created in step one
// Verify the telemetry table is filled with > 1 row // Verify the telemetry table is filled with > 1 row

View File

@ -27,7 +27,10 @@ This test suite is dedicated to tests which verify the basic operations surround
const { test, expect } = require('../../../../baseFixtures'); const { test, expect } = require('../../../../baseFixtures');
test.describe('Sine Wave Generator', () => { test.describe('Sine Wave Generator', () => {
test('Create new Sine Wave Generator Object and validate create Form Logic', async ({ page, browserName }) => { test('Create new Sine Wave Generator Object and validate create Form Logic', async ({
page,
browserName
}) => {
// eslint-disable-next-line playwright/no-skipped-test // eslint-disable-next-line playwright/no-skipped-test
test.skip(browserName === 'firefox', 'This test needs to be updated to work with firefox'); test.skip(browserName === 'firefox', 'This test needs to be updated to work with firefox');
@ -45,7 +48,9 @@ test.describe('Sine Wave Generator', () => {
await expect(page.locator('.c-form-row__state-indicator').first()).toHaveClass(/req/); await expect(page.locator('.c-form-row__state-indicator').first()).toHaveClass(/req/);
// Verify that the Notes row does not have a required indicator // Verify that the Notes row does not have a required indicator
await expect(page.locator('.c-form__section div:nth-child(3) .form-row .c-form-row__state-indicator')).not.toContain('.req'); await expect(
page.locator('.c-form__section div:nth-child(3) .form-row .c-form-row__state-indicator')
).not.toContain('.req');
await page.locator('textarea[type="text"]').fill('Optional Note Text'); await page.locator('textarea[type="text"]').fill('Optional Note Text');
// Period // Period
@ -67,20 +72,32 @@ test.describe('Sine Wave Generator', () => {
await expect(page.locator('div:nth-child(9) .c-form-row__state-indicator')).toHaveClass(/req/); await expect(page.locator('div:nth-child(9) .c-form-row__state-indicator')).toHaveClass(/req/);
// Verify that by removing value from required text field shows invalid indicator // Verify that by removing value from required text field shows invalid indicator
await page.locator('text=Properties Title Notes Period Amplitude Offset Data Rate (hz) Phase (radians) Ra >> input[type="text"]').fill(''); await page
.locator(
'text=Properties Title Notes Period Amplitude Offset Data Rate (hz) Phase (radians) Ra >> input[type="text"]'
)
.fill('');
await expect(page.locator('.c-form-row__state-indicator').first()).toHaveClass(/invalid/); await expect(page.locator('.c-form-row__state-indicator').first()).toHaveClass(/invalid/);
// Verify that by adding value to empty required text field changes invalid to valid indicator // Verify that by adding value to empty required text field changes invalid to valid indicator
await page.locator('text=Properties Title Notes Period Amplitude Offset Data Rate (hz) Phase (radians) Ra >> input[type="text"]').fill('New Sine Wave Generator'); await page
.locator(
'text=Properties Title Notes Period Amplitude Offset Data Rate (hz) Phase (radians) Ra >> input[type="text"]'
)
.fill('New Sine Wave Generator');
await expect(page.locator('.c-form-row__state-indicator').first()).toHaveClass(/valid/); await expect(page.locator('.c-form-row__state-indicator').first()).toHaveClass(/valid/);
// Verify that by removing value from required number field shows invalid indicator // Verify that by removing value from required number field shows invalid indicator
await page.locator('.field.control.l-input-sm input').first().fill(''); await page.locator('.field.control.l-input-sm input').first().fill('');
await expect(page.locator('div:nth-child(4) .c-form-row__state-indicator')).toHaveClass(/invalid/); await expect(page.locator('div:nth-child(4) .c-form-row__state-indicator')).toHaveClass(
/invalid/
);
// Verify that by adding value to empty required number field changes invalid to valid indicator // Verify that by adding value to empty required number field changes invalid to valid indicator
await page.locator('.field.control.l-input-sm input').first().fill('3'); await page.locator('.field.control.l-input-sm input').first().fill('3');
await expect(page.locator('div:nth-child(4) .c-form-row__state-indicator')).toHaveClass(/valid/); await expect(page.locator('div:nth-child(4) .c-form-row__state-indicator')).toHaveClass(
/valid/
);
// Verify that can change value of number field by up/down arrows keys // Verify that can change value of number field by up/down arrows keys
// Click .field.control.l-input-sm input >> nth=0 // Click .field.control.l-input-sm input >> nth=0
@ -94,17 +111,19 @@ test.describe('Sine Wave Generator', () => {
await expect(value).toBe('6'); await expect(value).toBe('6');
//Click text=OK //Click text=OK
await Promise.all([ await Promise.all([page.waitForNavigation(), page.click('button:has-text("OK")')]);
page.waitForNavigation(),
page.click('button:has-text("OK")')
]);
// Verify that the Sine Wave Generator is displayed and correct // Verify that the Sine Wave Generator is displayed and correct
// Verify object properties // Verify object properties
await expect(page.locator('.l-browse-bar__object-name')).toContainText('New Sine Wave Generator'); await expect(page.locator('.l-browse-bar__object-name')).toContainText(
'New Sine Wave Generator'
);
// Verify canvas rendered and can be interacted with // Verify canvas rendered and can be interacted with
await page.locator('canvas').nth(1).click({ await page
.locator('canvas')
.nth(1)
.click({
position: { position: {
x: 341, x: 341,
y: 28 y: 28
@ -113,7 +132,8 @@ test.describe('Sine Wave Generator', () => {
// Verify that where we click on canvas shows the number we clicked on // Verify that where we click on canvas shows the number we clicked on
// Note that any number will do, we just care that a number exists // Note that any number will do, we just care that a number exists
await expect(page.locator('.value-to-display-nearestValue')).toContainText(/[+-]?([0-9]*[.])?[0-9]+/); await expect(page.locator('.value-to-display-nearestValue')).toContainText(
/[+-]?([0-9]*[.])?[0-9]+/
);
}); });
}); });

View File

@ -34,7 +34,9 @@ const jsonFilePath = 'e2e/test-data/ExampleLayouts.json';
const imageFilePath = 'e2e/test-data/rick.jpg'; const imageFilePath = 'e2e/test-data/rick.jpg';
test.describe('Form Validation Behavior', () => { test.describe('Form Validation Behavior', () => {
test('Required Field indicators appear if title is empty and can be corrected', async ({ page }) => { test('Required Field indicators appear if title is empty and can be corrected', async ({
page
}) => {
//Go to baseURL //Go to baseURL
await page.goto('./', { waitUntil: 'domcontentloaded' }); await page.goto('./', { waitUntil: 'domcontentloaded' });
@ -60,10 +62,7 @@ test.describe('Form Validation Behavior', () => {
await expect(page.locator('.c-form-row__state-indicator').first()).not.toHaveClass(/invalid/); await expect(page.locator('.c-form-row__state-indicator').first()).not.toHaveClass(/invalid/);
//Finish Creating Domain Object //Finish Creating Domain Object
await Promise.all([ await Promise.all([page.waitForNavigation(), page.click('button:has-text("OK")')]);
page.waitForNavigation(),
page.click('button:has-text("OK")')
]);
//Verify that the Domain Object has been created with the corrected title property //Verify that the Domain Object has been created with the corrected title property
await expect(page.locator('.l-browse-bar__object-name')).toContainText(TEST_FOLDER); await expect(page.locator('.l-browse-bar__object-name')).toContainText(TEST_FOLDER);
@ -72,7 +71,9 @@ test.describe('Form Validation Behavior', () => {
test.describe('Form File Input Behavior', () => { test.describe('Form File Input Behavior', () => {
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
await page.addInitScript({ path: path.join(__dirname, '../../helper', 'addInitFileInputObject.js') }); await page.addInitScript({
path: path.join(__dirname, '../../helper', 'addInitFileInputObject.js')
});
}); });
test('Can select a JSON file type', async ({ page }) => { test('Can select a JSON file type', async ({ page }) => {
@ -107,7 +108,9 @@ test.describe('Form File Input Behavior', () => {
test.describe('Persistence operations @addInit', () => { test.describe('Persistence operations @addInit', () => {
// add non persistable root item // add non persistable root item
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
await page.addInitScript({ path: path.join(__dirname, '../../helper', 'addNoneditableObject.js') }); await page.addInitScript({
path: path.join(__dirname, '../../helper', 'addNoneditableObject.js')
});
}); });
test('Persistability should be respected in the create form location field', async ({ page }) => { test('Persistability should be respected in the create form location field', async ({ page }) => {
@ -130,7 +133,9 @@ test.describe('Persistence operations @addInit', () => {
test.describe('Persistence operations @couchdb', () => { test.describe('Persistence operations @couchdb', () => {
test.use({ failOnConsoleError: false }); test.use({ failOnConsoleError: false });
test('Editing object properties should generate a single persistence operation', async ({ page }) => { test('Editing object properties should generate a single persistence operation', async ({
page
}) => {
test.info().annotations.push({ test.info().annotations.push({
type: 'issue', type: 'issue',
description: 'https://github.com/nasa/openmct/issues/5616' description: 'https://github.com/nasa/openmct/issues/5616'
@ -145,7 +150,7 @@ test.describe('Persistence operations @couchdb', () => {
// Count all persistence operations (PUT requests) for this specific object // Count all persistence operations (PUT requests) for this specific object
let putRequestCount = 0; let putRequestCount = 0;
page.on('request', req => { page.on('request', (req) => {
if (req.method() === 'PUT' && req.url().endsWith(clock.uuid)) { if (req.method() === 'PUT' && req.url().endsWith(clock.uuid)) {
putRequestCount += 1; putRequestCount += 1;
} }
@ -156,15 +161,22 @@ test.describe('Persistence operations @couchdb', () => {
await page.click('li[title="Edit properties of this object."]'); await page.click('li[title="Edit properties of this object."]');
// Modify the display format from default 12hr -> 24hr and click 'Save' // Modify the display format from default 12hr -> 24hr and click 'Save'
await page.locator('select[aria-label="12 or 24 hour clock"]').selectOption({ value: 'clock24' }); await page
.locator('select[aria-label="12 or 24 hour clock"]')
.selectOption({ value: 'clock24' });
await page.click('button[aria-label="Save"]'); await page.click('button[aria-label="Save"]');
await expect.poll(() => putRequestCount, { await expect
.poll(() => putRequestCount, {
message: 'Verify a single PUT request was made to persist the object', message: 'Verify a single PUT request was made to persist the object',
timeout: 1000 timeout: 1000
}).toEqual(1); })
.toEqual(1);
}); });
test('Can create an object after a conflict error @couchdb @2p', async ({ page, openmctConfig }) => { test('Can create an object after a conflict error @couchdb @2p', async ({
page,
openmctConfig
}) => {
test.info().annotations.push({ test.info().annotations.push({
type: 'issue', type: 'issue',
description: 'https://github.com/nasa/openmct/issues/5982' description: 'https://github.com/nasa/openmct/issues/5982'
@ -201,9 +213,9 @@ test.describe('Persistence operations @couchdb', () => {
// Both pages: Fill in the 'Name' form field. // Both pages: Fill in the 'Name' form field.
await Promise.all([ await Promise.all([
nameInput.fill(""), nameInput.fill(''),
nameInput.fill(`Clock:${genUuid()}`), nameInput.fill(`Clock:${genUuid()}`),
nameInput2.fill(""), nameInput2.fill(''),
nameInput2.fill(`Clock:${genUuid()}`) nameInput2.fill(`Clock:${genUuid()}`)
]); ]);
@ -212,10 +224,7 @@ test.describe('Persistence operations @couchdb', () => {
const testNotes = page.testNotes; const testNotes = page.testNotes;
const notesInput = page.locator('form[name="mctForm"] #notes-textarea'); const notesInput = page.locator('form[name="mctForm"] #notes-textarea');
const notesInput2 = page2.locator('form[name="mctForm"] #notes-textarea'); const notesInput2 = page2.locator('form[name="mctForm"] #notes-textarea');
await Promise.all([ await Promise.all([notesInput.fill(testNotes), notesInput2.fill(testNotes)]);
notesInput.fill(testNotes),
notesInput2.fill(testNotes)
]);
// Page 2: Click "OK" to create the domain object and wait for navigation. // Page 2: Click "OK" to create the domain object and wait for navigation.
// This will update the composition of the parent folder, setting the // This will update the composition of the parent folder, setting the
@ -241,9 +250,11 @@ test.describe('Persistence operations @couchdb', () => {
]); ]);
// Page 1: Verify that the conflict has occurred and an error notification is displayed. // Page 1: Verify that the conflict has occurred and an error notification is displayed.
await expect(page.locator('.c-message-banner__message', { await expect(
hasText: "Conflict detected while saving mine" page.locator('.c-message-banner__message', {
})).toBeVisible(); hasText: 'Conflict detected while saving mine'
})
).toBeVisible();
// Page 1: Start logging console errors from this point on // Page 1: Start logging console errors from this point on
let errors = []; let errors = [];
@ -259,14 +270,19 @@ test.describe('Persistence operations @couchdb', () => {
}); });
// Page 1: Wait for save progress dialog to appear/disappear // Page 1: Wait for save progress dialog to appear/disappear
await page.locator('.c-message-banner__message', { await page
hasText: 'Do not navigate away from this page or close this browser tab while this message is displayed.', .locator('.c-message-banner__message', {
hasText:
'Do not navigate away from this page or close this browser tab while this message is displayed.',
state: 'visible' state: 'visible'
}).waitFor({ state: 'hidden' }); })
.waitFor({ state: 'hidden' });
// Page 1: Navigate to 'My Items' and verify that the second clock was created // Page 1: Navigate to 'My Items' and verify that the second clock was created
await page.goto('./#/browse/mine'); await page.goto('./#/browse/mine');
await expect(page.locator(`.c-grid-item__name[title="${clockAfterConflict.name}"]`)).toBeVisible(); await expect(
page.locator(`.c-grid-item__name[title="${clockAfterConflict.name}"]`)
).toBeVisible();
// Verify no console errors occurred // Verify no console errors occurred
expect(errors).toHaveLength(0); expect(errors).toHaveLength(0);
@ -274,9 +290,9 @@ test.describe('Persistence operations @couchdb', () => {
}); });
test.describe('Form Correctness by Object Type', () => { test.describe('Form Correctness by Object Type', () => {
test.fixme('Verify correct behavior of number object (SWG)', async ({page}) => {}); test.fixme('Verify correct behavior of number object (SWG)', async ({ page }) => {});
test.fixme('Verify correct behavior of number object Timer', async ({page}) => {}); test.fixme('Verify correct behavior of number object Timer', async ({ page }) => {});
test.fixme('Verify correct behavior of number object Plan View', async ({page}) => {}); test.fixme('Verify correct behavior of number object Plan View', async ({ page }) => {});
test.fixme('Verify correct behavior of number object Clock', async ({page}) => {}); test.fixme('Verify correct behavior of number object Clock', async ({ page }) => {});
test.fixme('Verify correct behavior of number object Hyperlink', async ({page}) => {}); test.fixme('Verify correct behavior of number object Hyperlink', async ({ page }) => {});
}); });

View File

@ -31,7 +31,9 @@ const path = require('path');
test.describe('Persistence operations @addInit', () => { test.describe('Persistence operations @addInit', () => {
// add non persistable root item // add non persistable root item
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
await page.addInitScript({ path: path.join(__dirname, '../../helper', 'addNoneditableObject.js') }); await page.addInitScript({
path: path.join(__dirname, '../../helper', 'addNoneditableObject.js')
});
}); });
test('Non-persistable objects should not show persistence related actions', async ({ page }) => { test('Non-persistable objects should not show persistence related actions', async ({ page }) => {
@ -44,6 +46,14 @@ test.describe('Persistence operations @addInit', () => {
const menuOptions = page.locator('.c-menu li'); const menuOptions = page.locator('.c-menu li');
await expect.soft(menuOptions).toContainText(['Open In New Tab', 'View', 'Create Link']); await expect.soft(menuOptions).toContainText(['Open In New Tab', 'View', 'Create Link']);
await expect(menuOptions).not.toContainText(['Move', 'Duplicate', 'Remove', 'Add New Folder', 'Edit Properties...', 'Export as JSON', 'Import from JSON']); await expect(menuOptions).not.toContainText([
'Move',
'Duplicate',
'Remove',
'Add New Folder',
'Edit Properties...',
'Export as JSON',
'Import from JSON'
]);
}); });
}); });

View File

@ -28,7 +28,10 @@ const { test, expect } = require('../../pluginFixtures');
const { createDomainObjectWithDefaults } = require('../../appActions'); const { createDomainObjectWithDefaults } = require('../../appActions');
test.describe('Move & link item tests', () => { test.describe('Move & link item tests', () => {
test('Create a basic object and verify that it can be moved to another folder', async ({ page, openmctConfig }) => { test('Create a basic object and verify that it can be moved to another folder', async ({
page,
openmctConfig
}) => {
const { myItemsFolderName } = openmctConfig; const { myItemsFolderName } = openmctConfig;
// Go to Open MCT // Go to Open MCT
@ -55,18 +58,22 @@ test.describe('Move & link item tests', () => {
const treePane = page.getByRole('tree', { const treePane = page.getByRole('tree', {
name: 'Main Tree' name: 'Main Tree'
}); });
await treePane.getByRole('treeitem', { await treePane
.getByRole('treeitem', {
name: 'Parent Folder' name: 'Parent Folder'
}).click({ })
.click({
button: 'right' button: 'right'
}); });
await page.getByRole('menuitem', { await page
.getByRole('menuitem', {
name: /Move/ name: /Move/
}).click(); })
.click();
const createModalTree = page.getByRole('tree', { const createModalTree = page.getByRole('tree', {
name: "Create Modal Tree" name: 'Create Modal Tree'
}); });
const myItemsLocatorTreeItem = createModalTree.getByRole('treeitem', { const myItemsLocatorTreeItem = createModalTree.getByRole('treeitem', {
name: myItemsFolderName name: myItemsFolderName
@ -100,14 +107,18 @@ test.describe('Move & link item tests', () => {
await page.locator('[aria-label="Cancel"]').click(); await page.locator('[aria-label="Cancel"]').click();
// Move Child Folder from Parent Folder to My Items // Move Child Folder from Parent Folder to My Items
await treePane.getByRole('treeitem', { await treePane
.getByRole('treeitem', {
name: new RegExp(childFolder.name) name: new RegExp(childFolder.name)
}).click({ })
.click({
button: 'right' button: 'right'
}); });
await page.getByRole('menuitem', { await page
.getByRole('menuitem', {
name: /Move/ name: /Move/
}).click(); })
.click();
await myItemsLocatorTreeItem.click(); await myItemsLocatorTreeItem.click();
await page.locator('[aria-label="Save"]').click(); await page.locator('[aria-label="Save"]').click();
@ -118,7 +129,10 @@ test.describe('Move & link item tests', () => {
// Expect that Child Folder is in My Items, the root folder // Expect that Child Folder is in My Items, the root folder
expect(myItemsPaneTreeItem.locator('nth=0:has(text=Child Folder)')).toBeTruthy(); expect(myItemsPaneTreeItem.locator('nth=0:has(text=Child Folder)')).toBeTruthy();
}); });
test('Create a basic object and verify that it cannot be moved to telemetry object without Composition Provider', async ({ page, openmctConfig }) => { test('Create a basic object and verify that it cannot be moved to telemetry object without Composition Provider', async ({
page,
openmctConfig
}) => {
const { myItemsFolderName } = openmctConfig; const { myItemsFolderName } = openmctConfig;
// Go to Open MCT // Go to Open MCT
@ -158,11 +172,10 @@ test.describe('Move & link item tests', () => {
await page.locator(`text=Open MCT ${myItemsFolderName} >> span`).nth(3).click(); await page.locator(`text=Open MCT ${myItemsFolderName} >> span`).nth(3).click();
// Select Folder Object and select Move from context menu // Select Folder Object and select Move from context menu
await Promise.all([ await Promise.all([page.waitForNavigation(), page.locator(`a:has-text("${folder}")`).click()]);
page.waitForNavigation(), await page
page.locator(`a:has-text("${folder}")`).click() .locator('.c-tree__item.is-navigated-object .c-tree__item__label .c-tree__item__type-icon')
]); .click({
await page.locator('.c-tree__item.is-navigated-object .c-tree__item__label .c-tree__item__type-icon').click({
button: 'right' button: 'right'
}); });
await page.locator('li.icon-move').click(); await page.locator('li.icon-move').click();
@ -175,7 +188,10 @@ test.describe('Move & link item tests', () => {
expect(okButtonStateDisabled2).toBeTruthy(); expect(okButtonStateDisabled2).toBeTruthy();
}); });
test('Create a basic object and verify that it can be linked to another folder', async ({ page, openmctConfig }) => { test('Create a basic object and verify that it can be linked to another folder', async ({
page,
openmctConfig
}) => {
const { myItemsFolderName } = openmctConfig; const { myItemsFolderName } = openmctConfig;
// Go to Open MCT // Go to Open MCT
@ -202,18 +218,22 @@ test.describe('Move & link item tests', () => {
const treePane = page.getByRole('tree', { const treePane = page.getByRole('tree', {
name: 'Main Tree' name: 'Main Tree'
}); });
await treePane.getByRole('treeitem', { await treePane
.getByRole('treeitem', {
name: 'Parent Folder' name: 'Parent Folder'
}).click({ })
.click({
button: 'right' button: 'right'
}); });
await page.getByRole('menuitem', { await page
.getByRole('menuitem', {
name: /Move/ name: /Move/
}).click(); })
.click();
const createModalTree = page.getByRole('tree', { const createModalTree = page.getByRole('tree', {
name: "Create Modal Tree" name: 'Create Modal Tree'
}); });
const myItemsLocatorTreeItem = createModalTree.getByRole('treeitem', { const myItemsLocatorTreeItem = createModalTree.getByRole('treeitem', {
name: myItemsFolderName name: myItemsFolderName
@ -247,14 +267,18 @@ test.describe('Move & link item tests', () => {
await page.locator('[aria-label="Cancel"]').click(); await page.locator('[aria-label="Cancel"]').click();
// Move Child Folder from Parent Folder to My Items // Move Child Folder from Parent Folder to My Items
await treePane.getByRole('treeitem', { await treePane
.getByRole('treeitem', {
name: new RegExp(childFolder.name) name: new RegExp(childFolder.name)
}).click({ })
.click({
button: 'right' button: 'right'
}); });
await page.getByRole('menuitem', { await page
.getByRole('menuitem', {
name: /Link/ name: /Link/
}).click(); })
.click();
await myItemsLocatorTreeItem.click(); await myItemsLocatorTreeItem.click();
await page.locator('[aria-label="Save"]').click(); await page.locator('[aria-label="Save"]').click();
@ -267,10 +291,13 @@ test.describe('Move & link item tests', () => {
}); });
}); });
test.fixme('Cannot move a previously created domain object to non-peristable object in Move Modal', async ({ page }) => { test.fixme(
'Cannot move a previously created domain object to non-peristable object in Move Modal',
async ({ page }) => {
//Create a domain object //Create a domain object
//Save Domain object //Save Domain object
//Move Object and verify that cannot select non-persistable object //Move Object and verify that cannot select non-persistable object
//Move Object to My Items //Move Object to My Items
//Verify successful move //Verify successful move
}); }
);

View File

@ -59,10 +59,14 @@ test.describe('Notifications List', () => {
await page.click('button[aria-label="Dismiss notification of Error message"]'); await page.click('button[aria-label="Dismiss notification of Error message"]');
// Verify there is no a notification (listitem) with the text "Error message" since it was dismissed // Verify there is no a notification (listitem) with the text "Error message" since it was dismissed
expect(await page.locator('div[role="dialog"] div[role="listitem"]').innerText()).not.toContain('Error message'); expect(await page.locator('div[role="dialog"] div[role="listitem"]').innerText()).not.toContain(
'Error message'
);
// Verify there is still a notification (listitem) with the text "Alert message" // Verify there is still a notification (listitem) with the text "Alert message"
expect(await page.locator('div[role="dialog"] div[role="listitem"]').innerText()).toContain('Alert message'); expect(await page.locator('div[role="dialog"] div[role="listitem"]').innerText()).toContain(
'Alert message'
);
// Click on button with aria-label="Dismiss notification of Alert message" // Click on button with aria-label="Dismiss notification of Alert message"
await page.click('button[aria-label="Dismiss notification of Alert message"]'); await page.click('button[aria-label="Dismiss notification of Alert message"]');
@ -73,7 +77,9 @@ test.describe('Notifications List', () => {
}); });
test.describe('Notification Overlay', () => { test.describe('Notification Overlay', () => {
test('Closing notification list after notification banner disappeared does not cause it to open automatically', async ({ page }) => { test('Closing notification list after notification banner disappeared does not cause it to open automatically', async ({
page
}) => {
test.info().annotations.push({ test.info().annotations.push({
type: 'issue', type: 'issue',
description: 'https://github.com/nasa/openmct/issues/6130' description: 'https://github.com/nasa/openmct/issues/6130'
@ -92,7 +98,7 @@ test.describe('Notification Overlay', () => {
expect(await page.locator('div[role="dialog"]').isVisible()).toBe(true); expect(await page.locator('div[role="dialog"]').isVisible()).toBe(true);
// Wait until there is no Notification Banner // Wait until there is no Notification Banner
await page.waitForSelector('div[role="alert"]', { state: 'detached'}); await page.waitForSelector('div[role="alert"]', { state: 'detached' });
// Click on the "Close" button of the Notification List // Click on the "Close" button of the Notification List
await page.click('button[aria-label="Close"]'); await page.click('button[aria-label="Close"]');

View File

@ -20,13 +20,20 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
const { test, expect } = require('../../../pluginFixtures'); const { test, expect } = require('../../../pluginFixtures');
const { createPlanFromJSON, createDomainObjectWithDefaults, selectInspectorTab } = require('../../../appActions'); const {
createPlanFromJSON,
createDomainObjectWithDefaults,
selectInspectorTab
} = require('../../../appActions');
const testPlan1 = require('../../../test-data/examplePlans/ExamplePlan_Small1.json'); const testPlan1 = require('../../../test-data/examplePlans/ExamplePlan_Small1.json');
const testPlan2 = require('../../../test-data/examplePlans/ExamplePlan_Small2.json'); const testPlan2 = require('../../../test-data/examplePlans/ExamplePlan_Small2.json');
const { assertPlanActivities, setBoundsToSpanAllActivities } = require('../../../helper/planningUtils'); const {
assertPlanActivities,
setBoundsToSpanAllActivities
} = require('../../../helper/planningUtils');
const { getPreciseDuration } = require('../../../../src/utils/duration'); const { getPreciseDuration } = require('../../../../src/utils/duration');
test.describe("Gantt Chart", () => { test.describe('Gantt Chart', () => {
let ganttChart; let ganttChart;
let plan; let plan;
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
@ -40,24 +47,28 @@ test.describe("Gantt Chart", () => {
}); });
}); });
test("Displays all plan events", async ({ page }) => { test('Displays all plan events', async ({ page }) => {
await page.goto(ganttChart.url); await page.goto(ganttChart.url);
await assertPlanActivities(page, testPlan1, ganttChart.url); await assertPlanActivities(page, testPlan1, ganttChart.url);
}); });
test("Replaces a plan with a new plan", async ({ page }) => { test('Replaces a plan with a new plan', async ({ page }) => {
await assertPlanActivities(page, testPlan1, ganttChart.url); await assertPlanActivities(page, testPlan1, ganttChart.url);
await createPlanFromJSON(page, { await createPlanFromJSON(page, {
json: testPlan2, json: testPlan2,
parent: ganttChart.uuid parent: ganttChart.uuid
}); });
const replaceModal = page.getByRole('dialog').filter({ hasText: "This action will replace the current Plan. Do you want to continue?" }); const replaceModal = page
.getByRole('dialog')
.filter({ hasText: 'This action will replace the current Plan. Do you want to continue?' });
await expect(replaceModal).toBeVisible(); await expect(replaceModal).toBeVisible();
await page.getByRole('button', { name: 'OK' }).click(); await page.getByRole('button', { name: 'OK' }).click();
await assertPlanActivities(page, testPlan2, ganttChart.url); await assertPlanActivities(page, testPlan2, ganttChart.url);
}); });
test("Can select a single activity and display its details in the inspector", async ({ page }) => { test('Can select a single activity and display its details in the inspector', async ({
page
}) => {
test.slow(); test.slow();
await page.goto(ganttChart.url); await page.goto(ganttChart.url);
@ -65,12 +76,23 @@ test.describe("Gantt Chart", () => {
const activities = Object.values(testPlan1).flat(); const activities = Object.values(testPlan1).flat();
const activity = activities[0]; const activity = activities[0];
await page.locator('g').filter({ hasText: new RegExp(activity.name) }).click(); await page
.locator('g')
.filter({ hasText: new RegExp(activity.name) })
.click();
await selectInspectorTab(page, 'Activity'); await selectInspectorTab(page, 'Activity');
const startDateTime = await page.locator('.c-inspect-properties__label:has-text("Start DateTime")+.c-inspect-properties__value').innerText(); const startDateTime = await page
const endDateTime = await page.locator('.c-inspect-properties__label:has-text("End DateTime")+.c-inspect-properties__value').innerText(); .locator(
const duration = await page.locator('.c-inspect-properties__label:has-text("duration")+.c-inspect-properties__value').innerText(); '.c-inspect-properties__label:has-text("Start DateTime")+.c-inspect-properties__value'
)
.innerText();
const endDateTime = await page
.locator('.c-inspect-properties__label:has-text("End DateTime")+.c-inspect-properties__value')
.innerText();
const duration = await page
.locator('.c-inspect-properties__label:has-text("duration")+.c-inspect-properties__value')
.innerText();
const expectedStartDate = new Date(activity.start).toISOString(); const expectedStartDate = new Date(activity.start).toISOString();
const actualStartDate = new Date(startDateTime).toISOString(); const actualStartDate = new Date(startDateTime).toISOString();
@ -98,6 +120,8 @@ test.describe("Gantt Chart", () => {
await page.goto(ganttChart.url); await page.goto(ganttChart.url);
// Assert that the Plan's status is displayed as draft // Assert that the Plan's status is displayed as draft
expect(await page.locator('.u-contents.c-swimlane.is-status--draft').count()).toBe(Object.keys(testPlan1).length); expect(await page.locator('.u-contents.c-swimlane.is-status--draft').count()).toBe(
Object.keys(testPlan1).length
);
}); });
}); });

View File

@ -24,7 +24,7 @@ const { createPlanFromJSON } = require('../../../appActions');
const testPlan1 = require('../../../test-data/examplePlans/ExamplePlan_Small1.json'); const testPlan1 = require('../../../test-data/examplePlans/ExamplePlan_Small1.json');
const { assertPlanActivities } = require('../../../helper/planningUtils'); const { assertPlanActivities } = require('../../../helper/planningUtils');
test.describe("Plan", () => { test.describe('Plan', () => {
let plan; let plan;
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
await page.goto('./', { waitUntil: 'domcontentloaded' }); await page.goto('./', { waitUntil: 'domcontentloaded' });
@ -33,7 +33,7 @@ test.describe("Plan", () => {
}); });
}); });
test("Displays all plan events", async ({ page }) => { test('Displays all plan events', async ({ page }) => {
await assertPlanActivities(page, testPlan1, plan.url); await assertPlanActivities(page, testPlan1, plan.url);
}); });
}); });

View File

@ -24,65 +24,69 @@ const { test, expect } = require('../../../pluginFixtures');
const { createDomainObjectWithDefaults, createPlanFromJSON } = require('../../../appActions'); const { createDomainObjectWithDefaults, createPlanFromJSON } = require('../../../appActions');
const testPlan = { const testPlan = {
"TEST_GROUP": [ TEST_GROUP: [
{ {
"name": "Past event 1", name: 'Past event 1',
"start": 1660320408000, start: 1660320408000,
"end": 1660343797000, end: 1660343797000,
"type": "TEST-GROUP", type: 'TEST-GROUP',
"color": "orange", color: 'orange',
"textColor": "white" textColor: 'white'
}, },
{ {
"name": "Past event 2", name: 'Past event 2',
"start": 1660406808000, start: 1660406808000,
"end": 1660429160000, end: 1660429160000,
"type": "TEST-GROUP", type: 'TEST-GROUP',
"color": "orange", color: 'orange',
"textColor": "white" textColor: 'white'
}, },
{ {
"name": "Past event 3", name: 'Past event 3',
"start": 1660493208000, start: 1660493208000,
"end": 1660503981000, end: 1660503981000,
"type": "TEST-GROUP", type: 'TEST-GROUP',
"color": "orange", color: 'orange',
"textColor": "white" textColor: 'white'
}, },
{ {
"name": "Past event 4", name: 'Past event 4',
"start": 1660579608000, start: 1660579608000,
"end": 1660624108000, end: 1660624108000,
"type": "TEST-GROUP", type: 'TEST-GROUP',
"color": "orange", color: 'orange',
"textColor": "white" textColor: 'white'
}, },
{ {
"name": "Past event 5", name: 'Past event 5',
"start": 1660666008000, start: 1660666008000,
"end": 1660681529000, end: 1660681529000,
"type": "TEST-GROUP", type: 'TEST-GROUP',
"color": "orange", color: 'orange',
"textColor": "white" textColor: 'white'
} }
] ]
}; };
test.describe("Time Strip", () => { test.describe('Time Strip', () => {
test("Create two Time Strips, add a single Plan to both, and verify they can have separate Indepdenent Time Contexts @unstable", async ({ page }) => { test('Create two Time Strips, add a single Plan to both, and verify they can have separate Indepdenent Time Contexts @unstable', async ({
page
}) => {
test.info().annotations.push({ test.info().annotations.push({
type: 'issue', type: 'issue',
description: 'https://github.com/nasa/openmct/issues/5627' description: 'https://github.com/nasa/openmct/issues/5627'
}); });
// Constant locators // Constant locators
const independentTimeConductorInputs = page.locator('.l-shell__main-independent-time-conductor .c-input--datetime'); const independentTimeConductorInputs = page.locator(
'.l-shell__main-independent-time-conductor .c-input--datetime'
);
const activityBounds = page.locator('.activity-bounds'); const activityBounds = page.locator('.activity-bounds');
// Goto baseURL // Goto baseURL
await page.goto('./', { waitUntil: 'domcontentloaded' }); await page.goto('./', { waitUntil: 'domcontentloaded' });
const timestrip = await test.step("Create a Time Strip", async () => { const timestrip = await test.step('Create a Time Strip', async () => {
const createdTimeStrip = await createDomainObjectWithDefaults(page, { type: 'Time Strip' }); const createdTimeStrip = await createDomainObjectWithDefaults(page, { type: 'Time Strip' });
const objectName = await page.locator('.l-browse-bar__object-name').innerText(); const objectName = await page.locator('.l-browse-bar__object-name').innerText();
expect(objectName).toBe(createdTimeStrip.name); expect(objectName).toBe(createdTimeStrip.name);
@ -90,7 +94,7 @@ test.describe("Time Strip", () => {
return createdTimeStrip; return createdTimeStrip;
}); });
const plan = await test.step("Create a Plan and add it to the timestrip", async () => { const plan = await test.step('Create a Plan and add it to the timestrip', async () => {
const createdPlan = await createPlanFromJSON(page, { const createdPlan = await createPlanFromJSON(page, {
name: 'Test Plan', name: 'Test Plan',
json: testPlan json: testPlan
@ -106,7 +110,9 @@ test.describe("Time Strip", () => {
const endBound = testPlan.TEST_GROUP[testPlan.TEST_GROUP.length - 1].end; const endBound = testPlan.TEST_GROUP[testPlan.TEST_GROUP.length - 1].end;
// Switch to fixed time mode with all plan events within the bounds // Switch to fixed time mode with all plan events within the bounds
await page.goto(`${timestrip.url}?tc.mode=fixed&tc.startBound=${startBound}&tc.endBound=${endBound}&tc.timeSystem=utc&view=time-strip.view`); await page.goto(
`${timestrip.url}?tc.mode=fixed&tc.startBound=${startBound}&tc.endBound=${endBound}&tc.timeSystem=utc&view=time-strip.view`
);
// Verify all events are displayed // Verify all events are displayed
const eventCount = await page.locator('.activity-bounds').count(); const eventCount = await page.locator('.activity-bounds').count();
@ -115,7 +121,7 @@ test.describe("Time Strip", () => {
return createdPlan; return createdPlan;
}); });
await test.step("TimeStrip can use the Independent Time Conductor", async () => { await test.step('TimeStrip can use the Independent Time Conductor', async () => {
// Activate Independent Time Conductor in Fixed Time Mode // Activate Independent Time Conductor in Fixed Time Mode
await page.click('.c-toggle-switch__slider'); await page.click('.c-toggle-switch__slider');
expect(await activityBounds.count()).toEqual(0); expect(await activityBounds.count()).toEqual(0);
@ -135,11 +141,11 @@ test.describe("Time Strip", () => {
expect(await activityBounds.count()).toEqual(1); expect(await activityBounds.count()).toEqual(1);
}); });
await test.step("Can have multiple TimeStrips with the same plan linked and different Independent Time Contexts", async () => { await test.step('Can have multiple TimeStrips with the same plan linked and different Independent Time Contexts', async () => {
// Create another Time Strip and verify that it has been created // Create another Time Strip and verify that it has been created
const createdTimeStrip = await createDomainObjectWithDefaults(page, { const createdTimeStrip = await createDomainObjectWithDefaults(page, {
type: 'Time Strip', type: 'Time Strip',
name: "Another Time Strip" name: 'Another Time Strip'
}); });
const objectName = await page.locator('.l-browse-bar__object-name').innerText(); const objectName = await page.locator('.l-browse-bar__object-name').innerText();

View File

@ -27,8 +27,9 @@ This test suite is dedicated to tests which verify the basic operations surround
const { test, expect } = require('../../../../baseFixtures'); const { test, expect } = require('../../../../baseFixtures');
test.describe('Clock Generator CRUD Operations', () => { test.describe('Clock Generator CRUD Operations', () => {
test('Timezone dropdown will collapse when clicked outside or on dropdown icon again', async ({
test('Timezone dropdown will collapse when clicked outside or on dropdown icon again', async ({ page }) => { page
}) => {
test.info().annotations.push({ test.info().annotations.push({
type: 'issue', type: 'issue',
description: 'https://github.com/nasa/openmct/issues/4878' description: 'https://github.com/nasa/openmct/issues/4878'
@ -45,22 +46,21 @@ test.describe('Clock Generator CRUD Operations', () => {
// Click .icon-arrow-down // Click .icon-arrow-down
await page.locator('.icon-arrow-down').click(); await page.locator('.icon-arrow-down').click();
//verify if the autocomplete dropdown is visible //verify if the autocomplete dropdown is visible
await expect(page.locator(".c-input--autocomplete__options")).toBeVisible(); await expect(page.locator('.c-input--autocomplete__options')).toBeVisible();
// Click .icon-arrow-down // Click .icon-arrow-down
await page.locator('.icon-arrow-down').click(); await page.locator('.icon-arrow-down').click();
// Verify clicking on the autocomplete arrow collapses the dropdown // Verify clicking on the autocomplete arrow collapses the dropdown
await expect(page.locator(".c-input--autocomplete__options")).toBeHidden(); await expect(page.locator('.c-input--autocomplete__options')).toBeHidden();
// Click timezone input to open dropdown // Click timezone input to open dropdown
await page.locator('.c-input--autocomplete__input').click(); await page.locator('.c-input--autocomplete__input').click();
//verify if the autocomplete dropdown is visible //verify if the autocomplete dropdown is visible
await expect(page.locator(".c-input--autocomplete__options")).toBeVisible(); await expect(page.locator('.c-input--autocomplete__options')).toBeVisible();
// Verify clicking outside the autocomplete dropdown collapses it // Verify clicking outside the autocomplete dropdown collapses it
await page.locator('text=Timezone').click(); await page.locator('text=Timezone').click();
// Verify clicking on the autocomplete arrow collapses the dropdown // Verify clicking on the autocomplete arrow collapses the dropdown
await expect(page.locator(".c-input--autocomplete__options")).toBeHidden(); await expect(page.locator('.c-input--autocomplete__options')).toBeHidden();
}); });
}); });

View File

@ -33,7 +33,7 @@ let conditionSetUrl;
let getConditionSetIdentifierFromUrl; let getConditionSetIdentifierFromUrl;
test.describe.serial('Condition Set CRUD Operations on @localStorage', () => { test.describe.serial('Condition Set CRUD Operations on @localStorage', () => {
test.beforeAll(async ({ browser}) => { test.beforeAll(async ({ browser }) => {
//TODO: This needs to be refactored //TODO: This needs to be refactored
const context = await browser.newContext(); const context = await browser.newContext();
const page = await context.newPage(); const page = await context.newPage();
@ -42,10 +42,7 @@ test.describe.serial('Condition Set CRUD Operations on @localStorage', () => {
await page.locator('li[role="menuitem"]:has-text("Condition Set")').click(); await page.locator('li[role="menuitem"]:has-text("Condition Set")').click();
await Promise.all([ await Promise.all([page.waitForNavigation(), page.click('button:has-text("OK")')]);
page.waitForNavigation(),
page.click('button:has-text("OK")')
]);
//Save localStorage for future test execution //Save localStorage for future test execution
await context.storageState({ path: './e2e/test-data/recycled_local_storage.json' }); await context.storageState({ path: './e2e/test-data/recycled_local_storage.json' });
@ -62,27 +59,29 @@ test.describe.serial('Condition Set CRUD Operations on @localStorage', () => {
test.use({ storageState: './e2e/test-data/recycled_local_storage.json' }); test.use({ storageState: './e2e/test-data/recycled_local_storage.json' });
//Begin suite of tests again localStorage //Begin suite of tests again localStorage
test('Condition set object properties persist in main view and inspector @localStorage', async ({ page }) => { test('Condition set object properties persist in main view and inspector @localStorage', async ({
page
}) => {
//Navigate to baseURL with injected localStorage //Navigate to baseURL with injected localStorage
await page.goto(conditionSetUrl, { waitUntil: 'networkidle' }); await page.goto(conditionSetUrl, { waitUntil: 'networkidle' });
//Assertions on loaded Condition Set in main view. This is a stateful transition step after page.goto() //Assertions on loaded Condition Set in main view. This is a stateful transition step after page.goto()
await expect.soft(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Condition Set'); await expect
.soft(page.locator('.l-browse-bar__object-name'))
.toContainText('Unnamed Condition Set');
//Assertions on loaded Condition Set in Inspector //Assertions on loaded Condition Set in Inspector
expect.soft(page.locator('_vue=item.name=Unnamed Condition Set')).toBeTruthy(); expect.soft(page.locator('_vue=item.name=Unnamed Condition Set')).toBeTruthy();
//Reload Page //Reload Page
await Promise.all([ await Promise.all([page.reload(), page.waitForLoadState('networkidle')]);
page.reload(),
page.waitForLoadState('networkidle')
]);
//Re-verify after reload //Re-verify after reload
await expect.soft(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Condition Set'); await expect
.soft(page.locator('.l-browse-bar__object-name'))
.toContainText('Unnamed Condition Set');
//Assertions on loaded Condition Set in Inspector //Assertions on loaded Condition Set in Inspector
expect.soft(page.locator('_vue=item.name=Unnamed Condition Set')).toBeTruthy(); expect.soft(page.locator('_vue=item.name=Unnamed Condition Set')).toBeTruthy();
}); });
test('condition set object can be modified on @localStorage', async ({ page, openmctConfig }) => { test('condition set object can be modified on @localStorage', async ({ page, openmctConfig }) => {
const { myItemsFolderName } = openmctConfig; const { myItemsFolderName } = openmctConfig;
@ -90,22 +89,37 @@ test.describe.serial('Condition Set CRUD Operations on @localStorage', () => {
await page.goto(conditionSetUrl, { waitUntil: 'networkidle' }); await page.goto(conditionSetUrl, { waitUntil: 'networkidle' });
//Assertions on loaded Condition Set in main view. This is a stateful transition step after page.goto() //Assertions on loaded Condition Set in main view. This is a stateful transition step after page.goto()
await expect.soft(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Condition Set'); await expect
.soft(page.locator('.l-browse-bar__object-name'))
.toContainText('Unnamed Condition Set');
//Update the Condition Set properties //Update the Condition Set properties
// Click Edit Button // Click Edit Button
await page.locator('text=Conditions View Snapshot >> button').nth(3).click(); await page.locator('text=Conditions View Snapshot >> button').nth(3).click();
//Edit Condition Set Name from main view //Edit Condition Set Name from main view
await page.locator('.l-browse-bar__object-name').filter({ hasText: 'Unnamed Condition Set' }).first().fill('Renamed Condition Set'); await page
await page.locator('.l-browse-bar__object-name').filter({ hasText: 'Renamed Condition Set' }).first().press('Enter'); .locator('.l-browse-bar__object-name')
.filter({ hasText: 'Unnamed Condition Set' })
.first()
.fill('Renamed Condition Set');
await page
.locator('.l-browse-bar__object-name')
.filter({ hasText: 'Renamed Condition Set' })
.first()
.press('Enter');
// Click Save Button // Click Save Button
await page.locator('text=Snapshot Save and Finish Editing Save and Continue Editing >> button').nth(1).click(); await page
.locator('text=Snapshot Save and Finish Editing Save and Continue Editing >> button')
.nth(1)
.click();
// Click Save and Finish Editing Option // Click Save and Finish Editing Option
await page.locator('text=Save and Finish Editing').click(); await page.locator('text=Save and Finish Editing').click();
//Verify Main section reflects updated Name Property //Verify Main section reflects updated Name Property
await expect.soft(page.locator('.l-browse-bar__object-name')).toContainText('Renamed Condition Set'); await expect
.soft(page.locator('.l-browse-bar__object-name'))
.toContainText('Renamed Condition Set');
// Verify Inspector properties // Verify Inspector properties
// Verify Inspector has updated Name property // Verify Inspector has updated Name property
@ -123,13 +137,12 @@ test.describe.serial('Condition Set CRUD Operations on @localStorage', () => {
expect(page.locator('a:has-text("Renamed Condition Set")')).toBeTruthy(); expect(page.locator('a:has-text("Renamed Condition Set")')).toBeTruthy();
//Reload Page //Reload Page
await Promise.all([ await Promise.all([page.reload(), page.waitForLoadState('networkidle')]);
page.reload(),
page.waitForLoadState('networkidle')
]);
//Verify Main section reflects updated Name Property //Verify Main section reflects updated Name Property
await expect.soft(page.locator('.l-browse-bar__object-name')).toContainText('Renamed Condition Set'); await expect
.soft(page.locator('.l-browse-bar__object-name'))
.toContainText('Renamed Condition Set');
// Verify Inspector properties // Verify Inspector properties
// Verify Inspector has updated Name property // Verify Inspector has updated Name property
@ -146,19 +159,30 @@ test.describe.serial('Condition Set CRUD Operations on @localStorage', () => {
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Renamed'); await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Renamed');
expect(page.locator('a:has-text("Renamed Condition Set")')).toBeTruthy(); expect(page.locator('a:has-text("Renamed Condition Set")')).toBeTruthy();
}); });
test('condition set object can be deleted by Search Tree Actions menu on @localStorage', async ({ page }) => { test('condition set object can be deleted by Search Tree Actions menu on @localStorage', async ({
page
}) => {
//Navigate to baseURL //Navigate to baseURL
await page.goto('./', { waitUntil: 'domcontentloaded' }); await page.goto('./', { waitUntil: 'domcontentloaded' });
//Assertions on loaded Condition Set in main view. This is a stateful transition step after page.goto() //Assertions on loaded Condition Set in main view. This is a stateful transition step after page.goto()
await expect(page.locator('a:has-text("Unnamed Condition Set Condition Set") >> nth=0')).toBeVisible(); await expect(
page.locator('a:has-text("Unnamed Condition Set Condition Set") >> nth=0')
).toBeVisible();
const numberOfConditionSetsToStart = await page.locator('a:has-text("Unnamed Condition Set Condition Set")').count(); const numberOfConditionSetsToStart = await page
.locator('a:has-text("Unnamed Condition Set Condition Set")')
.count();
// Search for Unnamed Condition Set // Search for Unnamed Condition Set
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Unnamed Condition Set'); await page
.locator('[aria-label="OpenMCT Search"] input[type="search"]')
.fill('Unnamed Condition Set');
// Click Search Result // Click Search Result
await page.locator('[aria-label="OpenMCT Search"] >> text=Unnamed Condition Set').first().click(); await page
.locator('[aria-label="OpenMCT Search"] >> text=Unnamed Condition Set')
.first()
.click();
// Click hamburger button // Click hamburger button
await page.locator('[title="More options"]').click(); await page.locator('[title="More options"]').click();
@ -167,7 +191,9 @@ test.describe.serial('Condition Set CRUD Operations on @localStorage', () => {
await page.locator('button:has-text("OK")').click(); await page.locator('button:has-text("OK")').click();
//Expect Unnamed Condition Set to be removed in Main View //Expect Unnamed Condition Set to be removed in Main View
const numberOfConditionSetsAtEnd = await page.locator('a:has-text("Unnamed Condition Set Condition Set")').count(); const numberOfConditionSetsAtEnd = await page
.locator('a:has-text("Unnamed Condition Set Condition Set")')
.count();
expect(numberOfConditionSetsAtEnd).toEqual(numberOfConditionSetsToStart - 1); expect(numberOfConditionSetsAtEnd).toEqual(numberOfConditionSetsToStart - 1);
@ -175,7 +201,6 @@ test.describe.serial('Condition Set CRUD Operations on @localStorage', () => {
//Domain Object is still available by direct URL after delete //Domain Object is still available by direct URL after delete
await page.goto(conditionSetUrl, { waitUntil: 'networkidle' }); await page.goto(conditionSetUrl, { waitUntil: 'networkidle' });
await expect(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Condition Set'); await expect(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Condition Set');
}); });
}); });
@ -188,7 +213,7 @@ test.describe('Basic Condition Set Use', () => {
// Create a new condition set // Create a new condition set
await createDomainObjectWithDefaults(page, { await createDomainObjectWithDefaults(page, {
type: 'Condition Set', type: 'Condition Set',
name: "Test Condition Set" name: 'Test Condition Set'
}); });
// Change the object to edit mode // Change the object to edit mode
await page.locator('[title="Edit"]').click(); await page.locator('[title="Edit"]').click();
@ -207,15 +232,15 @@ test.describe('Basic Condition Set Use', () => {
await createDomainObjectWithDefaults(page, { await createDomainObjectWithDefaults(page, {
type: 'Sine Wave Generator', type: 'Sine Wave Generator',
name: "Alpha Sine Wave Generator" name: 'Alpha Sine Wave Generator'
}); });
await createDomainObjectWithDefaults(page, { await createDomainObjectWithDefaults(page, {
type: 'Sine Wave Generator', type: 'Sine Wave Generator',
name: "Beta Sine Wave Generator" name: 'Beta Sine Wave Generator'
}); });
const conditionSet1 = await createDomainObjectWithDefaults(page, { const conditionSet1 = await createDomainObjectWithDefaults(page, {
type: 'Condition Set', type: 'Condition Set',
name: "Test Condition Set" name: 'Test Condition Set'
}); });
// Change the object to edit mode // Change the object to edit mode
@ -228,8 +253,12 @@ test.describe('Basic Condition Set Use', () => {
const treePane = page.getByRole('tree', { const treePane = page.getByRole('tree', {
name: 'Main Tree' name: 'Main Tree'
}); });
const alphaGeneratorTreeItem = treePane.getByRole('treeitem', { name: "Alpha Sine Wave Generator"}); const alphaGeneratorTreeItem = treePane.getByRole('treeitem', {
const betaGeneratorTreeItem = treePane.getByRole('treeitem', { name: "Beta Sine Wave Generator"}); name: 'Alpha Sine Wave Generator'
});
const betaGeneratorTreeItem = treePane.getByRole('treeitem', {
name: 'Beta Sine Wave Generator'
});
const conditionCollection = page.locator('#conditionCollection'); const conditionCollection = page.locator('#conditionCollection');
await alphaGeneratorTreeItem.dragTo(conditionCollection); await alphaGeneratorTreeItem.dragTo(conditionCollection);
@ -256,7 +285,7 @@ test.describe('Basic Condition Set Use', () => {
await page.click(`li[role='menuitem']:text("Sine Wave Generator")`); await page.click(`li[role='menuitem']:text("Sine Wave Generator")`);
await page.getByRole('spinbutton', { name: 'Loading Delay (ms)' }).fill('8000'); await page.getByRole('spinbutton', { name: 'Loading Delay (ms)' }).fill('8000');
const nameInput = page.locator('form[name="mctForm"] .first input[type="text"]'); const nameInput = page.locator('form[name="mctForm"] .first input[type="text"]');
await nameInput.fill("Delayed Sine Wave Generator"); await nameInput.fill('Delayed Sine Wave Generator');
// Click OK button and wait for Navigate event // Click OK button and wait for Navigate event
await Promise.all([ await Promise.all([
@ -269,7 +298,7 @@ test.describe('Basic Condition Set Use', () => {
// Create a new condition set // Create a new condition set
await createDomainObjectWithDefaults(page, { await createDomainObjectWithDefaults(page, {
type: 'Condition Set', type: 'Condition Set',
name: "Test Blank Output of Condition Set" name: 'Test Blank Output of Condition Set'
}); });
// Change the object to edit mode // Change the object to edit mode
await page.locator('[title="Edit"]').click(); await page.locator('[title="Edit"]').click();
@ -286,34 +315,48 @@ test.describe('Basic Condition Set Use', () => {
const treePane = page.getByRole('tree', { const treePane = page.getByRole('tree', {
name: 'Main Tree' name: 'Main Tree'
}); });
const sineWaveGeneratorTreeItem = treePane.getByRole('treeitem', { name: "Delayed Sine Wave Generator"}); const sineWaveGeneratorTreeItem = treePane.getByRole('treeitem', {
name: 'Delayed Sine Wave Generator'
});
const conditionCollection = await page.locator('#conditionCollection'); const conditionCollection = await page.locator('#conditionCollection');
await sineWaveGeneratorTreeItem.dragTo(conditionCollection); await sineWaveGeneratorTreeItem.dragTo(conditionCollection);
const firstCriterionTelemetry = await page.locator('[aria-label="Criterion Telemetry Selection"] >> nth=0'); const firstCriterionTelemetry = await page.locator(
'[aria-label="Criterion Telemetry Selection"] >> nth=0'
);
firstCriterionTelemetry.selectOption({ label: 'Delayed Sine Wave Generator' }); firstCriterionTelemetry.selectOption({ label: 'Delayed Sine Wave Generator' });
const secondCriterionTelemetry = await page.locator('[aria-label="Criterion Telemetry Selection"] >> nth=1'); const secondCriterionTelemetry = await page.locator(
'[aria-label="Criterion Telemetry Selection"] >> nth=1'
);
secondCriterionTelemetry.selectOption({ label: 'Delayed Sine Wave Generator' }); secondCriterionTelemetry.selectOption({ label: 'Delayed Sine Wave Generator' });
const firstCriterionMetadata = await page.locator('[aria-label="Criterion Metadata Selection"] >> nth=0'); const firstCriterionMetadata = await page.locator(
'[aria-label="Criterion Metadata Selection"] >> nth=0'
);
firstCriterionMetadata.selectOption({ label: 'Sine' }); firstCriterionMetadata.selectOption({ label: 'Sine' });
const secondCriterionMetadata = await page.locator('[aria-label="Criterion Metadata Selection"] >> nth=1'); const secondCriterionMetadata = await page.locator(
'[aria-label="Criterion Metadata Selection"] >> nth=1'
);
secondCriterionMetadata.selectOption({ label: 'Sine' }); secondCriterionMetadata.selectOption({ label: 'Sine' });
const firstCriterionComparison = await page.locator('[aria-label="Criterion Comparison Selection"] >> nth=0'); const firstCriterionComparison = await page.locator(
'[aria-label="Criterion Comparison Selection"] >> nth=0'
);
firstCriterionComparison.selectOption({ label: 'is greater than or equal to' }); firstCriterionComparison.selectOption({ label: 'is greater than or equal to' });
const secondCriterionComparison = await page.locator('[aria-label="Criterion Comparison Selection"] >> nth=1'); const secondCriterionComparison = await page.locator(
'[aria-label="Criterion Comparison Selection"] >> nth=1'
);
secondCriterionComparison.selectOption({ label: 'is less than' }); secondCriterionComparison.selectOption({ label: 'is less than' });
const firstCriterionInput = await page.locator('[aria-label="Criterion Input"] >> nth=0'); const firstCriterionInput = await page.locator('[aria-label="Criterion Input"] >> nth=0');
await firstCriterionInput.fill("0"); await firstCriterionInput.fill('0');
const secondCriterionInput = await page.locator('[aria-label="Criterion Input"] >> nth=1'); const secondCriterionInput = await page.locator('[aria-label="Criterion Input"] >> nth=1');
await secondCriterionInput.fill("0"); await secondCriterionInput.fill('0');
const saveButtonLocator = page.locator('button[title="Save"]'); const saveButtonLocator = page.locator('button[title="Save"]');
await saveButtonLocator.click(); await saveButtonLocator.click();

View File

@ -21,7 +21,12 @@
*****************************************************************************/ *****************************************************************************/
const { test, expect } = require('../../../../pluginFixtures'); const { test, expect } = require('../../../../pluginFixtures');
const { createDomainObjectWithDefaults, setStartOffset, setFixedTimeMode, setRealTimeMode } = require('../../../../appActions'); const {
createDomainObjectWithDefaults,
setStartOffset,
setFixedTimeMode,
setRealTimeMode
} = require('../../../../appActions');
test.describe('Display Layout', () => { test.describe('Display Layout', () => {
/** @type {import('../../../../appActions').CreatedObjectInfo} */ /** @type {import('../../../../appActions').CreatedObjectInfo} */
@ -35,11 +40,13 @@ test.describe('Display Layout', () => {
type: 'Sine Wave Generator' type: 'Sine Wave Generator'
}); });
}); });
test('alpha-numeric widget telemetry value exactly matches latest telemetry value received in real time', async ({ page }) => { test('alpha-numeric widget telemetry value exactly matches latest telemetry value received in real time', async ({
page
}) => {
// Create a Display Layout // Create a Display Layout
await createDomainObjectWithDefaults(page, { await createDomainObjectWithDefaults(page, {
type: 'Display Layout', type: 'Display Layout',
name: "Test Display Layout" name: 'Test Display Layout'
}); });
// Edit Display Layout // Edit Display Layout
await page.locator('[title="Edit"]').click(); await page.locator('[title="Edit"]').click();
@ -63,17 +70,21 @@ test.describe('Display Layout', () => {
// from the Sine Wave Generator // from the Sine Wave Generator
const getTelemValuePromise = await subscribeToTelemetry(page, sineWaveObject.uuid); const getTelemValuePromise = await subscribeToTelemetry(page, sineWaveObject.uuid);
const formattedTelemetryValue = getTelemValuePromise; const formattedTelemetryValue = getTelemValuePromise;
const displayLayoutValuePromise = await page.waitForSelector(`text="${formattedTelemetryValue}"`); const displayLayoutValuePromise = await page.waitForSelector(
`text="${formattedTelemetryValue}"`
);
const displayLayoutValue = await displayLayoutValuePromise.textContent(); const displayLayoutValue = await displayLayoutValuePromise.textContent();
const trimmedDisplayValue = displayLayoutValue.trim(); const trimmedDisplayValue = displayLayoutValue.trim();
expect(trimmedDisplayValue).toBe(formattedTelemetryValue); expect(trimmedDisplayValue).toBe(formattedTelemetryValue);
}); });
test('alpha-numeric widget telemetry value exactly matches latest telemetry value received in fixed time', async ({ page }) => { test('alpha-numeric widget telemetry value exactly matches latest telemetry value received in fixed time', async ({
page
}) => {
// Create a Display Layout // Create a Display Layout
await createDomainObjectWithDefaults(page, { await createDomainObjectWithDefaults(page, {
type: 'Display Layout', type: 'Display Layout',
name: "Test Display Layout" name: 'Test Display Layout'
}); });
// Edit Display Layout // Edit Display Layout
await page.locator('[title="Edit"]').click(); await page.locator('[title="Edit"]').click();
@ -101,17 +112,21 @@ test.describe('Display Layout', () => {
// On getting data, check if the value found in the Display Layout is the most recent value // On getting data, check if the value found in the Display Layout is the most recent value
// from the Sine Wave Generator // from the Sine Wave Generator
const formattedTelemetryValue = getTelemValuePromise; const formattedTelemetryValue = getTelemValuePromise;
const displayLayoutValuePromise = await page.waitForSelector(`text="${formattedTelemetryValue}"`); const displayLayoutValuePromise = await page.waitForSelector(
`text="${formattedTelemetryValue}"`
);
const displayLayoutValue = await displayLayoutValuePromise.textContent(); const displayLayoutValue = await displayLayoutValuePromise.textContent();
const trimmedDisplayValue = displayLayoutValue.trim(); const trimmedDisplayValue = displayLayoutValue.trim();
expect(trimmedDisplayValue).toBe(formattedTelemetryValue); expect(trimmedDisplayValue).toBe(formattedTelemetryValue);
}); });
test('items in a display layout can be removed with object tree context menu when viewing the display layout', async ({ page }) => { test('items in a display layout can be removed with object tree context menu when viewing the display layout', async ({
page
}) => {
// Create a Display Layout // Create a Display Layout
await createDomainObjectWithDefaults(page, { await createDomainObjectWithDefaults(page, {
type: 'Display Layout', type: 'Display Layout',
name: "Test Display Layout" name: 'Test Display Layout'
}); });
// Edit Display Layout // Edit Display Layout
await page.locator('[title="Edit"]').click(); await page.locator('[title="Edit"]').click();
@ -144,7 +159,9 @@ test.describe('Display Layout', () => {
expect(await page.locator('.l-layout .l-layout__frame').count()).toEqual(0); expect(await page.locator('.l-layout .l-layout__frame').count()).toEqual(0);
}); });
test('items in a display layout can be removed with object tree context menu when viewing another item', async ({ page }) => { test('items in a display layout can be removed with object tree context menu when viewing another item', async ({
page
}) => {
test.info().annotations.push({ test.info().annotations.push({
type: 'issue', type: 'issue',
description: 'https://github.com/nasa/openmct/issues/3117' description: 'https://github.com/nasa/openmct/issues/3117'
@ -200,7 +217,9 @@ test.describe('Display Layout', () => {
* @returns {Promise<string>} the formatted sin telemetry value * @returns {Promise<string>} the formatted sin telemetry value
*/ */
async function subscribeToTelemetry(page, objectIdentifier) { async function subscribeToTelemetry(page, objectIdentifier) {
const getTelemValuePromise = new Promise(resolve => page.exposeFunction('getTelemValue', resolve)); const getTelemValuePromise = new Promise((resolve) =>
page.exposeFunction('getTelemValue', resolve)
);
await page.evaluate(async (telemetryIdentifier) => { await page.evaluate(async (telemetryIdentifier) => {
const telemetryObject = await window.openmct.objects.get(telemetryIdentifier); const telemetryObject = await window.openmct.objects.get(telemetryIdentifier);

View File

@ -36,29 +36,45 @@ test.describe('The Fault Management Plugin using example faults', () => {
expect.soft(faultCount).toEqual(criticalityIconCount); expect.soft(faultCount).toEqual(criticalityIconCount);
}); });
test('When selecting a fault, it has an "is-selected" class and it\'s information shows in the inspector @unstable', async ({ page }) => { test('When selecting a fault, it has an "is-selected" class and it\'s information shows in the inspector @unstable', async ({
page
}) => {
await utils.selectFaultItem(page, 1); await utils.selectFaultItem(page, 1);
await selectInspectorTab(page, 'Fault Management Configuration'); await selectInspectorTab(page, 'Fault Management Configuration');
const selectedFaultName = await page.locator('.c-fault-mgmt__list.is-selected .c-fault-mgmt__list-faultname').textContent(); const selectedFaultName = await page
const inspectorFaultNameCount = await page.locator(`.c-inspector__properties >> :text("${selectedFaultName}")`).count(); .locator('.c-fault-mgmt__list.is-selected .c-fault-mgmt__list-faultname')
.textContent();
const inspectorFaultNameCount = await page
.locator(`.c-inspector__properties >> :text("${selectedFaultName}")`)
.count();
await expect.soft(page.locator('.c-faults-list-view-item-body > .c-fault-mgmt__list').first()).toHaveClass(/is-selected/); await expect
.soft(page.locator('.c-faults-list-view-item-body > .c-fault-mgmt__list').first())
.toHaveClass(/is-selected/);
expect.soft(inspectorFaultNameCount).toEqual(1); expect.soft(inspectorFaultNameCount).toEqual(1);
}); });
test('When selecting multiple faults, no specific fault information is shown in the inspector @unstable', async ({ page }) => { test('When selecting multiple faults, no specific fault information is shown in the inspector @unstable', async ({
page
}) => {
await utils.selectFaultItem(page, 1); await utils.selectFaultItem(page, 1);
await utils.selectFaultItem(page, 2); await utils.selectFaultItem(page, 2);
const selectedRows = page.locator('.c-fault-mgmt__list.is-selected .c-fault-mgmt__list-faultname'); const selectedRows = page.locator(
'.c-fault-mgmt__list.is-selected .c-fault-mgmt__list-faultname'
);
expect.soft(await selectedRows.count()).toEqual(2); expect.soft(await selectedRows.count()).toEqual(2);
await selectInspectorTab(page, 'Fault Management Configuration'); await selectInspectorTab(page, 'Fault Management Configuration');
const firstSelectedFaultName = await selectedRows.nth(0).textContent(); const firstSelectedFaultName = await selectedRows.nth(0).textContent();
const secondSelectedFaultName = await selectedRows.nth(1).textContent(); const secondSelectedFaultName = await selectedRows.nth(1).textContent();
const firstNameInInspectorCount = await page.locator(`.c-inspector__properties >> :text("${firstSelectedFaultName}")`).count(); const firstNameInInspectorCount = await page
const secondNameInInspectorCount = await page.locator(`.c-inspector__properties >> :text("${secondSelectedFaultName}")`).count(); .locator(`.c-inspector__properties >> :text("${firstSelectedFaultName}")`)
.count();
const secondNameInInspectorCount = await page
.locator(`.c-inspector__properties >> :text("${secondSelectedFaultName}")`)
.count();
expect.soft(firstNameInInspectorCount).toEqual(0); expect.soft(firstNameInInspectorCount).toEqual(0);
expect.soft(secondNameInInspectorCount).toEqual(0); expect.soft(secondNameInInspectorCount).toEqual(0);
@ -208,7 +224,6 @@ test.describe('The Fault Management Plugin using example faults', () => {
expect.soft(sortedHighestSeverity).toEqual(highestSeverity); expect.soft(sortedHighestSeverity).toEqual(highestSeverity);
expect.soft(sortedLowestSeverity).toEqual(lowestSeverity); expect.soft(sortedLowestSeverity).toEqual(lowestSeverity);
}); });
}); });
test.describe('The Fault Management Plugin without using example faults', () => { test.describe('The Fault Management Plugin without using example faults', () => {

View File

@ -39,7 +39,9 @@ test.describe('Flexible Layout', () => {
type: 'Clock' type: 'Clock'
}); });
}); });
test('panes have the appropriate draggable attribute while in Edit and Browse modes', async ({ page }) => { test('panes have the appropriate draggable attribute while in Edit and Browse modes', async ({
page
}) => {
const treePane = page.getByRole('tree', { const treePane = page.getByRole('tree', {
name: 'Main Tree' name: 'Main Tree'
}); });
@ -62,7 +64,9 @@ test.describe('Flexible Layout', () => {
await sineWaveGeneratorTreeItem.dragTo(page.locator('.c-fl__container.is-empty').first()); await sineWaveGeneratorTreeItem.dragTo(page.locator('.c-fl__container.is-empty').first());
await clockTreeItem.dragTo(page.locator('.c-fl__container.is-empty')); await clockTreeItem.dragTo(page.locator('.c-fl__container.is-empty'));
// Check that panes can be dragged while Flexible Layout is in Edit mode // Check that panes can be dragged while Flexible Layout is in Edit mode
let dragWrapper = page.locator('.c-fl-container__frames-holder .c-fl-frame__drag-wrapper').first(); let dragWrapper = page
.locator('.c-fl-container__frames-holder .c-fl-frame__drag-wrapper')
.first();
await expect(dragWrapper).toHaveAttribute('draggable', 'true'); await expect(dragWrapper).toHaveAttribute('draggable', 'true');
// Save Flexible Layout // Save Flexible Layout
await page.locator('button[title="Save"]').click(); await page.locator('button[title="Save"]').click();
@ -71,7 +75,9 @@ test.describe('Flexible Layout', () => {
dragWrapper = page.locator('.c-fl-container__frames-holder .c-fl-frame__drag-wrapper').first(); dragWrapper = page.locator('.c-fl-container__frames-holder .c-fl-frame__drag-wrapper').first();
await expect(dragWrapper).toHaveAttribute('draggable', 'false'); await expect(dragWrapper).toHaveAttribute('draggable', 'false');
}); });
test('items in a flexible layout can be removed with object tree context menu when viewing the flexible layout', async ({ page }) => { test('items in a flexible layout can be removed with object tree context menu when viewing the flexible layout', async ({
page
}) => {
const treePane = page.getByRole('tree', { const treePane = page.getByRole('tree', {
name: 'Main Tree' name: 'Main Tree'
}); });
@ -105,7 +111,9 @@ test.describe('Flexible Layout', () => {
// Verify that the item has been removed from the layout // Verify that the item has been removed from the layout
expect(await page.locator('.c-fl-container__frame').count()).toEqual(0); expect(await page.locator('.c-fl-container__frame').count()).toEqual(0);
}); });
test('items in a flexible layout can be removed with object tree context menu when viewing another item', async ({ page }) => { test('items in a flexible layout can be removed with object tree context menu when viewing another item', async ({
page
}) => {
test.info().annotations.push({ test.info().annotations.push({
type: 'issue', type: 'issue',
description: 'https://github.com/nasa/openmct/issues/3117' description: 'https://github.com/nasa/openmct/issues/3117'

View File

@ -21,8 +21,8 @@
*****************************************************************************/ *****************************************************************************/
/* /*
* This test suite is dedicated to testing the Gauge component. * This test suite is dedicated to testing the Gauge component.
*/ */
const { test, expect } = require('../../../../pluginFixtures'); const { test, expect } = require('../../../../pluginFixtures');
const { createDomainObjectWithDefaults } = require('../../../../appActions'); const { createDomainObjectWithDefaults } = require('../../../../appActions');
@ -63,7 +63,13 @@ test.describe('Gauge', () => {
}); });
// Verify that the 'Replace telemetry source' modal appears and accept it // Verify that the 'Replace telemetry source' modal appears and accept it
await expect.soft(page.locator('text=This action will replace the current telemetry source. Do you want to continue?')).toBeVisible(); await expect
.soft(
page.locator(
'text=This action will replace the current telemetry source. Do you want to continue?'
)
)
.toBeVisible();
await page.click('text=Ok'); await page.click('text=Ok');
// Navigate to the gauge and verify that the new SWG // Navigate to the gauge and verify that the new SWG
@ -81,7 +87,13 @@ test.describe('Gauge', () => {
await page.locator('li[title="Remove this object from its containing object."]').click(); await page.locator('li[title="Remove this object from its containing object."]').click();
// Verify that the 'Remove object' confirmation modal appears and accept it // Verify that the 'Remove object' confirmation modal appears and accept it
await expect.soft(page.locator('text=Warning! This action will remove this object. Are you sure you want to continue?')).toBeVisible(); await expect
.soft(
page.locator(
'text=Warning! This action will remove this object. Are you sure you want to continue?'
)
)
.toBeVisible();
await page.click('text=Ok'); await page.click('text=Ok');
// Verify that the elements pool shows no elements // Verify that the elements pool shows no elements

View File

@ -44,7 +44,7 @@ test.describe('Example Imagery Object', () => {
// Verify that the created object is focused // Verify that the created object is focused
await expect(page.locator('.l-browse-bar__object-name')).toContainText(exampleImagery.name); await expect(page.locator('.l-browse-bar__object-name')).toContainText(exampleImagery.name);
await page.locator(backgroundImageSelector).hover({trial: true}); await page.locator(backgroundImageSelector).hover({ trial: true });
}); });
test('Can use Mouse Wheel to zoom in and out of latest image', async ({ page }) => { test('Can use Mouse Wheel to zoom in and out of latest image', async ({ page }) => {
@ -55,7 +55,10 @@ test.describe('Example Imagery Object', () => {
await mouseZoomOnImageAndAssert(page, -2); await mouseZoomOnImageAndAssert(page, -2);
}); });
test('Can adjust image brightness/contrast by dragging the sliders', async ({ page, browserName }) => { test('Can adjust image brightness/contrast by dragging the sliders', async ({
page,
browserName
}) => {
// eslint-disable-next-line playwright/no-skipped-test // eslint-disable-next-line playwright/no-skipped-test
test.skip(browserName === 'firefox', 'This test needs to be updated to work with firefox'); test.skip(browserName === 'firefox', 'This test needs to be updated to work with firefox');
// Open the image filter menu // Open the image filter menu
@ -69,11 +72,11 @@ test.describe('Example Imagery Object', () => {
test('Can use alt+drag to move around image once zoomed in', async ({ page }) => { test('Can use alt+drag to move around image once zoomed in', async ({ page }) => {
const deltaYStep = 100; //equivalent to 1x zoom const deltaYStep = 100; //equivalent to 1x zoom
await page.locator(backgroundImageSelector).hover({trial: true}); await page.locator(backgroundImageSelector).hover({ trial: true });
// zoom in // zoom in
await page.mouse.wheel(0, deltaYStep * 2); await page.mouse.wheel(0, deltaYStep * 2);
await page.locator(backgroundImageSelector).hover({trial: true}); await page.locator(backgroundImageSelector).hover({ trial: true });
const zoomedBoundingBox = await page.locator(backgroundImageSelector).boundingBox(); const zoomedBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
const imageCenterX = zoomedBoundingBox.x + zoomedBoundingBox.width / 2; const imageCenterX = zoomedBoundingBox.x + zoomedBoundingBox.width / 2;
const imageCenterY = zoomedBoundingBox.y + zoomedBoundingBox.height / 2; const imageCenterY = zoomedBoundingBox.y + zoomedBoundingBox.height / 2;
@ -91,42 +94,41 @@ test.describe('Example Imagery Object', () => {
expect(expectedAltText).toEqual(imageryHintsText); expect(expectedAltText).toEqual(imageryHintsText);
// pan right // pan right
await Promise.all(panHotkey.map(x => page.keyboard.down(x))); await Promise.all(panHotkey.map((x) => page.keyboard.down(x)));
await page.mouse.down(); await page.mouse.down();
await page.mouse.move(imageCenterX - 200, imageCenterY, 10); await page.mouse.move(imageCenterX - 200, imageCenterY, 10);
await page.mouse.up(); await page.mouse.up();
await Promise.all(panHotkey.map(x => page.keyboard.up(x))); await Promise.all(panHotkey.map((x) => page.keyboard.up(x)));
const afterRightPanBoundingBox = await page.locator(backgroundImageSelector).boundingBox(); const afterRightPanBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
expect(zoomedBoundingBox.x).toBeGreaterThan(afterRightPanBoundingBox.x); expect(zoomedBoundingBox.x).toBeGreaterThan(afterRightPanBoundingBox.x);
// pan left // pan left
await Promise.all(panHotkey.map(x => page.keyboard.down(x))); await Promise.all(panHotkey.map((x) => page.keyboard.down(x)));
await page.mouse.down(); await page.mouse.down();
await page.mouse.move(imageCenterX, imageCenterY, 10); await page.mouse.move(imageCenterX, imageCenterY, 10);
await page.mouse.up(); await page.mouse.up();
await Promise.all(panHotkey.map(x => page.keyboard.up(x))); await Promise.all(panHotkey.map((x) => page.keyboard.up(x)));
const afterLeftPanBoundingBox = await page.locator(backgroundImageSelector).boundingBox(); const afterLeftPanBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
expect(afterRightPanBoundingBox.x).toBeLessThan(afterLeftPanBoundingBox.x); expect(afterRightPanBoundingBox.x).toBeLessThan(afterLeftPanBoundingBox.x);
// pan up // pan up
await page.mouse.move(imageCenterX, imageCenterY); await page.mouse.move(imageCenterX, imageCenterY);
await Promise.all(panHotkey.map(x => page.keyboard.down(x))); await Promise.all(panHotkey.map((x) => page.keyboard.down(x)));
await page.mouse.down(); await page.mouse.down();
await page.mouse.move(imageCenterX, imageCenterY + 200, 10); await page.mouse.move(imageCenterX, imageCenterY + 200, 10);
await page.mouse.up(); await page.mouse.up();
await Promise.all(panHotkey.map(x => page.keyboard.up(x))); await Promise.all(panHotkey.map((x) => page.keyboard.up(x)));
const afterUpPanBoundingBox = await page.locator(backgroundImageSelector).boundingBox(); const afterUpPanBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
expect(afterUpPanBoundingBox.y).toBeGreaterThan(afterLeftPanBoundingBox.y); expect(afterUpPanBoundingBox.y).toBeGreaterThan(afterLeftPanBoundingBox.y);
// pan down // pan down
await Promise.all(panHotkey.map(x => page.keyboard.down(x))); await Promise.all(panHotkey.map((x) => page.keyboard.down(x)));
await page.mouse.down(); await page.mouse.down();
await page.mouse.move(imageCenterX, imageCenterY - 200, 10); await page.mouse.move(imageCenterX, imageCenterY - 200, 10);
await page.mouse.up(); await page.mouse.up();
await Promise.all(panHotkey.map(x => page.keyboard.up(x))); await Promise.all(panHotkey.map((x) => page.keyboard.up(x)));
const afterDownPanBoundingBox = await page.locator(backgroundImageSelector).boundingBox(); const afterDownPanBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
expect(afterDownPanBoundingBox.y).toBeLessThan(afterUpPanBoundingBox.y); expect(afterDownPanBoundingBox.y).toBeLessThan(afterUpPanBoundingBox.y);
}); });
test('Can use + - buttons to zoom on the image @unstable', async ({ page }) => { test('Can use + - buttons to zoom on the image @unstable', async ({ page }) => {
@ -134,7 +136,7 @@ test.describe('Example Imagery Object', () => {
}); });
test('Can use the reset button to reset the image @unstable', async ({ page }, testInfo) => { test('Can use the reset button to reset the image @unstable', async ({ page }, testInfo) => {
test.slow(testInfo.project === 'chrome-beta', "This test is slow in chrome-beta"); test.slow(testInfo.project === 'chrome-beta', 'This test is slow in chrome-beta');
// Get initial image dimensions // Get initial image dimensions
const initialBoundingBox = await page.locator(backgroundImageSelector).boundingBox(); const initialBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
@ -196,18 +198,22 @@ test.describe('Example Imagery in Display Layout', () => {
// Click text=OK // Click text=OK
await Promise.all([ await Promise.all([
page.waitForNavigation({waitUntil: 'networkidle'}), page.waitForNavigation({ waitUntil: 'networkidle' }),
page.click('button:has-text("OK")'), page.click('button:has-text("OK")'),
//Wait for Save Banner to appear //Wait for Save Banner to appear
page.waitForSelector('.c-message-banner__message') page.waitForSelector('.c-message-banner__message')
]); ]);
await expect(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Example Imagery'); await expect(page.locator('.l-browse-bar__object-name')).toContainText(
'Unnamed Example Imagery'
);
await page.goto(displayLayout.url); await page.goto(displayLayout.url);
}); });
test('View Large action pauses imagery when in realtime and returns to realtime', async ({ page }) => { test('View Large action pauses imagery when in realtime and returns to realtime', async ({
page
}) => {
test.info().annotations.push({ test.info().annotations.push({
type: 'issue', type: 'issue',
description: 'https://github.com/nasa/openmct/issues/3647' description: 'https://github.com/nasa/openmct/issues/3647'
@ -335,13 +341,15 @@ test.describe('Example Imagery in Flexible layout', () => {
// Click text=OK // Click text=OK
await Promise.all([ await Promise.all([
page.waitForNavigation({waitUntil: 'networkidle'}), page.waitForNavigation({ waitUntil: 'networkidle' }),
page.click('button:has-text("OK")'), page.click('button:has-text("OK")'),
//Wait for Save Banner to appear //Wait for Save Banner to appear
page.waitForSelector('.c-message-banner__message') page.waitForSelector('.c-message-banner__message')
]); ]);
await expect(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Example Imagery'); await expect(page.locator('.l-browse-bar__object-name')).toContainText(
'Unnamed Example Imagery'
);
await page.goto(flexibleLayout.url); await page.goto(flexibleLayout.url);
}); });
@ -377,13 +385,15 @@ test.describe('Example Imagery in Tabs View', () => {
// Click text=OK // Click text=OK
await Promise.all([ await Promise.all([
page.waitForNavigation({waitUntil: 'networkidle'}), page.waitForNavigation({ waitUntil: 'networkidle' }),
page.click('button:has-text("OK")'), page.click('button:has-text("OK")'),
//Wait for Save Banner to appear //Wait for Save Banner to appear
page.waitForSelector('.c-message-banner__message') page.waitForSelector('.c-message-banner__message')
]); ]);
await expect(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Example Imagery'); await expect(page.locator('.l-browse-bar__object-name')).toContainText(
'Unnamed Example Imagery'
);
await page.goto(tabsView.url); await page.goto(tabsView.url);
}); });
@ -417,7 +427,9 @@ test.describe('Example Imagery in Time Strip', () => {
await page.locator('.c-imagery-tsv-container').hover(); await page.locator('.c-imagery-tsv-container').hover();
// Get the img src of the hovered image thumbnail // Get the img src of the hovered image thumbnail
const hoveredThumbnailImg = page.locator('.c-imagery-tsv div.c-imagery-tsv__image-wrapper:hover img'); const hoveredThumbnailImg = page.locator(
'.c-imagery-tsv div.c-imagery-tsv__image-wrapper:hover img'
);
const hoveredThumbnailImgSrc = await hoveredThumbnailImg.getAttribute('src'); const hoveredThumbnailImgSrc = await hoveredThumbnailImg.getAttribute('src');
// Verify that imagery timestrip view uses the thumbnailUrl as img src for thumbnails // Verify that imagery timestrip view uses the thumbnailUrl as img src for thumbnails
@ -496,14 +508,19 @@ async function performImageryViewOperationsAndAssert(page) {
// The imagery view should be updated when new images come in // The imagery view should be updated when new images come in
const imageCount = await page.locator('.c-imagery__thumb').count(); const imageCount = await page.locator('.c-imagery__thumb').count();
await expect.poll(async () => { await expect
.poll(
async () => {
const newImageCount = await page.locator('.c-imagery__thumb').count(); const newImageCount = await page.locator('.c-imagery__thumb').count();
return newImageCount; return newImageCount;
}, { },
message: "verify that old images are discarded", {
message: 'verify that old images are discarded',
timeout: 7 * 1000 timeout: 7 * 1000
}).toBe(imageCount); }
)
.toBe(imageCount);
// Verify selected image is still displayed // Verify selected image is still displayed
await expect(selectedImage).toBeVisible(); await expect(selectedImage).toBeVisible();
@ -532,7 +549,7 @@ async function dragBrightnessSliderAndAssertFilterValues(page) {
const brightnessMidX = brightnessBoundingBox.x + brightnessBoundingBox.width / 2; const brightnessMidX = brightnessBoundingBox.x + brightnessBoundingBox.width / 2;
const brightnessMidY = brightnessBoundingBox.y + brightnessBoundingBox.height / 2; const brightnessMidY = brightnessBoundingBox.y + brightnessBoundingBox.height / 2;
await page.locator(brightnessSlider).hover({trial: true}); await page.locator(brightnessSlider).hover({ trial: true });
await page.mouse.down(); await page.mouse.down();
await page.mouse.move(brightnessBoundingBox.x + brightnessBoundingBox.width, brightnessMidY); await page.mouse.move(brightnessBoundingBox.x + brightnessBoundingBox.width, brightnessMidY);
await assertBackgroundImageBrightness(page, '500'); await assertBackgroundImageBrightness(page, '500');
@ -553,7 +570,7 @@ async function dragContrastSliderAndAssertFilterValues(page) {
const contrastMidX = contrastBoundingBox.x + contrastBoundingBox.width / 2; const contrastMidX = contrastBoundingBox.x + contrastBoundingBox.width / 2;
const contrastMidY = contrastBoundingBox.y + contrastBoundingBox.height / 2; const contrastMidY = contrastBoundingBox.y + contrastBoundingBox.height / 2;
await page.locator(contrastSlider).hover({trial: true}); await page.locator(contrastSlider).hover({ trial: true });
await page.mouse.down(); await page.mouse.down();
await page.mouse.move(contrastBoundingBox.x + contrastBoundingBox.width, contrastMidY); await page.mouse.move(contrastBoundingBox.x + contrastBoundingBox.width, contrastMidY);
await assertBackgroundImageContrast(page, '500'); await assertBackgroundImageContrast(page, '500');
@ -586,24 +603,35 @@ async function assertBackgroundImageBrightness(page, expected) {
async function assertBackgroundImageUrlFromBackgroundCss(page) { async function assertBackgroundImageUrlFromBackgroundCss(page) {
const backgroundImage = page.locator('.c-imagery__main-image__background-image'); const backgroundImage = page.locator('.c-imagery__main-image__background-image');
let backgroundImageUrl = await backgroundImage.evaluate((el) => { let backgroundImageUrl = await backgroundImage.evaluate((el) => {
return window.getComputedStyle(el).getPropertyValue('background-image').match(/url\(([^)]+)\)/)[1]; return window
.getComputedStyle(el)
.getPropertyValue('background-image')
.match(/url\(([^)]+)\)/)[1];
}); });
let backgroundImageUrl1 = backgroundImageUrl.slice(1, -1); //forgive me, padre let backgroundImageUrl1 = backgroundImageUrl.slice(1, -1); //forgive me, padre
console.log('backgroundImageUrl1 ' + backgroundImageUrl1); console.log('backgroundImageUrl1 ' + backgroundImageUrl1);
let backgroundImageUrl2; let backgroundImageUrl2;
await expect.poll(async () => { await expect
.poll(
async () => {
// Verify next image has updated // Verify next image has updated
let backgroundImageUrlNext = await backgroundImage.evaluate((el) => { let backgroundImageUrlNext = await backgroundImage.evaluate((el) => {
return window.getComputedStyle(el).getPropertyValue('background-image').match(/url\(([^)]+)\)/)[1]; return window
.getComputedStyle(el)
.getPropertyValue('background-image')
.match(/url\(([^)]+)\)/)[1];
}); });
backgroundImageUrl2 = backgroundImageUrlNext.slice(1, -1); //forgive me, padre backgroundImageUrl2 = backgroundImageUrlNext.slice(1, -1); //forgive me, padre
return backgroundImageUrl2; return backgroundImageUrl2;
}, { },
message: "verify next image has updated", {
message: 'verify next image has updated',
timeout: 7 * 1000 timeout: 7 * 1000
}).not.toBe(backgroundImageUrl1); }
)
.not.toBe(backgroundImageUrl1);
console.log('backgroundImageUrl2 ' + backgroundImageUrl2); console.log('backgroundImageUrl2 ' + backgroundImageUrl2);
} }
@ -618,39 +646,39 @@ async function panZoomAndAssertImageProperties(page) {
const imageCenterY = zoomedBoundingBox.y + zoomedBoundingBox.height / 2; const imageCenterY = zoomedBoundingBox.y + zoomedBoundingBox.height / 2;
// Pan right // Pan right
await Promise.all(panHotkey.map(x => page.keyboard.down(x))); await Promise.all(panHotkey.map((x) => page.keyboard.down(x)));
await page.mouse.down(); await page.mouse.down();
await page.mouse.move(imageCenterX - 200, imageCenterY, 10); await page.mouse.move(imageCenterX - 200, imageCenterY, 10);
await page.mouse.up(); await page.mouse.up();
await Promise.all(panHotkey.map(x => page.keyboard.up(x))); await Promise.all(panHotkey.map((x) => page.keyboard.up(x)));
const afterRightPanBoundingBox = await page.locator(backgroundImageSelector).boundingBox(); const afterRightPanBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
expect(zoomedBoundingBox.x).toBeGreaterThan(afterRightPanBoundingBox.x); expect(zoomedBoundingBox.x).toBeGreaterThan(afterRightPanBoundingBox.x);
// Pan left // Pan left
await Promise.all(panHotkey.map(x => page.keyboard.down(x))); await Promise.all(panHotkey.map((x) => page.keyboard.down(x)));
await page.mouse.down(); await page.mouse.down();
await page.mouse.move(imageCenterX, imageCenterY, 10); await page.mouse.move(imageCenterX, imageCenterY, 10);
await page.mouse.up(); await page.mouse.up();
await Promise.all(panHotkey.map(x => page.keyboard.up(x))); await Promise.all(panHotkey.map((x) => page.keyboard.up(x)));
const afterLeftPanBoundingBox = await page.locator(backgroundImageSelector).boundingBox(); const afterLeftPanBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
expect(afterRightPanBoundingBox.x).toBeLessThan(afterLeftPanBoundingBox.x); expect(afterRightPanBoundingBox.x).toBeLessThan(afterLeftPanBoundingBox.x);
// Pan up // Pan up
await page.mouse.move(imageCenterX, imageCenterY); await page.mouse.move(imageCenterX, imageCenterY);
await Promise.all(panHotkey.map(x => page.keyboard.down(x))); await Promise.all(panHotkey.map((x) => page.keyboard.down(x)));
await page.mouse.down(); await page.mouse.down();
await page.mouse.move(imageCenterX, imageCenterY + 200, 10); await page.mouse.move(imageCenterX, imageCenterY + 200, 10);
await page.mouse.up(); await page.mouse.up();
await Promise.all(panHotkey.map(x => page.keyboard.up(x))); await Promise.all(panHotkey.map((x) => page.keyboard.up(x)));
const afterUpPanBoundingBox = await page.locator(backgroundImageSelector).boundingBox(); const afterUpPanBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
expect(afterUpPanBoundingBox.y).toBeGreaterThanOrEqual(afterLeftPanBoundingBox.y); expect(afterUpPanBoundingBox.y).toBeGreaterThanOrEqual(afterLeftPanBoundingBox.y);
// Pan down // Pan down
await Promise.all(panHotkey.map(x => page.keyboard.down(x))); await Promise.all(panHotkey.map((x) => page.keyboard.down(x)));
await page.mouse.down(); await page.mouse.down();
await page.mouse.move(imageCenterX, imageCenterY - 200, 10); await page.mouse.move(imageCenterX, imageCenterY - 200, 10);
await page.mouse.up(); await page.mouse.up();
await Promise.all(panHotkey.map(x => page.keyboard.up(x))); await Promise.all(panHotkey.map((x) => page.keyboard.up(x)));
const afterDownPanBoundingBox = await page.locator(backgroundImageSelector).boundingBox(); const afterDownPanBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
expect(afterDownPanBoundingBox.y).toBeLessThanOrEqual(afterUpPanBoundingBox.y); expect(afterDownPanBoundingBox.y).toBeLessThanOrEqual(afterUpPanBoundingBox.y);
} }
@ -660,11 +688,11 @@ async function panZoomAndAssertImageProperties(page) {
* has successfully zoomed in or out. * has successfully zoomed in or out.
* @param {import('@playwright/test').Page} page * @param {import('@playwright/test').Page} page
* @param {number} [factor = 2] The zoom factor. Positive for zoom in, negative for zoom out. * @param {number} [factor = 2] The zoom factor. Positive for zoom in, negative for zoom out.
*/ */
async function mouseZoomOnImageAndAssert(page, factor = 2) { async function mouseZoomOnImageAndAssert(page, factor = 2) {
// Zoom in // Zoom in
const originalImageDimensions = await page.locator(backgroundImageSelector).boundingBox(); const originalImageDimensions = await page.locator(backgroundImageSelector).boundingBox();
await page.locator(backgroundImageSelector).hover({trial: true}); await page.locator(backgroundImageSelector).hover({ trial: true });
const deltaYStep = 100; // equivalent to 1x zoom const deltaYStep = 100; // equivalent to 1x zoom
await page.mouse.wheel(0, deltaYStep * factor); await page.mouse.wheel(0, deltaYStep * factor);
const zoomedBoundingBox = await page.locator(backgroundImageSelector).boundingBox(); const zoomedBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
@ -675,7 +703,7 @@ async function mouseZoomOnImageAndAssert(page, factor = 2) {
await page.mouse.move(imageCenterX, imageCenterY); await page.mouse.move(imageCenterX, imageCenterY);
// Wait for zoom animation to finish // Wait for zoom animation to finish
await page.locator(backgroundImageSelector).hover({trial: true}); await page.locator(backgroundImageSelector).hover({ trial: true });
const imageMouseZoomed = await page.locator(backgroundImageSelector).boundingBox(); const imageMouseZoomed = await page.locator(backgroundImageSelector).boundingBox();
if (factor > 0) { if (factor > 0) {
@ -742,10 +770,12 @@ async function assertBackgroundImageContrast(page, expected) {
*/ */
async function zoomIntoImageryByButton(page) { async function zoomIntoImageryByButton(page) {
// FIXME: There should only be one set of imagery buttons, but there are two? // FIXME: There should only be one set of imagery buttons, but there are two?
const zoomInBtn = page.locator("[role='toolbar'][aria-label='Image controls'] .t-btn-zoom-in").nth(0); const zoomInBtn = page
.locator("[role='toolbar'][aria-label='Image controls'] .t-btn-zoom-in")
.nth(0);
const backgroundImage = page.locator(backgroundImageSelector); const backgroundImage = page.locator(backgroundImageSelector);
if (!(await zoomInBtn.isVisible())) { if (!(await zoomInBtn.isVisible())) {
await backgroundImage.hover({trial: true}); await backgroundImage.hover({ trial: true });
} }
await zoomInBtn.click(); await zoomInBtn.click();
@ -759,10 +789,12 @@ async function zoomIntoImageryByButton(page) {
*/ */
async function zoomOutOfImageryByButton(page) { async function zoomOutOfImageryByButton(page) {
// FIXME: There should only be one set of imagery buttons, but there are two? // FIXME: There should only be one set of imagery buttons, but there are two?
const zoomOutBtn = page.locator("[role='toolbar'][aria-label='Image controls'] .t-btn-zoom-out").nth(0); const zoomOutBtn = page
.locator("[role='toolbar'][aria-label='Image controls'] .t-btn-zoom-out")
.nth(0);
const backgroundImage = page.locator(backgroundImageSelector); const backgroundImage = page.locator(backgroundImageSelector);
if (!(await zoomOutBtn.isVisible())) { if (!(await zoomOutBtn.isVisible())) {
await backgroundImage.hover({trial: true}); await backgroundImage.hover({ trial: true });
} }
await zoomOutBtn.click(); await zoomOutBtn.click();
@ -776,10 +808,12 @@ async function zoomOutOfImageryByButton(page) {
*/ */
async function resetImageryPanAndZoom(page) { async function resetImageryPanAndZoom(page) {
// FIXME: There should only be one set of imagery buttons, but there are two? // FIXME: There should only be one set of imagery buttons, but there are two?
const panZoomResetBtn = page.locator("[role='toolbar'][aria-label='Image controls'] .t-btn-zoom-reset").nth(0); const panZoomResetBtn = page
.locator("[role='toolbar'][aria-label='Image controls'] .t-btn-zoom-reset")
.nth(0);
const backgroundImage = page.locator(backgroundImageSelector); const backgroundImage = page.locator(backgroundImageSelector);
if (!(await panZoomResetBtn.isVisible())) { if (!(await panZoomResetBtn.isVisible())) {
await backgroundImage.hover({trial: true}); await backgroundImage.hover({ trial: true });
} }
await panZoomResetBtn.click(); await panZoomResetBtn.click();

View File

@ -29,22 +29,31 @@ This test suite is dedicated to tests which verify the basic operations surround
const { test, expect } = require('../../../../baseFixtures'); const { test, expect } = require('../../../../baseFixtures');
test.describe('ExportAsJSON', () => { test.describe('ExportAsJSON', () => {
test.fixme('Create a basic object and verify that it can be exported as JSON from Tree', async ({ page }) => { test.fixme(
'Create a basic object and verify that it can be exported as JSON from Tree',
async ({ page }) => {
//Create domain object //Create domain object
//Save Domain Object //Save Domain Object
//Verify that the newly created domain object can be exported as JSON from the Tree //Verify that the newly created domain object can be exported as JSON from the Tree
}); }
test.fixme('Create a basic object and verify that it can be exported as JSON from 3 dot menu', async ({ page }) => { );
test.fixme(
'Create a basic object and verify that it can be exported as JSON from 3 dot menu',
async ({ page }) => {
//Create domain object //Create domain object
//Save Domain Object //Save Domain Object
//Verify that the newly created domain object can be exported as JSON from the 3 dot menu //Verify that the newly created domain object can be exported as JSON from the 3 dot menu
}); }
);
test.fixme('Verify that a nested Object can be exported as JSON', async ({ page }) => { test.fixme('Verify that a nested Object can be exported as JSON', async ({ page }) => {
// Create 2 objects with hierarchy // Create 2 objects with hierarchy
// Export as JSON // Export as JSON
// Verify Hiearchy // Verify Hiearchy
}); });
test.fixme('Verify that the ExportAsJSON dropdown does not appear for the item X', async ({ page }) => { test.fixme(
'Verify that the ExportAsJSON dropdown does not appear for the item X',
async ({ page }) => {
// Other than non-persistible objects // Other than non-persistible objects
}); }
);
}); });

View File

@ -33,16 +33,22 @@ test.describe('ExportAsJSON', () => {
//Verify that an testdata JSON file can be imported from Tree //Verify that an testdata JSON file can be imported from Tree
//Verify correctness of imported domain object //Verify correctness of imported domain object
}); });
test.fixme('Verify that domain object can be importAsJSON from 3 dot menu on folder', async ({ page }) => { test.fixme(
'Verify that domain object can be importAsJSON from 3 dot menu on folder',
async ({ page }) => {
//Verify that an testdata JSON file can be imported from 3 dot menu on folder domain object //Verify that an testdata JSON file can be imported from 3 dot menu on folder domain object
//Verify correctness of imported domain object //Verify correctness of imported domain object
}); }
);
test.fixme('Verify that a nested Objects can be importAsJSON', async ({ page }) => { test.fixme('Verify that a nested Objects can be importAsJSON', async ({ page }) => {
// Testdata with hierarchy // Testdata with hierarchy
// ImportAsJSON on Tree // ImportAsJSON on Tree
// Verify Hierarchy // Verify Hierarchy
}); });
test.fixme('Verify that the ImportAsJSON dropdown does not appear for the item X', async ({ page }) => { test.fixme(
'Verify that the ImportAsJSON dropdown does not appear for the item X',
async ({ page }) => {
// Other than non-persistible objects // Other than non-persistible objects
}); }
);
}); });

View File

@ -21,7 +21,13 @@
*****************************************************************************/ *****************************************************************************/
const { test, expect } = require('../../../../pluginFixtures'); const { test, expect } = require('../../../../pluginFixtures');
const { createDomainObjectWithDefaults, setStartOffset, setFixedTimeMode, setRealTimeMode, selectInspectorTab } = require('../../../../appActions'); const {
createDomainObjectWithDefaults,
setStartOffset,
setFixedTimeMode,
setRealTimeMode,
selectInspectorTab
} = require('../../../../appActions');
test.describe('Testing LAD table configuration', () => { test.describe('Testing LAD table configuration', () => {
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
@ -30,13 +36,13 @@ test.describe('Testing LAD table configuration', () => {
// Create LAD table // Create LAD table
const ladTable = await createDomainObjectWithDefaults(page, { const ladTable = await createDomainObjectWithDefaults(page, {
type: 'LAD Table', type: 'LAD Table',
name: "Test LAD Table" name: 'Test LAD Table'
}); });
// Create Sine Wave Generator // Create Sine Wave Generator
await createDomainObjectWithDefaults(page, { await createDomainObjectWithDefaults(page, {
type: 'Sine Wave Generator', type: 'Sine Wave Generator',
name: "Test Sine Wave Generator", name: 'Test Sine Wave Generator',
parent: ladTable.uuid parent: ladTable.uuid
}); });
@ -117,7 +123,9 @@ test.describe('Testing LAD table configuration', () => {
await expect(page.getByRole('cell', { name: 'Type' })).toBeVisible(); await expect(page.getByRole('cell', { name: 'Type' })).toBeVisible();
}); });
test('LAD Tables don\'t allow selection of rows but does show context click menus', async ({ page }) => { test("LAD Tables don't allow selection of rows but does show context click menus", async ({
page
}) => {
const cell = await page.locator('.js-first-data'); const cell = await page.locator('.js-first-data');
const userSelectable = await cell.evaluate((el) => { const userSelectable = await cell.evaluate((el) => {
return window.getComputedStyle(el).getPropertyValue('user-select'); return window.getComputedStyle(el).getPropertyValue('user-select');
@ -145,14 +153,16 @@ test.describe('Testing LAD table @unstable', () => {
// Create Sine Wave Generator // Create Sine Wave Generator
sineWaveObject = await createDomainObjectWithDefaults(page, { sineWaveObject = await createDomainObjectWithDefaults(page, {
type: 'Sine Wave Generator', type: 'Sine Wave Generator',
name: "Test Sine Wave Generator" name: 'Test Sine Wave Generator'
}); });
}); });
test('telemetry value exactly matches latest telemetry value received in real time', async ({ page }) => { test('telemetry value exactly matches latest telemetry value received in real time', async ({
page
}) => {
// Create LAD table // Create LAD table
await createDomainObjectWithDefaults(page, { await createDomainObjectWithDefaults(page, {
type: 'LAD Table', type: 'LAD Table',
name: "Test LAD Table" name: 'Test LAD Table'
}); });
// Edit LAD table // Edit LAD table
await page.locator('[title="Edit"]').click(); await page.locator('[title="Edit"]').click();
@ -174,11 +184,13 @@ test.describe('Testing LAD table @unstable', () => {
expect(ladTableValue).toBe(subscribeTelemValue); expect(ladTableValue).toBe(subscribeTelemValue);
}); });
test('telemetry value exactly matches latest telemetry value received in fixed time', async ({ page }) => { test('telemetry value exactly matches latest telemetry value received in fixed time', async ({
page
}) => {
// Create LAD table // Create LAD table
await createDomainObjectWithDefaults(page, { await createDomainObjectWithDefaults(page, {
type: 'LAD Table', type: 'LAD Table',
name: "Test LAD Table" name: 'Test LAD Table'
}); });
// Edit LAD table // Edit LAD table
await page.locator('[title="Edit"]').click(); await page.locator('[title="Edit"]').click();
@ -216,7 +228,9 @@ test.describe('Testing LAD table @unstable', () => {
* @returns {Promise<string>} the formatted sin telemetry value * @returns {Promise<string>} the formatted sin telemetry value
*/ */
async function subscribeToTelemetry(page, objectIdentifier) { async function subscribeToTelemetry(page, objectIdentifier) {
const getTelemValuePromise = new Promise(resolve => page.exposeFunction('getTelemValue', resolve)); const getTelemValuePromise = new Promise((resolve) =>
page.exposeFunction('getTelemValue', resolve)
);
await page.evaluate(async (telemetryIdentifier) => { await page.evaluate(async (telemetryIdentifier) => {
const telemetryObject = await window.openmct.objects.get(telemetryIdentifier); const telemetryObject = await window.openmct.objects.get(telemetryIdentifier);

View File

@ -50,22 +50,31 @@ test.describe('Default Notebook', () => {
// `JSON.parse(localStorage.getItem('notebook-storage'));` // `JSON.parse(localStorage.getItem('notebook-storage'));`
// 1. - Clear default notebook: // 1. - Clear default notebook:
// `localStorage.setItem('notebook-storage', null);` // `localStorage.setItem('notebook-storage', null);`
test.fixme('A newly created Notebook is automatically set as the default notebook if no other notebooks exist', async ({ page }) => { test.fixme(
'A newly created Notebook is automatically set as the default notebook if no other notebooks exist',
async ({ page }) => {
//Create new notebook //Create new notebook
//Verify Default Notebook Characteristics //Verify Default Notebook Characteristics
}); }
test.fixme('A newly created Notebook is automatically set as the default notebook if at least one other notebook exists', async ({ page }) => { );
test.fixme(
'A newly created Notebook is automatically set as the default notebook if at least one other notebook exists',
async ({ page }) => {
//Create new notebook A //Create new notebook A
//Create second notebook B //Create second notebook B
//Verify Non-Default Notebook A Characteristics //Verify Non-Default Notebook A Characteristics
//Verify Default Notebook B Characteristics //Verify Default Notebook B Characteristics
}); }
test.fixme('If a default notebook is deleted, the second most recent notebook becomes the default', async ({ page }) => { );
test.fixme(
'If a default notebook is deleted, the second most recent notebook becomes the default',
async ({ page }) => {
//Create new notebook A //Create new notebook A
//Create second notebook B //Create second notebook B
//Delete Notebook B //Delete Notebook B
//Verify Default Notebook A Characteristics //Verify Default Notebook A Characteristics
}); }
);
}); });
test.describe('Notebook section tests', () => { test.describe('Notebook section tests', () => {
@ -79,7 +88,9 @@ test.describe('Notebook section tests', () => {
type: NOTEBOOK_NAME type: NOTEBOOK_NAME
}); });
}); });
test('Default and new sections are automatically named Unnamed Section with Unnamed Page', async ({ page }) => { test('Default and new sections are automatically named Unnamed Section with Unnamed Page', async ({
page
}) => {
const notebookSectionNames = page.locator('.c-notebook__sections .c-list__item__name'); const notebookSectionNames = page.locator('.c-notebook__sections .c-list__item__name');
const notebookPageNames = page.locator('.c-notebook__pages .c-list__item__name'); const notebookPageNames = page.locator('.c-notebook__pages .c-list__item__name');
await expect(notebookSectionNames).toBeHidden(); await expect(notebookSectionNames).toBeHidden();
@ -104,7 +115,6 @@ test.describe('Notebook section tests', () => {
const newPageName = await notebookPageNames.innerText(); const newPageName = await notebookPageNames.innerText();
await expect(notebookPageNames).toBeVisible(); await expect(notebookPageNames).toBeVisible();
expect(newPageName).toBe('Unnamed Page'); expect(newPageName).toBe('Unnamed Page');
}); });
test.fixme('Section selection operations and associated behavior', async ({ page }) => { test.fixme('Section selection operations and associated behavior', async ({ page }) => {
//Create new notebook A //Create new notebook A
@ -152,7 +162,9 @@ test.describe('Notebook page tests', () => {
}); });
//Test will need to be implemented after a refactor in #5713 //Test will need to be implemented after a refactor in #5713
// eslint-disable-next-line playwright/no-skipped-test // eslint-disable-next-line playwright/no-skipped-test
test.skip('Delete page popup is removed properly on clicking dropdown again', async ({ page }) => { test.skip('Delete page popup is removed properly on clicking dropdown again', async ({
page
}) => {
test.info().annotations.push({ test.info().annotations.push({
type: 'issue', type: 'issue',
description: 'https://github.com/nasa/openmct/issues/5713' description: 'https://github.com/nasa/openmct/issues/5713'
@ -252,7 +264,9 @@ test.describe('Notebook entry tests', () => {
let notebookObject; let notebookObject;
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
await page.addInitScript({ path: path.join(__dirname, '../../../../helper/', 'addInitNotebookWithUrls.js') }); await page.addInitScript({
path: path.join(__dirname, '../../../../helper/', 'addInitNotebookWithUrls.js')
});
await page.goto('./', { waitUntil: 'domcontentloaded' }); await page.goto('./', { waitUntil: 'domcontentloaded' });
notebookObject = await createDomainObjectWithDefaults(page, { notebookObject = await createDomainObjectWithDefaults(page, {
@ -268,7 +282,9 @@ test.describe('Notebook entry tests', () => {
await expect(page.locator('[aria-label="Notebook Entry Input"]')).toBeVisible(); await expect(page.locator('[aria-label="Notebook Entry Input"]')).toBeVisible();
await expect(page.locator('[aria-label="Notebook Entry"]')).toHaveClass(/is-selected/); await expect(page.locator('[aria-label="Notebook Entry"]')).toHaveClass(/is-selected/);
}); });
test('When an object is dropped into a notebook, a new entry is created and it should be focused @unstable', async ({ page }) => { test('When an object is dropped into a notebook, a new entry is created and it should be focused @unstable', async ({
page
}) => {
// Create Overlay Plot // Create Overlay Plot
const overlayPlot = await createDomainObjectWithDefaults(page, { const overlayPlot = await createDomainObjectWithDefaults(page, {
type: 'Overlay Plot' type: 'Overlay Plot'
@ -280,7 +296,9 @@ test.describe('Notebook entry tests', () => {
// Reveal the notebook in the tree // Reveal the notebook in the tree
await page.getByTitle('Show selected item in tree').click(); await page.getByTitle('Show selected item in tree').click();
await page.getByRole('treeitem', { name: overlayPlot.name }).dragTo(page.locator('.c-notebook__drag-area')); await page
.getByRole('treeitem', { name: overlayPlot.name })
.dragTo(page.locator('.c-notebook__drag-area'));
const embed = page.locator('.c-ne__embed__link'); const embed = page.locator('.c-ne__embed__link');
const embedName = await embed.innerText(); const embedName = await embed.innerText();
@ -288,7 +306,9 @@ test.describe('Notebook entry tests', () => {
await expect(embed).toHaveClass(/icon-plot-overlay/); await expect(embed).toHaveClass(/icon-plot-overlay/);
expect(embedName).toBe(overlayPlot.name); expect(embedName).toBe(overlayPlot.name);
}); });
test('When an object is dropped into a notebooks existing entry, it should be focused @unstable', async ({ page }) => { test('When an object is dropped into a notebooks existing entry, it should be focused @unstable', async ({
page
}) => {
// Create Overlay Plot // Create Overlay Plot
const overlayPlot = await createDomainObjectWithDefaults(page, { const overlayPlot = await createDomainObjectWithDefaults(page, {
type: 'Overlay Plot' type: 'Overlay Plot'
@ -301,7 +321,9 @@ test.describe('Notebook entry tests', () => {
await page.getByTitle('Show selected item in tree').click(); await page.getByTitle('Show selected item in tree').click();
await nbUtils.enterTextEntry(page, 'Entry to drop into'); await nbUtils.enterTextEntry(page, 'Entry to drop into');
await page.getByRole('treeitem', { name: overlayPlot.name }).dragTo(page.locator('text=Entry to drop into')); await page
.getByRole('treeitem', { name: overlayPlot.name })
.dragTo(page.locator('text=Entry to drop into'));
const existingEntry = page.locator('.c-ne__content', { const existingEntry = page.locator('.c-ne__content', {
has: page.locator('text="Entry to drop into"') has: page.locator('text="Entry to drop into"')
@ -332,7 +354,9 @@ test.describe('Notebook entry tests', () => {
await expect(page.locator('text="Another First Entry"')).toBeVisible(); await expect(page.locator('text="Another First Entry"')).toBeVisible();
await expect(page.locator('text="Second Entry"')).toBeVisible(); await expect(page.locator('text="Second Entry"')).toBeVisible();
}); });
test('when a valid link is entered into a notebook entry, it becomes clickable when viewing', async ({ page }) => { test('when a valid link is entered into a notebook entry, it becomes clickable when viewing', async ({
page
}) => {
const TEST_LINK = 'http://www.google.com'; const TEST_LINK = 'http://www.google.com';
// Navigate to the notebook object // Navigate to the notebook object
@ -357,7 +381,9 @@ test.describe('Notebook entry tests', () => {
expect(await validLink.count()).toBe(1); expect(await validLink.count()).toBe(1);
}); });
test('when an invalid link is entered into a notebook entry, it does not become clickable when viewing', async ({ page }) => { test('when an invalid link is entered into a notebook entry, it does not become clickable when viewing', async ({
page
}) => {
const TEST_LINK = 'www.google.com'; const TEST_LINK = 'www.google.com';
// Navigate to the notebook object // Navigate to the notebook object
@ -372,7 +398,9 @@ test.describe('Notebook entry tests', () => {
expect(await invalidLink.count()).toBe(0); expect(await invalidLink.count()).toBe(0);
}); });
test('when a link is entered, but it is not in the whitelisted urls, it does not become clickable when viewing', async ({ page }) => { test('when a link is entered, but it is not in the whitelisted urls, it does not become clickable when viewing', async ({
page
}) => {
const TEST_LINK = 'http://www.bing.com'; const TEST_LINK = 'http://www.bing.com';
// Navigate to the notebook object // Navigate to the notebook object
@ -387,7 +415,9 @@ test.describe('Notebook entry tests', () => {
expect(await invalidLink.count()).toBe(0); expect(await invalidLink.count()).toBe(0);
}); });
test('when a valid link with a subdomain and a valid domain in the whitelisted urls is entered into a notebook entry, it becomes clickable when viewing', async ({ page }) => { test('when a valid link with a subdomain and a valid domain in the whitelisted urls is entered into a notebook entry, it becomes clickable when viewing', async ({
page
}) => {
const INVALID_TEST_LINK = 'http://bing.google.com'; const INVALID_TEST_LINK = 'http://bing.google.com';
// Navigate to the notebook object // Navigate to the notebook object
@ -402,7 +432,9 @@ test.describe('Notebook entry tests', () => {
expect(await validLink.count()).toBe(1); expect(await validLink.count()).toBe(1);
}); });
test('when a valid secure link is entered into a notebook entry, it becomes clickable when viewing', async ({ page }) => { test('when a valid secure link is entered into a notebook entry, it becomes clickable when viewing', async ({
page
}) => {
const TEST_LINK = 'https://www.google.com'; const TEST_LINK = 'https://www.google.com';
// Navigate to the notebook object // Navigate to the notebook object
@ -427,7 +459,9 @@ test.describe('Notebook entry tests', () => {
expect(await validLink.count()).toBe(1); expect(await validLink.count()).toBe(1);
}); });
test('when a nefarious link is entered into a notebook entry, it is sanitized when viewing', async ({ page }) => { test('when a nefarious link is entered into a notebook entry, it is sanitized when viewing', async ({
page
}) => {
const TEST_LINK = 'http://www.google.com?bad='; const TEST_LINK = 'http://www.google.com?bad=';
const TEST_LINK_BAD = `http://www.google.com?bad=<script>alert('gimme your cookies')</script>`; const TEST_LINK_BAD = `http://www.google.com?bad=<script>alert('gimme your cookies')</script>`;
@ -437,7 +471,10 @@ test.describe('Notebook entry tests', () => {
// Reveal the notebook in the tree // Reveal the notebook in the tree
await page.getByTitle('Show selected item in tree').click(); await page.getByTitle('Show selected item in tree').click();
await nbUtils.enterTextEntry(page, `This should be a link, BUT not a bad link: ${TEST_LINK_BAD} is it?`); await nbUtils.enterTextEntry(
page,
`This should be a link, BUT not a bad link: ${TEST_LINK_BAD} is it?`
);
const sanitizedLink = page.locator(`a[href="${TEST_LINK}"]`); const sanitizedLink = page.locator(`a[href="${TEST_LINK}"]`);
const unsanitizedLink = page.locator(`a[href="${TEST_LINK_BAD}"]`); const unsanitizedLink = page.locator(`a[href="${TEST_LINK_BAD}"]`);

View File

@ -29,14 +29,19 @@ const { test, expect } = require('../../../../pluginFixtures');
// const nbUtils = require('../../../../helper/notebookUtils'); // const nbUtils = require('../../../../helper/notebookUtils');
test.describe('Snapshot Menu tests', () => { test.describe('Snapshot Menu tests', () => {
test.fixme('When no default notebook is selected, Snapshot Menu dropdown should only have a single option', async ({ page }) => { test.fixme(
'When no default notebook is selected, Snapshot Menu dropdown should only have a single option',
async ({ page }) => {
// There should be no default notebook // There should be no default notebook
// Clear default notebook if exists using `localStorage.setItem('notebook-storage', null);` // Clear default notebook if exists using `localStorage.setItem('notebook-storage', null);`
// refresh page // refresh page
// Click on 'Notebook Snaphot Menu' // Click on 'Notebook Snaphot Menu'
// 'save to Notebook Snapshots' should be only option there // 'save to Notebook Snapshots' should be only option there
}); }
test.fixme('When default notebook is updated selected, Snapshot Menu dropdown should list it as the newest option', async ({ page }) => { );
test.fixme(
'When default notebook is updated selected, Snapshot Menu dropdown should list it as the newest option',
async ({ page }) => {
// Create 2a notebooks // Create 2a notebooks
// Set Notebook A as Default // Set Notebook A as Default
// Open Snapshot Menu and note that Notebook A is listed // Open Snapshot Menu and note that Notebook A is listed
@ -44,7 +49,8 @@ test.describe('Snapshot Menu tests', () => {
// Set Default Notebook to Notebook B // Set Default Notebook to Notebook B
// Open Snapshot Notebook and note that Notebook B is listed // Open Snapshot Notebook and note that Notebook B is listed
// Select Default Notebook Option and verify that Snapshot is added to Notebook B // Select Default Notebook Option and verify that Snapshot is added to Notebook B
}); }
);
test.fixme('Can add Snapshots via Snapshot Menu and details are correct', async ({ page }) => { test.fixme('Can add Snapshots via Snapshot Menu and details are correct', async ({ page }) => {
//Note this should be a visual test, too //Note this should be a visual test, too
// Create Telemetry object // Create Telemetry object
@ -82,12 +88,19 @@ test.describe('Snapshot Container tests', () => {
await page.getByRole('button', { name: ' Snapshot ' }).click(); await page.getByRole('button', { name: ' Snapshot ' }).click();
await page.getByRole('menuitem', { name: ' Save to Notebook Snapshots' }).click(); await page.getByRole('menuitem', { name: ' Save to Notebook Snapshots' }).click();
await page.getByRole('button', { name: 'Show' }).click(); await page.getByRole('button', { name: 'Show' }).click();
}); });
test.fixme('5 Snapshots can be added to a container', async ({ page }) => {}); test.fixme('5 Snapshots can be added to a container', async ({ page }) => {});
test.fixme('5 Snapshots can be added to a container and Deleted with Delete All action', async ({ page }) => {}); test.fixme(
test.fixme('A snapshot can be Deleted from Container with 3 dot action menu', async ({ page }) => {}); '5 Snapshots can be added to a container and Deleted with Delete All action',
test.fixme('A snapshot can be Viewed, Annotated, display deleted, and saved from Container with 3 dot action menu', async ({ page }) => { async ({ page }) => {}
);
test.fixme(
'A snapshot can be Deleted from Container with 3 dot action menu',
async ({ page }) => {}
);
test.fixme(
'A snapshot can be Viewed, Annotated, display deleted, and saved from Container with 3 dot action menu',
async ({ page }) => {
await page.locator('.c-snapshot.c-ne__embed').first().getByTitle('More options').click(); await page.locator('.c-snapshot.c-ne__embed').first().getByTitle('More options').click();
await page.getByRole('menuitem', { name: ' View Snapshot' }).click(); await page.getByRole('menuitem', { name: ' View Snapshot' }).click();
await expect(page.locator('.c-overlay__outer')).toBeVisible(); await expect(page.locator('.c-overlay__outer')).toBeVisible();
@ -98,16 +111,25 @@ test.describe('Snapshot Container tests', () => {
await page.getByRole('button', { name: 'Save' }).click(); await page.getByRole('button', { name: 'Save' }).click();
await page.getByRole('button', { name: 'Done' }).click(); await page.getByRole('button', { name: 'Done' }).click();
//await expect(await page.locator) //await expect(await page.locator)
}); }
);
test('A snapshot can be Quick Viewed from Container with 3 dot action menu', async ({ page }) => { test('A snapshot can be Quick Viewed from Container with 3 dot action menu', async ({ page }) => {
await page.locator('.c-snapshot.c-ne__embed').first().getByTitle('More options').click(); await page.locator('.c-snapshot.c-ne__embed').first().getByTitle('More options').click();
await page.getByRole('menuitem', { name: 'Quick View' }).click(); await page.getByRole('menuitem', { name: 'Quick View' }).click();
await expect(page.locator('.c-overlay__outer')).toBeVisible(); await expect(page.locator('.c-overlay__outer')).toBeVisible();
}); });
test.fixme('A snapshot can be Navigated To from Container with 3 dot action menu', async ({ page }) => {}); test.fixme(
test.fixme('A snapshot can be Navigated To Item in Time from Container with 3 dot action menu', async ({ page }) => {}); 'A snapshot can be Navigated To from Container with 3 dot action menu',
async ({ page }) => {}
);
test.fixme(
'A snapshot can be Navigated To Item in Time from Container with 3 dot action menu',
async ({ page }) => {}
);
test.fixme('A snapshot Container can be open and closed', async ({ page }) => {}); test.fixme('A snapshot Container can be open and closed', async ({ page }) => {});
test.fixme('Can add object to Snapshot container and pull into notebook and create a new entry', async ({ page }) => { test.fixme(
'Can add object to Snapshot container and pull into notebook and create a new entry',
async ({ page }) => {
//Create Notebook //Create Notebook
//Create Telemetry Object //Create Telemetry Object
//From Telemetry Object, use 'save to Notebook Snapshots' //From Telemetry Object, use 'save to Notebook Snapshots'
@ -116,8 +138,11 @@ test.describe('Snapshot Container tests', () => {
//Drag and Drop onto droppable area for new entry //Drag and Drop onto droppable area for new entry
//New Entry created with given snapshot added //New Entry created with given snapshot added
//Snapshot removed from container? //Snapshot removed from container?
}); }
test.fixme('Can add object to Snapshot container and pull into notebook and existing entry', async ({ page }) => { );
test.fixme(
'Can add object to Snapshot container and pull into notebook and existing entry',
async ({ page }) => {
//Create Notebook //Create Notebook
//Create Telemetry Object //Create Telemetry Object
//From Telemetry Object, use 'save to Notebook Snapshots' //From Telemetry Object, use 'save to Notebook Snapshots'
@ -126,9 +151,13 @@ test.describe('Snapshot Container tests', () => {
//Drag and Drop into exiting entry //Drag and Drop into exiting entry
//Existing Entry updated with given snapshot //Existing Entry updated with given snapshot
//Snapshot removed from container? //Snapshot removed from container?
}); }
test.fixme('Verify Embedded options for PNG, JPG, and Annotate work correctly', async ({ page }) => { );
test.fixme(
'Verify Embedded options for PNG, JPG, and Annotate work correctly',
async ({ page }) => {
//Add snapshot to container //Add snapshot to container
//Verify PNG, JPG, and Annotate buttons work correctly //Verify PNG, JPG, and Annotate buttons work correctly
}); }
);
}); });

View File

@ -36,8 +36,8 @@ test.describe('Notebook Tests with CouchDB @couchdb', () => {
await page.goto('./', { waitUntil: 'domcontentloaded' }); await page.goto('./', { waitUntil: 'domcontentloaded' });
// Create Notebook // Create Notebook
testNotebook = await createDomainObjectWithDefaults(page, {type: 'Notebook' }); testNotebook = await createDomainObjectWithDefaults(page, { type: 'Notebook' });
await page.goto(testNotebook.url, { waitUntil: 'networkidle'}); await page.goto(testNotebook.url, { waitUntil: 'networkidle' });
}); });
test('Inspect Notebook Entry Network Requests', async ({ page }) => { test('Inspect Notebook Entry Network Requests', async ({ page }) => {
@ -69,7 +69,9 @@ test.describe('Notebook Tests with CouchDB @couchdb', () => {
// Assert on request object // Assert on request object
expect(notebookUrlRequest.postDataJSON().metadata.name).toBe(testNotebook.name); expect(notebookUrlRequest.postDataJSON().metadata.name).toBe(testNotebook.name);
expect(notebookUrlRequest.postDataJSON().model.persisted).toBeGreaterThanOrEqual(notebookUrlRequest.postDataJSON().model.modified); expect(notebookUrlRequest.postDataJSON().model.persisted).toBeGreaterThanOrEqual(
notebookUrlRequest.postDataJSON().model.modified
);
expect(allDocsRequest.postDataJSON().keys).toContain(testNotebook.uuid); expect(allDocsRequest.postDataJSON().keys).toContain(testNotebook.uuid);
// Add an entry // Add an entry
@ -186,9 +188,11 @@ test.describe('Notebook Tests with CouchDB @couchdb', () => {
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click(); await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
//Partial match for "Science" should only return Science //Partial match for "Science" should only return Science
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Sc'); await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Sc');
await expect(page.locator('[aria-label="Search Result"]').first()).toContainText("Science"); await expect(page.locator('[aria-label="Search Result"]').first()).toContainText('Science');
await expect(page.locator('[aria-label="Search Result"]').first()).not.toContainText("Driving"); await expect(page.locator('[aria-label="Search Result"]').first()).not.toContainText('Driving');
await expect(page.locator('[aria-label="Search Result"]').first()).not.toContainText("Drilling"); await expect(page.locator('[aria-label="Search Result"]').first()).not.toContainText(
'Drilling'
);
//Searching for a tag which does not exist should return an empty result //Searching for a tag which does not exist should return an empty result
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click(); await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
@ -200,8 +204,8 @@ test.describe('Notebook Tests with CouchDB @couchdb', () => {
// Try to reduce indeterminism of browser requests by only returning fetch requests. // Try to reduce indeterminism of browser requests by only returning fetch requests.
// Filter out preflight CORS, fetching stylesheets, page icons, etc. that can occur during tests // Filter out preflight CORS, fetching stylesheets, page icons, etc. that can occur during tests
function filterNonFetchRequests(requests) { function filterNonFetchRequests(requests) {
return requests.filter(request => { return requests.filter((request) => {
return (request.resourceType() === 'fetch'); return request.resourceType() === 'fetch';
}); });
} }
@ -236,7 +240,9 @@ async function removeTagAndAwaitNetwork(page, tagName) {
await Promise.all([ await Promise.all([
page.locator(`[aria-label="Remove tag ${tagName}"]`).click(), page.locator(`[aria-label="Remove tag ${tagName}"]`).click(),
//With this pattern, we're awaiting the response but asserting on the request payload. //With this pattern, we're awaiting the response but asserting on the request payload.
page.waitForResponse(resp => resp.request().postData().includes(`"_deleted":true`) && resp.status() === 201) page.waitForResponse(
(resp) => resp.request().postData().includes(`"_deleted":true`) && resp.status() === 201
)
]); ]);
await expect(page.locator(`[aria-label="Tag"]:has-text("${tagName}")`)).toBeHidden(); await expect(page.locator(`[aria-label="Tag"]:has-text("${tagName}")`)).toBeHidden();
await page.waitForLoadState('networkidle'); await page.waitForLoadState('networkidle');

View File

@ -21,7 +21,10 @@
*****************************************************************************/ *****************************************************************************/
/* global __dirname */ /* global __dirname */
const { test, expect, streamToString } = require('../../../../pluginFixtures'); const { test, expect, streamToString } = require('../../../../pluginFixtures');
const { openObjectTreeContextMenu, createDomainObjectWithDefaults } = require('../../../../appActions'); const {
openObjectTreeContextMenu,
createDomainObjectWithDefaults
} = require('../../../../appActions');
const path = require('path'); const path = require('path');
const nbUtils = require('../../../../helper/notebookUtils'); const nbUtils = require('../../../../helper/notebookUtils');
@ -65,13 +68,11 @@ test.describe('Restricted Notebook', () => {
}); });
test('Can be locked if at least one page has one entry @addInit', async ({ page }) => { test('Can be locked if at least one page has one entry @addInit', async ({ page }) => {
await nbUtils.enterTextEntry(page, TEST_TEXT); await nbUtils.enterTextEntry(page, TEST_TEXT);
const commitButton = page.locator('button:has-text("Commit Entries")'); const commitButton = page.locator('button:has-text("Commit Entries")');
expect(await commitButton.count()).toEqual(1); expect(await commitButton.count()).toEqual(1);
}); });
}); });
test.describe('Restricted Notebook with at least one entry and with the page locked @addInit', () => { test.describe('Restricted Notebook with at least one entry and with the page locked @addInit', () => {
@ -85,11 +86,15 @@ test.describe('Restricted Notebook with at least one entry and with the page loc
await page.locator('button.c-notebook__toggle-nav-button').click(); await page.locator('button.c-notebook__toggle-nav-button').click();
}); });
test('Locked page should now be in a locked state @addInit @unstable', async ({ page }, testInfo) => { test('Locked page should now be in a locked state @addInit @unstable', async ({
page
}, testInfo) => {
// eslint-disable-next-line playwright/no-skipped-test // eslint-disable-next-line playwright/no-skipped-test
test.skip(testInfo.project === 'chrome-beta', "Test is unreliable on chrome-beta"); test.skip(testInfo.project === 'chrome-beta', 'Test is unreliable on chrome-beta');
// main lock message on page // main lock message on page
const lockMessage = page.locator('text=This page has been committed and cannot be modified or removed'); const lockMessage = page.locator(
'text=This page has been committed and cannot be modified or removed'
);
expect.soft(await lockMessage.count()).toEqual(1); expect.soft(await lockMessage.count()).toEqual(1);
// lock icon on page in sidebar // lock icon on page in sidebar
@ -103,7 +108,9 @@ test.describe('Restricted Notebook with at least one entry and with the page loc
await expect(menuOptions).not.toContainText('Remove'); await expect(menuOptions).not.toContainText('Remove');
}); });
test('Can still: add page, rename, add entry, delete unlocked pages @addInit', async ({ page }) => { test('Can still: add page, rename, add entry, delete unlocked pages @addInit', async ({
page
}) => {
// Add a new page to the section // Add a new page to the section
await page.getByRole('button', { name: 'Add Page' }).click(); await page.getByRole('button', { name: 'Add Page' }).click();
// Focus the new page by clicking it // Focus the new page by clicking it
@ -138,7 +145,6 @@ test.describe('Restricted Notebook with at least one entry and with the page loc
}); });
test.describe('Restricted Notebook with a page locked and with an embed @addInit', () => { test.describe('Restricted Notebook with a page locked and with an embed @addInit', () => {
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
const notebook = await startAndAddRestrictedNotebookObject(page); const notebook = await startAndAddRestrictedNotebookObject(page);
await nbUtils.dragAndDropEmbed(page, notebook); await nbUtils.dragAndDropEmbed(page, notebook);
@ -160,7 +166,6 @@ test.describe('Restricted Notebook with a page locked and with an embed @addInit
const embedMenu = page.locator('body >> .c-menu'); const embedMenu = page.locator('body >> .c-menu');
await expect(embedMenu).not.toContainText('Remove This Embed'); await expect(embedMenu).not.toContainText('Remove This Embed');
}); });
}); });
test.describe('can export restricted notebook as text', () => { test.describe('can export restricted notebook as text', () => {
@ -181,7 +186,6 @@ test.describe('can export restricted notebook as text', () => {
const readStream = await download.createReadStream(); const readStream = await download.createReadStream();
const exportedText = await streamToString(readStream); const exportedText = await streamToString(readStream);
expect(exportedText).toContain('Foo bar entry'); expect(exportedText).toContain('Foo bar entry');
}); });
test.fixme('can export multiple notebook entries as text ', async ({ page }) => {}); test.fixme('can export multiple notebook entries as text ', async ({ page }) => {});
@ -194,7 +198,9 @@ test.describe('can export restricted notebook as text', () => {
* @param {import('@playwright/test').Page} page * @param {import('@playwright/test').Page} page
*/ */
async function startAndAddRestrictedNotebookObject(page) { async function startAndAddRestrictedNotebookObject(page) {
await page.addInitScript({ path: path.join(__dirname, '../../../../helper/', 'addInitRestrictedNotebook.js') }); await page.addInitScript({
path: path.join(__dirname, '../../../../helper/', 'addInitRestrictedNotebook.js')
});
await page.goto('./', { waitUntil: 'domcontentloaded' }); await page.goto('./', { waitUntil: 'domcontentloaded' });
return createDomainObjectWithDefaults(page, { type: CUSTOM_NAME }); return createDomainObjectWithDefaults(page, { type: CUSTOM_NAME });

View File

@ -91,22 +91,22 @@ test.describe('Tagging in Notebooks @addInit', () => {
await page.locator('[placeholder="Type to select tag"]').click(); await page.locator('[placeholder="Type to select tag"]').click();
await expect(page.locator('[aria-label="Autocomplete Options"]')).toContainText("Science"); await expect(page.locator('[aria-label="Autocomplete Options"]')).toContainText('Science');
await expect(page.locator('[aria-label="Autocomplete Options"]')).toContainText("Drilling"); await expect(page.locator('[aria-label="Autocomplete Options"]')).toContainText('Drilling');
await expect(page.locator('[aria-label="Autocomplete Options"]')).toContainText("Driving"); await expect(page.locator('[aria-label="Autocomplete Options"]')).toContainText('Driving');
}); });
test('Can add tags', async ({ page }) => { test('Can add tags', async ({ page }) => {
await createNotebookEntryAndTags(page); await createNotebookEntryAndTags(page);
await expect(page.locator('[aria-label="Notebook Entry"]')).toContainText("Science"); await expect(page.locator('[aria-label="Notebook Entry"]')).toContainText('Science');
await expect(page.locator('[aria-label="Notebook Entry"]')).toContainText("Driving"); await expect(page.locator('[aria-label="Notebook Entry"]')).toContainText('Driving');
await page.locator('button:has-text("Add Tag")').click(); await page.locator('button:has-text("Add Tag")').click();
await page.locator('[placeholder="Type to select tag"]').click(); await page.locator('[placeholder="Type to select tag"]').click();
await expect(page.locator('[aria-label="Autocomplete Options"]')).not.toContainText("Science"); await expect(page.locator('[aria-label="Autocomplete Options"]')).not.toContainText('Science');
await expect(page.locator('[aria-label="Autocomplete Options"]')).not.toContainText("Driving"); await expect(page.locator('[aria-label="Autocomplete Options"]')).not.toContainText('Driving');
await expect(page.locator('[aria-label="Autocomplete Options"]')).toContainText("Drilling"); await expect(page.locator('[aria-label="Autocomplete Options"]')).toContainText('Drilling');
}); });
test('Can add tags with blank entry', async ({ page }) => { test('Can add tags with blank entry', async ({ page }) => {
await createDomainObjectWithDefaults(page, { type: 'Notebook' }); await createDomainObjectWithDefaults(page, { type: 'Notebook' });
@ -121,7 +121,7 @@ test.describe('Tagging in Notebooks @addInit', () => {
// Select the "Driving" tag // Select the "Driving" tag
await page.locator('[aria-label="Autocomplete Options"] >> text=Driving').click(); await page.locator('[aria-label="Autocomplete Options"] >> text=Driving').click();
await expect(page.locator('[aria-label="Notebook Entry"]')).toContainText("Driving"); await expect(page.locator('[aria-label="Notebook Entry"]')).toContainText('Driving');
}); });
test('Can cancel adding tags', async ({ page }) => { test('Can cancel adding tags', async ({ page }) => {
await createNotebookAndEntry(page); await createNotebookAndEntry(page);
@ -148,13 +148,13 @@ test.describe('Tagging in Notebooks @addInit', () => {
await createNotebookEntryAndTags(page); await createNotebookEntryAndTags(page);
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click(); await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('sc'); await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('sc');
await expect(page.locator('[aria-label="Search Result"]')).toContainText("Science"); await expect(page.locator('[aria-label="Search Result"]')).toContainText('Science');
await expect(page.locator('[aria-label="Search Result"]')).not.toContainText("Driving"); await expect(page.locator('[aria-label="Search Result"]')).not.toContainText('Driving');
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click(); await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Sc'); await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Sc');
await expect(page.locator('[aria-label="Search Result"]')).toContainText("Science"); await expect(page.locator('[aria-label="Search Result"]')).toContainText('Science');
await expect(page.locator('[aria-label="Search Result"]')).not.toContainText("Driving"); await expect(page.locator('[aria-label="Search Result"]')).not.toContainText('Driving');
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click(); await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Xq'); await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Xq');
@ -169,7 +169,7 @@ test.describe('Tagging in Notebooks @addInit', () => {
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click(); await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Sc'); await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Sc');
await expect(page.locator('[aria-label="Search Result"]')).toContainText("Science"); await expect(page.locator('[aria-label="Search Result"]')).toContainText('Science');
await page.getByText('Entry 0').click(); await page.getByText('Entry 0').click();
await expect(page.locator('.js-preview-window')).toBeVisible(); await expect(page.locator('.js-preview-window')).toBeVisible();
}); });
@ -180,11 +180,11 @@ test.describe('Tagging in Notebooks @addInit', () => {
await page.hover('[aria-label="Tag"]:has-text("Driving")'); await page.hover('[aria-label="Tag"]:has-text("Driving")');
await page.locator('[aria-label="Remove tag Driving"]').click(); await page.locator('[aria-label="Remove tag Driving"]').click();
await expect(page.locator('[aria-label="Tags Inspector"]')).toContainText("Science"); await expect(page.locator('[aria-label="Tags Inspector"]')).toContainText('Science');
await expect(page.locator('[aria-label="Tags Inspector"]')).not.toContainText("Driving"); await expect(page.locator('[aria-label="Tags Inspector"]')).not.toContainText('Driving');
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('sc'); await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('sc');
await expect(page.locator('[aria-label="Search Result"]')).not.toContainText("Driving"); await expect(page.locator('[aria-label="Search Result"]')).not.toContainText('Driving');
}); });
test('Can delete entries without tags', async ({ page }) => { test('Can delete entries without tags', async ({ page }) => {
@ -203,9 +203,13 @@ test.describe('Tagging in Notebooks @addInit', () => {
await page.hover('[aria-label="Notebook Entry Input"] >> nth=1'); await page.hover('[aria-label="Notebook Entry Input"] >> nth=1');
await page.locator('button[title="Delete this entry"]').last().click(); await page.locator('button[title="Delete this entry"]').last().click();
await expect(page.locator('text=This action will permanently delete this entry. Do you wish to continue?')).toBeVisible(); await expect(
page.locator('text=This action will permanently delete this entry. Do you wish to continue?')
).toBeVisible();
await page.locator('button:has-text("Ok")').click(); await page.locator('button:has-text("Ok")').click();
await expect(page.locator('text=This action will permanently delete this entry. Do you wish to continue?')).toBeHidden(); await expect(
page.locator('text=This action will permanently delete this entry. Do you wish to continue?')
).toBeHidden();
}); });
test('Can delete objects with tags and neither return in search', async ({ page }) => { test('Can delete objects with tags and neither return in search', async ({ page }) => {
@ -234,8 +238,8 @@ test.describe('Tagging in Notebooks @addInit', () => {
// Verify tags are present // Verify tags are present
for (let iteration = 0; iteration < ITERATIONS; iteration++) { for (let iteration = 0; iteration < ITERATIONS; iteration++) {
const entryLocator = `[aria-label="Notebook Entry"] >> nth = ${iteration}`; const entryLocator = `[aria-label="Notebook Entry"] >> nth = ${iteration}`;
await expect(page.locator(entryLocator)).toContainText("Science"); await expect(page.locator(entryLocator)).toContainText('Science');
await expect(page.locator(entryLocator)).toContainText("Driving"); await expect(page.locator(entryLocator)).toContainText('Driving');
} }
//Reload Page //Reload Page
@ -244,8 +248,8 @@ test.describe('Tagging in Notebooks @addInit', () => {
// Verify tags persist across reload // Verify tags persist across reload
for (let iteration = 0; iteration < ITERATIONS; iteration++) { for (let iteration = 0; iteration < ITERATIONS; iteration++) {
const entryLocator = `[aria-label="Notebook Entry"] >> nth = ${iteration}`; const entryLocator = `[aria-label="Notebook Entry"] >> nth = ${iteration}`;
await expect(page.locator(entryLocator)).toContainText("Science"); await expect(page.locator(entryLocator)).toContainText('Science');
await expect(page.locator(entryLocator)).toContainText("Driving"); await expect(page.locator(entryLocator)).toContainText('Driving');
} }
}); });
test('Can cancel adding a tag', async ({ page }) => { test('Can cancel adding a tag', async ({ page }) => {

View File

@ -21,8 +21,8 @@
*****************************************************************************/ *****************************************************************************/
/* global __dirname */ /* global __dirname */
/* /*
* This test suite is dedicated to testing the operator status plugin. * This test suite is dedicated to testing the operator status plugin.
*/ */
const path = require('path'); const path = require('path');
const { test, expect } = require('../../../../pluginFixtures'); const { test, expect } = require('../../../../pluginFixtures');
@ -40,8 +40,12 @@ STUB (test.fixme) Rolling through each
test.describe('Operator Status', () => { test.describe('Operator Status', () => {
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
// FIXME: determine if plugins will be added to index.html or need to be injected // FIXME: determine if plugins will be added to index.html or need to be injected
await page.addInitScript({ path: path.join(__dirname, '../../../../helper/', 'addInitExampleUser.js')}); await page.addInitScript({
await page.addInitScript({ path: path.join(__dirname, '../../../../helper/', 'addInitOperatorStatus.js')}); path: path.join(__dirname, '../../../../helper/', 'addInitExampleUser.js')
});
await page.addInitScript({
path: path.join(__dirname, '../../../../helper/', 'addInitOperatorStatus.js')
});
await page.goto('./', { waitUntil: 'domcontentloaded' }); await page.goto('./', { waitUntil: 'domcontentloaded' });
}); });
@ -76,7 +80,7 @@ test.describe('Operator Status', () => {
// get selected status value // get selected status value
const selectStatus = page.locator('select[name="setStatus"]'); const selectStatus = page.locator('select[name="setStatus"]');
await selectStatus.selectOption({ index: 1}); await selectStatus.selectOption({ index: 1 });
const initialStatusValue = await selectStatus.inputValue(); const initialStatusValue = await selectStatus.inputValue();
// open manage status poll // open manage status poll
@ -88,13 +92,14 @@ test.describe('Operator Status', () => {
const rowValuesArr = rowValues.split('\t'); const rowValuesArr = rowValues.split('\t');
const COLUMN_STATUS_INDEX = 1; const COLUMN_STATUS_INDEX = 1;
// check initial set value matches status table // check initial set value matches status table
expect(rowValuesArr[COLUMN_STATUS_INDEX].toLowerCase()) expect(rowValuesArr[COLUMN_STATUS_INDEX].toLowerCase()).toEqual(
.toEqual(initialStatusValue.toLowerCase()); initialStatusValue.toLowerCase()
);
// change user status // change user status
await statusPollIndicator.click(); await statusPollIndicator.click();
// FIXME: might want to grab a dynamic option instead of arbitrary // FIXME: might want to grab a dynamic option instead of arbitrary
await page.locator('select[name="setStatus"]').selectOption({ index: 2}); await page.locator('select[name="setStatus"]').selectOption({ index: 2 });
const updatedStatusValue = await selectStatus.inputValue(); const updatedStatusValue = await selectStatus.inputValue();
// verify user status is reflected in table // verify user status is reflected in table
await manageStatusPollIndicator.click(); await manageStatusPollIndicator.click();
@ -103,9 +108,9 @@ test.describe('Operator Status', () => {
const updatedRowValues = await updatedRow.innerText(); const updatedRowValues = await updatedRow.innerText();
const updatedRowValuesArr = updatedRowValues.split('\t'); const updatedRowValuesArr = updatedRowValues.split('\t');
expect(updatedRowValuesArr[COLUMN_STATUS_INDEX].toLowerCase()) expect(updatedRowValuesArr[COLUMN_STATUS_INDEX].toLowerCase()).toEqual(
.toEqual(updatedStatusValue.toLowerCase()); updatedStatusValue.toLowerCase()
);
}); });
test('clear poll button removes poll responses', async ({ page }) => { test('clear poll button removes poll responses', async ({ page }) => {
@ -120,7 +125,7 @@ test.describe('Operator Status', () => {
// get selected status value // get selected status value
const selectStatus = page.locator('select[name="setStatus"]'); const selectStatus = page.locator('select[name="setStatus"]');
// FIXME: might want to grab a dynamic option instead of arbitrary // FIXME: might want to grab a dynamic option instead of arbitrary
await selectStatus.selectOption({ index: 1}); await selectStatus.selectOption({ index: 1 });
const initialStatusValue = await selectStatus.inputValue(); const initialStatusValue = await selectStatus.inputValue();
// open manage status poll // open manage status poll
@ -132,8 +137,9 @@ test.describe('Operator Status', () => {
const rowValuesArr = rowValues.split('\t'); const rowValuesArr = rowValues.split('\t');
const COLUMN_STATUS_INDEX = 1; const COLUMN_STATUS_INDEX = 1;
// check initial set value matches status table // check initial set value matches status table
expect(rowValuesArr[COLUMN_STATUS_INDEX].toLowerCase()) expect(rowValuesArr[COLUMN_STATUS_INDEX].toLowerCase()).toEqual(
.toEqual(initialStatusValue.toLowerCase()); initialStatusValue.toLowerCase()
);
// clear the poll // clear the poll
await page.locator('button[title="Clear the previous poll question"]').click(); await page.locator('button[title="Clear the previous poll question"]').click();
@ -142,13 +148,10 @@ test.describe('Operator Status', () => {
const updatedRowValues = await updatedRow.innerText(); const updatedRowValues = await updatedRow.innerText();
const updatedRowValuesArr = updatedRowValues.split('\t'); const updatedRowValuesArr = updatedRowValues.split('\t');
const UNSET_VALUE_LABEL = 'Not set'; const UNSET_VALUE_LABEL = 'Not set';
expect(updatedRowValuesArr[COLUMN_STATUS_INDEX]) expect(updatedRowValuesArr[COLUMN_STATUS_INDEX]).toEqual(UNSET_VALUE_LABEL);
.toEqual(UNSET_VALUE_LABEL);
}); });
test.fixme('iterate through all possible response values', async ({ page }) => { test.fixme('iterate through all possible response values', async ({ page }) => {
// test all possible respone values for the poll // test all possible respone values for the poll
}); });
}); });

View File

@ -65,17 +65,29 @@ test.describe('Autoscale', () => {
]); ]);
//Wait until Save Banner is gone //Wait until Save Banner is gone
await page.locator('.c-message-banner__close-button').click(); await page.locator('.c-message-banner__close-button').click();
await page.waitForSelector('.c-message-banner__message', { state: 'detached'}); await page.waitForSelector('.c-message-banner__message', { state: 'detached' });
// Make sure that after turning off autoscale, the user entered range values are reflexted in the ticks. // Make sure that after turning off autoscale, the user entered range values are reflexted in the ticks.
await testYTicks(page, ['-2.00', '-1.50', '-1.00', '-0.50', '0.00', '0.50', '1.00', '1.50', '2.00']); await testYTicks(page, [
'-2.00',
'-1.50',
'-1.00',
'-0.50',
'0.00',
'0.50',
'1.00',
'1.50',
'2.00'
]);
const canvas = page.locator('canvas').nth(1); const canvas = page.locator('canvas').nth(1);
await canvas.hover({trial: true}); await canvas.hover({ trial: true });
await expect(page.locator('.js-series-data-loaded')).toBeVisible(); await expect(page.locator('.js-series-data-loaded')).toBeVisible();
expect.soft(await canvas.screenshot()).toMatchSnapshot('autoscale-canvas-prepan.png', { animations: 'disabled' }); expect
.soft(await canvas.screenshot())
.toMatchSnapshot('autoscale-canvas-prepan.png', { animations: 'disabled' });
//Alt Drag Start //Alt Drag Start
await page.keyboard.down('Alt'); await page.keyboard.down('Alt');
@ -98,9 +110,11 @@ test.describe('Autoscale', () => {
await testYTicks(page, ['0.00', '0.50', '1.00', '1.50', '2.00', '2.50', '3.00', '3.50']); await testYTicks(page, ['0.00', '0.50', '1.00', '1.50', '2.00', '2.50', '3.00', '3.50']);
//Wait for canvas to stablize. //Wait for canvas to stablize.
await canvas.hover({trial: true}); await canvas.hover({ trial: true });
expect.soft(await canvas.screenshot()).toMatchSnapshot('autoscale-canvas-panned.png', { animations: 'disabled' }); expect
.soft(await canvas.screenshot())
.toMatchSnapshot('autoscale-canvas-panned.png', { animations: 'disabled' });
}); });
}); });
@ -109,7 +123,11 @@ test.describe('Autoscale', () => {
* @param {string} start * @param {string} start
* @param {string} end * @param {string} end
*/ */
async function setTimeRange(page, start = '2022-03-29 22:00:00.000Z', end = '2022-03-29 22:00:30.000Z') { async function setTimeRange(
page,
start = '2022-03-29 22:00:00.000Z',
end = '2022-03-29 22:00:30.000Z'
) {
// Set a specific time range for consistency, otherwise it will change // Set a specific time range for consistency, otherwise it will change
// on every test to a range based on the current time. // on every test to a range based on the current time.
@ -139,10 +157,13 @@ async function createSinewaveOverlayPlot(page, myItemsFolderName) {
]); ]);
//Wait until Save Banner is gone //Wait until Save Banner is gone
await page.locator('.c-message-banner__close-button').click(); await page.locator('.c-message-banner__close-button').click();
await page.waitForSelector('.c-message-banner__message', { state: 'detached'}); await page.waitForSelector('.c-message-banner__message', { state: 'detached' });
// save (exit edit mode) // save (exit edit mode)
await page.locator('text=Snapshot Save and Finish Editing Save and Continue Editing >> button').nth(1).click(); await page
.locator('text=Snapshot Save and Finish Editing Save and Continue Editing >> button')
.nth(1)
.click();
await page.locator('text=Save and Finish Editing').click(); await page.locator('text=Save and Finish Editing').click();
// click create button // click create button
@ -158,7 +179,7 @@ async function createSinewaveOverlayPlot(page, myItemsFolderName) {
]); ]);
//Wait until Save Banner is gone //Wait until Save Banner is gone
await page.locator('.c-message-banner__close-button').click(); await page.locator('.c-message-banner__close-button').click();
await page.waitForSelector('.c-message-banner__message', { state: 'detached'}); await page.waitForSelector('.c-message-banner__message', { state: 'detached' });
// focus the overlay plot // focus the overlay plot
await page.locator(`text=Open MCT ${myItemsFolderName} >> span`).nth(3).click(); await page.locator(`text=Open MCT ${myItemsFolderName} >> span`).nth(3).click();
@ -194,7 +215,7 @@ async function setUserDefinedMinAndMax(page, min, max) {
async function testYTicks(page, values) { async function testYTicks(page, values) {
const yTicks = page.locator('.gl-plot-y-tick-label'); const yTicks = page.locator('.gl-plot-y-tick-label');
await page.locator('canvas >> nth=1').hover(); await page.locator('canvas >> nth=1').hover();
let promises = [yTicks.count().then(c => expect(c).toBe(values.length))]; let promises = [yTicks.count().then((c) => expect(c).toBe(values.length))];
for (let i = 0, l = values.length; i < l; i += 1) { for (let i = 0, l = values.length; i < l; i += 1) {
promises.push(expect.soft(yTicks.nth(i)).toHaveText(values[i])); // eslint-disable-line promises.push(expect.soft(yTicks.nth(i)).toHaveText(values[i])); // eslint-disable-line

View File

@ -29,7 +29,10 @@ const { test, expect } = require('../../../../pluginFixtures');
const { selectInspectorTab } = require('../../../../appActions'); const { selectInspectorTab } = require('../../../../appActions');
test.describe('Log plot tests', () => { test.describe('Log plot tests', () => {
test('Log Plot ticks are functionally correct in regular and log mode and after refresh', async ({ page, openmctConfig }) => { test('Log Plot ticks are functionally correct in regular and log mode and after refresh', async ({
page,
openmctConfig
}) => {
const { myItemsFolderName } = openmctConfig; const { myItemsFolderName } = openmctConfig;
//Test.slow decorator is currently broken. Needs to be fixed in https://github.com/nasa/openmct/issues/5374 //Test.slow decorator is currently broken. Needs to be fixed in https://github.com/nasa/openmct/issues/5374
@ -51,7 +54,9 @@ test.describe('Log plot tests', () => {
// Leaving test as 'TODO' for now. // Leaving test as 'TODO' for now.
// NOTE: Not eligible for community contributions. // NOTE: Not eligible for community contributions.
test.fixme('Verify that log mode option is reflected in import/export JSON', async ({ page, openmctConfig }) => { test.fixme(
'Verify that log mode option is reflected in import/export JSON',
async ({ page, openmctConfig }) => {
const { myItemsFolderName } = openmctConfig; const { myItemsFolderName } = openmctConfig;
await makeOverlayPlot(page, myItemsFolderName); await makeOverlayPlot(page, myItemsFolderName);
@ -66,7 +71,8 @@ test.describe('Log plot tests', () => {
// TODO, the plot is slightly at different position that in the other test, so this fails. // TODO, the plot is slightly at different position that in the other test, so this fails.
// ...We can fix it by copying all steps from the first test... // ...We can fix it by copying all steps from the first test...
// await testLogPlotPixels(page); // await testLogPlotPixels(page);
}); }
);
}); });
/** /**
@ -93,14 +99,14 @@ async function makeOverlayPlot(page, myItemsFolderName) {
await page.locator('button.c-create-button').click(); await page.locator('button.c-create-button').click();
await page.locator('li[role="menuitem"]:has-text("Overlay Plot")').click(); await page.locator('li[role="menuitem"]:has-text("Overlay Plot")').click();
await Promise.all([ await Promise.all([
page.waitForNavigation({ waitUntil: 'networkidle'}), page.waitForNavigation({ waitUntil: 'networkidle' }),
page.locator('button:has-text("OK")').click(), page.locator('button:has-text("OK")').click(),
//Wait for Save Banner to appear //Wait for Save Banner to appear
page.waitForSelector('.c-message-banner__message') page.waitForSelector('.c-message-banner__message')
]); ]);
//Wait until Save Banner is gone //Wait until Save Banner is gone
await page.locator('.c-message-banner__close-button').click(); await page.locator('.c-message-banner__close-button').click();
await page.waitForSelector('.c-message-banner__message', { state: 'detached'}); await page.waitForSelector('.c-message-banner__message', { state: 'detached' });
// save the overlay plot // save the overlay plot
@ -125,14 +131,14 @@ async function makeOverlayPlot(page, myItemsFolderName) {
// Click OK to make generator // Click OK to make generator
await Promise.all([ await Promise.all([
page.waitForNavigation({ waitUntil: 'networkidle'}), page.waitForNavigation({ waitUntil: 'networkidle' }),
page.locator('button:has-text("OK")').click(), page.locator('button:has-text("OK")').click(),
//Wait for Save Banner to appear //Wait for Save Banner to appear
page.waitForSelector('.c-message-banner__message') page.waitForSelector('.c-message-banner__message')
]); ]);
//Wait until Save Banner is gone //Wait until Save Banner is gone
await page.locator('.c-message-banner__close-button').click(); await page.locator('.c-message-banner__close-button').click();
await page.waitForSelector('.c-message-banner__message', { state: 'detached'}); await page.waitForSelector('.c-message-banner__message', { state: 'detached' });
// click on overlay plot // click on overlay plot
@ -205,7 +211,10 @@ async function disableLogMode(page) {
*/ */
async function saveOverlayPlot(page) { async function saveOverlayPlot(page) {
// save overlay plot // save overlay plot
await page.locator('text=Snapshot Save and Finish Editing Save and Continue Editing >> button').nth(1).click(); await page
.locator('text=Snapshot Save and Finish Editing Save and Continue Editing >> button')
.nth(1)
.click();
await Promise.all([ await Promise.all([
page.locator('text=Save and Finish Editing').click(), page.locator('text=Save and Finish Editing').click(),

View File

@ -27,14 +27,18 @@ Tests to verify log plot functionality when objects are missing
const { test, expect } = require('../../../../pluginFixtures'); const { test, expect } = require('../../../../pluginFixtures');
test.describe('Handle missing object for plots', () => { test.describe('Handle missing object for plots', () => {
test('Displays empty div for missing stacked plot item @unstable', async ({ page, browserName, openmctConfig }) => { test('Displays empty div for missing stacked plot item @unstable', async ({
page,
browserName,
openmctConfig
}) => {
// eslint-disable-next-line playwright/no-skipped-test // eslint-disable-next-line playwright/no-skipped-test
test.skip(browserName === 'firefox', 'Firefox failing due to console events being missed'); test.skip(browserName === 'firefox', 'Firefox failing due to console events being missed');
const { myItemsFolderName } = openmctConfig; const { myItemsFolderName } = openmctConfig;
const errorLogs = []; const errorLogs = [];
page.on("console", (message) => { page.on('console', (message) => {
if (message.type() === 'warning' && message.text().includes('Missing domain object')) { if (message.type() === 'warning' && message.text().includes('Missing domain object')) {
errorLogs.push(message.text()); errorLogs.push(message.text());
} }
@ -52,18 +56,15 @@ test.describe('Handle missing object for plots', () => {
delete parsedData[lastKey]; delete parsedData[lastKey];
//Sets local storage with missing object //Sets local storage with missing object
await page.evaluate( await page.evaluate(`window.localStorage.setItem('mct', '${JSON.stringify(parsedData)}')`);
`window.localStorage.setItem('mct', '${JSON.stringify(parsedData)}')`
);
//Reloads page and clicks on stacked plot //Reloads page and clicks on stacked plot
await Promise.all([ await Promise.all([page.reload(), page.waitForLoadState('networkidle')]);
page.reload(),
page.waitForLoadState('networkidle')
]);
//Verify Main section is there on load //Verify Main section is there on load
await expect.soft(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Stacked Plot'); await expect
.soft(page.locator('.l-browse-bar__object-name'))
.toContainText('Unnamed Stacked Plot');
await page.locator(`text=Open MCT ${myItemsFolderName} >> span`).nth(3).click(); await page.locator(`text=Open MCT ${myItemsFolderName} >> span`).nth(3).click();
await Promise.all([ await Promise.all([
@ -72,7 +73,7 @@ test.describe('Handle missing object for plots', () => {
]); ]);
//Check that there is only one stacked item plot with a plot, the missing one will be empty //Check that there is only one stacked item plot with a plot, the missing one will be empty
await expect(page.locator(".c-plot--stacked-container:has(.gl-plot)")).toHaveCount(1); await expect(page.locator('.c-plot--stacked-container:has(.gl-plot)')).toHaveCount(1);
//Verify that console.warn is thrown //Verify that console.warn is thrown
expect(errorLogs).toHaveLength(1); expect(errorLogs).toHaveLength(1);
}); });
@ -91,7 +92,7 @@ async function makeStackedPlot(page, myItemsFolderName) {
await page.locator('li[role="menuitem"]:has-text("Stacked Plot")').click(); await page.locator('li[role="menuitem"]:has-text("Stacked Plot")').click();
await Promise.all([ await Promise.all([
page.waitForNavigation({ waitUntil: 'networkidle'}), page.waitForNavigation({ waitUntil: 'networkidle' }),
page.locator('button:has-text("OK")').click(), page.locator('button:has-text("OK")').click(),
//Wait for Save Banner to appear //Wait for Save Banner to appear
page.waitForSelector('.c-message-banner__message') page.waitForSelector('.c-message-banner__message')
@ -127,7 +128,10 @@ async function makeStackedPlot(page, myItemsFolderName) {
*/ */
async function saveStackedPlot(page) { async function saveStackedPlot(page) {
// save stacked plot // save stacked plot
await page.locator('text=Snapshot Save and Finish Editing Save and Continue Editing >> button').nth(1).click(); await page
.locator('text=Snapshot Save and Finish Editing Save and Continue Editing >> button')
.nth(1)
.click();
await Promise.all([ await Promise.all([
page.locator('text=Save and Finish Editing').click(), page.locator('text=Save and Finish Editing').click(),
@ -149,7 +153,7 @@ async function createSineWaveGenerator(page) {
await page.locator('li[role="menuitem"]:has-text("Sine Wave Generator")').click(); await page.locator('li[role="menuitem"]:has-text("Sine Wave Generator")').click();
await Promise.all([ await Promise.all([
page.waitForNavigation({ waitUntil: 'networkidle'}), page.waitForNavigation({ waitUntil: 'networkidle' }),
page.locator('button:has-text("OK")').click(), page.locator('button:has-text("OK")').click(),
//Wait for Save Banner to appear //Wait for Save Banner to appear
page.waitForSelector('.c-message-banner__message') page.waitForSelector('.c-message-banner__message')

View File

@ -26,7 +26,12 @@ necessarily be used for reference when writing new tests in this area.
*/ */
const { test, expect } = require('../../../../pluginFixtures'); const { test, expect } = require('../../../../pluginFixtures');
const { createDomainObjectWithDefaults, getCanvasPixels, selectInspectorTab, waitForPlotsToRender } = require('../../../../appActions'); const {
createDomainObjectWithDefaults,
getCanvasPixels,
selectInspectorTab,
waitForPlotsToRender
} = require('../../../../appActions');
test.describe('Overlay Plot', () => { test.describe('Overlay Plot', () => {
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
@ -35,11 +40,11 @@ test.describe('Overlay Plot', () => {
test('Plot legend color is in sync with plot series color', async ({ page }) => { test('Plot legend color is in sync with plot series color', async ({ page }) => {
const overlayPlot = await createDomainObjectWithDefaults(page, { const overlayPlot = await createDomainObjectWithDefaults(page, {
type: "Overlay Plot" type: 'Overlay Plot'
}); });
await createDomainObjectWithDefaults(page, { await createDomainObjectWithDefaults(page, {
type: "Sine Wave Generator", type: 'Sine Wave Generator',
parent: overlayPlot.uuid parent: overlayPlot.uuid
}); });
@ -53,22 +58,26 @@ test.describe('Overlay Plot', () => {
await page.locator('.c-click-swatch--menu').click(); await page.locator('.c-click-swatch--menu').click();
await page.locator('.c-palette__item[style="background: rgb(255, 166, 61);"]').click(); await page.locator('.c-palette__item[style="background: rgb(255, 166, 61);"]').click();
// gets color for swatch located in legend // gets color for swatch located in legend
const seriesColorSwatch = page.locator('.gl-plot-y-label-swatch-container > .plot-series-color-swatch'); const seriesColorSwatch = page.locator(
'.gl-plot-y-label-swatch-container > .plot-series-color-swatch'
);
await expect(seriesColorSwatch).toHaveCSS('background-color', 'rgb(255, 166, 61)'); await expect(seriesColorSwatch).toHaveCSS('background-color', 'rgb(255, 166, 61)');
}); });
test('Limit lines persist when series is moved to another Y Axis and on refresh', async ({ page }) => { test('Limit lines persist when series is moved to another Y Axis and on refresh', async ({
page
}) => {
test.info().annotations.push({ test.info().annotations.push({
type: 'issue', type: 'issue',
description: 'https://github.com/nasa/openmct/issues/6338' description: 'https://github.com/nasa/openmct/issues/6338'
}); });
// Create an Overlay Plot with a default SWG // Create an Overlay Plot with a default SWG
const overlayPlot = await createDomainObjectWithDefaults(page, { const overlayPlot = await createDomainObjectWithDefaults(page, {
type: "Overlay Plot" type: 'Overlay Plot'
}); });
const swgA = await createDomainObjectWithDefaults(page, { const swgA = await createDomainObjectWithDefaults(page, {
type: "Sine Wave Generator", type: 'Sine Wave Generator',
parent: overlayPlot.uuid parent: overlayPlot.uuid
}); });
@ -83,8 +92,15 @@ test.describe('Overlay Plot', () => {
// Expand the "Sine Wave Generator" plot series options and enable limit lines // Expand the "Sine Wave Generator" plot series options and enable limit lines
await selectInspectorTab(page, 'Config'); await selectInspectorTab(page, 'Config');
await page.getByRole('list', { name: 'Plot Series Properties' }).locator('span').first().click(); await page
await page.getByRole('list', { name: 'Plot Series Properties' }).locator('[title="Display limit lines"]~div input').check(); .getByRole('list', { name: 'Plot Series Properties' })
.locator('span')
.first()
.click();
await page
.getByRole('list', { name: 'Plot Series Properties' })
.locator('[title="Display limit lines"]~div input')
.check();
await assertLimitLinesExistAndAreVisible(page); await assertLimitLinesExistAndAreVisible(page);
@ -104,7 +120,9 @@ test.describe('Overlay Plot', () => {
await selectInspectorTab(page, 'Elements'); await selectInspectorTab(page, 'Elements');
// Drag Sine Wave Generator series from Y Axis 1 into Y Axis 2 // Drag Sine Wave Generator series from Y Axis 1 into Y Axis 2
await page.locator(`#inspector-elements-tree >> text=${swgA.name}`).dragTo(page.locator('[aria-label="Element Item Group Y Axis 2"]')); await page
.locator(`#inspector-elements-tree >> text=${swgA.name}`)
.dragTo(page.locator('[aria-label="Element Item Group Y Axis 2"]'));
await assertLimitLinesExistAndAreVisible(page); await assertLimitLinesExistAndAreVisible(page);
@ -117,32 +135,33 @@ test.describe('Overlay Plot', () => {
await page.reload(); await page.reload();
await assertLimitLinesExistAndAreVisible(page); await assertLimitLinesExistAndAreVisible(page);
}); });
test('The elements pool supports dragging series into multiple y-axis buckets', async ({ page }) => { test('The elements pool supports dragging series into multiple y-axis buckets', async ({
page
}) => {
const overlayPlot = await createDomainObjectWithDefaults(page, { const overlayPlot = await createDomainObjectWithDefaults(page, {
type: "Overlay Plot" type: 'Overlay Plot'
}); });
const swgA = await createDomainObjectWithDefaults(page, { const swgA = await createDomainObjectWithDefaults(page, {
type: "Sine Wave Generator", type: 'Sine Wave Generator',
parent: overlayPlot.uuid parent: overlayPlot.uuid
}); });
const swgB = await createDomainObjectWithDefaults(page, { const swgB = await createDomainObjectWithDefaults(page, {
type: "Sine Wave Generator", type: 'Sine Wave Generator',
parent: overlayPlot.uuid parent: overlayPlot.uuid
}); });
const swgC = await createDomainObjectWithDefaults(page, { const swgC = await createDomainObjectWithDefaults(page, {
type: "Sine Wave Generator", type: 'Sine Wave Generator',
parent: overlayPlot.uuid parent: overlayPlot.uuid
}); });
const swgD = await createDomainObjectWithDefaults(page, { const swgD = await createDomainObjectWithDefaults(page, {
type: "Sine Wave Generator", type: 'Sine Wave Generator',
parent: overlayPlot.uuid parent: overlayPlot.uuid
}); });
const swgE = await createDomainObjectWithDefaults(page, { const swgE = await createDomainObjectWithDefaults(page, {
type: "Sine Wave Generator", type: 'Sine Wave Generator',
parent: overlayPlot.uuid parent: overlayPlot.uuid
}); });
@ -152,9 +171,15 @@ test.describe('Overlay Plot', () => {
await selectInspectorTab(page, 'Elements'); await selectInspectorTab(page, 'Elements');
// Drag swg a, c, e into Y Axis 2 // Drag swg a, c, e into Y Axis 2
await page.locator(`#inspector-elements-tree >> text=${swgA.name}`).dragTo(page.locator('[aria-label="Element Item Group Y Axis 2"]')); await page
await page.locator(`#inspector-elements-tree >> text=${swgC.name}`).dragTo(page.locator('[aria-label="Element Item Group Y Axis 2"]')); .locator(`#inspector-elements-tree >> text=${swgA.name}`)
await page.locator(`#inspector-elements-tree >> text=${swgE.name}`).dragTo(page.locator('[aria-label="Element Item Group Y Axis 2"]')); .dragTo(page.locator('[aria-label="Element Item Group Y Axis 2"]'));
await page
.locator(`#inspector-elements-tree >> text=${swgC.name}`)
.dragTo(page.locator('[aria-label="Element Item Group Y Axis 2"]'));
await page
.locator(`#inspector-elements-tree >> text=${swgE.name}`)
.dragTo(page.locator('[aria-label="Element Item Group Y Axis 2"]'));
// Assert that Y Axis 1 and Y Axis 2 property groups are visible only // Assert that Y Axis 1 and Y Axis 2 property groups are visible only
await selectInspectorTab(page, 'Config'); await selectInspectorTab(page, 'Config');
@ -167,14 +192,16 @@ test.describe('Overlay Plot', () => {
await expect(yAxis2PropertyGroup).toBeVisible(); await expect(yAxis2PropertyGroup).toBeVisible();
await expect(yAxis3PropertyGroup).toBeHidden(); await expect(yAxis3PropertyGroup).toBeHidden();
const yAxis1Group = page.getByLabel("Y Axis 1"); const yAxis1Group = page.getByLabel('Y Axis 1');
const yAxis2Group = page.getByLabel("Y Axis 2"); const yAxis2Group = page.getByLabel('Y Axis 2');
const yAxis3Group = page.getByLabel("Y Axis 3"); const yAxis3Group = page.getByLabel('Y Axis 3');
await selectInspectorTab(page, 'Elements'); await selectInspectorTab(page, 'Elements');
// Drag swg b into Y Axis 3 // Drag swg b into Y Axis 3
await page.locator(`#inspector-elements-tree >> text=${swgB.name}`).dragTo(page.locator('[aria-label="Element Item Group Y Axis 3"]')); await page
.locator(`#inspector-elements-tree >> text=${swgB.name}`)
.dragTo(page.locator('[aria-label="Element Item Group Y Axis 3"]'));
// Assert that all Y Axis property groups are visible // Assert that all Y Axis property groups are visible
await selectInspectorTab(page, 'Config'); await selectInspectorTab(page, 'Config');
@ -198,13 +225,15 @@ test.describe('Overlay Plot', () => {
expect(yAxis3Group.getByRole('listitem').nth(0).getByText(swgB.name)).toBeTruthy(); expect(yAxis3Group.getByRole('listitem').nth(0).getByText(swgB.name)).toBeTruthy();
}); });
test('Clicking on an item in the elements pool brings up the plot preview with data points', async ({ page }) => { test('Clicking on an item in the elements pool brings up the plot preview with data points', async ({
page
}) => {
const overlayPlot = await createDomainObjectWithDefaults(page, { const overlayPlot = await createDomainObjectWithDefaults(page, {
type: "Overlay Plot" type: 'Overlay Plot'
}); });
const swgA = await createDomainObjectWithDefaults(page, { const swgA = await createDomainObjectWithDefaults(page, {
type: "Sine Wave Generator", type: 'Sine Wave Generator',
parent: overlayPlot.uuid parent: overlayPlot.uuid
}); });

View File

@ -21,9 +21,9 @@
*****************************************************************************/ *****************************************************************************/
/* /*
* This test suite is dedicated to testing the rendering and interaction of plots. * This test suite is dedicated to testing the rendering and interaction of plots.
* *
*/ */
const { test, expect } = require('../../../../pluginFixtures'); const { test, expect } = require('../../../../pluginFixtures');
const { createDomainObjectWithDefaults, getCanvasPixels } = require('../../../../appActions'); const { createDomainObjectWithDefaults, getCanvasPixels } = require('../../../../appActions');
@ -34,7 +34,9 @@ test.describe('Plot Rendering', () => {
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
// Open a browser, navigate to the main page, and wait until all networkevents to resolve // Open a browser, navigate to the main page, and wait until all networkevents to resolve
await page.goto('./', { waitUntil: 'domcontentloaded' }); await page.goto('./', { waitUntil: 'domcontentloaded' });
sineWaveGeneratorObject = await createDomainObjectWithDefaults(page, { type: 'Sine Wave Generator' }); sineWaveGeneratorObject = await createDomainObjectWithDefaults(page, {
type: 'Sine Wave Generator'
});
}); });
test('Plots do not re-request data when a plot is clicked', async ({ page }) => { test('Plots do not re-request data when a plot is clicked', async ({ page }) => {
@ -44,7 +46,7 @@ test.describe('Plot Rendering', () => {
await page.locator('canvas').nth(1).click(); await page.locator('canvas').nth(1).click();
// No request was made to get historical data // No request was made to get historical data
const createMineFolderRequests = []; const createMineFolderRequests = [];
page.on('request', req => { page.on('request', (req) => {
createMineFolderRequests.push(req); createMineFolderRequests.push(req);
}); });
expect(createMineFolderRequests.length).toEqual(0); expect(createMineFolderRequests.length).toEqual(0);
@ -73,13 +75,17 @@ async function editSineWaveToUseInfinityOption(page, sineWaveGeneratorObject) {
// Edit SWG properties to include infinity values // Edit SWG properties to include infinity values
await page.locator('[title="More options"]').click(); await page.locator('[title="More options"]').click();
await page.locator('[title="Edit properties of this object."]').click(); await page.locator('[title="Edit properties of this object."]').click();
await page.getByRole('switch', { await page
name: "Include Infinity Values" .getByRole('switch', {
}).check(); name: 'Include Infinity Values'
})
.check();
await page.getByRole('button', { await page
.getByRole('button', {
name: 'Save' name: 'Save'
}).click(); })
.click();
// FIXME: Changes to SWG properties should be reflected on save, but they're not? // FIXME: Changes to SWG properties should be reflected on save, but they're not?
// Thus, navigate away and back to the object. // Thus, navigate away and back to the object.

View File

@ -21,8 +21,8 @@
*****************************************************************************/ *****************************************************************************/
/* /*
* This test suite is dedicated to testing the Scatter Plot component. * This test suite is dedicated to testing the Scatter Plot component.
*/ */
const { test, expect } = require('../../../../pluginFixtures'); const { test, expect } = require('../../../../pluginFixtures');
const { createDomainObjectWithDefaults, selectInspectorTab } = require('../../../../appActions'); const { createDomainObjectWithDefaults, selectInspectorTab } = require('../../../../appActions');
@ -67,7 +67,13 @@ test.describe('Scatter Plot', () => {
}); });
// Verify that the 'Replace telemetry source' modal appears and accept it // Verify that the 'Replace telemetry source' modal appears and accept it
await expect.soft(page.locator('text=This action will replace the current telemetry source. Do you want to continue?')).toBeVisible(); await expect
.soft(
page.locator(
'text=This action will replace the current telemetry source. Do you want to continue?'
)
)
.toBeVisible();
await page.click('text=Ok'); await page.click('text=Ok');
// Navigate to the scatter plot and verify that the new SWG // Navigate to the scatter plot and verify that the new SWG
@ -88,7 +94,13 @@ test.describe('Scatter Plot', () => {
await page.locator('li[title="Remove this object from its containing object."]').click(); await page.locator('li[title="Remove this object from its containing object."]').click();
// Verify that the 'Remove object' confirmation modal appears and accept it // Verify that the 'Remove object' confirmation modal appears and accept it
await expect.soft(page.locator('text=Warning! This action will remove this object. Are you sure you want to continue?')).toBeVisible(); await expect
.soft(
page.locator(
'text=Warning! This action will remove this object. Are you sure you want to continue?'
)
)
.toBeVisible();
await page.click('text=Ok'); await page.click('text=Ok');
// Verify that the elements pool shows no elements // Verify that the elements pool shows no elements

View File

@ -39,27 +39,33 @@ test.describe('Stacked Plot', () => {
await page.goto('./', { waitUntil: 'domcontentloaded' }); await page.goto('./', { waitUntil: 'domcontentloaded' });
stackedPlot = await createDomainObjectWithDefaults(page, { stackedPlot = await createDomainObjectWithDefaults(page, {
type: "Stacked Plot" type: 'Stacked Plot'
}); });
swgA = await createDomainObjectWithDefaults(page, { swgA = await createDomainObjectWithDefaults(page, {
type: "Sine Wave Generator", type: 'Sine Wave Generator',
parent: stackedPlot.uuid parent: stackedPlot.uuid
}); });
swgB = await createDomainObjectWithDefaults(page, { swgB = await createDomainObjectWithDefaults(page, {
type: "Sine Wave Generator", type: 'Sine Wave Generator',
parent: stackedPlot.uuid parent: stackedPlot.uuid
}); });
swgC = await createDomainObjectWithDefaults(page, { swgC = await createDomainObjectWithDefaults(page, {
type: "Sine Wave Generator", type: 'Sine Wave Generator',
parent: stackedPlot.uuid parent: stackedPlot.uuid
}); });
}); });
test('Using the remove action removes the correct plot', async ({ page }) => { test('Using the remove action removes the correct plot', async ({ page }) => {
const swgAElementsPoolItem = page.locator('#inspector-elements-tree').locator('.c-object-label', { hasText: swgA.name }); const swgAElementsPoolItem = page
const swgBElementsPoolItem = page.locator('#inspector-elements-tree').locator('.c-object-label', { hasText: swgB.name }); .locator('#inspector-elements-tree')
const swgCElementsPoolItem = page.locator('#inspector-elements-tree').locator('.c-object-label', { hasText: swgC.name }); .locator('.c-object-label', { hasText: swgA.name });
const swgBElementsPoolItem = page
.locator('#inspector-elements-tree')
.locator('.c-object-label', { hasText: swgB.name });
const swgCElementsPoolItem = page
.locator('#inspector-elements-tree')
.locator('.c-object-label', { hasText: swgC.name });
await page.goto(stackedPlot.url); await page.goto(stackedPlot.url);
@ -68,8 +74,11 @@ test.describe('Stacked Plot', () => {
await selectInspectorTab(page, 'Elements'); await selectInspectorTab(page, 'Elements');
await swgBElementsPoolItem.click({ button: 'right' }); await swgBElementsPoolItem.click({ button: 'right' });
await page.getByRole('menuitem').filter({ hasText: /Remove/ }).click(); await page
await page.getByRole('button').filter({ hasText: "OK" }).click(); .getByRole('menuitem')
.filter({ hasText: /Remove/ })
.click();
await page.getByRole('button').filter({ hasText: 'OK' }).click();
await expect(page.locator('#inspector-elements-tree .js-elements-pool__item')).toHaveCount(2); await expect(page.locator('#inspector-elements-tree .js-elements-pool__item')).toHaveCount(2);
@ -80,9 +89,15 @@ test.describe('Stacked Plot', () => {
}); });
test('Can reorder Stacked Plot items', async ({ page }) => { test('Can reorder Stacked Plot items', async ({ page }) => {
const swgAElementsPoolItem = page.locator('#inspector-elements-tree').locator('.c-object-label', { hasText: swgA.name }); const swgAElementsPoolItem = page
const swgBElementsPoolItem = page.locator('#inspector-elements-tree').locator('.c-object-label', { hasText: swgB.name }); .locator('#inspector-elements-tree')
const swgCElementsPoolItem = page.locator('#inspector-elements-tree').locator('.c-object-label', { hasText: swgC.name }); .locator('.c-object-label', { hasText: swgA.name });
const swgBElementsPoolItem = page
.locator('#inspector-elements-tree')
.locator('.c-object-label', { hasText: swgB.name });
const swgCElementsPoolItem = page
.locator('#inspector-elements-tree')
.locator('.c-object-label', { hasText: swgC.name });
await page.goto(stackedPlot.url); await page.goto(stackedPlot.url);
@ -128,7 +143,9 @@ test.describe('Stacked Plot', () => {
await expect(stackedPlotItem3).toHaveAttribute('aria-label', `Stacked Plot Item ${swgA.name}`); await expect(stackedPlotItem3).toHaveAttribute('aria-label', `Stacked Plot Item ${swgA.name}`);
}); });
test('Selecting a child plot while in browse and edit modes shows its properties in the inspector', async ({ page }) => { test('Selecting a child plot while in browse and edit modes shows its properties in the inspector', async ({
page
}) => {
await page.goto(stackedPlot.url); await page.goto(stackedPlot.url);
await selectInspectorTab(page, 'Config'); await selectInspectorTab(page, 'Config');
@ -137,25 +154,37 @@ test.describe('Stacked Plot', () => {
await page.locator(`[aria-label="Stacked Plot Item ${swgA.name}"] canvas`).nth(1).click(); await page.locator(`[aria-label="Stacked Plot Item ${swgA.name}"] canvas`).nth(1).click();
// Assert that the inspector shows the Y Axis properties for swgA // Assert that the inspector shows the Y Axis properties for swgA
await expect(page.locator('[aria-label="Plot Series Properties"] >> h2')).toContainText("Plot Series"); await expect(page.locator('[aria-label="Plot Series Properties"] >> h2')).toContainText(
await expect(page.getByRole('heading', { name: "Y Axis" })).toBeVisible(); 'Plot Series'
await expect(page.locator('[aria-label="Plot Series Properties"] .c-object-label')).toContainText(swgA.name); );
await expect(page.getByRole('heading', { name: 'Y Axis' })).toBeVisible();
await expect(
page.locator('[aria-label="Plot Series Properties"] .c-object-label')
).toContainText(swgA.name);
// Click on the 2nd plot // Click on the 2nd plot
await page.locator(`[aria-label="Stacked Plot Item ${swgB.name}"] canvas`).nth(1).click(); await page.locator(`[aria-label="Stacked Plot Item ${swgB.name}"] canvas`).nth(1).click();
// Assert that the inspector shows the Y Axis properties for swgB // Assert that the inspector shows the Y Axis properties for swgB
await expect(page.locator('[aria-label="Plot Series Properties"] >> h2')).toContainText("Plot Series"); await expect(page.locator('[aria-label="Plot Series Properties"] >> h2')).toContainText(
'Plot Series'
);
await expect(page.getByRole('heading', { name: 'Y Axis' })).toBeVisible(); await expect(page.getByRole('heading', { name: 'Y Axis' })).toBeVisible();
await expect(page.locator('[aria-label="Plot Series Properties"] .c-object-label')).toContainText(swgB.name); await expect(
page.locator('[aria-label="Plot Series Properties"] .c-object-label')
).toContainText(swgB.name);
// Click on the 3rd plot // Click on the 3rd plot
await page.locator(`[aria-label="Stacked Plot Item ${swgC.name}"] canvas`).nth(1).click(); await page.locator(`[aria-label="Stacked Plot Item ${swgC.name}"] canvas`).nth(1).click();
// Assert that the inspector shows the Y Axis properties for swgC // Assert that the inspector shows the Y Axis properties for swgC
await expect(page.locator('[aria-label="Plot Series Properties"] >> h2')).toContainText("Plot Series"); await expect(page.locator('[aria-label="Plot Series Properties"] >> h2')).toContainText(
'Plot Series'
);
await expect(page.getByRole('heading', { name: 'Y Axis' })).toBeVisible(); await expect(page.getByRole('heading', { name: 'Y Axis' })).toBeVisible();
await expect(page.locator('[aria-label="Plot Series Properties"] .c-object-label')).toContainText(swgC.name); await expect(
page.locator('[aria-label="Plot Series Properties"] .c-object-label')
).toContainText(swgC.name);
// Go into edit mode // Go into edit mode
await page.click('button[title="Edit"]'); await page.click('button[title="Edit"]');
@ -166,24 +195,36 @@ test.describe('Stacked Plot', () => {
await page.locator(`[aria-label="Stacked Plot Item ${swgA.name}"]`).click(); await page.locator(`[aria-label="Stacked Plot Item ${swgA.name}"]`).click();
// Assert that the inspector shows the Y Axis properties for swgA // Assert that the inspector shows the Y Axis properties for swgA
await expect(page.locator('[aria-label="Plot Series Properties"] >> h2')).toContainText("Plot Series"); await expect(page.locator('[aria-label="Plot Series Properties"] >> h2')).toContainText(
'Plot Series'
);
await expect(page.getByRole('heading', { name: 'Y Axis' })).toBeVisible(); await expect(page.getByRole('heading', { name: 'Y Axis' })).toBeVisible();
await expect(page.locator('[aria-label="Plot Series Properties"] .c-object-label')).toContainText(swgA.name); await expect(
page.locator('[aria-label="Plot Series Properties"] .c-object-label')
).toContainText(swgA.name);
//Click on canvas for the 2nd plot //Click on canvas for the 2nd plot
await page.locator(`[aria-label="Stacked Plot Item ${swgB.name}"]`).click(); await page.locator(`[aria-label="Stacked Plot Item ${swgB.name}"]`).click();
// Assert that the inspector shows the Y Axis properties for swgB // Assert that the inspector shows the Y Axis properties for swgB
await expect(page.locator('[aria-label="Plot Series Properties"] >> h2')).toContainText("Plot Series"); await expect(page.locator('[aria-label="Plot Series Properties"] >> h2')).toContainText(
'Plot Series'
);
await expect(page.getByRole('heading', { name: 'Y Axis' })).toBeVisible(); await expect(page.getByRole('heading', { name: 'Y Axis' })).toBeVisible();
await expect(page.locator('[aria-label="Plot Series Properties"] .c-object-label')).toContainText(swgB.name); await expect(
page.locator('[aria-label="Plot Series Properties"] .c-object-label')
).toContainText(swgB.name);
//Click on canvas for the 3rd plot //Click on canvas for the 3rd plot
await page.locator(`[aria-label="Stacked Plot Item ${swgC.name}"]`).click(); await page.locator(`[aria-label="Stacked Plot Item ${swgC.name}"]`).click();
// Assert that the inspector shows the Y Axis properties for swgC // Assert that the inspector shows the Y Axis properties for swgC
await expect(page.locator('[aria-label="Plot Series Properties"] >> h2')).toContainText("Plot Series"); await expect(page.locator('[aria-label="Plot Series Properties"] >> h2')).toContainText(
'Plot Series'
);
await expect(page.getByRole('heading', { name: 'Y Axis' })).toBeVisible(); await expect(page.getByRole('heading', { name: 'Y Axis' })).toBeVisible();
await expect(page.locator('[aria-label="Plot Series Properties"] .c-object-label')).toContainText(swgC.name); await expect(
page.locator('[aria-label="Plot Series Properties"] .c-object-label')
).toContainText(swgC.name);
}); });
}); });

View File

@ -25,7 +25,12 @@ Tests to verify plot tagging functionality.
*/ */
const { test, expect } = require('../../../../pluginFixtures'); const { test, expect } = require('../../../../pluginFixtures');
const { createDomainObjectWithDefaults, setRealTimeMode, setFixedTimeMode, waitForPlotsToRender } = require('../../../../appActions'); const {
createDomainObjectWithDefaults,
setRealTimeMode,
setFixedTimeMode,
waitForPlotsToRender
} = require('../../../../appActions');
test.describe('Plot Tagging', () => { test.describe('Plot Tagging', () => {
/** /**
@ -36,8 +41,8 @@ test.describe('Plot Tagging', () => {
* @param {Number} yEnd a telemetry item with a plot * @param {Number} yEnd a telemetry item with a plot
* @returns {Promise} * @returns {Promise}
*/ */
async function createTags({page, canvas, xEnd, yEnd}) { async function createTags({ page, canvas, xEnd, yEnd }) {
await canvas.hover({trial: true}); await canvas.hover({ trial: true });
//Alt+Shift Drag Start to select some points to tag //Alt+Shift Drag Start to select some points to tag
await page.keyboard.down('Alt'); await page.keyboard.down('Alt');
@ -59,7 +64,7 @@ test.describe('Plot Tagging', () => {
await page.keyboard.up('Shift'); await page.keyboard.up('Shift');
//Wait for canvas to stablize. //Wait for canvas to stablize.
await canvas.hover({trial: true}); await canvas.hover({ trial: true });
// add some tags // add some tags
await page.getByText('Annotations').click(); await page.getByText('Annotations').click();
@ -87,7 +92,7 @@ test.describe('Plot Tagging', () => {
const canvas = page.locator('canvas').nth(1); const canvas = page.locator('canvas').nth(1);
//Wait for canvas to stablize. //Wait for canvas to stablize.
await canvas.hover({trial: true}); await canvas.hover({ trial: true });
// click on the tagged plot point // click on the tagged plot point
await canvas.click({ await canvas.click({
@ -115,7 +120,11 @@ test.describe('Plot Tagging', () => {
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('driv'); await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('driv');
// click on the search result // click on the search result
await page.getByRole('searchbox', { name: 'OpenMCT Search' }).getByText(/Sine Wave/).first().click(); await page
.getByRole('searchbox', { name: 'OpenMCT Search' })
.getByText(/Sine Wave/)
.first()
.click();
// Delete Driving // Delete Driving
await page.hover('[aria-label="Tag"]:has-text("Driving")'); await page.hover('[aria-label="Tag"]:has-text("Driving")');
@ -124,8 +133,8 @@ test.describe('Plot Tagging', () => {
// Search for Science // Search for Science
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click(); await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('sc'); await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('sc');
await expect(page.locator('[aria-label="Search Result"]').nth(0)).toContainText("Science"); await expect(page.locator('[aria-label="Search Result"]').nth(0)).toContainText('Science');
await expect(page.locator('[aria-label="Search Result"]').nth(0)).not.toContainText("Drilling"); await expect(page.locator('[aria-label="Search Result"]').nth(0)).not.toContainText('Drilling');
// Search for Driving // Search for Driving
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click(); await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
@ -162,18 +171,18 @@ test.describe('Plot Tagging', () => {
test.slow(); test.slow();
const overlayPlot = await createDomainObjectWithDefaults(page, { const overlayPlot = await createDomainObjectWithDefaults(page, {
type: "Overlay Plot" type: 'Overlay Plot'
}); });
const alphaSineWave = await createDomainObjectWithDefaults(page, { const alphaSineWave = await createDomainObjectWithDefaults(page, {
type: "Sine Wave Generator", type: 'Sine Wave Generator',
name: "Alpha Sine Wave", name: 'Alpha Sine Wave',
parent: overlayPlot.uuid parent: overlayPlot.uuid
}); });
await createDomainObjectWithDefaults(page, { await createDomainObjectWithDefaults(page, {
type: "Sine Wave Generator", type: 'Sine Wave Generator',
name: "Beta Sine Wave", name: 'Beta Sine Wave',
parent: overlayPlot.uuid parent: overlayPlot.uuid
}); });
@ -204,7 +213,11 @@ test.describe('Plot Tagging', () => {
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click(); await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('sc'); await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('sc');
// click on the search result // click on the search result
await page.getByRole('searchbox', { name: 'OpenMCT Search' }).getByText('Alpha Sine Wave').first().click(); await page
.getByRole('searchbox', { name: 'OpenMCT Search' })
.getByText('Alpha Sine Wave')
.first()
.click();
// wait for plots to load // wait for plots to load
await expect(page.locator('.js-series-data-loaded')).toBeVisible(); await expect(page.locator('.js-series-data-loaded')).toBeVisible();
// expect plot to be paused // expect plot to be paused
@ -215,7 +228,7 @@ test.describe('Plot Tagging', () => {
test('Tags work with Plot View of telemetry items', async ({ page }) => { test('Tags work with Plot View of telemetry items', async ({ page }) => {
await createDomainObjectWithDefaults(page, { await createDomainObjectWithDefaults(page, {
type: "Sine Wave Generator" type: 'Sine Wave Generator'
}); });
const canvas = page.locator('canvas').nth(1); const canvas = page.locator('canvas').nth(1);
@ -230,18 +243,18 @@ test.describe('Plot Tagging', () => {
test('Tags work with Stacked Plots', async ({ page }) => { test('Tags work with Stacked Plots', async ({ page }) => {
const stackedPlot = await createDomainObjectWithDefaults(page, { const stackedPlot = await createDomainObjectWithDefaults(page, {
type: "Stacked Plot" type: 'Stacked Plot'
}); });
const alphaSineWave = await createDomainObjectWithDefaults(page, { const alphaSineWave = await createDomainObjectWithDefaults(page, {
type: "Sine Wave Generator", type: 'Sine Wave Generator',
name: "Alpha Sine Wave", name: 'Alpha Sine Wave',
parent: stackedPlot.uuid parent: stackedPlot.uuid
}); });
await createDomainObjectWithDefaults(page, { await createDomainObjectWithDefaults(page, {
type: "Sine Wave Generator", type: 'Sine Wave Generator',
name: "Beta Sine Wave", name: 'Beta Sine Wave',
parent: stackedPlot.uuid parent: stackedPlot.uuid
}); });

View File

@ -24,7 +24,9 @@ const { createDomainObjectWithDefaults } = require('../../../../appActions');
const { test, expect } = require('../../../../pluginFixtures'); const { test, expect } = require('../../../../pluginFixtures');
test.describe('Telemetry Table', () => { test.describe('Telemetry Table', () => {
test('unpauses and filters data when paused by button and user changes bounds', async ({ page }) => { test('unpauses and filters data when paused by button and user changes bounds', async ({
page
}) => {
test.info().annotations.push({ test.info().annotations.push({
type: 'issue', type: 'issue',
description: 'https://github.com/nasa/openmct/issues/5113' description: 'https://github.com/nasa/openmct/issues/5113'
@ -65,7 +67,12 @@ test.describe('Telemetry Table', () => {
await expect(tableWrapper).not.toHaveClass(/is-paused/); await expect(tableWrapper).not.toHaveClass(/is-paused/);
// Get the most recent telemetry date // Get the most recent telemetry date
const latestTelemetryDate = await page.locator('table.c-telemetry-table__body > tbody > tr').last().locator('td').nth(1).getAttribute('title'); const latestTelemetryDate = await page
.locator('table.c-telemetry-table__body > tbody > tr')
.last()
.locator('td')
.nth(1)
.getAttribute('title');
// Verify that it is <= our new end bound // Verify that it is <= our new end bound
const latestMilliseconds = Date.parse(latestTelemetryDate); const latestMilliseconds = Date.parse(latestTelemetryDate);

View File

@ -21,7 +21,12 @@
*****************************************************************************/ *****************************************************************************/
const { test, expect } = require('../../../../pluginFixtures'); const { test, expect } = require('../../../../pluginFixtures');
const { setFixedTimeMode, setRealTimeMode, setStartOffset, setEndOffset } = require('../../../../appActions'); const {
setFixedTimeMode,
setRealTimeMode,
setStartOffset,
setEndOffset
} = require('../../../../appActions');
test.describe('Time conductor operations', () => { test.describe('Time conductor operations', () => {
test('validate start time does not exceeds end time', async ({ page }) => { test('validate start time does not exceeds end time', async ({ page }) => {
@ -48,23 +53,27 @@ test.describe('Time conductor operations', () => {
await startTimeLocator.fill(startDate.toString()); await startTimeLocator.fill(startDate.toString());
// invalid start date // invalid start date
startDate = (year + 1) + startDate.substring(4); startDate = year + 1 + startDate.substring(4);
await startTimeLocator.fill(startDate.toString()); await startTimeLocator.fill(startDate.toString());
await endTimeLocator.click(); await endTimeLocator.click();
const startDateValidityStatus = await startTimeLocator.evaluate((element) => element.checkValidity()); const startDateValidityStatus = await startTimeLocator.evaluate((element) =>
element.checkValidity()
);
expect(startDateValidityStatus).not.toBeTruthy(); expect(startDateValidityStatus).not.toBeTruthy();
// fix to valid start date // fix to valid start date
startDate = (year - 1) + startDate.substring(4); startDate = year - 1 + startDate.substring(4);
await startTimeLocator.fill(startDate.toString()); await startTimeLocator.fill(startDate.toString());
// invalid end date // invalid end date
endDate = (year - 2) + endDate.substring(4); endDate = year - 2 + endDate.substring(4);
await endTimeLocator.fill(endDate.toString()); await endTimeLocator.fill(endDate.toString());
await startTimeLocator.click(); await startTimeLocator.click();
const endDateValidityStatus = await endTimeLocator.evaluate((element) => element.checkValidity()); const endDateValidityStatus = await endTimeLocator.evaluate((element) =>
element.checkValidity()
);
expect(endDateValidityStatus).not.toBeTruthy(); expect(endDateValidityStatus).not.toBeTruthy();
}); });
}); });
@ -91,7 +100,9 @@ test.describe('Time conductor input fields real-time mode', () => {
await setStartOffset(page, startOffset); await setStartOffset(page, startOffset);
// Verify time was updated on time offset button // Verify time was updated on time offset button
await expect(page.locator('data-testid=conductor-start-offset-button')).toContainText('00:30:23'); await expect(page.locator('data-testid=conductor-start-offset-button')).toContainText(
'00:30:23'
);
// Set end time offset // Set end time offset
await setEndOffset(page, endOffset); await setEndOffset(page, endOffset);
@ -104,7 +115,9 @@ test.describe('Time conductor input fields real-time mode', () => {
* Verify that offsets and url params are preserved when switching * Verify that offsets and url params are preserved when switching
* between fixed timespan and real-time mode. * between fixed timespan and real-time mode.
*/ */
test('preserve offsets and url params when switching between fixed and real-time mode', async ({ page }) => { test('preserve offsets and url params when switching between fixed and real-time mode', async ({
page
}) => {
const startOffset = { const startOffset = {
mins: '30', mins: '30',
secs: '23' secs: '23'
@ -115,8 +128,8 @@ test.describe('Time conductor input fields real-time mode', () => {
}; };
// Convert offsets to milliseconds // Convert offsets to milliseconds
const startDelta = (30 * 60 * 1000) + (23 * 1000); const startDelta = 30 * 60 * 1000 + 23 * 1000;
const endDelta = (1 * 1000); const endDelta = 1 * 1000;
// Go to baseURL // Go to baseURL
await page.goto('./', { waitUntil: 'domcontentloaded' }); await page.goto('./', { waitUntil: 'domcontentloaded' });
@ -137,7 +150,9 @@ test.describe('Time conductor input fields real-time mode', () => {
await setRealTimeMode(page); await setRealTimeMode(page);
// Verify updated start time offset persists after mode switch // Verify updated start time offset persists after mode switch
await expect(page.locator('data-testid=conductor-start-offset-button')).toContainText('00:30:23'); await expect(page.locator('data-testid=conductor-start-offset-button')).toContainText(
'00:30:23'
);
// Verify updated end time offset persists after mode switch // Verify updated end time offset persists after mode switch
await expect(page.locator('data-testid=conductor-end-offset-button')).toContainText('00:00:01'); await expect(page.locator('data-testid=conductor-end-offset-button')).toContainText('00:00:01');
@ -148,20 +163,29 @@ test.describe('Time conductor input fields real-time mode', () => {
expect(page.url()).toContain(`endDelta=${endDelta}`); expect(page.url()).toContain(`endDelta=${endDelta}`);
}); });
test.fixme('time conductor history in fixed time mode will track changing start and end times', async ({ page }) => { test.fixme(
'time conductor history in fixed time mode will track changing start and end times',
async ({ page }) => {
// change start time, verify it's tracked in history // change start time, verify it's tracked in history
// change end time, verify it's tracked in history // change end time, verify it's tracked in history
}); }
);
test.fixme('time conductor history in realtime mode will track changing start and end times', async ({ page }) => { test.fixme(
'time conductor history in realtime mode will track changing start and end times',
async ({ page }) => {
// change start offset, verify it's tracked in history // change start offset, verify it's tracked in history
// change end offset, verify it's tracked in history // change end offset, verify it's tracked in history
}); }
);
test.fixme('time conductor history allows you to set a historical timeframe', async ({ page }) => { test.fixme(
'time conductor history allows you to set a historical timeframe',
async ({ page }) => {
// make sure there are historical history options // make sure there are historical history options
// select an option and make sure the time conductor start and end bounds are updated correctly // select an option and make sure the time conductor start and end bounds are updated correctly
}); }
);
test.fixme('time conductor history allows you to set a realtime offsets', async ({ page }) => { test.fixme('time conductor history allows you to set a realtime offsets', async ({ page }) => {
// make sure there are realtime history options // make sure there are realtime history options
@ -170,7 +194,7 @@ test.describe('Time conductor input fields real-time mode', () => {
}); });
test.describe('Time Conductor History', () => { test.describe('Time Conductor History', () => {
test("shows milliseconds on hover @unstable", async ({ page }) => { test('shows milliseconds on hover @unstable', async ({ page }) => {
test.info().annotations.push({ test.info().annotations.push({
type: 'issue', type: 'issue',
description: 'https://github.com/nasa/openmct/issues/4386' description: 'https://github.com/nasa/openmct/issues/4386'
@ -178,13 +202,19 @@ test.describe('Time Conductor History', () => {
// Navigate to Open MCT in Fixed Time Mode, UTC Time System // Navigate to Open MCT in Fixed Time Mode, UTC Time System
// with startBound at 2022-01-01 00:00:00.000Z // with startBound at 2022-01-01 00:00:00.000Z
// and endBound at 2022-01-01 00:00:00.200Z // and endBound at 2022-01-01 00:00:00.200Z
await page.goto('./#/browse/mine?view=grid&tc.mode=fixed&tc.startBound=1640995200000&tc.endBound=1640995200200&tc.timeSystem=utc&hideInspector=true', { waitUntil: 'networkidle' }); await page.goto(
await page.locator("[aria-label='Time Conductor History']").hover({ trial: true}); './#/browse/mine?view=grid&tc.mode=fixed&tc.startBound=1640995200000&tc.endBound=1640995200200&tc.timeSystem=utc&hideInspector=true',
{ waitUntil: 'networkidle' }
);
await page.locator("[aria-label='Time Conductor History']").hover({ trial: true });
await page.locator("[aria-label='Time Conductor History']").click(); await page.locator("[aria-label='Time Conductor History']").click();
// Validate history item format // Validate history item format
const historyItem = page.locator('text="2022-01-01 00:00:00 + 200ms"'); const historyItem = page.locator('text="2022-01-01 00:00:00 + 200ms"');
await expect(historyItem).toBeEnabled(); await expect(historyItem).toBeEnabled();
await expect(historyItem).toHaveAttribute('title', '2022-01-01 00:00:00.000 - 2022-01-01 00:00:00.200'); await expect(historyItem).toHaveAttribute(
'title',
'2022-01-01 00:00:00.000 - 2022-01-01 00:00:00.200'
);
}); });
}); });

View File

@ -21,7 +21,10 @@
*****************************************************************************/ *****************************************************************************/
const { test, expect } = require('../../../../pluginFixtures'); const { test, expect } = require('../../../../pluginFixtures');
const { openObjectTreeContextMenu, createDomainObjectWithDefaults } = require('../../../../appActions'); const {
openObjectTreeContextMenu,
createDomainObjectWithDefaults
} = require('../../../../appActions');
test.describe('Timer', () => { test.describe('Timer', () => {
let timer; let timer;
@ -38,21 +41,21 @@ test.describe('Timer', () => {
const timerUrl = timer.url; const timerUrl = timer.url;
await test.step("From the tree context menu", async () => { await test.step('From the tree context menu', async () => {
await triggerTimerContextMenuAction(page, timerUrl, 'Start'); await triggerTimerContextMenuAction(page, timerUrl, 'Start');
await triggerTimerContextMenuAction(page, timerUrl, 'Pause'); await triggerTimerContextMenuAction(page, timerUrl, 'Pause');
await triggerTimerContextMenuAction(page, timerUrl, 'Restart at 0'); await triggerTimerContextMenuAction(page, timerUrl, 'Restart at 0');
await triggerTimerContextMenuAction(page, timerUrl, 'Stop'); await triggerTimerContextMenuAction(page, timerUrl, 'Stop');
}); });
await test.step("From the 3dot menu", async () => { await test.step('From the 3dot menu', async () => {
await triggerTimer3dotMenuAction(page, 'Start'); await triggerTimer3dotMenuAction(page, 'Start');
await triggerTimer3dotMenuAction(page, 'Pause'); await triggerTimer3dotMenuAction(page, 'Pause');
await triggerTimer3dotMenuAction(page, 'Restart at 0'); await triggerTimer3dotMenuAction(page, 'Restart at 0');
await triggerTimer3dotMenuAction(page, 'Stop'); await triggerTimer3dotMenuAction(page, 'Stop');
}); });
await test.step("From the object view", async () => { await test.step('From the object view', async () => {
await triggerTimerViewAction(page, 'Start'); await triggerTimerViewAction(page, 'Start');
await triggerTimerViewAction(page, 'Pause'); await triggerTimerViewAction(page, 'Pause');
await triggerTimerViewAction(page, 'Restart at 0'); await triggerTimerViewAction(page, 'Restart at 0');
@ -111,7 +114,7 @@ async function triggerTimer3dotMenuAction(page, action) {
* @param {TimerViewAction} action * @param {TimerViewAction} action
*/ */
async function triggerTimerViewAction(page, action) { async function triggerTimerViewAction(page, action) {
await page.locator('.c-timer').hover({trial: true}); await page.locator('.c-timer').hover({ trial: true });
const buttonTitle = buttonTitleFromAction(action); const buttonTitle = buttonTitleFromAction(action);
await page.click(`button[title="${buttonTitle}"]`); await page.click(`button[title="${buttonTitle}"]`);
assertTimerStateAfterAction(page, action); assertTimerStateAfterAction(page, action);
@ -142,7 +145,7 @@ async function assertTimerStateAfterAction(page, action) {
switch (action) { switch (action) {
case 'Start': case 'Start':
case 'Restart at 0': case 'Restart at 0':
timerStateClass = "is-started"; timerStateClass = 'is-started';
break; break;
case 'Stop': case 'Stop':
timerStateClass = 'is-stopped'; timerStateClass = 'is-stopped';

View File

@ -49,14 +49,19 @@ test.describe('Recent Objects', () => {
}); });
// Drag the Recent Objects panel up a bit // Drag the Recent Objects panel up a bit
await page.locator('.l-pane.l-pane--vertical-handle-before', { await page
.locator('.l-pane.l-pane--vertical-handle-before', {
hasText: 'Recently Viewed' hasText: 'Recently Viewed'
}).locator('.l-pane__handle').hover(); })
.locator('.l-pane__handle')
.hover();
await page.mouse.down(); await page.mouse.down();
await page.mouse.move(0, 100); await page.mouse.move(0, 100);
await page.mouse.up(); await page.mouse.up();
}); });
test('Navigated objects show up in recents, object renames and deletions are reflected', async ({ page }) => { test('Navigated objects show up in recents, object renames and deletions are reflected', async ({
page
}) => {
// Verify that both created objects appear in the list and are in the correct order // Verify that both created objects appear in the list and are in the correct order
await assertInitialRecentObjectsListState(); await assertInitialRecentObjectsListState();
@ -67,22 +72,31 @@ test.describe('Recent Objects', () => {
// Rename // Rename
folderA.name = `${folderA.name}-NEW!`; folderA.name = `${folderA.name}-NEW!`;
await page.locator('.l-browse-bar__object-name').fill(""); await page.locator('.l-browse-bar__object-name').fill('');
await page.locator('.l-browse-bar__object-name').fill(folderA.name); await page.locator('.l-browse-bar__object-name').fill(folderA.name);
await page.keyboard.press('Enter'); await page.keyboard.press('Enter');
// Verify rename has been applied in recent objects list item and objects paths // Verify rename has been applied in recent objects list item and objects paths
expect(await page.getByRole('navigation', { expect(
await page
.getByRole('navigation', {
name: clock.name name: clock.name
}).locator('a').filter({ })
.locator('a')
.filter({
hasText: folderA.name hasText: folderA.name
}).count()).toBeGreaterThan(0); })
.count()
).toBeGreaterThan(0);
expect(recentObjectsList.getByRole('listitem', { name: folderA.name })).toBeTruthy(); expect(recentObjectsList.getByRole('listitem', { name: folderA.name })).toBeTruthy();
// Delete // Delete
await page.click('button[title="Show selected item in tree"]'); await page.click('button[title="Show selected item in tree"]');
// Delete the folder via the left tree pane treeitem context menu // Delete the folder via the left tree pane treeitem context menu
await page.getByRole('treeitem', { name: new RegExp(folderA.name) }).locator('a').click({ await page
.getByRole('treeitem', { name: new RegExp(folderA.name) })
.locator('a')
.click({
button: 'right' button: 'right'
}); });
await page.getByRole('menuitem', { name: /Remove/ }).click(); await page.getByRole('menuitem', { name: /Remove/ }).click();
@ -92,7 +106,10 @@ test.describe('Recent Objects', () => {
await expect(recentObjectsList.getByRole('listitem', { name: folderA.name })).toBeHidden(); await expect(recentObjectsList.getByRole('listitem', { name: folderA.name })).toBeHidden();
await expect(recentObjectsList.getByRole('listitem', { name: clock.name })).toBeHidden(); await expect(recentObjectsList.getByRole('listitem', { name: clock.name })).toBeHidden();
}); });
test("Clicking on an object in the path of a recent object navigates to the object", async ({ page, openmctConfig }) => { test('Clicking on an object in the path of a recent object navigates to the object', async ({
page,
openmctConfig
}) => {
const { myItemsFolderName } = openmctConfig; const { myItemsFolderName } = openmctConfig;
test.info().annotations.push({ test.info().annotations.push({
type: 'issue', type: 'issue',
@ -102,11 +119,15 @@ test.describe('Recent Objects', () => {
// Navigate to the folder by clicking on its entry in the Clock's breadcrumb // Navigate to the folder by clicking on its entry in the Clock's breadcrumb
const waitForFolderNavigation = page.waitForURL(`**/${folderA.uuid}?*`); const waitForFolderNavigation = page.waitForURL(`**/${folderA.uuid}?*`);
await page.getByRole('navigation', { await page
.getByRole('navigation', {
name: clock.name name: clock.name
}).locator('a').filter({ })
.locator('a')
.filter({
hasText: folderA.name hasText: folderA.name
}).click(); })
.click();
// Verify that the hash URL updates correctly // Verify that the hash URL updates correctly
await waitForFolderNavigation; await waitForFolderNavigation;
@ -114,26 +135,33 @@ test.describe('Recent Objects', () => {
// Navigate to My Items by clicking on its entry in the Clock's breadcrumb // Navigate to My Items by clicking on its entry in the Clock's breadcrumb
const waitForMyItemsNavigation = page.waitForURL(`**/mine?*`); const waitForMyItemsNavigation = page.waitForURL(`**/mine?*`);
await page.getByRole('navigation', { await page
.getByRole('navigation', {
name: clock.name name: clock.name
}).locator('a').filter({ })
.locator('a')
.filter({
hasText: myItemsFolderName hasText: myItemsFolderName
}).click(); })
.click();
// Verify that the hash URL updates correctly // Verify that the hash URL updates correctly
await waitForMyItemsNavigation; await waitForMyItemsNavigation;
expect(page.url()).toMatch(new RegExp(`.*mine?.*`)); expect(page.url()).toMatch(new RegExp(`.*mine?.*`));
}); });
test("Clicking on the 'target button' scrolls the object into view in the tree and highlights it", async ({ page }) => { test("Clicking on the 'target button' scrolls the object into view in the tree and highlights it", async ({
const clockTreeItem = page.getByRole('tree', { name: 'Main Tree'}).getByRole('treeitem', { name: clock.name }); page
const folderTreeItem = page.getByRole('tree', { name: 'Main Tree'}) }) => {
.getByRole('treeitem', { const clockTreeItem = page
.getByRole('tree', { name: 'Main Tree' })
.getByRole('treeitem', { name: clock.name });
const folderTreeItem = page.getByRole('tree', { name: 'Main Tree' }).getByRole('treeitem', {
name: folderA.name, name: folderA.name,
expanded: true expanded: true
}); });
// Click the "Target" button for the Clock which is nested in a folder // Click the "Target" button for the Clock which is nested in a folder
await page.getByRole('button', { name: `Open and scroll to ${clock.name}`}).click(); await page.getByRole('button', { name: `Open and scroll to ${clock.name}` }).click();
// Assert that the Clock parent folder has expanded and the Clock is visible) // Assert that the Clock parent folder has expanded and the Clock is visible)
await expect(folderTreeItem.locator('.c-disclosure-triangle')).toHaveClass(/--expanded/); await expect(folderTreeItem.locator('.c-disclosure-triangle')).toHaveClass(/--expanded/);
@ -148,50 +176,65 @@ test.describe('Recent Objects', () => {
// Assert that the Clock treeitem is no longer highlighted // Assert that the Clock treeitem is no longer highlighted
await expect(clockTreeItem.locator('.c-tree__item')).not.toHaveClass(/is-targeted-item/); await expect(clockTreeItem.locator('.c-tree__item')).not.toHaveClass(/is-targeted-item/);
}); });
test("Persists on refresh", async ({ page }) => { test('Persists on refresh', async ({ page }) => {
await assertInitialRecentObjectsListState(); await assertInitialRecentObjectsListState();
await page.reload(); await page.reload();
await assertInitialRecentObjectsListState(); await assertInitialRecentObjectsListState();
}); });
test("Displays objects and aliases uniquely", async ({ page }) => { test('Displays objects and aliases uniquely', async ({ page }) => {
const mainTree = page.getByRole('tree', { name: 'Main Tree'}); const mainTree = page.getByRole('tree', { name: 'Main Tree' });
// Navigate to the clock and reveal it in the tree // Navigate to the clock and reveal it in the tree
await page.goto(clock.url); await page.goto(clock.url);
await page.getByTitle('Show selected item in tree').click(); await page.getByTitle('Show selected item in tree').click();
// Right click the clock and create an alias using the "link" context menu action // Right click the clock and create an alias using the "link" context menu action
const clockTreeItem = page.getByRole('tree', { const clockTreeItem = page
.getByRole('tree', {
name: 'Main Tree' name: 'Main Tree'
}).getByRole('treeitem', { })
.getByRole('treeitem', {
name: clock.name name: clock.name
}); });
await clockTreeItem.click({ await clockTreeItem.click({
button: 'right' button: 'right'
}); });
await page.getByRole('menuitem', { await page
.getByRole('menuitem', {
name: /Create Link/ name: /Create Link/
}).click(); })
await page.getByRole('tree', { name: 'Create Modal Tree'}).getByRole('treeitem').first().click(); .click();
await page
.getByRole('tree', { name: 'Create Modal Tree' })
.getByRole('treeitem')
.first()
.click();
await page.getByRole('button', { name: 'Save' }).click(); await page.getByRole('button', { name: 'Save' }).click();
// Click the newly created object alias in the tree // Click the newly created object alias in the tree
await mainTree.getByRole('treeitem', { await mainTree
.getByRole('treeitem', {
name: new RegExp(clock.name) name: new RegExp(clock.name)
}).filter({ })
.filter({
has: page.locator('.is-alias') has: page.locator('.is-alias')
}).click(); })
.click();
// Assert that two recent objects are displayed and one of them is an alias // Assert that two recent objects are displayed and one of them is an alias
expect(await recentObjectsList.getByRole('listitem', { name: clock.name }).count()).toBe(2); expect(await recentObjectsList.getByRole('listitem', { name: clock.name }).count()).toBe(2);
expect(await recentObjectsList.locator('.is-alias').count()).toBe(1); expect(await recentObjectsList.locator('.is-alias').count()).toBe(1);
// Assert that the alias and the original's breadcrumbs are different // Assert that the alias and the original's breadcrumbs are different
const clockBreadcrumbs = recentObjectsList.getByRole('listitem', {name: clock.name}).getByRole('navigation'); const clockBreadcrumbs = recentObjectsList
.getByRole('listitem', { name: clock.name })
.getByRole('navigation');
expect(await clockBreadcrumbs.count()).toBe(2); expect(await clockBreadcrumbs.count()).toBe(2);
expect(await clockBreadcrumbs.nth(0).innerText()).not.toEqual(await clockBreadcrumbs.nth(1).innerText()); expect(await clockBreadcrumbs.nth(0).innerText()).not.toEqual(
await clockBreadcrumbs.nth(1).innerText()
);
}); });
test("Enforces a limit of 20 recent objects and clears the recent objects", async ({ page }) => { test('Enforces a limit of 20 recent objects and clears the recent objects', async ({ page }) => {
// Creating 21 objects takes a while, so increase the timeout // Creating 21 objects takes a while, so increase the timeout
test.slow(); test.slow();
@ -203,11 +246,11 @@ test.describe('Recent Objects', () => {
// Create 19 more objects (3 in beforeEach() + 18 new = 21 total) // Create 19 more objects (3 in beforeEach() + 18 new = 21 total)
for (let i = 0; i < 9; i++) { for (let i = 0; i < 9; i++) {
lastFolder = await createDomainObjectWithDefaults(page, { lastFolder = await createDomainObjectWithDefaults(page, {
type: "Folder", type: 'Folder',
parent: lastFolder?.uuid parent: lastFolder?.uuid
}); });
lastClock = await createDomainObjectWithDefaults(page, { lastClock = await createDomainObjectWithDefaults(page, {
type: "Clock", type: 'Clock',
parent: lastFolder?.uuid parent: lastFolder?.uuid
}); });
} }
@ -216,19 +259,17 @@ test.describe('Recent Objects', () => {
expect(await recentObjectsList.locator('.c-recentobjects-listitem').count()).toBe(20); expect(await recentObjectsList.locator('.c-recentobjects-listitem').count()).toBe(20);
// Collapse the tree // Collapse the tree
await page.getByTitle("Collapse all tree items").click(); await page.getByTitle('Collapse all tree items').click();
const lastFolderTreeItem = page.getByRole('tree', { name: 'Main Tree'}) const lastFolderTreeItem = page.getByRole('tree', { name: 'Main Tree' }).getByRole('treeitem', {
.getByRole('treeitem', {
name: lastFolder.name, name: lastFolder.name,
expanded: true expanded: true
}); });
const lastClockTreeItem = page.getByRole('tree', { name: 'Main Tree'}) const lastClockTreeItem = page.getByRole('tree', { name: 'Main Tree' }).getByRole('treeitem', {
.getByRole('treeitem', {
name: lastClock.name name: lastClock.name
}); });
// Test "Open and Scroll To" in a deeply nested tree, while we're here // Test "Open and Scroll To" in a deeply nested tree, while we're here
await page.getByRole('button', { name: `Open and scroll to ${lastClock.name}`}).click(); await page.getByRole('button', { name: `Open and scroll to ${lastClock.name}` }).click();
// Assert that the Clock parent folder has expanded and the Clock is visible) // Assert that the Clock parent folder has expanded and the Clock is visible)
await expect(lastFolderTreeItem.locator('.c-disclosure-triangle')).toHaveClass(/--expanded/); await expect(lastFolderTreeItem.locator('.c-disclosure-triangle')).toHaveClass(/--expanded/);
@ -252,34 +293,28 @@ test.describe('Recent Objects', () => {
// Assert that the list is empty // Assert that the list is empty
expect(await recentObjectsList.locator('.c-recentobjects-listitem').count()).toBe(0); expect(await recentObjectsList.locator('.c-recentobjects-listitem').count()).toBe(0);
}); });
test("Ensure clear recent objects button is active or inactive", async ({ page }) => { test('Ensure clear recent objects button is active or inactive', async ({ page }) => {
// Assert that the list initially contains 3 objects (clock, folder, my items) // Assert that the list initially contains 3 objects (clock, folder, my items)
expect(await recentObjectsList.locator('.c-recentobjects-listitem').count()).toBe(3); expect(await recentObjectsList.locator('.c-recentobjects-listitem').count()).toBe(3);
// Assert that the button is enabled // Assert that the button is enabled
expect( expect(await page.getByRole('button', { name: 'Clear Recently Viewed' }).isEnabled()).toBe(
await page true
.getByRole("button", { name: "Clear Recently Viewed" }) );
.isEnabled()
).toBe(true);
// Click the aria-label="Clear Recently Viewed" button // Click the aria-label="Clear Recently Viewed" button
await page.getByRole("button", { name: "Clear Recently Viewed" }).click(); await page.getByRole('button', { name: 'Clear Recently Viewed' }).click();
// Click on the "OK" button in the confirmation dialog // Click on the "OK" button in the confirmation dialog
await page.getByRole("button", { name: "OK" }).click(); await page.getByRole('button', { name: 'OK' }).click();
// Assert that the list is empty // Assert that the list is empty
expect( expect(await recentObjectsList.locator('.c-recentobjects-listitem').count()).toBe(0);
await recentObjectsList.locator(".c-recentobjects-listitem").count()
).toBe(0);
// Assert that the button is disabled // Assert that the button is disabled
expect( expect(await page.getByRole('button', { name: 'Clear Recently Viewed' }).isEnabled()).toBe(
await page false
.getByRole("button", { name: "Clear Recently Viewed" }) );
.isEnabled()
).toBe(false);
// Navigate to folder object // Navigate to folder object
await page.goto(folderA.url); await page.goto(folderA.url);
@ -288,20 +323,28 @@ test.describe('Recent Objects', () => {
expect(await recentObjectsList.locator('.c-recentobjects-listitem').count()).toBe(1); expect(await recentObjectsList.locator('.c-recentobjects-listitem').count()).toBe(1);
// Assert that the button is enabled // Assert that the button is enabled
expect( expect(await page.getByRole('button', { name: 'Clear Recently Viewed' }).isEnabled()).toBe(
await page true
.getByRole("button", { name: "Clear Recently Viewed" }) );
.isEnabled()
).toBe(true);
}); });
function assertInitialRecentObjectsListState() { function assertInitialRecentObjectsListState() {
return Promise.all([ return Promise.all([
expect(recentObjectsList.getByRole('listitem', { name: clock.name })).toBeVisible(), expect(recentObjectsList.getByRole('listitem', { name: clock.name })).toBeVisible(),
expect(recentObjectsList.getByRole('listitem', { name: folderA.name })).toBeVisible(), expect(recentObjectsList.getByRole('listitem', { name: folderA.name })).toBeVisible(),
expect(recentObjectsList.getByRole('listitem', { name: clock.name }).locator('a').getByText(folderA.name)).toBeVisible(), expect(
recentObjectsList
.getByRole('listitem', { name: clock.name })
.locator('a')
.getByText(folderA.name)
).toBeVisible(),
expect(recentObjectsList.getByRole('listitem').nth(0).getByText(clock.name)).toBeVisible(), expect(recentObjectsList.getByRole('listitem').nth(0).getByText(clock.name)).toBeVisible(),
expect(recentObjectsList.getByRole('listitem', { name: clock.name }).locator('a').getByText(folderA.name)).toBeVisible(), expect(
recentObjectsList
.getByRole('listitem', { name: clock.name })
.locator('a')
.getByText(folderA.name)
).toBeVisible(),
expect(recentObjectsList.getByRole('listitem').nth(3).getByText(folderA.name)).toBeVisible() expect(recentObjectsList.getByRole('listitem').nth(3).getByText(folderA.name)).toBeVisible()
]); ]);
} }

View File

@ -33,10 +33,13 @@ test.describe('Grand Search', () => {
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
// Go to baseURL // Go to baseURL
await page.goto("./", { waitUntil: "networkidle" }); await page.goto('./', { waitUntil: 'networkidle' });
}); });
test('Can search for objects, and subsequent search dropdown behaves properly', async ({ page, openmctConfig }) => { test('Can search for objects, and subsequent search dropdown behaves properly', async ({
page,
openmctConfig
}) => {
const { myItemsFolderName } = openmctConfig; const { myItemsFolderName } = openmctConfig;
const createdObjects = await createObjectsForSearch(page); const createdObjects = await createObjectsForSearch(page);
@ -45,10 +48,18 @@ test.describe('Grand Search', () => {
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click(); await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
// Fill [aria-label="OpenMCT Search"] input[type="search"] // Fill [aria-label="OpenMCT Search"] input[type="search"]
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Cl'); await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Cl');
await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toContainText(`Clock A ${myItemsFolderName} Red Folder Blue Folder`); await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toContainText(
await expect(page.locator('[aria-label="Search Result"] >> nth=1')).toContainText(`Clock B ${myItemsFolderName} Red Folder Blue Folder`); `Clock A ${myItemsFolderName} Red Folder Blue Folder`
await expect(page.locator('[aria-label="Search Result"] >> nth=2')).toContainText(`Clock C ${myItemsFolderName} Red Folder Blue Folder`); );
await expect(page.locator('[aria-label="Search Result"] >> nth=3')).toContainText(`Clock D ${myItemsFolderName} Red Folder Blue Folder`); await expect(page.locator('[aria-label="Search Result"] >> nth=1')).toContainText(
`Clock B ${myItemsFolderName} Red Folder Blue Folder`
);
await expect(page.locator('[aria-label="Search Result"] >> nth=2')).toContainText(
`Clock C ${myItemsFolderName} Red Folder Blue Folder`
);
await expect(page.locator('[aria-label="Search Result"] >> nth=3')).toContainText(
`Clock D ${myItemsFolderName} Red Folder Blue Folder`
);
// Click the Elements pool to dismiss the search menu // Click the Elements pool to dismiss the search menu
await selectInspectorTab(page, 'Elements'); await selectInspectorTab(page, 'Elements');
await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toBeHidden(); await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toBeHidden();
@ -60,7 +71,9 @@ test.describe('Grand Search', () => {
// Click [aria-label="Close"] // Click [aria-label="Close"]
await page.locator('[aria-label="Close"]').click(); await page.locator('[aria-label="Close"]').click();
await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toBeVisible(); await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toBeVisible();
await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toContainText(`Clock A ${myItemsFolderName} Red Folder Blue Folder`); await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toContainText(
`Clock A ${myItemsFolderName} Red Folder Blue Folder`
);
// Click [aria-label="OpenMCT Search"] a >> nth=0 // Click [aria-label="OpenMCT Search"] a >> nth=0
await page.locator('[aria-label="Search Result"] >> nth=0').click(); await page.locator('[aria-label="Search Result"] >> nth=0').click();
@ -71,7 +84,10 @@ test.describe('Grand Search', () => {
await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toBeHidden(); await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toBeHidden();
// Click text=Snapshot Save and Finish Editing Save and Continue Editing >> button >> nth=1 // Click text=Snapshot Save and Finish Editing Save and Continue Editing >> button >> nth=1
await page.locator('text=Snapshot Save and Finish Editing Save and Continue Editing >> button').nth(1).click(); await page
.locator('text=Snapshot Save and Finish Editing Save and Continue Editing >> button')
.nth(1)
.click();
// Click text=Save and Finish Editing // Click text=Save and Finish Editing
await page.locator('text=Save and Finish Editing').click(); await page.locator('text=Save and Finish Editing').click();
// Click [aria-label="OpenMCT Search"] [aria-label="Search Input"] // Click [aria-label="OpenMCT Search"] [aria-label="Search Input"]
@ -85,22 +101,34 @@ test.describe('Grand Search', () => {
await expect(page.locator('.is-object-type-clock')).toBeVisible(); await expect(page.locator('.is-object-type-clock')).toBeVisible();
await page.locator('[aria-label="OpenMCT Search"] [aria-label="Search Input"]').fill('Disp'); await page.locator('[aria-label="OpenMCT Search"] [aria-label="Search Input"]').fill('Disp');
await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toContainText(createdObjects.displayLayout.name); await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toContainText(
createdObjects.displayLayout.name
);
await expect(page.locator('[aria-label="Search Result"] >> nth=0')).not.toContainText('Folder'); await expect(page.locator('[aria-label="Search Result"] >> nth=0')).not.toContainText('Folder');
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Clock C'); await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Clock C');
await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toContainText(`Clock C ${myItemsFolderName} Red Folder Blue Folder`); await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toContainText(
`Clock C ${myItemsFolderName} Red Folder Blue Folder`
);
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Cloc'); await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Cloc');
await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toContainText(`Clock A ${myItemsFolderName} Red Folder Blue Folder`); await expect(page.locator('[aria-label="Search Result"] >> nth=0')).toContainText(
await expect(page.locator('[aria-label="Search Result"] >> nth=1')).toContainText(`Clock B ${myItemsFolderName} Red Folder Blue Folder`); `Clock A ${myItemsFolderName} Red Folder Blue Folder`
await expect(page.locator('[aria-label="Search Result"] >> nth=2')).toContainText(`Clock C ${myItemsFolderName} Red Folder Blue Folder`); );
await expect(page.locator('[aria-label="Search Result"] >> nth=3')).toContainText(`Clock D ${myItemsFolderName} Red Folder Blue Folder`); await expect(page.locator('[aria-label="Search Result"] >> nth=1')).toContainText(
`Clock B ${myItemsFolderName} Red Folder Blue Folder`
);
await expect(page.locator('[aria-label="Search Result"] >> nth=2')).toContainText(
`Clock C ${myItemsFolderName} Red Folder Blue Folder`
);
await expect(page.locator('[aria-label="Search Result"] >> nth=3')).toContainText(
`Clock D ${myItemsFolderName} Red Folder Blue Folder`
);
}); });
test('Validate empty search result', async ({ page }) => { test('Validate empty search result', async ({ page }) => {
// Invalid search for objects // Invalid search for objects
await page.type("input[type=search]", 'not found'); await page.type('input[type=search]', 'not found');
// Wait for search to complete // Wait for search to complete
await waitForSearchCompletion(page); await waitForSearchCompletion(page);
@ -124,7 +152,7 @@ test.describe('Grand Search', () => {
}); });
// Full search for object // Full search for object
await page.type("input[type=search]", folderName); await page.type('input[type=search]', folderName);
// Wait for search to complete // Wait for search to complete
await waitForSearchCompletion(page); await waitForSearchCompletion(page);
@ -155,7 +183,7 @@ test.describe('Grand Search', () => {
}); });
// Full search for object // Full search for object
await page.type("input[type=search]", 'Clock', { delay: 100 }); await page.type('input[type=search]', 'Clock', { delay: 100 });
// Wait for search to finish // Wait for search to finish
await waitForSearchCompletion(page); await waitForSearchCompletion(page);
@ -169,15 +197,15 @@ test.describe('Grand Search', () => {
await expect(searchResultDropDown).toContainText('Clock A'); await expect(searchResultDropDown).toContainText('Clock A');
}); });
test("Validate multiple objects in search results return partial matches", async ({ page }) => { test('Validate multiple objects in search results return partial matches', async ({ page }) => {
test.info().annotations.push({ test.info().annotations.push({
type: 'issue', type: 'issue',
description: 'https://github.com/nasa/openmct/issues/4667' description: 'https://github.com/nasa/openmct/issues/4667'
}); });
// Create folder objects // Create folder objects
const folderName1 = "e928a26e-e924-4ea0"; const folderName1 = 'e928a26e-e924-4ea0';
const folderName2 = "e928a26e-e924-4001"; const folderName2 = 'e928a26e-e924-4001';
await createDomainObjectWithDefaults(page, { await createDomainObjectWithDefaults(page, {
type: 'Folder', type: 'Folder',
@ -190,7 +218,7 @@ test.describe('Grand Search', () => {
}); });
// Partial search for objects // Partial search for objects
await page.type("input[type=search]", 'e928a26e'); await page.type('input[type=search]', 'e928a26e');
// Wait for search to finish // Wait for search to finish
await waitForSearchCompletion(page); await waitForSearchCompletion(page);

View File

@ -35,8 +35,9 @@ Make no assumptions about the order that elements appear in the DOM.
const { test, expect } = require('../../pluginFixtures'); const { test, expect } = require('../../pluginFixtures');
test('Verify that the create button appears and that the Folder Domain Object is available for selection', async ({ page }) => { test('Verify that the create button appears and that the Folder Domain Object is available for selection', async ({
page
}) => {
//Go to baseURL //Go to baseURL
await page.goto('./', { waitUntil: 'domcontentloaded' }); await page.goto('./', { waitUntil: 'domcontentloaded' });

View File

@ -31,7 +31,9 @@ test.describe('Main Tree', () => {
await page.goto('./', { waitUntil: 'domcontentloaded' }); await page.goto('./', { waitUntil: 'domcontentloaded' });
}); });
test('Creating a child object within a folder and immediately opening it shows the created object in the tree @couchdb', async ({ page }) => { test('Creating a child object within a folder and immediately opening it shows the created object in the tree @couchdb', async ({
page
}) => {
test.info().annotations.push({ test.info().annotations.push({
type: 'issue', type: 'issue',
description: 'https://github.com/nasa/openmct/issues/5975' description: 'https://github.com/nasa/openmct/issues/5975'
@ -52,7 +54,10 @@ test.describe('Main Tree', () => {
await assertTreeItemIsVisible(page, clock.name); await assertTreeItemIsVisible(page, clock.name);
}); });
test('Creating a child object on one tab and expanding its parent on the other shows the correct composition @2p', async ({ page, openmctConfig }) => { test('Creating a child object on one tab and expanding its parent on the other shows the correct composition @2p', async ({
page,
openmctConfig
}) => {
test.info().annotations.push({ test.info().annotations.push({
type: 'issue', type: 'issue',
description: 'https://github.com/nasa/openmct/issues/6391' description: 'https://github.com/nasa/openmct/issues/6391'
@ -75,7 +80,10 @@ test.describe('Main Tree', () => {
await assertTreeItemIsVisible(page2, page1Folder.name); await assertTreeItemIsVisible(page2, page1Folder.name);
}); });
test('Creating a child object on one tab and expanding its parent on the other shows the correct composition @couchdb @2p', async ({ page, openmctConfig }) => { test('Creating a child object on one tab and expanding its parent on the other shows the correct composition @couchdb @2p', async ({
page,
openmctConfig
}) => {
test.info().annotations.push({ test.info().annotations.push({
type: 'issue', type: 'issue',
description: 'https://github.com/nasa/openmct/issues/6391' description: 'https://github.com/nasa/openmct/issues/6391'
@ -129,13 +137,13 @@ test.describe('Main Tree', () => {
// Expand the root folder // Expand the root folder
await expandTreePaneItemByName(page, myItemsFolderName); await expandTreePaneItemByName(page, myItemsFolderName);
await test.step("Reorders objects with the same tree depth", async () => { await test.step('Reorders objects with the same tree depth', async () => {
await getAndAssertTreeItems(page, ['aaa', 'Bar', 'Baz', 'Foo', 'www']); await getAndAssertTreeItems(page, ['aaa', 'Bar', 'Baz', 'Foo', 'www']);
await renameObjectFromContextMenu(page, clock1.url, 'zzz'); await renameObjectFromContextMenu(page, clock1.url, 'zzz');
await getAndAssertTreeItems(page, ['Bar', 'Baz', 'Foo', 'www', 'zzz']); await getAndAssertTreeItems(page, ['Bar', 'Baz', 'Foo', 'www', 'zzz']);
}); });
await test.step("Reorders links to objects as well as original objects", async () => { await test.step('Reorders links to objects as well as original objects', async () => {
await page.click('role=treeitem[name=/Bar/]'); await page.click('role=treeitem[name=/Bar/]');
await page.dragAndDrop('role=treeitem[name=/www/]', '.c-object-view'); await page.dragAndDrop('role=treeitem[name=/www/]', '.c-object-view');
await page.dragAndDrop('role=treeitem[name=/zzz/]', '.c-object-view'); await page.dragAndDrop('role=treeitem[name=/zzz/]', '.c-object-view');
@ -151,19 +159,18 @@ test.describe('Main Tree', () => {
await expandTreePaneItemByName(page, 'Foo'); await expandTreePaneItemByName(page, 'Foo');
await renameObjectFromContextMenu(page, clock1.url, '___'); await renameObjectFromContextMenu(page, clock1.url, '___');
await getAndAssertTreeItems(page, await getAndAssertTreeItems(page, [
[ '___',
"___", 'Bar',
"Bar", '___',
"___", 'www',
"www", 'Baz',
"Baz", '___',
"___", 'www',
"www", 'Foo',
"Foo", '___',
"___", 'www',
"www", 'www'
"www"
]); ]);
}); });
}); });
@ -217,7 +224,7 @@ async function renameObjectFromContextMenu(page, url, newName) {
await openObjectTreeContextMenu(page, url); await openObjectTreeContextMenu(page, url);
await page.click('li:text("Edit Properties")'); await page.click('li:text("Edit Properties")');
const nameInput = page.locator('form[name="mctForm"] .first input[type="text"]'); const nameInput = page.locator('form[name="mctForm"] .first input[type="text"]');
await nameInput.fill(""); await nameInput.fill('');
await nameInput.fill(newName); await nameInput.fill(newName);
await page.click('[aria-label="Save"]'); await page.click('[aria-label="Save"]');
} }

View File

@ -55,39 +55,50 @@ test.describe('Performance tests', () => {
// Click text=OK // Click text=OK
await page.locator('button:has-text("OK")').click(); await page.locator('button:has-text("OK")').click();
await expect(page.locator('a:has-text("Performance Display Layout Display Layout")')).toBeVisible(); await expect(
page.locator('a:has-text("Performance Display Layout Display Layout")')
).toBeVisible();
//Create a Chrome Performance Timeline trace to store as a test artifact //Create a Chrome Performance Timeline trace to store as a test artifact
console.log("\n==== Devtools: startTracing ====\n"); console.log('\n==== Devtools: startTracing ====\n');
await browser.startTracing(page, { await browser.startTracing(page, {
path: `${testInfo.outputPath()}-trace.json`, path: `${testInfo.outputPath()}-trace.json`,
screenshots: true screenshots: true
}); });
}); });
test.afterEach(async ({ page, browser}) => { test.afterEach(async ({ page, browser }) => {
console.log("\n==== Devtools: stopTracing ====\n"); console.log('\n==== Devtools: stopTracing ====\n');
await browser.stopTracing(); await browser.stopTracing();
/* Measurement Section /* Measurement Section
/ The following section includes a block of performance measurements. / The following section includes a block of performance measurements.
*/ */
//Get time difference between viewlarge actionability and evaluate time //Get time difference between viewlarge actionability and evaluate time
await page.evaluate(() => (window.performance.measure("machine-time-difference", "viewlarge.start", "viewLarge.start.test"))); await page.evaluate(() =>
window.performance.measure(
'machine-time-difference',
'viewlarge.start',
'viewLarge.start.test'
)
);
//Get StartTime //Get StartTime
const startTime = await page.evaluate(() => window.performance.timing.navigationStart); const startTime = await page.evaluate(() => window.performance.timing.navigationStart);
console.log('window.performance.timing.navigationStart', startTime); console.log('window.performance.timing.navigationStart', startTime);
//Get All Performance Marks //Get All Performance Marks
const getAllMarksJson = await page.evaluate(() => JSON.stringify(window.performance.getEntriesByType("mark"))); const getAllMarksJson = await page.evaluate(() =>
JSON.stringify(window.performance.getEntriesByType('mark'))
);
const getAllMarks = JSON.parse(getAllMarksJson); const getAllMarks = JSON.parse(getAllMarksJson);
console.log('window.performance.getEntriesByType("mark")', getAllMarks); console.log('window.performance.getEntriesByType("mark")', getAllMarks);
//Get All Performance Measures //Get All Performance Measures
const getAllMeasuresJson = await page.evaluate(() => JSON.stringify(window.performance.getEntriesByType("measure"))); const getAllMeasuresJson = await page.evaluate(() =>
JSON.stringify(window.performance.getEntriesByType('measure'))
);
const getAllMeasures = JSON.parse(getAllMeasuresJson); const getAllMeasures = JSON.parse(getAllMeasuresJson);
console.log('window.performance.getEntriesByType("measure")', getAllMeasures); console.log('window.performance.getEntriesByType("measure")', getAllMeasures);
}); });
/* The following test will navigate to a previously created Performance Display Layout and measure the /* The following test will navigate to a previously created Performance Display Layout and measure the
/ following metrics: / following metrics:
@ -104,48 +115,53 @@ test.describe('Performance tests', () => {
// Search Available after Launch // Search Available after Launch
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click(); await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
await page.evaluate(() => window.performance.mark("search-available")); await page.evaluate(() => window.performance.mark('search-available'));
// Fill Search input // Fill Search input
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Performance Display Layout'); await page
await page.evaluate(() => window.performance.mark("search-entered")); .locator('[aria-label="OpenMCT Search"] input[type="search"]')
.fill('Performance Display Layout');
await page.evaluate(() => window.performance.mark('search-entered'));
//Search Result Appears and is clicked //Search Result Appears and is clicked
await Promise.all([ await Promise.all([
page.waitForNavigation(), page.waitForNavigation(),
page.locator('a:has-text("Performance Display Layout")').first().click(), page.locator('a:has-text("Performance Display Layout")').first().click(),
page.evaluate(() => window.performance.mark("click-search-result")) page.evaluate(() => window.performance.mark('click-search-result'))
]); ]);
//Time to Example Imagery Frame loads within Display Layout //Time to Example Imagery Frame loads within Display Layout
await page.waitForSelector('.c-imagery__main-image__bg', { state: 'visible'}); await page.waitForSelector('.c-imagery__main-image__bg', { state: 'visible' });
//Time to Example Imagery object loads //Time to Example Imagery object loads
await page.waitForSelector('.c-imagery__main-image__background-image', { state: 'visible'}); await page.waitForSelector('.c-imagery__main-image__background-image', { state: 'visible' });
//Get background-image url from background-image css prop //Get background-image url from background-image css prop
const backgroundImage = await page.locator('.c-imagery__main-image__background-image'); const backgroundImage = await page.locator('.c-imagery__main-image__background-image');
let backgroundImageUrl = await backgroundImage.evaluate((el) => { let backgroundImageUrl = await backgroundImage.evaluate((el) => {
return window.getComputedStyle(el).getPropertyValue('background-image').match(/url\(([^)]+)\)/)[1]; return window
.getComputedStyle(el)
.getPropertyValue('background-image')
.match(/url\(([^)]+)\)/)[1];
}); });
backgroundImageUrl = backgroundImageUrl.slice(1, -1); //forgive me, padre backgroundImageUrl = backgroundImageUrl.slice(1, -1); //forgive me, padre
console.log('backgroundImageurl ' + backgroundImageUrl); console.log('backgroundImageurl ' + backgroundImageUrl);
//Get ResourceTiming of background-image jpg //Get ResourceTiming of background-image jpg
const resourceTimingJson = await page.evaluate((bgImageUrl) => const resourceTimingJson = await page.evaluate(
JSON.stringify(window.performance.getEntriesByName(bgImageUrl).pop()), (bgImageUrl) => JSON.stringify(window.performance.getEntriesByName(bgImageUrl).pop()),
backgroundImageUrl backgroundImageUrl
); );
console.log('resourceTimingJson ' + resourceTimingJson); console.log('resourceTimingJson ' + resourceTimingJson);
//Open Large view //Open Large view
await page.locator('button:has-text("Large View")').click(); //This action includes the performance.mark named 'viewLarge.start' await page.locator('button:has-text("Large View")').click(); //This action includes the performance.mark named 'viewLarge.start'
await page.evaluate(() => window.performance.mark("viewLarge.start.test")); //This is a mark only to compare evaluate timing await page.evaluate(() => window.performance.mark('viewLarge.start.test')); //This is a mark only to compare evaluate timing
//Time to Imagery Rendered in Large Frame //Time to Imagery Rendered in Large Frame
await page.waitForSelector('.c-imagery__main-image__bg', { state: 'visible'}); await page.waitForSelector('.c-imagery__main-image__bg', { state: 'visible' });
await page.evaluate(() => window.performance.mark("background-image-frame")); await page.evaluate(() => window.performance.mark('background-image-frame'));
//Time to Example Imagery object loads //Time to Example Imagery object loads
await page.waitForSelector('.c-imagery__main-image__background-image', { state: 'visible'}); await page.waitForSelector('.c-imagery__main-image__background-image', { state: 'visible' });
await page.evaluate(() => window.performance.mark("background-image-visible")); await page.evaluate(() => window.performance.mark('background-image-visible'));
// Get Current number of images in thumbstrip // Get Current number of images in thumbstrip
await page.waitForSelector('.c-imagery__thumb'); await page.waitForSelector('.c-imagery__thumb');
@ -158,20 +174,17 @@ test.describe('Performance tests', () => {
JSON.stringify(window.performance.getEntriesByType('resource')) JSON.stringify(window.performance.getEntriesByType('resource'))
); );
const resourceTiming = JSON.parse(resourceTimingJson2); const resourceTiming = JSON.parse(resourceTimingJson2);
const jpgResourceTiming = resourceTiming.find((element) => const jpgResourceTiming = resourceTiming.find((element) => element.name.includes('.jpg'));
element.name.includes('.jpg')
);
console.log('jpgResourceTiming ' + JSON.stringify(jpgResourceTiming)); console.log('jpgResourceTiming ' + JSON.stringify(jpgResourceTiming));
// Click Close Icon // Click Close Icon
await page.locator('[aria-label="Close"]').click(); await page.locator('[aria-label="Close"]').click();
await page.evaluate(() => window.performance.mark("view-large-close-button")); await page.evaluate(() => window.performance.mark('view-large-close-button'));
//await client.send('HeapProfiler.enable'); //await client.send('HeapProfiler.enable');
await client.send('HeapProfiler.collectGarbage'); await client.send('HeapProfiler.collectGarbage');
let performanceMetrics = await client.send('Performance.getMetrics'); let performanceMetrics = await client.send('Performance.getMetrics');
console.log(performanceMetrics.metrics); console.log(performanceMetrics.metrics);
}); });
}); });

View File

@ -56,17 +56,20 @@ test.describe.skip('Memory Performance tests', () => {
// Click text=OK // Click text=OK
await page.locator('text=OK').click(); await page.locator('text=OK').click();
await expect(page.locator('a:has-text("Performance Display Layout Display Layout")')).toBeVisible(); await expect(
page.locator('a:has-text("Performance Display Layout Display Layout")')
).toBeVisible();
}); });
test('Embedded View Large for Imagery is performant in Fixed Time', async ({ page, browser }) => { test('Embedded View Large for Imagery is performant in Fixed Time', async ({ page, browser }) => {
await page.goto('./', { waitUntil: 'networkidle' });
await page.goto('./', {waitUntil: 'networkidle'});
// To to Search Available after Launch // To to Search Available after Launch
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click(); await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
// Fill Search input // Fill Search input
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Performance Display Layout'); await page
.locator('[aria-label="OpenMCT Search"] input[type="search"]')
.fill('Performance Display Layout');
//Search Result Appears and is clicked //Search Result Appears and is clicked
await Promise.all([ await Promise.all([
page.waitForNavigation(), page.waitForNavigation(),
@ -74,9 +77,9 @@ test.describe.skip('Memory Performance tests', () => {
]); ]);
//Time to Example Imagery Frame loads within Display Layout //Time to Example Imagery Frame loads within Display Layout
await page.waitForSelector('.c-imagery__main-image__bg', { state: 'visible'}); await page.waitForSelector('.c-imagery__main-image__bg', { state: 'visible' });
//Time to Example Imagery object loads //Time to Example Imagery object loads
await page.waitForSelector('.c-imagery__main-image__background-image', { state: 'visible'}); await page.waitForSelector('.c-imagery__main-image__background-image', { state: 'visible' });
const client = await page.context().newCDPSession(page); const client = await page.context().newCDPSession(page);
await client.send('HeapProfiler.enable'); await client.send('HeapProfiler.enable');
@ -94,18 +97,18 @@ test.describe.skip('Memory Performance tests', () => {
await client.send('HeapProfiler.takeHeapSnapshot'); await client.send('HeapProfiler.takeHeapSnapshot');
//Time to Imagery Rendered in Large Frame //Time to Imagery Rendered in Large Frame
await page.waitForSelector('.c-imagery__main-image__bg', { state: 'visible'}); await page.waitForSelector('.c-imagery__main-image__bg', { state: 'visible' });
//Time to Example Imagery object loads //Time to Example Imagery object loads
await page.waitForSelector('.c-imagery__main-image__background-image', { state: 'visible'}); await page.waitForSelector('.c-imagery__main-image__background-image', { state: 'visible' });
// Click Close Icon // Click Close Icon
await page.locator('.c-click-icon').click(); await page.locator('.c-click-icon').click();
//Time to Example Imagery Frame loads within Display Layout //Time to Example Imagery Frame loads within Display Layout
await page.waitForSelector('.c-imagery__main-image__bg', { state: 'visible'}); await page.waitForSelector('.c-imagery__main-image__bg', { state: 'visible' });
//Time to Example Imagery object loads //Time to Example Imagery object loads
await page.waitForSelector('.c-imagery__main-image__background-image', { state: 'visible'}); await page.waitForSelector('.c-imagery__main-image__background-image', { state: 'visible' });
await client.send('HeapProfiler.collectGarbage'); await client.send('HeapProfiler.collectGarbage');
//await client.send('Performance.enable'); //await client.send('Performance.enable');
@ -114,6 +117,5 @@ test.describe.skip('Memory Performance tests', () => {
console.log(performanceMetricsAfter.metrics); console.log(performanceMetricsAfter.metrics);
//await client.send('Performance.disable'); //await client.send('Performance.disable');
}); });
}); });

View File

@ -57,14 +57,14 @@ test.describe('Performance tests', () => {
await expect(page.locator('a:has-text("Performance Notebook")')).toBeVisible(); await expect(page.locator('a:has-text("Performance Notebook")')).toBeVisible();
//Create a Chrome Performance Timeline trace to store as a test artifact //Create a Chrome Performance Timeline trace to store as a test artifact
console.log("\n==== Devtools: startTracing ====\n"); console.log('\n==== Devtools: startTracing ====\n');
await browser.startTracing(page, { await browser.startTracing(page, {
path: `${testInfo.outputPath()}-trace.json`, path: `${testInfo.outputPath()}-trace.json`,
screenshots: true screenshots: true
}); });
}); });
test.afterEach(async ({ page, browser}) => { test.afterEach(async ({ page, browser }) => {
console.log("\n==== Devtools: stopTracing ====\n"); console.log('\n==== Devtools: stopTracing ====\n');
await browser.stopTracing(); await browser.stopTracing();
/* Measurement Section /* Measurement Section
@ -74,15 +74,18 @@ test.describe('Performance tests', () => {
console.log('window.performance.timing.navigationStart', startTime); console.log('window.performance.timing.navigationStart', startTime);
//Get All Performance Marks //Get All Performance Marks
const getAllMarksJson = await page.evaluate(() => JSON.stringify(window.performance.getEntriesByType("mark"))); const getAllMarksJson = await page.evaluate(() =>
JSON.stringify(window.performance.getEntriesByType('mark'))
);
const getAllMarks = JSON.parse(getAllMarksJson); const getAllMarks = JSON.parse(getAllMarksJson);
console.log('window.performance.getEntriesByType("mark")', getAllMarks); console.log('window.performance.getEntriesByType("mark")', getAllMarks);
//Get All Performance Measures //Get All Performance Measures
const getAllMeasuresJson = await page.evaluate(() => JSON.stringify(window.performance.getEntriesByType("measure"))); const getAllMeasuresJson = await page.evaluate(() =>
JSON.stringify(window.performance.getEntriesByType('measure'))
);
const getAllMeasures = JSON.parse(getAllMeasuresJson); const getAllMeasures = JSON.parse(getAllMeasuresJson);
console.log('window.performance.getEntriesByType("measure")', getAllMeasures); console.log('window.performance.getEntriesByType("measure")', getAllMeasures);
}); });
/* The following test will navigate to a previously created Performance Display Layout and measure the /* The following test will navigate to a previously created Performance Display Layout and measure the
/ following metrics: / following metrics:
@ -99,56 +102,60 @@ test.describe('Performance tests', () => {
// To to Search Available after Launch // To to Search Available after Launch
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click(); await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
await page.evaluate(() => window.performance.mark("search-available")); await page.evaluate(() => window.performance.mark('search-available'));
// Fill Search input // Fill Search input
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Performance Notebook'); await page
await page.evaluate(() => window.performance.mark("search-entered")); .locator('[aria-label="OpenMCT Search"] input[type="search"]')
.fill('Performance Notebook');
await page.evaluate(() => window.performance.mark('search-entered'));
//Search Result Appears and is clicked //Search Result Appears and is clicked
await Promise.all([ await Promise.all([
page.waitForNavigation(), page.waitForNavigation(),
page.locator('a:has-text("Performance Notebook")').first().click(), page.locator('a:has-text("Performance Notebook")').first().click(),
page.evaluate(() => window.performance.mark("click-search-result")) page.evaluate(() => window.performance.mark('click-search-result'))
]); ]);
await page.waitForSelector('.c-tree__item c-tree-and-search__loading loading', {state: 'hidden'}); await page.waitForSelector('.c-tree__item c-tree-and-search__loading loading', {
await page.evaluate(() => window.performance.mark("search-spinner-gone")); state: 'hidden'
});
await page.evaluate(() => window.performance.mark('search-spinner-gone'));
await page.waitForSelector('.l-browse-bar__object-name', { state: 'visible'}); await page.waitForSelector('.l-browse-bar__object-name', { state: 'visible' });
await page.evaluate(() => window.performance.mark("object-title-appears")); await page.evaluate(() => window.performance.mark('object-title-appears'));
await page.waitForSelector('.c-notebook__entry >> nth=0', { state: 'visible'}); await page.waitForSelector('.c-notebook__entry >> nth=0', { state: 'visible' });
await page.evaluate(() => window.performance.mark("notebook-entry-appears")); await page.evaluate(() => window.performance.mark('notebook-entry-appears'));
// Click Add new Notebook Entry // Click Add new Notebook Entry
await page.locator('.c-notebook__drag-area').click(); await page.locator('.c-notebook__drag-area').click();
await page.evaluate(() => window.performance.mark("new-notebook-entry-created")); await page.evaluate(() => window.performance.mark('new-notebook-entry-created'));
// Enter Notebook Entry text // Enter Notebook Entry text
await page.locator('div.c-ne__text').last().fill('New Entry'); await page.locator('div.c-ne__text').last().fill('New Entry');
await page.keyboard.press('Enter'); await page.keyboard.press('Enter');
await page.evaluate(() => window.performance.mark("new-notebook-entry-filled")); await page.evaluate(() => window.performance.mark('new-notebook-entry-filled'));
//Individual Notebook Entry Search //Individual Notebook Entry Search
await page.evaluate(() => window.performance.mark("notebook-search-start")); await page.evaluate(() => window.performance.mark('notebook-search-start'));
await page.locator('.c-notebook__search >> input').fill('Existing Entry'); await page.locator('.c-notebook__search >> input').fill('Existing Entry');
await page.evaluate(() => window.performance.mark("notebook-search-filled")); await page.evaluate(() => window.performance.mark('notebook-search-filled'));
await page.waitForSelector('text=Search Results (3)', { state: 'visible'}); await page.waitForSelector('text=Search Results (3)', { state: 'visible' });
await page.evaluate(() => window.performance.mark("notebook-search-processed")); await page.evaluate(() => window.performance.mark('notebook-search-processed'));
await page.waitForSelector('.c-notebook__entry >> nth=2', { state: 'visible'}); await page.waitForSelector('.c-notebook__entry >> nth=2', { state: 'visible' });
await page.evaluate(() => window.performance.mark("notebook-search-processed")); await page.evaluate(() => window.performance.mark('notebook-search-processed'));
//Clear Search //Clear Search
await page.locator('.c-search.c-notebook__search .c-search__input').hover(); await page.locator('.c-search.c-notebook__search .c-search__input').hover();
await page.locator('.c-search.c-notebook__search .c-search__clear-input').click(); await page.locator('.c-search.c-notebook__search .c-search__clear-input').click();
await page.evaluate(() => window.performance.mark("notebook-search-processed")); await page.evaluate(() => window.performance.mark('notebook-search-processed'));
// Hover on Last // Hover on Last
await page.evaluate(() => window.performance.mark("new-notebook-entry-delete")); await page.evaluate(() => window.performance.mark('new-notebook-entry-delete'));
await page.locator('div.c-ne__time-and-content').last().hover(); await page.locator('div.c-ne__time-and-content').last().hover();
await page.locator('button[title="Delete this entry"]').last().click(); await page.locator('button[title="Delete this entry"]').last().click();
await page.locator('button:has-text("Ok")').click(); await page.locator('button:has-text("Ok")').click();
await page.waitForSelector('.c-notebook__entry >> nth=3', { state: 'detached'}); await page.waitForSelector('.c-notebook__entry >> nth=3', { state: 'detached' });
await page.evaluate(() => window.performance.mark("new-notebook-entry-deleted")); await page.evaluate(() => window.performance.mark('new-notebook-entry-deleted'));
//await client.send('HeapProfiler.enable'); //await client.send('HeapProfiler.enable');
await client.send('HeapProfiler.collectGarbage'); await client.send('HeapProfiler.collectGarbage');

View File

@ -48,7 +48,9 @@ test.describe('Visual - addInit', () => {
}); });
test('Restricted Notebook is visually correct @addInit @unstable', async ({ page, theme }) => { test('Restricted Notebook is visually correct @addInit @unstable', async ({ page, theme }) => {
await page.addInitScript({ path: path.join(__dirname, '../../helper', './addInitRestrictedNotebook.js') }); await page.addInitScript({
path: path.join(__dirname, '../../helper', './addInitRestrictedNotebook.js')
});
//Go to baseURL //Go to baseURL
await page.goto('./#/browse/mine?hideTree=true', { waitUntil: 'networkidle' }); await page.goto('./#/browse/mine?hideTree=true', { waitUntil: 'networkidle' });
@ -56,6 +58,5 @@ test.describe('Visual - addInit', () => {
// Take a snapshot of the newly created CUSTOM_NAME notebook // Take a snapshot of the newly created CUSTOM_NAME notebook
await percySnapshot(page, `Restricted Notebook with CUSTOM_NAME (theme: '${theme}')`); await percySnapshot(page, `Restricted Notebook with CUSTOM_NAME (theme: '${theme}')`);
}); });
}); });

View File

@ -32,18 +32,18 @@ test.describe('Visual - Tree Pane', () => {
const foo = await createDomainObjectWithDefaults(page, { const foo = await createDomainObjectWithDefaults(page, {
type: 'Folder', type: 'Folder',
name: "Foo Folder" name: 'Foo Folder'
}); });
const bar = await createDomainObjectWithDefaults(page, { const bar = await createDomainObjectWithDefaults(page, {
type: 'Folder', type: 'Folder',
name: "Bar Folder", name: 'Bar Folder',
parent: foo.uuid parent: foo.uuid
}); });
const baz = await createDomainObjectWithDefaults(page, { const baz = await createDomainObjectWithDefaults(page, {
type: 'Folder', type: 'Folder',
name: "Baz Folder", name: 'Baz Folder',
parent: bar.uuid parent: bar.uuid
}); });

View File

@ -48,7 +48,7 @@ test.describe('Visual - Controlled Clock @localStorage', () => {
await expect(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Overlay Plot'); await expect(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Overlay Plot');
//Wait for canvas to be rendered and stop animating //Wait for canvas to be rendered and stop animating
await page.locator('canvas >> nth=1').hover({trial: true}); await page.locator('canvas >> nth=1').hover({ trial: true });
//Take snapshot of Sine Wave Generator within Overlay Plot //Take snapshot of Sine Wave Generator within Overlay Plot
await percySnapshot(page, `SineWaveInOverlayPlot (theme: '${theme}')`); await percySnapshot(page, `SineWaveInOverlayPlot (theme: '${theme}')`);

View File

@ -61,14 +61,17 @@ test.describe('Visual - Default', () => {
// Modify the Build information in 'about' to be consistent run-over-run // Modify the Build information in 'about' to be consistent run-over-run
const versionInformationLocator = page.locator('ul.t-info.l-info.s-info').first(); const versionInformationLocator = page.locator('ul.t-info.l-info.s-info').first();
await expect(versionInformationLocator).toBeEnabled(); await expect(versionInformationLocator).toBeEnabled();
await versionInformationLocator.evaluate(node => node.innerHTML = '<li>Version: visual-snapshot</li> <li>Build Date: Mon Nov 15 2021 08:07:51 GMT-0800 (Pacific Standard Time)</li> <li>Revision: 93049cdbc6c047697ca204893db9603b864b8c9f</li> <li>Branch: master</li>'); await versionInformationLocator.evaluate(
(node) =>
(node.innerHTML =
'<li>Version: visual-snapshot</li> <li>Build Date: Mon Nov 15 2021 08:07:51 GMT-0800 (Pacific Standard Time)</li> <li>Revision: 93049cdbc6c047697ca204893db9603b864b8c9f</li> <li>Branch: master</li>')
);
// Take a snapshot of the About modal // Take a snapshot of the About modal
await percySnapshot(page, `About (theme: '${theme}')`); await percySnapshot(page, `About (theme: '${theme}')`);
}); });
test('Visual - Default Condition Set @unstable', async ({ page, theme }) => { test('Visual - Default Condition Set @unstable', async ({ page, theme }) => {
await createDomainObjectWithDefaults(page, { type: 'Condition Set' }); await createDomainObjectWithDefaults(page, { type: 'Condition Set' });
// Take a snapshot of the newly created Condition Set object // Take a snapshot of the newly created Condition Set object
@ -102,17 +105,17 @@ test.describe('Visual - Default', () => {
// verify no error msg // verify no error msg
await percySnapshot(page, `Default Time conductor (theme: '${theme}')`); await percySnapshot(page, `Default Time conductor (theme: '${theme}')`);
startDate = (year + 1) + startDate.substring(4); startDate = year + 1 + startDate.substring(4);
await page.locator('input[type="text"]').first().fill(startDate.toString()); await page.locator('input[type="text"]').first().fill(startDate.toString());
await page.locator('input[type="text"]').nth(1).click(); await page.locator('input[type="text"]').nth(1).click();
// verify error msg for start time (unable to capture snapshot of popup) // verify error msg for start time (unable to capture snapshot of popup)
await percySnapshot(page, `Start time error (theme: '${theme}')`); await percySnapshot(page, `Start time error (theme: '${theme}')`);
startDate = (year - 1) + startDate.substring(4); startDate = year - 1 + startDate.substring(4);
await page.locator('input[type="text"]').first().fill(startDate.toString()); await page.locator('input[type="text"]').first().fill(startDate.toString());
endDate = (year - 2) + endDate.substring(4); endDate = year - 2 + endDate.substring(4);
await page.locator('input[type="text"]').nth(1).fill(endDate.toString()); await page.locator('input[type="text"]').nth(1).fill(endDate.toString());
await page.locator('input[type="text"]').first().click(); await page.locator('input[type="text"]').first().click();
@ -145,7 +148,7 @@ test.describe('Visual - Default', () => {
//Wait until Save Banner is gone //Wait until Save Banner is gone
await page.locator('.c-message-banner__close-button').click(); await page.locator('.c-message-banner__close-button').click();
await page.waitForSelector('.c-message-banner__message', { state: 'detached'}); await page.waitForSelector('.c-message-banner__message', { state: 'detached' });
await percySnapshot(page, `Banner message gone (theme: '${theme}')`); await percySnapshot(page, `Banner message gone (theme: '${theme}')`);
}); });
@ -156,7 +159,6 @@ test.describe('Visual - Default', () => {
//Hover on Display Layout option. //Hover on Display Layout option.
await page.locator('text=Display Layout').hover(); await page.locator('text=Display Layout').hover();
await percySnapshot(page, `Display Layout Create Menu (theme: '${theme}')`); await percySnapshot(page, `Display Layout Create Menu (theme: '${theme}')`);
}); });
test('Visual - Default Gauge is correct @unstable', async ({ page, theme }) => { test('Visual - Default Gauge is correct @unstable', async ({ page, theme }) => {

View File

@ -27,9 +27,10 @@ const percySnapshot = require('@percy/playwright');
const utils = require('../../helper/faultUtils'); const utils = require('../../helper/faultUtils');
test.describe('The Fault Management Plugin Visual Test', () => { test.describe('The Fault Management Plugin Visual Test', () => {
test('icon test', async ({ page, theme }) => { test('icon test', async ({ page, theme }) => {
await page.addInitScript({ path: path.join(__dirname, '../../helper/', 'addInitFaultManagementPlugin.js') }); await page.addInitScript({
path: path.join(__dirname, '../../helper/', 'addInitFaultManagementPlugin.js')
});
await page.goto('./', { waitUntil: 'networkidle' }); await page.goto('./', { waitUntil: 'networkidle' });
await percySnapshot(page, `Fault Management icon appears in tree (theme: '${theme}')`); await percySnapshot(page, `Fault Management icon appears in tree (theme: '${theme}')`);
@ -43,7 +44,10 @@ test.describe('The Fault Management Plugin Visual Test', () => {
await utils.acknowledgeFault(page, 1); await utils.acknowledgeFault(page, 1);
await utils.changeViewTo(page, 'acknowledged'); await utils.changeViewTo(page, 'acknowledged');
await percySnapshot(page, `Acknowledged faults, have a checkmark on the fault icon and appear in the acknowldeged view (theme: '${theme}')`); await percySnapshot(
page,
`Acknowledged faults, have a checkmark on the fault icon and appear in the acknowldeged view (theme: '${theme}')`
);
}); });
test('shelved faults', async ({ page, theme }) => { test('shelved faults', async ({ page, theme }) => {
@ -56,7 +60,10 @@ test.describe('The Fault Management Plugin Visual Test', () => {
await utils.openFaultRowMenu(page, 1); await utils.openFaultRowMenu(page, 1);
await percySnapshot(page, `Shelved faults have a 3-dot menu with Unshelve option enabled (theme: '${theme}')`); await percySnapshot(
page,
`Shelved faults have a 3-dot menu with Unshelve option enabled (theme: '${theme}')`
);
}); });
test('3-dot menu for fault', async ({ page, theme }) => { test('3-dot menu for fault', async ({ page, theme }) => {
@ -64,7 +71,10 @@ test.describe('The Fault Management Plugin Visual Test', () => {
await utils.openFaultRowMenu(page, 1); await utils.openFaultRowMenu(page, 1);
await percySnapshot(page, `Faults have a 3-dot menu with Acknowledge, Shelve and Unshelve (Unshelve is disabled) options (theme: '${theme}')`); await percySnapshot(
page,
`Faults have a 3-dot menu with Acknowledge, Shelve and Unshelve (Unshelve is disabled) options (theme: '${theme}')`
);
}); });
test('ability to acknowledge or shelve', async ({ page, theme }) => { test('ability to acknowledge or shelve', async ({ page, theme }) => {
@ -72,6 +82,9 @@ test.describe('The Fault Management Plugin Visual Test', () => {
await utils.selectFaultItem(page, 1); await utils.selectFaultItem(page, 1);
await percySnapshot(page, `Selected faults highlight the ability to Acknowledge or Shelve above the fault list (theme: '${theme}')`); await percySnapshot(
page,
`Selected faults highlight the ability to Acknowledge or Shelve above the fault list (theme: '${theme}')`
);
}); });
}); });

View File

@ -54,7 +54,6 @@ test.describe('Visual - LAD Table', () => {
await page.getByRole('button', { name: 'Save' }).click(); await page.getByRole('button', { name: 'Save' }).click();
}); });
test('Toggled column widths behave accordingly', async ({ page, theme }) => { test('Toggled column widths behave accordingly', async ({ page, theme }) => {
await page.goto(ladTable.url); await page.goto(ladTable.url);
//Close panes for visual consistency //Close panes for visual consistency
await page.getByTitle('Collapse Inspect Pane').click(); await page.getByTitle('Collapse Inspect Pane').click();
@ -62,13 +61,18 @@ test.describe('Visual - LAD Table', () => {
await expect(page.locator('button[title="Expand Columns"]')).toBeVisible(); await expect(page.locator('button[title="Expand Columns"]')).toBeVisible();
await percySnapshot(page, `LAD Table w/ Sine Wave Generator columns autosized (theme: ${theme})`); await percySnapshot(
page,
`LAD Table w/ Sine Wave Generator columns autosized (theme: ${theme})`
);
await page.locator('button[title="Expand Columns"]').click(); await page.locator('button[title="Expand Columns"]').click();
await expect(page.locator('button[title="Autosize Columns"]')).toBeVisible(); await expect(page.locator('button[title="Autosize Columns"]')).toBeVisible();
await percySnapshot(page, `LAD Table w/ Sine Wave Generator columns expanded (theme: ${theme})`); await percySnapshot(
page,
`LAD Table w/ Sine Wave Generator columns expanded (theme: ${theme})`
);
}); });
}); });

View File

@ -32,12 +32,12 @@ test.describe('Visual - Notebook', () => {
// Create Notebook // Create Notebook
const notebook = await createDomainObjectWithDefaults(page, { const notebook = await createDomainObjectWithDefaults(page, {
type: 'Notebook', type: 'Notebook',
name: "Embed Test Notebook" name: 'Embed Test Notebook'
}); });
// Create Overlay Plot // Create Overlay Plot
await createDomainObjectWithDefaults(page, { await createDomainObjectWithDefaults(page, {
type: 'Overlay Plot', type: 'Overlay Plot',
name: "Dropped Overlay Plot" name: 'Dropped Overlay Plot'
}); });
await expandTreePaneItemByName(page, myItemsFolderName); await expandTreePaneItemByName(page, myItemsFolderName);
@ -46,6 +46,5 @@ test.describe('Visual - Notebook', () => {
await page.dragAndDrop('role=treeitem[name=/Dropped Overlay Plot/]', '.c-notebook__drag-area'); await page.dragAndDrop('role=treeitem[name=/Dropped Overlay Plot/]', '.c-notebook__drag-area');
await percySnapshot(page, `Notebook w/ dropped embed (theme: ${theme})`); await percySnapshot(page, `Notebook w/ dropped embed (theme: ${theme})`);
}); });
}); });

View File

@ -28,19 +28,24 @@ const { test, expect } = require('../../pluginFixtures');
const percySnapshot = require('@percy/playwright'); const percySnapshot = require('@percy/playwright');
const { createDomainObjectWithDefaults } = require('../../appActions'); const { createDomainObjectWithDefaults } = require('../../appActions');
test.describe('Visual - Check Notification Info Banner of \'Save successful\'', () => { test.describe("Visual - Check Notification Info Banner of 'Save successful'", () => {
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
// Go to baseURL and Hide Tree // Go to baseURL and Hide Tree
await page.goto('./', { waitUntil: 'networkidle' }); await page.goto('./', { waitUntil: 'networkidle' });
}); });
test('Create a clock, click on \'Save successful\' banner and dismiss it', async ({ page, theme }) => { test("Create a clock, click on 'Save successful' banner and dismiss it", async ({
page,
theme
}) => {
// Create a clock domain object // Create a clock domain object
await createDomainObjectWithDefaults(page, { type: 'Clock' }); await createDomainObjectWithDefaults(page, { type: 'Clock' });
// Verify there is a button with aria-label="Review 1 Notification" // Verify there is a button with aria-label="Review 1 Notification"
expect(await page.locator('button[aria-label="Review 1 Notification"]').isVisible()).toBe(true); expect(await page.locator('button[aria-label="Review 1 Notification"]').isVisible()).toBe(true);
// Verify there is a button with aria-label="Clear all notifications" // Verify there is a button with aria-label="Clear all notifications"
expect(await page.locator('button[aria-label="Clear all notifications"]').isVisible()).toBe(true); expect(await page.locator('button[aria-label="Clear all notifications"]').isVisible()).toBe(
true
);
// Click on the div with role="alert" that has "Save successful" text // Click on the div with role="alert" that has "Save successful" text
await page.locator('div[role="alert"]:has-text("Save successful")').click(); await page.locator('div[role="alert"]:has-text("Save successful")').click();
// Verify there is a div with role="dialog" // Verify there is a div with role="dialog"

View File

@ -41,7 +41,10 @@ test.describe('Grand Search', () => {
} }
}); });
//This needs to be rewritten to use a non clock or non display layout object //This needs to be rewritten to use a non clock or non display layout object
test('Can search for objects, and subsequent search dropdown behaves properly @unstable', async ({ page, theme }) => { test('Can search for objects, and subsequent search dropdown behaves properly @unstable', async ({
page,
theme
}) => {
// await createDomainObjectWithDefaults(page, 'Display Layout'); // await createDomainObjectWithDefaults(page, 'Display Layout');
// await page.locator('text=Snapshot Save and Finish Editing Save and Continue Editing >> button').nth(1).click(); // await page.locator('text=Snapshot Save and Finish Editing Save and Continue Editing >> button').nth(1).click();
// await page.locator('text=Save and Finish Editing').click(); // await page.locator('text=Save and Finish Editing').click();
@ -60,12 +63,18 @@ test.describe('Grand Search', () => {
await page.locator('[aria-label="OpenMCT Search"] [aria-label="Search Input"]').click(); await page.locator('[aria-label="OpenMCT Search"] [aria-label="Search Input"]').click();
await page.locator('[aria-label="Unnamed Clock clock result"] >> text=Unnamed Clock').click(); await page.locator('[aria-label="Unnamed Clock clock result"] >> text=Unnamed Clock').click();
await percySnapshot(page, 'Preview for clock should display when editing enabled and search item clicked'); await percySnapshot(
page,
'Preview for clock should display when editing enabled and search item clicked'
);
await page.locator('[aria-label="Close"]').click(); await page.locator('[aria-label="Close"]').click();
await percySnapshot(page, 'Search should still be showing after preview closed'); await percySnapshot(page, 'Search should still be showing after preview closed');
await page.locator('text=Snapshot Save and Finish Editing Save and Continue Editing >> button').nth(1).click(); await page
.locator('text=Snapshot Save and Finish Editing Save and Continue Editing >> button')
.nth(1)
.click();
await page.locator('text=Save and Finish Editing').click(); await page.locator('text=Save and Finish Editing').click();
@ -73,12 +82,10 @@ test.describe('Grand Search', () => {
await page.locator('[aria-label="OpenMCT Search"] [aria-label="Search Input"]').fill('Cl'); await page.locator('[aria-label="OpenMCT Search"] [aria-label="Search Input"]').fill('Cl');
await Promise.all([ await Promise.all([page.waitForNavigation(), page.locator('text=Unnamed Clock').click()]);
page.waitForNavigation(), await percySnapshot(
page.locator('text=Unnamed Clock').click() page,
]); `Clicking on search results should navigate to them if not editing (theme: '${theme}')`
await percySnapshot(page, `Clicking on search results should navigate to them if not editing (theme: '${theme}')`); );
}); });
}); });

View File

@ -23,25 +23,25 @@
class EventMetadataProvider { class EventMetadataProvider {
constructor() { constructor() {
this.METADATA_BY_TYPE = { this.METADATA_BY_TYPE = {
'eventGenerator': { eventGenerator: {
values: [ values: [
{ {
key: "name", key: 'name',
name: "Name", name: 'Name',
format: "string" format: 'string'
}, },
{ {
key: "utc", key: 'utc',
name: "Time", name: 'Time',
format: "utc", format: 'utc',
hints: { hints: {
domain: 1 domain: 1
} }
}, },
{ {
key: "message", key: 'message',
name: "Message", name: 'Message',
format: "string" format: 'string'
} }
] ]
} }
@ -53,11 +53,7 @@ class EventMetadataProvider {
} }
getMetadata(domainObject) { getMetadata(domainObject) {
return Object.assign( return Object.assign({}, domainObject.telemetry, this.METADATA_BY_TYPE[domainObject.type]);
{},
domainObject.telemetry,
this.METADATA_BY_TYPE[domainObject.type]
);
} }
} }

View File

@ -33,9 +33,9 @@ class EventTelemetryProvider {
generateData(firstObservedTime, count, startTime, duration, name) { generateData(firstObservedTime, count, startTime, duration, name) {
const millisecondsSinceStart = startTime - firstObservedTime; const millisecondsSinceStart = startTime - firstObservedTime;
const utc = startTime + (count * duration); const utc = startTime + count * duration;
const ind = count % messages.length; const ind = count % messages.length;
const message = messages[ind] + " - [" + millisecondsSinceStart + "]"; const message = messages[ind] + ' - [' + millisecondsSinceStart + ']';
return { return {
name, name,
@ -59,7 +59,13 @@ class EventTelemetryProvider {
const interval = setInterval(() => { const interval = setInterval(() => {
const startTime = Date.now(); const startTime = Date.now();
const datum = this.generateData(firstObservedTime, count, startTime, duration, domainObject.name); const datum = this.generateData(
firstObservedTime,
count,
startTime,
duration,
domainObject.name
);
count += 1; count += 1;
callback(datum); callback(datum);
}, duration); }, duration);
@ -84,7 +90,9 @@ class EventTelemetryProvider {
while (start <= end && data.length < size) { while (start <= end && data.length < size) {
const startTime = options.start + count; const startTime = options.start + count;
data.push(this.generateData(firstObservedTime, count, startTime, duration, domainObject.name)); data.push(
this.generateData(firstObservedTime, count, startTime, duration, domainObject.name)
);
start += duration; start += duration;
count += 1; count += 1;
} }

View File

@ -24,10 +24,11 @@ import EventMetadataProvider from './EventMetadataProvider';
export default function EventGeneratorPlugin(options) { export default function EventGeneratorPlugin(options) {
return function install(openmct) { return function install(openmct) {
openmct.types.addType("eventGenerator", { openmct.types.addType('eventGenerator', {
name: "Event Message Generator", name: 'Event Message Generator',
description: "For development use. Creates sample event message data that mimics a live data stream.", description:
cssClass: "icon-generator-events", 'For development use. Creates sample event message data that mimics a live data stream.',
cssClass: 'icon-generator-events',
creatable: true, creatable: true,
initialize: function (object) { initialize: function (object) {
object.telemetry = { object.telemetry = {
@ -37,6 +38,5 @@ export default function EventGeneratorPlugin(options) {
}); });
openmct.telemetry.addProvider(new EventTelmetryProvider()); openmct.telemetry.addProvider(new EventTelmetryProvider());
openmct.telemetry.addProvider(new EventMetadataProvider()); openmct.telemetry.addProvider(new EventMetadataProvider());
}; };
} }

View File

@ -20,10 +20,7 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
import EventMessageGeneratorPlugin from './plugin.js'; import EventMessageGeneratorPlugin from './plugin.js';
import { import { createOpenMct, resetApplicationState } from '../../src/utils/testing';
createOpenMct,
resetApplicationState
} from '../../src/utils/testing';
describe('the plugin', () => { describe('the plugin', () => {
let openmct; let openmct;
@ -52,7 +49,7 @@ describe('the plugin', () => {
}); });
describe('the plugin', () => { describe('the plugin', () => {
it("supports subscription", (done) => { it('supports subscription', (done) => {
const unsubscribe = openmct.telemetry.subscribe(mockDomainObject, (telemetry) => { const unsubscribe = openmct.telemetry.subscribe(mockDomainObject, (telemetry) => {
expect(telemetry).not.toEqual(null); expect(telemetry).not.toEqual(null);
expect(telemetry.message).toContain('CC: Eagle, Houston'); expect(telemetry.message).toContain('CC: Eagle, Houston');
@ -62,12 +59,12 @@ describe('the plugin', () => {
}); });
}); });
it("supports requests without start/end defined", async () => { it('supports requests without start/end defined', async () => {
const telemetry = await openmct.telemetry.request(mockDomainObject); const telemetry = await openmct.telemetry.request(mockDomainObject);
expect(telemetry[0].message).toContain('CC: Eagle, Houston'); expect(telemetry[0].message).toContain('CC: Eagle, Houston');
}); });
it("supports requests with arbitrary start time in the past", async () => { it('supports requests with arbitrary start time in the past', async () => {
mockDomainObject.options.start = 100000000000; // Mar 03 1973 mockDomainObject.options.start = 100000000000; // Mar 03 1973
const telemetry = await openmct.telemetry.request(mockDomainObject); const telemetry = await openmct.telemetry.request(mockDomainObject);
expect(telemetry[0].message).toContain('CC: Eagle, Houston'); expect(telemetry[0].message).toContain('CC: Eagle, Houston');

View File

@ -37,7 +37,7 @@ export default function exampleTagsPlugin(options) {
openmct.annotation.setNamespaceToSaveAnnotations(options?.namespaceToSaveAnnotations); openmct.annotation.setNamespaceToSaveAnnotations(options?.namespaceToSaveAnnotations);
} }
Object.keys(availableTags.tags).forEach(tagKey => { Object.keys(availableTags.tags).forEach((tagKey) => {
const tagDefinition = availableTags.tags[tagKey]; const tagDefinition = availableTags.tags[tagKey];
openmct.annotation.defineTag(tagKey, tagDefinition); openmct.annotation.defineTag(tagKey, tagDefinition);
}); });

View File

@ -24,41 +24,46 @@ import EventEmitter from 'EventEmitter';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import createExampleUser from './exampleUserCreator'; import createExampleUser from './exampleUserCreator';
const STATUSES = [{ const STATUSES = [
key: "NO_STATUS", {
label: "Not set", key: 'NO_STATUS',
iconClass: "icon-question-mark", label: 'Not set',
iconClassPoll: "icon-status-poll-question-mark" iconClass: 'icon-question-mark',
}, { iconClassPoll: 'icon-status-poll-question-mark'
key: "GO", },
label: "Go", {
iconClass: "icon-check", key: 'GO',
iconClassPoll: "icon-status-poll-question-mark", label: 'Go',
statusClass: "s-status-ok", iconClass: 'icon-check',
statusBgColor: "#33cc33", iconClassPoll: 'icon-status-poll-question-mark',
statusFgColor: "#000" statusClass: 's-status-ok',
}, { statusBgColor: '#33cc33',
key: "MAYBE", statusFgColor: '#000'
label: "Maybe", },
iconClass: "icon-alert-triangle", {
iconClassPoll: "icon-status-poll-question-mark", key: 'MAYBE',
statusClass: "s-status-warning", label: 'Maybe',
statusBgColor: "#ffb66c", iconClass: 'icon-alert-triangle',
statusFgColor: "#000" iconClassPoll: 'icon-status-poll-question-mark',
}, { statusClass: 's-status-warning',
key: "NO_GO", statusBgColor: '#ffb66c',
label: "No go", statusFgColor: '#000'
iconClass: "icon-circle-slash", },
iconClassPoll: "icon-status-poll-question-mark", {
statusClass: "s-status-error", key: 'NO_GO',
statusBgColor: "#9900cc", label: 'No go',
statusFgColor: "#fff" iconClass: 'icon-circle-slash',
}]; iconClassPoll: 'icon-status-poll-question-mark',
statusClass: 's-status-error',
statusBgColor: '#9900cc',
statusFgColor: '#fff'
}
];
/** /**
* @implements {StatusUserProvider} * @implements {StatusUserProvider}
*/ */
export default class ExampleUserProvider extends EventEmitter { export default class ExampleUserProvider extends EventEmitter {
constructor(openmct, {defaultStatusRole} = {defaultStatusRole: undefined}) { constructor(openmct, { defaultStatusRole } = { defaultStatusRole: undefined }) {
super(); super();
this.openmct = openmct; this.openmct = openmct;
@ -155,7 +160,7 @@ export default class ExampleUserProvider extends EventEmitter {
question: pollQuestion, question: pollQuestion,
timestamp: Date.now() timestamp: Date.now()
}; };
this.emit("pollQuestionChange", this.pollQuestion); this.emit('pollQuestionChange', this.pollQuestion);
return true; return true;
} }
@ -177,17 +182,17 @@ export default class ExampleUserProvider extends EventEmitter {
} }
const formStructure = { const formStructure = {
title: "Login", title: 'Login',
sections: [ sections: [
{ {
rows: [ rows: [
{ {
key: "username", key: 'username',
control: "textfield", control: 'textfield',
name: "Username", name: 'Username',
pattern: "\\S+", pattern: '\\S+',
required: true, required: true,
cssClass: "l-input-lg", cssClass: 'l-input-lg',
value: '' value: ''
} }
] ]
@ -205,7 +210,8 @@ export default class ExampleUserProvider extends EventEmitter {
this.user = new this.ExampleUser(id, info.username, ['example-role']); this.user = new this.ExampleUser(id, info.username, ['example-role']);
this.loggedIn = true; this.loggedIn = true;
}, },
() => { // user canceled, setting a default username () => {
// user canceled, setting a default username
this.user = new this.ExampleUser(id, 'Pat', ['example-role']); this.user = new this.ExampleUser(id, 'Pat', ['example-role']);
this.loggedIn = true; this.loggedIn = true;
} }

View File

@ -22,10 +22,12 @@
import ExampleUserProvider from './ExampleUserProvider'; import ExampleUserProvider from './ExampleUserProvider';
export default function ExampleUserPlugin({autoLoginUser, defaultStatusRole} = { export default function ExampleUserPlugin(
{ autoLoginUser, defaultStatusRole } = {
autoLoginUser: 'guest', autoLoginUser: 'guest',
defaultStatusRole: 'test-role' defaultStatusRole: 'test-role'
}) { }
) {
return function install(openmct) { return function install(openmct) {
const userProvider = new ExampleUserProvider(openmct, { const userProvider = new ExampleUserProvider(openmct, {
defaultStatusRole defaultStatusRole

View File

@ -20,13 +20,10 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
import { import { createOpenMct, resetApplicationState } from '../../src/utils/testing';
createOpenMct,
resetApplicationState
} from '../../src/utils/testing';
import ExampleUserProvider from './ExampleUserProvider'; import ExampleUserProvider from './ExampleUserProvider';
describe("The Example User Plugin", () => { describe('The Example User Plugin', () => {
let openmct; let openmct;
beforeEach(() => { beforeEach(() => {

View File

@ -20,12 +20,9 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
import { import { createOpenMct, resetApplicationState } from '../../src/utils/testing';
createOpenMct,
resetApplicationState
} from '../../src/utils/testing';
describe("The Example Fault Source Plugin", () => { describe('The Example Fault Source Plugin', () => {
let openmct; let openmct;
beforeEach(() => { beforeEach(() => {

View File

@ -43,11 +43,14 @@ const getRandom = {
} }
}; };
function shelveFault(fault, opts = { function shelveFault(
fault,
opts = {
shelved: true, shelved: true,
comment: '', comment: '',
shelveDuration: 90000 shelveDuration: 90000
}) { }
) {
fault.shelved = true; fault.shelved = true;
setTimeout(() => { setTimeout(() => {

View File

@ -1,37 +1,32 @@
define([ define(['lodash'], function (_) {
'lodash'
], function (
_
) {
var METADATA_BY_TYPE = { var METADATA_BY_TYPE = {
'generator': { generator: {
values: [ values: [
{ {
key: "name", key: 'name',
name: "Name", name: 'Name',
format: "string" format: 'string'
}, },
{ {
key: "utc", key: 'utc',
name: "Time", name: 'Time',
format: "utc", format: 'utc',
hints: { hints: {
domain: 1 domain: 1
} }
}, },
{ {
key: "yesterday", key: 'yesterday',
name: "Yesterday", name: 'Yesterday',
format: "utc", format: 'utc',
hints: { hints: {
domain: 2 domain: 2
} }
}, },
{ {
key: "wavelengths", key: 'wavelengths',
name: "Wavelength", name: 'Wavelength',
unit: "nm", unit: 'nm',
format: 'string[]', format: 'string[]',
hints: { hints: {
range: 4 range: 4
@ -48,26 +43,26 @@ define([
// } // }
// }, // },
{ {
key: "sin", key: 'sin',
name: "Sine", name: 'Sine',
unit: "Hz", unit: 'Hz',
formatString: '%0.2f', formatString: '%0.2f',
hints: { hints: {
range: 1 range: 1
} }
}, },
{ {
key: "cos", key: 'cos',
name: "Cosine", name: 'Cosine',
unit: "deg", unit: 'deg',
formatString: '%0.2f', formatString: '%0.2f',
hints: { hints: {
range: 2 range: 2
} }
}, },
{ {
key: "intensities", key: 'intensities',
name: "Intensities", name: 'Intensities',
format: 'number[]', format: 'number[]',
hints: { hints: {
range: 3 range: 3
@ -78,40 +73,40 @@ define([
'example.state-generator': { 'example.state-generator': {
values: [ values: [
{ {
key: "name", key: 'name',
name: "Name", name: 'Name',
format: "string" format: 'string'
}, },
{ {
key: "utc", key: 'utc',
name: "Time", name: 'Time',
format: "utc", format: 'utc',
hints: { hints: {
domain: 1 domain: 1
} }
}, },
{ {
key: "local", key: 'local',
name: "Time", name: 'Time',
format: "utc", format: 'utc',
source: "utc", source: 'utc',
hints: { hints: {
domain: 2 domain: 2
} }
}, },
{ {
key: "state", key: 'state',
source: "value", source: 'value',
name: "State", name: 'State',
format: "enum", format: 'enum',
enumerations: [ enumerations: [
{ {
value: 0, value: 0,
string: "OFF" string: 'OFF'
}, },
{ {
value: 1, value: 1,
string: "ON" string: 'ON'
} }
], ],
hints: { hints: {
@ -119,8 +114,8 @@ define([
} }
}, },
{ {
key: "value", key: 'value',
name: "Value", name: 'Value',
hints: { hints: {
range: 2 range: 2
} }
@ -129,22 +124,15 @@ define([
} }
}; };
function GeneratorMetadataProvider() { function GeneratorMetadataProvider() {}
}
GeneratorMetadataProvider.prototype.supportsMetadata = function (domainObject) { GeneratorMetadataProvider.prototype.supportsMetadata = function (domainObject) {
return Object.prototype.hasOwnProperty.call(METADATA_BY_TYPE, domainObject.type); return Object.prototype.hasOwnProperty.call(METADATA_BY_TYPE, domainObject.type);
}; };
GeneratorMetadataProvider.prototype.getMetadata = function (domainObject) { GeneratorMetadataProvider.prototype.getMetadata = function (domainObject) {
return Object.assign( return Object.assign({}, domainObject.telemetry, METADATA_BY_TYPE[domainObject.type]);
{},
domainObject.telemetry,
METADATA_BY_TYPE[domainObject.type]
);
}; };
return GeneratorMetadataProvider; return GeneratorMetadataProvider;
}); });

View File

@ -20,12 +20,7 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
define([ define(['./WorkerInterface'], function (WorkerInterface) {
'./WorkerInterface'
], function (
WorkerInterface
) {
var REQUEST_DEFAULTS = { var REQUEST_DEFAULTS = {
amplitude: 1, amplitude: 1,
period: 10, period: 10,
@ -46,8 +41,7 @@ define([
return domainObject.type === 'generator'; return domainObject.type === 'generator';
}; };
GeneratorProvider.prototype.supportsRequest = GeneratorProvider.prototype.supportsRequest = GeneratorProvider.prototype.supportsSubscribe =
GeneratorProvider.prototype.supportsSubscribe =
GeneratorProvider.prototype.canProvideTelemetry; GeneratorProvider.prototype.canProvideTelemetry;
GeneratorProvider.prototype.makeWorkerRequest = function (domainObject, request) { GeneratorProvider.prototype.makeWorkerRequest = function (domainObject, request) {
@ -67,7 +61,10 @@ define([
var workerRequest = {}; var workerRequest = {};
props.forEach(function (prop) { props.forEach(function (prop) {
if (domainObject.telemetry && Object.prototype.hasOwnProperty.call(domainObject.telemetry, prop)) { if (
domainObject.telemetry &&
Object.prototype.hasOwnProperty.call(domainObject.telemetry, prop)
) {
workerRequest[prop] = domainObject.telemetry[prop]; workerRequest[prop] = domainObject.telemetry[prop];
} }

View File

@ -20,12 +20,7 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
define([ define([], function () {
], function (
) {
var PURPLE = { var PURPLE = {
sin: 2.2, sin: 2.2,
cos: 2.2 cos: 2.2
@ -48,34 +43,32 @@ define([
}, },
LIMITS = { LIMITS = {
rh: { rh: {
cssClass: "is-limit--upr is-limit--red", cssClass: 'is-limit--upr is-limit--red',
low: RED, low: RED,
high: Number.POSITIVE_INFINITY, high: Number.POSITIVE_INFINITY,
name: "Red High" name: 'Red High'
}, },
rl: { rl: {
cssClass: "is-limit--lwr is-limit--red", cssClass: 'is-limit--lwr is-limit--red',
high: -RED, high: -RED,
low: Number.NEGATIVE_INFINITY, low: Number.NEGATIVE_INFINITY,
name: "Red Low" name: 'Red Low'
}, },
yh: { yh: {
cssClass: "is-limit--upr is-limit--yellow", cssClass: 'is-limit--upr is-limit--yellow',
low: YELLOW, low: YELLOW,
high: RED, high: RED,
name: "Yellow High" name: 'Yellow High'
}, },
yl: { yl: {
cssClass: "is-limit--lwr is-limit--yellow", cssClass: 'is-limit--lwr is-limit--yellow',
low: -RED, low: -RED,
high: -YELLOW, high: -YELLOW,
name: "Yellow Low" name: 'Yellow Low'
} }
}; };
function SinewaveLimitProvider() { function SinewaveLimitProvider() {}
}
SinewaveLimitProvider.prototype.supportsLimits = function (domainObject) { SinewaveLimitProvider.prototype.supportsLimits = function (domainObject) {
return domainObject.type === 'generator'; return domainObject.type === 'generator';
@ -106,62 +99,61 @@ define([
}; };
SinewaveLimitProvider.prototype.getLimits = function (domainObject) { SinewaveLimitProvider.prototype.getLimits = function (domainObject) {
return { return {
limits: function () { limits: function () {
return Promise.resolve({ return Promise.resolve({
WATCH: { WATCH: {
low: { low: {
color: "cyan", color: 'cyan',
sin: -CYAN.sin, sin: -CYAN.sin,
cos: -CYAN.cos cos: -CYAN.cos
}, },
high: { high: {
color: "cyan", color: 'cyan',
...CYAN ...CYAN
} }
}, },
WARNING: { WARNING: {
low: { low: {
color: "yellow", color: 'yellow',
sin: -YELLOW.sin, sin: -YELLOW.sin,
cos: -YELLOW.cos cos: -YELLOW.cos
}, },
high: { high: {
color: "yellow", color: 'yellow',
...YELLOW ...YELLOW
} }
}, },
DISTRESS: { DISTRESS: {
low: { low: {
color: "orange", color: 'orange',
sin: -ORANGE.sin, sin: -ORANGE.sin,
cos: -ORANGE.cos cos: -ORANGE.cos
}, },
high: { high: {
color: "orange", color: 'orange',
...ORANGE ...ORANGE
} }
}, },
CRITICAL: { CRITICAL: {
low: { low: {
color: "red", color: 'red',
sin: -RED.sin, sin: -RED.sin,
cos: -RED.cos cos: -RED.cos
}, },
high: { high: {
color: "red", color: 'red',
...RED ...RED
} }
}, },
SEVERE: { SEVERE: {
low: { low: {
color: "purple", color: 'purple',
sin: -PURPLE.sin, sin: -PURPLE.sin,
cos: -PURPLE.cos cos: -PURPLE.cos
}, },
high: { high: {
color: "purple", color: 'purple',
...PURPLE ...PURPLE
} }
} }

Some files were not shown because too many files have changed in this diff Show More