Skip to content

Commit 12bc65a

Browse files
feat: adds a new overview screen based on LeafyGreen components VSCODE-485 (#617)
* feat: added a new overview screen using LG components * fix: checking webpack fix on webview config * chore: path/crypto-browserify are dev deps * chore: added a small msg in reference to new webpack plugin * Update src/test/suite/views/webview-app/connect-helper.test.tsx Co-authored-by: Rhys <[email protected]> * fix: colors based on dark/light mode of vscode theme * Update src/views/webview-app/use-connection-status.ts Co-authored-by: Rhys <[email protected]> * fix: dispose the theme change subscription on deactivate * chore: adds a focusRing for better accessibility of resources button --------- Co-authored-by: Rhys <[email protected]>
1 parent 76f57f0 commit 12bc65a

29 files changed

+22470
-14921
lines changed

package-lock.json

Lines changed: 21005 additions & 14915 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,7 @@
979979
"@iconify-icons/codicon": "^1.2.25",
980980
"@iconify/react": "^1.1.4",
981981
"@leafygreen-ui/logo": "^8.0.4",
982+
"@mongodb-js/compass-components": "^1.19.0",
982983
"@mongodb-js/mongodb-constants": "^0.7.1",
983984
"@mongosh/browser-runtime-electron": "^2.0.2",
984985
"@mongosh/i18n": "^2.0.2",
@@ -1047,6 +1048,7 @@
10471048
"chalk": "^4.1.2",
10481049
"cli-ux": "^5.6.7",
10491050
"cross-env": "^7.0.3",
1051+
"crypto-browserify": "^3.12.0",
10501052
"css-loader": "^6.8.1",
10511053
"depcheck": "^1.4.3",
10521054
"download": "^8.0.0",
@@ -1056,6 +1058,7 @@
10561058
"eslint-config-mongodb-js": "^5.0.3",
10571059
"eslint-plugin-mocha": "^10.1.0",
10581060
"execa": "^1.0.0",
1061+
"fork-ts-checker-webpack-plugin": "^9.0.2",
10591062
"glob": "^7.2.3",
10601063
"jest": "^26.6.3",
10611064
"jest-junit": "^12.3.0",
@@ -1071,6 +1074,7 @@
10711074
"node-loader": "^0.6.0",
10721075
"npm-run-all": "^4.1.5",
10731076
"ora": "^5.4.1",
1077+
"path-browserify": "^1.0.1",
10741078
"postcss-loader": "^7.3.3",
10751079
"pre-commit": "^1.2.2",
10761080
"prettier": "^2.8.8",

src/mdbExtensionController.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,5 +696,6 @@ export default class MDBExtensionController implements vscode.Disposable {
696696
this._playgroundController.deactivate();
697697
this._telemetryService.deactivate();
698698
this._editorsController.deactivate();
699+
this._webviewController.deactivate();
699700
}
700701
}

