Skip to content

Commit 2bfe632

Browse files
unlikelyzeroozyx
andauthored
Fix all of the e2e tests (#5477)
* Fix timer test * be explicit about the warnings text * add full suite to CI to enable CircleCI Checks * add back in devtool=false for CI env so firefox tests run * add framework suite * Don't install webpack HMR in CI * Fix playwright version installs * exclude HMR if running tests in any environment - use NODE_ENV=TEST to exclude webpack HMR - deparameterize some of the playwright configs * use lower-case 'test' * timer hover fix * conditionally skip for firefox due to missing console events * increase timeouts to give time for mutation * no need to close save banner * remove devtool setting * revert * update snapshots * disable video to save some resources * use one worker * more timeouts :) * Remove `browser.close()` and `page.close()` as it was breaking other tests * Remove unnecessary awaits and fix func call syntax * Fix image reset test * fix restrictedNotebook tests * revert playwright-ci.config settings * increase timeout for polling imagery test * remove unnecessary waits * disable notebook lock test for chrome-beta as its unreliable - remove some unnecessary 'wait for save banner' logic - remove unused await - mark imagery test as slow in chrome-beta * LINT!! *shakes fist* * don't run full e2e suite per commit * disable video in all configs * add flakey zoom comment * exclude webpack HMR in non-development modes Co-authored-by: Jesse Mazzella <[email protected]> Co-authored-by: Jesse Mazzella <[email protected]>
1 parent 4ac39a3 commit 2bfe632

21 files changed

+152
-105
lines changed

.github/workflows/e2e-pr.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ jobs:
3030
- uses: actions/setup-node@v3
3131
with:
3232
node-version: '16'
33-
- run: npx [email protected] install
33+
- run: npx [email protected] install
34+
- run: npx playwright install chrome-beta
3435
- run: npm install
3536
- run: npm run test:e2e:full
3637
- name: Archive test results

.github/workflows/e2e-visual.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717
- uses: actions/setup-node@v3
1818
with:
1919
node-version: '16'
20-
- run: npx playwright@1.21.1 install
20+
- run: npx playwright@1.23.0 install
2121
- run: npm install
2222
- name: Run the e2e visual tests
2323
run: npm run test:e2e:visual

app.js

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const express = require('express');
1212
const app = express();
1313
const fs = require('fs');
1414
const request = require('request');
15+
const __DEV__ = process.env.NODE_ENV === 'development';
1516

1617
// Defaults
1718
options.port = options.port || options.p || 8080;
@@ -49,14 +50,18 @@ class WatchRunPlugin {
4950
}
5051

5152
const webpack = require('webpack');
52-
const webpackConfig = process.env.CI ? require('./webpack.coverage.js') : require('./webpack.dev.js');
53-
webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin());
54-
webpackConfig.plugins.push(new WatchRunPlugin());
55-
56-
webpackConfig.entry.openmct = [
57-
'webpack-hot-middleware/client?reload=true',
58-
webpackConfig.entry.openmct
59-
];
53+
let webpackConfig;
54+
if (__DEV__) {
55+
webpackConfig = require('./webpack.dev');
56+
webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin());
57+
webpackConfig.entry.openmct = [
58+
'webpack-hot-middleware/client?reload=true',
59+
webpackConfig.entry.openmct
60+
];
61+
webpackConfig.plugins.push(new WatchRunPlugin());
62+
} else {
63+
webpackConfig = require('./webpack.coverage');
64+
}
6065

6166
const compiler = webpack(webpackConfig);
6267

@@ -68,10 +73,12 @@ app.use(require('webpack-dev-middleware')(
6873
}
6974
));
7075

71-
app.use(require('webpack-hot-middleware')(
72-
compiler,
73-
{}
74-
));
76+
if (__DEV__) {
77+
app.use(require('webpack-hot-middleware')(
78+
compiler,
79+
{}
80+
));
81+
}
7582

