diff --git a/package.json b/package.json index 8e16c70c..a8b1b3fa 100644 --- a/package.json +++ b/package.json @@ -28,10 +28,10 @@ "prepare": "npm run build:dist", "test:getopensource": "sh ./tests/git-opensource-tests.sh", "posttest:getopensource": "npm install", - "test:e2e:smoke": "npm test --workspace tests/e2e/opensource -- --config=../playwright-quickstart.config.js --project=chromium quickstartSmoke", - "test:e2e:quickstart": "npm test --workspace tests/e2e/opensource -- --config=../playwright-quickstart.config.js --project=chromium tests/e2e/yamcs/", - "test:e2e:quickstart:local": "npm test --workspace tests/e2e/opensource -- --config=../playwright-quickstart.config.js --project=local-chrome tests/e2e/yamcs/", - "test:e2e:watch": "npm test --workspace tests/e2e/opensource -- --ui --config=../playwright-quickstart.config.js", + "test:e2e:smoke": "npm test --workspace tests/e2e/opensource -- --config=../playwright-quickstart.config.mjs --project=chromium quickstartSmoke", + "test:e2e:quickstart": "npm test --workspace tests/e2e/opensource -- --config=../playwright-quickstart.config.mjs --project=chromium tests/e2e/yamcs/", + "test:e2e:quickstart:local": "npm test --workspace tests/e2e/opensource -- --config=../playwright-quickstart.config.mjs --project=local-chrome tests/e2e/yamcs/", + "test:e2e:watch": "npm test --workspace tests/e2e/opensource -- --ui --config=../playwright-quickstart.config.mjs", "wait-for-yamcs": "wait-on http-get://localhost:8090/ -v" }, "keywords": [ diff --git a/tests/e2e/framework/quickstartFixtures.e2e.spec.mjs b/tests/e2e/framework/quickstartFixtures.e2e.spec.mjs new file mode 100644 index 00000000..7d91dbd1 --- /dev/null +++ b/tests/e2e/framework/quickstartFixtures.e2e.spec.mjs @@ -0,0 +1,49 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ + +/* +This test suite is dedicated to testing our use of our custom fixtures to verify +that they are working as expected. +*/ + +import { expect, filterNonFetchRequests, test} from '../quickstartFixtures.js'; + +test.describe('quickstartFixtures tests', () => { + // Keeping track of network requests during the tests. + let allNetworkRequests = []; + let fetchRequests = []; + + test('filterNonFetchRequests', async ({ page }) => { + // Listening for all network requests and pushing them into allNetworkRequests array. + page.on('request', request => allNetworkRequests.push(request)); + + // Setting up promises to wait for specific network responses. + // Testing the initial page load and verifying the presence of specific elements. + await page.goto("./", { waitUntil: "networkidle" }); + fetchRequests = filterNonFetchRequests(allNetworkRequests); + expect(allNetworkRequests.length).toBeGreaterThan(0); + expect(fetchRequests.length).toBeGreaterThan(0); + + // Removing the 'request' event listener to prevent potential memory leaks. + page.removeListener('request', request => allNetworkRequests.push(request)); + }); +}); diff --git a/tests/e2e/playwright-quickstart.config.js b/tests/e2e/playwright-quickstart.config.mjs similarity index 89% rename from tests/e2e/playwright-quickstart.config.js rename to tests/e2e/playwright-quickstart.config.mjs index fe446900..8c6b3f51 100644 --- a/tests/e2e/playwright-quickstart.config.js +++ b/tests/e2e/playwright-quickstart.config.mjs @@ -15,20 +15,20 @@ const config = { baseURL: 'http://localhost:9000/#', ignoreHTTPSErrors: true, myItemsFolderName: "My Items", - failOnConsoleError: false + failOnConsoleError: true }, webServer: { cwd: '../', command: 'npm run start:coverage', url: 'http://localhost:9000/#', timeout: 120 * 1000, - reuseExistingServer: false + reuseExistingServer: true }, workers: 1, projects: [ { name: "chromium", - grepInvert: /@unstable|@snapshot|@localStorage|@addInit/, + grepInvert: /@snapshot|@localStorage|@addInit/, use: { browserName: 'chromium', headless: true, @@ -40,7 +40,7 @@ const config = { // -- Local Browsers -- { name: "local-chrome", - grepInvert: /@unstable|@snapshot|@localStorage|@addInit/, + grepInvert: /@snapshot|@localStorage|@addInit/, use: { browserName: 'chromium', channel: 'chrome' diff --git a/tests/e2e/quickstartFixtures.mjs b/tests/e2e/quickstartFixtures.mjs new file mode 100644 index 00000000..a861445f --- /dev/null +++ b/tests/e2e/quickstartFixtures.mjs @@ -0,0 +1,56 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ + +/** + * The file contains custom fixtures which extend the base functionality of the Playwright fixtures + * and appActions. These fixtures should be generalized across all plugins. + */ + +// import { createDomainObjectWithDefaults } from './appActions.js'; +const { test, request, expect } = await import('./opensource/pluginFixtures.js'); + +/** + * The name of the "My Items" folder in the domain object tree. + * + * Default: `"My Items"` + * + * @type {string} + */ +export const myItemsFolderName = 'My Items'; + +export { expect, request, test }; + +/** + * Filters out non-fetch requests from the given array of network requests. + * This includes preflight CORS, fetching stylesheets, page icons, etc. + * Requires that a page requests instantiated like so + * ```js + * page.on('request', request => allNetworkRequests.push(request)); + * ``` + * @param {Array} requests - Array of network requests to filter. + * @returns {Array} Filtered network requests. + */ +export function filterNonFetchRequests(requests) { + return requests.filter(request => request.resourceType() === 'fetch'); +} + +//get linkZeroTelemetryToCurrentObject \ No newline at end of file diff --git a/tests/e2e/yamcs/actions.e2e.spec.mjs b/tests/e2e/yamcs/actions.e2e.spec.mjs new file mode 100644 index 00000000..54b6a3fb --- /dev/null +++ b/tests/e2e/yamcs/actions.e2e.spec.mjs @@ -0,0 +1,215 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2022, 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. + *****************************************************************************/ +/* + * Network Specific Tests for Open MCT and YAMCS connectivity. + * This suite verifies the network requests made by the application to ensure correct interaction with YAMCS. + */ + +import { test, expect, filterNonFetchRequests } from '../quickstartFixtures.mjs'; +import { createDomainObjectWithDefaults, setFixedTimeMode, navigateToObjectWithRealTime,navigateToObjectWithFixedTimeBounds } from '../opensource/appActions.js'; + +test.describe('Reload action', () => { + let displayLayout; + let batchGetResponse; + let battery1tempResponse; + let battery1tempResponseCont; + let battery1voltageResponse; + let battery1voltageResponeCont; + let allNetworkRequests = []; + test.beforeEach(async ({ page }) => { + await page.goto('./', { waitUntil: 'domcontentloaded' }); + + displayLayout = await createDomainObjectWithDefaults(page, { + type: 'Display Layout', + name: 'Display Layout' + }); + + await createDomainObjectWithDefaults(page, { + type: 'Telemetry Table', + name: 'Battery1_Temp Table' + }); + + //Expand the quickstart myproject twice to get to the telemetry in the tree + await page.getByLabel('Expand myproject folder').click(); + await page.getByLabel('Expand myproject folder').click(); + + //Add Battery1_Temp to Battery1_Temp Table + await page.getByLabel('Edit Object').click(); + await page.getByRole('treeitem', { name: 'Battery1_Temp' }).dragTo(page.locator('.c-table__body-w')); + await page.getByRole('button', { name: 'Save' }).click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); + + await createDomainObjectWithDefaults(page, { + type: 'Telemetry Table', + name: 'Beta Table' + }); + + //Add Battery1_Voltage to Beta Table + await page.getByLabel('Edit Object').click(); + await page.getByRole('treeitem', { name: 'Battery1_Voltage' }).dragTo(page.locator('.c-table__body-w')); + await page.getByRole('button', { name: 'Save' }).click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); + + //Add both Telemetry Tables to the Display Layout + await page.goto(displayLayout.url, { waitUntil: 'domcontentloaded' }); + await page.getByLabel('Edit Object', { exact: true }).click(); + await page.getByLabel('Collapse myproject folder').first().click(); + await page.getByLabel('Expand My Items folder').click(); + + await page.getByLabel('Preview Battery1_Temp Table table') + .dragTo(page.getByLabel('Display Layout Layout Grid').locator('div').nth(1), { + targetPosition: { x: 0, y: 0 } + }); + + await page.getByLabel('Preview Beta Table table') + .dragTo(page.getByLabel('Display Layout Layout Grid').locator('div').nth(1), { + targetPosition: { x: 0, y: 250 } + }); + + + await page.getByRole('button', { name: 'Save' }).click(); + await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); + + }); + + test('can reload telemetry table in display layout in real time mode', async ({ page }) => { + /* + * This test will + * 1. Load the display layout in realtime mode with seeded values + * 2. Reload the telemetry table + * 3. Verify that the network requests are correct + * 4. Verify that the telemetry values are different + */ + + //Intercept the request to /api/archive/myproject/parameters/myproject/Battery1_Temp before pageload + await page.route('**/api/archive/myproject/parameters/myproject/Battery1_Temp**', async route => { + const response = await route.fetch(); + const json = await response.json(); + + // Replace every "floatValue" with 1337 + json.parameter.forEach(param => { + if (param.rawValue && param.rawValue.type === 'FLOAT') { + param.rawValue.floatValue = 1337; + } + if (param.engValue && param.engValue.type === 'FLOAT') { + param.engValue.floatValue = 1337; + } + }); + + // Fulfill using the modified JSON object + await route.fulfill({ + body: JSON.stringify(json) + }); + }); + //Set to 1 Minute to reduce the time the opportunity for paginated data + await navigateToObjectWithRealTime(page, displayLayout.url, 60000, 0); + + // Listening for all network requests and pushing them into allNetworkRequests array. + page.on('request', request => allNetworkRequests.push(request)); + + const beforeReloadBattery1TempTelemetryValue = await page + .getByLabel('Battery1_Temp Table table content') + .getByLabel('value table cell') + .first() + .getAttribute('title'); + + const beforeReloadBetaTelemetryValue = await page + .getByLabel('Beta Table table content') + .getByLabel('value table cell') + .first() + .getAttribute('title'); + + //reload Battery1_Temp Table and verify network correctness + await page.waitForLoadState('networkidle'); + allNetworkRequests = []; + + //Create response promises + battery1tempResponse = page.waitForResponse('**/api/archive/myproject/parameters/myproject/Battery1_Temp**') + batchGetResponse = page.waitForResponse('**/api/processors/myproject/realtime/parameters:batchGet'); + + //Click on Reload Action on Battery1_Temp Table + await page.getByLabel('Battery1_Temp Table Frame Controls').getByLabel('View menu items').click(); + await page.getByLabel('Reload').click(); + + await Promise.all([battery1tempResponse, batchGetResponse]); + + await page.waitForLoadState('networkidle'); + //Only 2 requests should be made + expect(allNetworkRequests.length).toBe(2); + + const afterReloadAlphaTelemetryValue = await page + .getByLabel('Battery1_Temp Table table content') + .getByLabel('value table cell') + .first() + .getAttribute('title'); + const afterReloadBetaTelemetryValue = await page + .getByLabel('Beta Table table content') + .getByLabel('value table cell') + .first() + .getAttribute('title'); + + //After reload, the telemetry value should be different for Battery1_Temp Table + expect(beforeReloadBattery1TempTelemetryValue).not.toEqual(afterReloadAlphaTelemetryValue); + + expect(beforeReloadBetaTelemetryValue).toEqual(afterReloadBetaTelemetryValue); + + await page.waitForLoadState('networkidle'); + allNetworkRequests = []; + + battery1tempResponse = page.waitForResponse('**/api/archive/myproject/parameters/myproject/Battery1_Temp**') + battery1voltageResponse = page.waitForResponse('**/api/archive/myproject/parameters/myproject/Battery1_Voltage**') + batchGetResponse = page.waitForResponse('**/api/processors/myproject/realtime/parameters:batchGet'); + + await page.getByTitle('More actions').click(); + await page.getByRole('menuitem', { name: /Reload/ }).click(); + + await Promise.all([battery1tempResponse, battery1voltageResponse, batchGetResponse]); + + await page.waitForLoadState('networkidle'); + console.log(JSON.stringify(allNetworkRequests)); + + expect(allNetworkRequests.length).toBe(3); + + const fullReloadAlphaTelemetryValue = await page + .getByLabel('Battery1_Temp Table table content') + .getByLabel('value table cell') + .first() + .getAttribute('title'); + const fullReloadBetaTelemetryValue = await page + .getByLabel('Beta Table table content') + .getByLabel('value table cell') + .first() + .getAttribute('title'); + + expect(fullReloadAlphaTelemetryValue).not.toEqual(afterReloadAlphaTelemetryValue); + expect(fullReloadBetaTelemetryValue).not.toEqual(afterReloadBetaTelemetryValue); + }); + test('can reload telemetry table in display layout in fixed time mode', async ({ page }) => { + http://localhost:9000/#/browse/mine/83ae30a5-8d13-4def-881a-920b9fa795c1?tc.mode=local&tc.startDelta=60000&tc.endDelta=0&tc.timeSystem=utc + + + // Switch to fixed time mode with all plan events within the bounds + await navigateToObjectWithFixedTimeBounds(page, displayLayout.url, 60000, endBound); + }); + test.fixme('can reload notebook', async ({ page }) => {}); + test.fixme('can reload gauge', async ({ page }) => {}); +}); diff --git a/tests/e2e/yamcs/network.e2e.spec.mjs b/tests/e2e/yamcs/network.e2e.spec.mjs index 4ce60e52..bf8e6c35 100644 --- a/tests/e2e/yamcs/network.e2e.spec.mjs +++ b/tests/e2e/yamcs/network.e2e.spec.mjs @@ -33,18 +33,22 @@ const { setFixedTimeMode } = appActions; */ test.describe("Quickstart network requests @yamcs", () => { // Keeping track of network requests during the tests. - let networkRequests = []; - let filteredRequests = []; + let allNetworkRequests = []; + let fetchRequests = []; // These variables hold the promises for specific network requests we expect to occur. let parameterArchiveGet, batchGetStaleness, allParams, userGet, mdbOverride, mdbGet; test('Validate network traffic to YAMCS', async ({ page }) => { + // Listening for all network requests and pushing them into allNetworkRequests array. + page.on('request', request => allNetworkRequests.push(request)); + + // Setting up promises to wait for specific network responses. + allNetworkRequests = []; // Listening for all network requests and pushing them into networkRequests array. page.on('request', request => networkRequests.push(request)); // Setting up promises to wait for specific network responses. - networkRequests = []; mdbGet = page.waitForResponse('**/api/mdb/myproject/space-systems'); allParams = page.waitForResponse('**/api/mdb/myproject/parameters?details=yes&limit=1000'); userGet = page.waitForResponse('**/api/user/'); @@ -53,8 +57,8 @@ test.describe("Quickstart network requests @yamcs", () => { // Testing the initial page load and verifying the presence of specific elements. await page.goto("./", { waitUntil: "networkidle" }); await Promise.all([mdbGet, allParams, userGet, mdbOverride]); - filteredRequests = filterNonFetchRequests(networkRequests); - expect(filteredRequests.length).toBe(4); + fetchRequests = filterNonFetchRequests(allNetworkRequests); + expect(fetchRequests.length).toBe(4); // I'm not sure what is going on here const myProjectTreeItem = page.locator('.c-tree__item').filter({ hasText: 'myproject' }); @@ -64,16 +68,18 @@ test.describe("Quickstart network requests @yamcs", () => { // More UI interactions and network request verifications. await page.waitForLoadState('networkidle'); - networkRequests = []; + allNetworkRequests = []; + batchGetStaleness = page.waitForResponse('**/api/processors/myproject/realtime/parameters:batchGet'); await page.getByRole('treeitem', { name: 'Expand CCSDS_Packet_Sequence' }).click(); await batchGetStaleness; await page.waitForLoadState('networkidle'); - expect(networkRequests.length).toBe(1); + expect(allNetworkRequests.length).toBe(1); // Further UI interactions and network requests verification. - networkRequests = []; + allNetworkRequests = []; + parameterArchiveGet = page.waitForResponse('**/api/archive/myproject/parameters/myproject/CCSDS_Packet_Length/samples**'); batchGetStaleness = page.waitForResponse('**/api/processors/myproject/realtime/parameters:batchGet'); await page.getByRole('treeitem', { name: 'CCSDS_Packet_Length' }).click(); @@ -81,18 +87,20 @@ test.describe("Quickstart network requests @yamcs", () => { await Promise.all([parameterArchiveGet, batchGetStaleness]); await page.waitForLoadState('networkidle'); - expect(networkRequests.length).toBe(2); + expect(allNetworkRequests.length).toBe(2); // Simulating the change to fixed time mode and validating network requests. - networkRequests = []; + allNetworkRequests = []; + parameterArchiveGet = page.waitForResponse('**/api/archive/myproject/parameters/myproject/CCSDS_Packet_Length/samples**'); await setFixedTimeMode(page); await page.waitForLoadState('networkidle'); await parameterArchiveGet; - expect(networkRequests.length).toBe(1); + expect(allNetworkRequests.length).toBe(1); // Clicking on a different telemetry item to generate new requests. - networkRequests = []; + allNetworkRequests = []; + let groupFlagsGet = page.waitForResponse('**/api/archive/myproject/parameters/myproject/CCSDS_Packet_Sequence.GroupFlags**'); let countGet = page.waitForResponse('**/api/archive/myproject/parameters/myproject/CCSDS_Packet_Sequence.Count**'); batchGetStaleness = page.waitForResponse('**/api/processors/myproject/realtime/parameters:batchGet'); @@ -102,10 +110,11 @@ test.describe("Quickstart network requests @yamcs", () => { await Promise.all([groupFlagsGet, countGet, batchGetStaleness]); - expect(networkRequests.length).toBe(3); + expect(allNetworkRequests.length).toBe(3); // Clicking on the telemetry item in Fixed Time mode to generate two requests. - networkRequests = []; + allNetworkRequests = []; + parameterArchiveGet = page.waitForResponse('**/api/archive/myproject/parameters/myproject/CCSDS_Packet_Length/samples**'); batchGetStaleness = page.waitForResponse('**/api/processors/myproject/realtime/parameters:batchGet'); await page.getByRole('treeitem', { name: 'CCSDS_Packet_Length' }).click(); @@ -114,10 +123,11 @@ test.describe("Quickstart network requests @yamcs", () => { await Promise.all([parameterArchiveGet, batchGetStaleness]); // Waiting for debounced requests in YAMCS Latest Telemetry Provider to finish. - expect(networkRequests.length).toBe(2); + expect(allNetworkRequests.length).toBe(2); // Simulating a page refresh to generate a sequence of network requests. - networkRequests = []; + allNetworkRequests = []; + userGet = page.waitForResponse('**/api/user/'); allParams = page.waitForResponse('**/api/mdb/myproject/parameters?details=yes&limit=1000'); mdbOverride = page.waitForResponse('**/api/mdb-overrides/myproject/realtime'); @@ -129,11 +139,12 @@ test.describe("Quickstart network requests @yamcs", () => { await Promise.all([allParams, userGet, mdbOverride, parameterArchiveGet, batchGetStaleness, mdbOverride]); // Waiting for debounced requests in YAMCS Latest Telemetry Provider to finish. - filteredRequests = filterNonFetchRequests(networkRequests); - expect(filteredRequests.length).toBe(6); + fetchRequests = filterNonFetchRequests(allNetworkRequests); + expect(fetchRequests.length).toBe(6); // Removing the 'request' event listener to prevent potential memory leaks. - page.removeListener('request', request => networkRequests.push(request)); + page.removeListener('request', request => allNetworkRequests.push(request)); + }); /** diff --git a/tests/e2e/yamcs/staleness.e2e.mjs b/tests/e2e/yamcs/staleness.e2e.spec.mjs similarity index 100% rename from tests/e2e/yamcs/staleness.e2e.mjs rename to tests/e2e/yamcs/staleness.e2e.spec.mjs diff --git a/tests/e2e/yamcs/tabs.e2e.spec.mjs b/tests/e2e/yamcs/tabs.e2e.spec.mjs new file mode 100644 index 00000000..7ecc66ac --- /dev/null +++ b/tests/e2e/yamcs/tabs.e2e.spec.mjs @@ -0,0 +1,98 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2022, 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. + *****************************************************************************/ +/* + * Network Specific Tests for Open MCT and YAMCS connectivity with regard to tabs + */ + +import { test, expect, filterNonFetchRequests } from '../quickstartFixtures.mjs'; +import { createDomainObjectWithDefaults, setFixedTimeMode } from '../opensource/appActions.js'; + +test.describe('Tabs View', () => { + let tabsView; + let table; + let notebook; + let sineWaveGenerator; + + test.beforeEach(async ({ page }) => { + await page.goto('./', { waitUntil: 'domcontentloaded' }); + + tabsView = await createDomainObjectWithDefaults(page, { + type: 'Tabs View' + }); + table = await createDomainObjectWithDefaults(page, { + type: 'Telemetry Table', + parent: tabsView.uuid + }); + await createDomainObjectWithDefaults(page, { + type: 'Event Message Generator', + parent: table.uuid + }); + notebook = await createDomainObjectWithDefaults(page, { + type: 'Notebook', + parent: tabsView.uuid + }); + sineWaveGenerator = await createDomainObjectWithDefaults(page, { + type: 'Sine Wave Generator', + parent: tabsView.uuid + }); + }); + + test('Renders tabbed elements', async ({ page }) => { + await page.goto(tabsView.url); + + // select first tab + await page.getByLabel(`${table.name} tab`, { exact: true }).click(); + // ensure table header visible + await expect(page.getByRole('searchbox', { name: 'message filter input' })).toBeVisible(); + + // no canvas (i.e., sine wave generator) in the document should be visible + await expect(page.locator('canvas[id=webglContext]')).toBeHidden(); + + // select second tab + await page.getByLabel(`${notebook.name} tab`, { exact: true }).click(); + + // ensure notebook visible + await expect(page.locator('.c-notebook__drag-area')).toBeVisible(); + + // no canvas (i.e., sine wave generator) in the document should be visible + await expect(page.locator('canvas[id=webglContext]')).toBeHidden(); + + // select third tab + await page.getByLabel(`${sineWaveGenerator.name} tab`, { exact: true }).click(); + + // expect sine wave generator visible + await expect(page.locator('.c-plot')).toBeVisible(); + + // expect two canvases (i.e., overlay & main canvas for sine wave generator) to be visible + await expect(page.locator('canvas')).toHaveCount(2); + await expect(page.locator('canvas').nth(0)).toBeVisible(); + await expect(page.locator('canvas').nth(1)).toBeVisible(); + + // now try to select the first tab again + await page.getByLabel(`${table.name} tab`, { exact: true }).click(); + // ensure table header visible + await expect(page.getByRole('searchbox', { name: 'message filter input' })).toBeVisible(); + + // no canvas (i.e., sine wave generator) in the document should be visible + await expect(page.locator('canvas[id=webglContext]')).toBeHidden(); + }); +}); \ No newline at end of file