mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
* APM E2E with own package.json * Ignore cypress folder * Add cypress/apm as separate ts project * Exclude from parent tsconfig * Add p-limit as dep * Fix readme * Fix prettier command * Resolve feedback * Move date range into `loginAndWaitForPage` * Remove redundant file * Fixed lint errors * Remove uneeded `data-cy` attributes * Fix snapshots # Conflicts: # x-pack/legacy/plugins/apm/readme.md
This commit is contained in:
parent
81bc4f3e67
commit
0fa6ed315b
21 changed files with 4988 additions and 13 deletions
|
@ -38,6 +38,7 @@ bower_components
|
|||
/x-pack/legacy/plugins/infra/common/graphql/types.ts
|
||||
/x-pack/legacy/plugins/infra/public/graphql/types.ts
|
||||
/x-pack/legacy/plugins/infra/server/graphql/types.ts
|
||||
/x-pack/legacy/plugins/apm/cypress/**/snapshots.js
|
||||
**/graphql/types.ts
|
||||
**/*.js.snap
|
||||
!/.eslintrc.js
|
||||
|
|
|
@ -125,6 +125,7 @@ export default class ClusterManager {
|
|||
resolve(path, 'scripts'),
|
||||
resolve(path, 'docs'),
|
||||
resolve(path, 'legacy/plugins/siem/cypress'),
|
||||
resolve(path, 'legacy/plugins/apm/cypress'),
|
||||
resolve(path, 'x-pack/legacy/plugins/canvas/canvas_plugin_src') // prevents server from restarting twice for Canvas plugin changes
|
||||
),
|
||||
[]
|
||||
|
|
|
@ -32,6 +32,7 @@ export const PROJECTS = [
|
|||
resolve(REPO_ROOT, 'x-pack/legacy/plugins/siem/cypress/tsconfig.json'),
|
||||
'siem/cypress'
|
||||
),
|
||||
new Project(resolve(REPO_ROOT, 'x-pack/legacy/plugins/apm/cypress/tsconfig.json'), 'apm/cypress'),
|
||||
|
||||
// NOTE: using glob.sync rather than glob-all or globby
|
||||
// because it takes less than 10 ms, while the other modules
|
||||
|
|
63
x-pack/legacy/plugins/apm/cypress/README.md
Normal file
63
x-pack/legacy/plugins/apm/cypress/README.md
Normal file
|
@ -0,0 +1,63 @@
|
|||
### How to run
|
||||
|
||||
_Note: Run the following commands from `kibana/x-pack/legacy/plugins/apm/cypress`._
|
||||
|
||||
#### Interactive mode
|
||||
|
||||
```
|
||||
yarn cypress open
|
||||
```
|
||||
|
||||
#### Headless mode
|
||||
|
||||
```
|
||||
yarn cypress run
|
||||
```
|
||||
|
||||
### Connect to Elasticsearch on Cloud (internal devs only)
|
||||
|
||||
Update kibana.yml with the [cloud credentials](https://p.elstc.co/paste/nRxc9Fuq#0GKJvmrJajnl-PjgBZSnpItKaixWgPb2xn6DCyGD6nw). The cloud instance contains the static data set
|
||||
|
||||
### Kibana
|
||||
|
||||
#### `--no-base-path`
|
||||
|
||||
Kibana must be started with `yarn start --no-base-path`
|
||||
|
||||
#### Content Security Policy (CSP) Settings
|
||||
|
||||
Your local or cloud Kibana server must have the `csp.strict: false` setting
|
||||
configured in `kibana.dev.yml`, or `kibana.yml`, as shown in the example below:
|
||||
|
||||
```yaml
|
||||
csp.strict: false
|
||||
```
|
||||
|
||||
The above setting is required to prevent the _Please upgrade
|
||||
your browser_ / _This Kibana installation has strict security requirements
|
||||
enabled that your current browser does not meet._ warning that's displayed for
|
||||
unsupported user agents, like the one reported by Cypress when running tests.
|
||||
|
||||
### Ingest static data into Elasticsearch via APM Server
|
||||
|
||||
1. Download [static data file](https://storage.googleapis.com/apm-ui-e2e-static-data/events.json)
|
||||
|
||||
2. Post to APM Server
|
||||
|
||||
```
|
||||
node ingest-data/replay.js --server-url http://localhost:8200 --secret-token abcd --events ./events.json
|
||||
```
|
||||
|
||||
### Generate static data
|
||||
|
||||
Capture data from all agents with [apm-integration-testing](https://github.com/elastic/apm-integration-testing):
|
||||
|
||||
```
|
||||
./scripts/compose.py start master --all --apm-server-record
|
||||
```
|
||||
|
||||
To copy the captured data from the container to the host:
|
||||
|
||||
```
|
||||
docker cp localtesting_8.0.0_apm-server-2:/app/events.json .
|
||||
```
|
14
x-pack/legacy/plugins/apm/cypress/cypress.d.ts
vendored
Normal file
14
x-pack/legacy/plugins/apm/cypress/cypress.d.ts
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line spaced-comment
|
||||
/// <reference types="cypress" />
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainable<Subject> {
|
||||
snapshot: () => {};
|
||||
}
|
||||
}
|
14
x-pack/legacy/plugins/apm/cypress/cypress.json
Normal file
14
x-pack/legacy/plugins/apm/cypress/cypress.json
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"baseUrl": "http://localhost:5601",
|
||||
"video": false,
|
||||
|
||||
"trashAssetsBeforeRuns": false,
|
||||
"fileServerFolder": "../",
|
||||
"fixturesFolder": "./fixtures",
|
||||
"integrationFolder": "./integration",
|
||||
"pluginsFile": "./plugins/index.js",
|
||||
"screenshotsFolder": "./screenshots",
|
||||
"supportFile": "./support/index.ts",
|
||||
"videosFolder": "./videos",
|
||||
"useRelativeSnapshots": true
|
||||
}
|
5
x-pack/legacy/plugins/apm/cypress/fixtures/example.json
Normal file
5
x-pack/legacy/plugins/apm/cypress/fixtures/example.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"name": "Using fixtures to represent data",
|
||||
"email": "hello@cypress.io",
|
||||
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||
}
|
93
x-pack/legacy/plugins/apm/cypress/ingest-data/replay.js
Normal file
93
x-pack/legacy/plugins/apm/cypress/ingest-data/replay.js
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
/* eslint-disable no-console */
|
||||
|
||||
/**
|
||||
* This script is useful for ingesting previously generated APM data into Elasticsearch via APM Server
|
||||
*
|
||||
* You can either:
|
||||
* 1. Download a static test data file from: https://storage.googleapis.com/apm-ui-e2e-static-data/events.json
|
||||
* 2. Or, generate the test data file yourself by following the steps in: https://github.com/sqren/kibana/blob/master/x-pack/legacy/plugins/apm/cypress/README.md#how-to-generate-static-data
|
||||
*
|
||||
* Run the script:
|
||||
*
|
||||
* node replay.js --server-url <apm server url> --secret-token <apm server secret token> --events ./events.json
|
||||
*
|
||||
************/
|
||||
|
||||
const { promisify } = require('util');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const axios = require('axios');
|
||||
const readFile = promisify(fs.readFile);
|
||||
const pLimit = require('p-limit');
|
||||
const { argv } = require('yargs');
|
||||
|
||||
const APM_SERVER_URL = argv.serverUrl;
|
||||
const SECRET_TOKEN = argv.secretToken;
|
||||
const EVENTS_PATH = argv.events;
|
||||
|
||||
if (!APM_SERVER_URL) {
|
||||
console.log('`--server-url` is required');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!EVENTS_PATH) {
|
||||
console.log('`--events` is required');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
|
||||
async function insertItem(item) {
|
||||
try {
|
||||
const url = `${APM_SERVER_URL}${item.url}`;
|
||||
console.log(Date.now(), url);
|
||||
|
||||
const headers = {
|
||||
'content-type': 'application/x-ndjson'
|
||||
};
|
||||
|
||||
if (SECRET_TOKEN) {
|
||||
headers.Authorization = `Bearer ${SECRET_TOKEN}`;
|
||||
}
|
||||
|
||||
await axios({
|
||||
method: item.method,
|
||||
url,
|
||||
headers,
|
||||
data: item.body
|
||||
});
|
||||
|
||||
// add delay to avoid flooding the queue
|
||||
return delay(500);
|
||||
} catch (e) {
|
||||
console.log('an error occurred');
|
||||
if (e.response) {
|
||||
console.log(e.response.data);
|
||||
} else {
|
||||
console.log('error', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function init() {
|
||||
const content = await readFile(path.resolve(__dirname, EVENTS_PATH));
|
||||
const items = content
|
||||
.toString()
|
||||
.split('\n')
|
||||
.filter(item => item)
|
||||
.map(item => JSON.parse(item))
|
||||
.filter(item => item.url === '/intake/v2/events');
|
||||
|
||||
const limit = pLimit(20); // number of concurrent requests
|
||||
await Promise.all(items.map(item => limit(() => insertItem(item))));
|
||||
}
|
||||
|
||||
init().catch(e => {
|
||||
console.log('An error occurred:', e);
|
||||
});
|
56
x-pack/legacy/plugins/apm/cypress/integration/apm.spec.ts
Normal file
56
x-pack/legacy/plugins/apm/cypress/integration/apm.spec.ts
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line spaced-comment
|
||||
/// <reference types="cypress" />
|
||||
|
||||
import { loginAndWaitForPage } from './helpers';
|
||||
|
||||
describe('When clicking opbeans-go service', () => {
|
||||
before(() => {
|
||||
// open service overview page
|
||||
loginAndWaitForPage(`/app/apm#/services`);
|
||||
|
||||
// show loading text for services
|
||||
cy.contains('Loading...');
|
||||
|
||||
// click opbeans-go service
|
||||
cy.get(':contains(opbeans-go)')
|
||||
.last()
|
||||
.click({ force: true });
|
||||
});
|
||||
|
||||
it('should redirect to correct path with correct params', () => {
|
||||
cy.url().should('contain', `/app/apm#/services/opbeans-go/transactions`);
|
||||
cy.url().should('contain', `transactionType=request`);
|
||||
});
|
||||
|
||||
describe('transaction duration charts', () => {
|
||||
it('should have correct y-axis ticks', () => {
|
||||
const yAxisTick =
|
||||
'[data-cy=transaction-duration-charts] .rv-xy-plot__axis--vertical .rv-xy-plot__axis__tick__text';
|
||||
|
||||
cy.get(yAxisTick)
|
||||
.eq(2)
|
||||
.invoke('text')
|
||||
.snapshot();
|
||||
|
||||
cy.get(yAxisTick)
|
||||
.eq(1)
|
||||
.invoke('text')
|
||||
.snapshot();
|
||||
|
||||
cy.get(yAxisTick)
|
||||
.eq(0)
|
||||
.invoke('text')
|
||||
.snapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('TPM charts', () => {});
|
||||
|
||||
describe('Transaction group list', () => {});
|
||||
});
|
50
x-pack/legacy/plugins/apm/cypress/integration/helpers.ts
Normal file
50
x-pack/legacy/plugins/apm/cypress/integration/helpers.ts
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
|
||||
import { safeLoad } from 'js-yaml';
|
||||
|
||||
const RANGE_FROM = '2019-09-04T18:00:00.000Z';
|
||||
const RANGE_TO = '2019-09-05T06:00:00.000Z';
|
||||
const BASE_URL = Cypress.config().baseUrl;
|
||||
|
||||
/**
|
||||
* Credentials in the `kibana.dev.yml` config file will be used to authenticate with Kibana
|
||||
*/
|
||||
const KIBANA_DEV_YML_PATH = '../../../../../config/kibana.dev.yml';
|
||||
|
||||
/** The default time in ms to wait for a Cypress command to complete */
|
||||
export const DEFAULT_TIMEOUT = 30 * 1000;
|
||||
|
||||
export function loginAndWaitForPage(url: string) {
|
||||
// read the login details from `kibana.dev.yml`
|
||||
cy.readFile(KIBANA_DEV_YML_PATH).then(kibanaDevYml => {
|
||||
const config = safeLoad(kibanaDevYml);
|
||||
const username = config['elasticsearch.username'];
|
||||
const password = config['elasticsearch.password'];
|
||||
|
||||
const hasCredentials = username && password;
|
||||
|
||||
cy.log(
|
||||
`Authenticating via config credentials from "${KIBANA_DEV_YML_PATH}". username: ${username}, password: ${password}`
|
||||
);
|
||||
|
||||
const options = hasCredentials
|
||||
? {
|
||||
auth: { username, password }
|
||||
}
|
||||
: {};
|
||||
|
||||
const fullUrl = `${BASE_URL}${url}?rangeFrom=${RANGE_FROM}&rangeTo=${RANGE_TO}`;
|
||||
cy.visit(fullUrl, options);
|
||||
});
|
||||
|
||||
cy.viewport('macbook-15');
|
||||
|
||||
// wait for loading spinner to disappear
|
||||
cy.get('.kibanaLoaderWrap', { timeout: DEFAULT_TIMEOUT }).should('not.exist');
|
||||
}
|
12
x-pack/legacy/plugins/apm/cypress/integration/snapshots.js
Normal file
12
x-pack/legacy/plugins/apm/cypress/integration/snapshots.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
module.exports = {
|
||||
"When clicking opbeans-go service": {
|
||||
"transaction duration charts": {
|
||||
"should have correct y-axis ticks": {
|
||||
"1": "3.7 min",
|
||||
"2": "1.8 min",
|
||||
"3": "0.0 min"
|
||||
}
|
||||
}
|
||||
},
|
||||
"__version": "3.4.1"
|
||||
}
|
21
x-pack/legacy/plugins/apm/cypress/package.json
Normal file
21
x-pack/legacy/plugins/apm/cypress/package.json
Normal file
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "apm-cypress",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"cypress:open": "cypress open",
|
||||
"cypress:run": "cypress run"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cypress/snapshot": "^2.1.3",
|
||||
"@cypress/webpack-preprocessor": "^4.1.0",
|
||||
"@types/js-yaml": "^3.12.1",
|
||||
"cypress": "^3.4.1",
|
||||
"js-yaml": "^3.13.1",
|
||||
"p-limit": "^2.2.1",
|
||||
"ts-loader": "^6.1.0",
|
||||
"typescript": "^3.6.3",
|
||||
"webpack": "^4.40.2"
|
||||
}
|
||||
}
|
54
x-pack/legacy/plugins/apm/cypress/plugins/index.js
Normal file
54
x-pack/legacy/plugins/apm/cypress/plugins/index.js
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
// ***********************************************************
|
||||
// This example plugins/index.js can be used to load plugins
|
||||
//
|
||||
// You can change the location of this file or turn off loading
|
||||
// the plugins file with the 'pluginsFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/plugins-guide
|
||||
// ***********************************************************
|
||||
|
||||
// This function is called when a project is opened or re-opened (e.g. due to
|
||||
// the project's config changing)
|
||||
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
const wp = require('@cypress/webpack-preprocessor');
|
||||
const fs = require('fs');
|
||||
|
||||
module.exports = on => {
|
||||
// add typescript support
|
||||
const options = {
|
||||
webpackOptions: {
|
||||
resolve: {
|
||||
extensions: ['.ts', '.tsx', '.js']
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
loader: 'ts-loader',
|
||||
options: { transpileOnly: true }
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
on('file:preprocessor', wp(options));
|
||||
|
||||
// readFileMaybe
|
||||
on('task', {
|
||||
readFileMaybe(filename) {
|
||||
if (fs.existsSync(filename)) {
|
||||
return fs.readFileSync(filename, 'utf8');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
};
|
1
x-pack/legacy/plugins/apm/cypress/screenshots/.gitignore
vendored
Normal file
1
x-pack/legacy/plugins/apm/cypress/screenshots/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
*
|
3
x-pack/legacy/plugins/apm/cypress/snapshots.js
Normal file
3
x-pack/legacy/plugins/apm/cypress/snapshots.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
// auto-generated by @cypress/snapshot
|
||||
{
|
||||
}
|
10
x-pack/legacy/plugins/apm/cypress/support/index.ts
Normal file
10
x-pack/legacy/plugins/apm/cypress/support/index.ts
Normal file
|
@ -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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
// @ts-ignore
|
||||
import { register } from '@cypress/snapshot';
|
||||
|
||||
register();
|
8
x-pack/legacy/plugins/apm/cypress/tsconfig.json
Normal file
8
x-pack/legacy/plugins/apm/cypress/tsconfig.json
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": "../../../../tsconfig.json",
|
||||
"exclude": [],
|
||||
"include": ["./**/*"],
|
||||
"compilerOptions": {
|
||||
"types": ["cypress", "node"]
|
||||
}
|
||||
}
|
4532
x-pack/legacy/plugins/apm/cypress/yarn.lock
Normal file
4532
x-pack/legacy/plugins/apm/cypress/yarn.lock
Normal file
File diff suppressed because it is too large
Load diff
|
@ -156,7 +156,7 @@ export class TransactionCharts extends Component<TransactionChartProps> {
|
|||
return (
|
||||
<>
|
||||
<EuiFlexGrid columns={2} gutterSize="s">
|
||||
<EuiFlexItem>
|
||||
<EuiFlexItem data-cy={`transaction-duration-charts`}>
|
||||
<EuiPanel>
|
||||
<React.Fragment>
|
||||
<EuiFlexGroup justifyContent="spaceBetween">
|
||||
|
|
|
@ -1,32 +1,67 @@
|
|||
# Documentation for APM UI
|
||||
# Documentation for APM UI developers
|
||||
|
||||
### Setup local environment
|
||||
|
||||
#### Kibana
|
||||
|
||||
```
|
||||
git clone git@github.com:elastic/kibana.git
|
||||
cd kibana/
|
||||
yarn kbn bootstrap
|
||||
yarn start
|
||||
```
|
||||
|
||||
#### APM Server, Elasticsearch and data
|
||||
|
||||
To access an elasticsearch instance that has live data you have two options:
|
||||
|
||||
##### A. Connect to Elasticsearch on Cloud (internal devs only)
|
||||
|
||||
Add the following to the kibana config file (config/kibana.dev.yml):
|
||||
https://p.elstc.co/paste/fqorvbJi#Yf6tQ8Bxk4nYMWpoPXr1iZ-QnJ1EbKBEM+H/kdPsmBg
|
||||
|
||||
##### B. Start Elastic Stack and APM data generators
|
||||
|
||||
```
|
||||
git clone git@github.com:elastic/apm-integration-testing.git
|
||||
cd apm-integration-testing/
|
||||
./scripts/compose.py start master --all --no-kibana
|
||||
```
|
||||
|
||||
_Docker Compose is required_
|
||||
|
||||
### Unit testing
|
||||
|
||||
Note: Run the following commands from `kibana/x-pack`.
|
||||
|
||||
### Run tests
|
||||
#### Run unit tests
|
||||
|
||||
```
|
||||
node scripts/jest.js plugins/apm --watch
|
||||
```
|
||||
|
||||
### Update snapshots
|
||||
#### Update snapshots
|
||||
|
||||
```
|
||||
node scripts/jest.js plugins/apm --updateSnapshot
|
||||
```
|
||||
---
|
||||
|
||||
Note: Run the following commands from `kibana/`.
|
||||
### Cypress E2E tests
|
||||
|
||||
### Prettier
|
||||
See the Cypress-specific [readme.md](cypress/README.md)
|
||||
|
||||
### Linting
|
||||
|
||||
_Note: Run the following commands from `kibana/`._
|
||||
|
||||
#### Prettier
|
||||
|
||||
```
|
||||
yarn prettier "./x-pack/legacy/plugins/apm/**/*.{tsx,ts,js}" --write
|
||||
```
|
||||
|
||||
### ESLint
|
||||
#### ESLint
|
||||
|
||||
```
|
||||
yarn eslint ./x-pack/legacy/plugins/apm --fix
|
||||
```
|
||||
|
||||
### Ensure everything from master has been backported to 6.x
|
||||
```
|
||||
git fetch origin && git checkout 6.x && git diff origin/6.x..origin/master ./plugins/apm | git apply
|
||||
```
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
"exclude": [
|
||||
"test/**/*",
|
||||
"legacy/plugins/siem/cypress/**/*",
|
||||
"legacy/plugins/apm/cypress/**/*",
|
||||
"**/typespec_tests.ts"
|
||||
],
|
||||
"compilerOptions": {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue