Skip to content

Commit

Permalink
cypress tests set up with e2e tests for all pages
Browse files Browse the repository at this point in the history
Signed-off-by: Chenyang Ji <cyji@amazon.com>
  • Loading branch information
ansjcy committed Jan 11, 2025
1 parent 3ceb453 commit 362a6e1
Show file tree
Hide file tree
Showing 17 changed files with 5,592 additions and 197 deletions.
11 changes: 10 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ module.exports = {
extends: [
'@elastic/eslint-config-kibana',
'plugin:@elastic/eui/recommended',
"plugin:cypress/recommended",
'plugin:react-hooks/recommended',
'plugin:jest/recommended',
'plugin:prettier/recommended',
Expand All @@ -38,6 +39,7 @@ module.exports = {
],
},
],
'cypress/no-unnecessary-waiting': 'off',
},
overrides: [
{
Expand All @@ -53,6 +55,13 @@ module.exports = {
],
},
},
{
'files': [ '**/*.cy.js' ],
"rules": {
'jest/valid-expect': 'off',
'cypress/unsafe-to-chain-command': 'off',
}
},
],
"ignorePatterns": ["**/*.d.ts"]
'ignorePatterns': ['**/*.d.ts']
};
155 changes: 155 additions & 0 deletions .github/workflows/cypress-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
name: Cypress e2e integration tests workflow
on:
pull_request:
branches:
- "*"
push:
branches:
- "*"
env:
OPENSEARCH_DASHBOARDS_VERSION: 'main'
OPENSEARCH_VERSION: '3.0.0-SNAPSHOT'
QUERY_INSIGHTS_BRANCH: 'main'
GRADLE_VERSION: '7.6.1'
jobs:
tests:
name: Run Cypress E2E tests
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
include:
- os: windows-latest
cypress_cache_folder: ~/AppData/Local/Cypress/Cache
- os: ubuntu-latest
cypress_cache_folder: ~/.cache/Cypress
runs-on: ${{ matrix.os }}
env:
# prevents extra Cypress installation progress messages
CI: 1
# avoid warnings like "tput: No value for $TERM and no -T specified"
TERM: xterm
steps:
- name: Set up JDK
uses: actions/setup-java@v1
with:
java-version: 21

- name: Enable longer filenames
if: ${{ matrix.os == 'windows-latest' }}
run: git config --system core.longpaths true

- name: Checkout Query Insights
uses: actions/checkout@v2
with:
path: query-insights
repository: opensearch-project/query-insights
ref: ${{ env.QUERY_INSIGHTS_BRANCH }}

- name: Set up Gradle
uses: gradle/gradle-build-action@v2
with:
gradle-version: ${{ env.GRADLE_VERSION }}

- name: Run OpenSearch with Query Insights plugin
run: |
cd query-insights
./gradlew run -Dopensearch.version=${{ env.OPENSEARCH_VERSION }} &
sleep 300
shell: bash

- name: Checkout OpenSearch-Dashboards
uses: actions/checkout@v2
with:
repository: opensearch-project/OpenSearch-Dashboards
path: OpenSearch-Dashboards
ref: ${{ env.OPENSEARCH_DASHBOARDS_VERSION }}

- name: Checkout Query Insights Dashboards plugin
uses: actions/checkout@v2
with:
path: OpenSearch-Dashboards/plugins/query-insights-dashboards

- name: Setup Node
uses: actions/setup-node@v3
with:
node-version-file: './OpenSearch-Dashboards/.nvmrc'
registry-url: 'https://registry.npmjs.org'

- name: Install Yarn
# Need to use bash to avoid having a windows/linux specific step
shell: bash
run: |
YARN_VERSION=$(node -p "require('./OpenSearch-Dashboards/package.json').engines.yarn")
echo "Installing yarn@$YARN_VERSION"
npm i -g yarn@$YARN_VERSION
- run: node -v
- run: yarn -v

- name: Bootstrap plugin/OpenSearch-Dashboards
run: |
cd OpenSearch-Dashboards/plugins/query-insights-dashboards
yarn osd bootstrap --single-version=loose
- name: Run OpenSearch-Dashboards server
run: |
cd OpenSearch-Dashboards
yarn start --no-base-path --no-watch --server.host="0.0.0.0" &
shell: bash

