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

feat(arcgis): support arcgis content #335

Merged
merged 11 commits into from
Jan 16, 2024
28 changes: 28 additions & 0 deletions __mocks__/@esri/arcgis-rest-portal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const mockContent = {
items: [
{
id: "new-york",
name: "NewYork.slpk",
url: "https://123.com",
created: 123456,
type: "Scene Service",
typeKeywords: "This is a Hosted Service",
title: "New York",
token: "token-https://123.com",
},
{
id: "turanga-library",
name: "TurangaLibrary.slpk",
url: "https://456.com",
created: 123457,
type: "Scene Service",
typeKeywords: "This is a Hosted Service",
title: "Turanga Library",
token: "token-https://456.com",
},
],
};

export const getUserContent = async (authentication) => {
return mockContent;
};
27 changes: 16 additions & 11 deletions __mocks__/@esri/arcgis-rest-request.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
const mockEmailExpected = "[email protected]";
const mockSessionExpected = '{"usermail": "usermail"}';
const mockTokenExpectedPrefix = "token-";

const session = {
usermail: mockEmailExpected,
serialize: () => {
return mockSessionExpected;
},
getUser: async () => {
return { email: mockEmailExpected };
},
getToken: async (url: string) => {
return mockTokenExpectedPrefix + url;
},
};

