@verdaccio/ui-components 4.0.0-next-8.4 → 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.
Files changed (82) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/build/components/CopyClipboard/CopyToClipBoard.js +2 -2
  3. package/build/components/HeaderInfoDialog/HeaderInfoDialog.js +2 -2
  4. package/build/components/Heading/Heading.js +2 -2
  5. package/build/components/Help/Help.js +1 -1
  6. package/build/components/Icons/SvgIcon.js +2 -2
  7. package/build/components/Label/Label.js +2 -2
  8. package/build/components/LinkExternal/LinkExternal.js +2 -2
  9. package/build/components/NoItems/NoItems.js +2 -2
  10. package/build/components/Package/styles.js +13 -13
  11. package/build/components/Readme/Readme.spec.js +4 -2
  12. package/build/components/Readme/Readme.spec.js.map +1 -1
  13. package/build/components/Readme/utils.js +1 -1
  14. package/build/components/Search/Search.js +13 -2
  15. package/build/components/Search/SearchItem.js +2 -2
  16. package/build/components/TextField/TextField.js +2 -2
  17. package/build/components/Versions/HistoryList.js +6 -1
  18. package/build/components/Versions/__partials__/unsorted-versions.json +37 -0
  19. package/build/sections/Header/HeaderSettingsDialog.js +2 -2
  20. package/build/src/AppTest/App.stories.d.ts +9 -8
  21. package/build/src/components/Author/Author.stories.d.ts +1 -1
  22. package/build/src/components/Engines/Engines.stories.d.ts +1 -1
  23. package/build/src/components/Search/Search.d.ts +3 -1
  24. package/build/src/components/Search/Search.stories.d.ts +6 -8
  25. package/build/src/sections/Detail/Detail.stories.d.ts +8 -7
  26. package/build/src/sections/Header/Header.stories.d.ts +6 -5
  27. package/build/src/sections/Home/Home.stories.d.ts +6 -5
  28. package/build/src/sections/SideBar/Sidebar.stories.d.ts +7 -7
  29. package/build/src/store/api.d.ts +3 -0
  30. package/build/src/utils/token-generate.d.ts +4 -0
  31. package/build/store/api.js +1 -1
  32. package/build/store/models/routes.js +1 -1
  33. package/build/utils/token-generate.js +33 -0
  34. package/build/utils/url.js +19 -9
  35. package/package.json +37 -31
  36. package/src/AppTest/App.stories.tsx +81 -24
  37. package/src/AppTest/AppRoute.test.tsx +6 -2
  38. package/src/components/ActionBar/ActionBar.test.tsx +68 -29
  39. package/src/components/Author/Author.stories.tsx +1 -1
  40. package/src/components/Engines/Engines.stories.tsx +12 -12
  41. package/src/components/Help/Help.tsx +1 -1
  42. package/src/components/Package/Package.test.tsx +9 -0
  43. package/src/components/Package/styles.ts +1 -2
  44. package/src/components/Readme/Readme.spec.tsx +2 -2
  45. package/src/components/Readme/utils.ts +2 -2
  46. package/src/components/Search/Search.stories.tsx +24 -2
  47. package/src/components/Search/Search.tsx +7 -3
  48. package/src/components/Versions/HistoryList.tsx +10 -2
  49. package/src/components/Versions/Versions.test.tsx +11 -0
  50. package/src/components/Versions/__partials__/unsorted-versions.json +37 -0
  51. package/src/layouts/Version/Version.stories.tsx +26 -0
  52. package/src/sections/Detail/Detail.stories.tsx +52 -21
  53. package/src/sections/Header/Header.stories.tsx +33 -10
  54. package/src/sections/Home/Home.stories.tsx +25 -8
  55. package/src/sections/SideBar/Sidebar.stories.tsx +53 -28
  56. package/src/store/api.test.ts +4 -2
  57. package/src/store/api.ts +1 -1
  58. package/src/store/models/login.test.ts +25 -19
  59. package/src/utils/token.test.ts +2 -3
  60. package/src/utils/url.ts +25 -9
  61. package/tsconfig.build.json +2 -2
  62. package/tsconfig.json +3 -2
  63. package/vitest.config.mjs +2 -1
  64. package/vitest/api/glob-sidebar.json +0 -12520
  65. package/vitest/api/got-sidebar.json +0 -23346
  66. package/vitest/api/home-packages.json +0 -40
  67. package/vitest/api/jquery-readme.js +0 -3
  68. package/vitest/api/jquery-sidebar.json +0 -5908
  69. package/vitest/api/search-verdaccio.json +0 -1192
  70. package/vitest/api/storybook-readme.js +0 -3
  71. package/vitest/api/storybook-sidebar.json +0 -53782
  72. package/vitest/api/storybook-v.json +0 -53782
  73. package/vitest/identity.js +0 -29
  74. package/vitest/react-markdown.tsx +0 -7
  75. package/vitest/server-handlers.ts +0 -82
  76. package/vitest/server.ts +0 -6
  77. package/vitest/setup-env.ts +0 -33
  78. package/vitest/setup.ts +0 -40
  79. package/vitest/unit/empty-string.ts +0 -1
  80. package/vitest/unit/empty.ts +0 -1
  81. package/vitest/vitestSerializer.ts +0 -31
  82. /package/{vitest/unit/components/__mocks__/token.ts → src/utils/token-generate.ts} +0 -0
