Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: DisplayLayout and FlexibleLayout toolbar actions only apply to selected layout #7184

Merged
merged 25 commits into from
Nov 2, 2023
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
14983ea
WIP
ozyx Oct 27, 2023
3c38eb7
refactor: convert to ES6 function
ozyx Oct 30, 2023
43ea6cd
fix: include `keyString` in event name
ozyx Oct 30, 2023
2426f1f
fix: handle the case of currentView being null
ozyx Oct 30, 2023
88fbdbe
fix: add keyString to flexibleLayout toolbar events
ozyx Oct 30, 2023
3f7fcd1
fix: properly unregister listeners
ozyx Oct 30, 2023
e717bec
fix: remove unused imports
ozyx Oct 30, 2023
42a4de8
fix: revert parameter reorder
ozyx Oct 30, 2023
b5cc12c
refactor: replace usage of `arguments` with `...args`
ozyx Oct 30, 2023
0c0b478
fix: add a11y to display layout + toolbar
ozyx Nov 1, 2023
09e52c1
test: add first cut of layout toolbar suite
ozyx Nov 1, 2023
8fe50fa
test: cleanup a bit and add Image test
ozyx Nov 1, 2023
fc58177
test: add stubs
ozyx Nov 1, 2023
823ae28
fix: remove unused variable
ozyx Nov 1, 2023
a15aa52
refactor(DisplayLayoutToolbar): convert to ES6 class
ozyx Nov 1, 2023
dc50deb
test: generate localStorage data for display layout tests
ozyx Nov 1, 2023
e006906
fix: clarify "Add" button label
ozyx Nov 1, 2023
265b3e8
test: cleanup and don't parameterize tests
ozyx Nov 1, 2023
ec33110
test: fix path for recycled_local_storage.json
ozyx Nov 1, 2023
8235e58
fix: path to local storage file
ozyx Nov 1, 2023
1cf41d1
docs: add documentation for
ozyx Nov 1, 2023
865ba77
fix: path to recycled_local_storage.json
ozyx Nov 1, 2023
825365c
docs: add note hyperlink
ozyx Nov 1, 2023
cf43623
Merge branch 'master' into mct7176
scottbell Nov 2, 2023
f58465d
Merge branch 'master' into mct7176
ozyx Nov 2, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24 changes: 23 additions & 1 deletion e2e/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ Current list of test tags:
|`@ipad` | Test case or test suite is compatible with Playwright's iPad support and Open MCT's read-only mobile view (i.e. no create button).|
|`@gds` | Denotes a GDS Test Case used in the VIPER Mission.|
|`@addInit` | Initializes the browser with an injected and artificial state. Useful for loading non-default plugins. Likely will not work outside of `npm start`.|
|`@localStorage` | Captures or generates session storage to manipulate browser state. Useful for excluding in tests which require a persistent backend (i.e. CouchDB).|
|`@localStorage` | Captures or generates session storage to manipulate browser state. Useful for excluding in tests which require a persistent backend (i.e. CouchDB). See [note](#utilizing-localstorage)|
|`@snapshot` | Uses Playwright's snapshot functionality to record a copy of the DOM for direct comparison. Must be run inside of the playwright container.|
|`@unstable` | A new test or test which is known to be flaky.|
|`@2p` | Indicates that multiple users are involved, or multiple tabs/pages are used. Useful for testing multi-user interactivity.|
Expand Down Expand Up @@ -352,6 +352,28 @@ By adhering to this principle, we can create tests that are both robust and refl
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.

##### 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. 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:
```js
// Save localStorage for future test execution
await context.storageState({
path: path.join(__dirname, '../../../e2e/test-data/display_layout_with_child_layouts.json')
});
```
- Load the state from file at the beginning of the desired test suite (within the `test.describe()`). (NOTE: the storage state will be used for each test in the suite, so you may need to create a new suite):
```js
const LOCALSTORAGE_PATH = path.resolve(
__dirname,
'../../../../test-data/display_layout_with_child_layouts.json'
);
test.use({
storageState: path.resolve(__dirname, LOCALSTORAGE_PATH)
});
```


### How to write a great test

- Avoid using css locators to find elements to the page. Use modern web accessible locators like `getByRole`
Expand Down
22 changes: 22 additions & 0 deletions e2e/test-data/display_layout_with_child_layouts.json
ozyx marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"cookies": [],
"origins": [
{
"origin": "http://localhost:8080",
"localStorage": [
{
"name": "mct",
"value": "{\"mine\":{\"identifier\":{\"key\":\"mine\",\"namespace\":\"\"},\"name\":\"My Items\",\"type\":\"folder\",\"composition\":[{\"key\":\"764a490f-4a83-4874-a062-e38c112f69c7\",\"namespace\":\"\"}],\"location\":\"ROOT\",\"modified\":1732413602020,\"created\":1732413601160,\"persisted\":1732413602020},\"764a490f-4a83-4874-a062-e38c112f69c7\":{\"identifier\":{\"key\":\"764a490f-4a83-4874-a062-e38c112f69c7\",\"namespace\":\"\"},\"name\":\"Parent Display Layout\",\"type\":\"layout\",\"composition\":[{\"key\":\"801d3a35-91ac-43ae-b175-bc1be65f3587\",\"namespace\":\"\"},{\"key\":\"d70f3dfc-99c6-47f6-87c7-db8faed8598b\",\"namespace\":\"\"}],\"configuration\":{\"items\":[{\"width\":32,\"height\":18,\"x\":1,\"y\":30,\"identifier\":{\"key\":\"801d3a35-91ac-43ae-b175-bc1be65f3587\",\"namespace\":\"\"},\"hasFrame\":true,\"fontSize\":\"default\",\"font\":\"default\",\"type\":\"subobject-view\",\"id\":\"9acce141-5291-427d-8785-847faa2707e6\"},{\"width\":32,\"height\":18,\"x\":30,\"y\":1,\"identifier\":{\"key\":\"d70f3dfc-99c6-47f6-87c7-db8faed8598b\",\"namespace\":\"\"},\"hasFrame\":true,\"fontSize\":\"default\",\"font\":\"default\",\"type\":\"subobject-view\",\"id\":\"9f89d6f6-fb7f-4af3-9cc3-4c5d0864e908\"}],\"layoutGrid\":[10,10]},\"notes\":\"framework/generateLocalStorageData.e2e.spec.js\\nGenerate Visual Test Data @localStorage @generatedata\\nGenerate display layout with 2 child display layouts\\nchrome\",\"modified\":1732413605120,\"location\":\"mine\",\"created\":1732413602020,\"persisted\":1732413605120},\"801d3a35-91ac-43ae-b175-bc1be65f3587\":{\"name\":\"Child Layout 1\",\"type\":\"layout\",\"identifier\":{\"key\":\"801d3a35-91ac-43ae-b175-bc1be65f3587\",\"namespace\":\"\"},\"composition\":[],\"configuration\":{\"items\":[],\"layoutGrid\":[10,10]},\"notes\":\"framework/generateLocalStorageData.e2e.spec.js\\nGenerate Visual Test Data @localStorage @generatedata\\nGenerate display layout with 2 child display layouts\\nchrome\",\"modified\":1732413603140,\"location\":\"764a490f-4a83-4874-a062-e38c112f69c7\",\"created\":1732413603140,\"persisted\":1732413603140},\"d70f3dfc-99c6-47f6-87c7-db8faed8598b\":{\"name\":\"Child Layout 2\",\"type\":\"layout\",\"identifier\":{\"key\":\"d70f3dfc-99c6-47f6-87c7-db8faed8598b\",\"namespace\":\"\"},\"composition\":[],\"configuration\":{\"items\":[],\"layoutGrid\":[10,10]},\"notes\":\"framework/generateLocalStorageData.e2e.spec.js\\nGenerate Visual Test Data @localStorage @generatedata\\nGenerate display layout with 2 child display layouts\\nchrome\",\"modified\":1732413604240,\"location\":\"764a490f-4a83-4874-a062-e38c112f69c7\",\"created\":1732413604240,\"persisted\":1732413604240}}"
},
{
"name": "mct-recent-objects",
"value": "[{\"objectPath\":[{\"identifier\":{\"key\":\"764a490f-4a83-4874-a062-e38c112f69c7\",\"namespace\":\"\"},\"name\":\"Parent Display Layout\",\"type\":\"layout\",\"composition\":[{\"key\":\"801d3a35-91ac-43ae-b175-bc1be65f3587\",\"namespace\":\"\"},{\"key\":\"d70f3dfc-99c6-47f6-87c7-db8faed8598b\",\"namespace\":\"\"}],\"configuration\":{\"items\":[{\"width\":32,\"height\":18,\"x\":1,\"y\":1,\"identifier\":{\"key\":\"801d3a35-91ac-43ae-b175-bc1be65f3587\",\"namespace\":\"\"},\"hasFrame\":true,\"fontSize\":\"default\",\"font\":\"default\",\"type\":\"subobject-view\",\"id\":\"9acce141-5291-427d-8785-847faa2707e6\"}],\"layoutGrid\":[10,10]},\"notes\":\"framework/generateLocalStorageData.e2e.spec.js\\nGenerate Visual Test Data @localStorage @generatedata\\nGenerate display layout with 2 child display layouts\\nchrome\",\"modified\":1732413604240,\"location\":\"mine\",\"created\":1732413602020,\"persisted\":1732413604240},{\"identifier\":{\"key\":\"mine\",\"namespace\":\"\"},\"name\":\"My Items\",\"type\":\"folder\",\"composition\":[{\"key\":\"764a490f-4a83-4874-a062-e38c112f69c7\",\"namespace\":\"\"}],\"location\":\"ROOT\",\"modified\":1732413602020,\"created\":1732413601160,\"persisted\":1732413602020},{\"identifier\":{\"key\":\"ROOT\",\"namespace\":\"\"},\"name\":\"Open MCT\",\"type\":\"root\",\"composition\":[{\"key\":\"mine\",\"namespace\":\"\"}]}],\"navigationPath\":\"/browse/mine/764a490f-4a83-4874-a062-e38c112f69c7\",\"domainObject\":{\"identifier\":{\"key\":\"764a490f-4a83-4874-a062-e38c112f69c7\",\"namespace\":\"\"},\"name\":\"Parent Display Layout\",\"type\":\"layout\",\"composition\":[{\"key\":\"801d3a35-91ac-43ae-b175-bc1be65f3587\",\"namespace\":\"\"},{\"key\":\"d70f3dfc-99c6-47f6-87c7-db8faed8598b\",\"namespace\":\"\"}],\"configuration\":{\"items\":[{\"width\":32,\"height\":18,\"x\":1,\"y\":1,\"identifier\":{\"key\":\"801d3a35-91ac-43ae-b175-bc1be65f3587\",\"namespace\":\"\"},\"hasFrame\":true,\"fontSize\":\"default\",\"font\":\"default\",\"type\":\"subobject-view\",\"id\":\"9acce141-5291-427d-8785-847faa2707e6\"}],\"layoutGrid\":[10,10]},\"notes\":\"framework/generateLocalStorageData.e2e.spec.js\\nGenerate Visual Test Data @localStorage @generatedata\\nGenerate display layout with 2 child display layouts\\nchrome\",\"modified\":1732413604240,\"location\":\"mine\",\"created\":1732413602020,\"persisted\":1732413604240}},{\"objectPath\":[{\"identifier\":{\"key\":\"d70f3dfc-99c6-47f6-87c7-db8faed8598b\",\"namespace\":\"\"},\"name\":\"Child Layout 2\",\"type\":\"layout\",\"composition\":[],\"configuration\":{\"items\":[],\"layoutGrid\":[10,10]},\"notes\":\"framework/generateLocalStorageData.e2e.spec.js\\nGenerate Visual Test Data @localStorage @generatedata\\nGenerate display layout with 2 child display layouts\\nchrome\",\"modified\":1732413604240,\"location\":\"764a490f-4a83-4874-a062-e38c112f69c7\",\"created\":1732413604240,\"persisted\":1732413604240},{\"identifier\":{\"key\":\"764a490f-4a83-4874-a062-e38c112f69c7\",\"namespace\":\"\"},\"name\":\"Parent Display Layout\",\"type\":\"layout\",\"composition\":[{\"key\":\"801d3a35-91ac-43ae-b175-bc1be65f3587\",\"namespace\":\"\"},{\"key\":\"d70f3dfc-99c6-47f6-87c7-db8faed8598b\",\"namespace\":\"\"}],\"configuration\":{\"items\":[{\"width\":32,\"height\":18,\"x\":1,\"y\":1,\"identifier\":{\"key\":\"801d3a35-91ac-43ae-b175-bc1be65f3587\",\"namespace\":\"\"},\"hasFrame\":true,\"fontSize\":\"default\",\"font\":\"default\",\"type\":\"subobject-view\",\"id\":\"9acce141-5291-427d-8785-847faa2707e6\"}],\"layoutGrid\":[10,10]},\"notes\":\"framework/generateLocalStorageData.e2e.spec.js\\nGenerate Visual Test Data @localStorage @generatedata\\nGenerate display layout with 2 child display layouts\\nchrome\",\"modified\":1732413604240,\"location\":\"mine\",\"created\":1732413602020,\"persisted\":1732413604240},{\"identifier\":{\"key\":\"mine\",\"namespace\":\"\"},\"name\":\"My Items\",\"type\":\"folder\",\"composition\":[{\"key\":\"764a490f-4a83-4874-a062-e38c112f69c7\",\"namespace\":\"\"}],\"location\":\"ROOT\",\"modified\":1732413602020,\"created\":1732413601160,\"persisted\":1732413602020},{\"identifier\":{\"key\":\"ROOT\",\"namespace\":\"\"},\"name\":\"Open MCT\",\"type\":\"root\",\"composition\":[{\"key\":\"mine\",\"namespace\":\"\"}]}],\"navigationPath\":\"/browse/mine/764a490f-4a83-4874-a062-e38c112f69c7/d70f3dfc-99c6-47f6-87c7-db8faed8598b\",\"domainObject\":{\"identifier\":{\"key\":\"d70f3dfc-99c6-47f6-87c7-db8faed8598b\",\"namespace\":\"\"},\"name\":\"Child Layout 2\",\"type\":\"layout\",\"composition\":[],\"configuration\":{\"items\":[],\"layoutGrid\":[10,10]},\"notes\":\"framework/generateLocalStorageData.e2e.spec.js\\nGenerate Visual Test Data @localStorage @generatedata\\nGenerate display layout with 2 child display layouts\\nchrome\",\"modified\":1732413604240,\"location\":\"764a490f-4a83-4874-a062-e38c112f69c7\",\"created\":1732413604240,\"persisted\":1732413604240}},{\"objectPath\":[{\"identifier\":{\"key\":\"801d3a35-91ac-43ae-b175-bc1be65f3587\",\"namespace\":\"\"},\"name\":\"Child Layout 1\",\"type\":\"layout\",\"composition\":[],\"configuration\":{\"items\":[],\"layoutGrid\":[10,10]},\"notes\":\"framework/generateLocalStorageData.e2e.spec.js\\nGenerate Visual Test Data @localStorage @generatedata\\nGenerate display layout with 2 child display layouts\\nchrome\",\"modified\":1732413603140,\"location\":\"764a490f-4a83-4874-a062-e38c112f69c7\",\"created\":1732413603140,\"persisted\":1732413603140},{\"identifier\":{\"key\":\"764a490f-4a83-4874-a062-e38c112f69c7\",\"namespace\":\"\"},\"name\":\"Parent Display Layout\",\"type\":\"layout\",\"composition\":[{\"key\":\"801d3a35-91ac-43ae-b175-bc1be65f3587\",\"namespace\":\"\"},{\"key\":\"d70f3dfc-99c6-47f6-87c7-db8faed8598b\",\"namespace\":\"\"}],\"configuration\":{\"items\":[{\"width\":32,\"height\":18,\"x\":1,\"y\":1,\"identifier\":{\"key\":\"801d3a35-91ac-43ae-b175-bc1be65f3587\",\"namespace\":\"\"},\"hasFrame\":true,\"fontSize\":\"default\",\"font\":\"default\",\"type\":\"subobject-view\",\"id\":\"9acce141-5291-427d-8785-847faa2707e6\"}],\"layoutGrid\":[10,10]},\"notes\":\"framework/generateLocalStorageData.e2e.spec.js\\nGenerate Visual Test Data @localStorage @generatedata\\nGenerate display layout with 2 child display layouts\\nchrome\",\"modified\":1732413604240,\"location\":\"mine\",\"created\":1732413602020,\"persisted\":1732413604240},{\"identifier\":{\"key\":\"mine\",\"namespace\":\"\"},\"name\":\"My Items\",\"type\":\"folder\",\"composition\":[{\"key\":\"764a490f-4a83-4874-a062-e38c112f69c7\",\"namespace\":\"\"}],\"location\":\"ROOT\",\"modified\":1732413602020,\"created\":1732413601160,\"persisted\":1732413602020},{\"identifier\":{\"key\":\"ROOT\",\"namespace\":\"\"},\"name\":\"Open MCT\",\"type\":\"root\",\"composition\":[{\"key\":\"mine\",\"namespace\":\"\"}]}],\"navigationPath\":\"/browse/mine/764a490f-4a83-4874-a062-e38c112f69c7/801d3a35-91ac-43ae-b175-bc1be65f3587\",\"domainObject\":{\"identifier\":{\"key\":\"801d3a35-91ac-43ae-b175-bc1be65f3587\",\"namespace\":\"\"},\"name\":\"Child Layout 1\",\"type\":\"layout\",\"composition\":[],\"configuration\":{\"items\":[],\"layoutGrid\":[10,10]},\"notes\":\"framework/generateLocalStorageData.e2e.spec.js\\nGenerate Visual Test Data @localStorage @generatedata\\nGenerate display layout with 2 child display layouts\\nchrome\",\"modified\":1732413603140,\"location\":\"764a490f-4a83-4874-a062-e38c112f69c7\",\"created\":1732413603140,\"persisted\":1732413603140}},{\"objectPath\":[{\"identifier\":{\"key\":\"mine\",\"namespace\":\"\"},\"name\":\"My Items\",\"type\":\"folder\",\"composition\":[{\"key\":\"764a490f-4a83-4874-a062-e38c112f69c7\",\"namespace\":\"\"}],\"location\":\"ROOT\",\"modified\":1732413602020,\"created\":1732413601160,\"persisted\":1732413602020},{\"identifier\":{\"key\":\"ROOT\",\"namespace\":\"\"},\"name\":\"Open MCT\",\"type\":\"root\",\"composition\":[{\"key\":\"mine\",\"namespace\":\"\"}]}],\"navigationPath\":\"/browse/mine\",\"domainObject\":{\"identifier\":{\"key\":\"mine\",\"namespace\":\"\"},\"name\":\"My Items\",\"type\":\"folder\",\"composition\":[{\"key\":\"764a490f-4a83-4874-a062-e38c112f69c7\",\"namespace\":\"\"}],\"location\":\"ROOT\",\"modified\":1732413602020,\"created\":1732413601160,\"persisted\":1732413602020}}]"
},
{
"name": "mct-tree-expanded",
"value": "[]"
}
]
}
]
}
36 changes: 36 additions & 0 deletions e2e/tests/framework/generateLocalStorageData.e2e.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,42 @@ test.describe('Generate Visual Test Data @localStorage @generatedata', () => {
await page.goto('./', { waitUntil: 'domcontentloaded' });
});

