Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[D&D] Initial functional tests #2070

Merged
merged 7 commits into from
Aug 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build_and_test_workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ jobs:
name: Run functional tests
strategy:
matrix:
group: [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ]
group: [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 ]
steps:
- run: echo Running functional tests for ciGroup${{ matrix.group }}

Expand Down
1 change: 1 addition & 0 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ def functionalDynamicParallelSteps(image){
"ciGroup10",
"ciGroup11",
"ciGroup12",
"ciGroup13",
]
for (int i = 0; i < ciGroups.size(); i++) {
def currentCiGroup = ciGroups[i];
Expand Down
17 changes: 16 additions & 1 deletion TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ To run specific functional tests, you can run by CI group:

To debug functional tests:
Say that you would want to debug a test in CI group 1, you can run the following command in your environment:
`node --debug-brk --inspect scripts/functional_tests.js --config test/functional/config.js --include ciGroup1 --debug`
Copy link
Member

@kavilla kavilla Aug 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this work!? I know it starts for me but it doesn't really help for helping me debug

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep. thats why I changed the flag name

`node --inspect-brk --inspect scripts/functional_tests.js --config test/functional/config.js --include ciGroup1 --debug`

This will print off an address, to which you could open your chrome browser on your instance and navigate to `chrome://inspect/#devices` and inspect the functional test runner `scripts/functional_tests.js`.

Expand Down Expand Up @@ -89,9 +89,24 @@ Automated testing is provided with Jenkins for Continuous Integration. Jenkins e
Selenium tests are run in headless mode on CI. Locally the same tests will be executed in a real browser. You can activate headless mode by setting the environment variable:
`export TEST_BROWSER_HEADLESS=1`

Since local Selenium tests are run in a real browser, the dev environment should have a desktop environment and Google Chrome or Chromium installed to run the tests.

By default the version of OpenSearch Dashboards will pull the snapshot of the same version of OpenSearch if available while running a few integration tests and for running functional tests. However, if the version of OpenSearch Dashboards is not available, you can build OpenSearch locally and point the functional test runner to the executable with:
`export TEST_OPENSEARCH_FROM=[local directory of OpenSearch executable]`

Selinium tests require a chromedriver and a corresponding version of chrome to run properly. Depending on the version of chromedriver used, you may need to use a version of Google Chrome that is not the latest version. You can do this by running:

```sh
# Enter the version of chrome that you want to install
CHROME_VERSION=100.0.4896.127-1

# Download Chrome to a temp directory
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: specific to amd64 right maybe we can note it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure? amd64 software can be installed on both intel and AMD cpu's as long as they support the same instruction set, which all the processors released in the last decade do

curl -sSL "https://dl.google.com/linux/linux_signing_key.pub" | sudo apt-key add - && wget -O /tmp/chrome.deb "https://dl.google.com/linux/chrome/deb/pool/main/g/google-chrome-stable/google-chrome-stable_${CHROME_VERSION}_amd64.deb"

# Install/Downgrade Chrome
sudo apt-get install -y --allow-downgrades /tmp/chrome.deb
```

# Misc
Although Jest is the standard for this project, there are a few Mocha tests that still exist. You can run these tests by running:
`yarn test:mocha`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,12 @@ const DropboxComponent = ({
draggableId={id}
index={index}
>
<EuiPanel key={index} paddingSize="s" className="dropBox__field">
<EuiPanel
key={index}
paddingSize="s"
className="dropBox__field"
data-test-subj={`dropBoxField-${dropboxId}-${index}`}
>
<EuiText size="s" className="dropBox__field_text" onClick={() => onEditField(id)}>
<a role="button" tabIndex={0}>
{label}
Expand All @@ -108,13 +113,15 @@ const DropboxComponent = ({
aria-label="clear-field"
iconSize="s"
onClick={() => animateDelete(id)}
data-test-subj="dropBoxRemoveBtn"
/>
</EuiPanel>
</EuiDraggable>
))}
</EuiDroppable>
{fields.length < limit && (
<EuiPanel
data-test-subj={`dropBoxAddField-${dropboxId}`}
className={`dropBox__field dropBox__dropTarget ${
isValidDropTarget ? 'validField' : ''
} ${canDrop ? 'canDrop' : ''}`}
Expand All @@ -126,6 +133,7 @@ const DropboxComponent = ({
aria-label="clear-field"
iconSize="s"
onClick={() => onAddField()}
data-test-subj="dropBoxAddBtn"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: i see current standard has camelButton or kebab-button

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our styleguide prescribes cameCase with - for suffixing the subject with an id of sorts. I've followed that pattern here.

/>
</EuiPanel>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ export interface TitleProps {
}

export const Title = ({ title, isSecondary, closeMenu }: TitleProps) => {
const icon = isSecondary && <EuiIcon type="arrowLeft" onClick={closeMenu} />;
const icon = isSecondary && (
<EuiIcon type="arrowLeft" onClick={closeMenu} data-test-subj="panelCloseBtn" />
);
return (
<>
<div className="wizConfig__title">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,34 @@

.searchableDropdown {
overflow: "hidden";
}

.searchableDropdown .euiPopover,
.searchableDropdown .euiPopover__anchor {
width: 100%;
}
.euiFormControlLayout__childrenWrapper {
display: flex;
}

.searchableDropdown--fixedWidthChild {
width: calc(#{$wizSideNavWidth} - #{$euiSizeXL} * 2);
}
&--topDisplay {
padding-right: $euiSizeL;
font-size: $euiFontSizeS;
flex-grow: 1;

.searchableDropdown--topDisplay {
padding-right: $euiSizeL;
font-size: $euiFontSizeS;
}
.euiButtonEmpty__content {
justify-content: flex-start;
}
}

&--fixedWidthChild {
width: calc(#{$wizSideNavWidth} - #{$euiSizeXL} * 2);
}

&--selectableWrapper .euiSelectableList {
// When clicking on the selectable content it will "highlight" itself with a box shadow
// This turns that off
box-shadow: none !important;
margin: ($euiFormControlPadding * -1) - 4;
}

.searchableDropdown--selectableWrapper .euiSelectableList {
// When clicking on the selectable content it will "highlight" itself with a box shadow
// This turns that off
box-shadow: none !important;
margin: ($euiFormControlPadding * -1) - 4;
.euiPopover,
.euiPopover__anchor {
width: 100%;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ export const SearchableDropdown = ({
<div className="searchableDropdown--selectableWrapper">
<EuiSelectable
aria-label="Selectable options"
data-test-subj="searchableDropdownList"
searchable
options={localOptions}
onChange={selectNewOption}
Expand Down Expand Up @@ -145,6 +146,7 @@ export const SearchableDropdown = ({
size="s"
style={{ textAlign: 'left' }}
className="searchableDropdown--topDisplay"
data-test-subj="searchableDropdownValue"
onClick={onButtonClick}
>
{selectedText}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,11 @@ export const Workspace: FC = ({ children }) => {
<ExperimentalInfo />
</EuiFlexItem>
</EuiFlexGroup>
<EuiPanel className="wizCanvas">
<EuiPanel className="wizCanvas" data-test-subj="visualizationLoader">
{expression ? (
<ReactExpressionRenderer expression={expression} searchContext={searchContext} />
) : (
<EuiFlexItem className="wizWorkspace__empty">
<EuiFlexItem className="wizWorkspace__empty" data-test-subj="emptyWorkspace">
<EuiEmptyPrompt
title={<h2>Add a field to start</h2>}
body={
Expand Down

This file was deleted.

1 change: 1 addition & 0 deletions test/common/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export default function () {
`--opensearchDashboards.branding.mark.defaultUrl=https://opensearch.org/assets/brand/SVG/Mark/opensearch_mark_default.svg`,
`--opensearchDashboards.branding.mark.darkModeUrl=https://opensearch.org/assets/brand/SVG/Mark/opensearch_mark_darkmode.svg`,
`--opensearchDashboards.branding.applicationTitle=OpenSearch`,
`--wizard.enabled=true`,
],
},
services,
Expand Down
2 changes: 1 addition & 1 deletion test/examples/embeddables/dashboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

import { PluginFunctionalProviderContext } from 'test/plugin_functional/services';

export const testDashboardInput = {
const testDashboardInput = {
panels: {
'1': {
gridData: {
Expand Down
48 changes: 48 additions & 0 deletions test/functional/apps/wizard/_base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import expect from '@osd/expect';
import { FtrProviderContext } from '../../ftr_provider_context';

export default function ({ getService, getPageObjects }: FtrProviderContext) {
const PageObjects = getPageObjects(['visualize', 'wizard']);
const log = getService('log');
const retry = getService('retry');

describe('Basic tests for wizard app ', function () {
before(async () => {
log.debug('navigateToApp wizard');
await PageObjects.wizard.navigateToCreateWizard();
});

it('should be able to switch data sources', async () => {
const dataSourceValue = await PageObjects.wizard.selectDataSource(
PageObjects.wizard.index.LOGSTASH_NON_TIME_BASED
);

expect(dataSourceValue).to.equal(PageObjects.wizard.index.LOGSTASH_NON_TIME_BASED);
// TODO: Switch with a datasource with unique fields to test if it exists
});

it('should show visualization when a field is added', async () => {
await PageObjects.wizard.addField('metric', 'Average', 'machine.ram');
const avgMachineRam = ['13,104,036,080.615', 'Average machine.ram'];

await retry.try(async function tryingForTime() {
const metricValue = await PageObjects.wizard.getMetric();
expect(avgMachineRam).to.eql(metricValue);
});
});

it('should clear visualization when field is deleted', async () => {
await PageObjects.wizard.removeField('metric', 0);

await retry.try(async function tryingForTime() {
const isEmptyWorkspace = await PageObjects.wizard.isEmptyWorkspace();
expect(isEmptyWorkspace).to.be(true);
});
});
});
}
51 changes: 51 additions & 0 deletions test/functional/apps/wizard/_experimental_vis.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import expect from '@osd/expect';
import { VISUALIZE_ENABLE_LABS_SETTING } from '../../../../src/plugins/visualizations/common/constants';
import { FtrProviderContext } from '../../ftr_provider_context';

export default function ({ getService, getPageObjects }: FtrProviderContext) {
const PageObjects = getPageObjects(['visualize', 'wizard']);
const log = getService('log');
const opensearchDashboardsServer = getService('opensearchDashboardsServer');

describe('experimental settings for wizard app ', function () {
it('should show an notification when creating wizard visualization', async () => {
log.debug('navigateToApp visualize');
await PageObjects.visualize.navigateToNewVisualization();
await PageObjects.visualize.waitForVisualizationSelectPage();

// Try to find the wizard Vis type.
const wizardVisTypeExists = await PageObjects.visualize.hasVisType('wizard');
expect(wizardVisTypeExists).to.be(true);

// Create a new visualization
await PageObjects.visualize.clickVisType('wizard');

// Check that the experimental banner is there and state that this is experimental
const info = await PageObjects.wizard.getExperimentalInfo();
expect(await info.getVisibleText()).to.contain('experimental');
});

it('should not be available in the picker when disabled', async () => {
log.debug('navigateToApp visualize');
await opensearchDashboardsServer.uiSettings.replace({
[VISUALIZE_ENABLE_LABS_SETTING]: false,
});
await PageObjects.visualize.navigateToNewVisualization();
await PageObjects.visualize.waitForVisualizationSelectPage();

// Try to find the wizard Vis type.
const wizardVisTypeExists = await PageObjects.visualize.hasVisType('wizard');
expect(wizardVisTypeExists).to.be(false);
});

after(async () => {
// unset the experimental ui setting
await opensearchDashboardsServer.uiSettings.unset(VISUALIZE_ENABLE_LABS_SETTING);
ashwin-pc marked this conversation as resolved.
Show resolved Hide resolved
});
});
}
39 changes: 39 additions & 0 deletions test/functional/apps/wizard/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { FtrProviderContext } from '../../ftr_provider_context.d';
import { UI_SETTINGS } from '../../../../src/plugins/data/common';

export default function ({ getService, loadTestFile }: FtrProviderContext) {
const browser = getService('browser');
const log = getService('log');
const opensearchArchiver = getService('opensearchArchiver');
const opensearchDashboardsServer = getService('opensearchDashboardsServer');

describe('wizard app', function () {
this.tags('ciGroup13');

before(async function () {
log.debug('Starting wizard before method');
await browser.setWindowSize(1280, 800);
await opensearchArchiver.loadIfNeeded('logstash_functional');
await opensearchArchiver.loadIfNeeded('long_window_logstash');
await opensearchArchiver.loadIfNeeded('visualize');
await opensearchDashboardsServer.uiSettings.replace({
defaultIndex: 'logstash-*',
[UI_SETTINGS.FORMAT_BYTES_DEFAULT_PATTERN]: '0,0.[000]b',
});
});

after(async () => {
await opensearchArchiver.unload('logstash_functional');
await opensearchArchiver.unload('long_window_logstash');
await opensearchArchiver.unload('visualize');
});

loadTestFile(require.resolve('./_base'));
loadTestFile(require.resolve('./_experimental_vis'));
});
}
5 changes: 5 additions & 0 deletions test/functional/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export default async function ({ readConfigFile }) {
require.resolve('./apps/status_page'),
require.resolve('./apps/timeline'),
require.resolve('./apps/visualize'),
require.resolve('./apps/wizard'),
],
pageObjects,
services,
Expand Down Expand Up @@ -91,6 +92,10 @@ export default async function ({ readConfigFile }) {
pathname: '/app/visualize',
hash: '/',
},
wizard: {
pathname: '/app/wizard',
hash: '/',
},
dashboard: {
pathname: '/app/dashboards',
hash: '/list',
Expand Down
2 changes: 2 additions & 0 deletions test/functional/page_objects/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import { TimePickerProvider } from './time_picker';
import { TimelinePageProvider } from './timeline_page';
import { VisualBuilderPageProvider } from './visual_builder_page';
import { VisualizePageProvider } from './visualize_page';
import { WizardPageProvider } from './wizard_page';
import { VisualizeEditorPageProvider } from './visualize_editor_page';
import { VisualizeChartPageProvider } from './visualize_chart_page';
import { TileMapPageProvider } from './tile_map_page';
Expand All @@ -68,6 +69,7 @@ export const pageObjects = {
timePicker: TimePickerProvider,
visualBuilder: VisualBuilderPageProvider,
visualize: VisualizePageProvider,
wizard: WizardPageProvider,
visEditor: VisualizeEditorPageProvider,
visChart: VisualizeChartPageProvider,
tileMap: TileMapPageProvider,
Expand Down
Loading