export class ArcGISIdentityManager {
static beginOAuth2 = async () => {
const session = {
usermail: mockEmailExpected,
serialize: () => {
return mockSessionExpected;
},
getUser: async () => {
return { email: mockEmailExpected };
},
};
return session;
};
static completeOAuth2 = async () => {
Expand All @@ -20,7 +25,7 @@ export class ArcGISIdentityManager {
static destroy = async () => {
return;
};
static deserialize = (session) => {
return { usermail: "usermail" };
static deserialize = () => {
return session;
};
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"dependencies": {
"@esri/arcgis-rest-auth": "^3.7.0",
"@esri/arcgis-rest-request": "^4.2.0",
"@esri/arcgis-rest-portal": "^4.4.0",
"@fortawesome/fontawesome-svg-core": "^1.2.36",
"@fortawesome/free-solid-svg-icons": "^5.15.4",
"@fortawesome/react-fontawesome": "^0.1.17",
Expand Down
4 changes: 3 additions & 1 deletion src/components/common.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,10 @@ export const PanelContent = styled.div`
export const PanelHorizontalLine = styled.div<{
top?: number;
bottom?: number;
left?: number;
right?: number;
}>`
margin: ${({ top = 24, bottom = 16 }) => `${top}px 16px ${bottom}px 16px`};
margin: ${({ top = 24, bottom = 16, left = 16, right = 16 }) => `${top}px ${right}px ${bottom}px ${left}px`};
belom88 marked this conversation as resolved.
Show resolved Hide resolved
border: 1px solid ${({ theme }) => theme.colors.mainHiglightColorInverted};
border-radius: 1px;
background: ${({ theme }) => theme.colors.mainHiglightColorInverted};
Expand Down
21 changes: 20 additions & 1 deletion src/components/expand-icon/expand-icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,17 @@ const IconButton = styled.div<{
}
`;

const IconButtonContainer = styled.div<{
width: number;
height: number;
}>`
display: flex;
justify-content: center;
align-items: center;
width: ${({ width }) => `${width}px`}}
height: ${({ height }) => `${height}px`}}
`;

type ExpandIconProps = {
/** expanded/collapsed */
expandState: ExpandState;
Expand All @@ -56,6 +67,10 @@ type ExpandIconProps = {
fillExpanded?: string;
/** icon color for collapsed state */
fillCollapsed?: string;
/** Width of the icon */
width?: number;
/** Height of the icon */
height?: number;
/** click event handler */
onClick: (e: SyntheticEvent) => void;
};
Expand All @@ -65,6 +80,8 @@ export const ExpandIcon = ({
fillExpanded,
fillCollapsed,
collapseDirection = CollapseDirection.top,
width = 8,
height = 12,
}: ExpandIconProps) => {
return (
<IconButton
Expand All @@ -74,7 +91,9 @@ export const ExpandIcon = ({
fillCollapsed={fillCollapsed}
onClick={onClick}
>
<ChevronIcon />
<IconButtonContainer width={width} height={height}>
<ChevronIcon />
</IconButtonContainer>
</IconButton>
);
};
150 changes: 150 additions & 0 deletions src/components/layers-panel/arcgis-control-panel.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import { renderWithThemeProviders } from "../../utils/testing-utils/render-with-theme";
import { screen, within } from "@testing-library/react";
import { setupStore } from "../../redux/store";
import { ArcGisControlPanel } from "./arcgis-control-panel";
import userEvent from "@testing-library/user-event";
import {
arcGisLogin,
arcGisLogout,
} from "../../redux/slices/arcgis-auth-slice";
import {
getAuthenticatedUser,
arcGisRequestLogin,
arcGisCompleteLogin,
arcGisRequestLogout,
} from "../../utils/arcgis";

jest.mock("../../utils/arcgis");

const getAuthenticatedUserMock =
getAuthenticatedUser as unknown as jest.Mocked<any>;
const arcGisRequestLoginMock =
arcGisRequestLogin as unknown as jest.Mocked<any>;
const arcGisCompleteLoginMock =
arcGisCompleteLogin as unknown as jest.Mocked<any>;
const arcGisRequestLogoutMock =
arcGisRequestLogout as unknown as jest.Mocked<any>;

const EMAIL_EXPECTED = "[email protected]";
let storageUserinfo = "";

const onArcGisImportMock = jest.fn();

const callRender = (renderFunc, props = {}, store = setupStore()) => {
return renderFunc(
<ArcGisControlPanel onArcGisImportClick={onArcGisImportMock} {...props} />,
store
);
};

describe("Layers Control Panel - ArcGIS auth", () => {
beforeAll(() => {
arcGisRequestLoginMock.mockImplementation(async () => {
storageUserinfo = EMAIL_EXPECTED;
return storageUserinfo;
});
arcGisCompleteLoginMock.mockImplementation(async () => {
return storageUserinfo;
});
arcGisRequestLogoutMock.mockImplementation(async () => {
storageUserinfo = "";
return storageUserinfo;
});
getAuthenticatedUserMock.mockImplementation(() => {
return storageUserinfo;
});
});

it("Should render ArcGIS Login button", async () => {
const store = setupStore();
// Let's Log out...
await store.dispatch(arcGisLogout());
const { container } = callRender(
renderWithThemeProviders,
undefined,
store
);
expect(container).toBeInTheDocument();
expect(arcGisRequestLogoutMock).toHaveBeenCalledTimes(1);

// We are in the "Logged out" state, so the "Log in" button should be there.
const loginButton = await screen.findByText("Login to ArcGIS");
expect(loginButton).toBeInTheDocument();
loginButton && userEvent.click(loginButton);
expect(arcGisRequestLoginMock).toHaveBeenCalledTimes(1);

const importButton = screen.queryByText("Import from ArcGIS");
expect(importButton).not.toBeInTheDocument();
});

it("Should render ArcGIS Import and Logout buttons", async () => {
const store = setupStore();
// Let's Log in...
await store.dispatch(arcGisLogin());
const { container } = callRender(
renderWithThemeProviders,
undefined,
store
);
expect(container).toBeInTheDocument();
expect(arcGisRequestLoginMock).toHaveBeenCalledTimes(1);

// We are in the "Logged in" state, so the "Log in" button should NOT be there.
const importButton = await screen.findByText("Import from ArcGIS");
expect(importButton).toBeInTheDocument();

const logoutUserInfo = await screen.findByText(EMAIL_EXPECTED);
expect(logoutUserInfo).toBeInTheDocument();

const loginButton = screen.queryByText("Login to ArcGIS");
expect(loginButton).not.toBeInTheDocument();
});

it("Should respond to action on the ArcGIS Login button", async () => {
const store = setupStore();
// Let's Log out...
await store.dispatch(arcGisLogout());
const { container } = callRender(
renderWithThemeProviders,
undefined,
store
);
expect(container).toBeInTheDocument();

const loginButton = screen.getByText("Login to ArcGIS");
loginButton && userEvent.click(loginButton);
expect(arcGisRequestLoginMock).toHaveBeenCalledTimes(1);

const importButton = await screen.findByText("Import from ArcGIS");
expect(importButton).toBeInTheDocument();

const loginButtonHidden = screen.queryByText("Login to ArcGIS");
expect(loginButtonHidden).not.toBeInTheDocument();
});

it("Should respond to action on ArcGIS Logout button", async () => {
const store = setupStore();
// Let's Log in...
await store.dispatch(arcGisLogin());
callRender(
renderWithThemeProviders,
undefined,
store
);

const logoutButton = await screen.findByTestId("userinfo-button");
logoutButton && userEvent.click(logoutButton);

const modalDialog = await screen.findByTestId("modal-dialog-content");
expect(modalDialog).toContainHTML("Are you sure you want to log out?");

const cancelButton = within(modalDialog).getByText("Log out");
cancelButton && userEvent.click(cancelButton);

const modalDialogHidden = screen.queryByTestId("modal-dialog-content");
expect(modalDialogHidden).not.toBeInTheDocument();

const loginButton = await screen.findByText("Login to ArcGIS");
expect(loginButton).toBeInTheDocument();
});
});
Loading