test('Generate display layout with 2 child display layouts', async ({ page, context }) => {
// Create Display Layout
const parent = await createDomainObjectWithDefaults(page, {
type: 'Display Layout',
name: 'Parent Display Layout'
});
const child1 = await createDomainObjectWithDefaults(page, {
type: 'Display Layout',
name: 'Child Layout 1',
parent: parent.uuid
});
const child2 = await createDomainObjectWithDefaults(page, {
type: 'Display Layout',
name: 'Child Layout 2',
parent: parent.uuid
});

await page.goto(parent.url);
await page.getByLabel('Edit').click();
await page.getByLabel(`${child2.name} Layout Grid`).hover();
await page.getByLabel('Move Sub-object Frame').nth(1).click();
await page.getByLabel('X:').fill('30');

await page.getByLabel(`${child1.name} Layout Grid`).hover();
await page.getByLabel('Move Sub-object Frame').first().click();
await page.getByLabel('Y:').fill('30');

await page.getByLabel('Save').click();
await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click();

//Save localStorage for future test execution
await context.storageState({
path: path.join(__dirname, '../../../e2e/test-data/display_layout_with_child_layouts.json')
});
});

// TODO: Visual test for the generated object here
// - Move to using appActions to create the overlay plot
// and embedded standard telemetry object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/

