mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Enterprise Search] Set up basic scaffolding for Cypress tests in Kibana (#108309)
* Set up tsconfigs - Required if we're going to have several different Cypress suites (one for each plugin/product essentially) in order for global cy.() commands and it()/describe() to register as expected @see https://docs.cypress.io/guides/tooling/typescript-support#Clashing-types-with-Jest * Set up shared commands and routes NOTE: Unlike ent-search, shared/ will *not* have its own set of tests - rather, shared/cypress is a resource/set of helpers for other test suites to extend/import/etc. * Create basic Enterprise Search Overview E2E tests - For happy path testing, we _likely_ shouldn't need more than these tests going forward - If we ever want to add an error connecting test however, this is likely where it should go (or alternatively, use Kibana's FTR with Enterprise Search host set but not spun up) * Set up App Search Cypress test scaffolding - placeholder/hello world test only * Set up Workplace Search Cypress test scaffolding - placeholder/hello world test only * Add helper script and update README * Add config setup & documentation for potentially running Cypress against Kibana functional server * PR feedback: Remove unnecessary return true
This commit is contained in:
parent
33f3933118
commit
4d7aa45e14
19 changed files with 402 additions and 0 deletions
|
@ -40,6 +40,22 @@ export const PROJECTS = [
|
|||
createProject('x-pack/plugins/security_solution/cypress/tsconfig.json', {
|
||||
name: 'security_solution/cypress',
|
||||
}),
|
||||
createProject(
|
||||
'x-pack/plugins/enterprise_search/public/applications/shared/cypress/tsconfig.json',
|
||||
{ name: 'enterprise_search/cypress' }
|
||||
),
|
||||
createProject(
|
||||
'x-pack/plugins/enterprise_search/public/applications/enterprise_search/cypress/tsconfig.json',
|
||||
{ name: 'enterprise_search/cypress' }
|
||||
),
|
||||
createProject(
|
||||
'x-pack/plugins/enterprise_search/public/applications/app_search/cypress/tsconfig.json',
|
||||
{ name: 'enterprise_search/cypress' }
|
||||
),
|
||||
createProject(
|
||||
'x-pack/plugins/enterprise_search/public/applications/workplace_search/cypress/tsconfig.json',
|
||||
{ name: 'enterprise_search/cypress' }
|
||||
),
|
||||
createProject('x-pack/plugins/osquery/cypress/tsconfig.json', {
|
||||
name: 'osquery/cypress',
|
||||
}),
|
||||
|
|
|
@ -66,6 +66,89 @@ sh jest.sh public/applications/shared/flash_messages/flash_messages_logic.test.t
|
|||
|
||||
### E2E tests
|
||||
|
||||
We currently have two testing libraries in which we run E2E tests:
|
||||
|
||||
- [Cypress](#cypress-tests)
|
||||
- Will contain the majority of our happy path E2E testing
|
||||
- [Kibana's Functional Test Runner (FTR)](#kibana-ftr-tests)
|
||||
- Contains basic tests that only run when the Enterprise Search host is not configured
|
||||
- It's likely we will not continue to expand these tests, and might even trim some over time (to be replaced by Cypress)
|
||||
|
||||
#### Cypress tests
|
||||
|
||||
Documentation: https://docs.cypress.io/
|
||||
|
||||
Cypress tests can be run directly from the `x-pack/plugins/enterprise_search` folder. You can use our handy cypress.sh script to run specific product test suites:
|
||||
|
||||
```bash
|
||||
# Basic syntax
|
||||
sh cypress.sh {run|open} {suite}
|
||||
|
||||
# Examples
|
||||
sh cypress.sh run overview # run Enterprise Search overview tests
|
||||
sh cypress.sh open overview # open Enterprise Search overview tests
|
||||
|
||||
sh cypress.sh run as # run App Search tests
|
||||
sh cypress.sh open as # open App Search tests
|
||||
|
||||
sh cypress.sh run ws # run Workplace Search tests
|
||||
sh cypress.sh open ws # open Workplace Search tests
|
||||
|
||||
# Overriding env variables
|
||||
sh cypress.sh open as --env username=enterprise_search password=123
|
||||
|
||||
# Overriding config settings, e.g. changing the base URL to a dev path, or enabling video recording
|
||||
sh cypress.sh open as --config baseUrl=http://localhost:5601/xyz video=true
|
||||
|
||||
# Only run a single specific test file
|
||||
sh cypress.sh run ws --spec '**/example.spec.ts'
|
||||
|
||||
# Opt to run Chrome headlessly
|
||||
sh cypress.sh run ws --headless
|
||||
```
|
||||
|
||||
There are 3 ways you can spin up the required environments to run our Cypress tests:
|
||||
|
||||
1. Running Cypress against local dev environments:
|
||||
- Elasticsearch:
|
||||
- Start a local instance, or use Kibana's `yarn es snapshot` command (with all configurations/versions required to run Enterprise Search locally)
|
||||
- NOTE: We generally recommend a fresh instance (or blowing away your `data/` folder) to reduce false negatives due to custom user data
|
||||
- Kibana:
|
||||
- You **must** have `csp.strict: false` and `csp.warnLegacyBrowsers: false` set in your `kibana.dev.yml`.
|
||||
- You should either start Kibana with `yarn start --no-base-path` or pass `--config baseUrl=http://localhost:5601/xyz` into your Cypress command.
|
||||
- Enterprise Search:
|
||||
- Nothing extra is required to run Cypress tests, only what is already needed to run Kibana/Enterprise Search locally.
|
||||
2. Running Cypress against Kibana's functional test server:
|
||||
- :information_source: While we won't use the runner, we can still make use of Kibana's functional test server to help us spin up Elasticsearch and Kibana instances.
|
||||
- NOTE: We recommend stopping any other local dev processes, to reduce issues with memory/performance
|
||||
- From the `x-pack/` project folder, run `node scripts/functional_tests_server --config test/functional_enterprise_search/cypress.config.ts`
|
||||
- Kibana:
|
||||
- You will need to pass `--config baseUrl=http://localhost:5620` into your Cypress command.
|
||||
- Enterprise Search:
|
||||
- :warning: TODO: We _currently_ do not have a way of spinning up Enterprise Search from Kibana's FTR - for now, you can use local Enterprise Search (pointed at the FTR's `http://localhost:9220` Elasticsearch host instance)
|
||||
3. Running Cypress against Enterprise Search dockerized stack scripts
|
||||
- :warning: This is for Enterprise Search devs only, as this requires access to our closed source Enterprise Search repo
|
||||
- `stack_scripts/start-with-es-native-auth.sh --with-kibana`
|
||||
- Note that the tradeoff of an easier one-command start experience is you will not be able to run Cypress tests against any local changes.
|
||||
|
||||
##### Debugging
|
||||
|
||||
Cypress can either run silently in a headless browser in the command line (`run` or `--headless` mode), which is the default mode used by CI, or opened interactively in an included app and the Chrome browser (`open` or `--headed --no-exit` mode).
|
||||
|
||||
For debugging failures locally, we generally recommend using open mode, which allows you to run a single specific test suite, and makes browser dev tools available to you so you can pause and inspect DOM as needed.
|
||||
|
||||
> :warning: Although this is more extra caution than a hard-and-fast rule, we generally recommend taking a break and not clicking or continuing to use the app while tests are running. This can eliminate or lower the possibility of hard-to-reproduce/intermittently flaky behavior and timeouts due to user interference.
|
||||
|
||||
##### Artifacts
|
||||
|
||||
All failed tests will output a screenshot to the `x-pack/plugins/enterprise_search/target/cypress/screenshots` folder. We strongly recommend starting there for debugging failed tests to inspect error messages and UI state at point of failure.
|
||||
|
||||
To track what Cypress is doing while running tests, you can pass in `--config video=true` which will output screencaptures to a `videos/` folder for all tests (both successful and failing). This can potentially provide more context leading up to the failure point, if a static screenshot isn't providing enough information.
|
||||
|
||||
> :information_source: We have videos turned off in our config to reduce test runtime, especially on CI, but suggest re-enabling it for any deep debugging.
|
||||
|
||||
#### Kibana FTR tests
|
||||
|
||||
See [our functional test runner README](../../test/functional_enterprise_search).
|
||||
|
||||
Our automated accessibility tests can be found in [x-pack/test/accessibility/apps](../../test/accessibility/apps/enterprise_search.ts).
|
||||
|
|
18
x-pack/plugins/enterprise_search/cypress.sh
Normal file
18
x-pack/plugins/enterprise_search/cypress.sh
Normal file
|
@ -0,0 +1,18 @@
|
|||
#! /bin/bash
|
||||
|
||||
# Use either `cypress run` or `cypress open` - defaults to run
|
||||
MODE="${1:-run}"
|
||||
|
||||
# Choose which product folder to use, e.g. `yarn cypress open as`
|
||||
PRODUCT="${2}"
|
||||
# Provide helpful shorthands
|
||||
if [ "$PRODUCT" == "as" ]; then PRODUCT='app_search'; fi
|
||||
if [ "$PRODUCT" == "ws" ]; then PRODUCT='workplace_search'; fi
|
||||
if [ "$PRODUCT" == "overview" ]; then PRODUCT='enterprise_search'; fi
|
||||
|
||||
# Pass all remaining arguments (e.g., ...rest) from the 3rd arg onwards
|
||||
# as an open-ended string. Appends onto to the end the Cypress command
|
||||
# @see https://docs.cypress.io/guides/guides/command-line.html#Options
|
||||
ARGS="${*:3}"
|
||||
|
||||
../../../node_modules/.bin/cypress "$MODE" --project "public/applications/$PRODUCT" --browser chrome $ARGS
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"supportFile": "./cypress/support/commands.ts",
|
||||
"pluginsFile": false,
|
||||
"retries": {
|
||||
"runMode": 2
|
||||
},
|
||||
"baseUrl": "http://localhost:5601",
|
||||
"env": {
|
||||
"username": "elastic",
|
||||
"password": "changeme"
|
||||
},
|
||||
"screenshotsFolder": "../../../target/cypress/screenshots",
|
||||
"videosFolder": "../../../target/cypress/videos",
|
||||
"defaultCommandTimeout": 120000,
|
||||
"execTimeout": 120000,
|
||||
"pageLoadTimeout": 180000,
|
||||
"viewportWidth": 1600,
|
||||
"viewportHeight": 1200,
|
||||
"video": false
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { login } from '../support/commands';
|
||||
|
||||
context('Engines', () => {
|
||||
beforeEach(() => {
|
||||
login();
|
||||
});
|
||||
|
||||
it('renders', () => {
|
||||
cy.contains('Engines');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { login as baseLogin } from '../../../shared/cypress/commands';
|
||||
import { appSearchPath } from '../../../shared/cypress/routes';
|
||||
|
||||
interface Login {
|
||||
path?: string;
|
||||
username?: string;
|
||||
password?: string;
|
||||
}
|
||||
export const login = ({ path = '/', ...args }: Login = {}) => {
|
||||
baseLogin({ ...args });
|
||||
cy.visit(`${appSearchPath}${path}`);
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"extends": "../../shared/cypress/tsconfig.json",
|
||||
"references": [{ "path": "../../shared/cypress/tsconfig.json" }],
|
||||
"include": ["./**/*"]
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"supportFile": false,
|
||||
"pluginsFile": false,
|
||||
"retries": {
|
||||
"runMode": 2
|
||||
},
|
||||
"baseUrl": "http://localhost:5601",
|
||||
"env": {
|
||||
"username": "elastic",
|
||||
"password": "changeme"
|
||||
},
|
||||
"fixturesFolder": false,
|
||||
"screenshotsFolder": "../../../target/cypress/screenshots",
|
||||
"videosFolder": "../../../target/cypress/videos",
|
||||
"defaultCommandTimeout": 120000,
|
||||
"execTimeout": 120000,
|
||||
"pageLoadTimeout": 180000,
|
||||
"viewportWidth": 1600,
|
||||
"viewportHeight": 1200,
|
||||
"video": false
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { login } from '../../../shared/cypress/commands';
|
||||
import { overviewPath } from '../../../shared/cypress/routes';
|
||||
|
||||
context('Enterprise Search Overview', () => {
|
||||
beforeEach(() => {
|
||||
login();
|
||||
});
|
||||
|
||||
it('should contain product cards', () => {
|
||||
cy.visit(overviewPath);
|
||||
cy.contains('Welcome to Elastic Enterprise Search');
|
||||
|
||||
cy.get('[data-test-subj="appSearchProductCard"]')
|
||||
.contains('Launch App Search')
|
||||
.should('have.attr', 'href')
|
||||
.and('match', /app_search/);
|
||||
|
||||
cy.get('[data-test-subj="workplaceSearchProductCard"]')
|
||||
.contains('Launch Workplace Search')
|
||||
.should('have.attr', 'href')
|
||||
.and('match', /workplace_search/);
|
||||
});
|
||||
|
||||
it('should have a setup guide', () => {
|
||||
// @see https://github.com/quasarframework/quasar/issues/2233#issuecomment-492975745
|
||||
// This only appears to occur for setup guides - I haven't (yet?) run into it on other pages
|
||||
cy.on('uncaught:exception', (err) => {
|
||||
if (err.message.includes('> ResizeObserver loop limit exceeded')) return false;
|
||||
});
|
||||
|
||||
cy.visit(`${overviewPath}/setup_guide`);
|
||||
cy.contains('Setup Guide');
|
||||
cy.contains('Add your Enterprise Search host URL to your Kibana configuration');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"extends": "../../shared/cypress/tsconfig.json",
|
||||
"references": [{ "path": "../../shared/cypress/tsconfig.json" }],
|
||||
"include": ["./**/*"]
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Shared non-product-specific commands
|
||||
*/
|
||||
|
||||
/*
|
||||
* Log in a user via XHR
|
||||
* @see https://docs.cypress.io/guides/getting-started/testing-your-app#Logging-in
|
||||
*/
|
||||
interface Login {
|
||||
username?: string;
|
||||
password?: string;
|
||||
}
|
||||
export const login = ({
|
||||
username = Cypress.env('username'),
|
||||
password = Cypress.env('password'),
|
||||
}: Login = {}) => {
|
||||
cy.request({
|
||||
method: 'POST',
|
||||
url: '/internal/security/login',
|
||||
headers: { 'kbn-xsrf': 'cypress' },
|
||||
body: {
|
||||
providerType: 'basic',
|
||||
providerName: 'basic',
|
||||
currentURL: '/',
|
||||
params: { username, password },
|
||||
},
|
||||
});
|
||||
};
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
export const overviewPath = '/app/enterprise_search/overview';
|
||||
export const appSearchPath = '/app/enterprise_search/app_search';
|
||||
export const workplaceSearchPath = '/app/enterprise_search/workplace_search';
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": "../../../../../../../tsconfig.base.json",
|
||||
"exclude": [],
|
||||
"include": ["./**/*"],
|
||||
"compilerOptions": {
|
||||
"types": ["cypress", "node"]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"supportFile": "./cypress/support/commands.ts",
|
||||
"pluginsFile": false,
|
||||
"retries": {
|
||||
"runMode": 2
|
||||
},
|
||||
"baseUrl": "http://localhost:5601",
|
||||
"env": {
|
||||
"username": "elastic",
|
||||
"password": "changeme"
|
||||
},
|
||||
"screenshotsFolder": "../../../target/cypress/screenshots",
|
||||
"videosFolder": "../../../target/cypress/videos",
|
||||
"defaultCommandTimeout": 120000,
|
||||
"execTimeout": 120000,
|
||||
"pageLoadTimeout": 180000,
|
||||
"viewportWidth": 1600,
|
||||
"viewportHeight": 1200,
|
||||
"video": false
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { login } from '../support/commands';
|
||||
|
||||
context('Overview', () => {
|
||||
beforeEach(() => {
|
||||
login();
|
||||
});
|
||||
|
||||
it('renders', () => {
|
||||
cy.contains('Workplace Search');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { login as baseLogin } from '../../../shared/cypress/commands';
|
||||
import { workplaceSearchPath } from '../../../shared/cypress/routes';
|
||||
|
||||
interface Login {
|
||||
path?: string;
|
||||
username?: string;
|
||||
password?: string;
|
||||
}
|
||||
export const login = ({ path = '/', ...args }: Login = {}) => {
|
||||
baseLogin({ ...args });
|
||||
cy.visit(`${workplaceSearchPath}${path}`);
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"extends": "../../shared/cypress/tsconfig.json",
|
||||
"references": [{ "path": "../../shared/cypress/tsconfig.json" }],
|
||||
"include": ["./**/*"]
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
"declaration": true,
|
||||
"declarationMap": true
|
||||
},
|
||||
"exclude": ["public/applications/**/cypress/**/*"],
|
||||
"include": [
|
||||
"common/**/*",
|
||||
"public/**/*",
|
||||
|
|
39
x-pack/test/functional_enterprise_search/cypress.config.ts
Normal file
39
x-pack/test/functional_enterprise_search/cypress.config.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { FtrConfigProviderContext } from '@kbn/test';
|
||||
|
||||
// TODO: If Kibana CI doesn't end up using this (e.g., uses Dockerized containers
|
||||
// instead of the functional test server), we can opt to delete this file later.
|
||||
|
||||
export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
||||
const baseConfig = await readConfigFile(require.resolve('./base_config'));
|
||||
|
||||
return {
|
||||
// default to the xpack functional config
|
||||
...baseConfig.getAll(),
|
||||
|
||||
esTestCluster: {
|
||||
...baseConfig.get('esTestCluster'),
|
||||
serverArgs: [
|
||||
...baseConfig.get('esTestCluster.serverArgs'),
|
||||
'xpack.security.enabled=true',
|
||||
'xpack.security.authc.api_key.enabled=true',
|
||||
],
|
||||
},
|
||||
|
||||
kbnTestServer: {
|
||||
...baseConfig.get('kbnTestServer'),
|
||||
serverArgs: [
|
||||
...baseConfig.get('kbnTestServer.serverArgs'),
|
||||
'--csp.strict=false',
|
||||
'--csp.warnLegacyBrowsers=false',
|
||||
'--enterpriseSearch.host=http://localhost:3002',
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue