@verdaccio/ui-components 4.0.0-next-8.5 → 4.0.0-next-8.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/build/components/Search/Search.js +13 -2
- package/build/src/AppTest/App.stories.d.ts +9 -8
- package/build/src/components/Search/Search.d.ts +3 -1
- package/build/src/components/Search/Search.stories.d.ts +6 -8
- package/build/src/sections/Detail/Detail.stories.d.ts +8 -7
- package/build/src/sections/Header/Header.stories.d.ts +6 -5
- package/build/src/sections/Home/Home.stories.d.ts +6 -5
- package/build/src/sections/SideBar/Sidebar.stories.d.ts +7 -7
- package/build/utils/url.js +19 -9
- package/package.json +16 -14
- package/src/AppTest/App.stories.tsx +81 -24
- package/src/AppTest/AppRoute.test.tsx +6 -2
- package/src/components/ActionBar/ActionBar.test.tsx +68 -29
- package/src/components/Package/Package.test.tsx +9 -0
- package/src/components/Search/Search.stories.tsx +24 -2
- package/src/components/Search/Search.tsx +7 -3
- package/src/layouts/Version/Version.stories.tsx +26 -0
- package/src/sections/Detail/Detail.stories.tsx +52 -21
- package/src/sections/Header/Header.stories.tsx +33 -10
- package/src/sections/Home/Home.stories.tsx +25 -8
- package/src/sections/SideBar/Sidebar.stories.tsx +53 -28
- package/src/utils/url.ts +25 -9
- package/tsconfig.build.json +2 -2
- package/tsconfig.json +3 -2
- package/vitest.config.mjs +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
var _excluded = ["key"];
|
|
2
|
+
function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
|
|
3
|
+
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
|
|
1
4
|
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
2
5
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
3
6
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
@@ -121,12 +124,18 @@ var Search = _ref => {
|
|
|
121
124
|
}
|
|
122
125
|
};
|
|
123
126
|
var renderOption = (props, option) => {
|
|
127
|
+
var {
|
|
128
|
+
key
|
|
129
|
+
} = props,
|
|
130
|
+
otherProps = _objectWithoutProperties(props, _excluded);
|
|
124
131
|
if (searchRemote) {
|
|
125
132
|
var item = option.package;
|
|
126
133
|
var isPrivate = option === null || option === void 0 ? void 0 : option.verdaccioPrivate;
|
|
127
134
|
var isCached = option === null || option === void 0 ? void 0 : option.verdaccioPkgCached;
|
|
128
135
|
var isRemote = !isCached && !isPrivate;
|
|
129
|
-
return /*#__PURE__*/React.createElement(SearchItem, _extends({
|
|
136
|
+
return /*#__PURE__*/React.createElement(SearchItem, _extends({
|
|
137
|
+
key: key
|
|
138
|
+
}, otherProps, {
|
|
130
139
|
description: item === null || item === void 0 ? void 0 : item.description,
|
|
131
140
|
isCached: isCached,
|
|
132
141
|
isPrivate: isPrivate,
|
|
@@ -135,7 +144,9 @@ var Search = _ref => {
|
|
|
135
144
|
version: item === null || item === void 0 ? void 0 : item.version
|
|
136
145
|
}));
|
|
137
146
|
} else {
|
|
138
|
-
return /*#__PURE__*/React.createElement(SearchItem, _extends({
|
|
147
|
+
return /*#__PURE__*/React.createElement(SearchItem, _extends({
|
|
148
|
+
key: key
|
|
149
|
+
}, otherProps, {
|
|
139
150
|
description: option === null || option === void 0 ? void 0 : option.description,
|
|
140
151
|
name: option === null || option === void 0 ? void 0 : option.name,
|
|
141
152
|
version: option === null || option === void 0 ? void 0 : option.version
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export default
|
|
5
|
-
|
|
6
|
-
export declare const
|
|
7
|
-
export declare const
|
|
8
|
-
export declare const
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import AppRoute from './AppRoute';
|
|
3
|
+
declare const meta: Meta<typeof AppRoute>;
|
|
4
|
+
export default meta;
|
|
5
|
+
type Story = StoryObj<typeof AppRoute>;
|
|
6
|
+
export declare const ApplicationStoryBook: Story;
|
|
7
|
+
export declare const ApplicationJquery: Story;
|
|
8
|
+
export declare const ApplicationForbidden: Story;
|
|
9
|
+
export declare const ApplicationNotFound: Story;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { RouteComponentProps } from 'react-router';
|
|
3
|
-
declare const _default: React.ComponentClass<Pick<RouteComponentProps<
|
|
3
|
+
declare const _default: React.ComponentClass<Pick<RouteComponentProps<any, import("react-router").StaticContext, H.LocationState>, never> | (Pick<RouteComponentProps<any, import("react-router").StaticContext, H.LocationState>, never> & {
|
|
4
|
+
wrappedComponentRef?: React.Ref<any> | undefined;
|
|
5
|
+
}), any> & import("react-router").WithRouterStatics<any>;
|
|
4
6
|
export default _default;
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export default
|
|
6
|
-
export declare const SearchByQuery:
|
|
7
|
-
render: (args: any) => React.JSX.Element;
|
|
8
|
-
};
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import Search from './Search';
|
|
3
|
+
type Story = StoryObj<typeof Search>;
|
|
4
|
+
declare const meta: Meta<typeof Search>;
|
|
5
|
+
export default meta;
|
|
6
|
+
export declare const SearchByQuery: Story;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export default
|
|
5
|
-
|
|
6
|
-
export declare const
|
|
7
|
-
export declare const
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import Detail from './Detail';
|
|
3
|
+
declare const meta: Meta<typeof Detail>;
|
|
4
|
+
export default meta;
|
|
5
|
+
type Story = StoryObj<typeof Detail>;
|
|
6
|
+
export declare const DetailStorybook: Story;
|
|
7
|
+
export declare const DetailJquery: Story;
|
|
8
|
+
export declare const DetailForbidden: Story;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import Header from './Header';
|
|
3
|
+
type Story = StoryObj<typeof Header>;
|
|
4
|
+
declare const meta: Meta<typeof Header>;
|
|
5
|
+
export default meta;
|
|
6
|
+
export declare const HeaderAll: Story;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import Home from './Home';
|
|
3
|
+
type Story = StoryObj<typeof Home>;
|
|
4
|
+
declare const meta: Meta<typeof Home>;
|
|
5
|
+
export default meta;
|
|
6
|
+
export declare const HomeDefault: Story;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export default
|
|
5
|
-
|
|
6
|
-
export declare const
|
|
7
|
-
export declare const
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import DetailSidebar from './Sidebar';
|
|
3
|
+
declare const meta: Meta<typeof DetailSidebar>;
|
|
4
|
+
export default meta;
|
|
5
|
+
type Story = StoryObj<typeof DetailSidebar>;
|
|
6
|
+
export declare const SidebarLatestPackage: Story;
|
|
7
|
+
export declare const SidebarPackageVersion: Story;
|
package/build/utils/url.js
CHANGED
|
@@ -41,14 +41,24 @@ export function downloadFile(fileStream, fileName) {
|
|
|
41
41
|
fileLink.href = objectURL;
|
|
42
42
|
fileLink.download = fileName;
|
|
43
43
|
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
44
|
+
// Skip actual download in test environment to avoid JSDOM navigation error
|
|
45
|
+
// Check if we're in a test environment (JSDOM)
|
|
46
|
+
var isTestEnvironment = typeof window !== 'undefined' && window.navigator && window.navigator.userAgent && window.navigator.userAgent.includes('Node.js') || window.navigator.userAgent.includes('jsdom');
|
|
47
|
+
if (!isTestEnvironment) {
|
|
48
|
+
// Without appending to an HTML Element, download dialog does not show up on Firefox
|
|
49
|
+
// https://github.com/verdaccio/ui/issues/119
|
|
50
|
+
document.documentElement.appendChild(fileLink);
|
|
51
|
+
fileLink.click();
|
|
52
|
+
// firefox requires remove the object url
|
|
53
|
+
setTimeout(() => {
|
|
54
|
+
URL.revokeObjectURL(objectURL);
|
|
55
|
+
document.documentElement.removeChild(fileLink);
|
|
56
|
+
}, 150);
|
|
57
|
+
} else {
|
|
58
|
+
// In test environment, just clean up without triggering navigation
|
|
59
|
+
setTimeout(() => {
|
|
60
|
+
URL.revokeObjectURL(objectURL);
|
|
61
|
+
}, 150);
|
|
62
|
+
}
|
|
53
63
|
}
|
|
54
64
|
//# sourceMappingURL=url.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@verdaccio/ui-components",
|
|
3
|
-
"version": "4.0.0-next-8.
|
|
3
|
+
"version": "4.0.0-next-8.6",
|
|
4
4
|
"description": "theme ui component",
|
|
5
5
|
"author": "Juan Picado <juanpicado19@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"@rematch/core": "2.2.0",
|
|
21
21
|
"@rematch/loading": "2.1.2",
|
|
22
22
|
"@rematch/persist": "2.1.2",
|
|
23
|
-
"country-flag-icons": "1.5.
|
|
23
|
+
"country-flag-icons": "1.5.16",
|
|
24
24
|
"dayjs": "1.11.13",
|
|
25
25
|
"dompurify": "3.2.3",
|
|
26
26
|
"highlight.js": "11.11.1",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"normalize.css": "8.0.1",
|
|
35
35
|
"react": "18.3.1",
|
|
36
36
|
"react-dom": "18.3.1",
|
|
37
|
-
"react-hook-form": "7.
|
|
37
|
+
"react-hook-form": "7.54.2",
|
|
38
38
|
"react-i18next": "15.0.0",
|
|
39
39
|
"react-markdown": "9.0.3",
|
|
40
40
|
"react-redux": "8.1.3",
|
|
@@ -42,19 +42,21 @@
|
|
|
42
42
|
"react-router-dom": "5.3.4",
|
|
43
43
|
"react-virtualized": "9.22.6",
|
|
44
44
|
"redux": "4.2.1",
|
|
45
|
-
"semver": "7.
|
|
46
|
-
"validator": "13.12.0"
|
|
45
|
+
"semver": "7.7.1",
|
|
46
|
+
"validator": "13.12.0",
|
|
47
|
+
"@verdaccio/ui-i18n": "8.0.0-next-8.11"
|
|
47
48
|
},
|
|
48
49
|
"devDependencies": {
|
|
49
|
-
"@babel/core": "7.26.
|
|
50
|
+
"@babel/core": "7.26.9",
|
|
50
51
|
"@emotion/babel-plugin": "11.12.0",
|
|
51
|
-
"@storybook/addon-actions": "^8.
|
|
52
|
-
"@storybook/addon-essentials": "^8.
|
|
53
|
-
"@storybook/addon-
|
|
54
|
-
"@storybook/addon-
|
|
52
|
+
"@storybook/addon-actions": "^8.6.3",
|
|
53
|
+
"@storybook/addon-essentials": "^8.6.3",
|
|
54
|
+
"@storybook/addon-mdx-gfm": "^8.6.3",
|
|
55
|
+
"@storybook/addon-interactions": "^8.6.3",
|
|
56
|
+
"@storybook/addon-links": "^8.6.3",
|
|
55
57
|
"@storybook/addon-webpack5-compiler-babel": "3.0.5",
|
|
56
|
-
"@storybook/react": "^8.
|
|
57
|
-
"@storybook/react-webpack5": "8.
|
|
58
|
+
"@storybook/react": "^8.6.3",
|
|
59
|
+
"@storybook/react-webpack5": "8.6.3",
|
|
58
60
|
"@testing-library/dom": "10.4.0",
|
|
59
61
|
"@testing-library/jest-dom": "6.6.3",
|
|
60
62
|
"@testing-library/react": "16.1.0",
|
|
@@ -69,7 +71,7 @@
|
|
|
69
71
|
"msw": "2.7.0",
|
|
70
72
|
"msw-storybook-addon": "^2.0.4",
|
|
71
73
|
"mutationobserver-shim": "0.3.7",
|
|
72
|
-
"storybook": "8.
|
|
74
|
+
"storybook": "8.6.3",
|
|
73
75
|
"typescript": "4.9.5",
|
|
74
76
|
"vitest": "3.0.4",
|
|
75
77
|
"whatwg-fetch": "3.6.20"
|
|
@@ -88,7 +90,7 @@
|
|
|
88
90
|
"watch": "babel src/ --out-dir build/ --watch --copy-files --no-copy-ignored --extensions \".ts,.tsx\" --source-maps --ignore \"src/**/*.stories.tsx\" --ignore \"src/**/*.test.tsx\" --ignore \"src/**/*.test.ts\"",
|
|
89
91
|
"build": "pnpm run build:js && pnpm run build:types",
|
|
90
92
|
"netlify:ui:deploy": "npx netlify-cli deploy --dir=./packages/ui-components/storybook-static --prod",
|
|
91
|
-
"start": "storybook dev -p 6006",
|
|
93
|
+
"start": "BROWSER=none storybook dev -p 6006",
|
|
92
94
|
"build-storybook": "storybook build"
|
|
93
95
|
}
|
|
94
96
|
}
|
|
@@ -1,32 +1,89 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { HttpResponse, http } from 'msw';
|
|
1
3
|
import React from 'react';
|
|
2
4
|
import { MemoryRouter } from 'react-router';
|
|
3
5
|
|
|
4
6
|
import AppRoute from './AppRoute';
|
|
5
7
|
|
|
6
|
-
|
|
8
|
+
const meta: Meta<typeof AppRoute> = {
|
|
7
9
|
title: 'App/Main',
|
|
10
|
+
component: AppRoute,
|
|
8
11
|
};
|
|
9
12
|
|
|
10
|
-
export
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
13
|
+
export default meta;
|
|
14
|
+
|
|
15
|
+
type Story = StoryObj<typeof AppRoute>;
|
|
16
|
+
|
|
17
|
+
export const ApplicationStoryBook: Story = {
|
|
18
|
+
render: () => (
|
|
19
|
+
<MemoryRouter initialEntries={[`/-/web/detail/storybook`]}>
|
|
20
|
+
<AppRoute />
|
|
21
|
+
</MemoryRouter>
|
|
22
|
+
),
|
|
23
|
+
parameters: {
|
|
24
|
+
msw: {
|
|
25
|
+
handlers: [
|
|
26
|
+
http.get('https://my-registry.org/-/verdaccio/data/sidebar/storybook', () => {
|
|
27
|
+
return HttpResponse.json(require('../../vitest/api/storybook-sidebar.json'));
|
|
28
|
+
}),
|
|
29
|
+
http.get('https://my-registry.org/-/verdaccio/data/package/readme/storybook', () => {
|
|
30
|
+
return HttpResponse.json(require('../../vitest/api/storybook-readme')());
|
|
31
|
+
}),
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const ApplicationJquery: Story = {
|
|
38
|
+
render: () => (
|
|
39
|
+
<MemoryRouter initialEntries={[`/-/web/detail/jquery`]}>
|
|
40
|
+
<AppRoute />
|
|
41
|
+
</MemoryRouter>
|
|
42
|
+
),
|
|
43
|
+
parameters: {
|
|
44
|
+
msw: {
|
|
45
|
+
handlers: [
|
|
46
|
+
http.get('https://my-registry.org/-/verdaccio/data/sidebar/jquery', () => {
|
|
47
|
+
return HttpResponse.json(require('../../vitest/api/jquery-sidebar.json'));
|
|
48
|
+
}),
|
|
49
|
+
http.get('https://my-registry.org/-/verdaccio/data/package/readme/jquery', () => {
|
|
50
|
+
return HttpResponse.json(require('../../vitest/api/jquery-readme')());
|
|
51
|
+
}),
|
|
52
|
+
],
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const ApplicationForbidden: Story = {
|
|
58
|
+
render: () => (
|
|
59
|
+
<MemoryRouter initialEntries={[`/-/web/detail/JSONStream`]}>
|
|
60
|
+
<AppRoute />
|
|
61
|
+
</MemoryRouter>
|
|
62
|
+
),
|
|
63
|
+
parameters: {
|
|
64
|
+
msw: {
|
|
65
|
+
handlers: [
|
|
66
|
+
http.get('https://my-registry.org/-/verdaccio/data/sidebar/JSONStream', () => {
|
|
67
|
+
return new HttpResponse('unauthorized', { status: 401 });
|
|
68
|
+
}),
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export const ApplicationNotFound: Story = {
|
|
75
|
+
render: () => (
|
|
76
|
+
<MemoryRouter initialEntries={[`/-/web/detail/kleur`]}>
|
|
77
|
+
<AppRoute />
|
|
78
|
+
</MemoryRouter>
|
|
79
|
+
),
|
|
80
|
+
parameters: {
|
|
81
|
+
msw: {
|
|
82
|
+
handlers: [
|
|
83
|
+
http.get('https://my-registry.org/-/verdaccio/data/sidebar/kleur', () => {
|
|
84
|
+
return new HttpResponse('unauthorized', { status: 404 });
|
|
85
|
+
}),
|
|
86
|
+
],
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
};
|
|
@@ -34,13 +34,17 @@ describe('AppRoute', () => {
|
|
|
34
34
|
|
|
35
35
|
test('renders VersionPage component for PACKAGE path', async () => {
|
|
36
36
|
act(() => appTest('/-/web/detail/jquery'));
|
|
37
|
-
await waitFor(() => screen.getByTestId('readme-tab'))
|
|
37
|
+
await waitFor(() => expect(screen.getByTestId('readme-tab')).toBeInTheDocument(), {
|
|
38
|
+
timeout: 3000,
|
|
39
|
+
});
|
|
38
40
|
expect(screen.getByTestId('sidebar')).toBeInTheDocument();
|
|
39
41
|
});
|
|
40
42
|
|
|
41
43
|
test('renders VersionPage component for PACKAGE VERSION path', async () => {
|
|
42
44
|
act(() => appTest('/-/web/detail/jquery/v/3.6.3'));
|
|
43
|
-
await waitFor(() => screen.getByTestId('readme-tab'))
|
|
45
|
+
await waitFor(() => expect(screen.getByTestId('readme-tab')).toBeInTheDocument(), {
|
|
46
|
+
timeout: 3000,
|
|
47
|
+
});
|
|
44
48
|
expect(screen.getByTestId('sidebar')).toBeInTheDocument();
|
|
45
49
|
});
|
|
46
50
|
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
|
+
import { cleanupDownloadMocks, setupDownloadMocks } from '../../../vitest/vitestHelpers';
|
|
3
4
|
import { store } from '../../store/store';
|
|
4
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
cleanup,
|
|
7
|
+
fireEvent,
|
|
8
|
+
renderWithStore,
|
|
9
|
+
screen,
|
|
10
|
+
waitFor,
|
|
11
|
+
} from '../../test/test-react-testing-library';
|
|
5
12
|
import ActionBar from './ActionBar';
|
|
6
13
|
|
|
7
14
|
const defaultPackageMeta = {
|
|
@@ -21,25 +28,37 @@ const defaultPackageMeta = {
|
|
|
21
28
|
},
|
|
22
29
|
};
|
|
23
30
|
|
|
31
|
+
beforeAll(() => {
|
|
32
|
+
setupDownloadMocks();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
afterAll(() => {
|
|
36
|
+
cleanupDownloadMocks();
|
|
37
|
+
});
|
|
38
|
+
|
|
24
39
|
describe('<ActionBar /> component', () => {
|
|
25
40
|
afterEach(() => {
|
|
26
41
|
cleanup();
|
|
27
42
|
});
|
|
28
43
|
|
|
29
|
-
test('should render the component in default state', () => {
|
|
44
|
+
test('should render the component in default state', async () => {
|
|
30
45
|
renderWithStore(<ActionBar packageMeta={defaultPackageMeta} />, store);
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
46
|
+
await waitFor(() => {
|
|
47
|
+
expect(screen.getByTestId('download-tarball-btn')).toBeInTheDocument();
|
|
48
|
+
expect(screen.getByTestId('BugReportIcon')).toBeInTheDocument();
|
|
49
|
+
expect(screen.getByTestId('HomeIcon')).toBeInTheDocument();
|
|
50
|
+
});
|
|
34
51
|
});
|
|
35
52
|
|
|
36
|
-
test('should not render if data is missing', () => {
|
|
53
|
+
test('should not render if data is missing', async () => {
|
|
37
54
|
// @ts-ignore - testing with missing data
|
|
38
55
|
renderWithStore(<ActionBar packageMeta={undefined} />, store);
|
|
39
|
-
|
|
56
|
+
await waitFor(() => {
|
|
57
|
+
expect(screen.queryByTestId('HomeIcon')).toBeNull();
|
|
58
|
+
});
|
|
40
59
|
});
|
|
41
60
|
|
|
42
|
-
test('when there is no action bar data', () => {
|
|
61
|
+
test('when there is no action bar data', async () => {
|
|
43
62
|
const packageMeta = {
|
|
44
63
|
...defaultPackageMeta,
|
|
45
64
|
latest: {
|
|
@@ -54,60 +73,80 @@ describe('<ActionBar /> component', () => {
|
|
|
54
73
|
};
|
|
55
74
|
|
|
56
75
|
renderWithStore(<ActionBar packageMeta={packageMeta} />, store);
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
76
|
+
await waitFor(() => {
|
|
77
|
+
expect(screen.queryByTestId('download-tarball-btn')).not.toBeInTheDocument();
|
|
78
|
+
expect(screen.queryByTestId('BugReportIcon')).not.toBeInTheDocument();
|
|
79
|
+
expect(screen.queryByTestId('HomeIcon')).not.toBeInTheDocument();
|
|
80
|
+
});
|
|
60
81
|
});
|
|
61
82
|
|
|
62
|
-
test('when there is a button to download a tarball', () => {
|
|
83
|
+
test('when there is a button to download a tarball', async () => {
|
|
63
84
|
renderWithStore(<ActionBar packageMeta={defaultPackageMeta} />, store);
|
|
64
|
-
|
|
85
|
+
await waitFor(() => {
|
|
86
|
+
expect(screen.getByLabelText('action-bar-action.download-tarball')).toBeTruthy();
|
|
87
|
+
});
|
|
65
88
|
});
|
|
66
89
|
|
|
67
|
-
test('when button to download is disabled', () => {
|
|
90
|
+
test('when button to download is disabled', async () => {
|
|
68
91
|
renderWithStore(
|
|
69
92
|
<ActionBar packageMeta={defaultPackageMeta} showDownloadTarball={false} />,
|
|
70
93
|
store
|
|
71
94
|
);
|
|
72
|
-
|
|
95
|
+
await waitFor(() => {
|
|
96
|
+
expect(screen.queryByTestId('download-tarball-btn')).not.toBeInTheDocument();
|
|
97
|
+
});
|
|
73
98
|
});
|
|
74
99
|
|
|
75
|
-
test('when there is a button to raw manifest', () => {
|
|
100
|
+
test('when there is a button to raw manifest', async () => {
|
|
76
101
|
renderWithStore(<ActionBar packageMeta={defaultPackageMeta} showRaw={true} />, store);
|
|
77
|
-
|
|
102
|
+
await waitFor(() => {
|
|
103
|
+
expect(screen.getByLabelText('action-bar-action.raw')).toBeTruthy();
|
|
104
|
+
});
|
|
78
105
|
});
|
|
79
106
|
|
|
80
107
|
test('when click button to raw manifest open a dialog with viewer', async () => {
|
|
81
108
|
renderWithStore(<ActionBar packageMeta={defaultPackageMeta} showRaw={true} />, store);
|
|
82
|
-
|
|
109
|
+
await waitFor(() => {
|
|
110
|
+
expect(screen.queryByTestId('rawViewer--dialog')).toBeFalsy();
|
|
111
|
+
});
|
|
83
112
|
|
|
84
113
|
fireEvent.click(screen.getByLabelText('action-bar-action.raw'));
|
|
85
|
-
await
|
|
114
|
+
await waitFor(() => {
|
|
115
|
+
expect(screen.getByTestId('rawViewer--dialog')).toBeInTheDocument();
|
|
116
|
+
});
|
|
86
117
|
|
|
87
118
|
fireEvent.click(screen.getByTestId('close-raw-viewer'));
|
|
88
|
-
await
|
|
89
|
-
|
|
90
|
-
|
|
119
|
+
await waitFor(() => {
|
|
120
|
+
expect(screen.queryByTestId('rawViewer--dialog')).toBeFalsy();
|
|
121
|
+
});
|
|
91
122
|
});
|
|
92
123
|
|
|
93
|
-
test('should not display download tarball button', () => {
|
|
124
|
+
test('should not display download tarball button', async () => {
|
|
94
125
|
renderWithStore(<ActionBar packageMeta={defaultPackageMeta} showRaw={false} />, store);
|
|
95
|
-
|
|
126
|
+
await waitFor(() => {
|
|
127
|
+
expect(screen.queryByLabelText('Download tarball')).toBeFalsy();
|
|
128
|
+
});
|
|
96
129
|
});
|
|
97
130
|
|
|
98
131
|
test('when click button to download ', async () => {
|
|
99
132
|
renderWithStore(<ActionBar packageMeta={defaultPackageMeta} showRaw={false} />, store);
|
|
100
133
|
fireEvent.click(screen.getByTestId('download-tarball-btn'));
|
|
101
|
-
await
|
|
134
|
+
await waitFor(() => {
|
|
135
|
+
expect(store.getState().loading.models.download).toBe(true);
|
|
136
|
+
});
|
|
102
137
|
});
|
|
103
138
|
|
|
104
|
-
test('should not display show raw button', () => {
|
|
139
|
+
test('should not display show raw button', async () => {
|
|
105
140
|
renderWithStore(<ActionBar packageMeta={defaultPackageMeta} showRaw={false} />, store);
|
|
106
|
-
|
|
141
|
+
await waitFor(() => {
|
|
142
|
+
expect(screen.queryByLabelText('action-bar-action.raw')).toBeFalsy();
|
|
143
|
+
});
|
|
107
144
|
});
|
|
108
145
|
|
|
109
|
-
test('when there is a button to open an issue', () => {
|
|
146
|
+
test('when there is a button to open an issue', async () => {
|
|
110
147
|
renderWithStore(<ActionBar packageMeta={defaultPackageMeta} />, store);
|
|
111
|
-
|
|
148
|
+
await waitFor(() => {
|
|
149
|
+
expect(screen.getByTestId('BugReportIcon')).toBeInTheDocument();
|
|
150
|
+
});
|
|
112
151
|
});
|
|
113
152
|
});
|
|
@@ -2,6 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { MemoryRouter } from 'react-router';
|
|
3
3
|
|
|
4
4
|
import { store } from '../../';
|
|
5
|
+
import { cleanupDownloadMocks, setupDownloadMocks } from '../../../vitest/vitestHelpers';
|
|
5
6
|
import {
|
|
6
7
|
cleanup,
|
|
7
8
|
fireEvent,
|
|
@@ -34,6 +35,14 @@ const props = {
|
|
|
34
35
|
keywords: ['verdaccio-core'],
|
|
35
36
|
};
|
|
36
37
|
|
|
38
|
+
beforeAll(() => {
|
|
39
|
+
setupDownloadMocks();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
afterAll(() => {
|
|
43
|
+
cleanupDownloadMocks();
|
|
44
|
+
});
|
|
45
|
+
|
|
37
46
|
describe('<Package /> component', () => {
|
|
38
47
|
afterEach(() => {
|
|
39
48
|
cleanup();
|
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
/* eslint-disable verdaccio/jsx-spread */
|
|
2
2
|
import Box from '@mui/material/Box';
|
|
3
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
4
|
+
import { HttpResponse, http } from 'msw';
|
|
3
5
|
import React from 'react';
|
|
4
6
|
import { MemoryRouter } from 'react-router';
|
|
5
7
|
|
|
8
|
+
import Home from '../../sections/Home';
|
|
6
9
|
import Search from './Search';
|
|
7
10
|
|
|
8
|
-
|
|
11
|
+
type Story = StoryObj<typeof Search>;
|
|
12
|
+
const meta: Meta<typeof Search> = {
|
|
9
13
|
title: 'Components/Header/Search',
|
|
14
|
+
component: Home,
|
|
10
15
|
};
|
|
11
16
|
|
|
12
|
-
export
|
|
17
|
+
export default meta;
|
|
18
|
+
|
|
19
|
+
export const SearchByQuery: Story = {
|
|
13
20
|
render: (args) => (
|
|
14
21
|
<MemoryRouter initialEntries={[`/-/web/detail/storybook`]}>
|
|
15
22
|
<Box
|
|
@@ -27,4 +34,19 @@ export const SearchByQuery = {
|
|
|
27
34
|
</Box>
|
|
28
35
|
</MemoryRouter>
|
|
29
36
|
),
|
|
37
|
+
parameters: {
|
|
38
|
+
msw: {
|
|
39
|
+
handlers: [
|
|
40
|
+
http.get('https://my-registry.org/-/verdaccio/data/sidebar/storybook', () => {
|
|
41
|
+
return HttpResponse.json(require('../../../vitest/api/storybook-sidebar.json'));
|
|
42
|
+
}),
|
|
43
|
+
http.get('https://my-registry.org/-/verdaccio/data/package/readme/storybook', () => {
|
|
44
|
+
return HttpResponse.json(require('../../../vitest/api/storybook-readme')());
|
|
45
|
+
}),
|
|
46
|
+
http.get('https://my-registry.org/-/verdaccio/data/search/*', () => {
|
|
47
|
+
return HttpResponse.json(require('../../../vitest/api/search-verdaccio.json'));
|
|
48
|
+
}),
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
},
|
|
30
52
|
};
|
|
@@ -118,6 +118,8 @@ const Search: React.FC<RouteComponentProps> = ({ history }) => {
|
|
|
118
118
|
};
|
|
119
119
|
|
|
120
120
|
const renderOption = (props, option) => {
|
|
121
|
+
const { key, ...otherProps } = props;
|
|
122
|
+
|
|
121
123
|
if (searchRemote) {
|
|
122
124
|
const item: SearchResultWeb = option.package;
|
|
123
125
|
const isPrivate = option?.verdaccioPrivate;
|
|
@@ -125,7 +127,8 @@ const Search: React.FC<RouteComponentProps> = ({ history }) => {
|
|
|
125
127
|
const isRemote = !isCached && !isPrivate;
|
|
126
128
|
return (
|
|
127
129
|
<SearchItem
|
|
128
|
-
{
|
|
130
|
+
key={key}
|
|
131
|
+
{...otherProps}
|
|
129
132
|
description={item?.description}
|
|
130
133
|
isCached={isCached}
|
|
131
134
|
isPrivate={isPrivate}
|
|
@@ -137,7 +140,8 @@ const Search: React.FC<RouteComponentProps> = ({ history }) => {
|
|
|
137
140
|
} else {
|
|
138
141
|
return (
|
|
139
142
|
<SearchItem
|
|
140
|
-
{
|
|
143
|
+
key={key}
|
|
144
|
+
{...otherProps}
|
|
141
145
|
description={option?.description}
|
|
142
146
|
name={option?.name}
|
|
143
147
|
version={option?.version}
|
|
@@ -161,4 +165,4 @@ const Search: React.FC<RouteComponentProps> = ({ history }) => {
|
|
|
161
165
|
);
|
|
162
166
|
};
|
|
163
167
|
|
|
164
|
-
export default withRouter(Search);
|
|
168
|
+
export default withRouter(Search as any);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { HttpResponse, http } from 'msw';
|
|
2
3
|
import React from 'react';
|
|
3
4
|
import { MemoryRouter, Route } from 'react-router';
|
|
4
5
|
|
|
@@ -11,6 +12,7 @@ const meta: Meta<typeof VersionLayout> = {
|
|
|
11
12
|
};
|
|
12
13
|
|
|
13
14
|
export default meta;
|
|
15
|
+
|
|
14
16
|
type Story = StoryObj<typeof VersionLayout>;
|
|
15
17
|
|
|
16
18
|
export const Primary: Story = {
|
|
@@ -26,6 +28,18 @@ export const Primary: Story = {
|
|
|
26
28
|
</MemoryRouter>
|
|
27
29
|
);
|
|
28
30
|
},
|
|
31
|
+
parameters: {
|
|
32
|
+
msw: {
|
|
33
|
+
handlers: [
|
|
34
|
+
http.get('https://my-registry.org/-/verdaccio/data/sidebar/storybook', () => {
|
|
35
|
+
return HttpResponse.json(require('../../../vitest/api/storybook-sidebar.json'));
|
|
36
|
+
}),
|
|
37
|
+
http.get('https://my-registry.org/-/verdaccio/data/package/readme/storybook', () => {
|
|
38
|
+
return HttpResponse.json(require('../../../vitest/api/storybook-readme')());
|
|
39
|
+
}),
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
},
|
|
29
43
|
};
|
|
30
44
|
|
|
31
45
|
export const jQuery: Story = {
|
|
@@ -41,4 +55,16 @@ export const jQuery: Story = {
|
|
|
41
55
|
</MemoryRouter>
|
|
42
56
|
);
|
|
43
57
|
},
|
|
58
|
+
parameters: {
|
|
59
|
+
msw: {
|
|
60
|
+
handlers: [
|
|
61
|
+
http.get('https://my-registry.org/-/verdaccio/data/sidebar/jquery', () => {
|
|
62
|
+
return HttpResponse.json(require('../../../vitest/api/jquery-sidebar.json'));
|
|
63
|
+
}),
|
|
64
|
+
http.get('https://my-registry.org/-/verdaccio/data/package/readme/jquery', () => {
|
|
65
|
+
return HttpResponse.json(require('../../../vitest/api/jquery-readme')());
|
|
66
|
+
}),
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
},
|
|
44
70
|
};
|
|
@@ -1,25 +1,21 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { HttpResponse, http } from 'msw';
|
|
1
3
|
import React from 'react';
|
|
2
4
|
import { MemoryRouter, Route } from 'react-router';
|
|
3
5
|
|
|
4
6
|
import { VersionProvider } from '../../providers';
|
|
5
7
|
import Detail from './Detail';
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
const meta: Meta<typeof Detail> = {
|
|
8
10
|
title: 'Sections/Detail',
|
|
11
|
+
component: Detail,
|
|
9
12
|
};
|
|
10
13
|
|
|
11
|
-
export
|
|
12
|
-
<MemoryRouter initialEntries={[`/-/web/detail/storybook`]}>
|
|
13
|
-
<Route exact={true} path="/-/web/detail/:package">
|
|
14
|
-
<VersionProvider>
|
|
15
|
-
<Detail />
|
|
16
|
-
</VersionProvider>
|
|
17
|
-
</Route>
|
|
18
|
-
</MemoryRouter>
|
|
19
|
-
);
|
|
14
|
+
export default meta;
|
|
20
15
|
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
type Story = StoryObj<typeof Detail>;
|
|
17
|
+
const getDetailApp = (url: string) => (
|
|
18
|
+
<MemoryRouter initialEntries={[url]}>
|
|
23
19
|
<Route exact={true} path="/-/web/detail/:package">
|
|
24
20
|
<VersionProvider>
|
|
25
21
|
<Detail />
|
|
@@ -28,12 +24,47 @@ export const DetailJquery: any = () => (
|
|
|
28
24
|
</MemoryRouter>
|
|
29
25
|
);
|
|
30
26
|
|
|
31
|
-
export const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
)
|
|
27
|
+
export const DetailStorybook: Story = {
|
|
28
|
+
render: () => getDetailApp(`/-/web/detail/storybook`),
|
|
29
|
+
parameters: {
|
|
30
|
+
msw: {
|
|
31
|
+
handlers: [
|
|
32
|
+
http.get('https://my-registry.org/-/verdaccio/data/sidebar/storybook', () => {
|
|
33
|
+
return HttpResponse.json(require('../../../vitest/api/storybook-sidebar.json'));
|
|
34
|
+
}),
|
|
35
|
+
http.get('https://my-registry.org/-/verdaccio/data/package/readme/storybook', () => {
|
|
36
|
+
return HttpResponse.json(require('../../../vitest/api/storybook-readme')());
|
|
37
|
+
}),
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const DetailJquery: Story = {
|
|
44
|
+
render: () => getDetailApp(`/-/web/detail/jquery`),
|
|
45
|
+
parameters: {
|
|
46
|
+
msw: {
|
|
47
|
+
handlers: [
|
|
48
|
+
http.get('https://my-registry.org/-/verdaccio/data/sidebar/jquery', () => {
|
|
49
|
+
return HttpResponse.json(require('../../../vitest/api/jquery-sidebar.json'));
|
|
50
|
+
}),
|
|
51
|
+
http.get('https://my-registry.org/-/verdaccio/data/package/readme/jquery', () => {
|
|
52
|
+
return HttpResponse.json(require('../../../vitest/api/jquery-readme')());
|
|
53
|
+
}),
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const DetailForbidden: Story = {
|
|
60
|
+
render: () => getDetailApp(`/-/web/detail/JSONStream`),
|
|
61
|
+
parameters: {
|
|
62
|
+
msw: {
|
|
63
|
+
handlers: [
|
|
64
|
+
http.get('https://my-registry.org/-/verdaccio/data/sidebar/JSONStream', () => {
|
|
65
|
+
return new HttpResponse('unauthorized', { status: 401 });
|
|
66
|
+
}),
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { HttpResponse, http } from 'msw';
|
|
1
3
|
import React from 'react';
|
|
2
4
|
import { MemoryRouter, Route } from 'react-router';
|
|
3
5
|
|
|
@@ -5,10 +7,14 @@ import { HeaderInfoDialog } from '../../';
|
|
|
5
7
|
import { VersionProvider } from '../../providers';
|
|
6
8
|
import Header from './Header';
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
type Story = StoryObj<typeof Header>;
|
|
11
|
+
const meta: Meta<typeof Header> = {
|
|
9
12
|
title: 'Sections/Header',
|
|
13
|
+
component: Header,
|
|
10
14
|
};
|
|
11
15
|
|
|
16
|
+
export default meta;
|
|
17
|
+
|
|
12
18
|
function CustomInfoDialog({ onCloseDialog, title, isOpen }) {
|
|
13
19
|
return (
|
|
14
20
|
<HeaderInfoDialog
|
|
@@ -25,12 +31,29 @@ function CustomInfoDialog({ onCloseDialog, title, isOpen }) {
|
|
|
25
31
|
);
|
|
26
32
|
}
|
|
27
33
|
|
|
28
|
-
export const HeaderAll:
|
|
29
|
-
|
|
30
|
-
<
|
|
31
|
-
<
|
|
32
|
-
<
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
export const HeaderAll: Story = {
|
|
35
|
+
render: () => (
|
|
36
|
+
<MemoryRouter initialEntries={[`/-/web/detail/storybook`]}>
|
|
37
|
+
<Route exact={true} path="/-/web/detail/:package">
|
|
38
|
+
<VersionProvider>
|
|
39
|
+
<Header HeaderInfoDialog={CustomInfoDialog} />
|
|
40
|
+
</VersionProvider>
|
|
41
|
+
</Route>
|
|
42
|
+
</MemoryRouter>
|
|
43
|
+
),
|
|
44
|
+
parameters: {
|
|
45
|
+
msw: {
|
|
46
|
+
handlers: [
|
|
47
|
+
http.get('https://my-registry.org/-/verdaccio/data/sidebar/storybook', () => {
|
|
48
|
+
return HttpResponse.json(require('../../../vitest/api/storybook-sidebar.json'));
|
|
49
|
+
}),
|
|
50
|
+
http.get('https://my-registry.org/-/verdaccio/data/package/readme/storybook', () => {
|
|
51
|
+
return HttpResponse.json(require('../../../vitest/api/storybook-readme')());
|
|
52
|
+
}),
|
|
53
|
+
http.get('https://my-registry.org/-/verdaccio/data/search/*', () => {
|
|
54
|
+
return HttpResponse.json(require('../../../vitest/api/search-verdaccio.json'));
|
|
55
|
+
}),
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
};
|
|
@@ -1,16 +1,33 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { HttpResponse, http } from 'msw';
|
|
1
3
|
import React from 'react';
|
|
2
4
|
import { MemoryRouter, Route } from 'react-router';
|
|
3
5
|
|
|
4
6
|
import Home from './Home';
|
|
5
7
|
|
|
6
|
-
|
|
8
|
+
type Story = StoryObj<typeof Home>;
|
|
9
|
+
const meta: Meta<typeof Home> = {
|
|
7
10
|
title: 'Sections/Home',
|
|
11
|
+
component: Home,
|
|
8
12
|
};
|
|
9
13
|
|
|
10
|
-
export
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
export default meta;
|
|
15
|
+
|
|
16
|
+
export const HomeDefault: Story = {
|
|
17
|
+
render: () => (
|
|
18
|
+
<MemoryRouter initialEntries={[`/`]}>
|
|
19
|
+
<Route exact={true} path="/">
|
|
20
|
+
<Home />
|
|
21
|
+
</Route>
|
|
22
|
+
</MemoryRouter>
|
|
23
|
+
),
|
|
24
|
+
parameters: {
|
|
25
|
+
msw: {
|
|
26
|
+
handlers: [
|
|
27
|
+
http.get('https://my-registry.org/-/verdaccio/data/packages', () => {
|
|
28
|
+
return HttpResponse.json([...require('../../../vitest/api/home.json')]);
|
|
29
|
+
}),
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
};
|
|
@@ -1,39 +1,64 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { HttpResponse, http } from 'msw';
|
|
1
3
|
import React from 'react';
|
|
2
4
|
import { MemoryRouter, Route } from 'react-router';
|
|
3
5
|
|
|
4
6
|
import { VersionProvider } from '../../providers';
|
|
5
7
|
import DetailSidebar from './Sidebar';
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
const meta: Meta<typeof DetailSidebar> = {
|
|
8
10
|
title: 'Sections/Sidebar',
|
|
11
|
+
component: DetailSidebar,
|
|
9
12
|
};
|
|
10
13
|
|
|
11
|
-
export
|
|
12
|
-
<MemoryRouter initialEntries={[`/-/web/detail/storybook`]}>
|
|
13
|
-
<Route exact={true} path="/-/web/detail/:package">
|
|
14
|
-
<VersionProvider>
|
|
15
|
-
<DetailSidebar />
|
|
16
|
-
</VersionProvider>
|
|
17
|
-
</Route>
|
|
18
|
-
</MemoryRouter>
|
|
19
|
-
);
|
|
14
|
+
export default meta;
|
|
20
15
|
|
|
21
|
-
|
|
22
|
-
<MemoryRouter initialEntries={[`/-/web/detail/storybook/v/6.0.26`]}>
|
|
23
|
-
<Route exact={true} path="/-/web/detail/:package/v/:version">
|
|
24
|
-
<VersionProvider>
|
|
25
|
-
<DetailSidebar />
|
|
26
|
-
</VersionProvider>
|
|
27
|
-
</Route>
|
|
28
|
-
</MemoryRouter>
|
|
29
|
-
);
|
|
16
|
+
type Story = StoryObj<typeof DetailSidebar>;
|
|
30
17
|
|
|
31
|
-
export const
|
|
32
|
-
|
|
33
|
-
<
|
|
34
|
-
<
|
|
35
|
-
<
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
18
|
+
export const SidebarLatestPackage: Story = {
|
|
19
|
+
render: () => (
|
|
20
|
+
<MemoryRouter initialEntries={[`/-/web/detail/storybook`]}>
|
|
21
|
+
<Route exact={true} path="/-/web/detail/:package">
|
|
22
|
+
<VersionProvider>
|
|
23
|
+
<DetailSidebar />
|
|
24
|
+
</VersionProvider>
|
|
25
|
+
</Route>
|
|
26
|
+
</MemoryRouter>
|
|
27
|
+
),
|
|
28
|
+
parameters: {
|
|
29
|
+
msw: {
|
|
30
|
+
handlers: [
|
|
31
|
+
http.get('https://my-registry.org/-/verdaccio/data/sidebar/storybook', () => {
|
|
32
|
+
return HttpResponse.json(require('../../../vitest/api/storybook-sidebar.json'));
|
|
33
|
+
}),
|
|
34
|
+
http.get('https://my-registry.org/-/verdaccio/data/package/readme/storybook', () => {
|
|
35
|
+
return HttpResponse.json(require('../../../vitest/api/storybook-readme')());
|
|
36
|
+
}),
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const SidebarPackageVersion: Story = {
|
|
43
|
+
render: () => (
|
|
44
|
+
<MemoryRouter initialEntries={[`/-/web/detail/storybook/v/6.0.26`]}>
|
|
45
|
+
<Route exact={true} path="/-/web/detail/:package/v/:version">
|
|
46
|
+
<VersionProvider>
|
|
47
|
+
<DetailSidebar />
|
|
48
|
+
</VersionProvider>
|
|
49
|
+
</Route>
|
|
50
|
+
</MemoryRouter>
|
|
51
|
+
),
|
|
52
|
+
parameters: {
|
|
53
|
+
msw: {
|
|
54
|
+
handlers: [
|
|
55
|
+
http.get('https://my-registry.org/-/verdaccio/data/sidebar/storybook', () => {
|
|
56
|
+
return HttpResponse.json(require('../../../vitest/api/storybook-sidebar.json'));
|
|
57
|
+
}),
|
|
58
|
+
http.get('https://my-registry.org/-/verdaccio/data/package/readme/storybook', () => {
|
|
59
|
+
return HttpResponse.json(require('../../../vitest/api/storybook-readme')());
|
|
60
|
+
}),
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
};
|
package/src/utils/url.ts
CHANGED
|
@@ -45,13 +45,29 @@ export function downloadFile(fileStream: Blob, fileName: string): void {
|
|
|
45
45
|
fileLink.href = objectURL;
|
|
46
46
|
fileLink.download = fileName;
|
|
47
47
|
|
|
48
|
-
//
|
|
49
|
-
//
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
48
|
+
// Skip actual download in test environment to avoid JSDOM navigation error
|
|
49
|
+
// Check if we're in a test environment (JSDOM)
|
|
50
|
+
const isTestEnvironment =
|
|
51
|
+
(typeof window !== 'undefined' &&
|
|
52
|
+
window.navigator &&
|
|
53
|
+
window.navigator.userAgent &&
|
|
54
|
+
window.navigator.userAgent.includes('Node.js')) ||
|
|
55
|
+
window.navigator.userAgent.includes('jsdom');
|
|
56
|
+
|
|
57
|
+
if (!isTestEnvironment) {
|
|
58
|
+
// Without appending to an HTML Element, download dialog does not show up on Firefox
|
|
59
|
+
// https://github.com/verdaccio/ui/issues/119
|
|
60
|
+
document.documentElement.appendChild(fileLink);
|
|
61
|
+
fileLink.click();
|
|
62
|
+
// firefox requires remove the object url
|
|
63
|
+
setTimeout(() => {
|
|
64
|
+
URL.revokeObjectURL(objectURL);
|
|
65
|
+
document.documentElement.removeChild(fileLink);
|
|
66
|
+
}, 150);
|
|
67
|
+
} else {
|
|
68
|
+
// In test environment, just clean up without triggering navigation
|
|
69
|
+
setTimeout(() => {
|
|
70
|
+
URL.revokeObjectURL(objectURL);
|
|
71
|
+
}, 150);
|
|
72
|
+
}
|
|
57
73
|
}
|
package/tsconfig.build.json
CHANGED
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
"rootDir": ".",
|
|
11
11
|
"outDir": "./build",
|
|
12
12
|
"skipLibCheck": true,
|
|
13
|
-
"jsx": "react"
|
|
13
|
+
"jsx": "react",
|
|
14
|
+
"types": ["node", "@testing-library/jest-dom"]
|
|
14
15
|
},
|
|
15
16
|
"include": ["src/**/*", "./src/types/index.d.ts"],
|
|
16
|
-
"types": ["node", "@testing-library/jest-dom"],
|
|
17
17
|
"typedocOptions": {
|
|
18
18
|
"categoryOrder": ["Model", "Component", "Provider", "*"],
|
|
19
19
|
"defaultCategory": "Component",
|
package/tsconfig.json
CHANGED
|
@@ -10,9 +10,10 @@
|
|
|
10
10
|
"outDir": "./build",
|
|
11
11
|
"preserveSymlinks": true,
|
|
12
12
|
"jsx": "react",
|
|
13
|
-
"allowJs": true
|
|
13
|
+
"allowJs": true,
|
|
14
|
+
"types": ["node", "jest", "@testing-library/jest-dom"]
|
|
14
15
|
},
|
|
15
|
-
"
|
|
16
|
+
"include": ["src/**/*", "vitest/**/*", "src/test/**/*"],
|
|
16
17
|
"references": [
|
|
17
18
|
{
|
|
18
19
|
"path": "../core/types"
|
package/vitest.config.mjs
CHANGED
|
@@ -7,7 +7,7 @@ export default defineConfig({
|
|
|
7
7
|
environment: 'jsdom',
|
|
8
8
|
globals: true,
|
|
9
9
|
setupFiles: ['./vitest/setup.ts', './vitest/setup-env.ts'],
|
|
10
|
-
exclude: ['node_modules', '
|
|
10
|
+
exclude: ['**/node_modules/**', '**/build/**'],
|
|
11
11
|
snapshotFormat: {
|
|
12
12
|
escapeString: true,
|
|
13
13
|
printBasicPrototype: true,
|
|
@@ -22,7 +22,7 @@ export default defineConfig({
|
|
|
22
22
|
'\\.(jpg)$': './vitest/unit/empty.ts',
|
|
23
23
|
'\\.(md)$': './vitest/unit/empty-string.ts',
|
|
24
24
|
},
|
|
25
|
-
testTimeout:
|
|
25
|
+
testTimeout: 20000,
|
|
26
26
|
},
|
|
27
27
|
plugins: [
|
|
28
28
|
react({
|