/* global __dirname */
/*
This test suite is dedicated to tests which verify the basic operations surrounding conditionSets. Note: this
suite is sharing state between tests which is considered an anti-pattern. Implementing in this way to
Expand All @@ -31,6 +31,7 @@ const {
createDomainObjectWithDefaults,
createExampleTelemetryObject
} = require('../../../../appActions');
const path = require('path');

let conditionSetUrl;
let getConditionSetIdentifierFromUrl;
Expand All @@ -48,7 +49,9 @@ test.describe.serial('Condition Set CRUD Operations on @localStorage', () => {
await Promise.all([page.waitForNavigation(), page.click('button:has-text("OK")')]);

//Save localStorage for future test execution
await context.storageState({ path: './e2e/test-data/recycled_local_storage.json' });
await context.storageState({
path: path.resolve(__dirname, '../../../../test-data/recycled_local_storage.json')
});

//Set object identifier from url
conditionSetUrl = page.url();
Expand All @@ -59,7 +62,9 @@ test.describe.serial('Condition Set CRUD Operations on @localStorage', () => {
});

//Load localStorage for subsequent tests
test.use({ storageState: './e2e/test-data/recycled_local_storage.json' });
test.use({
storageState: path.resolve(__dirname, '../../../../test-data/recycled_local_storage.json')
});

//Begin suite of tests again localStorage
test('Condition set object properties persist in main view and inspector @localStorage', async ({
Expand Down