# Window is slow so wait longer
- name: Sleep until OSD server starts - windows
if: ${{ matrix.os == 'windows-latest' }}
run: Start-Sleep -s 600
shell: powershell

- name: Sleep until OSD server starts - non-windows
if: ${{ matrix.os != 'windows-latest' }}
run: sleep 450
shell: bash

- name: Install Cypress
run: |
cd OpenSearch-Dashboards/plugins/query-insights-dashboards
# This will install Cypress in case the binary is missing which can happen on Windows and Mac
# If the binary exists, this will exit quickly so it should not be an expensive operation
npx cypress install
shell: bash

- name: Get Cypress version
id: cypress_version
run: |
cd OpenSearch-Dashboards/plugins/query-insights-dashboards
echo "::set-output name=cypress_version::$(cat ./package.json | jq '.dependencies.cypress' | tr -d '"')"
- name: Cache Cypress
id: cache-cypress
uses: actions/cache@v2
with:
path: ${{ matrix.cypress_cache_folder }}
key: cypress-cache-v2-${{ matrix.os }}-${{ hashFiles('OpenSearch-Dashboards/plugins/query-insights-dashboards/package.json') }}

# for now just chrome, use matrix to do all browsers later
- name: Cypress tests
uses: cypress-io/github-action@v5
with:
working-directory: OpenSearch-Dashboards/plugins/query-insights-dashboards
command: yarn run cypress run
wait-on: 'http://localhost:5601'
wait-on-timeout: 300
browser: chrome
env:
CYPRESS_CACHE_FOLDER: ${{ matrix.cypress_cache_folder }}

# Screenshots are only captured on failure, will change this once we do visual regression tests
- uses: actions/upload-artifact@v4
if: failure()
with:
name: cypress-screenshots-${{ matrix.os }}
path: OpenSearch-Dashboards/plugins/query-insights-dashboards/cypress/screenshots

# Test run video was always captured, so this action uses "always()" condition
- uses: actions/upload-artifact@v4
if: always()
with:
name: cypress-videos-${{ matrix.os }}
path: OpenSearch-Dashboards/plugins/query-insights-dashboards/cypress/videos
23 changes: 23 additions & 0 deletions cypress.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const { defineConfig } = require('cypress')

module.exports = defineConfig({
video: false,
screenshotOnRunFailure: false,
defaultCommandTimeout: 60000,
requestTimeout: 600000,
responseTimeout: 600000,
env: {
openSearchUrl: 'http://localhost:9200',
SECURITY_ENABLED: false,
username: 'admin',
password: 'admin',
},
e2e: {
// We've imported your old cypress plugins here.
// You may want to clean this up later by importing these.
setupNodeEvents(on, config) {
return require('./cypress/plugins/index.js')(on, config)
},
baseUrl: 'http://localhost:5601',
},
})
140 changes: 140 additions & 0 deletions cypress/e2e/1_top_queries.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import sampleDocument from '../fixtures/sample_document.json';
import { METRICS } from '../support/constants';

// Name of the test index used in tests
const indexName = 'sample_index';

/**
Helper function to clean up the environment:
- Deletes the test index.
- Disables the top queries features.
*/
const clearAll = () => {
cy.deleteIndexByName(indexName);
cy.disableTopQueries(METRICS.LATENCY);
cy.disableTopQueries(METRICS.CPU);
cy.disableTopQueries(METRICS.MEMORY);
};

