[Threat Intelligence] Switch to parallel cypress (#158801)

This pull request introduces parallel functionality to the TI Cypress
tests, which was recently implemented in the Security Solution. In
essence, this allows us to run multiple test files simultaneously, each
within its own Kibana/ES environment. The PR is here
https://github.com/elastic/kibana/pull/157387

The changes in the scope of the TI Cypress e2es include:

- Modified `package.json` scripts; `:run` is now being used both locally
and in CI. Note that Firefox is currently not supported.
- Removed all `{testIsolation: false}` flags, as no test should depend
on non-pure state.
- All actions required to set up the test environment (archiver, login)
have been moved to beforeEach blocks to ensure that each test starts
with a fresh state.
- Introduced ESLint configuration to help us keep up with the best
practices when writing tests.

TODO:
- The `timeline.cy.ts` test is flaky and requires refactoring. There are
too many actions being fired against elements that are not visible to
the user (`{force: true}`). I've added some waits to address race
conditions in the UI, but this should be considered a temporary
solution.

---------

Co-authored-by: Patryk Kopyciński <contact@patrykkopycinski.com>
Co-authored-by: PhilippeOberti <philippe.oberti@elastic.co>
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Konrad Szwarc 2023-06-07 15:58:26 +02:00 committed by GitHub
parent 3aa1b34394
commit 627b3547a1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 398 additions and 660 deletions

View file

@ -43,7 +43,6 @@ disabled:
- x-pack/test/security_solution_cypress/config.ts - x-pack/test/security_solution_cypress/config.ts
- x-pack/test/security_solution_cypress/response_ops_cli_config.ts - x-pack/test/security_solution_cypress/response_ops_cli_config.ts
- x-pack/test/security_solution_cypress/upgrade_config.ts - x-pack/test/security_solution_cypress/upgrade_config.ts
- x-pack/test/threat_intelligence_cypress/visual_config.ts
- x-pack/test/threat_intelligence_cypress/cli_config_parallel.ts - x-pack/test/threat_intelligence_cypress/cli_config_parallel.ts
- x-pack/test/threat_intelligence_cypress/config.ts - x-pack/test/threat_intelligence_cypress/config.ts
- x-pack/test/functional_enterprise_search/visual_config.ts - x-pack/test/functional_enterprise_search/visual_config.ts

View file

@ -5,7 +5,7 @@ steps:
queue: n2-4-spot queue: n2-4-spot
depends_on: build depends_on: build
timeout_in_minutes: 120 timeout_in_minutes: 120
parallelism: 4 parallelism: 2
retry: retry:
automatic: automatic:
- exit_status: '-1' - exit_status: '-1'

View file

@ -5,12 +5,12 @@ set -euo pipefail
source .buildkite/scripts/steps/functional/common.sh source .buildkite/scripts/steps/functional/common.sh
export JOB=kibana-threat-intelligence-chrome export JOB=kibana-threat-intelligence-chrome
export CLI_NUMBER=${CLI_NUMBER:-$((BUILDKITE_PARALLEL_JOB+1))} export KIBANA_INSTALL_DIR=${KIBANA_BUILD_LOCATION}
export CLI_COUNT=${CLI_COUNT:-$BUILDKITE_PARALLEL_JOB_COUNT}
Xvfb :99 -screen 0 1600x1200x24 &
export DISPLAY=:99
echo "--- Threat Intelligence tests (Chrome)" echo "--- Threat Intelligence tests (Chrome)"
node scripts/functional_tests \ yarn --cwd x-pack/plugins/threat_intelligence cypress:run
--debug --bail \
--kibana-install-dir "$KIBANA_BUILD_LOCATION" \
--config x-pack/test/threat_intelligence_cypress/cli_config_parallel.ts

View file

@ -0,0 +1,13 @@
{
"plugins": ["cypress"],
"extends": [
"plugin:cypress/recommended"
],
"env": {
"cypress/globals": true
},
"rules": {
"cypress/no-force": "warn",
"import/no-extraneous-dependencies": "off"
}
}

View file

@ -29,7 +29,7 @@ export default defineCypressConfig({
execTimeout: 120000, execTimeout: 120000,
pageLoadTimeout: 120000, pageLoadTimeout: 120000,
retries: { retries: {
runMode: 2, runMode: 1,
}, },
screenshotsFolder: '../../../target/kibana-threat-intelligence/cypress/screenshots', screenshotsFolder: '../../../target/kibana-threat-intelligence/cypress/screenshots',
trashAssetsBeforeRuns: false, trashAssetsBeforeRuns: false,
@ -44,5 +44,7 @@ export default defineCypressConfig({
}, },
e2e: { e2e: {
baseUrl: 'http://localhost:5601', baseUrl: 'http://localhost:5601',
experimentalMemoryManagement: true,
specPattern: './cypress/e2e/**/*.cy.ts',
}, },
}); });

View file