@@ -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 { cleanup, fireEvent, renderWithStore, screen } from '../../test/test-react-testing-library';
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
- expect(screen.getByTestId('download-tarball-btn')).toBeInTheDocument();
32
- expect(screen.getByTestId('BugReportIcon')).toBeInTheDocument();
33
- expect(screen.getByTestId('HomeIcon')).toBeInTheDocument();
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
- expect(screen.queryByTestId('HomeIcon')).toBeNull();
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
- expect(screen.queryByTestId('download-tarball-btn')).not.toBeInTheDocument();
58
- expect(screen.queryByTestId('BugReportIcon')).not.toBeInTheDocument();
59
- expect(screen.queryByTestId('HomeIcon')).not.toBeInTheDocument();
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
- expect(screen.getByLabelText('action-bar-action.download-tarball')).toBeTruthy();
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
- expect(screen.queryByTestId('download-tarball-btn')).not.toBeInTheDocument();
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
- expect(screen.getByLabelText('action-bar-action.raw')).toBeTruthy();
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
- expect(screen.queryByTestId('rawViewer--dialog')).toBeFalsy();
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 screen.findByTestId('rawViewer--dialog');
114
+ await waitFor(() => {
115
+ expect(screen.getByTestId('rawViewer--dialog')).toBeInTheDocument();
116
+ });
86
117
 
87
118
  fireEvent.click(screen.getByTestId('close-raw-viewer'));
88
- await screen.getByLabelText('action-bar-action.raw');
89
-
90
- expect(screen.queryByTestId('rawViewer--dialog')).toBeFalsy();
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
- expect(screen.queryByLabelText('Download tarball')).toBeFalsy();
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 store.getState().loading.models.download;
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
- expect(screen.queryByLabelText('action-bar-action.raw')).toBeFalsy();
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
- expect(screen.getByTestId('BugReportIcon')).toBeInTheDocument();
148
+ await waitFor(() => {
149
+ expect(screen.getByTestId('BugReportIcon')).toBeInTheDocument();
150
+ });
112
151
  });
113
152
  });
@@ -35,7 +35,7 @@ export const AuthorAll: any = () => (
35
35
  />
36
36
  );
37
37
 
