-
Notifications
You must be signed in to change notification settings - Fork 1.3k
[Flexible Layouts] Flexible Layout styling fixes #7319
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
Changes from 13 commits
39f30c0
30b34a2
ad290cb
5889376
6ab76ba
e28abcb
b462c6d
3aaf74b
aef2432
8bd5757
3b56b67
8190388
8165117
742e8e0
c4a7292
5f5c07e
08ed4be
70ad074
a8ac603
877b54a
3e16f0f
9945814
de1f511
3644534
72320b2
5001f66
2aa76b0
d0fadd3
ffdba24
46d4a29
8eb5856
f3409b3
5371591
1b7f0b3
cf2681e
4971bce
1df1f72
6e5fd05
8cf081d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
/* eslint-disable no-undef */ | ||
// playwright.config.js | ||
// @ts-check | ||
|
||
// eslint-disable-next-line no-unused-vars | ||
const { devices } = require('@playwright/test'); | ||
|
||
const MAX_FAILURES = 5; | ||
const NUM_WORKERS = 2; | ||
|
||
/** @type {import('@playwright/test').PlaywrightTestConfig} */ | ||
const config = { | ||
retries: 0, //Retries 2 times for a total of 3 runs. When running sharded and with max-failures=5, this should ensure that flake is managed without failing the full suite | ||
testDir: 'tests', | ||
timeout: 60 * 1000, | ||
webServer: { | ||
command: 'npm run start', //Start in dev mode for hot reloading | ||
url: 'http://localhost:8080/#', | ||
timeout: 200 * 1000, | ||
reuseExistingServer: true //This was originally disabled to prevent differences in local debugging vs. CI. However, it significantly speeds up local debugging. | ||
}, | ||
maxFailures: MAX_FAILURES, //Limits failures to 5 to reduce CI Waste | ||
workers: NUM_WORKERS, //Limit to 2 for CircleCI Agent | ||
use: { | ||
baseURL: 'http://localhost:8080/', | ||
headless: true, | ||
ignoreHTTPSErrors: true, | ||
screenshot: 'only-on-failure', | ||
trace: 'on-first-retry', | ||
video: 'off' | ||
}, | ||
projects: [ | ||
{ | ||
name: 'chrome', | ||
testMatch: '**/*.spec.js', // run all tests | ||
use: { | ||
browserName: 'chromium' | ||
} | ||
} | ||
], | ||
reporter: [ | ||
['list'], | ||
[ | ||
'html', | ||
{ | ||
open: 'never', | ||
outputFolder: '../html-test-results' //Must be in different location due to https://github.com/microsoft/playwright/issues/12840 | ||
} | ||
], | ||
['junit', { outputFile: '../test-results/results.xml' }], | ||
['@deploysentinel/playwright'] | ||
] | ||
}; | ||
|
||
module.exports = config; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,293 @@ | ||
/***************************************************************************** | ||
* Open MCT, Copyright (c) 2014-2023, 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 is dedicated to test styling of various plugins | ||
*/ | ||
|
||
const { test, expect } = require('../../pluginFixtures'); | ||
const { createDomainObjectWithDefaults } = require('../../appActions'); | ||
|
||
test.describe('Flex Layout Style Inspector Options', () => { | ||
let flexibleLayout; | ||
test.beforeEach(async ({ page }) => { | ||
await page.goto('./', { waitUntil: 'domcontentloaded' }); | ||
|
||
// Create a Flexible Layout and attach to the Stacked Plot | ||
flexibleLayout = await createDomainObjectWithDefaults(page, { | ||
type: 'Flexible Layout', | ||
name: 'Flexible Layout' | ||
}); | ||
}); | ||
|
||
test('selecting a flexible layout column hides the styles tab', async ({ page }) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. broke this out to its own suite to improve runtime and improve the opportunity to add new styling specific inspector tests |
||
await page.goto(flexibleLayout.url, { waitUntil: 'domcontentloaded' }); | ||
|
||
// Edit Flexible Layout | ||
await page.getByLabel('Edit').click(); | ||
|
||
// Expect to find styles tab | ||
await expect(page.getByRole('tab', { name: 'Styles' })).toBeVisible(); | ||
|
||
// Select flexible layout column | ||
await page.getByLabel('Container Handle 0').click(); | ||
|
||
// Expect to find no styles tab | ||
await expect(page.getByRole('tab', { name: 'Styles' })).toBeHidden(); | ||
}); | ||
}); | ||
|
||
test.describe('Flexible Layout styling', () => { | ||
let sineWaveObject; | ||
let sineWaveObject2; | ||
let stackedPlot; | ||
let flexibleLayout; | ||
test.beforeEach(async ({ page }) => { | ||
await page.goto('./', { waitUntil: 'domcontentloaded' }); | ||
|
||
// Create a Flexible Layout and attach to the Stacked Plot | ||
flexibleLayout = await createDomainObjectWithDefaults(page, { | ||
type: 'Flexible Layout', | ||
name: 'Flexible Layout' | ||
}); | ||
|
||
// Create a Stacked Plot and attach to the Flexible Layout | ||
stackedPlot = await createDomainObjectWithDefaults(page, { | ||
type: 'Stacked Plot', | ||
name: 'Stacked Plot', | ||
parent: flexibleLayout.uuid | ||
}); | ||
|
||
// Create two SWGs and attach them to the Stacked Plot | ||
sineWaveObject = await createDomainObjectWithDefaults(page, { | ||
type: 'Sine Wave Generator', | ||
name: 'Sine Wave Generator 1', | ||
parent: stackedPlot.uuid | ||
}); | ||
|
||
sineWaveObject2 = await createDomainObjectWithDefaults(page, { | ||
type: 'Sine Wave Generator', | ||
name: 'Sine Wave Generator 2', | ||
parent: stackedPlot.uuid | ||
}); | ||
}); | ||
|
||
test('styling the flexible layout properly applies the styles to all containers', async ({ | ||
page | ||
}) => { | ||
// Values to set styles to | ||
const backgroundColor = '#5b0f00'; | ||
const textColor = '#e6b8af'; | ||
|
||
// Directly navigate to the flexible layout | ||
await page.goto(flexibleLayout.url, { waitUntil: 'domcontentloaded' }); | ||
|
||
// Edit Flexible Layout | ||
await page.getByLabel('Edit').click(); | ||
|
||
// Select styles tab | ||
await page.getByRole('tab', { name: 'Styles' }).click(); | ||
|
||
// Set styles using setStyles function | ||
await setStyles(page, backgroundColor, textColor, page.locator('.c-fl__container-holder')); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we'll need to figure out why the |
||
|
||
// Check styles using checkStyles function | ||
await checkStyles( | ||
page, | ||
hexToRGB(backgroundColor), | ||
hexToRGB(textColor), | ||
page.locator('.c-fl__container-holder') | ||
); | ||
|
||
// Save Flexible Layout | ||
await page.getByRole('button', { name: 'Save' }).click(); | ||
await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); | ||
|
||
// Reload page | ||
await page.reload({ waitUntil: 'domcontentloaded' }); | ||
|
||
// Check styles using checkStyles function | ||
await checkStyles( | ||
page, | ||
hexToRGB(backgroundColor), | ||
hexToRGB(textColor), | ||
page.locator('.c-fl__container-holder') | ||
); | ||
}); | ||
|
||
test('styling a child object of the flexible layout properly applies that style to only that child', async ({ | ||
page | ||
}) => { | ||
const backgroundColor = '#5b0f00'; | ||
const textColor = '#e6b8af'; | ||
// Directly navigate to the flexible layout | ||
await page.goto(flexibleLayout.url, { waitUntil: 'domcontentloaded' }); | ||
|
||
// Edit Flexible Layout | ||
await page.getByLabel('Edit').click(); | ||
|
||
// Select styles tab | ||
await page.getByRole('tab', { name: 'Styles' }).click(); | ||
|
||
// Set styles using setStyles function | ||
await setStyles(page, backgroundColor, textColor, page.getByLabel('Stacked Plot Frame')); | ||
ozyx marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Check styles using checkStyles function | ||
await checkStyles( | ||
page, | ||
hexToRGB(backgroundColor), | ||
hexToRGB(textColor), | ||
page.getByLabel('Stacked Plot Frame') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. but not here. I'm thinking is something fundamentally wrong in the way we are selecting elements for comparison. |
||
); | ||
|
||
// Save Flexible Layout | ||
await page.getByRole('button', { name: 'Save' }).click(); | ||
await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); | ||
|
||
// Reload page | ||
await page.reload({ waitUntil: 'domcontentloaded' }); | ||
|
||
// Check styles using checkStyles function | ||
await checkStyles( | ||
page, | ||
hexToRGB(backgroundColor), | ||
hexToRGB(textColor), | ||
page.getByLabel('Stacked Plot Frame') | ||
); | ||
}); | ||
|
||
test('When the "no style" option is selected, background and text should be reset to inherited styles', async ({ | ||
page | ||
}) => { | ||
// Set background and font color on Stacked Plot object | ||
const backgroundColor = 'rgb(91, 15, 0)'; | ||
const textColor = 'rgb(230, 184, 175)'; | ||
const inheritedBackgroundColor = '#000000'; // inherited from the theme | ||
const inheritedColor = '#aaaaaa'; // inherited from the body style | ||
|
||
// Directly navigate to the flexible layout | ||
await page.goto(flexibleLayout.url, { waitUntil: 'domcontentloaded' }); | ||
|
||
// Edit Flexible Layout | ||
await page.getByLabel('Edit').click(); | ||
|
||
// Select styles tab | ||
await page.getByRole('tab', { name: 'Styles' }).click(); | ||
|
||
// Set styles using setStyles function | ||
await setStyles(page, backgroundColor, textColor, page.getByLabel('Stacked Plot Frame')); | ||
|
||
// Check styles using checkStyles function | ||
await checkStyles( | ||
page, | ||
hexToRGB(backgroundColor), | ||
hexToRGB(textColor), | ||
page.getByLabel('Stacked Plot Frame') | ||
); | ||
|
||
// Save Flexible Layout | ||
await page.getByRole('button', { name: 'Save' }).click(); | ||
await page.getByRole('listitem', { name: 'Save and Finish Editing' }).click(); | ||
|
||
// Reload page and set Styles to 'None' | ||
await page.reload({ waitUntil: 'domcontentloaded' }); | ||
|
||
// Edit Flexible Layout | ||
await page.getByLabel('Edit').click(); | ||
|
||
// Select styles tab | ||
await page.getByRole('tab', { name: 'Styles' }).click(); | ||
|
||
await setStyles(page, 'No Style', 'No Style', page.getByLabel('Stacked Plot Frame')); | ||
|
||
// Check styles using checkStyles function | ||
await checkStyles( | ||
page, | ||
hexToRGB(inheritedBackgroundColor), | ||
hexToRGB(inheritedColor), | ||
page.getByLabel('Stacked Plot Frame') | ||
); | ||
// Save Flexible Layout | ||
await page.locator('button[title="Save"]').click(); | ||
await page.locator('text=Save and Finish Editing').click(); | ||
|
||
// Reload page and verify that styles persist | ||
await page.reload({ waitUntil: 'domcontentloaded' }); | ||
|
||
// Check styles using checkStyles function | ||
await checkStyles( | ||
page, | ||
hexToRGB(inheritedBackgroundColor), | ||
hexToRGB(inheritedColor), | ||
page.getByLabel('Stacked Plot Frame') | ||
); | ||
}); | ||
}); | ||
|
||
/** | ||
* Converts a hex color value to its RGB equivalent. | ||
* | ||
* @param {string} hex - The hex color value. | ||
* @returns {string} The RGB equivalent of the hex color. | ||
*/ | ||
function hexToRGB(hex) { | ||
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); | ||
return result | ||
? `rgb(${parseInt(result[1], 16)}, ${parseInt(result[2], 16)}, ${parseInt(result[3], 16)})` | ||
: null; | ||
} | ||
|
||
/** | ||
* Sets the background and text color of a given element. | ||
* | ||
* @param {object} page - The Playwright page object. | ||
* @param {string} backgroundColorHex - The hex value of the background color to set. | ||
* @param {string} textColorHex - The hex value of the text color to set. | ||
* @param {object} locator - The Playwright locator for the element whose style is to be set. | ||
*/ | ||
async function setStyles(page, backgroundColorHex, textColorHex, locator) { | ||
await locator.click(); // Assuming the locator is clickable and opens the style setting UI | ||
await page.getByLabel('Set background color').click(); | ||
await page.getByLabel(backgroundColorHex).click(); | ||
await page.getByLabel('Set text color').click(); | ||
await page.getByLabel(textColorHex).click(); | ||
} | ||
|
||
/** | ||
* Checks if the styles of an element match the expected values. | ||
* | ||
* @param {object} page - The Playwright page object. | ||
* @param {string} expectedBackgroundColor - The expected background color in RGB format. | ||
* @param {string} expectedTextColor - The expected text color in RGB format. | ||
* @param {object} locator - The Playwright locator for the element whose style is to be checked. | ||
*/ | ||
async function checkStyles(page, expectedBackgroundColor, expectedTextColor, locator) { | ||
const layoutStyles = await locator.evaluate((el) => { | ||
return { | ||
background: window.getComputedStyle(el).getPropertyValue('background-color'), | ||
fontColor: window.getComputedStyle(el).getPropertyValue('color') | ||
}; | ||
}); | ||
|
||
expect(layoutStyles.background).toContain(expectedBackgroundColor); | ||
expect(layoutStyles.fontColor).toContain(expectedTextColor); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -111,7 +111,7 @@ | |
"test:e2e:visual:ci": "percy exec --config ./e2e/.percy.ci.yml --partial -- npx playwright test --config=e2e/playwright-visual-a11y.config.js --project=chrome --grep-invert @unstable", | ||
"test:e2e:visual:full": "percy exec --config ./e2e/.percy.nightly.yml -- npx playwright test --config=e2e/playwright-visual-a11y.config.js --grep-invert @unstable", | ||
"test:e2e:full": "npx playwright test --config=e2e/playwright-ci.config.js --grep-invert @couchdb", | ||
"test:e2e:watch": "npx playwright test --ui --config=e2e/playwright-ci.config.js", | ||
"test:e2e:watch": "npx playwright test --ui --config=e2e/playwright-watch.config.js", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. drive-by: improve the ability to debug multiple tests at once |
||
"test:perf:contract": "npx playwright test --config=e2e/playwright-performance-dev.config.js", | ||
"test:perf:localhost": "npx playwright test --config=e2e/playwright-performance-prod.config.js --project=chrome", | ||
"test:perf:memory": "npx playwright test --config=e2e/playwright-performance-prod.config.js --project=chrome-memory", | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
drive-by to make it easier to work with flex layouts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is so cool