src/test/suite/views/webview-app/app.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@ describe('App Component Test Suite', () => {
1616
test('it renders the new overview page when useNewConnectionForm is truthy', () => {
1717
sinon.stub(featureFlags, 'getFeatureFlag').returns(true);
1818
render(<App />);
19-
expect(() => screen.getAllByTestId('legacy-app')).to.throw;
19+
expect(screen.queryByTestId('legacy-app')).to.be.null;
2020
});
2121
});
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import React from 'react';
2+
import { cleanup, render, screen } from '@testing-library/react';
3+
import AtlasCta from '../../../../views/webview-app/atlas-cta';
4+
import { expect } from 'chai';
5+
import Sinon from 'sinon';
6+
import vscode from '../../../../views/webview-app/vscode-api';
7+
import { MESSAGE_TYPES } from '../../../../views/webview-app/extension-app-message-constants';
8+
9+
describe('AtlasCta test suite', function () {
10+
afterEach(function () {
11+
cleanup();
12+
Sinon.restore();
13+
});
14+
15+
test('it should render Atlas CTA', function () {
16+
render(<AtlasCta />);
17+
expect(screen.getByText('Create free cluster')).to.not.be.null;
18+
expect(screen.getByTestId('link-atlas')).to.not.be.null;
19+
});
20+
21+
test('it should track clicks on MongoDB Atlas link', function () {
22+
const postMessageStub = Sinon.stub(vscode, 'postMessage');
23+
render(<AtlasCta />);
24+
screen.getByTestId('link-atlas').click();
25+
expect(postMessageStub).to.be.calledWithExactly({
26+
command: MESSAGE_TYPES.EXTENSION_LINK_CLICKED,
27+
screen: 'overviewPage',
28+
linkId: 'atlasLanding',
29+
});
30+
});
31+
32+
test('when clicked on "Create free cluster" button, it should open create account page on atlas and also track the link', function () {
33+
const postMessageStub = Sinon.stub(vscode, 'postMessage');
34+
render(<AtlasCta />);
35+
screen.getByText('Create free cluster').click();
36+
expect(postMessageStub).calledTwice;
37+
expect(postMessageStub.firstCall.args[0].command).to.equal(
38+
MESSAGE_TYPES.OPEN_TRUSTED_LINK
39+
);
40+
expect(postMessageStub.secondCall.args[0].command).to.equal(
41+
MESSAGE_TYPES.EXTENSION_LINK_CLICKED
42+
);
43+
});
44+
});
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import React from 'react';
2+
import { expect } from 'chai';
3+
import { render, screen } from '@testing-library/react';
4+
import ConnectHelper from '../../../../views/webview-app/connect-helper';
5+
import Sinon from 'sinon';
6+
import vscode from '../../../../views/webview-app/vscode-api';
7+
import { MESSAGE_TYPES } from '../../../../views/webview-app/extension-app-message-constants';
8+
9+
describe('ConnectHelper test suite', function () {
10+
test('when rendered it should show both connection options', function () {
11+
render(<ConnectHelper />);
12+
expect(screen.getByLabelText('Connect with connection string')).to.not.be
13+
.null;
14+
expect(screen.getByLabelText('Open connection form')).to.not.be.null;
15+
});
16+
17+
test('when connecting with string, it should call vscode to open connection string input', function () {
18+
const postMessageStub = Sinon.stub(vscode, 'postMessage');
19+
render(<ConnectHelper />);
20+
screen.getByLabelText('Connect with connection string').click();
21+
expect(postMessageStub).to.have.been.calledWithExactly({
22+
command: MESSAGE_TYPES.OPEN_CONNECTION_STRING_INPUT,
23+
});
24+
});
25+
26+
test.skip('when clicked on open connection form, it should open connection form', function () {
27+
// TODO(VSCODE-488)
28+
});
29+
});
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import Sinon from 'sinon';
2+
import { expect } from 'chai';
3+
import * as React from 'react';
4+
import { act, cleanup, render, screen } from '@testing-library/react';
5+
import ConnectionStatus from '../../../../views/webview-app/connection-status';
6+
import {
7+
CONNECTION_STATUS,
8+
MESSAGE_TYPES,
9+
} from '../../../../views/webview-app/extension-app-message-constants';
10+
import vscode from '../../../../views/webview-app/vscode-api';
11+
12+
describe('ConnectionStatus test suite', function () {
13+
afterEach(function () {
14+
cleanup();
15+
Sinon.restore();
16+
});
17+
18+
test('it should show a loading status by default', function () {
19+
render(<ConnectionStatus />);
20+
expect(screen.getByText('Loading...')).to.not.be.null;
21+
});
22+
23+
test('it should periodically request connection status', function () {
24+
const postMessageStub = Sinon.stub(vscode, 'postMessage');
25+
render(<ConnectionStatus />);
26+
expect(postMessageStub).to.have.been.calledWithExactly({
27+
command: MESSAGE_TYPES.GET_CONNECTION_STATUS,
28+
});
29+
});
30+
31+
describe('when GET_CONNECTION_STATUS gets responded with a disconnecting state', function () {
32+
test('it should show a disconnecting status', function () {
33+
render(<ConnectionStatus />);
34+
act(() => {
35+
window.dispatchEvent(
36+
new MessageEvent('message', {
37+
data: {
38+
command: MESSAGE_TYPES.CONNECTION_STATUS_MESSAGE,
39+
connectionStatus: CONNECTION_STATUS.DISCONNECTING,
40+
activeConnectionName: '',
41+
},
42+
})
43+
);
44+
});
45+
expect(screen.getByText('Disconnecting...')).to.not.be.null;
46+
});
47+
});
48+
49+
describe('when GET_CONNECTION_STATUS gets responded with a disconnected state', function () {
50+
test('it should show a disconnected status', function () {
51+
render(<ConnectionStatus />);
52+
act(() => {
53+
window.dispatchEvent(
54+
new MessageEvent('message', {
55+
data: {
56+
command: MESSAGE_TYPES.CONNECTION_STATUS_MESSAGE,
57+
connectionStatus: CONNECTION_STATUS.DISCONNECTED,
58+
activeConnectionName: '',
59+
},
60+
})
61+
);
62+
});
63+
expect(screen.getByText('Not connected.')).to.not.be.null;
64+
});
65+
});
66+
67+
describe('when GET_CONNECTION_STATUS gets responded with a connecting state', function () {
68+
test('it should show a connecting status', function () {
69+
render(<ConnectionStatus />);
70+
act(() => {
71+
window.dispatchEvent(
72+
new MessageEvent('message', {
73+
data: {
74+
command: MESSAGE_TYPES.CONNECTION_STATUS_MESSAGE,
75+
connectionStatus: CONNECTION_STATUS.CONNECTING,
76+
activeConnectionName: '',
77+
},
78+
})
79+
);
80+
});
81+
expect(screen.getByText('Connecting...')).to.not.be.null;
82+
});
83+
});
84+
85+
describe('when GET_CONNECTION_STATUS gets responded with a connected state', function () {
86+
beforeEach(function () {
87+
render(<ConnectionStatus />);
88+
act(() => {
89+
window.dispatchEvent(
90+
new MessageEvent('message', {
91+
data: {
92+
command: MESSAGE_TYPES.CONNECTION_STATUS_MESSAGE,
93+
connectionStatus: CONNECTION_STATUS.CONNECTED,
94+
activeConnectionName: 'vscode-connection',
95+
},
96+
})
97+
);
98+
});
99+
});
100+
101+
test('it should show a connected status', function () {
102+
expect(screen.getByText('Connected to:')).to.not.be.null;
103+
expect(screen.getByText('vscode-connection')).to.not.be.null;
104+
});
105+
106+
test('it should allow editing the name of the connection', function () {
107+
const postMessageStub = Sinon.stub(vscode, 'postMessage');
108+
screen.getByLabelText('Rename connection').click();
109+
110+
expect(postMessageStub).to.be.calledWithExactly({
111+
command: MESSAGE_TYPES.RENAME_ACTIVE_CONNECTION,
112+
});
113+
});
114+
115+
test('it should allow creating new playground', function () {
116+
const postMessageStub = Sinon.stub(vscode, 'postMessage');
117+
screen.getByLabelText('Create playground').click();
118+
119+
expect(postMessageStub).to.be.calledWithExactly({
120+
command: MESSAGE_TYPES.CREATE_NEW_PLAYGROUND,
121+
});
122+
});
123+
});
124+
});

