@jpmorganchase/elemental 1.0.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. package/__fixtures__/api-descriptions/Instagram.d.ts +1547 -0
  2. package/__fixtures__/api-descriptions/badgesForSchema.d.ts +1 -0
  3. package/__fixtures__/api-descriptions/simpleApiWithInternalOperations.d.ts +224 -0
  4. package/__fixtures__/api-descriptions/simpleApiWithoutDescription.d.ts +212 -0
  5. package/__fixtures__/api-descriptions/todosApiBundled.d.ts +1 -0
  6. package/__fixtures__/api-descriptions/zoomApiYaml.d.ts +1 -0
  7. package/components/API/APIWithSidebarLayout.d.ts +17 -0
  8. package/components/API/APIWithStackedLayout.d.ts +15 -0
  9. package/components/API/utils.d.ts +18 -0
  10. package/containers/API.d.ts +23 -0
  11. package/containers/API.spec.d.ts +3 -0
  12. package/containers/API.stories.d.ts +57 -0
  13. package/hooks/useExportDocumentProps.d.ts +11 -0
  14. package/hooks/useExportDocumentProps.spec.d.ts +1 -0
  15. package/index.esm.js +516 -0
  16. package/index.js +549 -0
  17. package/index.mjs +516 -0
  18. package/package.json +17 -76
  19. package/styles.min.css +1 -0
  20. package/utils/oas/index.d.ts +3 -0
  21. package/utils/oas/oas2.d.ts +2 -0
  22. package/utils/oas/oas3.d.ts +2 -0
  23. package/utils/oas/types.d.ts +30 -0
  24. package/web-components/components.d.ts +1 -0
  25. package/web-components/index.d.ts +1 -0
  26. package/web-components.min.js +2 -0
  27. package/web-components.min.js.LICENSE.txt +189 -0
  28. package/.storybook/main.js +0 -1
  29. package/.storybook/manager.js +0 -1
  30. package/.storybook/preview.jsx +0 -3
  31. package/jest.config.js +0 -7
  32. package/src/__fixtures__/api-descriptions/Instagram.ts +0 -1859
  33. package/src/__fixtures__/api-descriptions/badgesForSchema.ts +0 -36
  34. package/src/__fixtures__/api-descriptions/simpleApiWithInternalOperations.ts +0 -253
  35. package/src/__fixtures__/api-descriptions/simpleApiWithoutDescription.ts +0 -243
  36. package/src/__fixtures__/api-descriptions/todosApiBundled.ts +0 -430
  37. package/src/__fixtures__/api-descriptions/zoomApiYaml.ts +0 -6083
  38. package/src/components/API/APIWithSidebarLayout.tsx +0 -111
  39. package/src/components/API/APIWithStackedLayout.tsx +0 -220
  40. package/src/components/API/__tests__/utils.test.ts +0 -848
  41. package/src/components/API/utils.ts +0 -174
  42. package/src/containers/API.spec.tsx +0 -131
  43. package/src/containers/API.stories.tsx +0 -99
  44. package/src/containers/API.tsx +0 -200
  45. package/src/hooks/useExportDocumentProps.spec.tsx +0 -68
  46. package/src/hooks/useExportDocumentProps.tsx +0 -48
  47. package/src/styles.css +0 -1
  48. package/src/utils/oas/__tests__/oas.spec.ts +0 -272
  49. package/src/utils/oas/index.ts +0 -150
  50. package/src/utils/oas/oas2.ts +0 -31
  51. package/src/utils/oas/oas3.ts +0 -37
  52. package/src/utils/oas/types.ts +0 -31
  53. package/src/web-components/__stories__/Api.stories.tsx +0 -63
  54. package/src/web-components/components.ts +0 -20
  55. package/src/web-components/index.ts +0 -3
  56. package/tsconfig.build.json +0 -18
  57. package/tsconfig.json +0 -7
  58. package/web-components.config.js +0 -1
  59. /package/{src/index.ts → index.d.ts} +0 -0
