Skip to content

Commit

Permalink
add unit tests for workspace core service (opensearch-project#191) (o…
Browse files Browse the repository at this point in the history
…pensearch-project#197)

rename workspace service class name and types

---------

Signed-off-by: Yulong Ruan <ruanyl@amazon.com>
  • Loading branch information
ruanyl committed Sep 25, 2023
1 parent e3b7da3 commit ecff529
Show file tree
Hide file tree
Showing 20 changed files with 186 additions and 46 deletions.
6 changes: 3 additions & 3 deletions src/core/public/application/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ import { IUiSettingsClient } from '../ui_settings';
import { SavedObjectsStart } from '../saved_objects';
import { AppCategory } from '../../types';
import { ScopedHistory } from './scoped_history';
import { WorkspaceStart } from '../workspace';
import { WorkspacesStart } from '../workspace';

/**
* Accessibility status of an application.
Expand Down Expand Up @@ -345,8 +345,8 @@ export interface AppMountContext {
injectedMetadata: {
getInjectedVar: (name: string, defaultValue?: any) => unknown;
};
/** {@link WorkspaceService} */
workspaces: WorkspaceStart;
/** {@link WorkspacesService} */
workspaces: WorkspacesStart;
};
}

Expand Down
4 changes: 2 additions & 2 deletions src/core/public/chrome/chrome_service.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import { ChromeNavLinks, NavLinksService, ChromeNavLink } from './nav_links';
import { ChromeRecentlyAccessed, RecentlyAccessedService } from './recently_accessed';
import { Header } from './ui';
import { ChromeHelpExtensionMenuLink } from './ui/header/header_help_menu';
import { Branding, WorkspaceStart } from '../';
import { Branding, WorkspacesStart } from '../';
import { getLogos } from '../../common';
import type { Logos } from '../../common/types';

Expand Down Expand Up @@ -96,7 +96,7 @@ interface StartDeps {
injectedMetadata: InjectedMetadataStart;
notifications: NotificationsStart;
uiSettings: IUiSettingsClient;
workspaces: WorkspaceStart;
workspaces: WorkspacesStart;
}

/** @internal */
Expand Down
4 changes: 2 additions & 2 deletions src/core/public/chrome/ui/header/collapsible_nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import { groupBy, sortBy } from 'lodash';
import React, { useRef } from 'react';
import useObservable from 'react-use/lib/useObservable';
import * as Rx from 'rxjs';
import { WorkspaceStart } from 'opensearch-dashboards/public';
import { WorkspacesStart } from 'opensearch-dashboards/public';
import { ChromeNavLink, ChromeRecentlyAccessedHistoryItem } from '../..';
import { AppCategory } from '../../../../types';
import { InternalApplicationStart } from '../../../application';
Expand Down Expand Up @@ -132,7 +132,7 @@ interface Props {
navigateToUrl: InternalApplicationStart['navigateToUrl'];
customNavLink$: Rx.Observable<ChromeNavLink | undefined>;
logos: Logos;
workspaces: WorkspaceStart;
workspaces: WorkspacesStart;
}

