* fix: resize conductor properly * refactor: more computed properties, unregister listener * fix: beforeUnmounted hook * test(visual): add time conductor visual test for fixed mode * fix: initialize to `null` * feat: extend the base `screenshot` function to mask elements which will always create variance in an Open MCT screenshot * docs: add types for fixtures * fix: remove unneeded await * chore: add sinon timers types package back * docs: remove unused docs * doc: remove unused docs * test: add visual realtime url, update imports * feat: provide wrapped page.screenshot fixture that applies defaults * test: add basic timeConductor snapshot tests * chore: update eslint config * lint: remove unused disable directives * test: remove redundant navigation * fix: remove listeners * fix: maybe stabilize unit tests * docs: remove * fix: provide sourcemaps in unit tests * test: add regression snapshot test for time conductor axis * lint: remove unused imports * feat(e2e): add fixture to manually tick the clock and use it * test: reactivate test now that we don't use deploysentinel :( * test: update snapshots * test: add test for clockOptions and tick fixtures * test: add afterEach stub and fixme * test: try and stabilize fault management flake * lint: defy the word gods * chore: ignore `*-darwin.png` screenshots * chore: remove darwin screenshot binaries * docs: markdownlint * docs: remove MacOS specific instructions from snapshot testing * fix: remove a11y
@ -1,10 +1,13 @@
|
|||||||
const LEGACY_FILES = ['example/**'];
|
const LEGACY_FILES = ['example/**'];
|
||||||
module.exports = {
|
/** @type {import('eslint').Linter.Config} */
|
||||||
|
const config = {
|
||||||
env: {
|
env: {
|
||||||
browser: true,
|
browser: true,
|
||||||
es6: true,
|
es2024: true,
|
||||||
jasmine: true,
|
jasmine: true,
|
||||||
amd: true
|
node: true,
|
||||||
|
worker: true,
|
||||||
|
serviceworker: true
|
||||||
},
|
},
|
||||||
globals: {
|
globals: {
|
||||||
_: 'readonly'
|
_: 'readonly'
|
||||||
@ -23,10 +26,11 @@ module.exports = {
|
|||||||
parser: '@babel/eslint-parser',
|
parser: '@babel/eslint-parser',
|
||||||
requireConfigFile: false,
|
requireConfigFile: false,
|
||||||
allowImportExportEverywhere: true,
|
allowImportExportEverywhere: true,
|
||||||
ecmaVersion: 2015,
|
ecmaVersion: 'latest',
|
||||||
ecmaFeatures: {
|
ecmaFeatures: {
|
||||||
impliedStrict: true
|
impliedStrict: true
|
||||||
}
|
},
|
||||||
|
sourceType: 'module'
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
'simple-import-sort/imports': 'warn',
|
'simple-import-sort/imports': 'warn',
|
||||||
@ -152,7 +156,7 @@ module.exports = {
|
|||||||
cases: {
|
cases: {
|
||||||
pascalCase: true
|
pascalCase: true
|
||||||
},
|
},
|
||||||
ignore: ['^.*\\.js$']
|
ignore: ['^.*\\.(js|cjs|mjs)$']
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
'vue/first-attribute-linebreak': 'error',
|
'vue/first-attribute-linebreak': 'error',
|
||||||
@ -179,3 +183,5 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module.exports = config;
|
||||||
|
3
.gitignore
vendored
@ -47,3 +47,6 @@ index.html.bak
|
|||||||
.nyc_output
|
.nyc_output
|
||||||
coverage
|
coverage
|
||||||
codecov
|
codecov
|
||||||
|
|
||||||
|
# Don't commit MacOS screenshots
|
||||||
|
*-darwin.png
|
||||||
|
@ -76,8 +76,9 @@ To read about how to write a good visual test, please see [How to write a great
|
|||||||
|
|
||||||
`npm run test:e2e:visual` commands will run all of the visual tests against a local instance of Open MCT. If no `PERCY_TOKEN` API key is found in the terminal or command line environment variables, no visual comparisons will be made.
|
`npm run test:e2e:visual` commands will run all of the visual tests against a local instance of Open MCT. If no `PERCY_TOKEN` API key is found in the terminal or command line environment variables, no visual comparisons will be made.
|
||||||
|
|
||||||
- `npm run test:e2e:visual:ci` will run against every commit and PR.
|
- `npm run test:e2e:visual:ci` will run against every commit and PR.
|
||||||
- `npm run test:e2e:visual:full` will run every night with additional comparisons made for Larger Displays and with the `snow` theme.
|
- `npm run test:e2e:visual:full` will run every night with additional comparisons made for Larger Displays and with the `snow` theme.
|
||||||
|
|
||||||
#### Percy.io
|
#### Percy.io
|
||||||
|
|
||||||
To make this possible, we're leveraging a 3rd party service, [Percy](https://percy.io/). This service maintains a copy of all changes, users, scm-metadata, and baselines to verify that the application looks and feels the same _unless approved by a Open MCT developer_. To request a Percy API token, please reach out to the Open MCT Dev team on GitHub. For more information, please see the official [Percy documentation](https://docs.percy.io/docs/visual-testing-basics).
|
To make this possible, we're leveraging a 3rd party service, [Percy](https://percy.io/). This service maintains a copy of all changes, users, scm-metadata, and baselines to verify that the application looks and feels the same _unless approved by a Open MCT developer_. To request a Percy API token, please reach out to the Open MCT Dev team on GitHub. For more information, please see the official [Percy documentation](https://docs.percy.io/docs/visual-testing-basics).
|
||||||
@ -89,15 +90,16 @@ At present, we are using percy with two configuration files: `./e2e/.percy.night
|
|||||||
While snapshot testing offers a precise way to detect changes in your application without relying on third-party services like Percy.io, we've found that it doesn't offer any advantages over visual testing in our use-cases. Therefore, snapshot testing is **not recommended** for further implementation.
|
While snapshot testing offers a precise way to detect changes in your application without relying on third-party services like Percy.io, we've found that it doesn't offer any advantages over visual testing in our use-cases. Therefore, snapshot testing is **not recommended** for further implementation.
|
||||||
|
|
||||||
#### CI vs Manual Checks
|
#### CI vs Manual Checks
|
||||||
|
|
||||||
Snapshot tests can be reliably executed in Continuous Integration (CI) environments but lack the manual oversight provided by visual testing platforms like Percy.io. This means they may miss issues that a human reviewer could catch during manual checks.
|
Snapshot tests can be reliably executed in Continuous Integration (CI) environments but lack the manual oversight provided by visual testing platforms like Percy.io. This means they may miss issues that a human reviewer could catch during manual checks.
|
||||||
|
|
||||||
#### Example
|
#### Example
|
||||||
|
|
||||||
A single visual test assertion in Percy.io can be executed across 10 different browser and resolution combinations without additional setup, providing comprehensive testing with minimal configuration. In contrast, a snapshot test is restricted to a single OS and browser resolution, requiring more effort to achieve the same level of coverage.
|
A single visual test assertion in Percy.io can be executed across 10 different browser and resolution combinations without additional setup, providing comprehensive testing with minimal configuration. In contrast, a snapshot test is restricted to a single OS and browser resolution, requiring more effort to achieve the same level of coverage.
|
||||||
|
|
||||||
|
|
||||||
#### Further Reading
|
#### Further Reading
|
||||||
For those interested in the mechanics of snapshot testing with Playwright, you can refer to the [Playwright Snapshots Documentation](https://playwright.dev/docs/test-snapshots). However, keep in mind that we do not recommend using this approach.
|
|
||||||
|
|
||||||
|
For those interested in the mechanics of snapshot testing with Playwright, you can refer to the [Playwright Snapshots Documentation](https://playwright.dev/docs/test-snapshots). However, keep in mind that we do not recommend using this approach.
|
||||||
|
|
||||||
#### Open MCT's implementation
|
#### Open MCT's implementation
|
||||||
|
|
||||||
@ -118,14 +120,6 @@ When the `@snapshot` tests fail, they will need to be evaluated to determine if
|
|||||||
|
|
||||||
To compare a snapshot, run a test and open the html report with the 'Expected' vs 'Actual' screenshot. If the actual screenshot is preferred, then the source-controlled 'Expected' snapshots will need to be updated with the following scripts.
|
To compare a snapshot, run a test and open the html report with the 'Expected' vs 'Actual' screenshot. If the actual screenshot is preferred, then the source-controlled 'Expected' snapshots will need to be updated with the following scripts.
|
||||||
|
|
||||||
MacOS
|
|
||||||
|
|
||||||
```
|
|
||||||
npm run test:e2e:updatesnapshots
|
|
||||||
```
|
|
||||||
|
|
||||||
Linux/CI
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
// Replace {X.X.X} with the current Playwright version
|
// Replace {X.X.X} with the current Playwright version
|
||||||
// from our package.json or circleCI configuration file
|
// from our package.json or circleCI configuration file
|
||||||
@ -335,9 +329,11 @@ We have a Mission-need to support iPad and mobile devices. To run our test suite
|
|||||||
In general, our test suite is not designed to run against mobile devices as the mobile experience is a focused version of the application. Core functionality is missing (chiefly the 'Create' button). To bypass the object creation, we leverage the `storageState` properties for starting the mobile tests with localstorage.
|
In general, our test suite is not designed to run against mobile devices as the mobile experience is a focused version of the application. Core functionality is missing (chiefly the 'Create' button). To bypass the object creation, we leverage the `storageState` properties for starting the mobile tests with localstorage.
|
||||||
|
|
||||||
For now, the mobile tests will exist in the /tests/mobile/ suites and be executed with the
|
For now, the mobile tests will exist in the /tests/mobile/ suites and be executed with the
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm run test:e2e:mobile
|
npm run test:e2e:mobile
|
||||||
```
|
```
|
||||||
|
|
||||||
command.
|
command.
|
||||||
|
|
||||||
#### **Skipping or executing tests based on browser, os, and/os browser version:**
|
#### **Skipping or executing tests based on browser, os, and/os browser version:**
|
||||||
@ -377,6 +373,7 @@ In general, strive to test only through the UI as a user would. As stated in the
|
|||||||
By adhering to this principle, we can create tests that are both robust and reflective of actual user experiences.
|
By adhering to this principle, we can create tests that are both robust and reflective of actual user experiences.
|
||||||
|
|
||||||
#### How to make tests robust to function in other contexts (VISTA, COUCHDB, YAMCS, VIPER, etc.)
|
#### How to make tests robust to function in other contexts (VISTA, COUCHDB, YAMCS, VIPER, etc.)
|
||||||
|
|
||||||
1. Leverage the use of `appActions.js` methods such as `createDomainObjectWithDefaults()`. This ensures that your tests will create unique instances of objects for your test to interact with.
|
1. Leverage the use of `appActions.js` methods such as `createDomainObjectWithDefaults()`. This ensures that your tests will create unique instances of objects for your test to interact with.
|
||||||
1. Do not assert on the order or structure of objects available unless you created them yourself. These tests may be used against a persistent datastore like couchdb with many objects in the tree.
|
1. Do not assert on the order or structure of objects available unless you created them yourself. These tests may be used against a persistent datastore like couchdb with many objects in the tree.
|
||||||
1. Do not search for your created objects. Open MCT does not performance uniqueness checks so it's possible that your tests will break when run twice.
|
1. Do not search for your created objects. Open MCT does not performance uniqueness checks so it's possible that your tests will break when run twice.
|
||||||
@ -384,6 +381,7 @@ By adhering to this principle, we can create tests that are both robust and refl
|
|||||||
1. Leverage `await page.goto('./', { waitUntil: 'domcontentloaded' });` instead of `{ waitUntil: 'networkidle' }`. Tests run against deployments with websockets often have issues with the networkidle detection.
|
1. Leverage `await page.goto('./', { waitUntil: 'domcontentloaded' });` instead of `{ waitUntil: 'networkidle' }`. Tests run against deployments with websockets often have issues with the networkidle detection.
|
||||||
|
|
||||||
#### How to make tests faster and more resilient
|
#### How to make tests faster and more resilient
|
||||||
|
|
||||||
1. Avoid app interaction when possible. The best way of doing this is to navigate directly by URL:
|
1. Avoid app interaction when possible. The best way of doing this is to navigate directly by URL:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
@ -396,10 +394,11 @@ By adhering to this principle, we can create tests that are both robust and refl
|
|||||||
|
|
||||||
1. Leverage `await page.goto('./', { waitUntil: 'domcontentloaded' });`
|
1. Leverage `await page.goto('./', { waitUntil: 'domcontentloaded' });`
|
||||||
- Initial navigation should _almost_ always use the `{ waitUntil: 'domcontentloaded' }` option.
|
- Initial navigation should _almost_ always use the `{ waitUntil: 'domcontentloaded' }` option.
|
||||||
1. Avoid repeated setup to test a single assertion. Write longer tests with multiple soft assertions.
|
1. Avoid repeated setup to test a single assertion. Write longer tests with multiple soft assertions.
|
||||||
This ensures that your changes will be picked up with large refactors.
|
This ensures that your changes will be picked up with large refactors.
|
||||||
|
|
||||||
##### Utilizing LocalStorage
|
##### Utilizing LocalStorage
|
||||||
|
|
||||||
1. In order to save test runtime in the case of tests that require a decent amount of initial setup (such as in the case of testing complex displays), you may use [Playwright's `storageState` feature](https://playwright.dev/docs/api/class-browsercontext#browser-context-storage-state) to generate and load localStorage states.
|
1. In order to save test runtime in the case of tests that require a decent amount of initial setup (such as in the case of testing complex displays), you may use [Playwright's `storageState` feature](https://playwright.dev/docs/api/class-browsercontext#browser-context-storage-state) to generate and load localStorage states.
|
||||||
1. To generate a localStorage state to be used in a test:
|
1. To generate a localStorage state to be used in a test:
|
||||||
- Add an e2e test to our generateLocalStorageData suite which sets the initial state (creating/configuring objects, etc.), saving it in the `test-data` folder:
|
- Add an e2e test to our generateLocalStorageData suite which sets the initial state (creating/configuring objects, etc.), saving it in the `test-data` folder:
|
||||||
@ -420,7 +419,6 @@ By adhering to this principle, we can create tests that are both robust and refl
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### How to write a great test
|
### How to write a great test
|
||||||
|
|
||||||
- Avoid using css locators to find elements to the page. Use modern web accessible locators like `getByRole`
|
- Avoid using css locators to find elements to the page. Use modern web accessible locators like `getByRole`
|
||||||
@ -436,7 +434,7 @@ By adhering to this principle, we can create tests that are both robust and refl
|
|||||||
await notesInput.fill(testNotes);
|
await notesInput.fill(testNotes);
|
||||||
```
|
```
|
||||||
|
|
||||||
#### How to Write a Great Visual Test
|
#### How to Write a Great Visual Test
|
||||||
|
|
||||||
1. **Look for the Unknown Unknowns**: Avoid asserting on specific differences in the visual diff. Visual tests are most effective for identifying unknown unknowns.
|
1. **Look for the Unknown Unknowns**: Avoid asserting on specific differences in the visual diff. Visual tests are most effective for identifying unknown unknowns.
|
||||||
|
|
||||||
@ -445,23 +443,27 @@ By adhering to this principle, we can create tests that are both robust and refl
|
|||||||
3. **Expect the Unexpected**: Use functional expect statements only to verify assumptions about the state between steps. A great visual test doesn't fail during the test itself, but rather when changes are reviewed in Percy.io.
|
3. **Expect the Unexpected**: Use functional expect statements only to verify assumptions about the state between steps. A great visual test doesn't fail during the test itself, but rather when changes are reviewed in Percy.io.
|
||||||
|
|
||||||
4. **Control Variability**: Account for variations inherent in working with time-based telemetry and clocks.
|
4. **Control Variability**: Account for variations inherent in working with time-based telemetry and clocks.
|
||||||
- Utilize `percyCSS` to ignore time-based elements. For more details, consult our [percyCSS file](./.percy.ci.yml).
|
|
||||||
- Use Open MCT's fixed-time mode unless explicitly testing realtime clock
|
- Utilize `percyCSS` to ignore time-based elements. For more details, consult our [percyCSS file](./.percy.ci.yml).
|
||||||
- Employ the `createExampleTelemetryObject` appAction to source telemetry and specify a `name` to avoid autogenerated names.
|
- Use Open MCT's fixed-time mode unless explicitly testing realtime clock
|
||||||
- Avoid creating objects with a time component like timers and clocks.
|
- Employ the `createExampleTelemetryObject` appAction to source telemetry and specify a `name` to avoid autogenerated names.
|
||||||
|
- Avoid creating objects with a time component like timers and clocks.
|
||||||
|
|
||||||
5. **Hide the Tree and Inspector**: Generally, your test will not require comparisons involving the tree and inspector. These aspects are covered in component-specific tests (explained below). To exclude them from the comparison by default, navigate to the root of the main view with the tree and inspector hidden:
|
5. **Hide the Tree and Inspector**: Generally, your test will not require comparisons involving the tree and inspector. These aspects are covered in component-specific tests (explained below). To exclude them from the comparison by default, navigate to the root of the main view with the tree and inspector hidden:
|
||||||
- `await page.goto('./#/browse/mine?hideTree=true&hideInspector=true')`
|
- `await page.goto('./#/browse/mine?hideTree=true&hideInspector=true')`
|
||||||
|
|
||||||
6. **Component-Specific Tests**: If you wish to focus on a particular component, use the `/visual-a11y/component/` folder and limit the scope of the comparison to that component. For instance:
|
6. **Component-Specific Tests**: If you wish to focus on a particular component, use the `/visual-a11y/component/` folder and limit the scope of the comparison to that component. For instance:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
await percySnapshot(page, `Tree Pane w/ single level expanded (theme: ${theme})`, {
|
await percySnapshot(page, `Tree Pane w/ single level expanded (theme: ${theme})`, {
|
||||||
scope: treePane
|
scope: treePane
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
- Note: The `scope` variable can be any valid CSS selector.
|
- Note: The `scope` variable can be any valid CSS selector.
|
||||||
|
|
||||||
7. **Write many `percySnapshot` commands in a single test**: In line with our approach to longer functional tests, we recommend that many test percySnapshots are taken in a single test. For instance:
|
7. **Write many `percySnapshot` commands in a single test**: In line with our approach to longer functional tests, we recommend that many test percySnapshots are taken in a single test. For instance:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
//<Some interesting state>
|
//<Some interesting state>
|
||||||
await percySnapshot(page, `Before object expanded (theme: ${theme})`);
|
await percySnapshot(page, `Before object expanded (theme: ${theme})`);
|
||||||
@ -511,6 +513,7 @@ test.describe('foo test suite', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
More info and options for `overrideClock` can be found in [baseFixtures.js](baseFixtures.js)
|
More info and options for `overrideClock` can be found in [baseFixtures.js](baseFixtures.js)
|
||||||
|
|
||||||
- Working with multiple pages
|
- Working with multiple pages
|
||||||
@ -539,7 +542,6 @@ const key = getFirstKeyFromOpenMctJson(jsonData);
|
|||||||
expect(jsonData.openmct[key]).toHaveProperty('name', 'e2e folder');
|
expect(jsonData.openmct[key]).toHaveProperty('name', 'e2e folder');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Reporting
|
### Reporting
|
||||||
|
|
||||||
Test Reporting is done through official Playwright reporters and the CI Systems which execute them.
|
Test Reporting is done through official Playwright reporters and the CI Systems which execute them.
|
||||||
@ -615,6 +617,7 @@ A single e2e test in Open MCT is extended to run:
|
|||||||
### Writing Tests
|
### Writing Tests
|
||||||
|
|
||||||
Playwright provides 3 supported methods of debugging and authoring tests:
|
Playwright provides 3 supported methods of debugging and authoring tests:
|
||||||
|
|
||||||
- A 'watch mode' for running tests locally and debugging on the fly
|
- A 'watch mode' for running tests locally and debugging on the fly
|
||||||
- A 'debug mode' for debugging tests and writing assertions against tests
|
- A 'debug mode' for debugging tests and writing assertions against tests
|
||||||
- A 'VSCode plugin' for debugging tests within the VSCode IDE.
|
- A 'VSCode plugin' for debugging tests within the VSCode IDE.
|
||||||
|
@ -36,27 +36,67 @@
|
|||||||
import AxeBuilder from '@axe-core/playwright';
|
import AxeBuilder from '@axe-core/playwright';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
import { expect, test } from './pluginFixtures.js';
|
import { expect, test } from './pluginFixtures.js';
|
||||||
|
|
||||||
// Constants for repeated values
|
// Constants for repeated values
|
||||||
const TEST_RESULTS_DIR = './test-results';
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||||
|
const TEST_RESULTS_DIR = path.join(__dirname, './test-results');
|
||||||
|
|
||||||
|
const extendedTest = test.extend({
|
||||||
|
/**
|
||||||
|
* Overrides the default screenshot function to apply default options that should apply to all
|
||||||
|
* screenshots taken in the AVP tests.
|
||||||
|
*
|
||||||
|
* @param {import('@playwright/test').PlaywrightTestArgs} args - The Playwright test arguments.
|
||||||
|
* @param {Function} use - The function to use the page object.
|
||||||
|
* Defaults:
|
||||||
|
* - Disables animations
|
||||||
|
* - Masks the clock indicator
|
||||||
|
* - Masks the time conductor last update time in realtime mode
|
||||||
|
* - Masks the time conductor start bounds in fixed mode
|
||||||
|
* - Masks the time conductor end bounds in fixed mode
|
||||||
|
*/
|
||||||
|
page: async ({ page }, use) => {
|
||||||
|
const playwrightScreenshot = page.screenshot;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override the screenshot function to always mask a given set of locators which will always
|
||||||
|
* show variance across screenshots. Defaults may be overridden by passing in options to the
|
||||||
|
* screenshot function.
|
||||||
|
* @param {import('@playwright/test').PageScreenshotOptions} options - The options for the screenshot.
|
||||||
|
* @returns {Promise<Buffer>} Returns the screenshot as a buffer.
|
||||||
|
*/
|
||||||
|
page.screenshot = async function (options = {}) {
|
||||||
|
const mask = [
|
||||||
|
this.getByLabel('Clock Indicator'), // Mask the clock indicator
|
||||||
|
this.getByLabel('Last update'), // Mask the time conductor last update time in realtime mode
|
||||||
|
this.getByLabel('Start bounds'), // Mask the time conductor start bounds in fixed mode
|
||||||
|
this.getByLabel('End bounds') // Mask the time conductor end bounds in fixed mode
|
||||||
|
];
|
||||||
|
|
||||||
|
const result = await playwrightScreenshot.call(this, {
|
||||||
|
animations: 'disabled',
|
||||||
|
mask,
|
||||||
|
...options // Pass through or override any options
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
await use(page);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scans for accessibility violations on a page and writes a report to disk if violations are found.
|
* Scans for accessibility violations on a page and writes a report to disk if violations are found.
|
||||||
* Automatically asserts that no violations should be present.
|
* Automatically asserts that no violations should be present.
|
||||||
*
|
*
|
||||||
* @typedef {Object} GenerateReportOptions
|
|
||||||
* @property {string} [reportName] - The name for the report file.
|
|
||||||
*
|
|
||||||
* @param {import('playwright').Page} page - The page object from Playwright.
|
* @param {import('playwright').Page} page - The page object from Playwright.
|
||||||
* @param {string} testCaseName - The name of the test case.
|
* @param {string} testCaseName - The name of the test case.
|
||||||
* @param {GenerateReportOptions} [options={}] - The options for the report generation.
|
* @param {{ reportName?: string }} [options={}] - The options for the report generation.
|
||||||
*
|
* @returns {Promise<Object|null>} Returns the accessibility scan results if violations are found, otherwise returns null.
|
||||||
* @returns {Promise<object|null>} Returns the accessibility scan results if violations are found,
|
|
||||||
* otherwise returns null.
|
|
||||||
*/
|
*/
|
||||||
/* eslint-disable no-undef */
|
|
||||||
export async function scanForA11yViolations(page, testCaseName, options = {}) {
|
export async function scanForA11yViolations(page, testCaseName, options = {}) {
|
||||||
const builder = new AxeBuilder({ page });
|
const builder = new AxeBuilder({ page });
|
||||||
builder.withTags(['wcag2aa']);
|
builder.withTags(['wcag2aa']);
|
||||||
@ -93,4 +133,4 @@ export async function scanForA11yViolations(page, testCaseName, options = {}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { expect, test };
|
export { expect, extendedTest as test };
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable no-undef */
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Open MCT, Copyright (c) 2014-2024, United States Government
|
* Open MCT, Copyright (c) 2014-2024, United States Government
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
@ -111,6 +110,40 @@ const extendedTest = test.extend({
|
|||||||
scope: 'test'
|
scope: 'test'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
/**
|
||||||
|
* Exposes a function to manually tick the clock. This is useful when overriding the clock to not
|
||||||
|
* tick (`shouldAdvanceTime: false`) for visual tests, as events such as re-renders and router params
|
||||||
|
* updates are clock-driven and must be manually ticked.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* ```js
|
||||||
|
* test.describe('Manual Clock Tick', () => {
|
||||||
|
* test.use({
|
||||||
|
* clockOptions: {
|
||||||
|
* now: MISSION_TIME, // Set to the desired time
|
||||||
|
* shouldAdvanceTime: false // Clock overridden to no longer tick
|
||||||
|
* }
|
||||||
|
* });
|
||||||
|
* test('Visual - Manual Clock Tick', async ({ page, tick }) => {
|
||||||
|
* // Tick the clock 2 seconds in the future
|
||||||
|
* await tick(2000);
|
||||||
|
* });
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param {Object} param0
|
||||||
|
* @param {import('@playwright/test').Page} param0.page
|
||||||
|
* @param {import('@playwright/test').Use} param0.use
|
||||||
|
*/
|
||||||
|
tick: async ({ page }, use) => {
|
||||||
|
// eslint-disable-next-line func-style
|
||||||
|
const tick = async (milliseconds) => {
|
||||||
|
await page.evaluate((_milliseconds) => {
|
||||||
|
window.__clock.tick(_milliseconds);
|
||||||
|
}, milliseconds);
|
||||||
|
};
|
||||||
|
await use(tick);
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* 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}
|
||||||
@ -154,17 +187,13 @@ const extendedTest = test.extend({
|
|||||||
// function in the generatorWorker context. This is necessary
|
// function in the generatorWorker context. This is necessary
|
||||||
// to ensure that example telemetry data is generated for the new clock time.
|
// to ensure that example telemetry data is generated for the new clock time.
|
||||||
if (clockOptions?.now !== undefined) {
|
if (clockOptions?.now !== undefined) {
|
||||||
page.on(
|
page.on('worker', (worker) => {
|
||||||
'worker',
|
if (worker.url().includes('generatorWorker')) {
|
||||||
(worker) => {
|
worker.evaluate((time) => {
|
||||||
if (worker.url().includes('generatorWorker')) {
|
self.Date.now = () => time;
|
||||||
worker.evaluate((time) => {
|
}, clockOptions.now);
|
||||||
self.Date.now = () => time;
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
},
|
|
||||||
clockOptions.now
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Capture any console errors during test execution
|
// Capture any console errors during test execution
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable prettier/prettier */
|
|
||||||
/**
|
/**
|
||||||
* Constants which may be used across all e2e tests.
|
* Constants which may be used across all e2e tests.
|
||||||
*/
|
*/
|
||||||
@ -8,12 +7,30 @@
|
|||||||
* - Used for overriding the browser clock in tests.
|
* - Used for overriding the browser clock in tests.
|
||||||
*/
|
*/
|
||||||
export const MISSION_TIME = 1732413600000; // Saturday, November 23, 2024 6:00:00 PM GMT-08:00 (Thanksgiving Dinner Time)
|
export const MISSION_TIME = 1732413600000; // Saturday, November 23, 2024 6:00:00 PM GMT-08:00 (Thanksgiving Dinner Time)
|
||||||
|
// Subtracting 30 minutes from MISSION_TIME
|
||||||
|
export const MISSION_TIME_FIXED_START = 1732413600000 - 1800000; // 1732411800000
|
||||||
|
|
||||||
|
// Adding 1 minute to MISSION_TIME
|
||||||
|
export const MISSION_TIME_FIXED_END = 1732413600000 + 60000; // 1732413660000
|
||||||
/**
|
/**
|
||||||
* URL Constants
|
* URL Constants
|
||||||
* - This is the URL that the browser will be directed to when running visual tests. This URL
|
* These constants are used for initial navigation in visual tests, in either fixed or realtime mode.
|
||||||
* - hides the tree and inspector to prevent visual noise
|
* They navigate to the 'My Items' folder at MISSION_TIME.
|
||||||
* - sets the time bounds to a fixed range
|
* They set the following url parameters:
|
||||||
|
* - tc.mode - The time conductor mode ('fixed' or 'local')
|
||||||
|
* - tc.startBound - The time conductor start bound (when in fixed mode)
|
||||||
|
* - tc.endBound - The time conductor end bound (when in fixed mode)
|
||||||
|
* - tc.startDelta - The time conductor start delta (when in realtime mode)
|
||||||
|
* - tc.endDelta - The time conductor end delta (when in realtime mode)
|
||||||
|
* - tc.timeSystem - The time conductor time system ('utc')
|
||||||
|
* - view - The view to display ('grid')
|
||||||
|
* - hideInspector - Whether to hide the inspector (true)
|
||||||
|
* - hideTree - Whether to hide the tree (true)
|
||||||
|
* @typedef {string} VisualUrl
|
||||||
*/
|
*/
|
||||||
export const VISUAL_URL =
|
|
||||||
'./#/browse/mine?tc.mode=fixed&tc.startBound=1693592063607&tc.endBound=1693593893607&tc.timeSystem=utc&view=grid&hideInspector=true&hideTree=true';
|
/** @type {VisualUrl} */
|
||||||
|
export const VISUAL_FIXED_URL = `./#/browse/mine?tc.mode=fixed&tc.startBound=${MISSION_TIME_FIXED_START}&tc.endBound=${MISSION_TIME_FIXED_END}&tc.timeSystem=utc&view=grid&hideInspector=true&hideTree=true`;
|
||||||
|
/** @type {VisualUrl} */
|
||||||
|
export const VISUAL_REALTIME_URL =
|
||||||
|
'./#/browse/mine?tc.mode=local&tc.timeSystem=utc&view=grid&tc.startDelta=1800000&tc.endDelta=30000&hideTree=true&hideInspector=true';
|
||||||
|
@ -68,7 +68,6 @@ async function commitEntry(page) {
|
|||||||
* @param {import('@playwright/test').Page} page
|
* @param {import('@playwright/test').Page} page
|
||||||
*/
|
*/
|
||||||
async function startAndAddRestrictedNotebookObject(page) {
|
async function startAndAddRestrictedNotebookObject(page) {
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
await page.addInitScript({
|
await page.addInitScript({
|
||||||
path: fileURLToPath(new URL('./addInitRestrictedNotebook.js', import.meta.url))
|
path: fileURLToPath(new URL('./addInitRestrictedNotebook.js', import.meta.url))
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable no-undef */
|
|
||||||
// playwright.config.js
|
// playwright.config.js
|
||||||
// @ts-check
|
// @ts-check
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable no-undef */
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Open MCT, Copyright (c) 2014-2024, United States Government
|
* Open MCT, Copyright (c) 2014-2024, United States Government
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
@ -123,7 +122,6 @@ const extendedTest = test.extend({
|
|||||||
theme: [theme, { option: true }],
|
theme: [theme, { option: true }],
|
||||||
// eslint-disable-next-line no-shadow
|
// eslint-disable-next-line no-shadow
|
||||||
page: async ({ page, theme }, use, testInfo) => {
|
page: async ({ page, theme }, use, testInfo) => {
|
||||||
// eslint-disable-next-line playwright/no-conditional-in-test
|
|
||||||
if (theme === 'snow') {
|
if (theme === 'snow') {
|
||||||
//inject snow theme
|
//inject snow theme
|
||||||
await page.addInitScript({
|
await page.addInitScript({
|
||||||
|
@ -26,11 +26,12 @@ relates to how we've extended it (i.e. ./e2e/baseFixtures.js) and assumptions ma
|
|||||||
(`npm start` and ./e2e/webpack-dev-middleware.js)
|
(`npm start` and ./e2e/webpack-dev-middleware.js)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { test } from '../../baseFixtures.js';
|
import { expect, test } from '../../baseFixtures.js';
|
||||||
|
import { MISSION_TIME } from '../../constants.js';
|
||||||
|
|
||||||
test.describe('baseFixtures tests', () => {
|
test.describe('baseFixtures tests', () => {
|
||||||
//Skip this test for now https://github.com/nasa/openmct/issues/6785
|
//Skip this test for now https://github.com/nasa/openmct/issues/6785
|
||||||
test.fixme('Verify that tests fail if console.error is thrown', async ({ page }) => {
|
test('Verify that tests fail if console.error is thrown', async ({ page }) => {
|
||||||
test.fail();
|
test.fail();
|
||||||
//Go to baseURL
|
//Go to baseURL
|
||||||
await page.goto('./', { waitUntil: 'domcontentloaded' });
|
await page.goto('./', { waitUntil: 'domcontentloaded' });
|
||||||
@ -52,3 +53,27 @@ test.describe('baseFixtures tests', () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test.describe('baseFixtures tests @clock', () => {
|
||||||
|
test.use({
|
||||||
|
clockOptions: {
|
||||||
|
now: MISSION_TIME,
|
||||||
|
shouldAdvanceTime: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test.beforeEach(async ({ page }) => {
|
||||||
|
await page.goto('./', { waitUntil: 'domcontentloaded' });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Can use clockOptions and tick fixtures to control the clock', async ({ page, tick }) => {
|
||||||
|
let time = await page.evaluate(() => new Date().getTime());
|
||||||
|
expect(time).toBe(MISSION_TIME);
|
||||||
|
await tick(1000);
|
||||||
|
time = await page.evaluate(() => new Date().getTime());
|
||||||
|
expect(time).toBe(MISSION_TIME + 1000 * 1);
|
||||||
|
await tick(1000);
|
||||||
|
time = await page.evaluate(() => new Date().getTime());
|
||||||
|
expect(time).toBe(MISSION_TIME + 1000 * 2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
This test suite is dedicated to tests which verify the basic operations surrounding imagery,
|
This test suite is dedicated to tests which verify the basic operations surrounding imagery,
|
||||||
but only assume that example imagery is present.
|
but only assume that example imagery is present.
|
||||||
*/
|
*/
|
||||||
/* globals process */
|
|
||||||
import { createDomainObjectWithDefaults, setRealTimeMode } from '../../../../appActions.js';
|
import { createDomainObjectWithDefaults, setRealTimeMode } from '../../../../appActions.js';
|
||||||
import { waitForAnimations } from '../../../../baseFixtures.js';
|
import { waitForAnimations } from '../../../../baseFixtures.js';
|
||||||
import { expect, test } from '../../../../pluginFixtures.js';
|
import { expect, test } from '../../../../pluginFixtures.js';
|
||||||
|
@ -27,7 +27,6 @@ import { expect, test } from '../../../../pluginFixtures.js';
|
|||||||
|
|
||||||
test.describe('Testing numeric data with inspector data visualization (i.e., data pivoting)', () => {
|
test.describe('Testing numeric data with inspector data visualization (i.e., data pivoting)', () => {
|
||||||
test.beforeEach(async ({ page }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
await page.addInitScript({
|
await page.addInitScript({
|
||||||
path: fileURLToPath(
|
path: fileURLToPath(
|
||||||
new URL('../../../../helper/addInitDataVisualization.js', import.meta.url)
|
new URL('../../../../helper/addInitDataVisualization.js', import.meta.url)
|
||||||
|
@ -277,7 +277,6 @@ test.describe('Notebook entry tests', () => {
|
|||||||
// Create Notebook with URL Whitelist
|
// Create Notebook with URL Whitelist
|
||||||
let notebookObject;
|
let notebookObject;
|
||||||
test.beforeEach(async ({ page }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
await page.addInitScript({
|
await page.addInitScript({
|
||||||
path: fileURLToPath(new URL('../../../../helper/addInitNotebookWithUrls.js', import.meta.url))
|
path: fileURLToPath(new URL('../../../../helper/addInitNotebookWithUrls.js', import.meta.url))
|
||||||
});
|
});
|
||||||
|
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 19 KiB |
@ -48,7 +48,7 @@ test.describe('Time conductor operations', () => {
|
|||||||
await setTimeConductorBounds(page, startDate);
|
await setTimeConductorBounds(page, startDate);
|
||||||
|
|
||||||
// Bring up the time conductor popup
|
// Bring up the time conductor popup
|
||||||
const timeConductorMode = await page.locator('.c-compact-tc');
|
const timeConductorMode = page.locator('.c-compact-tc');
|
||||||
await timeConductorMode.click();
|
await timeConductorMode.click();
|
||||||
const startDateLocator = page.locator('input[type="text"]').first();
|
const startDateLocator = page.locator('input[type="text"]').first();
|
||||||
const endDateLocator = page.locator('input[type="text"]').nth(2);
|
const endDateLocator = page.locator('input[type="text"]').nth(2);
|
||||||
|
@ -299,7 +299,6 @@ test.describe('Navigation memory leak is not detected in', () => {
|
|||||||
// for detecting memory leaks.
|
// for detecting memory leaks.
|
||||||
await page.evaluate(() => {
|
await page.evaluate(() => {
|
||||||
window.gcPromise = new Promise((resolve) => {
|
window.gcPromise = new Promise((resolve) => {
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
window.fr = new FinalizationRegistry(resolve);
|
window.fr = new FinalizationRegistry(resolve);
|
||||||
window.fr.register(
|
window.fr.register(
|
||||||
window.openmct.layout.$refs.browseObject.$refs.objectViewWrapper.firstChild,
|
window.openmct.layout.$refs.browseObject.$refs.objectViewWrapper.firstChild,
|
||||||
|
@ -21,14 +21,13 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
import { test } from '../../avpFixtures.js';
|
import { test } from '../../avpFixtures.js';
|
||||||
import { VISUAL_URL } from '../../constants.js';
|
import { VISUAL_FIXED_URL } from '../../constants.js';
|
||||||
|
|
||||||
test.describe('a11y - Default', () => {
|
test.describe('a11y - Default', () => {
|
||||||
test.beforeEach(async ({ page }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
await page.goto(VISUAL_URL, { waitUntil: 'domcontentloaded' });
|
await page.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
|
||||||
});
|
});
|
||||||
test('main view', async ({ page }, testInfo) => {
|
test('main view', async ({ page }, testInfo) => {
|
||||||
await page.goto('./');
|
|
||||||
//Skipping for https://github.com/nasa/openmct/issues/7421
|
//Skipping for https://github.com/nasa/openmct/issues/7421
|
||||||
//await scanForA11yViolations(page, testInfo.title);
|
//await scanForA11yViolations(page, testInfo.title);
|
||||||
});
|
});
|
||||||
|
@ -27,12 +27,12 @@ Tests the branding associated with the default deployment. At least the about mo
|
|||||||
import percySnapshot from '@percy/playwright';
|
import percySnapshot from '@percy/playwright';
|
||||||
|
|
||||||
import { expect, scanForA11yViolations, test } from '../../../avpFixtures.js';
|
import { expect, scanForA11yViolations, test } from '../../../avpFixtures.js';
|
||||||
import { VISUAL_URL } from '../../../constants.js';
|
import { VISUAL_FIXED_URL } from '../../../constants.js';
|
||||||
|
|
||||||
test.describe('Visual - Branding @a11y', () => {
|
test.describe('Visual - Branding @a11y', () => {
|
||||||
test.beforeEach(async ({ page }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
//Go to baseURL and Hide Tree
|
//Go to baseURL and Hide Tree
|
||||||
await page.goto(VISUAL_URL, { waitUntil: 'domcontentloaded' });
|
await page.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Visual - About Modal', async ({ page, theme }) => {
|
test('Visual - About Modal', async ({ page, theme }) => {
|
||||||
|
@ -28,7 +28,7 @@ import percySnapshot from '@percy/playwright';
|
|||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
import { expect, test } from '../../../avpFixtures.js';
|
import { expect, test } from '../../../avpFixtures.js';
|
||||||
import { VISUAL_URL } from '../../../constants.js';
|
import { VISUAL_FIXED_URL } from '../../../constants.js';
|
||||||
|
|
||||||
//Declare the component scope of the visual test for Percy
|
//Declare the component scope of the visual test for Percy
|
||||||
const header = '.l-shell__head';
|
const header = '.l-shell__head';
|
||||||
@ -36,7 +36,7 @@ const header = '.l-shell__head';
|
|||||||
test.describe('Visual - Header @a11y', () => {
|
test.describe('Visual - Header @a11y', () => {
|
||||||
test.beforeEach(async ({ page }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
//Go to baseURL and Hide Tree
|
//Go to baseURL and Hide Tree
|
||||||
await page.goto(VISUAL_URL, { waitUntil: 'domcontentloaded' });
|
await page.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
|
||||||
// Wait for status bar to load
|
// Wait for status bar to load
|
||||||
await expect(
|
await expect(
|
||||||
page.getByRole('status', {
|
page.getByRole('status', {
|
||||||
|
@ -23,14 +23,14 @@
|
|||||||
import percySnapshot from '@percy/playwright';
|
import percySnapshot from '@percy/playwright';
|
||||||
|
|
||||||
import { test } from '../../../avpFixtures.js';
|
import { test } from '../../../avpFixtures.js';
|
||||||
import { MISSION_TIME, VISUAL_URL } from '../../../constants.js';
|
import { MISSION_TIME, VISUAL_FIXED_URL } from '../../../constants.js';
|
||||||
|
|
||||||
//Declare the scope of the visual test
|
//Declare the scope of the visual test
|
||||||
const inspectorPane = '.l-shell__pane-inspector';
|
const inspectorPane = '.l-shell__pane-inspector';
|
||||||
|
|
||||||
test.describe('Visual - Inspector @ally @clock', () => {
|
test.describe('Visual - Inspector @ally @clock', () => {
|
||||||
test.beforeEach(async ({ page }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
await page.goto(VISUAL_URL, { waitUntil: 'domcontentloaded' });
|
await page.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
|
||||||
});
|
});
|
||||||
test.use({
|
test.use({
|
||||||
storageState: './e2e/test-data/overlay_plot_with_delay_storage.json',
|
storageState: './e2e/test-data/overlay_plot_with_delay_storage.json',
|
||||||
|
116
e2e/tests/visual-a11y/components/timeConductor.visual.spec.js
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2024, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Tests the visual appearance of the Time Conductor component
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { expect, test } from '../../../avpFixtures.js';
|
||||||
|
import {
|
||||||
|
MISSION_TIME,
|
||||||
|
MISSION_TIME_FIXED_END,
|
||||||
|
MISSION_TIME_FIXED_START,
|
||||||
|
VISUAL_REALTIME_URL
|
||||||
|
} from '../../../constants.js';
|
||||||
|
|
||||||
|
test.describe('Visual - Time Conductor', () => {
|
||||||
|
test.use({
|
||||||
|
clockOptions: {
|
||||||
|
now: MISSION_TIME,
|
||||||
|
shouldAdvanceTime: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
test.beforeEach(async ({ page }) => {
|
||||||
|
await page.goto('./', { waitUntil: 'domcontentloaded' });
|
||||||
|
});
|
||||||
|
|
||||||
|
// FIXME: checking for a11y violations times out. Might have something to do with the frozen clock.
|
||||||
|
// test.afterEach(async ({ page }, testInfo) => {
|
||||||
|
// await scanForA11yViolations(page, testInfo.title);
|
||||||
|
// });
|
||||||
|
|
||||||
|
test('Visual - Time Conductor (Fixed time) @clock @snapshot', async ({ page }) => {
|
||||||
|
// Navigate to a specific view that uses the Time Conductor in Fixed Time mode with inspect and browse panes collapsed
|
||||||
|
await page.goto(
|
||||||
|
`./#/browse/mine?tc.mode=fixed&tc.startBound=${MISSION_TIME_FIXED_START}&tc.endBound=${MISSION_TIME_FIXED_END}&tc.timeSystem=utc&view=grid&hideInspector=true&hideTree=true`,
|
||||||
|
{
|
||||||
|
waitUntil: 'domcontentloaded'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Take a snapshot for comparison
|
||||||
|
const snapshot = await page.screenshot({
|
||||||
|
mask: []
|
||||||
|
});
|
||||||
|
expect(snapshot).toMatchSnapshot('time-conductor-fixed-time.png');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Visual - Time Conductor (Realtime) @clock @snapshot', async ({ page }) => {
|
||||||
|
// Navigate to a specific view that uses the Time Conductor in Fixed Time mode with inspect and browse panes collapsed
|
||||||
|
await page.goto(VISUAL_REALTIME_URL, {
|
||||||
|
waitUntil: 'domcontentloaded'
|
||||||
|
});
|
||||||
|
|
||||||
|
const mask = [];
|
||||||
|
|
||||||
|
// Take a snapshot for comparison
|
||||||
|
const snapshot = await page.screenshot({
|
||||||
|
mask
|
||||||
|
});
|
||||||
|
expect(snapshot).toMatchSnapshot('time-conductor-realtime.png');
|
||||||
|
});
|
||||||
|
test(
|
||||||
|
'Visual - Time Conductor Axis Resized @clock @snapshot',
|
||||||
|
{ annotation: [{ type: 'issue', description: 'https://github.com/nasa/openmct/issues/7623' }] },
|
||||||
|
async ({ page, tick }) => {
|
||||||
|
const VISUAL_REALTIME_WITH_PANES = VISUAL_REALTIME_URL.replace(
|
||||||
|
'hideTree=true',
|
||||||
|
'hideTree=false'
|
||||||
|
).replace('hideInspector=true', 'hideInspector=false');
|
||||||
|
// Navigate to a specific view that uses the Time Conductor in Fixed Time mode with inspect
|
||||||
|
await page.goto(VISUAL_REALTIME_WITH_PANES, {
|
||||||
|
waitUntil: 'domcontentloaded'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set the time conductor to fixed time mode
|
||||||
|
await page.getByLabel('Time Conductor Mode').click();
|
||||||
|
await page.getByLabel('Time Conductor Mode Menu').click();
|
||||||
|
await page.getByLabel('Fixed Timespan').click();
|
||||||
|
await page.getByLabel('Submit time bounds').click();
|
||||||
|
|
||||||
|
// Collapse the inspect and browse panes to trigger a resize of the conductor axis
|
||||||
|
await page.getByLabel('Collapse Inspect Pane').click();
|
||||||
|
await page.getByLabel('Collapse Browse Pane').click();
|
||||||
|
|
||||||
|
// manually tick the clock to trigger the resize / re-render
|
||||||
|
await tick(1000 * 2);
|
||||||
|
|
||||||
|
const mask = [];
|
||||||
|
|
||||||
|
// Take a snapshot for comparison
|
||||||
|
const snapshot = await page.screenshot({
|
||||||
|
mask
|
||||||
|
});
|
||||||
|
expect(snapshot).toMatchSnapshot('time-conductor-axis-resized.png');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 29 KiB |
@ -23,7 +23,7 @@
|
|||||||
import percySnapshot from '@percy/playwright';
|
import percySnapshot from '@percy/playwright';
|
||||||
|
|
||||||
import { createDomainObjectWithDefaults, expandTreePaneItemByName } from '../../../appActions.js';
|
import { createDomainObjectWithDefaults, expandTreePaneItemByName } from '../../../appActions.js';
|
||||||
import { VISUAL_URL } from '../../../constants.js';
|
import { VISUAL_FIXED_URL } from '../../../constants.js';
|
||||||
import { test } from '../../../pluginFixtures.js';
|
import { test } from '../../../pluginFixtures.js';
|
||||||
|
|
||||||
//Declare the scope of the visual test
|
//Declare the scope of the visual test
|
||||||
@ -32,7 +32,7 @@ const treePane = "[role=tree][aria-label='Main Tree']";
|
|||||||
test.describe('Visual - Tree Pane', () => {
|
test.describe('Visual - Tree Pane', () => {
|
||||||
test('Tree pane in various states', async ({ page, theme, openmctConfig }) => {
|
test('Tree pane in various states', async ({ page, theme, openmctConfig }) => {
|
||||||
const { myItemsFolderName } = openmctConfig;
|
const { myItemsFolderName } = openmctConfig;
|
||||||
await page.goto(VISUAL_URL, { waitUntil: 'domcontentloaded' });
|
await page.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
|
||||||
|
|
||||||
//Open Tree
|
//Open Tree
|
||||||
await page.getByRole('button', { name: 'Browse' }).click();
|
await page.getByRole('button', { name: 'Browse' }).click();
|
||||||
|
@ -27,12 +27,12 @@ clockOptions plugin fixture.
|
|||||||
|
|
||||||
import percySnapshot from '@percy/playwright';
|
import percySnapshot from '@percy/playwright';
|
||||||
|
|
||||||
import { MISSION_TIME, VISUAL_URL } from '../../constants.js';
|
import { MISSION_TIME, VISUAL_FIXED_URL } from '../../constants.js';
|
||||||
import { expect, test } from '../../pluginFixtures.js';
|
import { expect, test } from '../../pluginFixtures.js';
|
||||||
|
|
||||||
test.describe('Visual - Controlled Clock @clock', () => {
|
test.describe('Visual - Controlled Clock @clock', () => {
|
||||||
test.beforeEach(async ({ page }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
await page.goto(VISUAL_URL, { waitUntil: 'domcontentloaded' });
|
await page.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
|
||||||
});
|
});
|
||||||
test.use({
|
test.use({
|
||||||
storageState: './e2e/test-data/overlay_plot_with_delay_storage.json',
|
storageState: './e2e/test-data/overlay_plot_with_delay_storage.json',
|
||||||
@ -43,7 +43,7 @@ test.describe('Visual - Controlled Clock @clock', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Overlay Plot Loading Indicator @localStorage', async ({ page, theme }) => {
|
test('Overlay Plot Loading Indicator @localStorage', async ({ page, theme }) => {
|
||||||
await page.goto(VISUAL_URL, { waitUntil: 'domcontentloaded' });
|
await page.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
|
||||||
await page
|
await page
|
||||||
.getByRole('gridcell', { hasText: 'Overlay Plot with 5s Delay Overlay Plot' })
|
.getByRole('gridcell', { hasText: 'Overlay Plot with 5s Delay Overlay Plot' })
|
||||||
.click();
|
.click();
|
||||||
|
@ -30,11 +30,11 @@ import percySnapshot from '@percy/playwright';
|
|||||||
|
|
||||||
import { createDomainObjectWithDefaults } from '../../appActions.js';
|
import { createDomainObjectWithDefaults } from '../../appActions.js';
|
||||||
import { expect, scanForA11yViolations, test } from '../../avpFixtures.js';
|
import { expect, scanForA11yViolations, test } from '../../avpFixtures.js';
|
||||||
import { VISUAL_URL } from '../../constants.js';
|
import { VISUAL_FIXED_URL } from '../../constants.js';
|
||||||
|
|
||||||
test.describe('Visual - Default @a11y', () => {
|
test.describe('Visual - Default @a11y', () => {
|
||||||
test.beforeEach(async ({ page }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
await page.goto(VISUAL_URL, { waitUntil: 'domcontentloaded' });
|
await page.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Visual - Default Dashboard', async ({ page, theme }) => {
|
test('Visual - Default Dashboard', async ({ page, theme }) => {
|
||||||
|
@ -23,12 +23,18 @@
|
|||||||
import percySnapshot from '@percy/playwright';
|
import percySnapshot from '@percy/playwright';
|
||||||
|
|
||||||
import { createDomainObjectWithDefaults } from '../../appActions.js';
|
import { createDomainObjectWithDefaults } from '../../appActions.js';
|
||||||
import { VISUAL_URL } from '../../constants.js';
|
import { MISSION_TIME, VISUAL_FIXED_URL } from '../../constants.js';
|
||||||
import { test } from '../../pluginFixtures.js';
|
import { test } from '../../pluginFixtures.js';
|
||||||
|
|
||||||
test.describe('Visual - Display Layout', () => {
|
test.describe('Visual - Display Layout @clock', () => {
|
||||||
test.beforeEach(async ({ page, theme }) => {
|
test.use({
|
||||||
await page.goto(VISUAL_URL, { waitUntil: 'domcontentloaded' });
|
clockOptions: {
|
||||||
|
now: MISSION_TIME,
|
||||||
|
shouldAdvanceTime: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
test.beforeEach(async ({ page }) => {
|
||||||
|
await page.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
|
||||||
|
|
||||||
const parentLayout = await createDomainObjectWithDefaults(page, {
|
const parentLayout = await createDomainObjectWithDefaults(page, {
|
||||||
type: 'Display Layout',
|
type: 'Display Layout',
|
||||||
@ -59,12 +65,15 @@ test.describe('Visual - Display Layout', () => {
|
|||||||
await page.goto(parentLayout.url, { waitUntil: 'domcontentloaded' });
|
await page.goto(parentLayout.url, { waitUntil: 'domcontentloaded' });
|
||||||
await page.getByRole('button', { name: 'Edit Object' }).click();
|
await page.getByRole('button', { name: 'Edit Object' }).click();
|
||||||
|
|
||||||
//Move the Child Right Layout to the Right. It should be on top of the Left Layout at this point.
|
// Select the child right layout
|
||||||
await page
|
await page
|
||||||
.getByLabel('Child Right Layout Layout', { exact: true })
|
.getByLabel('Child Right Layout Layout', { exact: true })
|
||||||
.getByLabel('Move Sub-object Frame')
|
.getByLabel('Move Sub-object Frame')
|
||||||
.click();
|
.click();
|
||||||
await page.getByLabel('Move Sub-object Frame').nth(3).click(); //I'm not sure why this step is necessary
|
// FIXME: Click to select the parent object (layout)
|
||||||
|
await page.getByLabel('Move Sub-object Frame').nth(3).click();
|
||||||
|
|
||||||
|
// Move the second layout element to the right
|
||||||
await page.getByLabel('X:').click();
|
await page.getByLabel('X:').click();
|
||||||
await page.getByLabel('X:').fill('35');
|
await page.getByLabel('X:').fill('35');
|
||||||
});
|
});
|
||||||
|
@ -84,6 +84,12 @@ test.describe('Fault Management Visual Tests', () => {
|
|||||||
await shelveFault(page, 1);
|
await shelveFault(page, 1);
|
||||||
await changeViewTo(page, 'shelved');
|
await changeViewTo(page, 'shelved');
|
||||||
|
|
||||||
|
/* cspell:disable-next-line */
|
||||||
|
// Since fault management is heavily dependent on events (bleh), we need to wait for the correct
|
||||||
|
// element counts
|
||||||
|
await expect(page.getByLabel('Select fault:')).toHaveCount(1);
|
||||||
|
await expect(page.getByLabel('Disposition Actions')).toHaveCount(1);
|
||||||
|
|
||||||
await percySnapshot(page, `Shelved faults appear in the shelved view (theme: '${theme}')`);
|
await percySnapshot(page, `Shelved faults appear in the shelved view (theme: '${theme}')`);
|
||||||
|
|
||||||
await openFaultRowMenu(page, 1);
|
await openFaultRowMenu(page, 1);
|
||||||
|
@ -24,7 +24,7 @@ import percySnapshot from '@percy/playwright';
|
|||||||
|
|
||||||
import { createDomainObjectWithDefaults, setRealTimeMode } from '../../appActions.js';
|
import { createDomainObjectWithDefaults, setRealTimeMode } from '../../appActions.js';
|
||||||
import { waitForAnimations } from '../../baseFixtures.js';
|
import { waitForAnimations } from '../../baseFixtures.js';
|
||||||
import { VISUAL_URL } from '../../constants.js';
|
import { VISUAL_FIXED_URL } from '../../constants.js';
|
||||||
import { expect, test } from '../../pluginFixtures.js';
|
import { expect, test } from '../../pluginFixtures.js';
|
||||||
|
|
||||||
test.describe('Visual - Example Imagery', () => {
|
test.describe('Visual - Example Imagery', () => {
|
||||||
@ -32,7 +32,7 @@ test.describe('Visual - Example Imagery', () => {
|
|||||||
let parentLayout;
|
let parentLayout;
|
||||||
|
|
||||||
test.beforeEach(async ({ page }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
await page.goto(VISUAL_URL, { waitUntil: 'domcontentloaded' });
|
await page.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
|
||||||
|
|
||||||
parentLayout = await createDomainObjectWithDefaults(page, {
|
parentLayout = await createDomainObjectWithDefaults(page, {
|
||||||
type: 'Display Layout',
|
type: 'Display Layout',
|
||||||
|
@ -23,14 +23,14 @@
|
|||||||
import percySnapshot from '@percy/playwright';
|
import percySnapshot from '@percy/playwright';
|
||||||
|
|
||||||
import { createDomainObjectWithDefaults } from '../../appActions.js';
|
import { createDomainObjectWithDefaults } from '../../appActions.js';
|
||||||
import { VISUAL_URL } from '../../constants.js';
|
import { VISUAL_FIXED_URL } from '../../constants.js';
|
||||||
import { expect, test } from '../../pluginFixtures.js';
|
import { expect, test } from '../../pluginFixtures.js';
|
||||||
|
|
||||||
test.describe('Visual - LAD Table', () => {
|
test.describe('Visual - LAD Table', () => {
|
||||||
let ladTable;
|
let ladTable;
|
||||||
|
|
||||||
test.beforeEach(async ({ page }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
await page.goto(VISUAL_URL, { waitUntil: 'domcontentloaded' });
|
await page.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
|
||||||
|
|
||||||
// Create LAD Table
|
// Create LAD Table
|
||||||
ladTable = await createDomainObjectWithDefaults(page, {
|
ladTable = await createDomainObjectWithDefaults(page, {
|
||||||
|
@ -24,7 +24,7 @@ import percySnapshot from '@percy/playwright';
|
|||||||
|
|
||||||
import { createDomainObjectWithDefaults, expandTreePaneItemByName } from '../../appActions.js';
|
import { createDomainObjectWithDefaults, expandTreePaneItemByName } from '../../appActions.js';
|
||||||
import { expect, test } from '../../avpFixtures.js';
|
import { expect, test } from '../../avpFixtures.js';
|
||||||
import { VISUAL_URL } from '../../constants.js';
|
import { VISUAL_FIXED_URL } from '../../constants.js';
|
||||||
import { enterTextEntry, startAndAddRestrictedNotebookObject } from '../../helper/notebookUtils.js';
|
import { enterTextEntry, startAndAddRestrictedNotebookObject } from '../../helper/notebookUtils.js';
|
||||||
|
|
||||||
test.describe('Visual - Restricted Notebook @a11y', () => {
|
test.describe('Visual - Restricted Notebook @a11y', () => {
|
||||||
@ -80,7 +80,7 @@ test.describe('Visual - Notebook Snapshot @a11y', () => {
|
|||||||
test.describe('Visual - Notebook @a11y', () => {
|
test.describe('Visual - Notebook @a11y', () => {
|
||||||
let notebook;
|
let notebook;
|
||||||
test.beforeEach(async ({ page }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
await page.goto(VISUAL_URL, { waitUntil: 'domcontentloaded' });
|
await page.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
|
||||||
notebook = await createDomainObjectWithDefaults(page, {
|
notebook = await createDomainObjectWithDefaults(page, {
|
||||||
type: 'Notebook',
|
type: 'Notebook',
|
||||||
name: 'Test Notebook'
|
name: 'Test Notebook'
|
||||||
|
@ -28,11 +28,11 @@ import percySnapshot from '@percy/playwright';
|
|||||||
|
|
||||||
import { createNotification } from '../../appActions.js';
|
import { createNotification } from '../../appActions.js';
|
||||||
import { expect, scanForA11yViolations, test } from '../../avpFixtures.js';
|
import { expect, scanForA11yViolations, test } from '../../avpFixtures.js';
|
||||||
import { VISUAL_URL } from '../../constants.js';
|
import { VISUAL_FIXED_URL } from '../../constants.js';
|
||||||
|
|
||||||
test.describe('Visual - Notifications @a11y', () => {
|
test.describe('Visual - Notifications @a11y', () => {
|
||||||
test.beforeEach(async ({ page }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
await page.goto(VISUAL_URL, { waitUntil: 'domcontentloaded' });
|
await page.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Alert Levels and Notification List Modal', async ({ page, theme }) => {
|
test('Alert Levels and Notification List Modal', async ({ page, theme }) => {
|
||||||
|
@ -25,7 +25,7 @@ import fs from 'fs';
|
|||||||
|
|
||||||
import { createDomainObjectWithDefaults, createPlanFromJSON } from '../../appActions.js';
|
import { createDomainObjectWithDefaults, createPlanFromJSON } from '../../appActions.js';
|
||||||
import { test } from '../../avpFixtures.js';
|
import { test } from '../../avpFixtures.js';
|
||||||
import { VISUAL_URL } from '../../constants.js';
|
import { VISUAL_FIXED_URL } from '../../constants.js';
|
||||||
import {
|
import {
|
||||||
createTimelistWithPlanAndSetActivityInProgress,
|
createTimelistWithPlanAndSetActivityInProgress,
|
||||||
getFirstActivity,
|
getFirstActivity,
|
||||||
@ -64,7 +64,7 @@ test.describe('Visual - Timelist progress bar @clock', () => {
|
|||||||
|
|
||||||
test.describe('Visual - Planning', () => {
|
test.describe('Visual - Planning', () => {
|
||||||
test.beforeEach(async ({ page }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
await page.goto(VISUAL_URL, { waitUntil: 'domcontentloaded' });
|
await page.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Plan View', async ({ page, theme }) => {
|
test('Plan View', async ({ page, theme }) => {
|
||||||
@ -83,7 +83,7 @@ test.describe('Visual - Planning', () => {
|
|||||||
});
|
});
|
||||||
const newPage = await newContext.newPage();
|
const newPage = await newContext.newPage();
|
||||||
|
|
||||||
await newPage.goto(VISUAL_URL, { waitUntil: 'domcontentloaded' });
|
await newPage.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
|
||||||
const plan = await createPlanFromJSON(newPage, {
|
const plan = await createPlanFromJSON(newPage, {
|
||||||
name: 'Plan Visual Test',
|
name: 'Plan Visual Test',
|
||||||
json: examplePlanSmall2
|
json: examplePlanSmall2
|
||||||
@ -100,7 +100,7 @@ test.describe('Visual - Planning', () => {
|
|||||||
name: 'Plan Visual Test (Draft)',
|
name: 'Plan Visual Test (Draft)',
|
||||||
json: examplePlanSmall2
|
json: examplePlanSmall2
|
||||||
});
|
});
|
||||||
await page.goto(VISUAL_URL, { waitUntil: 'domcontentloaded' });
|
await page.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
|
||||||
await setDraftStatusForPlan(page, plan);
|
await setDraftStatusForPlan(page, plan);
|
||||||
|
|
||||||
await setBoundsToSpanAllActivities(page, examplePlanSmall2, plan.url);
|
await setBoundsToSpanAllActivities(page, examplePlanSmall2, plan.url);
|
||||||
@ -110,7 +110,7 @@ test.describe('Visual - Planning', () => {
|
|||||||
|
|
||||||
test.describe('Visual - Gantt Chart', () => {
|
test.describe('Visual - Gantt Chart', () => {
|
||||||
test.beforeEach(async ({ page }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
await page.goto(VISUAL_URL, { waitUntil: 'domcontentloaded' });
|
await page.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
|
||||||
});
|
});
|
||||||
test('Gantt Chart View', async ({ page, theme }) => {
|
test('Gantt Chart View', async ({ page, theme }) => {
|
||||||
const ganttChart = await createDomainObjectWithDefaults(page, {
|
const ganttChart = await createDomainObjectWithDefaults(page, {
|
||||||
@ -153,7 +153,7 @@ test.describe('Visual - Gantt Chart', () => {
|
|||||||
|
|
||||||
await setDraftStatusForPlan(page, plan);
|
await setDraftStatusForPlan(page, plan);
|
||||||
|
|
||||||
await page.goto(VISUAL_URL, { waitUntil: 'domcontentloaded' });
|
await page.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
|
||||||
|
|
||||||
await setBoundsToSpanAllActivities(page, examplePlanSmall2, ganttChart.url);
|
await setBoundsToSpanAllActivities(page, examplePlanSmall2, ganttChart.url);
|
||||||
await percySnapshot(page, `Gantt Chart View w/ draft status (theme: ${theme})`);
|
await percySnapshot(page, `Gantt Chart View w/ draft status (theme: ${theme})`);
|
||||||
|
@ -28,13 +28,13 @@ import percySnapshot from '@percy/playwright';
|
|||||||
|
|
||||||
import { createDomainObjectWithDefaults } from '../../appActions.js';
|
import { createDomainObjectWithDefaults } from '../../appActions.js';
|
||||||
import { expect, scanForA11yViolations, test } from '../../avpFixtures.js';
|
import { expect, scanForA11yViolations, test } from '../../avpFixtures.js';
|
||||||
import { VISUAL_URL } from '../../constants.js';
|
import { VISUAL_FIXED_URL } from '../../constants.js';
|
||||||
|
|
||||||
test.describe('Grand Search @a11y', () => {
|
test.describe('Grand Search @a11y', () => {
|
||||||
let conditionWidget;
|
let conditionWidget;
|
||||||
let displayLayout;
|
let displayLayout;
|
||||||
test.beforeEach(async ({ page }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
await page.goto(VISUAL_URL, { waitUntil: 'domcontentloaded' });
|
await page.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
|
||||||
|
|
||||||
displayLayout = await createDomainObjectWithDefaults(page, {
|
displayLayout = await createDomainObjectWithDefaults(page, {
|
||||||
type: 'Display Layout',
|
type: 'Display Layout',
|
||||||
|
@ -23,14 +23,14 @@
|
|||||||
import percySnapshot from '@percy/playwright';
|
import percySnapshot from '@percy/playwright';
|
||||||
|
|
||||||
import { createDomainObjectWithDefaults } from '../../appActions.js';
|
import { createDomainObjectWithDefaults } from '../../appActions.js';
|
||||||
import { VISUAL_URL } from '../../constants.js';
|
import { VISUAL_FIXED_URL } from '../../constants.js';
|
||||||
import { expect, test } from '../../pluginFixtures.js';
|
import { expect, test } from '../../pluginFixtures.js';
|
||||||
|
|
||||||
test.describe('Visual - Telemetry Views', () => {
|
test.describe('Visual - Telemetry Views', () => {
|
||||||
let telemetry;
|
let telemetry;
|
||||||
|
|
||||||
test.beforeEach(async ({ page }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
await page.goto(VISUAL_URL, { waitUntil: 'domcontentloaded' });
|
await page.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
|
||||||
|
|
||||||
// Create SWG inside of LAD Table
|
// Create SWG inside of LAD Table
|
||||||
telemetry = await createDomainObjectWithDefaults(page, {
|
telemetry = await createDomainObjectWithDefaults(page, {
|
||||||
|
@ -20,26 +20,32 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
/*global module,process*/
|
// eslint-disable-next-line func-style
|
||||||
|
const loadWebpackConfig = async () => {
|
||||||
|
if (process.env.KARMA_DEBUG) {
|
||||||
|
return {
|
||||||
|
config: (await import('./.webpack/webpack.dev.js')).default,
|
||||||
|
browsers: ['ChromeDebugging'],
|
||||||
|
singleRun: false
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
config: (await import('./.webpack/webpack.coverage.js')).default,
|
||||||
|
browsers: ['ChromeHeadless'],
|
||||||
|
singleRun: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = async (config) => {
|
module.exports = async (config) => {
|
||||||
let webpackConfig;
|
const { config: webpackConfig, browsers, singleRun } = await loadWebpackConfig();
|
||||||
let browsers;
|
|
||||||
let singleRun;
|
|
||||||
|
|
||||||
if (process.env.KARMA_DEBUG) {
|
|
||||||
webpackConfig = (await import('./.webpack/webpack.dev.js')).default;
|
|
||||||
browsers = ['ChromeDebugging'];
|
|
||||||
singleRun = false;
|
|
||||||
} else {
|
|
||||||
webpackConfig = (await import('./.webpack/webpack.coverage.js')).default;
|
|
||||||
browsers = ['ChromeHeadless'];
|
|
||||||
singleRun = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Adjust webpack config for Karma
|
||||||
delete webpackConfig.output;
|
delete webpackConfig.output;
|
||||||
// karma doesn't support webpack entry
|
delete webpackConfig.entry; // Karma doesn't support webpack entry
|
||||||
delete webpackConfig.entry;
|
|
||||||
|
// Ensure source maps are enabled for better debugging
|
||||||
|
webpackConfig.devtool = 'inline-source-map';
|
||||||
|
|
||||||
config.set({
|
config.set({
|
||||||
basePath: '',
|
basePath: '',
|
||||||
@ -106,7 +112,7 @@ module.exports = async (config) => {
|
|||||||
},
|
},
|
||||||
webpack: webpackConfig,
|
webpack: webpackConfig,
|
||||||
webpackMiddleware: {
|
webpackMiddleware: {
|
||||||
stats: 'errors-warnings'
|
stats: 'detailed' // Changed to 'detailed' for more debugging info
|
||||||
},
|
},
|
||||||
concurrency: 1,
|
concurrency: 1,
|
||||||
singleRun,
|
singleRun,
|
||||||
|
409
package-lock.json
generated
@ -22,6 +22,7 @@
|
|||||||
"@types/eventemitter3": "1.2.0",
|
"@types/eventemitter3": "1.2.0",
|
||||||
"@types/jasmine": "5.1.2",
|
"@types/jasmine": "5.1.2",
|
||||||
"@types/lodash": "4.17.0",
|
"@types/lodash": "4.17.0",
|
||||||
|
"@types/sinonjs__fake-timers": "8.1.5",
|
||||||
"@vue/compiler-sfc": "3.4.3",
|
"@vue/compiler-sfc": "3.4.3",
|
||||||
"babel-loader": "9.1.0",
|
"babel-loader": "9.1.0",
|
||||||
"babel-plugin-istanbul": "6.1.1",
|
"babel-plugin-istanbul": "6.1.1",
|
||||||
@ -1904,6 +1905,12 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/sinonjs__fake-timers": {
|
||||||
|
"version": "8.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz",
|
||||||
|
"integrity": "sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/sockjs": {
|
"node_modules/@types/sockjs": {
|
||||||
"version": "0.3.36",
|
"version": "0.3.36",
|
||||||
"resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz",
|
"resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz",
|
||||||
@ -1932,207 +1939,6 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/parser": {
|
|
||||||
"version": "6.21.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz",
|
|
||||||
"integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@typescript-eslint/scope-manager": "6.21.0",
|
|
||||||
"@typescript-eslint/types": "6.21.0",
|
|
||||||
"@typescript-eslint/typescript-estree": "6.21.0",
|
|
||||||
"@typescript-eslint/visitor-keys": "6.21.0",
|
|
||||||
"debug": "^4.3.4"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "^16.0.0 || >=18.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/typescript-eslint"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"eslint": "^7.0.0 || ^8.0.0"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"typescript": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@typescript-eslint/scope-manager": {
|
|
||||||
"version": "6.21.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz",
|
|
||||||
"integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@typescript-eslint/types": "6.21.0",
|
|
||||||
"@typescript-eslint/visitor-keys": "6.21.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "^16.0.0 || >=18.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/typescript-eslint"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@typescript-eslint/types": {
|
|
||||||
"version": "6.21.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz",
|
|
||||||
"integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==",
|
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
|
||||||
"node": "^16.0.0 || >=18.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/typescript-eslint"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@typescript-eslint/typescript-estree": {
|
|
||||||
"version": "6.21.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz",
|
|
||||||
"integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@typescript-eslint/types": "6.21.0",
|
|
||||||
"@typescript-eslint/visitor-keys": "6.21.0",
|
|
||||||
"debug": "^4.3.4",
|
|
||||||
"globby": "^11.1.0",
|
|
||||||
"is-glob": "^4.0.3",
|
|
||||||
"minimatch": "9.0.3",
|
|
||||||
"semver": "^7.5.4",
|
|
||||||
"ts-api-utils": "^1.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "^16.0.0 || >=18.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/typescript-eslint"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"typescript": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"balanced-match": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/globby": {
|
|
||||||
"version": "11.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
|
|
||||||
"integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"array-union": "^2.1.0",
|
|
||||||
"dir-glob": "^3.0.1",
|
|
||||||
"fast-glob": "^3.2.9",
|
|
||||||
"ignore": "^5.2.0",
|
|
||||||
"merge2": "^1.4.1",
|
|
||||||
"slash": "^3.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": {
|
|
||||||
"version": "6.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
|
||||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"yallist": "^4.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
|
|
||||||
"version": "9.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
|
|
||||||
"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"brace-expansion": "^2.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=16 || 14 >=14.17"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
|
|
||||||
"version": "7.6.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
|
|
||||||
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"lru-cache": "^6.0.0"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"semver": "bin/semver.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/slash": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
|
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
|
||||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/@typescript-eslint/visitor-keys": {
|
|
||||||
"version": "6.21.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz",
|
|
||||||
"integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@typescript-eslint/types": "6.21.0",
|
|
||||||
"eslint-visitor-keys": "^3.4.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "^16.0.0 || >=18.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/typescript-eslint"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
|
|
||||||
"version": "3.4.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
|
|
||||||
"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
|
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
|
||||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://opencollective.com/eslint"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@ungap/structured-clone": {
|
"node_modules/@ungap/structured-clone": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
|
||||||
@ -9255,6 +9061,207 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/prettier-eslint/node_modules/@typescript-eslint/parser": {
|
||||||
|
"version": "6.21.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz",
|
||||||
|
"integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/scope-manager": "6.21.0",
|
||||||
|
"@typescript-eslint/types": "6.21.0",
|
||||||
|
"@typescript-eslint/typescript-estree": "6.21.0",
|
||||||
|
"@typescript-eslint/visitor-keys": "6.21.0",
|
||||||
|
"debug": "^4.3.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"eslint": "^7.0.0 || ^8.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"typescript": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/prettier-eslint/node_modules/@typescript-eslint/scope-manager": {
|
||||||
|
"version": "6.21.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz",
|
||||||
|
"integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/types": "6.21.0",
|
||||||
|
"@typescript-eslint/visitor-keys": "6.21.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/prettier-eslint/node_modules/@typescript-eslint/types": {
|
||||||
|
"version": "6.21.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz",
|
||||||
|
"integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/prettier-eslint/node_modules/@typescript-eslint/typescript-estree": {
|
||||||
|
"version": "6.21.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz",
|
||||||
|
"integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/types": "6.21.0",
|
||||||
|
"@typescript-eslint/visitor-keys": "6.21.0",
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"globby": "^11.1.0",
|
||||||
|
"is-glob": "^4.0.3",
|
||||||
|
"minimatch": "9.0.3",
|
||||||
|
"semver": "^7.5.4",
|
||||||
|
"ts-api-utils": "^1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"typescript": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/prettier-eslint/node_modules/@typescript-eslint/visitor-keys": {
|
||||||
|
"version": "6.21.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz",
|
||||||
|
"integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/types": "6.21.0",
|
||||||
|
"eslint-visitor-keys": "^3.4.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/prettier-eslint/node_modules/brace-expansion": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"balanced-match": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/prettier-eslint/node_modules/eslint-visitor-keys": {
|
||||||
|
"version": "3.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
|
||||||
|
"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/prettier-eslint/node_modules/globby": {
|
||||||
|
"version": "11.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
|
||||||
|
"integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"array-union": "^2.1.0",
|
||||||
|
"dir-glob": "^3.0.1",
|
||||||
|
"fast-glob": "^3.2.9",
|
||||||
|
"ignore": "^5.2.0",
|
||||||
|
"merge2": "^1.4.1",
|
||||||
|
"slash": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/prettier-eslint/node_modules/lru-cache": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"yallist": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/prettier-eslint/node_modules/minimatch": {
|
||||||
|
"version": "9.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
|
||||||
|
"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"brace-expansion": "^2.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16 || 14 >=14.17"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/prettier-eslint/node_modules/semver": {
|
||||||
|
"version": "7.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
|
||||||
|
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"lru-cache": "^6.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"semver": "bin/semver.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/prettier-eslint/node_modules/slash": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/prettier-eslint/node_modules/yallist": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/prettier-linter-helpers": {
|
"node_modules/prettier-linter-helpers": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
|
||||||
|
@ -12,12 +12,13 @@
|
|||||||
"@percy/playwright": "1.0.4",
|
"@percy/playwright": "1.0.4",
|
||||||
"@playwright/test": "1.42.1",
|
"@playwright/test": "1.42.1",
|
||||||
"@types/d3-axis": "3.0.6",
|
"@types/d3-axis": "3.0.6",
|
||||||
"@types/d3-shape": "3.0.0",
|
|
||||||
"@types/d3-scale": "4.0.8",
|
"@types/d3-scale": "4.0.8",
|
||||||
"@types/d3-selection": "3.0.10",
|
"@types/d3-selection": "3.0.10",
|
||||||
|
"@types/d3-shape": "3.0.0",
|
||||||
"@types/eventemitter3": "1.2.0",
|
"@types/eventemitter3": "1.2.0",
|
||||||
"@types/jasmine": "5.1.2",
|
"@types/jasmine": "5.1.2",
|
||||||
"@types/lodash": "4.17.0",
|
"@types/lodash": "4.17.0",
|
||||||
|
"@types/sinonjs__fake-timers": "8.1.5",
|
||||||
"@vue/compiler-sfc": "3.4.3",
|
"@vue/compiler-sfc": "3.4.3",
|
||||||
"babel-loader": "9.1.0",
|
"babel-loader": "9.1.0",
|
||||||
"babel-plugin-istanbul": "6.1.1",
|
"babel-plugin-istanbul": "6.1.1",
|
||||||
@ -27,9 +28,9 @@
|
|||||||
"cspell": "7.3.8",
|
"cspell": "7.3.8",
|
||||||
"css-loader": "6.10.0",
|
"css-loader": "6.10.0",
|
||||||
"d3-axis": "3.0.0",
|
"d3-axis": "3.0.0",
|
||||||
"d3-shape": "3.0.0",
|
|
||||||
"d3-scale": "4.0.2",
|
"d3-scale": "4.0.2",
|
||||||
"d3-selection": "3.0.0",
|
"d3-selection": "3.0.0",
|
||||||
|
"d3-shape": "3.0.0",
|
||||||
"eslint": "8.56.0",
|
"eslint": "8.56.0",
|
||||||
"eslint-config-prettier": "9.1.0",
|
"eslint-config-prettier": "9.1.0",
|
||||||
"eslint-plugin-compat": "4.2.0",
|
"eslint-plugin-compat": "4.2.0",
|
||||||
|
@ -61,7 +61,6 @@ describe('DeviceClassifier', function () {
|
|||||||
mockAgent[m].and.returnValue(true);
|
mockAgent[m].and.returnValue(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
// eslint-disable-next-line no-new
|
|
||||||
DeviceClassifier(mockAgent, mockDocument);
|
DeviceClassifier(mockAgent, mockDocument);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ describe('The URLIndicator', function () {
|
|||||||
let openmct;
|
let openmct;
|
||||||
let indicatorElement;
|
let indicatorElement;
|
||||||
let pluginOptions;
|
let pluginOptions;
|
||||||
let urlIndicator; // eslint-disable-line
|
let urlIndicator;
|
||||||
let fetchSpy;
|
let fetchSpy;
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
|
@ -125,7 +125,7 @@ describe('the plugin', function () {
|
|||||||
|
|
||||||
describe('The bar graph view', () => {
|
describe('The bar graph view', () => {
|
||||||
let barGraphObject;
|
let barGraphObject;
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
let mockComposition;
|
let mockComposition;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
@ -222,7 +222,7 @@ describe('the plugin', function () {
|
|||||||
|
|
||||||
describe('The spectral plot view for telemetry objects with array values', () => {
|
describe('The spectral plot view for telemetry objects with array values', () => {
|
||||||
let barGraphObject;
|
let barGraphObject;
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
let mockComposition;
|
let mockComposition;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
@ -117,7 +117,7 @@ describe('the plugin', function () {
|
|||||||
describe('The scatter plot view', () => {
|
describe('The scatter plot view', () => {
|
||||||
let testDomainObject;
|
let testDomainObject;
|
||||||
let scatterPlotObject;
|
let scatterPlotObject;
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
let mockComposition;
|
let mockComposition;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
@ -134,7 +134,7 @@ describe('The import JSON action', function () {
|
|||||||
const pollutedResponse = {
|
const pollutedResponse = {
|
||||||
selectFile: {
|
selectFile: {
|
||||||
name: 'imported object',
|
name: 'imported object',
|
||||||
// eslint-disable-next-line prettier/prettier
|
|
||||||
body: '{"openmct":{"c28d230d-e909-4a3e-9840-d9ef469dda70":{"identifier":{"key":"c28d230d-e909-4a3e-9840-d9ef469dda70","namespace":""},"name":"Unnamed Overlay Plot","type":"telemetry.plot.overlay","composition":[],"configuration":{"series":[]},"modified":1695837546833,"location":"mine","created":1695837546833,"persisted":1695837546833,"__proto__":{"toString":"foobar"}}},"rootId":"c28d230d-e909-4a3e-9840-d9ef469dda70"}'
|
body: '{"openmct":{"c28d230d-e909-4a3e-9840-d9ef469dda70":{"identifier":{"key":"c28d230d-e909-4a3e-9840-d9ef469dda70","namespace":""},"name":"Unnamed Overlay Plot","type":"telemetry.plot.overlay","composition":[],"configuration":{"series":[]},"modified":1695837546833,"location":"mine","created":1695837546833,"persisted":1695837546833,"__proto__":{"toString":"foobar"}}},"rootId":"c28d230d-e909-4a3e-9840-d9ef469dda70"}'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable no-invalid-this */
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Open MCT, Copyright (c) 2014-2024, United States Government
|
* Open MCT, Copyright (c) 2014-2024, United States Government
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
@ -161,7 +161,6 @@ export default function Rule(
|
|||||||
*/
|
*/
|
||||||
function onDragStart(event) {
|
function onDragStart(event) {
|
||||||
document.querySelectorAll('.t-drag-indicator').forEach((indicator) => {
|
document.querySelectorAll('.t-drag-indicator').forEach((indicator) => {
|
||||||
// eslint-disable-next-line no-invalid-this
|
|
||||||
const ruleHeader = self.domElement.querySelectorAll('.widget-rule-header')[0].cloneNode(true);
|
const ruleHeader = self.domElement.querySelectorAll('.widget-rule-header')[0].cloneNode(true);
|
||||||
indicator.textContent = '';
|
indicator.textContent = '';
|
||||||
indicator.appendChild(ruleHeader);
|
indicator.appendChild(ruleHeader);
|
||||||
|
@ -106,7 +106,6 @@ export default function ColorPalette(cssClass, container, colors) {
|
|||||||
domElement.querySelector('.c-palette').classList.add('c-palette--color');
|
domElement.querySelector('.c-palette').classList.add('c-palette--color');
|
||||||
|
|
||||||
domElement.querySelectorAll('.c-palette__item').forEach((item) => {
|
domElement.querySelectorAll('.c-palette__item').forEach((item) => {
|
||||||
// eslint-disable-next-line no-invalid-this
|
|
||||||
item.style.backgroundColor = item.dataset.item;
|
item.style.backgroundColor = item.dataset.item;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -51,7 +51,6 @@ export default function IconPalette(cssClass, container, icons) {
|
|||||||
domElement.querySelector('.c-palette').classList.add('c-palette--icon');
|
domElement.querySelector('.c-palette').classList.add('c-palette--icon');
|
||||||
|
|
||||||
domElement.querySelectorAll('.c-palette-item').forEach((item) => {
|
domElement.querySelectorAll('.c-palette-item').forEach((item) => {
|
||||||
// eslint-disable-next-line no-invalid-this
|
|
||||||
item.classList.add(item.dataset.item);
|
item.classList.add(item.dataset.item);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -20,7 +20,12 @@
|
|||||||
at runtime from the About dialog for additional information.
|
at runtime from the About dialog for additional information.
|
||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<div ref="axisHolder" class="c-conductor-axis" @mousedown="dragStart($event)">
|
<div
|
||||||
|
ref="axisHolder"
|
||||||
|
aria-label="Time Conductor Axis"
|
||||||
|
class="c-conductor-axis"
|
||||||
|
@mousedown="dragStart($event)"
|
||||||
|
>
|
||||||
<div class="c-conductor-axis__zoom-indicator" :style="zoomStyle"></div>
|
<div class="c-conductor-axis__zoom-indicator" :style="zoomStyle"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -29,7 +34,9 @@
|
|||||||
import { axisTop } from 'd3-axis';
|
import { axisTop } from 'd3-axis';
|
||||||
import { scaleLinear, scaleUtc } from 'd3-scale';
|
import { scaleLinear, scaleUtc } from 'd3-scale';
|
||||||
import { select } from 'd3-selection';
|
import { select } from 'd3-selection';
|
||||||
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
|
import { useResizeObserver } from '../../../src/ui/composables/resize.js';
|
||||||
import { TIME_CONTEXT_EVENTS } from '../../api/time/constants.js';
|
import { TIME_CONTEXT_EVENTS } from '../../api/time/constants.js';
|
||||||
import utcMultiTimeFormat from './utcMultiTimeFormat.js';
|
import utcMultiTimeFormat from './utcMultiTimeFormat.js';
|
||||||
|
|
||||||
@ -55,20 +62,69 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['pan-axis', 'end-pan', 'zoom-axis', 'end-zoom'],
|
emits: ['pan-axis', 'end-pan', 'zoom-axis', 'end-zoom'],
|
||||||
|
setup() {
|
||||||
|
const axisHolder = ref(null);
|
||||||
|
const { size: containerSize, startObserving } = useResizeObserver();
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
startObserving(axisHolder.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
axisHolder,
|
||||||
|
containerSize
|
||||||
|
};
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
inPanMode: false,
|
inPanMode: false,
|
||||||
dragStartX: undefined,
|
dragStartX: undefined,
|
||||||
dragX: undefined,
|
dragX: undefined,
|
||||||
zoomStyle: {}
|
zoomStyle: {},
|
||||||
|
rect: null
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
inZoomMode() {
|
inZoomMode() {
|
||||||
return !this.inPanMode;
|
return !this.inPanMode;
|
||||||
|
},
|
||||||
|
left() {
|
||||||
|
return this.rect.left;
|
||||||
|
},
|
||||||
|
panBounds() {
|
||||||
|
const bounds = this.openmct.time.getBounds();
|
||||||
|
const deltaTime = bounds.end - bounds.start;
|
||||||
|
const deltaX = this.dragX - this.dragStartX;
|
||||||
|
const percX = deltaX / this.width;
|
||||||
|
const panStart = bounds.start - percX * deltaTime;
|
||||||
|
|
||||||
|
return {
|
||||||
|
start: parseInt(panStart, 10),
|
||||||
|
end: parseInt(panStart + deltaTime, 10)
|
||||||
|
};
|
||||||
|
},
|
||||||
|
zoomRange() {
|
||||||
|
const leftBound = this.left;
|
||||||
|
const rightBound = this.left + this.width;
|
||||||
|
const zoomStart = this.dragX < leftBound ? leftBound : Math.min(this.dragX, this.dragStartX);
|
||||||
|
const zoomEnd = this.dragX > rightBound ? rightBound : Math.max(this.dragX, this.dragStartX);
|
||||||
|
|
||||||
|
return {
|
||||||
|
start: zoomStart,
|
||||||
|
end: zoomEnd
|
||||||
|
};
|
||||||
|
},
|
||||||
|
isChangingViewBounds() {
|
||||||
|
return this.dragStartX && this.dragX && this.dragStartX !== this.dragX;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
containerSize: {
|
||||||
|
handler() {
|
||||||
|
this.resize();
|
||||||
|
},
|
||||||
|
deep: true
|
||||||
|
},
|
||||||
viewBounds: {
|
viewBounds: {
|
||||||
handler() {
|
handler() {
|
||||||
this.setScale();
|
this.setScale();
|
||||||
@ -77,7 +133,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
let vis = select(this.$refs.axisHolder).append('svg:svg');
|
const vis = select(this.axisHolder).append('svg:svg');
|
||||||
|
|
||||||
this.xAxis = axisTop();
|
this.xAxis = axisTop();
|
||||||
this.dragging = false;
|
this.dragging = false;
|
||||||
@ -93,15 +149,14 @@ export default {
|
|||||||
this.openmct.time.on(TIME_CONTEXT_EVENTS.timeSystemChanged, this.setViewFromTimeSystem);
|
this.openmct.time.on(TIME_CONTEXT_EVENTS.timeSystemChanged, this.setViewFromTimeSystem);
|
||||||
},
|
},
|
||||||
beforeUnmount() {
|
beforeUnmount() {
|
||||||
clearInterval(this.resizeTimer);
|
// Remove the listeners in case the component is unmounted while dragging
|
||||||
|
document.removeEventListener('mousemove', this.drag);
|
||||||
|
document.removeEventListener('mouseup', this.dragEnd);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
setAxisDimensions() {
|
setAxisDimensions() {
|
||||||
const axisHolder = this.$refs.axisHolder;
|
this.rect = this.axisHolder.getBoundingClientRect();
|
||||||
const rect = axisHolder.getBoundingClientRect();
|
this.width = this.axisHolder.clientWidth;
|
||||||
|
|
||||||
this.left = Math.round(rect.left);
|
|
||||||
this.width = axisHolder.clientWidth;
|
|
||||||
},
|
},
|
||||||
setScale() {
|
setScale() {
|
||||||
if (!this.width) {
|
if (!this.width) {
|
||||||
@ -204,26 +259,14 @@ export default {
|
|||||||
this.dragX = undefined;
|
this.dragX = undefined;
|
||||||
},
|
},
|
||||||
pan() {
|
pan() {
|
||||||
const panBounds = this.getPanBounds();
|
const panBounds = this.panBounds;
|
||||||
this.$emit('pan-axis', panBounds);
|
this.$emit('pan-axis', panBounds);
|
||||||
},
|
},
|
||||||
endPan() {
|
endPan() {
|
||||||
const panBounds = this.isChangingViewBounds() ? this.getPanBounds() : undefined;
|
const panBounds = this.isChangingViewBounds ? this.panBounds : undefined;
|
||||||
this.$emit('end-pan', panBounds);
|
this.$emit('end-pan', panBounds);
|
||||||
this.inPanMode = false;
|
this.inPanMode = false;
|
||||||
},
|
},
|
||||||
getPanBounds() {
|
|
||||||
const bounds = this.openmct.time.getBounds();
|
|
||||||
const deltaTime = bounds.end - bounds.start;
|
|
||||||
const deltaX = this.dragX - this.dragStartX;
|
|
||||||
const percX = deltaX / this.width;
|
|
||||||
const panStart = bounds.start - percX * deltaTime;
|
|
||||||
|
|
||||||
return {
|
|
||||||
start: parseInt(panStart, 10),
|
|
||||||
end: parseInt(panStart + deltaTime, 10)
|
|
||||||
};
|
|
||||||
},
|
|
||||||
startZoom() {
|
startZoom() {
|
||||||
const x = this.scaleToBounds(this.dragStartX);
|
const x = this.scaleToBounds(this.dragStartX);
|
||||||
|
|
||||||
@ -237,7 +280,7 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
zoom() {
|
zoom() {
|
||||||
const zoomRange = this.getZoomRange();
|
const zoomRange = this.zoomRange;
|
||||||
|
|
||||||
this.zoomStyle = {
|
this.zoomStyle = {
|
||||||
left: `${zoomRange.start - this.left}px`,
|
left: `${zoomRange.start - this.left}px`,
|
||||||
@ -251,8 +294,8 @@ export default {
|
|||||||
},
|
},
|
||||||
endZoom() {
|
endZoom() {
|
||||||
let zoomBounds;
|
let zoomBounds;
|
||||||
if (this.isChangingViewBounds()) {
|
if (this.isChangingViewBounds) {
|
||||||
const zoomRange = this.getZoomRange();
|
const zoomRange = this.zoomRange;
|
||||||
zoomBounds = {
|
zoomBounds = {
|
||||||
start: this.scaleToBounds(zoomRange.start),
|
start: this.scaleToBounds(zoomRange.start),
|
||||||
end: this.scaleToBounds(zoomRange.end)
|
end: this.scaleToBounds(zoomRange.end)
|
||||||
@ -262,19 +305,6 @@ export default {
|
|||||||
this.zoomStyle = {};
|
this.zoomStyle = {};
|
||||||
this.$emit('end-zoom', zoomBounds);
|
this.$emit('end-zoom', zoomBounds);
|
||||||
},
|
},
|
||||||
getZoomRange() {
|
|
||||||
const leftBound = this.left;
|
|
||||||
const rightBound = this.left + this.width;
|
|
||||||
|
|
||||||
const zoomStart = this.dragX < leftBound ? leftBound : Math.min(this.dragX, this.dragStartX);
|
|
||||||
|
|
||||||
const zoomEnd = this.dragX > rightBound ? rightBound : Math.max(this.dragX, this.dragStartX);
|
|
||||||
|
|
||||||
return {
|
|
||||||
start: zoomStart,
|
|
||||||
end: zoomEnd
|
|
||||||
};
|
|
||||||
},
|
|
||||||
scaleToBounds(value) {
|
scaleToBounds(value) {
|
||||||
const bounds = this.openmct.time.getBounds();
|
const bounds = this.openmct.time.getBounds();
|
||||||
const timeDelta = bounds.end - bounds.start;
|
const timeDelta = bounds.end - bounds.start;
|
||||||
@ -283,11 +313,8 @@ export default {
|
|||||||
|
|
||||||
return parseInt(bounds.start + offset, 10);
|
return parseInt(bounds.start + offset, 10);
|
||||||
},
|
},
|
||||||
isChangingViewBounds() {
|
|
||||||
return this.dragStartX && this.dragX && this.dragStartX !== this.dragX;
|
|
||||||
},
|
|
||||||
resize() {
|
resize() {
|
||||||
if (this.$refs.axisHolder.clientWidth !== this.width) {
|
if (this.axisHolder.clientWidth !== this.width) {
|
||||||
this.setAxisDimensions();
|
this.setAxisDimensions();
|
||||||
this.setScale();
|
this.setScale();
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,6 @@ export default {
|
|||||||
formattedItemValues() {
|
formattedItemValues() {
|
||||||
let values = [];
|
let values = [];
|
||||||
this.itemProperties.forEach((property) => {
|
this.itemProperties.forEach((property) => {
|
||||||
// eslint-disable-next-line you-dont-need-lodash-underscore/get
|
|
||||||
let value = _.get(this.item, property.key);
|
let value = _.get(this.item, property.key);
|
||||||
if (property.format) {
|
if (property.format) {
|
||||||
value = property.format(value, this.item, property.key, this.openmct);
|
value = property.format(value, this.item, property.key, this.openmct);
|
||||||
|
@ -83,29 +83,26 @@ export function clearBuiltinSpies() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function resetApplicationState(openmct) {
|
export function resetApplicationState(openmct) {
|
||||||
let promise;
|
|
||||||
|
|
||||||
clearBuiltinSpies();
|
clearBuiltinSpies();
|
||||||
|
|
||||||
if (openmct !== undefined) {
|
if (openmct) {
|
||||||
openmct.destroy();
|
openmct.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window.location.hash !== '#' && window.location.hash !== '') {
|
if (window.location.hash !== '#' && window.location.hash !== '') {
|
||||||
promise = new Promise((resolve, reject) => {
|
window.location.hash = '#';
|
||||||
window.addEventListener('hashchange', cleanup);
|
// Optionally wait for hashchange if necessary
|
||||||
window.location.hash = '#';
|
return new Promise((resolve) => {
|
||||||
|
// eslint-disable-next-line func-style
|
||||||
function cleanup() {
|
const onHashChange = () => {
|
||||||
window.removeEventListener('hashchange', cleanup);
|
window.removeEventListener('hashchange', onHashChange);
|
||||||
resolve();
|
resolve();
|
||||||
}
|
};
|
||||||
|
window.addEventListener('hashchange', onHashChange);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
promise = Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
return promise;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// required: key
|
// required: key
|
||||||
|