Skip to content
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/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
cache: 'npm'
- run: npm ci
- name: Run end-to-end tests
run: xvfb-run npm run test:e2e
run: xvfb-run npm run test:e2e:docker
- name: Upload Screenshots as Artifact
if: ${{ always() }}
uses: actions/upload-artifact@v4
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ node_modules
.DS_Store
e2e-testing/.resources
e2e-testing/.test-extensions
e2e-testing/test-ws/.vscode/settings.json
test-reports/
tsconfig.tsbuildinfo
.env*.local
8 changes: 6 additions & 2 deletions e2e-testing/src/mocharc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ import { MochaOptions } from 'vscode-extension-tester';

const options: MochaOptions = {
timeout: 30000,
reporter: 'mocha-ctrf-json-reporter',
slow: 20000,
reporter: 'mocha-multi-reporters',
reporterOptions: {
outputDir: 'test-reports',
reporterEnabled: 'spec, mocha-ctrf-json-reporter',
mochaCtrfJsonReporterReporterOptions: {
outputDir: 'test-reports',
},
},
};

Expand Down
2 changes: 1 addition & 1 deletion e2e-testing/src/pageObjects/EditorViewExtended.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ export class EditorViewExtended extends EditorView {

await tab.select();

return new WebViewExtended(group).wait();
return new WebViewExtended(group).waitForStable();
}

