Skip to content

Commit c4edf3e

Browse files
committed
Merge branch 'mct-7876' of https://github.com/akhenry/openmct-yamcs into mct-7876
Mergin
2 parents b8320d6 + 35ca8ee commit c4edf3e

File tree

4 files changed

+133
-1
lines changed

4 files changed

+133
-1
lines changed

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ npm start
3434
This should build the example, and launch a web browser with Open MCT connected to a locally running YAMCS server. By
3535
default it is configured to connect to the "myproject" instance provided in the [YAMCS QuickStart](https://github.com/yamcs/quickstart) server.
3636

37+
> #### IMPORTANT NOTE
38+
> If Open MCT version issues are encountered with `npm run build:example`, try using `npm run build:example:master` to force usage of the latest version of Open MCT.
39+
3740
### Testing
3841

3942
This project is using the openmct-e2e-as-a-dependency model. For getting started with our tests, please see [our README](./tests/README.md)

example/example-display.json

+1
Large diffs are not rendered by default.

example/index.js

+112
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ const STATUS_STYLES = {
4545
const openmct = window.openmct;
4646

4747
(() => {
48+
const POLL_INTERVAL = 100; // ms
49+
const MAX_POLL_TIME = 10000; // 10 seconds
50+
const COMPOSITION_RETRY_DELAY = 250; // ms
51+
const MAX_COMPOSITION_RETRIES = 20; // 5 seconds total with 250ms intervals
4852
const ONE_SECOND = 1000;
4953
const ONE_MINUTE = ONE_SECOND * 60;
5054
const THIRTY_MINUTES = ONE_MINUTE * 30;
@@ -111,5 +115,113 @@ const openmct = window.openmct;
111115

112116
openmct.install(openmct.plugins.FaultManagement());
113117
openmct.install(openmct.plugins.BarChart());
118+
119+
// setup example display layout
120+
openmct.on('start', async () => {
121+
if (localStorage.getItem('exampleLayout') !== null) {
122+
return;
123+
}
124+
125+
// try to import the example display layout, fail gracefully
126+
try {
127+
// Function to fetch JSON content as text
128+
async function fetchJsonText(url) {
129+
const response = await fetch(url);
130+
const text = await response.text();
131+
132+
return text;
133+
}
134+
135+
async function getExampleLayoutPath() {
136+
const objects = Object.values(JSON.parse(localStorage.getItem('mct')));
137+
const exampleLayout = objects.find(object => object.name === 'Example Flexible Layout');
138+
let path = await openmct.objects.getOriginalPath(exampleLayout.identifier);
139+
140+
path.pop();
141+
path = path.reverse();
142+
path = path.reduce((prev, curr) => {
143+
return prev + '/' + openmct.objects.makeKeyString(curr.identifier);
144+
}, '#/browse');
145+
146+
return path;
147+
}
148+
149+
// poll for the localStorage item
150+
function mctItemExists() {
151+
return new Promise((resolve, reject) => {
152+
const startTime = Date.now();
153+
154+
function checkItem() {
155+
if (localStorage.getItem('mct') !== null) {
156+
resolve(true);
157+
158+
return;
159+
}
160+
161+
if (Date.now() - startTime > MAX_POLL_TIME) {
162+
reject(new Error('Timeout waiting for mct localStorage item'));
163+
164+
return;
165+
}
166+
167+
setTimeout(checkItem, POLL_INTERVAL);
168+
}
169+
170+
checkItem();
171+
});
172+
}
173+
174+
// wait for the 'mct' item to exist
175+
await mctItemExists();
176+
177+
// setup to use import as JSON action
178+
const importAction = openmct.actions.getAction('import.JSON');
179+
const myItems = await openmct.objects.get('mine');
180+
const exampleDisplayText = await fetchJsonText('./example-display.json');
181+
const selectFile = {
182+
body: exampleDisplayText
183+
};
184+
185+
// import the example display layout
186+
importAction.onSave(myItems, { selectFile });
187+
188+
// the importAction has asynchronous code, so we will need to check
189+
// the composition of My Items to confirm the import was successful
190+
const compositionCollection = openmct.composition.get(myItems);
191+
let compositionLength = 0;
192+
let composition;
193+
194+
let retryCount = 0;
195+
while (compositionLength === 0 && retryCount < MAX_COMPOSITION_RETRIES) {
196+
composition = await compositionCollection.load();
197+
compositionLength = composition.length;
198+
199+
if (compositionLength === 0) {
200+
retryCount++;
201+
await new Promise(resolve => setTimeout(resolve, COMPOSITION_RETRY_DELAY));
202+
}
203+
}
204+
205+
if (compositionLength === 0) {
206+
throw new Error('Failed to load composition after maximum retries');
207+
}
208+
209+
const exampleLayoutPath = await getExampleLayoutPath();
210+
211+
// give everything time to initialize
212+
await new Promise(resolve => setTimeout(resolve, 250));
213+
214+
openmct.notifications.info('Navigated to Example Display Layout');
215+
216+
// navigate to the "Example Display Layout"
217+
openmct.router.navigate(exampleLayoutPath);
218+
219+
// set the localStorage item to prevent this from running again
220+
localStorage.setItem('exampleLayout', 'true');
221+
} catch (error) {
222+
console.error('Failed to set up example display layout:', error);
223+
openmct.notifications.error('Failed to load example display layout: ' + error.message);
224+
}
225+
});
114226
}
115227
})();

tests/e2e/yamcs/quickstartSmoke.e2e.spec.mjs

+17-1
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,12 @@ import { baseFixtures } from 'openmct-e2e';
3737
const { test, expect } = baseFixtures;
3838

3939
test.describe("Quickstart smoke tests @yamcs", () => {
40-
test('Verify that the create button appears and that the Folder Domain Object is available for selection', async ({ page }) => {
40+
test.beforeEach(async ({ page }) => {
4141
//Go to baseURL
4242
await page.goto('./', { waitUntil: 'networkidle' });
43+
});
4344

45+
test('Verify that the create button appears and that the Folder Domain Object is available for selection', async ({ page }) => {
4446
//Click the Create button
4547
await page.getByRole('button', { name: 'Create' }).click();
4648

@@ -57,4 +59,18 @@ test.describe("Quickstart smoke tests @yamcs", () => {
5759
await expect(page.locator('.c-tree__item :text-is("myproject")')).toBeEnabled();
5860
await expect(page.locator('.c-tree__item :text-is("My Items")')).toBeEnabled();
5961
});
62+
63+
test('Verify that the default display is generated and navigated to without error', async ({ page }) => {
64+
await expect(page.getByRole('main').getByText('Example Flexible Layout')).toBeVisible();
65+
await expect(page.getByLabel('Health tab')).toBeVisible();
66+
await expect(page.getByLabel('Position tab')).toBeVisible();
67+
await expect(page.getByLabel('Velocity tab')).toBeVisible();
68+
await expect(page.getByLabel('All Current Values tab')).toBeVisible();
69+
await expect(page.getByText('SUBSYS')).toBeVisible();
70+
await expect(page.getByText('ADCS', { exact: true })).toBeVisible();
71+
await expect(page.getByText('CDHS', { exact: true })).toBeVisible();
72+
await expect(page.getByText('COMMS', { exact: true })).toBeVisible();
73+
await expect(page.getByText('EPS', { exact: true })).toBeVisible();
74+
await expect(page.getByLabel('CW PYLD Status Object View').getByText('PAYLOAD')).toBeVisible();
75+
});
6076
});

0 commit comments

Comments
 (0)