Skip to content

Commit

Permalink
VSCODE-164: Display connection status in overview (#183)
Browse files Browse the repository at this point in the history
  • Loading branch information
Anemy authored Oct 14, 2020
1 parent 52efbbd commit a7bb28a
Show file tree
Hide file tree
Showing 16 changed files with 574 additions and 81 deletions.
17 changes: 17 additions & 0 deletions src/connectionController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { StorageController, StorageVariables } from './storage';
import { SavedConnection, StorageScope } from './storage/storageController';
import TelemetryController from './telemetry/telemetryController';
import { ext } from './extensionConstants';
import { CONNECTION_STATUS } from './views/webview-app/extension-app-message-constants';

const { name, version } = require('../package.json');
const log = createLogger('connection controller');
Expand Down Expand Up @@ -708,6 +709,22 @@ export default class ConnectionController {
return this._activeConnectionModel;
}

public getConnectionStatus(): CONNECTION_STATUS {
if (this.isCurrentlyConnected()) {
if (this.isDisconnecting()) {
return CONNECTION_STATUS.DISCONNECTING;
}

return CONNECTION_STATUS.CONNECTED;
}

if (this.isConnecting()) {
return CONNECTION_STATUS.CONNECTING;
}

return CONNECTION_STATUS.DISCONNECTED;
}

public getConnectionStatusStringForConnection(connectionId: string): string {
if (
this.getActiveConnectionId() === connectionId
Expand Down
3 changes: 3 additions & 0 deletions src/test/suite/connectionController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ suite('Connection Controller Test Suite', function () {
succesfullyConnected === true,
'Expected a successful (true) connection response.'
);
assert(testConnectionController.getConnectionStatus() === 'CONNECTED');

const successfullyDisconnected = await testConnectionController.disconnect();

Expand All @@ -129,6 +130,7 @@ suite('Connection Controller Test Suite', function () {
const connectionModel = testConnectionController.getActiveConnectionModel();
const dataService = testConnectionController.getActiveDataService();

assert(testConnectionController.getConnectionStatus() === 'DISCONNECTED');
assert(
successfullyDisconnected === true,
'Expected a successful (true) disconnect response.'
Expand Down Expand Up @@ -891,6 +893,7 @@ suite('Connection Controller Test Suite', function () {
await sleep(250);

assert(testConnectionController.isConnecting());
assert(testConnectionController.getConnectionStatus() === 'CONNECTING');

await testConnectionController.removeSavedConnection(connectionId);

Expand Down
76 changes: 71 additions & 5 deletions src/test/suite/views/webview-app/components/app.test.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,29 @@
import assert from 'assert';
import * as React from 'react';
import { shallow } from 'enzyme';
import { mount, shallow } from 'enzyme';
import * as sinon from 'sinon';
import { Provider } from 'react-redux';
import { createStore } from 'redux';

import {
App
initialState,
rootReducer
} from '../../../../../views/webview-app/store/store';
import App, {
App as NotConnectedApp
} from '../../../../../views/webview-app/components/app';
import ConnectionForm from '../../../../../views/webview-app/components/connect-form/connection-form';
import OverviewPage from '../../../../../views/webview-app/components/overview-page/overview-page';
import { WEBVIEW_VIEWS } from '../../../../../views/webview-app/extension-app-message-constants';
import { CONNECTION_STATUS, MESSAGE_TYPES, WEBVIEW_VIEWS } from '../../../../../views/webview-app/extension-app-message-constants';

describe('App Component Test Suite', () => {
describe('when passed currentView=CONNECT', () => {
test('it shows a connection form', () => {
const wrapper = shallow(<App
const wrapper = shallow(<NotConnectedApp
currentView={WEBVIEW_VIEWS.CONNECT}
onConnectedEvent={() => { }}
onFilePickerEvent={() => { }}
setConnectionStatus={() => { }}
/>);
assert(wrapper.find(ConnectionForm).exists());
assert(!wrapper.find(OverviewPage).exists());
Expand All @@ -24,13 +32,71 @@ describe('App Component Test Suite', () => {

describe('when passed currentView=CONNECT', () => {
test('it shows a connection form', () => {
const wrapper = shallow(<App
const wrapper = shallow(<NotConnectedApp
currentView={WEBVIEW_VIEWS.OVERVIEW}
onConnectedEvent={() => { }}
onFilePickerEvent={() => { }}
setConnectionStatus={() => { }}
/>);
assert(wrapper.find(OverviewPage).exists());
assert(!wrapper.find(ConnectionForm).exists());
});
});

describe('when the extension sends a connection status message', () => {
let fakeVscodeWindowPostMessage;
let wrapper;
let store;
let fakeOnEventFunction;
let fakeAddEventListener;

beforeEach(() => {
fakeVscodeWindowPostMessage = sinon.fake.returns(null);
fakeAddEventListener = (eventName, eventFn) => {
if (eventName === 'message') {
fakeOnEventFunction = eventFn;
}
};

sinon.replace(
(global as any).vscodeFake,
'postMessage',
fakeVscodeWindowPostMessage
);

sinon.replace(
window,
'addEventListener',
fakeAddEventListener
);

store = createStore(rootReducer, initialState);

wrapper = mount(
<Provider
store={store}
>
<App />
</Provider>
);
});

afterEach(() => {
sinon.restore();
});

test('it updates the connectionStatus in the store', () => {
assert(store.getState().connectionStatus === CONNECTION_STATUS.LOADING);
assert(store.getState().activeConnectionName === '');
fakeOnEventFunction({
data: {
command: MESSAGE_TYPES.CONNECTION_STATUS_MESSAGE,
connectionStatus: CONNECTION_STATUS.CONNECTED,
activeConnectionName: 'Nice connection'
}
});
assert(store.getState().connectionStatus === CONNECTION_STATUS.CONNECTED);
assert(store.getState().activeConnectionName === 'Nice connection');
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import assert from 'assert';
import * as React from 'react';
import { mount, shallow } from 'enzyme';
import * as sinon from 'sinon';
import { createStore } from 'redux';
import { Provider } from 'react-redux';

import {
rootReducer
} from '../../../../../../views/webview-app/store/store';
import {
ConnectionStatus
} from '../../../../../../views/webview-app/components/connection-status/connection-status';
import { CONNECTION_STATUS } from '../../../../../../views/webview-app/extension-app-message-constants';

describe('Connection Status Component Test Suite', () => {
describe('connected connection status', () => {
test('it shows that it is connected to the connection name', () => {
const wrapper = shallow(<ConnectionStatus
activeConnectionName="Active connection name"
connectionStatus={CONNECTION_STATUS.CONNECTED}
onClickCreatePlayground={() => {}}
requestConnectionStatus={() => {}}
/>);
assert(wrapper.text().includes('Connected to:'));
assert(wrapper.text().includes('Active connection name'));
});

test('it shows a create playground button', () => {
const wrapper = shallow(<ConnectionStatus
activeConnectionName="Active connection name"
connectionStatus={CONNECTION_STATUS.CONNECTED}
onClickCreatePlayground={() => {}}
requestConnectionStatus={() => {}}
/>);
assert(wrapper.find('button').exists());
});
});

describe('disconnected', () => {
test('it shows a disconnect message', () => {
const wrapper = shallow(<ConnectionStatus
activeConnectionName=""
connectionStatus={CONNECTION_STATUS.DISCONNECTED}
onClickCreatePlayground={() => {}}
requestConnectionStatus={() => {}}
/>);
assert(wrapper.text().includes('Not connected'));
});

test('it does not show a create playground button', () => {
const wrapper = shallow(<ConnectionStatus
activeConnectionName=""
connectionStatus={CONNECTION_STATUS.DISCONNECTED}
onClickCreatePlayground={() => {}}
requestConnectionStatus={() => {}}
/>);
assert(wrapper.find('button').exists() === false);
});
});

describe('connecting', () => {
test('it shows a connecting message', () => {
const wrapper = shallow(<ConnectionStatus
activeConnectionName=""
connectionStatus={CONNECTION_STATUS.CONNECTING}
onClickCreatePlayground={() => {}}
requestConnectionStatus={() => {}}
/>);
assert(wrapper.text().includes('Connecting...'));
});
});

describe('disconnecting', () => {
test('it shows a connecting message', () => {
const wrapper = shallow(<ConnectionStatus
activeConnectionName=""
connectionStatus={CONNECTION_STATUS.DISCONNECTING}
onClickCreatePlayground={() => {}}
requestConnectionStatus={() => {}}
/>);
assert(wrapper.text().includes('Disconnecting...'));
});
});

describe('loading', () => {
test('it shows a loading message', () => {
const wrapper = shallow(<ConnectionStatus
activeConnectionName=""
connectionStatus={CONNECTION_STATUS.LOADING}
onClickCreatePlayground={() => {}}
requestConnectionStatus={() => {}}
/>);
assert(wrapper.text().includes('Loading...'));
});
});
});
109 changes: 109 additions & 0 deletions src/test/suite/views/webviewController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -543,4 +543,113 @@ suite('Connect Form View Test Suite', () => {
done();
}, 50);
});

test('webview returns the connection status on a connection status request', (done) => {
const testExtensionContext = new TestExtensionContext();
const testStorageController = new StorageController(testExtensionContext);
const testTelemetryController = new TelemetryController(
testStorageController,
testExtensionContext
);
const testConnectionController = new ConnectionController(
new StatusView(testExtensionContext),
testStorageController,
testTelemetryController
);
let messageRecieved: any;
const fakeWebview = {
html: '',
postMessage: (message: any): void => {
assert(message.command === 'CONNECTION_STATUS_MESSAGE');
assert(message.connectionStatus === 'DISCONNECTED');
assert(message.activeConnectionName === '');

done();
},
onDidReceiveMessage: (callback): void => {
messageRecieved = callback;
},
asWebviewUri: sinon.fake.returns('')
};
const fakeVSCodeCreateWebviewPanel = sinon.fake.returns({
webview: fakeWebview
});

sinon.replace(
vscode.window,
'createWebviewPanel',
fakeVSCodeCreateWebviewPanel
);

const testWebviewController = new WebviewController(
testConnectionController,
testTelemetryController
);

testWebviewController.showOverviewPage(
mdbTestExtension.testExtensionContext
);

// Mock a connection status request call.
messageRecieved({
command: MESSAGE_TYPES.GET_CONNECTION_STATUS
});
});

test('webview returns the connection status on a connection status request', (done) => {
const testExtensionContext = new TestExtensionContext();
const testStorageController = new StorageController(testExtensionContext);
const testTelemetryController = new TelemetryController(
testStorageController,
testExtensionContext
);
const testConnectionController = new ConnectionController(
new StatusView(testExtensionContext),
testStorageController,
testTelemetryController
);
let messageRecieved: any;
const fakeWebview = {
html: '',
postMessage: (message: any): void => {
assert(message.command === 'CONNECTION_STATUS_MESSAGE');
assert(message.connectionStatus === 'CONNECTED');
assert(message.activeConnectionName === 'localhost:27018');
testConnectionController.disconnect();

done();
},
onDidReceiveMessage: (callback): void => {
messageRecieved = callback;
},
asWebviewUri: sinon.fake.returns('')
};
const fakeVSCodeCreateWebviewPanel = sinon.fake.returns({
webview: fakeWebview
});

sinon.replace(
vscode.window,
'createWebviewPanel',
fakeVSCodeCreateWebviewPanel
);

const testWebviewController = new WebviewController(
testConnectionController,
testTelemetryController
);

testWebviewController.showOverviewPage(
mdbTestExtension.testExtensionContext
);

testConnectionController.addNewConnectionStringAndConnect(
TEST_DATABASE_URI
).then(() => {
// Mock a connection status request call.
messageRecieved({
command: MESSAGE_TYPES.GET_CONNECTION_STATUS
});
});
});
});
Loading

0 comments on commit a7bb28a

Please sign in to comment.