/**
Expand Down
13 changes: 6 additions & 7 deletions e2e-testing/src/specs/panels.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Workbench } from 'vscode-extension-tester';
import { EditorViewExtended } from '../pageObjects';
import {
connectToServer,
executeCommandWithRetry,
expectDeepEqualArray,
openFileResources,
runDhFileCodeLens,
setup,
SIMPLE_TICKING3_PY,
Expand Down Expand Up @@ -50,10 +50,9 @@ const expectedTabs = {

describe('Panels Tests', () => {
before(async () => {
const explorerView = await setup();
await openFileResources(SIMPLE_TICKING3_PY.path);
await explorerView?.closeView();
await new Workbench().executeCommand('View: Split Editor Down');
await setup(SIMPLE_TICKING3_PY.path);
await connectToServer();
await executeCommandWithRetry('View: Split Editor Down');
});

after(async () => {
Expand Down Expand Up @@ -207,7 +206,7 @@ describe('Panels Tests', () => {
await step(7, 'Move tab to new group', async stepLabel => {
await editorView.openWebView('t3', 2);

await new Workbench().executeCommand('View: Move Editor into Next Group');
await executeCommandWithRetry('View: Move Editor into Next Group');

const editorGroupsData = await editorView.getEditorGroupsData();
expectDeepEqualArray(
Expand Down
62 changes: 18 additions & 44 deletions e2e-testing/src/specs/statusBar.spec.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,33 @@
import { InputBox } from 'vscode-extension-tester';
import {
InputBox,
QuickPickItem,
StatusBar,
VSBrowser,
} from 'vscode-extension-tester';
import {
getDhStatusBarItem,
getServerItems,
getSidebarViewItem,
openFileResources,
setup,
SIMPLE_TICKING3_PY,
SIMPLE_TICKING_MD,
step,
teardown,
TEST_GROOVY,
TEST_TXT,
waitForServerConnection,
} from '../util';
import { EditorViewExtended } from '../pageObjects';
import { assert } from 'chai';
import { SERVER_TITLE, STATUS_BAR_TITLE, VIEW_NAME } from '../util/constants';
import { VIEW_NAME } from '../util/constants';

describe('Status Bar Tests', () => {
let editorView: EditorViewExtended;
let statusBar: StatusBar;

before(async () => {
const explorerView = await setup();

await openFileResources(
await setup(
SIMPLE_TICKING_MD.path,
SIMPLE_TICKING3_PY.path,
TEST_GROOVY.path,
TEST_TXT.path
);

await explorerView?.closeView();

editorView = new EditorViewExtended();
statusBar = new StatusBar();
});

after(async () => {
Expand All @@ -55,14 +46,12 @@ describe('Status Bar Tests', () => {
] as const) {
await step(s, fileName, async stepLabel => {
await editorView.openTextEditor(fileName);
const statusBarItem = await statusBar.getItem(
'plug Deephaven: Disconnected'
);
const statusBarItem = await getDhStatusBarItem();

if (isVisible) {
assert.isDefined(statusBarItem, stepLabel);
assert.isNotNull(statusBarItem, stepLabel);
} else {
assert.isUndefined(statusBarItem, stepLabel);
assert.isNull(statusBarItem, stepLabel);
}
});
}
Expand All @@ -71,41 +60,26 @@ describe('Status Bar Tests', () => {
it('should connect to server on click', async () => {
await editorView.openTextEditor(SIMPLE_TICKING3_PY.name);

await step(1, 'Click Deephaven status bar item', async () => {
const statusBarItem = await statusBar.getItem(
STATUS_BAR_TITLE.disconnected
);
assert.isDefined(statusBarItem);
await step(1, 'Click Deephaven status bar item', async stepLabel => {
const statusBarItem = await getDhStatusBarItem();
assert.isNotNull(statusBarItem, stepLabel);
await statusBarItem.click();
});

await step(2, 'Select connection', async () => {
const input = await InputBox.create();
const qpItem = new QuickPickItem(0, input);
await qpItem.click();
await input.selectQuickPick(0);

// We could call `ViewControl.openView` to ensure DH view is opened, but we
// want to test it opens automatically when a connection is initiated. The
// 500ms sleep matches the timeout that `ViewControl.openView` uses but
// without attempting to open the view.
await VSBrowser.instance.driver.sleep(500);
await waitForServerConnection();
});

step(3, 'Verify server node', async stepLabel => {
const localhost1000Item = await getSidebarViewItem(
VIEW_NAME.servers,
SERVER_TITLE
);
await step(3, 'Verify server node', async stepLabel => {
const [serverItem] = await getServerItems();

assert.isDefined(localhost1000Item, stepLabel);
assert.equal(
await localhost1000Item.getText(),
`${SERVER_TITLE}(1)`,
stepLabel
);
assert.isDefined(serverItem, stepLabel);
});

step(4, 'Verify connection node', async stepLabel => {
await step(4, 'Verify connection node', async stepLabel => {
const simpleTickingEditor = await getSidebarViewItem(
VIEW_NAME.connections,
SIMPLE_TICKING3_PY.name
Expand Down
3 changes: 1 addition & 2 deletions e2e-testing/src/util/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
export const SERVER_TITLE = 'localhost:10000';

export const STATUS_BAR_TITLE = {
connectedPrefix: 'vm-connect DHC:',
Copy link
Member

Choose a reason for hiding this comment

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

Intentional double space?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yes, it's a quirk of how status bar item text with leading icon gets stringified

disconnected: 'plug Deephaven: Disconnected',
} as const;

Expand Down
43 changes: 27 additions & 16 deletions e2e-testing/src/util/lifeCycle.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,34 @@
import { EditorView } from 'vscode-extension-tester';
import {
ActivityBar,
EditorView,
type ViewControl,
} from 'vscode-extension-tester';
import { disconnectFromServer, getElementOrNull } from './testUtils';
import { SERVER_TITLE } from './constants';
getElementOrNull,
openFileResources,
openActivityBarView,
disconnectFromServers,
closeActivityBarView,
} from './testUtils';
import { locators } from './locators';

/**
* Setup before running test suite.
*/
export async function setup(): Promise<ViewControl | undefined> {
const chatCloseButton = await getElementOrNull(locators.chatCloseButton);
await chatCloseButton?.click();
export async function setup(
...initialFilePaths: [string, ...string[]]
): Promise<void> {
try {
const chatCloseButton = await getElementOrNull(locators.chatCloseButton);
await chatCloseButton?.click();
} catch {
// Chat button not found or not interactable - continue anyway
}

const explorer = await new ActivityBar().getViewControl('Explorer');
// Need to open a file before login since an active editor is required for
// Deephaven: Select Connection command to work
await openFileResources(...initialFilePaths);

if (!(await explorer?.isSelected())) {
await explorer?.openView();
}
// Ensure Deephaven extension is activated by opening the Deephaven view
await openActivityBarView('Deephaven');

return explorer;
await closeActivityBarView('Deephaven');
}

/**
Expand All @@ -30,6 +38,9 @@ export async function teardown(): Promise<void> {
await new EditorView().closeAllEditors();

try {
await disconnectFromServer(SERVER_TITLE);
} catch {}
await disconnectFromServers();
} catch (err) {
// eslint-disable-next-line no-console
console.error('Error during disconnectFromServers:', err);
}
}
10 changes: 10 additions & 0 deletions e2e-testing/src/util/locators.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { By } from 'vscode-extension-tester';

export const locators = {
/** Locator for an active connection icon */
activeConnection: By.css(
'.custom-view-tree-node-item-icon.codicon.codicon-vm-connect'
),

/**
* Locator for side panel close button so we can close the Copilot chat. Note
* that the button is always present, but parent div gets `empty` class when
Expand All @@ -10,6 +15,11 @@ export const locators = {
'.auxiliarybar:not(.empty) a[aria-label^="Hide Secondary Side Bar"]'
),

/** Locator for a connected server icon */
connectedServerIcon: By.css(
'.custom-view-tree-node-item-icon.codicon.codicon-circle-large-filled'
),

irisGrid: By.css('.iris-grid'),

/** Locator for the containing div of a WebView */
Expand Down
Loading
Loading