@ -7,20 +7,19 @@
import { import {
closeFlyout, closeFlyout,
navigateToThreatIntelligence,
openFlyout, openFlyout,
openFlyoutTakeAction, openFlyoutTakeAction,
openIndicatorsTableMoreActions, openIndicatorsTableMoreActions,
} from '../tasks/common'; } from '../tasks/common';
import { import {
deleteBlocklistEntry,
fillBlocklistForm, fillBlocklistForm,
openAddToBlockListFlyoutFromTable, openAddToBlockListFlyoutFromTable,
openAddToBlocklistFromFlyout, openAddToBlocklistFromFlyout,
} from '../tasks/blocklist'; } from '../tasks/blocklist';
import { navigateToBlocklist, navigateToThreatIntelligence } from '../tasks/common'; import { navigateToBlocklist } from '../tasks/common';
import { login } from '../tasks/login'; import { login, visit } from '../tasks/login';
import { esArchiverLoad, esArchiverUnload } from '../tasks/es_archiver'; import { esArchiverLoad, esArchiverUnload } from '../tasks/es_archiver';
import { selectRange } from '../tasks/select_range';
import { import {
BLOCK_LIST_VALUE_INPUT, BLOCK_LIST_VALUE_INPUT,
FLYOUT_ADD_TO_BLOCK_LIST_ITEM, FLYOUT_ADD_TO_BLOCK_LIST_ITEM,
@ -31,88 +30,76 @@ import {
const THREAT_INTELLIGENCE = '/app/security/threat_intelligence/indicators'; const THREAT_INTELLIGENCE = '/app/security/threat_intelligence/indicators';
const BLOCK_LIST_NEW_NAME = 'new blocklist entry'; const FIRST_BLOCK_LIST_NEW_NAME = 'first blocklist entry';
const BLOCK_LIST_NEW_DESCRIPTION = 'the best description'; const FIRST_BLOCK_LIST_NEW_DESCRIPTION = 'the first description';
const SECOND_BLOCK_LIST_NEW_NAME = 'second blocklist entry';
const SECOND_BLOCK_LIST_NEW_DESCRIPTION = 'the second description';
describe('Block list with invalid indicators', { testIsolation: false }, () => { describe('Block list with invalid indicators', () => {
before(() => { beforeEach(() => {
esArchiverLoad('threat_intelligence/invalid_indicators_data'); esArchiverLoad('threat_intelligence/invalid_indicators_data');
login(); login();
cy.visit(THREAT_INTELLIGENCE); visit(THREAT_INTELLIGENCE);
selectRange();
}); });
after(() => { afterEach(() => {
esArchiverUnload('threat_intelligence/invalid_indicators_data'); esArchiverUnload('threat_intelligence/invalid_indicators_data');
}); });
it('should disabled the indicators table context menu item if invalid indicator', () => { it('should disabled blocklist in the indicators table context menu item and flyout context menu items', () => {
openIndicatorsTableMoreActions(3); openIndicatorsTableMoreActions(3);
cy.get(INDICATORS_TABLE_ADD_TO_BLOCK_LIST_BUTTON_ICON).should('be.disabled'); cy.get(INDICATORS_TABLE_ADD_TO_BLOCK_LIST_BUTTON_ICON).should('be.disabled');
});
it('should disable the flyout context menu items if invalid indicator', () => {
openFlyout(3); openFlyout(3);
openFlyoutTakeAction(); openFlyoutTakeAction();
cy.get(FLYOUT_ADD_TO_BLOCK_LIST_ITEM).should('be.disabled'); cy.get(FLYOUT_ADD_TO_BLOCK_LIST_ITEM).should('be.disabled');
}); });
}); });
describe('Block list interactions', { testIsolation: false }, () => { describe('Block list interactions', () => {
before(() => { beforeEach(() => {
esArchiverLoad('threat_intelligence/indicators_data'); esArchiverLoad('threat_intelligence/indicators_data');
login(); login();
cy.visit(THREAT_INTELLIGENCE); visit(THREAT_INTELLIGENCE);
selectRange();
}); });
after(() => { afterEach(() => {
esArchiverUnload('threat_intelligence/indicators_data'); esArchiverUnload('threat_intelligence/indicators_data');
}); });
it('should add to block list from the indicators table', () => { it('should add to block list from the indicators table and from flyout', () => {
openIndicatorsTableMoreActions(0);
openAddToBlockListFlyoutFromTable();
fillBlocklistForm(BLOCK_LIST_NEW_NAME, BLOCK_LIST_NEW_DESCRIPTION);
navigateToBlocklist();
cy.get(SAVED_BLOCK_LIST_NAME).should('have.text', BLOCK_LIST_NEW_NAME);
cy.get(SAVED_BLOCK_LIST_DESCRIPTION).should('have.text', BLOCK_LIST_NEW_DESCRIPTION);
deleteBlocklistEntry();
navigateToThreatIntelligence();
});
it('should add to block list from the indicator flyout', () => {
openFlyout(0);
openFlyoutTakeAction();
openAddToBlocklistFromFlyout();
fillBlocklistForm(BLOCK_LIST_NEW_NAME, BLOCK_LIST_NEW_DESCRIPTION);
closeFlyout();
navigateToBlocklist();
cy.get(SAVED_BLOCK_LIST_NAME).should('have.text', BLOCK_LIST_NEW_NAME);
cy.get(SAVED_BLOCK_LIST_DESCRIPTION).should('have.text', BLOCK_LIST_NEW_DESCRIPTION);
deleteBlocklistEntry();
navigateToThreatIntelligence();
});
it('add to blocklist flyout should have the correct IoC id', () => {
// first indicator is a valid indicator for add to blocklist feature // first indicator is a valid indicator for add to blocklist feature
const firstIndicatorId = 'd86e656455f985357df3063dff6637f7f3b95bb27d1769a6b88c7adecaf7763f'; const firstIndicatorId = 'd86e656455f985357df3063dff6637f7f3b95bb27d1769a6b88c7adecaf7763f';
openIndicatorsTableMoreActions(0); openIndicatorsTableMoreActions(0);
openAddToBlockListFlyoutFromTable(); openAddToBlockListFlyoutFromTable();
cy.get(BLOCK_LIST_VALUE_INPUT(firstIndicatorId)).should('exist'); cy.get(BLOCK_LIST_VALUE_INPUT(firstIndicatorId));
closeFlyout(); fillBlocklistForm(FIRST_BLOCK_LIST_NEW_NAME, FIRST_BLOCK_LIST_NEW_DESCRIPTION);
navigateToBlocklist();
cy.get(SAVED_BLOCK_LIST_NAME).eq(0).should('have.text', FIRST_BLOCK_LIST_NEW_NAME);
cy.get(SAVED_BLOCK_LIST_DESCRIPTION)
.eq(0)
.should('have.text', FIRST_BLOCK_LIST_NEW_DESCRIPTION);
navigateToThreatIntelligence();
// second indicator is a valid indicator for add to blocklist feature // second indicator is a valid indicator for add to blocklist feature
const secondIndicatorId = 'd3e2cf87eabf84ef929aaf8dad1431b3387f5a26de8ffb7a0c3c2a13f973c0ab'; const secondIndicatorId = 'd3e2cf87eabf84ef929aaf8dad1431b3387f5a26de8ffb7a0c3c2a13f973c0ab';
openIndicatorsTableMoreActions(1); openFlyout(1);
openAddToBlockListFlyoutFromTable(); openFlyoutTakeAction();
openAddToBlocklistFromFlyout();
cy.get(BLOCK_LIST_VALUE_INPUT(secondIndicatorId)).should('exist'); cy.get(BLOCK_LIST_VALUE_INPUT(secondIndicatorId));
fillBlocklistForm(SECOND_BLOCK_LIST_NEW_NAME, SECOND_BLOCK_LIST_NEW_DESCRIPTION);
closeFlyout();
navigateToBlocklist();
cy.get(SAVED_BLOCK_LIST_NAME).eq(0).should('have.text', SECOND_BLOCK_LIST_NEW_NAME);
cy.get(SAVED_BLOCK_LIST_DESCRIPTION)
.eq(0)
.should('have.text', SECOND_BLOCK_LIST_NEW_DESCRIPTION);
}); });
}); });

View file

@ -6,16 +6,13 @@
*/ */
import { import {
navigateToCases,
navigateToThreatIntelligence, navigateToThreatIntelligence,
openFlyout, openFlyout,
openFlyoutTakeAction, openFlyoutTakeAction,
openIndicatorsTableMoreActions, openIndicatorsTableMoreActions,
} from '../tasks/common'; } from '../tasks/common';
import { import {
createNewCaseFromCases,
createNewCaseFromTI, createNewCaseFromTI,
deleteCase,
navigateToCaseViaToaster, navigateToCaseViaToaster,
openAddToExistingCaseFlyoutFromTable, openAddToExistingCaseFlyoutFromTable,
openAddToExistingCaseFromFlyout, openAddToExistingCaseFromFlyout,
@ -30,34 +27,29 @@ import {
INDICATORS_TABLE_ADD_TO_EXISTING_CASE_BUTTON_ICON, INDICATORS_TABLE_ADD_TO_EXISTING_CASE_BUTTON_ICON,
INDICATORS_TABLE_ADD_TO_NEW_CASE_BUTTON_ICON, INDICATORS_TABLE_ADD_TO_NEW_CASE_BUTTON_ICON,
} from '../screens/cases'; } from '../screens/cases';
import { login } from '../tasks/login'; import { login, visit } from '../tasks/login';
import { esArchiverLoad, esArchiverUnload } from '../tasks/es_archiver'; import { esArchiverLoad, esArchiverUnload } from '../tasks/es_archiver';
import { selectRange } from '../tasks/select_range';
const THREAT_INTELLIGENCE = '/app/security/threat_intelligence/indicators'; const THREAT_INTELLIGENCE = '/app/security/threat_intelligence/indicators';
describe('Cases with invalid indicators', { testIsolation: false }, () => { describe('Cases with invalid indicators', () => {
before(() => { beforeEach(() => {
esArchiverLoad('threat_intelligence/invalid_indicators_data'); esArchiverLoad('threat_intelligence/invalid_indicators_data');
login(); login();
cy.visit(THREAT_INTELLIGENCE); visit(THREAT_INTELLIGENCE);
selectRange();
}); });
after(() => { afterEach(() => {
esArchiverUnload('threat_intelligence/invalid_indicators_data'); esArchiverUnload('threat_intelligence/invalid_indicators_data');
}); });
it('should disable the indicators table context menu items if invalid indicator', () => { it('should disable the indicators table context menu items and flyout context menu items', () => {
const documentsNumber = 22; const documentsNumber = 22;
openIndicatorsTableMoreActions(documentsNumber - 1); openIndicatorsTableMoreActions(documentsNumber - 1);
cy.get(INDICATORS_TABLE_ADD_TO_EXISTING_CASE_BUTTON_ICON).should('be.disabled'); cy.get(INDICATORS_TABLE_ADD_TO_EXISTING_CASE_BUTTON_ICON).should('be.disabled');
cy.get(INDICATORS_TABLE_ADD_TO_NEW_CASE_BUTTON_ICON).should('be.disabled'); cy.get(INDICATORS_TABLE_ADD_TO_NEW_CASE_BUTTON_ICON).should('be.disabled');
});
it('should disable the flyout context menu items if invalid indicator', () => {
const documentsNumber = 22;
openFlyout(documentsNumber - 1); openFlyout(documentsNumber - 1);
openFlyoutTakeAction(); openFlyoutTakeAction();
@ -66,24 +58,36 @@ describe('Cases with invalid indicators', { testIsolation: false }, () => {
}); });
}); });
describe('Cases interactions', { testIsolation: false }, () => { describe('Cases interactions', () => {
before(() => { beforeEach(() => {
esArchiverLoad('threat_intelligence/indicators_data'); esArchiverLoad('threat_intelligence/indicators_data');
login(); login();
cy.visit(THREAT_INTELLIGENCE); visit(THREAT_INTELLIGENCE);
selectRange();
}); });
after(() => { afterEach(() => {
esArchiverUnload('threat_intelligence/indicators_data'); esArchiverUnload('threat_intelligence/indicators_data');
}); });
it('should add to existing case when clicking on the button in the indicators table', () => { it('should add to new case and to existing case from the indicators table and the flyout', () => {
navigateToCases(); cy.log('should add to new case when clicking on the button in the indicators table');
createNewCaseFromCases();
openIndicatorsTableMoreActions(0);
openAddToNewCaseFlyoutFromTable();
createNewCaseFromTI();
navigateToCaseViaToaster();
cy.get(CASE_COMMENT_EXTERNAL_REFERENCE)
.should('exist')
.and('contain.text', 'added an indicator of compromise')
.and('contain.text', 'Indicator name')
.and('contain.text', 'Indicator type')
.and('contain.text', 'Feed name');
navigateToThreatIntelligence();
cy.log('should add to existing case when clicking on the button in the indicators table');
cy.visit(THREAT_INTELLIGENCE);
selectRange();
openIndicatorsTableMoreActions(0); openIndicatorsTableMoreActions(0);
openAddToExistingCaseFlyoutFromTable(); openAddToExistingCaseFlyoutFromTable();
selectExistingCase(); selectExistingCase();
@ -96,51 +100,10 @@ describe('Cases interactions', { testIsolation: false }, () => {
.and('contain.text', 'Indicator type') .and('contain.text', 'Indicator type')
.and('contain.text', 'Feed name'); .and('contain.text', 'Feed name');
deleteCase();
navigateToThreatIntelligence(); navigateToThreatIntelligence();
});
it('should add to new case when clicking on the button in the indicators table', () => { cy.log('should add to new case when clicking on the button in the indicators flyout');
openIndicatorsTableMoreActions(0);
openAddToNewCaseFlyoutFromTable();
createNewCaseFromTI();
navigateToCaseViaToaster();
cy.get(CASE_COMMENT_EXTERNAL_REFERENCE)
.should('exist')
.and('contain.text', 'added an indicator of compromise')
.and('contain.text', 'Indicator name')
.and('contain.text', 'Indicator type')
.and('contain.text', 'Feed name');
deleteCase();
navigateToThreatIntelligence();
});
it('should add to existing case when clicking on the button in the indicators flyout', () => {
navigateToCases();
createNewCaseFromCases();
cy.visit(THREAT_INTELLIGENCE);
selectRange();
openFlyout(0);
openFlyoutTakeAction();
openAddToExistingCaseFromFlyout();
selectExistingCase();
navigateToCaseViaToaster();
cy.get(CASE_COMMENT_EXTERNAL_REFERENCE)
.should('exist')
.and('contain.text', 'added an indicator of compromise')
.and('contain.text', 'Indicator name')
.and('contain.text', 'Indicator type')
.and('contain.text', 'Feed name');
deleteCase();
navigateToThreatIntelligence();
});
it('should add to new case when clicking on the button in the indicators flyout', () => {
openFlyout(0); openFlyout(0);
openFlyoutTakeAction(); openFlyoutTakeAction();
openAddToNewCaseFromFlyout(); openAddToNewCaseFromFlyout();
@ -154,7 +117,21 @@ describe('Cases interactions', { testIsolation: false }, () => {
.and('contain.text', 'Indicator type') .and('contain.text', 'Indicator type')
.and('contain.text', 'Feed name'); .and('contain.text', 'Feed name');
deleteCase();
navigateToThreatIntelligence(); navigateToThreatIntelligence();
cy.log('should add to existing case when clicking on the button in the indicators flyout');
openFlyout(0);
openFlyoutTakeAction();
openAddToExistingCaseFromFlyout();
selectExistingCase();
navigateToCaseViaToaster();
cy.get(CASE_COMMENT_EXTERNAL_REFERENCE)
.should('exist')
.and('contain.text', 'added an indicator of compromise')
.and('contain.text', 'Indicator name')
.and('contain.text', 'Indicator type')
.and('contain.text', 'Feed name');
}); });
}); });

View file

@ -5,7 +5,7 @@
* 2.0. * 2.0.
*/ */
import { login } from '../tasks/login'; import { login, visit } from '../tasks/login';
import { import {
EMPTY_PAGE_BODY, EMPTY_PAGE_BODY,
EMPTY_PAGE_DOCS_LINK, EMPTY_PAGE_DOCS_LINK,
@ -14,19 +14,17 @@ import {
const THREAT_INTEL_PATH = '/app/security/threat_intelligence/'; const THREAT_INTEL_PATH = '/app/security/threat_intelligence/';
describe('Empty Page', { testIsolation: false }, () => { describe('Empty Page', () => {
before(() => { beforeEach(() => {
login(); login();
cy.visit(THREAT_INTEL_PATH); visit(THREAT_INTEL_PATH);
}); });
it('should render the empty page with link to docs and integrations', () => { it('should render the empty page with link to docs and integrations, and navigate to integrations page', () => {
cy.get(EMPTY_PAGE_BODY).should('be.visible'); cy.get(EMPTY_PAGE_BODY).should('be.visible');
cy.get(EMPTY_PAGE_DOCS_LINK).should('be.visible'); cy.get(EMPTY_PAGE_DOCS_LINK).should('be.visible');
cy.get(EMPTY_PAGE_INTEGRATIONS_LINK).should('be.visible'); cy.get(EMPTY_PAGE_INTEGRATIONS_LINK).should('be.visible');
});
it('should navigate to the integrations page', () => {
cy.get(EMPTY_PAGE_INTEGRATIONS_LINK).click(); cy.get(EMPTY_PAGE_INTEGRATIONS_LINK).click();
cy.url().should('include', '/app/integrations/browse/threat_intel'); cy.url().should('include', '/app/integrations/browse/threat_intel');
cy.get('h1').first().should('contain', 'Integrations'); cy.get('h1').first().should('contain', 'Integrations');

View file

@ -41,9 +41,8 @@ import {
TIME_RANGE_PICKER, TIME_RANGE_PICKER,
REFRESH_BUTTON, REFRESH_BUTTON,
} from '../screens/indicators'; } from '../screens/indicators';
import { login } from '../tasks/login'; import { login, visit, waitForPageToBeLoaded } from '../tasks/login';
import { esArchiverLoad, esArchiverUnload } from '../tasks/es_archiver'; import { esArchiverLoad, esArchiverUnload } from '../tasks/es_archiver';
import { selectRange } from '../tasks/select_range';
import { import {
closeFlyout, closeFlyout,
navigateToFlyoutJsonTab, navigateToFlyoutJsonTab,
@ -58,15 +57,11 @@ const URL_WITH_CONTRADICTORY_FILTERS =
'/app/security/threat_intelligence/indicators?indicators=(filterQuery:(language:kuery,query:%27%27),filters:!((%27$state%27:(store:appState),meta:(alias:!n,disabled:!f,index:%27%27,key:threat.indicator.type,negate:!f,params:(query:file),type:phrase),query:(match_phrase:(threat.indicator.type:file))),(%27$state%27:(store:appState),meta:(alias:!n,disabled:!f,index:%27%27,key:threat.indicator.type,negate:!f,params:(query:url),type:phrase),query:(match_phrase:(threat.indicator.type:url)))),timeRange:(from:now/d,to:now/d))'; '/app/security/threat_intelligence/indicators?indicators=(filterQuery:(language:kuery,query:%27%27),filters:!((%27$state%27:(store:appState),meta:(alias:!n,disabled:!f,index:%27%27,key:threat.indicator.type,negate:!f,params:(query:file),type:phrase),query:(match_phrase:(threat.indicator.type:file))),(%27$state%27:(store:appState),meta:(alias:!n,disabled:!f,index:%27%27,key:threat.indicator.type,negate:!f,params:(query:url),type:phrase),query:(match_phrase:(threat.indicator.type:url)))),timeRange:(from:now/d,to:now/d))';
describe('Invalid Indicators', () => { describe('Invalid Indicators', () => {
before(() => {
login();
});
describe('verify the grid loads even with missing fields', () => { describe('verify the grid loads even with missing fields', () => {
before(() => { beforeEach(() => {
esArchiverLoad('threat_intelligence/invalid_indicators_data'); esArchiverLoad('threat_intelligence/invalid_indicators_data');
cy.visit(THREAT_INTELLIGENCE); login();
selectRange(); visit(THREAT_INTELLIGENCE);
}); });
after(() => { after(() => {
@ -114,10 +109,10 @@ describe('Invalid Indicators', () => {
}); });
describe('verify the grid loads even with missing mappings and missing fields', () => { describe('verify the grid loads even with missing mappings and missing fields', () => {
before(() => { beforeEach(() => {
esArchiverLoad('threat_intelligence/missing_mappings_indicators_data'); esArchiverLoad('threat_intelligence/missing_mappings_indicators_data');
cy.visit(THREAT_INTELLIGENCE); login();
selectRange(); visit(THREAT_INTELLIGENCE);
}); });
after(() => { after(() => {
@ -140,7 +135,6 @@ describe('Invalid Indicators', () => {
describe('Indicators', () => { describe('Indicators', () => {
before(() => { before(() => {
esArchiverLoad('threat_intelligence/indicators_data'); esArchiverLoad('threat_intelligence/indicators_data');
login();
}); });
after(() => { after(() => {
@ -148,6 +142,11 @@ describe('Indicators', () => {
}); });
describe('Indicators page loading', () => { describe('Indicators page loading', () => {
beforeEach(() => {
login();
visit(THREAT_INTELLIGENCE);
});
it('verify the fleet plugin integrations endpoint exists', () => { it('verify the fleet plugin integrations endpoint exists', () => {
cy.request({ cy.request({
method: 'GET', method: 'GET',
@ -156,10 +155,10 @@ describe('Indicators', () => {
}); });
}); });
describe('Indicators page basics', { testIsolation: false }, () => { describe('Indicators page basics', () => {
before(() => { beforeEach(() => {
cy.visit(THREAT_INTELLIGENCE); login();
selectRange(); visit(THREAT_INTELLIGENCE);
}); });
it('should render the basic page elements', () => { it('should render the basic page elements', () => {
@ -184,11 +183,8 @@ describe('Indicators', () => {
cy.get(`${FILTERS_GLOBAL_CONTAINER} ${TIME_RANGE_PICKER}`).should('exist'); cy.get(`${FILTERS_GLOBAL_CONTAINER} ${TIME_RANGE_PICKER}`).should('exist');
cy.get(`${FIELD_SELECTOR}`).should('exist'); cy.get(`${FIELD_SELECTOR}`).should('exist');
});
it('should show the indicator flyout on ioc click', () => { cy.log('should show the indicator flyout on ioc click');
// Just to know that the data is loaded. This will be replaced with some better mechanism.
cy.get(TABLE_CONTROLS).should('contain.text', 'Showing 1-25 of');
openFlyout(1); openFlyout(1);
@ -208,13 +204,15 @@ describe('Indicators', () => {
}); });
}); });
describe('Indicator page search', { testIsolation: false }, () => { describe('Indicator page search', () => {
before(() => { beforeEach(() => {
cy.visit(THREAT_INTELLIGENCE); login();
selectRange(); visit(THREAT_INTELLIGENCE);
}); });
it('should narrow the results to url indicators when respective KQL search is executed', () => { it('should handle all search actions', () => {
cy.log('should narrow the results to url indicators when respective KQL search is executed');
enterQuery('threat.indicator.type: "url"{enter}'); enterQuery('threat.indicator.type: "url"{enter}');
// Check if query results are narrowed after search // Check if query results are narrowed after search
@ -226,47 +224,45 @@ describe('Indicators', () => {
cy.get(INDICATOR_TYPE_CELL).should('not.contain.text', 'url'); cy.get(INDICATOR_TYPE_CELL).should('not.contain.text', 'url');
clearQuery(); clearQuery();
});
it('should go to the 2nd page', () => { cy.log('should go to the 2nd page');
navigateToIndicatorsTablePage(1); navigateToIndicatorsTablePage(1);
cy.get(TABLE_CONTROLS).should('contain.text', 'Showing 26-50 of'); cy.get(TABLE_CONTROLS).should('contain.text', 'Showing 26-50 of');
});
it('should go to page 1 when search input is cleared', () => { cy.log('should go to page 1 when search input is cleared');
cy.get(QUERY_INPUT).should('exist').focus().clear().type('{enter}'); cy.get(QUERY_INPUT).should('exist').focus();
cy.get(QUERY_INPUT).clear();
cy.get(QUERY_INPUT).type('{enter}');
cy.get(TABLE_CONTROLS).should('contain.text', 'Showing 1-25 of'); cy.get(TABLE_CONTROLS).should('contain.text', 'Showing 1-25 of');
});
it('should reload the data when refresh button is pressed', () => { cy.log('should reload the data when refresh button is pressed');
cy.intercept(/bsearch/).as('search'); cy.intercept(/bsearch/).as('search');
cy.get(REFRESH_BUTTON).should('exist').click(); cy.get(REFRESH_BUTTON).should('exist').click();
cy.wait('@search'); cy.wait('@search');
});
cy.get(REFRESH_BUTTON).should('exist').click();
cy.wait('@search');
}); });
describe('No items match search criteria', () => { describe('No items match search criteria', () => {
before(() => { beforeEach(() => {
// Contradictory filter set login();
cy.visit(URL_WITH_CONTRADICTORY_FILTERS); cy.visit(URL_WITH_CONTRADICTORY_FILTERS);
selectRange(); waitForPageToBeLoaded();
}); });
it('should not display the table when contradictory filters are set', () => { it('should handle no match search criterie', () => {
cy.log('not display the table when contradictory filters are set');
cy.get(FLYOUT_TABLE).should('not.exist'); cy.get(FLYOUT_TABLE).should('not.exist');
cy.get(EMPTY_STATE).should('exist').and('contain.text', 'No results'); cy.get(EMPTY_STATE).should('exist').and('contain.text', 'No results');
});
});
it('should have the default selected field, then update when user selects', () => { cy.log('have the default selected field, then update when user selects');
const threatFeedName = 'threat.feed.name'; const threatFeedName = 'threat.feed.name';
cy.get(`${FIELD_SELECTOR_INPUT}`).eq(0).should('have.text', threatFeedName); cy.get(`${FIELD_SELECTOR_INPUT}`).eq(0).should('have.text', threatFeedName);
@ -279,14 +275,15 @@ describe('Indicators', () => {
}); });
describe('Field browser', () => { describe('Field browser', () => {
before(() => { beforeEach(() => {
cy.visit(THREAT_INTELLIGENCE); login();
selectRange(); visit(THREAT_INTELLIGENCE);
}); });
describe('when field browser is triggered', () => { describe('when field browser is triggered', () => {
it('should render proper modal window', () => { it('should render proper modal window', () => {
cy.get(FIELD_BROWSER).last().click({ force: true }); cy.get('[data-test-subj="tiIndicatorsTable"]').within(() => {
cy.get(FIELD_BROWSER).last().click();
});
cy.get(FIELD_BROWSER_MODAL).should('be.visible'); cy.get(FIELD_BROWSER_MODAL).should('be.visible');
}); });
@ -294,32 +291,28 @@ describe('Indicators', () => {
}); });
describe('Request inspector', () => { describe('Request inspector', () => {
before(() => { beforeEach(() => {
cy.visit(THREAT_INTELLIGENCE); login();
selectRange(); visit(THREAT_INTELLIGENCE);
}); });
describe('when inspector button is clicked', () => { it('when inspector button is clicked it should render the inspector flyout', () => {
it('should render the inspector flyout', () => { cy.get(INSPECTOR_BUTTON).last().click();
cy.get(INSPECTOR_BUTTON).last().click({ force: true });
cy.get(INSPECTOR_PANEL).contains('Indicators search requests'); cy.get(INSPECTOR_PANEL).contains('Indicators search requests');
}); });
}); });
});
describe('Add integrations', () => { describe('Add integrations', () => {
before(() => { beforeEach(() => {
cy.visit(THREAT_INTELLIGENCE); login();
selectRange(); visit(THREAT_INTELLIGENCE);
}); });
describe('when the global header add integrations button is clicked', () => { it('when the global header add integrations button is clicked it should navigate to the Integrations page with Threat Intelligence category selected', () => {
it('should navigate to the Integrations page with Threat Intelligence category selected', () => {
cy.get(ADD_INTEGRATIONS_BUTTON).click(); cy.get(ADD_INTEGRATIONS_BUTTON).click();
cy.url().should('include', 'threat_intel'); cy.url().should('include', 'threat_intel');
}); });
}); });
}); });
});

View file

@ -8,7 +8,6 @@
import { import {
closeFlyout, closeFlyout,
navigateToFlyoutTableTab, navigateToFlyoutTableTab,
openBarchartPopoverMenu,
openFlyout, openFlyout,
waitForViewToBeUpdated, waitForViewToBeUpdated,
} from '../tasks/common'; } from '../tasks/common';
@ -27,152 +26,163 @@ import {
} from '../tasks/query_bar'; } from '../tasks/query_bar';
import { INDICATOR_TYPE_CELL } from '../screens/indicators'; import { INDICATOR_TYPE_CELL } from '../screens/indicators';
import { KQL_FILTER } from '../screens/query_bar'; import { KQL_FILTER } from '../screens/query_bar';
import { selectRange } from '../tasks/select_range'; import { login, visit } from '../tasks/login';
import { login } from '../tasks/login';
import { esArchiverLoad, esArchiverUnload } from '../tasks/es_archiver'; import { esArchiverLoad, esArchiverUnload } from '../tasks/es_archiver';
const THREAT_INTELLIGENCE = '/app/security/threat_intelligence/indicators'; const THREAT_INTELLIGENCE = '/app/security/threat_intelligence/indicators';
describe('Indicators query bar interaction', { testIsolation: false }, () => { describe('Indicators query bar interaction', () => {
before(() => { beforeEach(() => {
esArchiverLoad('threat_intelligence/indicators_data'); esArchiverLoad('threat_intelligence/indicators_data');
login(); login();
cy.visit(THREAT_INTELLIGENCE); visit(THREAT_INTELLIGENCE);
selectRange();
}); });
after(() => {
afterEach(() => {
esArchiverUnload('threat_intelligence/indicators_data'); esArchiverUnload('threat_intelligence/indicators_data');
}); });
it('should add filter to kql and filter in values when clicking in the barchart legend', () => { it('should add filter to kql', () => {
cy.log('filter in values when clicking in the barchart legend');
waitForViewToBeUpdated(); waitForViewToBeUpdated();
cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0); cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0);
openBarchartPopoverMenu();
filterInFromBarChartLegend(); filterInFromBarChartLegend();
waitForViewToBeUpdated();
cy.get(KQL_FILTER).should('exist'); cy.get(KQL_FILTER).should('exist');
cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0); cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0);
clearKQLBar(); clearKQLBar();
});
it('should add negated filter to kql and filter out values when clicking in the barchart legend', () => {
waitForViewToBeUpdated(); waitForViewToBeUpdated();
cy.log('filter out values when clicking in the barchart legend');
cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0); cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0);
openBarchartPopoverMenu();
filterOutFromBarChartLegend(); filterOutFromBarChartLegend();
waitForViewToBeUpdated();
cy.get(KQL_FILTER).should('exist'); cy.get(KQL_FILTER).should('exist');
cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0); cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0);
clearKQLBar(); clearKQLBar();
});
it('should add filter to kql and filter in and out values when clicking in an indicators table cell', () => {
waitForViewToBeUpdated(); waitForViewToBeUpdated();
cy.log('filter in values when clicking in an indicators table cell');
cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0); cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0);
filterInFromTableCell(); filterInFromTableCell();
waitForViewToBeUpdated();
cy.get(KQL_FILTER).should('exist'); cy.get(KQL_FILTER).should('exist');
cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0); cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0);
clearKQLBar(); clearKQLBar();
}); waitForViewToBeUpdated();
cy.log('filter out and out values when clicking in an indicators table cell');
it('should add negated filter and filter out and out values when clicking in an indicators table cell', () => {
waitForViewToBeUpdated(); waitForViewToBeUpdated();
cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0); cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0);
filterOutFromTableCell(); filterOutFromTableCell();
waitForViewToBeUpdated();
cy.get(KQL_FILTER).should('exist'); cy.get(KQL_FILTER).should('exist');
cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0); cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0);
clearKQLBar(); clearKQLBar();
});
it('should add filter to kql and filter in values when clicking in an indicators flyout overview tab block', () => {
waitForViewToBeUpdated(); waitForViewToBeUpdated();
cy.log('filter in values when clicking in an indicators flyout overview tab block');
cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0); cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0);
openFlyout(0); openFlyout(0);
filterInFromFlyoutBlockItem(); filterInFromFlyoutBlockItem();
closeFlyout(); closeFlyout();
waitForViewToBeUpdated();
cy.get(KQL_FILTER).should('exist'); cy.get(KQL_FILTER).should('exist');
cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0); cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0);
clearKQLBar(); clearKQLBar();
});
it('should add negated filter to kql filter out values when clicking in an indicators flyout overview block', () => {
waitForViewToBeUpdated(); waitForViewToBeUpdated();
cy.log('filter out values when clicking in an indicators flyout overview block');
cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0); cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0);
openFlyout(0); openFlyout(0);
filterOutFromFlyoutBlockItem(); filterOutFromFlyoutBlockItem();
closeFlyout(); closeFlyout();
waitForViewToBeUpdated();
cy.get(KQL_FILTER).should('exist'); cy.get(KQL_FILTER).should('exist');
cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0); cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0);
clearKQLBar(); clearKQLBar();
});
it('should add filter to kql and filter in values when clicking in an indicators flyout overview tab table row', () => {
waitForViewToBeUpdated(); waitForViewToBeUpdated();
cy.log('filter in values when clicking in an indicators flyout overview tab table row');
cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0); cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0);
openFlyout(0); openFlyout(0);
filterInFromFlyoutOverviewTable(); filterInFromFlyoutOverviewTable();
closeFlyout(); closeFlyout();
waitForViewToBeUpdated();
cy.get(KQL_FILTER).should('exist'); cy.get(KQL_FILTER).should('exist');
cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0); cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0);
clearKQLBar(); clearKQLBar();
});
it('should add negated filter to kql filter out values when clicking in an indicators flyout overview tab row', () => {
waitForViewToBeUpdated(); waitForViewToBeUpdated();
cy.log('filter out values when clicking in an indicators flyout overview tab row');
cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0); cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0);
openFlyout(0); openFlyout(0);
filterOutFromFlyoutOverviewTable(); filterOutFromFlyoutOverviewTable();
closeFlyout(); closeFlyout();
waitForViewToBeUpdated();
cy.get(KQL_FILTER).should('exist'); cy.get(KQL_FILTER).should('exist');
cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0); cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0);
clearKQLBar(); clearKQLBar();
});
it('should add filter to kql and filter in values when clicking in an indicators flyout table tab action column', () => {
waitForViewToBeUpdated(); waitForViewToBeUpdated();
cy.log('filter in values when clicking in an indicators flyout table tab action column');
cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0); cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0);
openFlyout(0); openFlyout(0);
navigateToFlyoutTableTab(); navigateToFlyoutTableTab();
filterInFromFlyoutTableTab(); filterInFromFlyoutTableTab();
closeFlyout(); closeFlyout();
waitForViewToBeUpdated();
cy.get(KQL_FILTER).should('exist'); cy.get(KQL_FILTER).should('exist');
cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0); cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0);
clearKQLBar(); clearKQLBar();
});
it('should add negated filter to kql filter out values when clicking in an indicators flyout table tab action column', () => {
waitForViewToBeUpdated(); waitForViewToBeUpdated();
cy.log('filter out values when clicking in an indicators flyout table tab action column');
cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0); cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0);
openFlyout(0); openFlyout(0);
navigateToFlyoutTableTab(); navigateToFlyoutTableTab();
filterOutFromFlyoutTableTab(); filterOutFromFlyoutTableTab();
closeFlyout(); closeFlyout();
waitForViewToBeUpdated();
cy.get(KQL_FILTER).should('exist'); cy.get(KQL_FILTER).should('exist');
cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0); cy.get(INDICATOR_TYPE_CELL).its('length').should('be.gte', 0);

View file

@ -15,87 +15,101 @@ import {
investigateInTimelineFromTable, investigateInTimelineFromTable,
openTimeline, openTimeline,
} from '../tasks/timeline'; } from '../tasks/timeline';
import { closeFlyout, openFlyout, openFlyoutTakeAction } from '../tasks/common';
import { import {
closeFlyout, TIMELINE_AND_OR_BADGE,
openBarchartPopoverMenu, TIMELINE_DATA_PROVIDERS_WRAPPER,
openFlyout, TIMELINE_DRAGGABLE_ITEM,
openFlyoutTakeAction, } from '../screens/timeline';
} from '../tasks/common';
import { TIMELINE_DRAGGABLE_ITEM } from '../screens/timeline';
import { esArchiverLoad, esArchiverUnload } from '../tasks/es_archiver'; import { esArchiverLoad, esArchiverUnload } from '../tasks/es_archiver';
import { login } from '../tasks/login'; import { login, visit } from '../tasks/login';
import { selectRange } from '../tasks/select_range';
const THREAT_INTELLIGENCE = '/app/security/threat_intelligence/indicators'; const THREAT_INTELLIGENCE = '/app/security/threat_intelligence/indicators';
describe('Timeline', { testIsolation: false }, () => { describe('Timeline', () => {
before(() => { beforeEach(() => {
esArchiverLoad('threat_intelligence/indicators_data'); esArchiverLoad('threat_intelligence/indicators_data');
login(); login();
cy.visit(THREAT_INTELLIGENCE); visit(THREAT_INTELLIGENCE);
selectRange();
}); });
after(() => { afterEach(() => {
esArchiverUnload('threat_intelligence/indicators_data'); esArchiverUnload('threat_intelligence/indicators_data');
}); });
it('should add entry in timeline when clicking in the barchart legend', () => { it('should verify add to timeline and investigate in timeline work from various places', () => {
openBarchartPopoverMenu(); cy.log('add to timeline when clicking in the barchart legend');
addToTimelineFromBarchartLegend(); addToTimelineFromBarchartLegend();
openTimeline(); openTimeline();
cy.get(TIMELINE_DATA_PROVIDERS_WRAPPER).within(() => {
cy.get(TIMELINE_DRAGGABLE_ITEM).should('exist'); cy.get(TIMELINE_DRAGGABLE_ITEM).should('exist');
cy.get(TIMELINE_AND_OR_BADGE).should('be.visible').and('have.length', 3);
closeTimeline();
}); });
it('should add entry in timeline when clicking in an indicator table cell', () => {
addToTimelineFromTableCell();
openTimeline();
cy.get(TIMELINE_DRAGGABLE_ITEM).should('exist');
closeTimeline(); closeTimeline();
});
it('should add entry in timeline when clicking in an indicator flyout overview tab table row', () => { cy.log('add to timeline when clicking in an indicator flyout overview tab table row');
openFlyout(0); openFlyout(0);
addToTimelineFromFlyoutOverviewTabTable(); addToTimelineFromFlyoutOverviewTabTable();
closeFlyout(); closeFlyout();
openTimeline(); openTimeline();
cy.get(TIMELINE_DATA_PROVIDERS_WRAPPER).within(() => {
cy.get(TIMELINE_DRAGGABLE_ITEM).should('exist'); cy.get(TIMELINE_DRAGGABLE_ITEM).should('exist');
cy.get(TIMELINE_AND_OR_BADGE).should('be.visible').and('have.length', 5);
closeTimeline();
}); });
it('should add entry in timeline when clicking in an indicator flyout overview block', () => { closeTimeline();
cy.log('add to timeline when clicking in an indicator flyout overview block');
openFlyout(0); openFlyout(0);
addToTimelineFromFlyoutOverviewTabBlock(); addToTimelineFromFlyoutOverviewTabBlock();
closeFlyout(); closeFlyout();
openTimeline(); openTimeline();
cy.get(TIMELINE_DATA_PROVIDERS_WRAPPER).within(() => {
cy.get(TIMELINE_DRAGGABLE_ITEM).should('exist'); cy.get(TIMELINE_DRAGGABLE_ITEM).should('exist');
cy.get(TIMELINE_AND_OR_BADGE).should('be.visible').and('have.length', 7);
closeTimeline();
}); });
it('should investigate in timeline when clicking in an indicator table action row', () => { closeTimeline();
cy.log('add to timeline when clicking in an indicator table cell');
addToTimelineFromTableCell();
openTimeline();
cy.get(TIMELINE_DATA_PROVIDERS_WRAPPER).within(() => {
cy.get(TIMELINE_DRAGGABLE_ITEM).should('exist');
cy.get(TIMELINE_AND_OR_BADGE).should('be.visible').and('have.length', 9);
});
closeTimeline();
cy.log('investigate in timeline when clicking in an indicator table action row');
investigateInTimelineFromTable(); investigateInTimelineFromTable();
cy.get(TIMELINE_DATA_PROVIDERS_WRAPPER).within(() => {
cy.get(TIMELINE_DRAGGABLE_ITEM).should('exist'); cy.get(TIMELINE_DRAGGABLE_ITEM).should('exist');
cy.get(TIMELINE_AND_OR_BADGE).should('be.visible').and('have.length', 5);
closeTimeline();
}); });
it('should investigate in timeline when clicking in an indicator flyout', () => { closeTimeline();
cy.log('investigate in timeline when clicking in an indicator flyout');
openFlyout(0); openFlyout(0);
openFlyoutTakeAction(); openFlyoutTakeAction();
investigateInTimelineFromFlyout(); investigateInTimelineFromFlyout();
cy.get(TIMELINE_DATA_PROVIDERS_WRAPPER).within(() => {
cy.get(TIMELINE_DRAGGABLE_ITEM).should('exist'); cy.get(TIMELINE_DRAGGABLE_ITEM).should('exist');
cy.get(TIMELINE_AND_OR_BADGE).should('be.visible').and('have.length', 5);
closeTimeline(); });
}); });
}); });

View file

@ -18,6 +18,3 @@ export const BLOCK_LIST_VALUE_INPUT = (iocId: string) =>
`[data-test-subj="blocklist-form-values-input-${iocId}"]`; `[data-test-subj="blocklist-form-values-input-${iocId}"]`;
export const SAVED_BLOCK_LIST_NAME = `[data-test-subj="blocklistPage-card-header-title"]`; export const SAVED_BLOCK_LIST_NAME = `[data-test-subj="blocklistPage-card-header-title"]`;
export const SAVED_BLOCK_LIST_DESCRIPTION = `[data-test-subj="blocklistPage-card-description"]`; export const SAVED_BLOCK_LIST_DESCRIPTION = `[data-test-subj="blocklistPage-card-description"]`;
export const SAVED_BLOCK_LIST_ACTION_MENU = `[data-test-subj="blocklistPage-card-header-actions-button"]`;
export const SAVED_BLOCK_LIST_DELETE_BUTTON = `[data-test-subj="blocklistPage-card-cardDeleteAction"]`;
export const SAVED_BLOCK_LIST_CONFIRM_DELETE_BUTTON = `[data-test-subj="blocklistPage-deleteModal-submitButton"]`;

View file

@ -18,14 +18,9 @@ export const INDICATORS_TABLE_ADD_TO_NEW_CASE_BUTTON_ICON = `[data-test-subj="${
export const INDICATORS_TABLE_ADD_TO_EXISTING_CASE_BUTTON_ICON = `[data-test-subj="${INDICATORS_TABLE_ADD_TO_EXISTING_TEST_ID}"]`; export const INDICATORS_TABLE_ADD_TO_EXISTING_CASE_BUTTON_ICON = `[data-test-subj="${INDICATORS_TABLE_ADD_TO_EXISTING_TEST_ID}"]`;
export const FLYOUT_ADD_TO_EXISTING_CASE_ITEM = `[data-test-subj="${INDICATOR_FLYOUT_TAKE_ACTION_ADD_TO_EXISTING_CASE_TEST_ID}"]`; export const FLYOUT_ADD_TO_EXISTING_CASE_ITEM = `[data-test-subj="${INDICATOR_FLYOUT_TAKE_ACTION_ADD_TO_EXISTING_CASE_TEST_ID}"]`;
export const FLYOUT_ADD_TO_NEW_CASE_ITEM = `[data-test-subj="${INDICATOR_FLYOUT_TAKE_ACTION_ADD_TO_NEW_CASE_TEST_ID}"]`; export const FLYOUT_ADD_TO_NEW_CASE_ITEM = `[data-test-subj="${INDICATOR_FLYOUT_TAKE_ACTION_ADD_TO_NEW_CASE_TEST_ID}"]`;
export const CREATE_CASE_BUTTON = `[data-test-subj="createNewCaseBtn"]`;
export const SELECT_EXISTING_CASE = `[class="eui-textTruncate"]`; export const SELECT_EXISTING_CASE = `[class="eui-textTruncate"]`;
export const VIEW_CASE_TOASTER_LINK = `[data-test-subj="toaster-content-case-view-link"]`; export const VIEW_CASE_TOASTER_LINK = `[data-test-subj="toaster-content-case-view-link"]`;
export const CASE_COMMENT_EXTERNAL_REFERENCE = `[data-test-subj="comment-externalReference-indicator"]`; export const CASE_COMMENT_EXTERNAL_REFERENCE = `[data-test-subj="comment-externalReference-indicator"]`;
export const CASE_ACTION_WRAPPER = `[data-test-subj="case-action-bar-wrapper"]`;
export const CASE_ELLIPSE_BUTTON = `[data-test-subj="property-actions-case-ellipses"]`;
export const CASE_ELLIPSE_DELETE_CASE_OPTION = `[data-test-subj="property-actions-case-trash"]`;
export const CASE_ELLIPSE_DELETE_CASE_CONFIRMATION_BUTTON = `[data-test-subj="confirmModalConfirmButton"]`;
export const NEW_CASE_NAME_INPUT = `[data-test-subj="input"][aria-describedby="caseTitle"]`; export const NEW_CASE_NAME_INPUT = `[data-test-subj="input"][aria-describedby="caseTitle"]`;
export const NEW_CASE_DESCRIPTION_INPUT = `[data-test-subj="euiMarkdownEditorTextArea"]`; export const NEW_CASE_DESCRIPTION_INPUT = `[data-test-subj="euiMarkdownEditorTextArea"]`;
export const NEW_CASE_CREATE_BUTTON = `[data-test-subj="create-case-submit"]`; export const NEW_CASE_CREATE_BUTTON = `[data-test-subj="create-case-submit"]`;

View file

@ -8,5 +8,4 @@
export const UPDATE_STATUS = `[data-test-subj="updateStatus"]`; export const UPDATE_STATUS = `[data-test-subj="updateStatus"]`;
export const SECURITY_SOLUTION_NAVBAR_MANAGE_ITEM = `[data-test-subj="solutionSideNavItemLink-administration"]`; export const SECURITY_SOLUTION_NAVBAR_MANAGE_ITEM = `[data-test-subj="solutionSideNavItemLink-administration"]`;
export const SECURITY_SOLUTION_NAVBAR_THREAT_INTELLIGENCE_ITEM = `[data-test-subj="solutionSideNavItemLink-threat_intelligence-indicators"]`; export const SECURITY_SOLUTION_NAVBAR_THREAT_INTELLIGENCE_ITEM = `[data-test-subj="solutionSideNavItemLink-threat_intelligence-indicators"]`;
export const SECURITY_SOLUTION_NAVBAR_CASES_ITEM = `[data-test-subj="solutionSideNavItemLink-cases"]`;
export const MANAGE_NAVIGATION_ITEMS = `.euiLink`; export const MANAGE_NAVIGATION_ITEMS = `.euiLink`;

View file

@ -105,3 +105,4 @@ export const INSPECTOR_BUTTON = `[data-test-subj="${INSPECT_BUTTON_TEST_ID}"]`;
export const INSPECTOR_PANEL = `[data-test-subj="inspectorPanel"]`; export const INSPECTOR_PANEL = `[data-test-subj="inspectorPanel"]`;
export const ADD_INTEGRATIONS_BUTTON = `[data-test-subj="add-data"]`; export const ADD_INTEGRATIONS_BUTTON = `[data-test-subj="add-data"]`;
export const REFRESH_BUTTON = `[data-test-subj="querySubmitButton"]`; export const REFRESH_BUTTON = `[data-test-subj="querySubmitButton"]`;
export const ADDED_TO_TIMELINE_TOAST = `[data-test-subj="add-to-timeline-toast-success"]`;

View file

@ -6,7 +6,6 @@
*/ */
import { import {
FLYOUT_TABLE_TEST_ID,
INDICATORS_FLYOUT_OVERVIEW_HIGH_LEVEL_BLOCKS, INDICATORS_FLYOUT_OVERVIEW_HIGH_LEVEL_BLOCKS,
INDICATORS_FLYOUT_OVERVIEW_TABLE, INDICATORS_FLYOUT_OVERVIEW_TABLE,
INVESTIGATE_IN_TIMELINE_TEST_ID as INDICATOR_FLYOUT_TAKE_ACTION_INVESTIGATE_IN_TIMELINE_TEST_ID, INVESTIGATE_IN_TIMELINE_TEST_ID as INDICATOR_FLYOUT_TAKE_ACTION_INVESTIGATE_IN_TIMELINE_TEST_ID,
@ -20,10 +19,10 @@ import {
export const INDICATORS_TABLE_INVESTIGATE_IN_TIMELINE_BUTTON_ICON = `[data-test-subj="${CELL_INVESTIGATE_IN_TIMELINE_TEST_ID}"]`; export const INDICATORS_TABLE_INVESTIGATE_IN_TIMELINE_BUTTON_ICON = `[data-test-subj="${CELL_INVESTIGATE_IN_TIMELINE_TEST_ID}"]`;
export const UNTITLED_TIMELINE_BUTTON = `[data-test-subj="flyoutOverlay"]`; export const UNTITLED_TIMELINE_BUTTON = `[data-test-subj="flyoutOverlay"]`;
export const INDICATORS_TABLE_CELL_TIMELINE_BUTTON = `[data-test-subj="${CELL_TIMELINE_BUTTON_TEST_ID}"] button`; export const INDICATORS_TABLE_CELL_TIMELINE_BUTTON = `[data-test-subj="${CELL_TIMELINE_BUTTON_TEST_ID}"] button`;
export const TIMELINE_DATA_PROVIDERS_WRAPPER = `[data-test-subj="dataProviders"]`;
export const TIMELINE_DRAGGABLE_ITEM = `[data-test-subj="providerContainer"]`; export const TIMELINE_DRAGGABLE_ITEM = `[data-test-subj="providerContainer"]`;
export const TIMELINE_AND_OR_BADGE = `[data-test-subj="and-or-badge"]`;
export const CLOSE_TIMELINE_BTN = '[data-test-subj="close-timeline"]'; export const CLOSE_TIMELINE_BTN = '[data-test-subj="close-timeline"]';
export const QUERY_TAB_BUTTON = '[data-test-subj="timelineTabs-query"]';
export const FLYOUT_OVERVIEW_TAB_TABLE_ROW_TIMELINE_BUTTON = `[data-test-subj="${INDICATORS_FLYOUT_OVERVIEW_TABLE}${VALUE_ACTION_TIMELINE_BUTTON_TEST_ID}"]`; export const FLYOUT_OVERVIEW_TAB_TABLE_ROW_TIMELINE_BUTTON = `[data-test-subj="${INDICATORS_FLYOUT_OVERVIEW_TABLE}${VALUE_ACTION_TIMELINE_BUTTON_TEST_ID}"]`;
export const FLYOUT_OVERVIEW_TAB_BLOCKS_TIMELINE_BUTTON = `[data-test-subj="${INDICATORS_FLYOUT_OVERVIEW_HIGH_LEVEL_BLOCKS}${VALUE_ACTION_TIMELINE_BUTTON_TEST_ID}"]`; export const FLYOUT_OVERVIEW_TAB_BLOCKS_TIMELINE_BUTTON = `[data-test-subj="${INDICATORS_FLYOUT_OVERVIEW_HIGH_LEVEL_BLOCKS}${VALUE_ACTION_TIMELINE_BUTTON_TEST_ID}"]`;
export const FLYOUT_TABLE_TAB_ROW_TIMELINE_BUTTON = `[data-test-subj="${FLYOUT_TABLE_TEST_ID}${VALUE_ACTION_TIMELINE_BUTTON_TEST_ID}"]`;
export const FLYOUT_INVESTIGATE_IN_TIMELINE_ITEM = `[data-test-subj="${INDICATOR_FLYOUT_TAKE_ACTION_INVESTIGATE_IN_TIMELINE_TEST_ID}"]`; export const FLYOUT_INVESTIGATE_IN_TIMELINE_ITEM = `[data-test-subj="${INDICATOR_FLYOUT_TAKE_ACTION_INVESTIGATE_IN_TIMELINE_TEST_ID}"]`;

View file

@ -1,8 +0,0 @@
/*
* 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 INDICATORS_URL = '/app/security/indicators';

View file

@ -9,10 +9,7 @@ import {
BLOCK_LIST_ADD_BUTTON, BLOCK_LIST_ADD_BUTTON,
BLOCK_LIST_DESCRIPTION, BLOCK_LIST_DESCRIPTION,
BLOCK_LIST_NAME, BLOCK_LIST_NAME,
SAVED_BLOCK_LIST_ACTION_MENU,
BLOCK_LIST_TOAST_LIST, BLOCK_LIST_TOAST_LIST,
SAVED_BLOCK_LIST_CONFIRM_DELETE_BUTTON,
SAVED_BLOCK_LIST_DELETE_BUTTON,
FLYOUT_ADD_TO_BLOCK_LIST_ITEM, FLYOUT_ADD_TO_BLOCK_LIST_ITEM,
INDICATORS_TABLE_ADD_TO_BLOCK_LIST_BUTTON_ICON, INDICATORS_TABLE_ADD_TO_BLOCK_LIST_BUTTON_ICON,
} from '../screens/blocklist'; } from '../screens/blocklist';
@ -42,12 +39,3 @@ export const fillBlocklistForm = (title: string, description: string) => {
const text: string = `"${title}" has been added`; const text: string = `"${title}" has been added`;
cy.get(BLOCK_LIST_TOAST_LIST).should('exist').and('contain.text', text); cy.get(BLOCK_LIST_TOAST_LIST).should('exist').and('contain.text', text);
}; };
/**
* Remove the blocklist entry
*/
export const deleteBlocklistEntry = () => {
cy.get(SAVED_BLOCK_LIST_ACTION_MENU).click();
cy.get(SAVED_BLOCK_LIST_DELETE_BUTTON).click();
cy.get(SAVED_BLOCK_LIST_CONFIRM_DELETE_BUTTON).click();
};

View file

@ -10,11 +10,6 @@ import {
FLYOUT_ADD_TO_NEW_CASE_ITEM, FLYOUT_ADD_TO_NEW_CASE_ITEM,
INDICATORS_TABLE_ADD_TO_EXISTING_CASE_BUTTON_ICON, INDICATORS_TABLE_ADD_TO_EXISTING_CASE_BUTTON_ICON,
INDICATORS_TABLE_ADD_TO_NEW_CASE_BUTTON_ICON, INDICATORS_TABLE_ADD_TO_NEW_CASE_BUTTON_ICON,
CASE_ACTION_WRAPPER,
CASE_ELLIPSE_BUTTON,
CASE_ELLIPSE_DELETE_CASE_CONFIRMATION_BUTTON,
CASE_ELLIPSE_DELETE_CASE_OPTION,
CREATE_CASE_BUTTON,
NEW_CASE_CREATE_BUTTON, NEW_CASE_CREATE_BUTTON,
NEW_CASE_DESCRIPTION_INPUT, NEW_CASE_DESCRIPTION_INPUT,
NEW_CASE_NAME_INPUT, NEW_CASE_NAME_INPUT,
@ -52,16 +47,6 @@ export const openAddToExistingCaseFromFlyout = () => {
cy.get(FLYOUT_ADD_TO_EXISTING_CASE_ITEM).first().click(); cy.get(FLYOUT_ADD_TO_EXISTING_CASE_ITEM).first().click();
}; };
/**
* Create a new case by filling out the form from the Cases page
*/
export const createNewCaseFromCases = () => {
cy.get(CREATE_CASE_BUTTON).click();
cy.get(NEW_CASE_NAME_INPUT).click().type('case');
cy.get(NEW_CASE_DESCRIPTION_INPUT).click().type('case description');
cy.get(NEW_CASE_CREATE_BUTTON).click();
};
/** /**
* Create a new case from the Threat Intelligence page * Create a new case from the Threat Intelligence page
*/ */
@ -78,15 +63,6 @@ export const navigateToCaseViaToaster = () => {
cy.get(VIEW_CASE_TOASTER_LINK).click(); cy.get(VIEW_CASE_TOASTER_LINK).click();
}; };
/**
* Delete case from the Cases page
*/
export const deleteCase = () => {
cy.get(CASE_ACTION_WRAPPER).find(CASE_ELLIPSE_BUTTON).click();
cy.get(CASE_ELLIPSE_DELETE_CASE_OPTION).click();
cy.get(CASE_ELLIPSE_DELETE_CASE_CONFIRMATION_BUTTON).click();
};
/** /**
* Select existing case from cases modal * Select existing case from cases modal
*/ */

View file

@ -7,7 +7,6 @@
import { import {
MANAGE_NAVIGATION_ITEMS, MANAGE_NAVIGATION_ITEMS,
SECURITY_SOLUTION_NAVBAR_CASES_ITEM,
SECURITY_SOLUTION_NAVBAR_MANAGE_ITEM, SECURITY_SOLUTION_NAVBAR_MANAGE_ITEM,
SECURITY_SOLUTION_NAVBAR_THREAT_INTELLIGENCE_ITEM, SECURITY_SOLUTION_NAVBAR_THREAT_INTELLIGENCE_ITEM,
UPDATE_STATUS, UPDATE_STATUS,
@ -26,7 +25,8 @@ import {
* Navigate to Blocklist screen via the Security Solution navbar and Manage menu item * Navigate to Blocklist screen via the Security Solution navbar and Manage menu item
*/ */
export const navigateToBlocklist = () => { export const navigateToBlocklist = () => {
cy.get(SECURITY_SOLUTION_NAVBAR_MANAGE_ITEM).scrollIntoView().click(); cy.get(SECURITY_SOLUTION_NAVBAR_MANAGE_ITEM).scrollIntoView();
cy.get(SECURITY_SOLUTION_NAVBAR_MANAGE_ITEM).click();
cy.get(MANAGE_NAVIGATION_ITEMS).contains('Blocklist').click(); cy.get(MANAGE_NAVIGATION_ITEMS).contains('Blocklist').click();
}; };
@ -37,13 +37,6 @@ export const navigateToThreatIntelligence = () => {
cy.get(SECURITY_SOLUTION_NAVBAR_THREAT_INTELLIGENCE_ITEM).click(); cy.get(SECURITY_SOLUTION_NAVBAR_THREAT_INTELLIGENCE_ITEM).click();
}; };
/**
* Navigate to Cases screen via the Security Solution navbar
*/
export const navigateToCases = () => {
cy.get(SECURITY_SOLUTION_NAVBAR_CASES_ITEM).click();
};
/** /**
* Close the opened flyout * Close the opened flyout
*/ */
@ -87,12 +80,14 @@ export const navigateToFlyoutJsonTab = () => {
}; };
export const waitForViewToBeUpdated = () => { export const waitForViewToBeUpdated = () => {
cy.get(UPDATE_STATUS).scrollIntoView().should('contain.text', 'Updated'); cy.get(UPDATE_STATUS).scrollIntoView();
cy.get(UPDATE_STATUS).should('contain.text', 'Updated');
}; };
/** /**
* Open barchart 3-dot popover menu * Open barchart 3-dot popover menu
*/ */
export const openBarchartPopoverMenu = () => { export const openBarchartPopoverMenu = () => {
cy.get(BARCHART_POPOVER_BUTTON).first().scrollIntoView();
cy.get(BARCHART_POPOVER_BUTTON).should('exist').first().click(); cy.get(BARCHART_POPOVER_BUTTON).should('exist').first().click();
}; };

View file

@ -8,7 +8,7 @@
import { QUERY_INPUT } from '../screens/indicators'; import { QUERY_INPUT } from '../screens/indicators';
/** /**
* Nvigate to specific page in indicators table * Navigate to specific page in indicators table
*/ */
export const navigateToIndicatorsTablePage = (index: number) => { export const navigateToIndicatorsTablePage = (index: number) => {
cy.get(`[data-test-subj="pagination-button-${index}"]`).click(); cy.get(`[data-test-subj="pagination-button-${index}"]`).click();
@ -18,12 +18,14 @@ export const navigateToIndicatorsTablePage = (index: number) => {
* Clears text in KQL bar * Clears text in KQL bar
*/ */
export const enterQuery = (text: string) => { export const enterQuery = (text: string) => {
cy.get(QUERY_INPUT).should('exist').focus().type(text); cy.get(QUERY_INPUT).should('exist').focus();
cy.get(QUERY_INPUT).should('exist').type(text);
}; };
/** /**
* Clears text in KQL bar * Clears text in KQL bar
*/ */
export const clearQuery = () => { export const clearQuery = () => {
cy.get(QUERY_INPUT).should('exist').focus().clear(); cy.get(QUERY_INPUT).should('exist').focus();
cy.get(QUERY_INPUT).should('exist').clear();
}; };

View file

@ -10,13 +10,15 @@ import Url from 'url';
import * as yaml from 'js-yaml'; import * as yaml from 'js-yaml';
import {
LOADING_INDICATOR,
LOADING_INDICATOR_HIDDEN,
} from '@kbn/security-solution-plugin/cypress/screens/security_header';
import { encode } from '@kbn/rison';
import { NEW_FEATURES_TOUR_STORAGE_KEYS } from '@kbn/security-solution-plugin/common/constants';
import type { ROLES } from './privileges'; import type { ROLES } from './privileges';
const LOGIN_API_ENDPOINT = '/internal/security/login'; const LOGIN_API_ENDPOINT = '/internal/security/login';
const LOGOUT_URL = '/logout';
export const hostDetailsUrl = (hostName: string) =>
`/app/security/hosts/${hostName}/authentications`;
/** /**
* Credentials in the `kibana.dev.yml` config file will be used to authenticate * Credentials in the `kibana.dev.yml` config file will be used to authenticate
@ -124,33 +126,6 @@ export const postRoleAndUser = (role: ROLES) => {
}); });
}; };
export const deleteRoleAndUser = (role: ROLES) => {
const env = getCurlScriptEnvVars();
const detectionsUserDeleteScriptPath = `./server/lib/detection_engine/scripts/roles_users/${role}/delete_detections_user.sh`;
// delete the role
cy.exec(`bash ${detectionsUserDeleteScriptPath}`, {
env,
});
};
export const loginWithUser = (user: User) => {
cy.request({
body: {
providerType: 'basic',
providerName: 'basic',
currentURL: '/',
params: {
username: user.username,
password: user.password,
},
},
headers: { 'kbn-xsrf': 'cypress-creds-via-config' },
method: 'POST',
url: constructUrlWithUser(user, LOGIN_API_ENDPOINT),
});
};
export const loginWithRole = async (role: ROLES) => { export const loginWithRole = async (role: ROLES) => {
postRoleAndUser(role); postRoleAndUser(role);
const theUrl = Url.format({ const theUrl = Url.format({
@ -297,57 +272,53 @@ export const getEnvAuth = (): User => {
} }
}; };
/** export const visit = (url: string, options: Partial<Cypress.VisitOptions> = {}, role?: ROLES) => {
* Authenticates with Kibana, visits the specified `url`, and waits for the const timerangeConfig = {
* Kibana global nav to be displayed before continuing from: 1547914976217,
*/ fromStr: '2019-01-19T16:22:56.217Z',
export const loginAndWaitForPage = ( kind: 'relative',
url: string, to: 1579537385745,
role?: ROLES, toStr: 'now',
onBeforeLoadCallback?: (win: Cypress.AUTWindow) => void };
) => {
login(role); const timerange = encode({
cy.visit( global: {
`${url}?timerange=(global:(linkTo:!(timeline),timerange:(from:1547914976217,fromStr:'2019-01-19T16:22:56.217Z',kind:relative,to:1579537385745,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1547914976217,fromStr:'2019-01-19T16:22:56.217Z',kind:relative,to:1579537385745,toStr:now)))`, linkTo: ['timeline'],
{ timerange: timerangeConfig,
onBeforeLoad(win) {
if (onBeforeLoadCallback) {
onBeforeLoadCallback(win);
}
}, },
} timeline: {
); linkTo: ['global'],
cy.get('[data-test-subj="headerGlobalNav"]'); timerange: timerangeConfig,
}; },
export const waitForPage = (url: string) => { });
cy.visit(
`${url}?timerange=(global:(linkTo:!(timeline),timerange:(from:1547914976217,fromStr:'2019-01-19T16:22:56.217Z',kind:relative,to:1579537385745,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1547914976217,fromStr:'2019-01-19T16:22:56.217Z',kind:relative,to:1579537385745,toStr:now)))` cy.visit(role ? getUrlWithRoute(role, url) : url, {
); ...options,
cy.get('[data-test-subj="headerGlobalNav"]'); qs: {
...options.qs,
timerange,
},
onBeforeLoad: (win) => {
options.onBeforeLoad?.(win);
disableNewFeaturesTours(win);
},
});
waitForPageToBeLoaded();
}; };
export const loginAndWaitForPageWithoutDateRange = (url: string, role?: ROLES) => { const disableNewFeaturesTours = (window: Window) => {
login(role); const tourStorageKeys = Object.values(NEW_FEATURES_TOUR_STORAGE_KEYS);
cy.visit(role ? getUrlWithRoute(role, url) : url); const tourConfig = {
cy.get('[data-test-subj="headerGlobalNav"]', { timeout: 120000 }); isTourActive: false,
}; };
export const loginWithUserAndWaitForPage = (url: string, user: User) => { tourStorageKeys.forEach((key) => {
loginWithUser(user); window.localStorage.setItem(key, JSON.stringify(tourConfig));
cy.visit(constructUrlWithUser(user, url)); });
cy.get('[data-test-subj="headerGlobalNav"]', { timeout: 120000 });
}; };
export const loginAndWaitForHostDetailsPage = (hostName = 'suricata-iowa') => { export const waitForPageToBeLoaded = () => {
loginAndWaitForPage(hostDetailsUrl(hostName)); cy.get(LOADING_INDICATOR_HIDDEN).should('exist');
cy.get('[data-test-subj="loading-spinner"]', { timeout: 12000 }).should('not.exist'); cy.get(LOADING_INDICATOR).should('not.exist');
};
export const waitForPageWithoutDateRange = (url: string, role?: ROLES) => {
cy.visit(role ? getUrlWithRoute(role, url) : url);
cy.get('[data-test-subj="headerGlobalNav"]', { timeout: 120000 });
};
export const logout = () => {
cy.visit(LOGOUT_URL);
}; };

View file

@ -48,118 +48,6 @@ interface Role {
}; };
} }
// Create roles with allowed combinations of Fleet and Integrations
export const FleetAllIntegrAllRole: Role = {
name: 'fleet_all_int_all_role',
privileges: {
elasticsearch: {
indices: [
{
names: ['*'],
privileges: ['all'],
},
],
},
kibana: [
{
feature: {
fleetv2: ['all'],
fleet: ['all'],
},
spaces: ['*'],
},
],
},
};
export const FleetAllIntegrAllUser: User = {
username: 'fleet_all_int_all_user',
password: 'password',
roles: [FleetAllIntegrAllRole.name],
};
export const FleetAllIntegrReadRole: Role = {
name: 'fleet_all_int_read_user',
privileges: {
elasticsearch: {
indices: [
{
names: ['*'],
privileges: ['all'],
},
],
},
kibana: [
{
feature: {
fleetv2: ['all'],
fleet: ['read'],
},
spaces: ['*'],
},
],
},
};
export const FleetAllIntegrReadUser: User = {
username: 'fleet_all_int_read_user',
password: 'password',
roles: [FleetAllIntegrReadRole.name],
};
export const FleetAllIntegrNoneRole: Role = {
name: 'fleet_all_int_none_role',
privileges: {
elasticsearch: {
indices: [
{
names: ['*'],
privileges: ['all'],
},
],
},
kibana: [
{
feature: {
fleetv2: ['all'],
fleet: ['none'],
},
spaces: ['*'],
},
],
},
};
export const FleetAllIntegrNoneUser: User = {
username: 'fleet_all_int_none_user',
password: 'password',
roles: [FleetAllIntegrNoneRole.name],
};
export const FleetNoneIntegrAllRole: Role = {
name: 'fleet_none_int_all_role',
privileges: {
elasticsearch: {
indices: [
{
names: ['*'],
privileges: ['all'],
},
],
},
kibana: [
{
feature: {
fleetv2: ['none'],
fleet: ['all'],
},
spaces: ['*'],
},
],
},
};
export const FleetNoneIntegrAllUser: User = {
username: 'fleet_none_int_all_user',
password: 'password',
roles: [FleetNoneIntegrAllRole.name],
};
const getUserInfo = (user: User): UserInfo => ({ const getUserInfo = (user: User): UserInfo => ({
username: user.username, username: user.username,
full_name: user.username.replace('_', ' '), full_name: user.username.replace('_', ' '),

View file

@ -5,6 +5,7 @@
* 2.0. * 2.0.
*/ */
import { openBarchartPopoverMenu } from './common';
import { import {
QUERY_BAR, QUERY_BAR,
QUERY_BAR_MENU_REMOVE_ALL_FILTERS_BUTTON, QUERY_BAR_MENU_REMOVE_ALL_FILTERS_BUTTON,
@ -29,6 +30,7 @@ import {
* Filter in value by clicking on the menu item within barchart popover * Filter in value by clicking on the menu item within barchart popover
*/ */
export const filterInFromBarChartLegend = () => { export const filterInFromBarChartLegend = () => {
openBarchartPopoverMenu();
cy.get(BARCHART_FILTER_IN_BUTTON).should('exist').click(); cy.get(BARCHART_FILTER_IN_BUTTON).should('exist').click();
}; };
@ -36,6 +38,7 @@ export const filterInFromBarChartLegend = () => {
* Filter out value by clicking on the menu item within barchart popover * Filter out value by clicking on the menu item within barchart popover
*/ */
export const filterOutFromBarChartLegend = () => { export const filterOutFromBarChartLegend = () => {
openBarchartPopoverMenu();
cy.get(BARCHART_FILTER_OUT_BUTTON).should('exist').click(); cy.get(BARCHART_FILTER_OUT_BUTTON).should('exist').click();
}; };
@ -43,10 +46,10 @@ export const filterOutFromBarChartLegend = () => {
* Filter in value by clicking on the menu item within an indicators table cell * Filter in value by clicking on the menu item within an indicators table cell
*/ */
export const filterInFromTableCell = () => { export const filterInFromTableCell = () => {
cy.get(INDICATOR_TYPE_CELL).first().should('be.visible');
cy.get(INDICATOR_TYPE_CELL).first().trigger('mouseover');
cy.get(INDICATOR_TYPE_CELL) cy.get(INDICATOR_TYPE_CELL)
.first() .first()
.should('be.visible')
.trigger('mouseover')
.within((_cell) => { .within((_cell) => {
cy.get(INDICATORS_TABLE_CELL_FILTER_IN_BUTTON).should('exist').click({ cy.get(INDICATORS_TABLE_CELL_FILTER_IN_BUTTON).should('exist').click({
force: true, force: true,
@ -58,9 +61,9 @@ export const filterInFromTableCell = () => {
* Filter out value by clicking on the menu item within an indicators table cell * Filter out value by clicking on the menu item within an indicators table cell
*/ */
export const filterOutFromTableCell = () => { export const filterOutFromTableCell = () => {
cy.get(INDICATOR_TYPE_CELL).first().trigger('mouseover');
cy.get(INDICATOR_TYPE_CELL) cy.get(INDICATOR_TYPE_CELL)
.first() .first()
.trigger('mouseover')
.within((_cell) => { .within((_cell) => {
cy.get(INDICATORS_TABLE_CELL_FILTER_OUT_BUTTON).should('exist').click({ force: true }); cy.get(INDICATORS_TABLE_CELL_FILTER_OUT_BUTTON).should('exist').click({ force: true });
}); });
@ -70,7 +73,10 @@ export const filterOutFromTableCell = () => {
* Clears all filters within KQL bar * Clears all filters within KQL bar
*/ */
export const clearKQLBar = () => { export const clearKQLBar = () => {
cy.get(QUERY_BAR).scrollIntoView();
cy.get(QUERY_BAR).within(() => cy.get(QUERY_BAR_MENU).click()); cy.get(QUERY_BAR).within(() => cy.get(QUERY_BAR_MENU).click());
cy.get(QUERY_BAR_MENU_REMOVE_ALL_FILTERS_BUTTON).scrollIntoView();
cy.get(QUERY_BAR_MENU_REMOVE_ALL_FILTERS_BUTTON).click(); cy.get(QUERY_BAR_MENU_REMOVE_ALL_FILTERS_BUTTON).click();
}; };

View file

@ -1,18 +0,0 @@
/*
* 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 { EMPTY_STATE, TIME_RANGE_PICKER } from '../screens/indicators';
export const selectRange = () => {
cy.get(EMPTY_STATE);
cy.get(TIME_RANGE_PICKER).first().click({ force: true });
cy.get('[aria-label="Time unit"]').select('y');
cy.get('[data-test-subj="superDatePickerQuickMenu"] .euiQuickSelect__applyButton').click({
force: true,
});
};

View file

@ -5,6 +5,8 @@
* 2.0. * 2.0.
*/ */
import { recurse } from 'cypress-recurse';
import { openBarchartPopoverMenu } from './common';
import { import {
CLOSE_TIMELINE_BTN, CLOSE_TIMELINE_BTN,
FLYOUT_INVESTIGATE_IN_TIMELINE_ITEM, FLYOUT_INVESTIGATE_IN_TIMELINE_ITEM,
@ -15,6 +17,7 @@ import {
UNTITLED_TIMELINE_BUTTON, UNTITLED_TIMELINE_BUTTON,
} from '../screens/timeline'; } from '../screens/timeline';
import { import {
ADDED_TO_TIMELINE_TOAST,
BARCHART_TIMELINE_BUTTON, BARCHART_TIMELINE_BUTTON,
FLYOUT_BLOCK_MORE_ACTIONS_BUTTON, FLYOUT_BLOCK_MORE_ACTIONS_BUTTON,
FLYOUT_TABLE_MORE_ACTIONS_BUTTON, FLYOUT_TABLE_MORE_ACTIONS_BUTTON,
@ -25,7 +28,15 @@ import {
* Add data to timeline from barchart legend menu item * Add data to timeline from barchart legend menu item
*/ */
export const addToTimelineFromBarchartLegend = () => { export const addToTimelineFromBarchartLegend = () => {
cy.get(BARCHART_TIMELINE_BUTTON).should('exist').first().click(); recurse(
() => {
openBarchartPopoverMenu();
cy.get(BARCHART_TIMELINE_BUTTON).first().click();
openBarchartPopoverMenu();
return cy.get(ADDED_TO_TIMELINE_TOAST).should(Cypress._.noop);
},
($el) => !!$el.length
);
}; };
/** /**
* Add data to timeline from indicators table cell menu * Add data to timeline from indicators table cell menu
@ -53,16 +64,33 @@ export const closeTimeline = () => {
* Add data to timeline from flyout overview tab table * Add data to timeline from flyout overview tab table
*/ */
export const addToTimelineFromFlyoutOverviewTabTable = () => { export const addToTimelineFromFlyoutOverviewTabTable = () => {
recurse(
() => {
cy.get(FLYOUT_TABLE_MORE_ACTIONS_BUTTON).first().click({ force: true }); cy.get(FLYOUT_TABLE_MORE_ACTIONS_BUTTON).first().click({ force: true });
cy.get(FLYOUT_OVERVIEW_TAB_TABLE_ROW_TIMELINE_BUTTON).should('exist').first().click(); cy.get(FLYOUT_OVERVIEW_TAB_TABLE_ROW_TIMELINE_BUTTON).first().click();
cy.get(FLYOUT_TABLE_MORE_ACTIONS_BUTTON).first().click({ force: true });
return cy.get(ADDED_TO_TIMELINE_TOAST).should(Cypress._.noop);
},
($el) => !!$el.length
);
}; };
/** /**
* Add data to timeline from flyout overview tab block * Add data to timeline from flyout overview tab block
*/ */
export const addToTimelineFromFlyoutOverviewTabBlock = () => { export const addToTimelineFromFlyoutOverviewTabBlock = () => {
recurse(
() => {
cy.get(FLYOUT_BLOCK_MORE_ACTIONS_BUTTON).first().click({ force: true }); cy.get(FLYOUT_BLOCK_MORE_ACTIONS_BUTTON).first().click({ force: true });
cy.get(FLYOUT_OVERVIEW_TAB_BLOCKS_TIMELINE_BUTTON).should('exist').first().click();
cy.get(FLYOUT_OVERVIEW_TAB_BLOCKS_TIMELINE_BUTTON).first().click();
cy.get(FLYOUT_BLOCK_MORE_ACTIONS_BUTTON).first().click({ force: true });
return cy.get(ADDED_TO_TIMELINE_TOAST).should(Cypress._.noop);
},
($el) => !!$el.length
);
}; };
/** /**

View file

@ -5,16 +5,12 @@
"license": "Elastic License 2.0", "license": "Elastic License 2.0",
"scripts": { "scripts": {
"cypress": "../../../node_modules/.bin/cypress", "cypress": "../../../node_modules/.bin/cypress",
"cypress:open": "yarn cypress open --config-file ./cypress/cypress.config.ts", "cypress:open": "TZ=UTC node ../security_solution/scripts/start_cypress_parallel open --spec './cypress/e2e/**/*.cy.ts' --config-file ./cypress/cypress.config.ts --ftr-config-file ../../../../../../x-pack/test/threat_intelligence_cypress/cli_config_parallel",
"cypress:open-as-ci": "node ../../../scripts/functional_tests --config ../../test/threat_intelligence_cypress/visual_config.ts",
"cypress:run": "yarn cypress:run:reporter --browser chrome --spec './cypress/e2e/**/*.cy.ts'; status=$?; yarn junit:merge && exit $status", "cypress:run": "yarn cypress:run:reporter --browser chrome --spec './cypress/e2e/**/*.cy.ts'; status=$?; yarn junit:merge && exit $status",
"cypress:run:spec": "yarn cypress:run:reporter --browser chrome --spec ${SPEC_LIST:-'./cypress/e2e/**/*.cy.ts'}; status=$?; yarn junit:merge && exit $status", "cypress:run:spec": "yarn cypress:run:reporter --browser chrome --spec ${SPEC_LIST:-'./cypress/e2e/**/*.cy.ts'}; status=$?; yarn junit:merge && exit $status",
"cypress:run:cases": "yarn cypress:run:reporter --browser chrome --spec './cypress/e2e/cases/*.cy.ts'; status=$?; yarn junit:merge && exit $status", "cypress:run:cases": "yarn cypress:run:reporter --browser chrome --spec './cypress/e2e/cases/*.cy.ts' --ftr-config-file ../../../../../../x-pack/test/security_solution_cypress/cases_cli_config; status=$?; yarn junit:merge && exit $status",
"cypress:run:firefox": "yarn cypress:run:reporter --browser firefox --spec './cypress/e2e/**/*.cy.ts'; status=$?; yarn junit:merge && exit $status", "cypress:run:reporter": "TZ=UTC node ../security_solution/scripts/start_cypress_parallel run --config-file ./cypress/cypress.config.ts --ftr-config-file ../../../../../../x-pack/test/threat_intelligence_cypress/cli_config_parallel --reporter ../../../node_modules/cypress-multi-reporters --reporter-options configFile=./cypress/reporter_config.json",
"cypress:run:reporter": "yarn cypress run --config-file ./cypress/cypress.config.ts --reporter ../../../node_modules/cypress-multi-reporters --reporter-options configFile=./cypress/reporter_config.json", "cypress:run:respops": "yarn cypress:run:reporter --browser chrome --spec ./cypress/e2e/detection_alerts/*.cy.ts,./cypress/e2e/detection_rules/*.cy.ts,./cypress/e2e/exceptions/*.cy.ts --ftr-config-file ../../../../../../x-pack/test/security_solution_cypress/response_ops_cli_config; status=$?; yarn junit:merge && exit $status",
"cypress:run:respops": "yarn cypress:run:reporter --browser chrome --spec ./cypress/e2e/detection_alerts/*.cy.ts,./cypress/e2e/detection_rules/*.cy.ts,./cypress/e2e/exceptions/*.cy.ts; status=$?; yarn junit:merge && exit $status",
"cypress:run-as-ci": "node --max-old-space-size=2048 ../../../scripts/functional_tests --config ../../test/threat_intelligence_cypress/cli_config_parallel.ts",
"cypress:run-as-ci:firefox": "node --max-old-space-size=2048 ../../../scripts/functional_tests --config ../../test/threat_intelligence_cypress/config.firefox.ts",
"junit:merge": "../../../node_modules/.bin/mochawesome-merge ../../../target/kibana-threat-intelligence/cypress/results/mochawesome*.json > ../../../target/kibana-threat-intelligence/cypress/results/output.json && ../../../node_modules/.bin/marge ../../../target/kibana-threat-intelligence/cypress/results/output.json --reportDir ../../../target/kibana-threat-intelligence/cypress/results && mkdir -p ../../../target/junit && cp ../../../target/kibana-threat-intelligence/cypress/results/*.xml ../../../target/junit/" "junit:merge": "../../../node_modules/.bin/mochawesome-merge ../../../target/kibana-threat-intelligence/cypress/results/mochawesome*.json > ../../../target/kibana-threat-intelligence/cypress/results/output.json && ../../../node_modules/.bin/marge ../../../target/kibana-threat-intelligence/cypress/results/output.json --reportDir ../../../target/kibana-threat-intelligence/cypress/results && mkdir -p ../../../target/junit && cp ../../../target/kibana-threat-intelligence/cypress/results/*.xml ../../../target/junit/"
} }
} }

View file

@ -8,10 +8,7 @@
import { FtrConfigProviderContext } from '@kbn/test'; import { FtrConfigProviderContext } from '@kbn/test';
import { FtrProviderContext } from './ftr_provider_context'; import { FtrProviderContext } from './ftr_provider_context';
import { ThreatIntelligenceCypressCliTestRunnerCI } from './runner'; import { ThreatIntelligenceConfigurableCypressTestRunner } from './runner';
const cliNumber = parseInt(process.env.CLI_NUMBER ?? '1', 10);
const cliCount = parseInt(process.env.CLI_COUNT ?? '1', 10);
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default async function ({ readConfigFile }: FtrConfigProviderContext) { export default async function ({ readConfigFile }: FtrConfigProviderContext) {
@ -20,6 +17,6 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
...securitySolutionCypressConfig.getAll(), ...securitySolutionCypressConfig.getAll(),
testRunner: (context: FtrProviderContext) => testRunner: (context: FtrProviderContext) =>
ThreatIntelligenceCypressCliTestRunnerCI(context, cliCount, cliNumber), ThreatIntelligenceConfigurableCypressTestRunner(context),
}; };
} }

View file

@ -5,9 +5,7 @@
* 2.0. * 2.0.
*/ */
import { chunk } from 'lodash';
import { resolve } from 'path'; import { resolve } from 'path';
import globby from 'globby';
import Url from 'url'; import Url from 'url';
@ -21,17 +19,8 @@ import { tiAbusechMalware } from './pipelines/ti_abusech_malware';
import { tiAbusechMalwareBazaar } from './pipelines/ti_abusech_malware_bazaar'; import { tiAbusechMalwareBazaar } from './pipelines/ti_abusech_malware_bazaar';
import { tiAbusechUrl } from './pipelines/ti_abusech_url'; import { tiAbusechUrl } from './pipelines/ti_abusech_url';
const retrieveIntegrations = (chunksTotal: number, chunkIndex: number) => {
const pattern = resolve(__dirname, '../../plugins/threat_intelligence/cypress/e2e/**/*.cy.ts');
const integrationsPaths = globby.sync(pattern);
const chunkSize = Math.ceil(integrationsPaths.length / chunksTotal);
return chunk(integrationsPaths, chunkSize)[chunkIndex - 1] || [];
};
export async function ThreatIntelligenceConfigurableCypressTestRunner( export async function ThreatIntelligenceConfigurableCypressTestRunner(
{ getService }: FtrProviderContext, { getService }: FtrProviderContext,
command: string,
envVars?: Record<string, string> envVars?: Record<string, string>
) { ) {
const log = getService('log'); const log = getService('log');
@ -55,56 +44,19 @@ export async function ThreatIntelligenceConfigurableCypressTestRunner(
log.info(`PUT pipeline ${pipeline.name}: ${res.statusCode}`); log.info(`PUT pipeline ${pipeline.name}: ${res.statusCode}`);
} }
await withProcRunner(log, async (procs) => { return {
await procs.run('cypress', {
cmd: 'yarn',
args: [command],
cwd: resolve(__dirname, '../../plugins/threat_intelligence'),
env: {
FORCE_COLOR: '1', FORCE_COLOR: '1',
CYPRESS_BASE_URL: Url.format(config.get('servers.kibana')), CYPRESS_BASE_URL: Url.format(config.get('servers.kibana')),
CYPRESS_ELASTICSEARCH_URL: Url.format(config.get('servers.elasticsearch')), CYPRESS_ELASTICSEARCH_URL: Url.format(config.get('servers.elasticsearch')),
CYPRESS_ELASTICSEARCH_USERNAME: config.get('servers.elasticsearch.username'), CYPRESS_ELASTICSEARCH_USERNAME: config.get('servers.elasticsearch.username'),
CYPRESS_ELASTICSEARCH_PASSWORD: config.get('servers.elasticsearch.password'), CYPRESS_ELASTICSEARCH_PASSWORD: config.get('servers.elasticsearch.password'),
...process.env,
...envVars, ...envVars,
}, baseUrl: Url.format(config.get('servers.kibana')),
wait: true, BASE_URL: Url.format(config.get('servers.kibana')),
}); ELASTICSEARCH_URL: Url.format(config.get('servers.elasticsearch')),
}); ELASTICSEARCH_USERNAME: config.get('servers.elasticsearch.username'),
} ELASTICSEARCH_PASSWORD: config.get('servers.elasticsearch.password'),
};
export async function ThreatIntelligenceCypressCliTestRunnerCI(
context: FtrProviderContext,
totalCiJobs: number,
ciJobNumber: number
) {
const integrations = retrieveIntegrations(totalCiJobs, ciJobNumber);
return ThreatIntelligenceConfigurableCypressTestRunner(context, 'cypress:run:spec', {
SPEC_LIST: integrations.join(','),
});
}
export async function ThreatIntelligenceCypressCliResponseOpsTestRunner(
context: FtrProviderContext
) {
return ThreatIntelligenceConfigurableCypressTestRunner(context, 'cypress:run:respops');
}
export async function ThreatIntelligenceCypressCliCasesTestRunner(context: FtrProviderContext) {
return ThreatIntelligenceConfigurableCypressTestRunner(context, 'cypress:run:cases');
}
export async function ThreatIntelligenceCypressCliTestRunner(context: FtrProviderContext) {
return ThreatIntelligenceConfigurableCypressTestRunner(context, 'cypress:run');
}
export async function ThreatIntelligenceCypressCliFirefoxTestRunner(context: FtrProviderContext) {
return ThreatIntelligenceConfigurableCypressTestRunner(context, 'cypress:run:firefox');
}
export async function ThreatIntelligenceCypressVisualTestRunner(context: FtrProviderContext) {
return ThreatIntelligenceConfigurableCypressTestRunner(context, 'cypress:open');
} }
export async function ThreatIntelligenceCypressCcsTestRunner({ getService }: FtrProviderContext) { export async function ThreatIntelligenceCypressCcsTestRunner({ getService }: FtrProviderContext) {

View file

@ -1,19 +0,0 @@
/*
* 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';
import { ThreatIntelligenceCypressVisualTestRunner } from './runner';
export default async function ({ readConfigFile }: FtrConfigProviderContext) {
const tiCypressConfig = await readConfigFile(require.resolve('./config.ts'));
return {
...tiCypressConfig.getAll(),
testRunner: ThreatIntelligenceCypressVisualTestRunner,
};
}