describe('Query Insights Dashboard', () => {
// Setup before each test
beforeEach(() => {
clearAll();
cy.createIndexByName(indexName, sampleDocument);
cy.enableTopQueries(METRICS.LATENCY);
cy.enableTopQueries(METRICS.CPU);
cy.enableTopQueries(METRICS.MEMORY);
cy.searchOnIndex(indexName);
// wait for 1s to avoid same timestamp
cy.wait(1000);
cy.searchOnIndex(indexName);
cy.wait(1000);
cy.searchOnIndex(indexName);
// waiting for the query insights queue to drain
cy.wait(10000);
cy.navigateToOverview();
});

/**
* Validate the main overview page loads correctly
*/
it('should display the main overview page', () => {

Check warning on line 46 in cypress/e2e/1_top_queries.cy.js

View workflow job for this annotation

GitHub Actions / Run lint

Test has no assertions
cy.get('.euiBasicTable').should('be.visible');
cy.contains('Query insights - Top N queries');
cy.url().should('include', '/queryInsights');

// should display the query table on the overview page
cy.get('.euiBasicTable').should('be.visible');
cy.get('.euiTableHeaderCell').should('have.length.greaterThan', 0);
// should have top n queries displayed on the table
cy.get('.euiTableRow').should('have.length.greaterThan', 0);
});

/**
* Validate sorting by the "Timestamp" column works correctly
*/
it('should sort the table by the Timestamp column', () => {
// Capture the first row content before sorting
let firstRowBeforeSort;
cy.get('.euiTableRow')
.first()
.invoke('text')
.then((text) => {
firstRowBeforeSort = text.trim();
});
// Click the Timestamp column header to sort
cy.get('.euiTableHeaderCell').contains('Timestamp').click();
// eslint-disable-next-line jest/valid-expect-in-promise
cy.get('.euiTableRow')
.first()
.invoke('text')
.then((firstRowAfterSort) => {
// Assert that the content has changed
expect(firstRowAfterSort.trim()).to.not.equal(firstRowBeforeSort);
});
cy.get('.euiTableHeaderCell').contains('Timestamp').click();
// eslint-disable-next-line jest/valid-expect-in-promise
cy.get('.euiTableRow')
.first()
.invoke('text')
.then((firstRowAfterSecondSort) => {
expect(firstRowAfterSecondSort.trim()).to.not.equal(firstRowBeforeSort);
});
});

/**
* Validate pagination works as expected
*/
it('should paginate the query table', () => {

Check warning on line 93 in cypress/e2e/1_top_queries.cy.js

View workflow job for this annotation

GitHub Actions / Run lint

Test has no assertions
for (let i = 0; i < 20; i++) {
cy.searchOnIndex(indexName);
}
// waiting for the query insights queue to drain
cy.wait(10000);
cy.reload();
cy.get('.euiPagination').should('be.visible');
cy.get('.euiPagination__item').contains('2').click();
// Verify rows on the second page
cy.get('.euiTableRow').should('have.length.greaterThan', 0);
});

it('should switch between tabs', () => {

Check warning on line 106 in cypress/e2e/1_top_queries.cy.js

View workflow job for this annotation

GitHub Actions / Run lint

Test has no assertions
// Click Configuration tab
cy.getElementByText('.euiTab', 'Configuration').click({ force: true });
cy.contains('Query insights - Configuration');
cy.url().should('include', '/configuration');

// Click back to Query Insights tab
cy.getElementByText('.euiTab', 'Top N queries').click({ force: true });
cy.url().should('include', '/queryInsights');
});

it('should filter queries', () => {

Check warning on line 117 in cypress/e2e/1_top_queries.cy.js

View workflow job for this annotation

GitHub Actions / Run lint

Test has no assertions
cy.get('.euiFieldSearch').should('be.visible');
cy.get('.euiFieldSearch').type('sample_index');
// Add assertions for filtered results
cy.get('.euiTableRow').should('have.length.greaterThan', 0);
});

it('should clear the search input and reset results', () => {

Check warning on line 124 in cypress/e2e/1_top_queries.cy.js

View workflow job for this annotation

GitHub Actions / Run lint

Test has no assertions
cy.get('.euiFieldSearch').type('random_string');
cy.get('.euiTableRow').should('have.length.greaterThan', 0);
cy.get('.euiFieldSearch').clear();
cy.get('.euiTableRow').should('have.length.greaterThan', 0); // Validate reset
});

it('should display a message when no top queries are found', () => {

Check warning on line 131 in cypress/e2e/1_top_queries.cy.js

View workflow job for this annotation

GitHub Actions / Run lint

Test has no assertions
clearAll(); // disable top n queries
// waiting for the query insights queue to drain
cy.wait(10000);
cy.reload();
cy.contains('No items found');
});

after(() => clearAll());
});
Loading

0 comments on commit 362a6e1

Please sign in to comment.