Skip to content

Commit e3b0114

Browse files
Merge branch 'master' into func-tests/refactor-dashboard-page
2 parents 3361560 + 9a871d2 commit e3b0114

File tree

25 files changed

+1595
-1480
lines changed

25 files changed

+1595
-1480
lines changed

src/core/public/chrome/chrome_service.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ export class ChromeService {
127127
)
128128
)
129129
);
130-
this.isVisible$ = combineLatest(this.appHidden$, this.toggleHidden$).pipe(
130+
this.isVisible$ = combineLatest([this.appHidden$, this.toggleHidden$]).pipe(
131131
map(([appHidden, toggleHidden]) => !(appHidden || toggleHidden)),
132132
takeUntil(this.stop$)
133133
);
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
import { BehaviorSubject } from 'rxjs';
21+
import { act } from 'react-dom/test-utils';
22+
import { mount } from 'enzyme';
23+
import React from 'react';
24+
25+
import { AppWrapper, AppContainer } from './app_containers';
26+
27+
describe('AppWrapper', () => {
28+
it('toggles the `hidden-chrome` class depending on the chrome visibility state', () => {
29+
const chromeVisible$ = new BehaviorSubject<boolean>(true);
30+
31+
const component = mount(<AppWrapper chromeVisible$={chromeVisible$}>app-content</AppWrapper>);
32+
expect(component.getDOMNode()).toMatchInlineSnapshot(`
33+
<div
34+
class="app-wrapper"
35+
>
36+
app-content
37+
</div>
38+
`);
39+
40+
act(() => chromeVisible$.next(false));
41+
component.update();
42+
expect(component.getDOMNode()).toMatchInlineSnapshot(`
43+
<div
44+
class="app-wrapper hidden-chrome"
45+
>
46+
app-content
47+
</div>
48+
`);
49+
50+
act(() => chromeVisible$.next(true));
51+
component.update();
52+
expect(component.getDOMNode()).toMatchInlineSnapshot(`
53+
<div
54+
class="app-wrapper"
55+
>
56+
app-content
57+
</div>
58+
`);
59+
});
60+
});
61+
62+
describe('AppContainer', () => {
63+
it('adds classes supplied by chrome', () => {
64+
const appClasses$ = new BehaviorSubject<string[]>([]);
65+
66+
const component = mount(<AppContainer classes$={appClasses$}>app-content</AppContainer>);
67+
expect(component.getDOMNode()).toMatchInlineSnapshot(`
68+
<div
69+
class="application"
70+
>
71+
app-content
72+
</div>
73+
`);
74+
75+
act(() => appClasses$.next(['classA', 'classB']));
76+
component.update();
77+
expect(component.getDOMNode()).toMatchInlineSnapshot(`
78+
<div
79+
class="application classA classB"
80+
>
81+
app-content
82+
</div>
83+
`);
84+
85+
act(() => appClasses$.next(['classC']));
86+
component.update();
87+
expect(component.getDOMNode()).toMatchInlineSnapshot(`
88+
<div
89+
class="application classC"
90+
>
91+
app-content
92+
</div>
93+
`);
94+
95+
act(() => appClasses$.next([]));
96+
component.update();
97+
expect(component.getDOMNode()).toMatchInlineSnapshot(`
98+
<div
99+
class="application"
100+
>
101+
app-content
102+
</div>
103+
`);
104+
});
105+
});
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
import React from 'react';
21+
import { Observable } from 'rxjs';
22+
import useObservable from 'react-use/lib/useObservable';
23+
import classNames from 'classnames';
24+
25+
export const AppWrapper: React.FunctionComponent<{
26+
chromeVisible$: Observable<boolean>;
27+
}> = ({ chromeVisible$, children }) => {
28+
const visible = useObservable(chromeVisible$);
29+
return <div className={classNames('app-wrapper', { 'hidden-chrome': !visible })}>{children}</div>;
30+
};
31+
32+
export const AppContainer: React.FunctionComponent<{
33+
classes$: Observable<string[]>;
34+
}> = ({ classes$, children }) => {
35+
const classes = useObservable(classes$);
36+
return <div className={classNames('application', classes)}>{children}</div>;
37+
};

src/core/public/rendering/rendering_service.test.tsx

Lines changed: 103 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -18,72 +18,129 @@
1818
*/
1919

2020
import React from 'react';
21+
import { act } from 'react-dom/test-utils';
2122

22-
import { chromeServiceMock } from '../chrome/chrome_service.mock';
2323
import { RenderingService } from './rendering_service';
24-
import { InternalApplicationStart } from '../application';
24+
import { applicationServiceMock } from '../application/application_service.mock';
25+
import { chromeServiceMock } from '../chrome/chrome_service.mock';
2526
import { injectedMetadataServiceMock } from '../injected_metadata/injected_metadata_service.mock';
2627
import { overlayServiceMock } from '../overlays/overlay_service.mock';
28+
import { BehaviorSubject } from 'rxjs';
2729

2830
describe('RenderingService#start', () => {
29-
const getService = ({ legacyMode = false }: { legacyMode?: boolean } = {}) => {
30-
const rendering = new RenderingService();
31-
const application = {
32-
getComponent: () => <div>Hello application!</div>,
33-
} as InternalApplicationStart;
34-
const chrome = chromeServiceMock.createStartContract();
31+
let application: ReturnType<typeof applicationServiceMock.createInternalStartContract>;
32+
let chrome: ReturnType<typeof chromeServiceMock.createStartContract>;
33+
let overlays: ReturnType<typeof overlayServiceMock.createStartContract>;
34+
let injectedMetadata: ReturnType<typeof injectedMetadataServiceMock.createStartContract>;
35+
let targetDomElement: HTMLDivElement;
36+
let rendering: RenderingService;
37+
38+
beforeEach(() => {
39+
application = applicationServiceMock.createInternalStartContract();
40+
application.getComponent.mockReturnValue(<div>Hello application!</div>);
41+
42+
chrome = chromeServiceMock.createStartContract();
3543
chrome.getHeaderComponent.mockReturnValue(<div>Hello chrome!</div>);
36-
const overlays = overlayServiceMock.createStartContract();
44+
45+
overlays = overlayServiceMock.createStartContract();
3746
overlays.banners.getComponent.mockReturnValue(<div>I&apos;m a banner!</div>);
3847

39-
const injectedMetadata = injectedMetadataServiceMock.createStartContract();
40-
injectedMetadata.getLegacyMode.mockReturnValue(legacyMode);
41-
const targetDomElement = document.createElement('div');
42-
const start = rendering.start({
48+
injectedMetadata = injectedMetadataServiceMock.createStartContract();
49+
50+
targetDomElement = document.createElement('div');
51+
52+
rendering = new RenderingService();
53+
});
54+
55+
const startService = () => {
56+
return rendering.start({
4357
application,
4458
chrome,
4559
injectedMetadata,
4660
overlays,
4761
targetDomElement,
4862
});
49-
return { start, targetDomElement };
5063
};
5164

52-
it('renders application service into provided DOM element', () => {
53-
const { targetDomElement } = getService();
54-
expect(targetDomElement.querySelector('div.application')).toMatchInlineSnapshot(`
55-
<div
56-
class="application"
57-
>
58-
<div>
59-
Hello application!
60-
</div>
61-
</div>
62-
`);
63-
});
65+
describe('standard mode', () => {
66+
beforeEach(() => {
67+
injectedMetadata.getLegacyMode.mockReturnValue(false);
68+
});
6469

65-
it('contains wrapper divs', () => {
66-
const { targetDomElement } = getService();
67-
expect(targetDomElement.querySelector('div.app-wrapper')).toBeDefined();
68-
expect(targetDomElement.querySelector('div.app-wrapper-pannel')).toBeDefined();
69-
});
70+
it('renders application service into provided DOM element', () => {
71+
startService();
72+
expect(targetDomElement.querySelector('div.application')).toMatchInlineSnapshot(`
73+
<div
74+
class="application class-name"
75+
>
76+
<div>
77+
Hello application!
78+
</div>
79+
</div>
80+
`);
81+
});
82+
83+
it('adds the `chrome-hidden` class to the AppWrapper when chrome is hidden', () => {
84+
const isVisible$ = new BehaviorSubject(true);
85+
chrome.getIsVisible$.mockReturnValue(isVisible$);
86+
startService();
87+
88+
const appWrapper = targetDomElement.querySelector('div.app-wrapper')!;
89+
expect(appWrapper.className).toEqual('app-wrapper');
90+
91+
act(() => isVisible$.next(false));
92+
expect(appWrapper.className).toEqual('app-wrapper hidden-chrome');
7093

71-
it('renders the banner UI', () => {
72-
const { targetDomElement } = getService();
73-
expect(targetDomElement.querySelector('#globalBannerList')).toMatchInlineSnapshot(`
74-
<div
75-
id="globalBannerList"
76-
>
77-
<div>
78-
I'm a banner!
79-
</div>
80-
</div>
81-
`);
94+
act(() => isVisible$.next(true));
95+
expect(appWrapper.className).toEqual('app-wrapper');
96+
});
97+
98+
it('adds the application classes to the AppContainer', () => {
99+
const applicationClasses$ = new BehaviorSubject<string[]>([]);
100+
chrome.getApplicationClasses$.mockReturnValue(applicationClasses$);
101+
startService();
102+
103+
const appContainer = targetDomElement.querySelector('div.application')!;
104+
expect(appContainer.className).toEqual('application');
105+
106+
act(() => applicationClasses$.next(['classA', 'classB']));
107+
expect(appContainer.className).toEqual('application classA classB');
108+
109+
act(() => applicationClasses$.next(['classC']));
110+
expect(appContainer.className).toEqual('application classC');
111+
112+
act(() => applicationClasses$.next([]));
113+
expect(appContainer.className).toEqual('application');
114+
});
115+
116+
it('contains wrapper divs', () => {
117+
startService();
118+
expect(targetDomElement.querySelector('div.app-wrapper')).toBeDefined();
119+
expect(targetDomElement.querySelector('div.app-wrapper-pannel')).toBeDefined();
120+
});
121+
122+
it('renders the banner UI', () => {
123+
startService();
124+
expect(targetDomElement.querySelector('#globalBannerList')).toMatchInlineSnapshot(`
125+
<div
126+
id="globalBannerList"
127+
>
128+
<div>
129+
I'm a banner!
130+
</div>
131+
</div>
132+
`);
133+
});
82134
});
83135

84-
describe('legacyMode', () => {
136+
describe('legacy mode', () => {
137+
beforeEach(() => {
138+
injectedMetadata.getLegacyMode.mockReturnValue(true);
139+
});
140+
85141
it('renders into provided DOM element', () => {
86-
const { targetDomElement } = getService({ legacyMode: true });
142+
startService();
143+
87144
expect(targetDomElement).toMatchInlineSnapshot(`
88145
<div>
89146
<div
@@ -100,10 +157,8 @@ describe('RenderingService#start', () => {
100157
});
101158

102159
it('returns a div for the legacy service to render into', () => {
103-
const {
104-
start: { legacyTargetDomElement },
105-
targetDomElement,
106-
} = getService({ legacyMode: true });
160+
const { legacyTargetDomElement } = startService();
161+
107162
expect(targetDomElement.contains(legacyTargetDomElement!)).toBe(true);
108163
});
109164
});

src/core/public/rendering/rendering_service.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { InternalChromeStart } from '../chrome';
2525
import { InternalApplicationStart } from '../application';
2626
import { InjectedMetadataStart } from '../injected_metadata';
2727
import { OverlayStart } from '../overlays';
28+
import { AppWrapper, AppContainer } from './app_containers';
2829

2930
interface StartDeps {
3031
application: InternalApplicationStart;
@@ -65,12 +66,12 @@ export class RenderingService {
6566
{chromeUi}
6667

6768
{!legacyMode && (
68-
<div className="app-wrapper">
69+
<AppWrapper chromeVisible$={chrome.getIsVisible$()}>
6970
<div className="app-wrapper-panel">
7071
<div id="globalBannerList">{bannerUi}</div>
71-
<div className="application">{appUi}</div>
72+
<AppContainer classes$={chrome.getApplicationClasses$()}>{appUi}</AppContainer>
7273
</div>
73-
</div>
74+
</AppWrapper>
7475
)}
7576

7677
{legacyMode && <div ref={legacyRef} />}

0 commit comments

Comments
 (0)