src/test/suite/views/webview-app/jest-setup.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
const Enzyme = require('enzyme');
55
const Adapter = require('@wojtekmaj/enzyme-adapter-react-17');
6+
const chai = require('chai');
7+
chai.use(require('sinon-chai'));
68
Enzyme.configure({ adapter: new Adapter() });
79

810
// eslint-disable-next-line no-undef
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import React from 'react';
2+
import { expect } from 'chai';
3+
import { cleanup, render, screen } from '@testing-library/react';
4+
import OverviewPage from '../../../../views/webview-app/overview-page';
5+
6+
describe('OverviewPage test suite', function () {
7+
afterEach(cleanup);
8+
test('it should render OverviewPage', function () {
9+
render(<OverviewPage />);
10+
expect(
11+
screen.getByText(
12+
'Navigate your databases and collections, use playgrounds for exploring and transforming your data'
13+
)
14+
).to.exist;
15+
});
16+
17+
test('on click of resources, it should open resources panel', function () {
18+
render(<OverviewPage />);
19+
screen.getByText('Resources').click();
20+
expect(screen.getByText('Product overview')).to.exist;
21+
});
22+
23+
test('on click of close button on resources panel, it should close resources panel', function () {
24+
render(<OverviewPage />);
25+
screen.getByText('Resources').click();
26+
screen.getByLabelText('Close').click();
27+
expect(screen.queryByText('Product overview')).to.be.null;
28+
});
29+
});
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import Sinon from 'sinon';
2+
import { expect } from 'chai';
3+
import * as React from 'react';
4+
import { cleanup, render, screen } from '@testing-library/react';
5+
import ResourcesPanel, {
6+
TELEMETRY_SCREEN_ID,
7+
} from '../../../../views/webview-app/resources-panel/panel';
8+
import { MESSAGE_TYPES } from '../../../../views/webview-app/extension-app-message-constants';
9+
import vscode from '../../../../views/webview-app/vscode-api';
10+
11+
describe('Resources panel test suite', function () {
12+
afterEach(function () {
13+
cleanup();
14+
});
15+
16+
test('it should render resources panel', function () {
17+
render(<ResourcesPanel onClose={() => {}} />);
18+
expect(() => screen.getByLabelText('Close')).to.not.throw;
19+
expect(screen.getAllByTestId(/link-\w+/)).to.have.length.greaterThan(0);
20+
expect(
21+
screen.getAllByTestId(/footer-feature-\w+/)
22+
).to.have.length.greaterThan(0);
23+
expect(screen.getAllByTestId(/footer-link-\w+/)).to.have.length.greaterThan(
24+
0
25+
);
26+
});
27+
28+
test('it should call onClose on close btn click', function () {
29+
const onCloseFake = Sinon.fake();
30+
render(<ResourcesPanel onClose={onCloseFake} />);
31+
screen.getByLabelText('Close').click();
32+
expect(onCloseFake).to.have.been.calledOnce;
33+
});
34+
35+
test('it should track link clicked event on click of any link', function () {
36+
const postMessageStub = Sinon.stub(vscode, 'postMessage');
37+
render(<ResourcesPanel onClose={() => {}} />);
38+
screen.getAllByTestId(/^link-\w+/).forEach((link) => {
39+
link.click();
40+
expect(postMessageStub).to.have.been.calledWithExactly({
41+
command: MESSAGE_TYPES.EXTENSION_LINK_CLICKED,
42+
screen: TELEMETRY_SCREEN_ID,
43+
linkId: link.getAttribute('data-testid')?.replace('link-', ''),
44+
});
45+
});
46+
47+
screen.getAllByTestId(/^footer-feature-\w+/).forEach((link) => {
48+
link.click();
49+
expect(postMessageStub).to.have.been.calledWithExactly({
50+
command: MESSAGE_TYPES.EXTENSION_LINK_CLICKED,
51+
screen: TELEMETRY_SCREEN_ID,
52+
linkId: link
53+
.getAttribute('data-testid')
54+
?.replace('footer-feature-', ''),
55+
});
56+
});
57+
58+
screen.getAllByTestId(/^footer-link-\w+/).forEach((link) => {
59+
link.click();
60+
expect(postMessageStub).to.have.been.calledWithExactly({
61+
command: MESSAGE_TYPES.EXTENSION_LINK_CLICKED,
62+
screen: TELEMETRY_SCREEN_ID,
63+
linkId: link.getAttribute('data-testid')?.replace('footer-link-', ''),
64+
});
65+
});
66+
});
67+
});

0 commit comments

Comments
 (0)