Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

De-13:direct navigate in single resolution #1316

Closed
wants to merge 10 commits into from
1 change: 1 addition & 0 deletions src/__mocks__/handlers/ResourceEditor/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,7 @@ const getSearchApiResponseObject = rest.get(

export {
resourceResolverApi,
resourceResolverApiId,
resourceFromSearchApiId,
resourceFromSearchApi,
getResolverResponseObject,
Expand Down
18 changes: 17 additions & 1 deletion src/shared/components/ResourceEditor/ResourceEditor.less
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,30 @@
}

.code-mirror-editor {
.fusion-resource-link {
text-decoration: underline;
cursor: pointer;
&::after {
content: '';
display: inline-block;
background-image: url(../../images/AnchorLink.svg);
background-repeat: no-repeat;
background-size: 14px 14px;
width: 14px;
height: 14px;
margin-left: 10px;
}
}
.CodeMirror-lines {
cursor: text;
}

&.resolution-on-progress {
.CodeMirror-lines {
cursor: progress !important;
user-select: none;
.fusion-resource-link {
cursor: progress !important;
}
}
}
}
148 changes: 76 additions & 72 deletions src/shared/components/ResourceEditor/editorUtils.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import '@testing-library/jest-dom';
import React from 'react';
import { resolveLinkInEditor, getNormalizedTypes } from './editorUtils';
import { getNormalizedTypes, editorLinkResolutionHandler } from './editorUtils';
import { Provider } from 'react-redux';
import { createMemoryHistory } from 'history';
import { NexusClient, createNexusClient } from '@bbp/nexus-sdk';
Expand All @@ -12,19 +12,37 @@ import { AnyAction, Store } from 'redux';
import { QueryClientProvider, QueryClient } from 'react-query';
import { setupServer } from 'msw/node';
import {
resourceResolverApi,
resourceFromSearchApiId,
resourceFromSearchApi,
getResolverResponseObject,
getSearchApiResponseObject,
} from '../../../__mocks__/handlers/ResourceEditor/handlers';
import { getResourceLabel } from '../../utils';
import {
getOrgAndProjectFromResourceObject,
getResourceLabel,
} from '../../utils';
import { render, screen, waitFor, act, cleanup } from '../../../utils/testUtil';
render,
screen,
waitFor,
cleanup,
RenderResult,
} from '../../../utils/testUtil';
import ResolvedLinkEditorPopover from '../../molecules/ResolvedLinkEditorPopover/ResolvedLinkEditorPopover';
import { UISettingsActionTypes } from 'shared/store/actions/ui-settings';

