chore: re-enable perf/mem tests on PR + fix broken locator in imagery perf test (#7806)

* test: fix broken locator in imagery perf test

* Prevent this from happening

* make rule explicit

* test: maintain `locator()` pattern for contract tests

* test(couchdb): try some new techniques to stabilize the test

* Revert "test(couchdb): try some new techniques to stabilize the test"

This reverts commit 9aa1ea95a1035238ec2c86bfd84eaab0178cca1b.

* chore: revert to `networkidle` and disable eslint rule

* test: add `@network` annotation for tests with real network requests

---------

Co-authored-by: Hill, John (ARC-TI)[KBR Wyle Services, LLC] <john.c.hill@nasa.gov>
This commit is contained in:
Jesse Mazzella 2024-08-13 14:55:57 -07:00 committed by GitHub
parent 0413e77d8a
commit 21a4335c4e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 45 additions and 28 deletions

View File

@ -8,8 +8,8 @@ executors:
- image: mcr.microsoft.com/playwright:v1.45.2-focal - image: mcr.microsoft.com/playwright:v1.45.2-focal
environment: environment:
NODE_ENV: development # Needed to ensure 'dist' folder created and devDependencies installed NODE_ENV: development # Needed to ensure 'dist' folder created and devDependencies installed
PERCY_POSTINSTALL_BROWSER: 'true' # Needed to store the percy browser in cache deps PERCY_POSTINSTALL_BROWSER: "true" # Needed to store the percy browser in cache deps
PERCY_LOGLEVEL: 'debug' # Enable DEBUG level logging for Percy (Issue: https://github.com/nasa/openmct/issues/5742) PERCY_LOGLEVEL: "debug" # Enable DEBUG level logging for Percy (Issue: https://github.com/nasa/openmct/issues/5742)
PERCY_PARALLEL_TOTAL: 2 PERCY_PARALLEL_TOTAL: 2
ubuntu: ubuntu:
machine: machine:
@ -17,7 +17,7 @@ executors:
docker_layer_caching: true docker_layer_caching: true
commands: commands:
build_and_install: build_and_install:
description: 'All steps used to build and install.' description: "All steps used to build and install."
parameters: parameters:
node-version: node-version:
type: string type: string
@ -27,7 +27,7 @@ commands:
node-version: << parameters.node-version >> node-version: << parameters.node-version >>
- node/install-packages - node/install-packages
generate_and_store_version_and_filesystem_artifacts: generate_and_store_version_and_filesystem_artifacts:
description: 'Track important packages and files' description: "Track important packages and files"
steps: steps:
- run: | - run: |
[[ $EUID -ne 0 ]] && (sudo mkdir -p /tmp/artifacts && sudo chmod 777 /tmp/artifacts) || (mkdir -p /tmp/artifacts && chmod 777 /tmp/artifacts) [[ $EUID -ne 0 ]] && (sudo mkdir -p /tmp/artifacts && sudo chmod 777 /tmp/artifacts) || (mkdir -p /tmp/artifacts && chmod 777 /tmp/artifacts)
@ -38,7 +38,7 @@ commands:
- store_artifacts: - store_artifacts:
path: /tmp/artifacts/ path: /tmp/artifacts/
generate_e2e_code_cov_report: generate_e2e_code_cov_report:
description: 'Generate e2e code coverage artifacts and publish to codecov.io. Needed to that we can ignore the exit code status of the npm run test' description: "Generate e2e code coverage artifacts and publish to codecov.io. Needed to that we can ignore the exit code status of the npm run test"
parameters: parameters:
suite: suite:
type: string type: string
@ -102,7 +102,7 @@ jobs:
node-version: lts/hydrogen node-version: lts/hydrogen
- when: #Only install chrome-beta when running the 'full' suite to save $$$ - when: #Only install chrome-beta when running the 'full' suite to save $$$
condition: condition:
equal: ['full', <<parameters.suite>>] equal: ["full", <<parameters.suite>>]
steps: steps:
- run: npx playwright install chrome-beta - run: npx playwright install chrome-beta
- run: - run:
@ -259,6 +259,8 @@ workflows:
- visual-a11y: - visual-a11y:
name: visual-a11y-ci name: visual-a11y-ci
suite: ci suite: ci
- perf-test
- mem-test
the-nightly: #These jobs do not run on PRs, but against master at night the-nightly: #These jobs do not run on PRs, but against master at night
jobs: jobs:
@ -282,7 +284,7 @@ workflows:
- e2e-couchdb - e2e-couchdb
triggers: triggers:
- schedule: - schedule:
cron: '0 0 * * *' cron: "0 0 * * *"
filters: filters:
branches: branches:
only: only:

View File

@ -20,6 +20,13 @@ module.exports = {
'playwright/no-get-by-title': 'error', 'playwright/no-get-by-title': 'error',
'playwright/prefer-comparison-matcher': 'error' 'playwright/prefer-comparison-matcher': 'error'
} }
},
{
// Disable no-raw-locators for .contract.perf.spec.js files until https://github.com/grafana/xk6-browser/issues/1226
files: ['**/*.contract.perf.spec.js'],
rules: {
'playwright/no-raw-locators': 'off'
}
} }
] ]
}; };