38
- export const NoDAuthor: any = () => (
38
+ export const NoAuthor: any = () => (
39
39
  <Author
40
40
  packageMeta={{
41
41
  latest: {
@@ -6,12 +6,14 @@ export default {
6
6
  title: 'Components/Sidebar/Engines',
7
7
  };
8
8
 
9
- export const EnginesNpmNode: any = () => (
9
+ export const EnginesAll: any = () => (
10
10
  <Engines
11
11
  packageMeta={{
12
12
  latest: {
13
13
  engines: {
14
- node: '>= 0.1.98',
14
+ node: '>= 18',
15
+ pnpm: '>7',
16
+ yarn: '>3',
15
17
  npm: '>3',
16
18
  },
17
19
  },
@@ -19,51 +21,49 @@ export const EnginesNpmNode: any = () => (
19
21
  />
20
22
  );
21
23
 
22
- export const EnginesNode: any = () => (
24
+ export const EnginesNpmNode: any = () => (
23
25
  <Engines
24
26
  packageMeta={{
25
27
  latest: {
26
28
  engines: {
27
- node: '>= 18',
29
+ node: '>= 0.1.98',
30
+ npm: '>3',
28
31
  },
29
32
  },
30
33
  }}
31
34
  />
32
35
  );
33
36
 
34
- export const EnginesYarn: any = () => (
37
+ export const EnginesNode: any = () => (
35
38
  <Engines
36
39
  packageMeta={{
37
40
  latest: {
38
41
  engines: {
39
- yarn: '>3',
42
+ node: '>= 18',
40
43
  },
41
44
  },
42
45
  }}
43
46
  />
44
47
  );
45
48
 
46
- export const EnginesPnpm: any = () => (
49
+ export const EnginesYarn: any = () => (
47
50
  <Engines
48
51
  packageMeta={{
49
52
  latest: {
50
53
  engines: {
51
- pnpm: '>7',
54
+ yarn: '>3',
52
55
  },
53
56
  },
54
57
  }}
55
58
  />
56
59
  );
57
60
 
58
- export const EnginesAll: any = () => (
61
+ export const EnginesPnpm: any = () => (
59
62
  <Engines
60
63
  packageMeta={{
61
64
  latest: {
62
65
  engines: {
63
- node: '>= 18',
64
66
  pnpm: '>7',
65
- yarn: '>3',
66
- npm: '>3',
67
67
  },
68
68
  },
69
69
  }}
@@ -40,7 +40,7 @@ const Help: React.FC = () => {
40
40
  t('help.second-step'),
41
41
  t('help.second-step-command-line', { registryUrl })
42
42
  )}
43
- <Typography variant="body2">{t('help.third-step')}</Typography>
43
+ <Typography variant="body1">{t('help.third-step')}</Typography>
44
44
  </CardContent>
45
45
  <CardActions>
46
46
  <Button color="primary" href="https://verdaccio.org/docs/cli-registry" size="small">
@@ -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();
@@ -71,8 +71,7 @@ export const GridRightAligned = styled(Grid)({
71
71
 
72
72
  export const Wrapper = styled(List)<{ theme?: Theme }>(({ theme }) => ({
73
73
  '&:hover': {
74
- backgroundColor:
75
- theme.palette.mode == 'dark' ? theme.palette.secondary.main : theme.palette.greyLight2,
74
+ backgroundColor: theme.palette.action.hover,
76
75
  },
77
76
  }));
78
77
 
@@ -7,8 +7,8 @@ describe('<Readme /> component', () => {
7
7
  beforeEach(cleanup);
8
8
 
9
9
  test('should load the component in default state', () => {
10
- const wrapper = render(<Readme description="test" />);
11
- expect(wrapper).toMatchSnapshot();
10
+ const { getByText } = render(<Readme description="test" />);
11
+ expect(getByText('test')).toBeInTheDocument();
12
12
  });
13
13
 
14
14
  test('should dangerously set html', () => {
@@ -1,4 +1,4 @@
1
- import * as DOMPurify from 'dompurify';
1
+ import DOMPurify from 'dompurify';
2
2
  import { Marked } from 'marked';
3
3
  import { markedHighlight } from 'marked-highlight';
4
4
 
@@ -22,5 +22,5 @@ marked.setOptions({
22
22
 
23
23
  export function parseReadme(readme: string): string | void {
24
24
  const html = marked.parse(readme);
25
- return DOMPurify.sanitize(html);
25
+ return DOMPurify.sanitize(html as string);
26
26
  }
@@ -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
- export default {
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 const SearchByQuery = {
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
- {...props}
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
- {...props}
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);
@@ -39,7 +39,11 @@ const VersionsHistoryList: React.FC<Props> = ({ versions, packageName, time }) =
39
39
  return (
40
40
  <List dense={true}>
41
41
  {Object.keys(listVersions)
42
- .reverse()
42
+ .sort((a, b) => {
43
+ const timeA = time[a] ? new Date(time[a]).getTime() : 0;
44
+ const timeB = time[b] ? new Date(time[b]).getTime() : 0;
45
+ return timeB - timeA;
46
+ })
43
47
  .map((version) => (
44
48
  <ListItem
45
49
  className="version-item"
@@ -48,7 +52,11 @@ const VersionsHistoryList: React.FC<Props> = ({ versions, packageName, time }) =
48
52
  sx={{ pr: 0 }}
49
53
  >
50
54
  <Link to={`${Route.DETAIL}${packageName}/v/${version}`} variant="outline">
51
- <ListItemText disableTypography={false} primary={version}></ListItemText>
55
+ <ListItemText
56
+ data-testid={`version-list-link`}
57
+ disableTypography={false}
58
+ primary={version}
59
+ />
52
60
  </Link>
53
61
  {typeof versions[version]?.deprecated === 'string' ? (
54
62
  <Chip
@@ -7,6 +7,7 @@ import { fireEvent, render, screen } from '../../test/test-react-testing-library
7
7
  import Versions, { Props } from './Versions';
8
8
  import data from './__partials__/data.json';
9
9
  import dataDeprecated from './__partials__/deprecated-versions.json';
10
+ import dataUnsorted from './__partials__/unsorted-versions.json';
10
11
 
11
12
  const VersionsComponent: React.FC<Props> = (props) => (
12
13
  <MemoryRouter>
@@ -68,5 +69,15 @@ describe('<Version /> component', () => {
68
69
  expect(screen.getByText('0.0.1')).toBeInTheDocument();
69
70
  });
70
71
 
72
+ test('should render versions sorted by timestamp in descending order', () => {
73
+ render(<VersionsComponent packageMeta={dataUnsorted} packageName={'dummy'} />);
74
+
75
+ const versionElements = screen.getAllByTestId('version-list-link');
76
+ const versions = versionElements.map((el) => el.textContent);
77
+
78
+ // Expected order based on timestamps in unsorted-versions.json:
79
+ expect(versions).toEqual(['1.0.1', '1.0.0', '0.1.1', '0.1.0']);
80
+ });
81
+
71
82
  test.todo('should click on version link');
72
83
  });
@@ -0,0 +1,37 @@
1
+ {
2
+ "versions": {
3
+ "1.0.0": {
4
+ "name": "dummy",
5
+ "version": "1.0.0"
6
+ },
7
+ "0.1.0": {
8
+ "name": "dummy",
9
+ "version": "0.1.0"
10
+ },
11
+ "0.1.1": {
12
+ "name": "dummy",
13
+ "version": "0.1.1"
14
+ },
15
+ "1.0.1": {
16
+ "name": "dummy",
17
+ "version": "1.0.1"
18
+ }
19
+ },
20
+ "time": {
21
+ "created": "2012-02-19T21:35:53.514Z",
22
+ "modified": "2024-11-21T06:32:43.761Z",
23
+ "1.0.0": "2025-01-10T14:55:23.763Z",
24
+ "0.1.0": "2012-02-19T21:35:54.455Z",
25
+ "0.1.1": "2012-02-20T06:12:03.403Z",
26
+ "1.0.1": "2025-01-10T15:11:36.318Z"
27
+ },
28
+ "users": {},
29
+ "dist-tags": {
30
+ "latest": "1.0.1"
31
+ },
32
+ "_id": "dummy",
33
+ "latest": {
34
+ "name": "dummy",
35
+ "version": "1.0.1"
36
+ }
37
+ }
@@ -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
- export default {
9
+ const meta: Meta<typeof Detail> = {
8
10
  title: 'Sections/Detail',
11
+ component: Detail,
9
12
  };
10
13
 
11
- export const DetailStorybook: any = () => (
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
- export const DetailJquery: any = () => (
22
- <MemoryRouter initialEntries={[`/-/web/detail/jquery`]}>
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 DetailForbidden: any = () => (
32
- <MemoryRouter initialEntries={[`/-/web/detail/JSONStream`]}>
33
- <Route exact={true} path="/-/web/detail/:package">
34
- <VersionProvider>
35
- <Detail />
36
- </VersionProvider>
37
- </Route>
38
- </MemoryRouter>
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
+ };