Skip to content

Commit

Permalink
[UI] Always show stackdriver link in GKE (#3167)
Browse files Browse the repository at this point in the history
* [Frontend] snapshot diff setup

* Rename

* Fix test

* Update README about recommended setup

* Change SideNav to load gke metadata from context

* Fix sidenav

* RunDetails page always show stackdriver link

* Fix tests

* Fix test

* Ajust test
  • Loading branch information
Bobgy authored Feb 25, 2020
1 parent 40a887f commit 9998a71
Show file tree
Hide file tree
Showing 9 changed files with 327 additions and 579 deletions.
8 changes: 4 additions & 4 deletions frontend/src/TestUtils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,6 @@ export default class TestUtils {
}
}

export function formatHTML(html: string): string {
return format(html, { parser: 'html' });
}

/**
* Generate diff text for two HTML strings.
* Recommend providing base and update annotations to clarify context in the diff directly.
Expand Down Expand Up @@ -152,3 +148,7 @@ export function diff({
bAnnotation: updateAnnotation,
});
}

function formatHTML(html: string): string {
return format(html, { parser: 'html' });
}
134 changes: 75 additions & 59 deletions frontend/src/components/SideNav.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,22 @@
* limitations under the License.
*/

import { mount, ReactWrapper, shallow, ShallowWrapper } from 'enzyme';
import * as React from 'react';

import SideNav, { css } from './SideNav';
import TestUtils, { diff } from '../TestUtils';
import { MemoryRouter, RouterProps } from 'react-router';
import { GkeMetadataProvider } from 'src/lib/GkeMetadata';
import { Apis } from '../lib/Apis';
import { LocalStorage } from '../lib/LocalStorage';
import { ReactWrapper, ShallowWrapper, shallow } from 'enzyme';
import TestUtils, { diffHTML } from '../TestUtils';
import { RoutePage } from './Router';
import { RouterProps } from 'react-router';
import EnhancedSideNav, { css, SideNav } from './SideNav';

const wideWidth = 1000;
const narrowWidth = 200;
const isCollapsed = (tree: ShallowWrapper<any>) =>
tree.find('WithStyles(IconButton)').hasClass(css.collapsedChevron);
const routerProps: RouterProps = { history: {} as any };
const defaultProps = { ...routerProps, gkeMetadata: {} };