@@ -1,174 +0,0 @@
1
- import { isHttpOperation, isHttpService, TableOfContentsItem } from '@stoplight/elements-core';
2
- import { NodeType } from '@stoplight/types';
3
- import { defaults } from 'lodash';
4
-
5
- import { OperationNode, ServiceChildNode, ServiceNode } from '../../utils/oas/types';
6
-
7
- export type TagGroup = { title: string; items: OperationNode[] };
8
-
9
- export const computeTagGroups = (serviceNode: ServiceNode) => {
10
- const groupsByTagId: { [tagId: string]: TagGroup } = {};
11
- const ungrouped = [];
12
-
13
- const lowerCaseServiceTags = serviceNode.tags.map(tn => tn.toLowerCase());
14
-
15
- for (const node of serviceNode.children) {
16
- if (node.type !== NodeType.HttpOperation) continue;
17
- const tagName = node.tags[0];
18
-
19
- if (tagName) {
20
- const tagId = tagName.toLowerCase();
21
- if (groupsByTagId[tagId]) {
22
- groupsByTagId[tagId].items.push(node);
23
- } else {
24
- const serviceTagIndex = lowerCaseServiceTags.findIndex(tn => tn === tagId);
25
- const serviceTagName = serviceNode.tags[serviceTagIndex];
26
- groupsByTagId[tagId] = {
27
- title: serviceTagName || tagName,
28
- items: [node],
29
- };
30
- }
31
- } else {
32
- ungrouped.push(node);
33
- }
34
- }
35
-
36
- const orderedTagGroups = Object.entries(groupsByTagId)
37
- .sort(([g1], [g2]) => {
38
- const g1LC = g1.toLowerCase();
39
- const g2LC = g2.toLowerCase();
40
- const g1Idx = lowerCaseServiceTags.findIndex(tn => tn === g1LC);
41
- const g2Idx = lowerCaseServiceTags.findIndex(tn => tn === g2LC);
42
-
43
- // Move not-tagged groups to the bottom
44
- if (g1Idx < 0 && g2Idx < 0) return 0;
45
- if (g1Idx < 0) return 1;
46
- if (g2Idx < 0) return -1;
47
-
48
- // sort tagged groups according to the order found in HttpService
49
- return g1Idx - g2Idx;
50
- })
51
- .map(([, tagGroup]) => tagGroup);
52
-
53
- return { groups: orderedTagGroups, ungrouped };
54
- };
55
-
56
- interface ComputeAPITreeConfig {
57
- hideSchemas?: boolean;
58
- hideInternal?: boolean;
59
- }
60
-
61
- const defaultComputerAPITreeConfig = {
62
- hideSchemas: false,
63
- hideInternal: false,
64
- };
65
-
66
- export const computeAPITree = (serviceNode: ServiceNode, config: ComputeAPITreeConfig = {}) => {
67
- const mergedConfig = defaults(config, defaultComputerAPITreeConfig);
68
- const tree: TableOfContentsItem[] = [];
69
-
70
- tree.push({
71
- id: '/',
72
- slug: '/',
73
- title: 'Overview',
74
- type: 'overview',
75
- meta: '',
76
- });
77
-
78
- const operationNodes = serviceNode.children.filter(node => node.type === NodeType.HttpOperation);
79
- if (operationNodes.length) {
80
- tree.push({
81
- title: 'Endpoints',
82
- });
83
-
84
- const { groups, ungrouped } = computeTagGroups(serviceNode);
85
-
86
- // Show ungroupped operations above tag groups
87
- ungrouped.forEach(operationNode => {
88
- if (mergedConfig.hideInternal && operationNode.data.internal) {
89
- return;
90
- }
91
- tree.push({
92
- id: operationNode.uri,
93
- slug: operationNode.uri,
94
- title: operationNode.name,
95
- type: operationNode.type,
96
- meta: operationNode.data.method,
97
- });
98
- });
99
-
100
- groups.forEach(group => {
101
- const items = group.items.flatMap(operationNode => {
102
- if (mergedConfig.hideInternal && operationNode.data.internal) {
103
- return [];
104
- }
105
- return {
106
- id: operationNode.uri,
107
- slug: operationNode.uri,
108
- title: operationNode.name,
109
- type: operationNode.type,
110
- meta: operationNode.data.method,
111
- };
112
- });
113
- if (items.length > 0) {
114
- tree.push({
115
- title: group.title,
116
- items,
117
- });
118
- }
119
- });
120
- }
121
-
122
- let schemaNodes = serviceNode.children.filter(node => node.type === NodeType.Model);
123
- if (mergedConfig.hideInternal) {
124
- schemaNodes = schemaNodes.filter(node => !node.data['x-internal']);
125
- }
126
-
127
- if (!mergedConfig.hideSchemas && schemaNodes.length) {
128
- tree.push({
129
- title: 'Schemas',
130
- });
131
-
132
- schemaNodes.forEach(node => {
133
- tree.push({
134
- id: node.uri,
135
- slug: node.uri,
136
- title: node.name,
137
- type: node.type,
138
- meta: '',
139
- });
140
- });
141
- }
142
- return tree;
143
- };
144
-
145
- export const findFirstNodeSlug = (tree: TableOfContentsItem[]): string | void => {
146
- for (const item of tree) {
147
- if ('slug' in item) {
148
- return item.slug;
149
- }
150
-
151
- if ('items' in item) {
152
- const slug = findFirstNodeSlug(item.items);
153
- if (slug) {
154
- return slug;
155
- }
156
- }
157
- }
158
-
159
- return;
160
- };
161
-
162
- export const isInternal = (node: ServiceChildNode | ServiceNode): boolean => {
163
- const data = node.data;
164
-
165
- if (isHttpOperation(data)) {
166
- return !!data.internal;
167
- }
168
-
169
- if (isHttpService(data)) {
170
- return false;
171
- }
172
-
173
- return !!data['x-internal'];
174
- };
@@ -1,131 +0,0 @@
1
- import '@testing-library/jest-dom';
2
-
3
- import {
4
- withMosaicProvider,
5
- withPersistenceBoundary,
6
- withQueryClientProvider,
7
- withStyles,
8
- } from '@stoplight/elements-core';
9
- import { render, screen } from '@testing-library/react';
10
- import { createMemoryHistory } from 'history';
11
- import { flow } from 'lodash';
12
- import * as React from 'react';
13
- import { Route, Router } from 'react-router';
14
-
15
- import { InstagramAPI } from '../__fixtures__/api-descriptions/Instagram';
16
- import { simpleApiWithoutDescription } from '../__fixtures__/api-descriptions/simpleApiWithoutDescription';
17
- import { API, APIImpl } from './API';
18
-
19
- export const APIWithoutRouter = flow(
20
- withStyles,
21
- withPersistenceBoundary,
22
- withMosaicProvider,
23
- withQueryClientProvider,
24
- )(APIImpl);
25
-
26
- describe('API', () => {
27
- const APIDocument = {
28
- ...InstagramAPI,
29
- info: {
30
- ...InstagramAPI.info,
31
- 'x-logo': {
32
- ...InstagramAPI.info['x-logo'],
33
- altText: 'instagram-logo',
34
- },
35
- },
36
- };
37
-
38
- // we need to add scrollTo to the Element prototype before we mount so it has the method available
39
- Element.prototype.scrollTo = () => {};
40
-
41
- it('displays logo specified in x-logo property of API document', async () => {
42
- render(<API layout="sidebar" apiDescriptionDocument={InstagramAPI} />);
43
-
44
- // checks if altText defaults to "logo" if the prop is not passed in API document
45
- // checks if logo is present
46
- expect(await screen.findByAltText('logo')).toBeInTheDocument();
47
- });
48
-
49
- it('uses the altText property from the API document', async () => {
50
- render(<API layout="sidebar" apiDescriptionDocument={APIDocument} />);
51
-
52
- expect(await screen.findByAltText('instagram-logo')).toBeInTheDocument();
53
- });
54
-
55
- it("doesn't display the logo when no properties are passed neither via API document nor as component prop", () => {
56
- render(<API layout="sidebar" apiDescriptionDocument={simpleApiWithoutDescription} />);
57
-
58
- expect(screen.queryByAltText('logo')).not.toBeInTheDocument();
59
- });
60
-
61
- it('overrides the logo from API document with the one passed in a prop', async () => {
62
- render(<API logo="thisisarequiredprop" layout="sidebar" apiDescriptionDocument={APIDocument} />);
63
-
64
- expect(screen.queryByAltText('instagram-logo')).not.toBeInTheDocument();
65
- expect(await screen.findByAltText('logo')).toBeInTheDocument();
66
- });
67
-
68
- it('displays internal operations by default', () => {
69
- const history = createMemoryHistory();
70
- history.push('/paths/internal-operation/get');
71
-
72
- const { unmount } = render(
73
- <Router history={history}>
74
- <Route path="/">
75
- <APIWithoutRouter layout="sidebar" apiDescriptionDocument={APIDocument} />
76
- </Route>
77
- </Router>,
78
- );
79
-
80
- expect(screen.getByText('If you see this, something went wrong')).toBeInTheDocument();
81
-
82
- unmount();
83
- });
84
-
85
- it('displays internal models by default', () => {
86
- const history = createMemoryHistory();
87
- history.push('/schemas/InternalObject');
88
-
89
- render(
90
- <Router history={history}>
91
- <Route path="/">
92
- <APIWithoutRouter layout="sidebar" apiDescriptionDocument={APIDocument} />
93
- </Route>
94
- </Router>,
95
- );
96
-
97
- expect(screen.getByText('Cool object, but internal.')).toBeInTheDocument();
98
- });
99
-
100
- it('reroutes to main page on internal operation if hideInternal is on', () => {
101
- const history = createMemoryHistory();
102
- history.push('/paths/internal-operation/get');
103
-
104
- render(
105
- <Router history={history}>
106
- <Route path="/">
107
- <APIWithoutRouter layout="sidebar" apiDescriptionDocument={APIDocument} hideInternal />
108
- </Route>
109
- </Router>,
110
- );
111
-
112
- expect(screen.queryByText('If you see this, something went wrong')).not.toBeInTheDocument();
113
- expect(history.location.pathname).toBe('/');
114
- });
115
-
116
- it('reroutes to main page on internal model if hideInternal is on', () => {
117
- const history = createMemoryHistory();
118
- history.push('/schemas/InternalObject');
119
-
120
- render(
121
- <Router history={history}>
122
- <Route path="/">
123
- <APIWithoutRouter layout="sidebar" apiDescriptionDocument={APIDocument} hideInternal />
124
- </Route>
125
- </Router>,
126
- );
127
-
128
- expect(screen.queryByText('Cool object, but internal.')).not.toBeInTheDocument();
129
- expect(history.location.pathname).toBe('/');
130
- });
131
- });
@@ -1,99 +0,0 @@
1
- import { parse } from '@stoplight/yaml';
2
- import { Story } from '@storybook/react';
3
- import * as React from 'react';
4
-
5
- import { badgesForSchema } from '../__fixtures__/api-descriptions/badgesForSchema';
6
- import { simpleApiWithInternalOperations } from '../__fixtures__/api-descriptions/simpleApiWithInternalOperations';
7
- import { simpleApiWithoutDescription } from '../__fixtures__/api-descriptions/simpleApiWithoutDescription';
8
- import { todosApiBundled } from '../__fixtures__/api-descriptions/todosApiBundled';
9
- import { zoomApiYaml } from '../__fixtures__/api-descriptions/zoomApiYaml';
10
- import { API, APIProps } from './API';
11
-
12
- export default {
13
- title: 'Public/API',
14
- component: API,
15
- argTypes: {
16
- apiDescriptionDocument: { control: 'text', type: { required: false }, table: { category: 'Input' } },
17
- apiDescriptionUrl: { control: 'text', table: { category: 'Input' } },
18
- layout: {
19
- control: { type: 'inline-radio' },
20
- table: { category: 'UI' },
21
- },
22
- basePath: { table: { category: 'Routing' } },
23
- router: { table: { category: 'Routing' } },
24
- },
25
- args: {
26
- router: 'memory',
27
- },
28
- };
29
-
30
- const Template: Story<APIProps> = args => <API {...args} />;
31
-
32
- export const APIWithYamlProvidedDirectly = Template.bind({});
33
- APIWithYamlProvidedDirectly.args = {
34
- apiDescriptionDocument: zoomApiYaml,
35
- };
36
- APIWithYamlProvidedDirectly.storyName = 'Direct YAML Input (Zoom)';
37
-
38
- export const APIWithJSONProvidedDirectly = Template.bind({});
39
- APIWithJSONProvidedDirectly.args = {
40
- apiDescriptionDocument: JSON.stringify(parse(zoomApiYaml), null, ' '),
41
- };
42
- APIWithJSONProvidedDirectly.storyName = 'Direct JSON Input (Zoom)';
43
-
44
- export const APIWithoutDescription = Template.bind({});
45
- APIWithoutDescription.args = {
46
- apiDescriptionDocument: JSON.stringify(simpleApiWithoutDescription, null, 2),
47
- };
48
- APIWithoutDescription.storyName = 'API Without Description';
49
-
50
- export const APIWithInternalOperations = Template.bind({});
51
- APIWithInternalOperations.args = {
52
- apiDescriptionDocument: JSON.stringify(simpleApiWithInternalOperations, null, 2),
53
- };
54
- APIWithInternalOperations.storyName = 'API With Internal Operations';
55
-
56
- export const OpenApi3Schema = Template.bind({});
57
- OpenApi3Schema.args = {
58
- apiDescriptionDocument: todosApiBundled,
59
- };
60
- OpenApi3Schema.storyName = 'Open Api 3.0 Schema';
61
-
62
- export const BadgesForSchema = Template.bind({});
63
- BadgesForSchema.args = {
64
- apiDescriptionDocument: badgesForSchema,
65
- };
66
- BadgesForSchema.storyName = 'Badges For Schema';
67
-
68
- export const StackedLayout = Template.bind({});
69
- StackedLayout.args = {
70
- apiDescriptionDocument: JSON.stringify(parse(zoomApiYaml), null, ' '),
71
- layout: 'stacked',
72
- };
73
- StackedLayout.storyName = 'Stacked Layout (Zoom)';
74
-
75
- export const Box = Template.bind({});
76
- Box.args = {
77
- apiDescriptionUrl: 'https://raw.githubusercontent.com/box/box-openapi/main/content/openapi.yml',
78
- };
79
- Box.storyName = 'Box';
80
-
81
- export const DigitalOcean = Template.bind({});
82
- DigitalOcean.args = {
83
- apiDescriptionUrl:
84
- 'https://raw.githubusercontent.com/digitalocean/openapi/main/specification/DigitalOcean-public.v2.yaml',
85
- };
86
- DigitalOcean.storyName = 'DigitalOcean';
87
-
88
- export const Github = Template.bind({});
89
- Github.args = {
90
- apiDescriptionUrl:
91
- 'https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/ghes-3.0/ghes-3.0.json',
92
- };
93
- Github.storyName = 'GitHub';
94
-
95
- export const Instagram = Template.bind({});
96
- Instagram.args = {
97
- apiDescriptionUrl: 'https://api.apis.guru/v2/specs/instagram.com/1.0.0/swagger.yaml',
98
- };
99
- Instagram.storyName = 'Instagram';
@@ -1,200 +0,0 @@
1
- import {
2
- InlineRefResolverProvider,
3
- NonIdealState,
4
- RoutingProps,
5
- useBundleRefsIntoDocument,
6
- useParsedValue,
7
- withMosaicProvider,
8
- withPersistenceBoundary,
9
- withQueryClientProvider,
10
- withRouter,
11
- withStyles,
12
- } from '@stoplight/elements-core';
13
- import { Box, Flex, Icon } from '@stoplight/mosaic';
14
- import { flow } from 'lodash';
15
- import * as React from 'react';
16
- import { useQuery } from 'react-query';
17
-
18
- import { APIWithSidebarLayout } from '../components/API/APIWithSidebarLayout';
19
- import { APIWithStackedLayout } from '../components/API/APIWithStackedLayout';
20
- import { useExportDocumentProps } from '../hooks/useExportDocumentProps';
21
- import { transformOasToServiceNode } from '../utils/oas';
22
-
23
- export type APIProps = APIPropsWithDocument | APIPropsWithUrl;
24
-
25
- export type APIPropsWithUrl = {
26
- /**
27
- * Specify the URL of the input OAS2/3 document here.
28
- *
29
- * Mutually exclusive with `apiDescriptionDocument`.
30
- */
31
- apiDescriptionUrl: string;
32
- } & CommonAPIProps;
33
- export type APIPropsWithDocument = {
34
- /**
35
- * You can specify the input OAS2/3 document here directly in JSON or YAML format.
36
- *
37
- * Mutually exclusive with `apiDescriptionUrl`.
38
- */
39
- apiDescriptionDocument: string | object;
40
- apiDescriptionUrl?: string;
41
- } & CommonAPIProps;
42
-
43
- export interface CommonAPIProps extends RoutingProps {
44
- /**
45
- * The API component supports two layout options.
46
- *
47
- * - Sidebar: Navigation on the left side, resembles Stoplight Platform.
48
- * - Stacked: No sidebar, resembles the structure of Swagger UI.
49
- *
50
- * @default "sidebar"
51
- */
52
- layout?: 'sidebar' | 'stacked';
53
- logo?: string;
54
-
55
- /**
56
- * Allows hiding the TryIt component
57
- */
58
- hideTryIt?: boolean;
59
-
60
- /**
61
- * Hides schemas from being displayed in Table of Contents
62
- */
63
- hideSchemas?: boolean;
64
-
65
- /**
66
- * Hides models and operations marked as internal
67
- * @default false
68
- */
69
- hideInternal?: boolean;
70
-
71
- /**
72
- * Hides export button from being displayed in overview page
73
- * @default false
74
- */
75
- hideExport?: boolean;
76
-
77
- /**
78
- * Fetch credentials policy for TryIt component
79
- * For more information: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
80
- * @default "omit"
81
- */
82
-
83
- tryItCredentialsPolicy?: 'omit' | 'include' | 'same-origin';
84
-
85
- /**
86
- * Url of a CORS proxy that will be used to send requests in TryIt.
87
- * Provided url will be prepended to an URL of an actual request.
88
- * @default false
89
- */
90
- tryItCorsProxy?: string;
91
- tryItOutDefaultServer?: string;
92
- }
93
-
94
- const propsAreWithDocument = (props: APIProps): props is APIPropsWithDocument => {
95
- return props.hasOwnProperty('apiDescriptionDocument');
96
- };
97
-
98
- export const APIImpl: React.FC<APIProps> = props => {
99
- const {
100
- layout,
101
- apiDescriptionUrl = '',
102
- logo,
103
- hideTryIt,
104
- hideSchemas,
105
- hideInternal,
106
- hideExport,
107
- tryItCredentialsPolicy,
108
- tryItCorsProxy,
109
- tryItOutDefaultServer,
110
- } = props;
111
- const apiDescriptionDocument = propsAreWithDocument(props) ? props.apiDescriptionDocument : undefined;
112
-
113
- const { data: fetchedDocument, error } = useQuery(
114
- [apiDescriptionUrl],
115
- () =>
116
- fetch(apiDescriptionUrl).then(res => {
117
- if (res.ok) {
118
- return res.text();
119
- }
120
- throw new Error(`Unable to load description document, status code: ${res.status}`);
121
- }),
122
- {
123
- enabled: apiDescriptionUrl !== '' && !apiDescriptionDocument,
124
- },
125
- );
126
-
127
- const document = apiDescriptionDocument || fetchedDocument || '';
128
- const parsedDocument = useParsedValue(document);
129
- const bundledDocument = useBundleRefsIntoDocument(parsedDocument, { baseUrl: apiDescriptionUrl });
130
- const serviceNode = React.useMemo(() => transformOasToServiceNode(bundledDocument), [bundledDocument]);
131
- const exportProps = useExportDocumentProps({ originalDocument: document, bundledDocument });
132
-
133
- if (error) {
134
- return (
135
- <Flex justify="center" alignItems="center" w="full" minH="screen">
136
- <NonIdealState
137
- title="Document could not be loaded"
138
- description="The API description document could not be fetched. This could indicate connectivity problems, or issues with the server hosting the spec."
139
- icon="exclamation-triangle"
140
- />
141
- </Flex>
142
- );
143
- }
144
-
145
- if (!bundledDocument) {
146
- return (
147
- <Flex justify="center" alignItems="center" w="full" minH="screen" color="light">
148
- <Box as={Icon} icon={['fal', 'circle-notch']} size="3x" spin />
149
- </Flex>
150
- );
151
- }
152
-
153
- if (!serviceNode) {
154
- return (
155
- <Flex justify="center" alignItems="center" w="full" minH="screen">
156
- <NonIdealState
157
- title="Failed to parse OpenAPI file"
158
- description="Please make sure your OpenAPI file is valid and try again"
159
- />
160
- </Flex>
161
- );
162
- }
163
-
164
- return (
165
- <InlineRefResolverProvider document={parsedDocument}>
166
- {layout === 'stacked' ? (
167
- <APIWithStackedLayout
168
- serviceNode={serviceNode}
169
- hideTryIt={hideTryIt}
170
- hideExport={hideExport}
171
- exportProps={exportProps}
172
- tryItCredentialsPolicy={tryItCredentialsPolicy}
173
- tryItCorsProxy={tryItCorsProxy}
174
- tryItOutDefaultServer={tryItOutDefaultServer}
175
- />
176
- ) : (
177
- <APIWithSidebarLayout
178
- logo={logo}
179
- serviceNode={serviceNode}
180
- hideTryIt={hideTryIt}
181
- hideSchemas={hideSchemas}
182
- hideInternal={hideInternal}
183
- hideExport={hideExport}
184
- exportProps={exportProps}
185
- tryItCredentialsPolicy={tryItCredentialsPolicy}
186
- tryItCorsProxy={tryItCorsProxy}
187
- tryItOutDefaultServer={tryItOutDefaultServer}
188
- />
189
- )}
190
- </InlineRefResolverProvider>
191
- );
192
- };
193
-
194
- export const API = flow(
195
- withRouter,
196
- withStyles,
197
- withPersistenceBoundary,
198
- withMosaicProvider,
199
- withQueryClientProvider,
200
- )(APIImpl);
@@ -1,68 +0,0 @@
1
- import '@testing-library/jest-dom';
2
-
3
- import { safeStringify } from '@stoplight/yaml';
4
- import { act, renderHook } from '@testing-library/react-hooks';
5
- import { saveAs } from 'file-saver';
6
-
7
- import { InstagramAPI as bundledJson } from '../__fixtures__/api-descriptions/Instagram';
8
- import { simpleApiWithoutDescription as json } from '../__fixtures__/api-descriptions/simpleApiWithoutDescription';
9
- import { todosApiBundled as bundledYaml } from '../__fixtures__/api-descriptions/todosApiBundled';
10
- import { zoomApiYaml as yaml } from '../__fixtures__/api-descriptions/zoomApiYaml';
11
- import { useExportDocumentProps } from './useExportDocumentProps';
12
-
13
- jest.mock('file-saver');
14
-
15
- describe('useExportDocumentProps', () => {
16
- afterEach(() => {
17
- jest.resetAllMocks();
18
- });
19
- it('exports json document', () => {
20
- const data = renderHook(() =>
21
- useExportDocumentProps({
22
- originalDocument: json,
23
- bundledDocument: bundledJson,
24
- }),
25
- );
26
-
27
- act(() => {
28
- data.result.current.original.onPress();
29
- data.result.current.bundled.onPress();
30
- });
31
-
32
- const expectedOriginalDocument = new Blob([JSON.stringify(json, null, 2)], {
33
- type: 'application/json',
34
- });
35
-
36
- const expectedBundledDocument = new Blob([JSON.stringify(bundledJson, null, 2)], {
37
- type: 'application/json',
38
- });
39
- expect(saveAs).toBeCalledTimes(2);
40
- expect(saveAs).toHaveBeenCalledWith(expectedOriginalDocument, 'document.json');
41
- expect(saveAs).toHaveBeenCalledWith(expectedBundledDocument, 'document.json');
42
- });
43
-
44
- it('exports yaml document', () => {
45
- const data = renderHook(() =>
46
- useExportDocumentProps({
47
- originalDocument: safeStringify(yaml),
48
- bundledDocument: bundledYaml,
49
- }),
50
- );
51
-
52
- act(() => {
53
- data.result.current.original.onPress();
54
- data.result.current.bundled.onPress();
55
- });
56
-
57
- const expectedOriginalDocument = new Blob([safeStringify(yaml)], {
58
- type: 'application/yaml',
59
- });
60
-
61
- const expectedBundledDocument = new Blob([safeStringify(bundledYaml)], {
62
- type: 'application/yaml',
63
- });
64
- expect(saveAs).toBeCalledTimes(2);
65
- expect(saveAs).toHaveBeenCalledWith(expectedOriginalDocument, 'document.yaml');
66
- expect(saveAs).toHaveBeenCalledWith(expectedBundledDocument, 'document.yaml');
67
- });
68
- });