export function CollapsibleNav({
Expand Down
4 changes: 2 additions & 2 deletions src/core/public/chrome/ui/header/collapsible_nav_header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import { i18n } from '@osd/i18n';
import React from 'react';
import useObservable from 'react-use/lib/useObservable';
import { EuiIcon, EuiFlexGroup, EuiFlexItem, EuiText, EuiCollapsibleNavGroup } from '@elastic/eui';
import { WorkspaceStart } from '../../../../public';
import { WorkspacesStart } from '../../../../public';

interface Props {
workspaces: WorkspaceStart;
workspaces: WorkspacesStart;
}

export function CollapsibleNavHeader({ workspaces }: Props) {
Expand Down
4 changes: 2 additions & 2 deletions src/core/public/chrome/ui/header/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import classnames from 'classnames';
import React, { createRef, useState } from 'react';
import useObservable from 'react-use/lib/useObservable';
import { Observable } from 'rxjs';
import { WorkspaceStart } from 'opensearch-dashboards/public';
import { WorkspacesStart } from 'opensearch-dashboards/public';
import { LoadingIndicator } from '../';
import {
ChromeBadge,
Expand Down Expand Up @@ -94,7 +94,7 @@ export interface HeaderProps {
branding: ChromeBranding;
logos: Logos;
survey: string | undefined;
workspaces: WorkspaceStart;
workspaces: WorkspacesStart;
}

export function Header({
Expand Down
9 changes: 9 additions & 0 deletions src/core/public/core_system.test.mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import { docLinksServiceMock } from './doc_links/doc_links_service.mock';
import { renderingServiceMock } from './rendering/rendering_service.mock';
import { contextServiceMock } from './context/context_service.mock';
import { integrationsServiceMock } from './integrations/integrations_service.mock';
import { workspacesServiceMock } from './workspace/workspaces_service.mock';
import { coreAppMock } from './core_app/core_app.mock';

export const MockInjectedMetadataService = injectedMetadataServiceMock.create();
Expand Down Expand Up @@ -145,3 +146,11 @@ export const CoreAppConstructor = jest.fn().mockImplementation(() => MockCoreApp
jest.doMock('./core_app', () => ({
CoreApp: CoreAppConstructor,
}));

export const MockWorkspacesService = workspacesServiceMock.create();
export const WorkspacesServiceConstructor = jest
.fn()
.mockImplementation(() => MockWorkspacesService);
jest.doMock('./workspace', () => ({
WorkspacesService: WorkspacesServiceConstructor,
}));
25 changes: 25 additions & 0 deletions src/core/public/core_system.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ import {
MockIntegrationsService,
CoreAppConstructor,
MockCoreApp,
WorkspacesServiceConstructor,
MockWorkspacesService,
} from './core_system.test.mocks';

import { CoreSystem } from './core_system';
Expand Down Expand Up @@ -99,6 +101,7 @@ describe('constructor', () => {
expect(RenderingServiceConstructor).toHaveBeenCalledTimes(1);
expect(IntegrationsServiceConstructor).toHaveBeenCalledTimes(1);
expect(CoreAppConstructor).toHaveBeenCalledTimes(1);
expect(WorkspacesServiceConstructor).toHaveBeenCalledTimes(1);
});

it('passes injectedMetadata param to InjectedMetadataService', () => {
Expand Down Expand Up @@ -223,6 +226,11 @@ describe('#setup()', () => {
expect(MockIntegrationsService.setup).toHaveBeenCalledTimes(1);
});

it('calls workspaces#setup()', async () => {
await setupCore();
expect(MockWorkspacesService.setup).toHaveBeenCalledTimes(1);
});

it('calls coreApp#setup()', async () => {
await setupCore();
expect(MockCoreApp.setup).toHaveBeenCalledTimes(1);
Expand Down Expand Up @@ -310,6 +318,15 @@ describe('#start()', () => {
expect(MockIntegrationsService.start).toHaveBeenCalledTimes(1);
});

it('calls workspaces#start()', async () => {
await startCore();
expect(MockWorkspacesService.start).toHaveBeenCalledTimes(1);
expect(MockWorkspacesService.start).toHaveBeenCalledWith({
application: expect.any(Object),
http: expect.any(Object),
});
});

it('calls coreApp#start()', async () => {
await startCore();
expect(MockCoreApp.start).toHaveBeenCalledTimes(1);
Expand Down Expand Up @@ -364,6 +381,14 @@ describe('#stop()', () => {
expect(MockIntegrationsService.stop).toHaveBeenCalled();
});

it('calls workspaces.stop()', () => {
const coreSystem = createCoreSystem();

expect(MockWorkspacesService.stop).not.toHaveBeenCalled();
coreSystem.stop();
expect(MockWorkspacesService.stop).toHaveBeenCalled();
});

it('calls coreApp.stop()', () => {
const coreSystem = createCoreSystem();

Expand Down
7 changes: 4 additions & 3 deletions src/core/public/core_system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ import { ContextService } from './context';
import { IntegrationsService } from './integrations';
import { CoreApp } from './core_app';
import type { InternalApplicationSetup, InternalApplicationStart } from './application/types';
import { WorkspaceService } from './workspace';
import { WorkspacesService } from './workspace';

interface Params {
rootDomElement: HTMLElement;
Expand Down Expand Up @@ -111,7 +111,7 @@ export class CoreSystem {

private readonly rootDomElement: HTMLElement;
private readonly coreContext: CoreContext;
private readonly workspaces: WorkspaceService;
private readonly workspaces: WorkspacesService;
private fatalErrorsSetup: FatalErrorsSetup | null = null;

constructor(params: Params) {
Expand Down Expand Up @@ -140,7 +140,7 @@ export class CoreSystem {
this.rendering = new RenderingService();
this.application = new ApplicationService();
this.integrations = new IntegrationsService();
this.workspaces = new WorkspaceService();
this.workspaces = new WorkspacesService();

this.coreContext = { coreId: Symbol('core'), env: injectedMetadata.env };

Expand Down Expand Up @@ -312,6 +312,7 @@ export class CoreSystem {
this.chrome.stop();
this.i18n.stop();
this.application.stop();
this.workspaces.stop();
this.rootDomElement.textContent = '';
}
}
16 changes: 8 additions & 8 deletions src/core/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ import {
HandlerParameters,
} from './context';
import { Branding } from '../types';
import { WorkspaceStart, WorkspaceSetup } from './workspace';
import { WorkspacesStart, WorkspacesSetup } from './workspace';

export type { Logos } from '../common';
export { PackageInfo, EnvironmentMode } from '../server/types';
Expand Down Expand Up @@ -241,8 +241,8 @@ export interface CoreSetup<TPluginsStart extends object = object, TStart = unkno
};
/** {@link StartServicesAccessor} */
getStartServices: StartServicesAccessor<TPluginsStart, TStart>;
/** {@link WorkspaceSetup} */
workspaces: WorkspaceSetup;
/** {@link WorkspacesSetup} */
workspaces: WorkspacesSetup;
}

/**
Expand Down Expand Up @@ -297,8 +297,8 @@ export interface CoreStart {
getInjectedVar: (name: string, defaultValue?: any) => unknown;
getBranding: () => Branding;
};
/** {@link WorkspaceStart} */
workspaces: WorkspaceStart;
/** {@link WorkspacesStart} */
workspaces: WorkspacesStart;
}

export {
Expand Down Expand Up @@ -349,9 +349,9 @@ export {
export { __osdBootstrap__ } from './osd_bootstrap';

export {
WorkspaceStart,
WorkspaceSetup,
WorkspaceService,
WorkspacesStart,
WorkspacesSetup,
WorkspacesService,
WorkspaceObservables,
} from './workspace';

Expand Down
2 changes: 1 addition & 1 deletion src/core/public/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ function createCoreSetupMock({
getInjectedVar: injectedMetadataServiceMock.createSetupContract().getInjectedVar,
getBranding: injectedMetadataServiceMock.createSetupContract().getBranding,
},
workspaces: workspacesServiceMock,
workspaces: workspacesServiceMock.createSetupContract(),
};

return mock;
Expand Down
2 changes: 1 addition & 1 deletion src/core/public/plugins/plugins_service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ describe('PluginsService', () => {
injectedMetadata: injectedMetadataServiceMock.createStartContract(),
notifications: notificationServiceMock.createSetupContract(),
uiSettings: uiSettingsServiceMock.createSetupContract(),
workspaces: workspacesServiceMock.createSetupContractMock(),
workspaces: workspacesServiceMock.createSetupContract(),
};
mockSetupContext = {
...mockSetupDeps,
Expand Down
6 changes: 3 additions & 3 deletions src/core/public/workspace/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
export {
WorkspaceStart,
WorkspaceService,
WorkspaceSetup,
WorkspacesStart,
WorkspacesService,
WorkspacesSetup,
WorkspaceObservables,
} from './workspaces_service';
13 changes: 12 additions & 1 deletion src/core/public/workspace/workspaces_service.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
*/

import { BehaviorSubject } from 'rxjs';
import type { PublicMethodsOf } from '@osd/utility-types';

import { WorkspacesService } from './workspaces_service';
import { WorkspaceAttribute } from '..';

const currentWorkspaceId$ = new BehaviorSubject<string>('');
Expand All @@ -30,7 +33,15 @@ const createWorkspacesStartContractMock = () => ({
renderWorkspaceMenu: jest.fn(),
});

export type WorkspacesServiceContract = PublicMethodsOf<WorkspacesService>;
const createMock = (): jest.Mocked<WorkspacesServiceContract> => ({
setup: jest.fn().mockReturnValue(createWorkspacesSetupContractMock()),
start: jest.fn().mockReturnValue(createWorkspacesStartContractMock()),
stop: jest.fn(),
});

export const workspacesServiceMock = {
createSetupContractMock: createWorkspacesSetupContractMock,
create: createMock,
createSetupContract: createWorkspacesSetupContractMock,
createStartContract: createWorkspacesStartContractMock,
};
94 changes: 94 additions & 0 deletions src/core/public/workspace/workspaces_service.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { httpServiceMock } from '../http/http_service.mock';
import { applicationServiceMock } from '../application/application_service.mock';
import { WorkspacesService, WorkspacesSetup, WorkspacesStart } from './workspaces_service';

describe('WorkspacesService', () => {
let workspaces: WorkspacesService;
let workspacesSetup: WorkspacesSetup;
let workspacesStart: WorkspacesStart;

beforeEach(() => {
workspaces = new WorkspacesService();
workspacesSetup = workspaces.setup();
workspacesStart = workspaces.start({
http: httpServiceMock.createStartContract(),
application: applicationServiceMock.createInternalStartContract(),
});
});

afterEach(() => {
workspaces.stop();
});

it('workspace initialized$ state is false by default', () => {
expect(workspacesStart.initialized$.value).toBe(false);
});

it('workspace is not enabled by default', () => {
expect(workspacesStart.workspaceEnabled$.value).toBe(false);
});

it('currentWorkspace is not set by default', () => {
expect(workspacesStart.currentWorkspace$.value).toBe(null);
expect(workspacesStart.currentWorkspaceId$.value).toBe('');
});

it('workspaceList$ is empty by default', () => {
expect(workspacesStart.workspaceList$.value.length).toBe(0);
});

it('should call menu render function', () => {
const renderFn = jest.fn();
workspacesSetup.registerWorkspaceMenuRender(renderFn);
workspacesStart.renderWorkspaceMenu();
expect(renderFn).toHaveBeenCalled();
});

it('should return null if NO menu render function was registered', () => {
expect(workspacesStart.renderWorkspaceMenu()).toBe(null);
});

it('the current workspace should also updated after changing current workspace id', () => {
expect(workspacesStart.currentWorkspace$.value).toBe(null);

workspacesStart.initialized$.next(true);
workspacesStart.workspaceList$.next([
{ id: 'workspace-1', name: 'workspace 1' },
{ id: 'workspace-2', name: 'workspace 2' },
]);
workspacesStart.currentWorkspaceId$.next('workspace-1');

expect(workspacesStart.currentWorkspace$.value).toEqual({
id: 'workspace-1',
name: 'workspace 1',
});

workspacesStart.currentWorkspaceId$.next('');
expect(workspacesStart.currentWorkspace$.value).toEqual(null);
});

it('should return error if the specified workspace id cannot be found', () => {
expect(workspacesStart.currentWorkspace$.hasError).toBe(false);
workspacesStart.initialized$.next(true);
workspacesStart.workspaceList$.next([
{ id: 'workspace-1', name: 'workspace 1' },
{ id: 'workspace-2', name: 'workspace 2' },
]);
workspacesStart.currentWorkspaceId$.next('workspace-3');
expect(workspacesStart.currentWorkspace$.hasError).toBe(true);
});

it('should stop all observables when workspace service stopped', () => {
workspaces.stop();
expect(workspacesStart.currentWorkspaceId$.isStopped).toBe(true);
expect(workspacesStart.currentWorkspace$.isStopped).toBe(true);
expect(workspacesStart.workspaceList$.isStopped).toBe(true);
expect(workspacesStart.workspaceEnabled$.isStopped).toBe(true);
expect(workspacesStart.initialized$.isStopped).toBe(true);
});
});
Loading

0 comments on commit ecff529

Please sign in to comment.