document.createRange = () => {
const range = new Range();

range.getBoundingClientRect = jest.fn();

range.getClientRects = () => {
return {
item: () => null,
length: 0,
[Symbol.iterator]: jest.fn(),
};
};

return range;
};
describe('getNormalizedTypes', () => {
const typesAsString = 'Resource';
it('should return the normalized types', () => {
Expand Down Expand Up @@ -64,12 +82,15 @@ describe('resolveLinkInEditor', () => {
const defaultPaylaod = { top: 0, left: 0, open: true };
let nexus: NexusClient;
let TestApp: JSX.Element;
let component: RenderResult;
let rerender: (ui: React.ReactElement) => void;

beforeAll(() => {
server = setupServer(getResolverResponseObject, getSearchApiResponseObject);
server.listen();
});

beforeAll(async () => {
beforeEach(async () => {
const history = createMemoryHistory({});
nexus = createNexusClient({
fetch,
Expand All @@ -87,89 +108,67 @@ describe('resolveLinkInEditor', () => {
</QueryClientProvider>
</Provider>
);
component = render(TestApp);
rerender = component.rerender;
});
beforeEach(async () => {
await act(async () => {
await render(TestApp);
});
});

afterEach(async () => {
cleanup();
});
afterAll(() => {
server.resetHandlers();
server.close();
});
// case-0: the url is not valid
// case-resource: can not be tested since codemirror issue and redirection
// case-error: link can not be resolved by the project resolver nor the search api and it's not external
it('should return null if the url is not valid', async () => {
const url = 'not a valid url';
const result = await resolveLinkInEditor({
const url = 'https://bbp.epfl.ch/nexus/v1/resources/bbp/lnmce/invalid';
const { resolvedAs, error, results } = await editorLinkResolutionHandler({
nexus,
url,
defaultPaylaod,
dispatch: store.dispatch,
orgLabel: 'orgLabel',
projectLabel: 'projectLabel',
});
store.dispatch({
type: UISettingsActionTypes.UPDATE_JSON_EDITOR_POPOVER,
payload: {
...defaultPaylaod,
resolvedAs,
error,
results,
},
});
rerender(TestApp);
expect(
store.getState().uiSettings.editorPopoverResolvedData.results.length
).toEqual(0);
store.getState().uiSettings.editorPopoverResolvedData.results
).toBeUndefined();
expect(
store.getState().uiSettings.editorPopoverResolvedData.resolvedAs
).toBeUndefined();
expect(result).toBeNull();
});
// case-1: url is valid and link resolved by the project resolver
it('should show popover when the link is resolved by the project resolver if the url is valid', async () => {
const orgProject = getOrgAndProjectFromResourceObject(resourceResolverApi);
const name = getResourceLabel(resourceResolverApi);
await waitFor(async () => {
await resolveLinkInEditor({
nexus,
defaultPaylaod: { ...defaultPaylaod, top: 400, left: 400 },
url: resourceResolverApi['@id'],
dispatch: store.dispatch,
orgLabel: orgProject?.orgLabel,
projectLabel: orgProject?.projectLabel,
});
expect(
store.getState().uiSettings.editorPopoverResolvedData.results
).toBeDefined();
expect(
store.getState().uiSettings.editorPopoverResolvedData.results._self
).toEqual(resourceResolverApi._self);
expect(
store.getState().uiSettings.editorPopoverResolvedData.resolvedAs
).toBe('resource');
expect(
store.getState().uiSettings.editorPopoverResolvedData.error
).toBeNull();
});
await waitFor(
async () => {
const nameMatch = new RegExp(name, 'i');
const nameInScreen = await screen.findByText(nameMatch);
expect(nameInScreen).toBeInTheDocument();
},
{ timeout: 3000 }
);
).toEqual('error');
});
// case-2: link can not be resolved by the project resolver
// then try to find it across all projects
it('should show popover when the link is resolved by search api and resolver can not resolve it if the url is valid', async () => {
// case-resources: link can be resolved by search api and has multiple results
it('should show popover when the link is resolved by search api with multiple results', async () => {
const orgProject = {
orgLabel: 'bbp',
projectLabel: 'lnmce',
};
await waitFor(async () => {
await resolveLinkInEditor({
const { resolvedAs, error, results } = await editorLinkResolutionHandler({
nexus,
defaultPaylaod: { ...defaultPaylaod, top: 400, left: 400 },
url: resourceFromSearchApiId,
dispatch: store.dispatch,
orgLabel: orgProject.orgLabel,
projectLabel: orgProject.projectLabel,
orgLabel: orgProject?.orgLabel,
projectLabel: orgProject?.projectLabel,
});
store.dispatch({
type: UISettingsActionTypes.UPDATE_JSON_EDITOR_POPOVER,
payload: {
...defaultPaylaod,
resolvedAs,
error,
results,
},
});
rerender(TestApp);
expect(
store.getState().uiSettings.editorPopoverResolvedData.results
).toBeDefined();
Expand All @@ -194,18 +193,26 @@ describe('resolveLinkInEditor', () => {
}
});
});
// case-3: link can not be resolved by the project resolver and search api and it's an external link
it('shoudl show popover when external link is provided', async () => {
// case-external: link can not be resolved by the project resolver nor the search api and it's external
it('should show popover when external link is provided', async () => {
const url = 'ftp://www.google.com';
await waitFor(async () => {
await resolveLinkInEditor({
const { resolvedAs, error, results } = await editorLinkResolutionHandler({
nexus,
url,
defaultPaylaod: { ...defaultPaylaod, top: 400, left: 400 },
dispatch: store.dispatch,
orgLabel: 'orgLabel',
projectLabel: 'projectLabel',
});
store.dispatch({
type: UISettingsActionTypes.UPDATE_JSON_EDITOR_POPOVER,
payload: {
...defaultPaylaod,
resolvedAs,
error,
results,
},
});
rerender(TestApp);
expect(
store.getState().uiSettings.editorPopoverResolvedData.results._self
).toEqual(url);
Expand All @@ -216,8 +223,5 @@ describe('resolveLinkInEditor', () => {
store.getState().uiSettings.editorPopoverResolvedData.error
).toBeUndefined();
});
const urlMatch = new RegExp(url, 'i');
const urlInScreen = await screen.findByText(urlMatch);
expect(urlInScreen).toBeInTheDocument();
});
});
Loading