describe('SideNav', () => {
let tree: ReactWrapper | ShallowWrapper;
Expand Down Expand Up @@ -71,69 +72,69 @@ describe('SideNav', () => {
it('renders expanded state', () => {
localStorageHasKeySpy.mockImplementationOnce(() => false);
(window as any).innerWidth = wideWidth;
tree = shallow(<SideNav page={RoutePage.PIPELINES} {...routerProps} />);
tree = shallow(<SideNav page={RoutePage.PIPELINES} {...defaultProps} />);
expect(tree).toMatchSnapshot();
});

it('renders collapsed state', () => {
localStorageHasKeySpy.mockImplementationOnce(() => false);
(window as any).innerWidth = narrowWidth;
tree = shallow(<SideNav page={RoutePage.PIPELINES} {...routerProps} />);
tree = shallow(<SideNav page={RoutePage.PIPELINES} {...defaultProps} />);
expect(tree).toMatchSnapshot();
});

it('renders Pipelines as active page', () => {
tree = shallow(<SideNav page={RoutePage.PIPELINES} {...routerProps} />);
tree = shallow(<SideNav page={RoutePage.PIPELINES} {...defaultProps} />);
expect(tree).toMatchSnapshot();
});

it('renders Pipelines as active when on PipelineDetails page', () => {
tree = shallow(<SideNav page={RoutePage.PIPELINE_DETAILS} {...routerProps} />);
tree = shallow(<SideNav page={RoutePage.PIPELINE_DETAILS} {...defaultProps} />);
expect(tree).toMatchSnapshot();
});

it('renders experiments as active page', () => {
tree = shallow(<SideNav page={RoutePage.EXPERIMENTS} {...routerProps} />);
tree = shallow(<SideNav page={RoutePage.EXPERIMENTS} {...defaultProps} />);
expect(tree).toMatchSnapshot();
});

it('renders experiments as active when on ExperimentDetails page', () => {
tree = shallow(<SideNav page={RoutePage.EXPERIMENT_DETAILS} {...routerProps} />);
tree = shallow(<SideNav page={RoutePage.EXPERIMENT_DETAILS} {...defaultProps} />);
expect(tree).toMatchSnapshot();
});

it('renders experiments as active page when on NewExperiment page', () => {
tree = shallow(<SideNav page={RoutePage.NEW_EXPERIMENT} {...routerProps} />);
tree = shallow(<SideNav page={RoutePage.NEW_EXPERIMENT} {...defaultProps} />);
expect(tree).toMatchSnapshot();
});

it('renders experiments as active page when on Compare page', () => {
tree = shallow(<SideNav page={RoutePage.COMPARE} {...routerProps} />);
tree = shallow(<SideNav page={RoutePage.COMPARE} {...defaultProps} />);
expect(tree).toMatchSnapshot();
});

it('renders experiments as active page when on AllRuns page', () => {
tree = shallow(<SideNav page={RoutePage.RUNS} {...routerProps} />);
tree = shallow(<SideNav page={RoutePage.RUNS} {...defaultProps} />);
expect(tree).toMatchSnapshot();
});

it('renders experiments as active page when on RunDetails page', () => {
tree = shallow(<SideNav page={RoutePage.RUN_DETAILS} {...routerProps} />);
tree = shallow(<SideNav page={RoutePage.RUN_DETAILS} {...defaultProps} />);
expect(tree).toMatchSnapshot();
});

it('renders experiments as active page when on RecurringRunDetails page', () => {
tree = shallow(<SideNav page={RoutePage.RECURRING_RUN} {...routerProps} />);
tree = shallow(<SideNav page={RoutePage.RECURRING_RUN} {...defaultProps} />);
expect(tree).toMatchSnapshot();
});

it('renders experiments as active page when on NewRun page', () => {
tree = shallow(<SideNav page={RoutePage.NEW_RUN} {...routerProps} />);
tree = shallow(<SideNav page={RoutePage.NEW_RUN} {...defaultProps} />);
expect(tree).toMatchSnapshot();
});

it('show jupyterhub link if accessible', () => {
tree = shallow(<SideNav page={RoutePage.COMPARE} {...routerProps} />);
tree = shallow(<SideNav page={RoutePage.COMPARE} {...defaultProps} />);
tree.setState({ jupyterHubAvailable: true });
expect(tree).toMatchSnapshot();
});
Expand All @@ -143,15 +144,15 @@ describe('SideNav', () => {
localStorageHasKeySpy.mockImplementationOnce(() => true);

(window as any).innerWidth = wideWidth;
tree = shallow(<SideNav page={RoutePage.COMPARE} {...routerProps} />);
tree = shallow(<SideNav page={RoutePage.COMPARE} {...defaultProps} />);
expect(isCollapsed(tree)).toBe(true);
});

it('expands if collapse state is false in localStorage', () => {
localStorageIsCollapsedSpy.mockImplementationOnce(() => false);
localStorageHasKeySpy.mockImplementationOnce(() => true);

tree = shallow(<SideNav page={RoutePage.COMPARE} {...routerProps} />);
tree = shallow(<SideNav page={RoutePage.COMPARE} {...defaultProps} />);
expect(isCollapsed(tree)).toBe(false);
});

Expand All @@ -160,7 +161,7 @@ describe('SideNav', () => {
localStorageHasKeySpy.mockImplementationOnce(() => false);

(window as any).innerWidth = narrowWidth;
tree = shallow(<SideNav page={RoutePage.COMPARE} {...routerProps} />);
tree = shallow(<SideNav page={RoutePage.COMPARE} {...defaultProps} />);
expect(isCollapsed(tree)).toBe(true);
});

Expand All @@ -169,7 +170,7 @@ describe('SideNav', () => {
localStorageHasKeySpy.mockImplementationOnce(() => false);

(window as any).innerWidth = wideWidth;
tree = shallow(<SideNav page={RoutePage.COMPARE} {...routerProps} />);
tree = shallow(<SideNav page={RoutePage.COMPARE} {...defaultProps} />);
expect(isCollapsed(tree)).toBe(false);
});

Expand All @@ -178,7 +179,7 @@ describe('SideNav', () => {
localStorageHasKeySpy.mockImplementationOnce(() => false);

(window as any).innerWidth = wideWidth;
tree = shallow(<SideNav page={RoutePage.COMPARE} {...routerProps} />);
tree = shallow(<SideNav page={RoutePage.COMPARE} {...defaultProps} />);
expect(isCollapsed(tree)).toBe(false);

(window as any).innerWidth = narrowWidth;
Expand All @@ -192,7 +193,7 @@ describe('SideNav', () => {
localStorageHasKeySpy.mockImplementationOnce(() => false);

(window as any).innerWidth = narrowWidth;
tree = shallow(<SideNav page={RoutePage.COMPARE} {...routerProps} />);
tree = shallow(<SideNav page={RoutePage.COMPARE} {...defaultProps} />);
expect(isCollapsed(tree)).toBe(true);

(window as any).innerWidth = wideWidth;
Expand All @@ -207,7 +208,7 @@ describe('SideNav', () => {
const spy = jest.spyOn(LocalStorage, 'saveNavbarCollapsed');

(window as any).innerWidth = narrowWidth;
tree = shallow(<SideNav page={RoutePage.COMPARE} {...routerProps} />);
tree = shallow(<SideNav page={RoutePage.COMPARE} {...defaultProps} />);
expect(isCollapsed(tree)).toBe(true);

tree.find('WithStyles(IconButton)').simulate('click');
Expand All @@ -219,7 +220,7 @@ describe('SideNav', () => {
localStorageHasKeySpy.mockImplementationOnce(() => true);

(window as any).innerWidth = wideWidth;
tree = shallow(<SideNav page={RoutePage.COMPARE} {...routerProps} />);
tree = shallow(<SideNav page={RoutePage.COMPARE} {...defaultProps} />);
expect(isCollapsed(tree)).toBe(false);

(window as any).innerWidth = narrowWidth;
Expand All @@ -237,7 +238,7 @@ describe('SideNav', () => {
};
buildInfoSpy.mockImplementationOnce(() => buildInfo);

tree = shallow(<SideNav page={RoutePage.PIPELINES} {...routerProps} />);
tree = shallow(<SideNav page={RoutePage.PIPELINES} {...defaultProps} />);
await TestUtils.flushPromises();
expect(tree).toMatchSnapshot();

Expand All @@ -249,44 +250,59 @@ describe('SideNav', () => {
});
});

it('populates the cluster information using the response from the system endpoints', async () => {
it('populates the cluster information from context', async () => {
const clusterName = 'some-cluster-name';
const projectId = 'some-project-id';

clusterNameSpy.mockImplementationOnce(() => Promise.resolve(clusterName));
projectIdSpy.mockImplementationOnce(() => Promise.resolve(projectId));
buildInfoSpy.mockImplementationOnce(() => Promise.reject('Error when fetching build info'));

tree = shallow(<SideNav page={RoutePage.PIPELINES} {...routerProps} />);
const base = tree.debug();
tree = mount(
<GkeMetadataProvider>
<MemoryRouter>
<EnhancedSideNav page={RoutePage.PIPELINES} {...routerProps} />
</MemoryRouter>
</GkeMetadataProvider>,
);
const base = tree.html();
await TestUtils.flushPromises();
tree.update();
expect(diff({ base, update: tree.debug() })).toMatchInlineSnapshot(`
expect(
diffHTML({
base,
baseAnnotation: 'base',
update: tree.html(),
updateAnnotation: 'after GKE metadata loaded',
}),
).toMatchInlineSnapshot(`
Snapshot Diff:
- Expected
+ Received
- base
+ after GKE metadata loaded
@@ --- --- @@
<WithStyles(IconButton) className="chevron" onClick={[Function: bound _toggleNavClicked]}>
<pure(ChevronLeftIcon) />
</WithStyles(IconButton)>
<path fill="none" d="M0 0h24v24H0z"></path></svg></span
><span class="MuiTouchRipple-root-53"></span>
</button>
</div>
<div className="infoVisible">
+ <WithStyles(Tooltip) title="Cluster name: some-cluster-name, Project ID: some-project-id" enterDelay={300} placement="top-start">
+ <div className="envMetadata">
+ <span>
+ Cluster name:
+ </span>
+ <a href="https://console.cloud.google.com/kubernetes/list?project=some-project-id&filter=name:some-cluster-name" className="link unstyled" rel="noopener" target="_blank">
+ some-cluster-name
+ </a>
+ </div>
+ </WithStyles(Tooltip)>
<WithStyles(Tooltip) title="Report an Issue" enterDelay={300} placement="top-start">
<div className="envMetadata">
<a href="https://github.com/kubeflow/pipelines/issues/new?template=BUG_REPORT.md" className="link unstyled" rel="noopener" target="_blank">
Report an Issue
</a>
<div class="infoVisible">
+ <div
+ class="envMetadata"
+ title="Cluster name: some-cluster-name, Project ID: some-project-id"
+ >
+ <span>Cluster name: </span
+ ><a
+ href="https://console.cloud.google.com/kubernetes/list?project=some-project-id&amp;filter=name:some-cluster-name"
+ class="link unstyled"
+ rel="noopener"
+ target="_blank"
+ >some-cluster-name</a
+ >
+ </div>
<div class="envMetadata" title="Report an Issue">
<a
href="https://github.com/kubeflow/pipelines/issues/new?template=BUG_REPORT.md"
class="link unstyled"
rel="noopener"
`);
});

Expand All @@ -299,7 +315,7 @@ describe('SideNav', () => {
};
buildInfoSpy.mockImplementationOnce(() => buildInfo);

tree = shallow(<SideNav page={RoutePage.PIPELINES} {...routerProps} />);
tree = shallow(<SideNav page={RoutePage.PIPELINES} {...defaultProps} />);
await TestUtils.flushPromises();

expect(tree.state('displayBuildInfo')).toEqual(
Expand All @@ -318,7 +334,7 @@ describe('SideNav', () => {
};
buildInfoSpy.mockImplementationOnce(() => buildInfo);

tree = shallow(<SideNav page={RoutePage.PIPELINES} {...routerProps} />);
tree = shallow(<SideNav page={RoutePage.PIPELINES} {...defaultProps} />);
await TestUtils.flushPromises();

expect(tree.state('displayBuildInfo')).toEqual(
Expand All @@ -338,7 +354,7 @@ describe('SideNav', () => {
};
buildInfoSpy.mockImplementationOnce(() => buildInfo);

tree = shallow(<SideNav page={RoutePage.PIPELINES} {...routerProps} />);
tree = shallow(<SideNav page={RoutePage.PIPELINES} {...defaultProps} />);
await TestUtils.flushPromises();

expect(tree.state('displayBuildInfo')).toEqual(
Expand All @@ -357,7 +373,7 @@ describe('SideNav', () => {
};
buildInfoSpy.mockImplementationOnce(() => buildInfo);

tree = shallow(<SideNav page={RoutePage.PIPELINES} {...routerProps} />);
tree = shallow(<SideNav page={RoutePage.PIPELINES} {...defaultProps} />);
await TestUtils.flushPromises();

expect(tree.state('displayBuildInfo')).toEqual(
Expand All @@ -376,7 +392,7 @@ describe('SideNav', () => {
};
buildInfoSpy.mockImplementationOnce(() => buildInfo);

tree = shallow(<SideNav page={RoutePage.PIPELINES} {...routerProps} />);
tree = shallow(<SideNav page={RoutePage.PIPELINES} {...defaultProps} />);
await TestUtils.flushPromises();

expect(tree.state('displayBuildInfo')).toEqual(
Expand All @@ -389,7 +405,7 @@ describe('SideNav', () => {
it('logs an error if the call getBuildInfo fails', async () => {
TestUtils.makeErrorResponseOnce(buildInfoSpy, 'Uh oh!');

tree = shallow(<SideNav page={RoutePage.PIPELINES} {...routerProps} />);
tree = shallow(<SideNav page={RoutePage.PIPELINES} {...defaultProps} />);
await TestUtils.flushPromises();

expect(tree.state('displayBuildInfo')).toBeUndefined();
Expand Down
Loading

0 comments on commit 9998a71

Please sign in to comment.