7683
// Expose index.html for development users.
7784
app.get('/', function (req, res) {

e2e/playwright-ci.config.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
// eslint-disable-next-line no-unused-vars
66
const { devices } = require('@playwright/test');
7+
const MAX_FAILURES = 5;
8+
const NUM_WORKERS = 2;
79

810
/** @type {import('@playwright/test').PlaywrightTestConfig} */
911
const config = {
@@ -12,20 +14,20 @@ const config = {
1214
testIgnore: '**/*.perf.spec.js', //Ignore performance tests and define in playwright-perfromance.config.js
1315
timeout: 60 * 1000,
1416
webServer: {
15-
command: 'npm run start',
17+
command: 'cross-env NODE_ENV=test npm run start',
1618
url: 'http://localhost:8080/#',
1719
timeout: 200 * 1000,
18-
reuseExistingServer: !process.env.CI
20+
reuseExistingServer: false
1921
},
20-
maxFailures: process.env.CI ? 5 : undefined, //Limits failures to 5 to reduce CI Waste
21-
workers: 2, //Limit to 2 for CircleCI Agent
22+
maxFailures: MAX_FAILURES, //Limits failures to 5 to reduce CI Waste
23+
workers: NUM_WORKERS, //Limit to 2 for CircleCI Agent
2224
use: {
2325
baseURL: 'http://localhost:8080/',
2426
headless: true,
2527
ignoreHTTPSErrors: true,
2628
screenshot: 'only-on-failure',
2729
trace: 'on-first-retry',
28-
video: 'on-first-retry'
30+
video: 'off'
2931
},
3032
projects: [
3133
{

e2e/playwright-local.config.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ const config = {
1212
testIgnore: '**/*.perf.spec.js',
1313
timeout: 30 * 1000,
1414
webServer: {
15-
command: 'npm run start',
15+
command: 'cross-env NODE_ENV=test npm run start',
1616
url: 'http://localhost:8080/#',
1717
timeout: 120 * 1000,
18-
reuseExistingServer: !process.env.CI
18+
reuseExistingServer: true
1919
},
2020
workers: 1,
2121
use: {
@@ -25,7 +25,7 @@ const config = {
2525
ignoreHTTPSErrors: true,
2626
screenshot: 'only-on-failure',
2727
trace: 'retain-on-failure',
28-
video: 'retain-on-failure'
28+
video: 'off'
2929
},
3030
projects: [
3131
{

e2e/playwright-performance.config.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,24 @@
22
// playwright.config.js
33
// @ts-check
44

5+
const CI = process.env.CI === 'true';
6+
57
/** @type {import('@playwright/test').PlaywrightTestConfig} */
68
const config = {
79
retries: 1, //Only for debugging purposes because trace is enabled only on first retry
810
testDir: 'tests/performance/',
911
timeout: 60 * 1000,
1012
workers: 1, //Only run in serial with 1 worker
1113
webServer: {
12-
command: 'npm run start',
14+
command: 'cross-env NODE_ENV=test npm run start',
1315
url: 'http://localhost:8080/#',
1416
timeout: 200 * 1000,
15-
reuseExistingServer: !process.env.CI
17+
reuseExistingServer: !CI
1618
},
1719
use: {
1820
browserName: "chromium",
1921
baseURL: 'http://localhost:8080/',
20-
headless: Boolean(process.env.CI), //Only if running locally
22+
headless: CI, //Only if running locally
2123
ignoreHTTPSErrors: true,
2224
screenshot: 'off',
2325
trace: 'on-first-retry',

e2e/playwright-visual.config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const config = {
99
timeout: 90 * 1000,
1010
workers: 1, // visual tests should never run in parallel due to test pollution
1111
webServer: {
12-
command: 'npm run start',
12+
command: 'cross-env NODE_ENV=test npm run start',
1313
url: 'http://localhost:8080/#',
1414
timeout: 200 * 1000,
1515
reuseExistingServer: !process.env.CI
@@ -21,7 +21,7 @@ const config = {
2121
ignoreHTTPSErrors: true,
2222
screenshot: 'on',
2323
trace: 'off',
24-
video: 'on'
24+
video: 'off'
2525
},
2626
reporter: [
2727
['list'],

e2e/tests/branding.e2e.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ test.describe('Branding tests', () => {
3636
await page.click('.l-shell__app-logo');
3737

3838
// Verify that the NASA Logo Appears
39-
await expect(await page.locator('.c-about__image')).toBeVisible();
39+
await expect(page.locator('.c-about__image')).toBeVisible();
4040

4141
// Modify the Build information in 'about' Modal
4242
const versionInformationLocator = page.locator('ul.t-info.l-info.s-info');

e2e/tests/framework.e2e.spec.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*****************************************************************************
2+
* Open MCT, Copyright (c) 2014-2022, United States Government
3+
* as represented by the Administrator of the National Aeronautics and Space
4+
* Administration. All rights reserved.
5+
*
6+
* Open MCT is licensed under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
* http://www.apache.org/licenses/LICENSE-2.0.
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14+
* License for the specific language governing permissions and limitations
15+
* under the License.
16+
*
17+
* Open MCT includes source code licensed under additional open source
18+
* licenses. See the Open Source Licenses file (LICENSES.md) included with
19+
* this source code distribution or the Licensing information page available
20+
* at runtime from the About dialog for additional information.
21+
*****************************************************************************/
22+
23+
/*
24+
This test suite is dedicated to testing our use of the playwright framework as it
25+
relates to how we've extended it (i.e. ./e2e/fixtures.js) and assumptions made in our dev environment
26+
(app.js and ./e2e/webpack-dev-middleware.js)
27+
*/
28+
29+
const { test } = require('../fixtures.js');
30+
31+
test.describe('fixtures.js tests', () => {
32+
test('Verify that tests fail if console.error is thrown', async ({ page }) => {
33+
test.fail();
34+
//Go to baseURL
35+
await page.goto('/', { waitUntil: 'networkidle' });
36+
37+
//Verify that ../fixtures.js detects console log errors
38+
await Promise.all([
39+
page.evaluate(() => console.error('This should result in a failure')),
40+
page.waitForEvent('console') // always wait for the event to happen while triggering it!
41+
]);
42+
43+
});
44+
test('Verify that tests pass if console.warn is thrown', async ({ page }) => {
45+
//Go to baseURL
46+
await page.goto('/', { waitUntil: 'networkidle' });
47+
48+
//Verify that ../fixtures.js detects console log errors
49+
await Promise.all([
50+
page.evaluate(() => console.warn('This should result in a pass')),
51+
page.waitForEvent('console') // always wait for the event to happen while triggering it!
52+
]);
53+
54+
});
55+
});

e2e/tests/plugins/condition/condition.e2e.spec.js

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,13 @@ test.describe.serial('Condition Set CRUD Operations on @localStorage', () => {
5555
await context.storageState({ path: './e2e/test-data/recycled_local_storage.json' });
5656

5757
//Set object identifier from url
58-
conditionSetUrl = await page.url();
58+
conditionSetUrl = page.url();
5959
console.log('conditionSetUrl ' + conditionSetUrl);
6060

61-
getConditionSetIdentifierFromUrl = await conditionSetUrl.split('/').pop().split('?')[0];
61+
getConditionSetIdentifierFromUrl = conditionSetUrl.split('/').pop().split('?')[0];
6262
console.debug('getConditionSetIdentifierFromUrl ' + getConditionSetIdentifierFromUrl);
63-
await page.close();
64-
});
65-
test.afterAll(async ({ browser }) => {
66-
await browser.close();
6763
});
64+
6865
//Load localStorage for subsequent tests
6966
test.use({ storageState: './e2e/test-data/recycled_local_storage.json' });
7067
//Begin suite of tests again localStorage
@@ -76,7 +73,7 @@ test.describe.serial('Condition Set CRUD Operations on @localStorage', () => {
7673
await expect.soft(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Condition Set');
7774

7875
//Assertions on loaded Condition Set in Inspector
79-
await expect.soft(page.locator('_vue=item.name=Unnamed Condition Set')).toBeTruthy;
76+
expect.soft(page.locator('_vue=item.name=Unnamed Condition Set')).toBeTruthy();
8077

8178
//Reload Page
8279
await Promise.all([
@@ -87,7 +84,7 @@ test.describe.serial('Condition Set CRUD Operations on @localStorage', () => {
8784
//Re-verify after reload
8885
await expect.soft(page.locator('.l-browse-bar__object-name')).toContainText('Unnamed Condition Set');
8986
//Assertions on loaded Condition Set in Inspector
90-
await expect.soft(page.locator('_vue=item.name=Unnamed Condition Set')).toBeTruthy;
87+
expect.soft(page.locator('_vue=item.name=Unnamed Condition Set')).toBeTruthy();
9188

9289
});
9390
test('condition set object can be modified on @localStorage', async ({ page }) => {
@@ -113,18 +110,18 @@ test.describe.serial('Condition Set CRUD Operations on @localStorage', () => {
113110

114111
// Verify Inspector properties
115112
// Verify Inspector has updated Name property
116-
await expect.soft(page.locator('text=Renamed Condition Set').nth(1)).toBeTruthy();
113+
expect.soft(page.locator('text=Renamed Condition Set').nth(1)).toBeTruthy();
117114
// Verify Inspector Details has updated Name property
118-
await expect.soft(page.locator('text=Renamed Condition Set').nth(2)).toBeTruthy();
115+
expect.soft(page.locator('text=Renamed Condition Set').nth(2)).toBeTruthy();
119116

120117
// Verify Tree reflects updated Name proprety
121118
// Expand Tree
122119
await page.locator('text=Open MCT My Items >> span >> nth=3').click();
123120
// Verify Condition Set Object is renamed in Tree
124-
await expect(page.locator('a:has-text("Renamed Condition Set")')).toBeTruthy();
121+
expect(page.locator('a:has-text("Renamed Condition Set")')).toBeTruthy();
125122
// Verify Search Tree reflects renamed Name property
126123
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Renamed');
127-
await expect(page.locator('a:has-text("Renamed Condition Set")')).toBeTruthy();
124+
expect(page.locator('a:has-text("Renamed Condition Set")')).toBeTruthy();
128125

129126
//Reload Page
130127
await Promise.all([
@@ -137,18 +134,18 @@ test.describe.serial('Condition Set CRUD Operations on @localStorage', () => {
137134

138135
// Verify Inspector properties
139136
// Verify Inspector has updated Name property
140-
await expect.soft(page.locator('text=Renamed Condition Set').nth(1)).toBeTruthy();
137+
expect.soft(page.locator('text=Renamed Condition Set').nth(1)).toBeTruthy();
141138
// Verify Inspector Details has updated Name property
142-
await expect.soft(page.locator('text=Renamed Condition Set').nth(2)).toBeTruthy();
139+
expect.soft(page.locator('text=Renamed Condition Set').nth(2)).toBeTruthy();
143140

144141
// Verify Tree reflects updated Name proprety
145142
// Expand Tree
146143
await page.locator('text=Open MCT My Items >> span >> nth=3').click();
147144
// Verify Condition Set Object is renamed in Tree
148-
await expect(page.locator('a:has-text("Renamed Condition Set")')).toBeTruthy();
145+
expect(page.locator('a:has-text("Renamed Condition Set")')).toBeTruthy();
149146
// Verify Search Tree reflects renamed Name property
150147
await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').fill('Renamed');
151-
await expect(page.locator('a:has-text("Renamed Condition Set")')).toBeTruthy();
148+
expect(page.locator('a:has-text("Renamed Condition Set")')).toBeTruthy();
152149
});
153150
test('condition set object can be deleted by Search Tree Actions menu on @localStorage', async ({ page }) => {
154151
//Navigate to baseURL

e2e/tests/plugins/imagery/exampleImagery.e2e.spec.js

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,8 @@ test.describe('Example Imagery Object', () => {
172172

173173
});
174174

175-
test('Can use the reset button to reset the image', async ({ page }) => {
175+
test('Can use the reset button to reset the image', async ({ page }, testInfo) => {
176+
test.slow(testInfo.project === 'chrome-beta', "This test is slow in chrome-beta");
176177
// wait for zoom animation to finish
177178
await page.locator(backgroundImageSelector).hover({trial: true});
178179

@@ -191,16 +192,17 @@ test.describe('Example Imagery Object', () => {
191192
expect.soft(zoomedInBoundingBox.height).toBeGreaterThan(initialBoundingBox.height);
192193
expect.soft(zoomedInBoundingBox.width).toBeGreaterThan(initialBoundingBox.width);
193194

194-
await zoomResetBtn.click();
195195
// wait for zoom animation to finish
196-
await page.locator(backgroundImageSelector).hover({trial: true});
197-
198-
const resetBoundingBox = await page.locator(backgroundImageSelector).boundingBox();
199-
expect.soft(resetBoundingBox.height).toBeLessThan(zoomedInBoundingBox.height);
200-
expect.soft(resetBoundingBox.width).toBeLessThan(zoomedInBoundingBox.width);
196+
// FIXME: The zoom is flakey, sometimes not returning to original dimensions
197+
// https://github.com/nasa/openmct/issues/5491
198+
await expect.poll(async () => {
199+
await zoomResetBtn.click();
200+
const boundingBox = await page.locator(backgroundImageSelector).boundingBox();
201201

202-
expect.soft(resetBoundingBox.height).toEqual(initialBoundingBox.height);
203-
expect(resetBoundingBox.width).toEqual(initialBoundingBox.width);
202+
return boundingBox;
203+
}, {
204+
timeout: 10 * 1000
205+
}).toEqual(initialBoundingBox);
204206
});
205207

206208
test('Using the zoom features does not pause telemetry', async ({ page }) => {

0 commit comments

Comments
 (0)