View File

@ -130,7 +130,7 @@ test.describe('Persistence operations @addInit', () => {
}); });
}); });
test.describe('Persistence operations @couchdb', () => { test.describe('Persistence operations @couchdb @network', () => {
test.use({ failOnConsoleError: false }); test.use({ failOnConsoleError: false });
test('Editing object properties should generate a single persistence operation', async ({ test('Editing object properties should generate a single persistence operation', async ({
page page
@ -170,7 +170,7 @@ test.describe('Persistence operations @couchdb', () => {
}) })
.toEqual(1); .toEqual(1);
}); });
test('Can create an object after a conflict error @couchdb @2p', async ({ test('Can create an object after a conflict error @couchdb @network @2p', async ({
page, page,
openmctConfig openmctConfig
}) => { }) => {

View File

@ -429,7 +429,7 @@ test.describe('Display Layout', () => {
await expect(page.getByText('2021-12-30 01:11:00.000Z')).toBeHidden(); await expect(page.getByText('2021-12-30 01:11:00.000Z')).toBeHidden();
}); });
test('When multiple plots are contained in a layout, we only ask for annotations once @couchdb', async ({ test('When multiple plots are contained in a layout, we only ask for annotations once @couchdb @network', async ({
page page
}) => { }) => {
await setFixedTimeMode(page); await setFixedTimeMode(page);

View File

@ -24,20 +24,26 @@
This test suite is dedicated to tests which verify the basic operations surrounding Notebooks with CouchDB. This test suite is dedicated to tests which verify the basic operations surrounding Notebooks with CouchDB.
*/ */
/**
* Disable no-networkidle eslint rule until we can engineer more deterministic network-event
* driven tests.
*/
/* eslint-disable playwright/no-networkidle */
import { createDomainObjectWithDefaults } from '../../../../appActions.js'; import { createDomainObjectWithDefaults } from '../../../../appActions.js';
import * as nbUtils from '../../../../helper/notebookUtils.js'; import * as nbUtils from '../../../../helper/notebookUtils.js';
import { expect, test } from '../../../../pluginFixtures.js'; import { expect, test } from '../../../../pluginFixtures.js';
test.describe('Notebook Tests with CouchDB @couchdb', () => { test.describe('Notebook Tests with CouchDB @couchdb @network', () => {
let testNotebook; let testNotebook;
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
// Navigate to baseURL // Navigate to baseURL
await page.goto('./', { waitUntil: 'domcontentloaded' }); await page.goto('./', { waitUntil: 'networkidle' });
// Create Notebook // Create Notebook
testNotebook = await createDomainObjectWithDefaults(page, { type: 'Notebook' }); testNotebook = await createDomainObjectWithDefaults(page, { type: 'Notebook' });
await page.goto(testNotebook.url, { waitUntil: 'domcontentloaded' }); await page.goto(testNotebook.url, { waitUntil: 'networkidle' });
}); });
test('Inspect Notebook Entry Network Requests', async ({ page }) => { test('Inspect Notebook Entry Network Requests', async ({ page }) => {
@ -58,7 +64,7 @@ test.describe('Notebook Tests with CouchDB @couchdb', () => {
page.getByLabel('Add Page').click() page.getByLabel('Add Page').click()
]); ]);
// Ensures that there are no other network requests // Ensures that there are no other network requests
await page.waitForLoadState('domcontentloaded'); await page.waitForLoadState('networkidle');
// Assert that only two requests are made // Assert that only two requests are made
// Network Requests are: // Network Requests are:
@ -77,7 +83,7 @@ test.describe('Notebook Tests with CouchDB @couchdb', () => {
// 2) The shared worker event from 👆 POST request // 2) The shared worker event from 👆 POST request
notebookElementsRequests = []; notebookElementsRequests = [];
await nbUtils.enterTextEntry(page, 'First Entry'); await nbUtils.enterTextEntry(page, 'First Entry');
await page.waitForLoadState('domcontentloaded'); await page.waitForLoadState('networkidle');
expect(notebookElementsRequests.length).toBeLessThanOrEqual(2); expect(notebookElementsRequests.length).toBeLessThanOrEqual(2);
// Add some tags // Add some tags
@ -141,7 +147,7 @@ test.describe('Notebook Tests with CouchDB @couchdb', () => {
// 4) The shared worker event from 👆 POST request // 4) The shared worker event from 👆 POST request
notebookElementsRequests = []; notebookElementsRequests = [];
await nbUtils.enterTextEntry(page, 'Fourth Entry'); await nbUtils.enterTextEntry(page, 'Fourth Entry');
page.waitForLoadState('domcontentloaded'); page.waitForLoadState('networkidle');
expect(filterNonFetchRequests(notebookElementsRequests).length).toBeLessThanOrEqual(4); expect(filterNonFetchRequests(notebookElementsRequests).length).toBeLessThanOrEqual(4);
@ -153,7 +159,7 @@ test.describe('Notebook Tests with CouchDB @couchdb', () => {
// 4) The shared worker event from 👆 POST request // 4) The shared worker event from 👆 POST request
notebookElementsRequests = []; notebookElementsRequests = [];
await nbUtils.enterTextEntry(page, 'Fifth Entry'); await nbUtils.enterTextEntry(page, 'Fifth Entry');
page.waitForLoadState('domcontentloaded'); page.waitForLoadState('networkidle');
expect(filterNonFetchRequests(notebookElementsRequests).length).toBeLessThanOrEqual(4); expect(filterNonFetchRequests(notebookElementsRequests).length).toBeLessThanOrEqual(4);
@ -164,7 +170,7 @@ test.describe('Notebook Tests with CouchDB @couchdb', () => {
// 4) The shared worker event from 👆 POST request // 4) The shared worker event from 👆 POST request
notebookElementsRequests = []; notebookElementsRequests = [];
await nbUtils.enterTextEntry(page, 'Sixth Entry'); await nbUtils.enterTextEntry(page, 'Sixth Entry');
page.waitForLoadState('domcontentloaded'); page.waitForLoadState('networkidle');
expect(filterNonFetchRequests(notebookElementsRequests).length).toBeLessThanOrEqual(4); expect(filterNonFetchRequests(notebookElementsRequests).length).toBeLessThanOrEqual(4);
}); });
@ -227,7 +233,7 @@ async function addTagAndAwaitNetwork(page, tagName) {
page.locator(`[aria-label="Autocomplete Options"] >> text=${tagName}`).click(), page.locator(`[aria-label="Autocomplete Options"] >> text=${tagName}`).click(),
expect(page.locator(`[aria-label="Tag"]:has-text("${tagName}")`)).toBeVisible() expect(page.locator(`[aria-label="Tag"]:has-text("${tagName}")`)).toBeVisible()
]); ]);
await page.waitForLoadState('domcontentloaded'); await page.waitForLoadState('networkidle');
} }
/** /**
@ -246,5 +252,5 @@ async function removeTagAndAwaitNetwork(page, tagName) {
) )
]); ]);
await expect(page.locator(`[aria-label="Tag"]:has-text("${tagName}")`)).toBeHidden(); await expect(page.locator(`[aria-label="Tag"]:has-text("${tagName}")`)).toBeHidden();
await page.waitForLoadState('domcontentloaded'); await page.waitForLoadState('networkidle');
} }

View File

@ -168,7 +168,7 @@ test.describe('Grand Search', () => {
await expect(page.getByText('No results found')).toBeVisible(); await expect(page.getByText('No results found')).toBeVisible();
}); });
test('Validate single object in search result @couchdb', async ({ page }) => { test('Validate single object in search result @couchdb @network', async ({ page }) => {
// Create a folder object // Create a folder object
const folderName = uuid(); const folderName = uuid();
await createDomainObjectWithDefaults(page, { await createDomainObjectWithDefaults(page, {
@ -191,7 +191,7 @@ test.describe('Grand Search', () => {
await expect(searchResults).toContainText(folderName); await expect(searchResults).toContainText(folderName);
}); });
test('Search results are debounced @couchdb', async ({ page }) => { test('Search results are debounced @couchdb @network', async ({ page }) => {
test.info().annotations.push({ test.info().annotations.push({
type: 'issue', type: 'issue',
description: 'https://github.com/nasa/openmct/issues/6179' description: 'https://github.com/nasa/openmct/issues/6179'
@ -221,7 +221,9 @@ test.describe('Grand Search', () => {
await expect(page.getByRole('list', { name: 'Object Results' })).toContainText('Clock A'); await expect(page.getByRole('list', { name: 'Object Results' })).toContainText('Clock A');
}); });
test('Slowly typing after search debounce will abort requests @couchdb', async ({ page }) => { test('Slowly typing after search debounce will abort requests @couchdb @network', async ({
page
}) => {
let requestWasAborted = false; let requestWasAborted = false;
await createObjectsForSearch(page); await createObjectsForSearch(page);
page.on('requestfailed', (request) => { page.on('requestfailed', (request) => {

View File

@ -28,7 +28,7 @@ test.describe('Main Tree', () => {
await page.goto('./', { waitUntil: 'domcontentloaded' }); await page.goto('./', { waitUntil: 'domcontentloaded' });
}); });
test('Creating a child object within a folder and immediately opening it shows the created object in the tree @couchdb', async ({ test('Creating a child object within a folder and immediately opening it shows the created object in the tree @couchdb @network', async ({
page page
}) => { }) => {
test.info().annotations.push({ test.info().annotations.push({
@ -88,7 +88,7 @@ test.describe('Main Tree', () => {
).toBeVisible(); ).toBeVisible();
}); });
test('Creating a child object on one tab and expanding its parent on the other shows the correct composition @couchdb @2p', async ({ test('Creating a child object on one tab and expanding its parent on the other shows the correct composition @couchdb @network @2p', async ({
page page
}) => { }) => {
test.info().annotations.push({ test.info().annotations.push({
@ -187,7 +187,7 @@ test.describe('Main Tree', () => {
]); ]);
}); });
}); });
test('Opening and closing an item before the request has been fulfilled will abort the request @couchdb', async ({ test('Opening and closing an item before the request has been fulfilled will abort the request @couchdb @network', async ({
page page
}) => { }) => {
let requestWasAborted = false; let requestWasAborted = false;

View File

@ -164,7 +164,7 @@ test.describe('Performance tests', () => {
await page.evaluate(() => window.performance.mark('background-image-visible')); await page.evaluate(() => window.performance.mark('background-image-visible'));
// Get Current number of images in thumbstrip // Get Current number of images in thumbstrip
await page.locator('.c-imagery__thumb').waitFor({ state: 'visible' }); await expect(page.locator('.c-imagery__thumb').last()).toBeInViewport();
const thumbCount = await page.locator('.c-imagery__thumb').count(); const thumbCount = await page.locator('.c-imagery__thumb').count();
console.log('number of thumbs rendered ' + thumbCount); console.log('number of thumbs rendered ' + thumbCount);
await page.locator('.c-imagery__thumb').last().click(); await page.locator('.c-imagery__thumb').last().click();