mirror of
https://github.com/verdaccio/verdaccio.git
synced 2024-11-08 23:25:51 +01:00
feat: upgrade react 18 (#3495)
* chore: update react 18 * Create four-ways-try.md * Update signin.cy.ts * chore: new ci * Update e2e-ui.yml * Update e2e-ui.yml * ci * ci * ci * Update e2e-ui.yml * Update e2e-ui.yml * chore: fix ui test * Update publish.cy.ts * chore: update tests * add strict mode
This commit is contained in:
parent
17984fa31b
commit
0481b9a329
5
.changeset/four-ways-try.md
Normal file
5
.changeset/four-ways-try.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'@verdaccio/ui-theme': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
feat: upgrade to react 18
|
47
.github/workflows/ci.yml
vendored
47
.github/workflows/ci.yml
vendored
@ -33,7 +33,9 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
run: npm i pnpm@6.32.15 -g
|
run: |
|
||||||
|
corepack enable
|
||||||
|
corepack prepare --activate pnpm@6.32.15
|
||||||
- name: set store
|
- name: set store
|
||||||
run: |
|
run: |
|
||||||
mkdir ~/.pnpm-store
|
mkdir ~/.pnpm-store
|
||||||
@ -58,7 +60,9 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
run: npm i pnpm@6.32.15 -g
|
run: |
|
||||||
|
corepack enable
|
||||||
|
corepack prepare --activate pnpm@6.32.15
|
||||||
- uses: actions/cache@1c73980b09e7aea7201f325a7aa3ad00beddcdda # tag=v3
|
- uses: actions/cache@1c73980b09e7aea7201f325a7aa3ad00beddcdda # tag=v3
|
||||||
with:
|
with:
|
||||||
path: ~/.pnpm-store
|
path: ~/.pnpm-store
|
||||||
@ -78,7 +82,9 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
run: npm i pnpm@6.32.15 -g
|
run: |
|
||||||
|
corepack enable
|
||||||
|
corepack prepare --activate pnpm@6.32.15
|
||||||
- uses: actions/cache@1c73980b09e7aea7201f325a7aa3ad00beddcdda # tag=v3
|
- uses: actions/cache@1c73980b09e7aea7201f325a7aa3ad00beddcdda # tag=v3
|
||||||
with:
|
with:
|
||||||
path: ~/.pnpm-store
|
path: ~/.pnpm-store
|
||||||
@ -87,7 +93,7 @@ jobs:
|
|||||||
run: pnpm recursive install --offline --frozen-lockfile --reporter=silence --ignore-scripts
|
run: pnpm recursive install --offline --frozen-lockfile --reporter=silence --ignore-scripts
|
||||||
- name: Lint
|
- name: Lint
|
||||||
run: pnpm format:check
|
run: pnpm format:check
|
||||||
build:
|
test:
|
||||||
needs: [format, lint]
|
needs: [format, lint]
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: true
|
fail-fast: true
|
||||||
@ -103,7 +109,9 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node_version }}
|
node-version: ${{ matrix.node_version }}
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
run: npm i pnpm@6.32.15 -g
|
run: |
|
||||||
|
corepack enable
|
||||||
|
corepack prepare --activate pnpm@6.32.15
|
||||||
- uses: actions/cache@1c73980b09e7aea7201f325a7aa3ad00beddcdda # tag=v3
|
- uses: actions/cache@1c73980b09e7aea7201f325a7aa3ad00beddcdda # tag=v3
|
||||||
with:
|
with:
|
||||||
path: ~/.pnpm-store
|
path: ~/.pnpm-store
|
||||||
@ -114,31 +122,8 @@ jobs:
|
|||||||
run: pnpm build
|
run: pnpm build
|
||||||
- name: Test
|
- name: Test
|
||||||
run: pnpm test
|
run: pnpm test
|
||||||
ci-e2e-ui:
|
|
||||||
needs: [format, lint]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: UI Test E2E
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
|
|
||||||
- uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # tag=v3
|
|
||||||
with:
|
|
||||||
node-version-file: '.nvmrc'
|
|
||||||
- name: Install pnpm
|
|
||||||
run: npm i pnpm@6.32.15 -g
|
|
||||||
- uses: actions/cache@1c73980b09e7aea7201f325a7aa3ad00beddcdda # tag=v3
|
|
||||||
with:
|
|
||||||
path: ~/.pnpm-store
|
|
||||||
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
|
||||||
- name: Install
|
|
||||||
run: pnpm recursive install --offline --frozen-lockfile --reporter=silence --registry http://localhost:4873
|
|
||||||
- name: build
|
|
||||||
run: pnpm build
|
|
||||||
- name: Test UI
|
|
||||||
run: pnpm test:e2e:ui
|
|
||||||
# env:
|
|
||||||
# DEBUG: verdaccio:e2e*
|
|
||||||
sync-translations:
|
sync-translations:
|
||||||
needs: [ci-e2e-ui]
|
needs: [test]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
name: synchronize translations
|
name: synchronize translations
|
||||||
if: (github.event_name == 'push' && github.ref == 'refs/heads/master') || github.event_name == 'workflow_dispatch'
|
if: (github.event_name == 'push' && github.ref == 'refs/heads/master') || github.event_name == 'workflow_dispatch'
|
||||||
@ -148,7 +133,9 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
run: npm i pnpm@6.32.15 -g
|
run: |
|
||||||
|
corepack enable
|
||||||
|
corepack prepare --activate pnpm@6.32.15
|
||||||
- uses: actions/cache@1c73980b09e7aea7201f325a7aa3ad00beddcdda # tag=v3
|
- uses: actions/cache@1c73980b09e7aea7201f325a7aa3ad00beddcdda # tag=v3
|
||||||
with:
|
with:
|
||||||
path: ~/.pnpm-store
|
path: ~/.pnpm-store
|
||||||
|
36
.github/workflows/e2e-ui.yml
vendored
Normal file
36
.github/workflows/e2e-ui.yml
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
name: E2E UI
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: UI Test E2E
|
||||||
|
services:
|
||||||
|
verdaccio:
|
||||||
|
image: verdaccio/verdaccio:5
|
||||||
|
ports:
|
||||||
|
- 4873:4873
|
||||||
|
env:
|
||||||
|
NODE_ENV: production
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3
|
||||||
|
- name: Use Node
|
||||||
|
uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # tag=v3
|
||||||
|
with:
|
||||||
|
node-version-file: '.nvmrc'
|
||||||
|
- name: Install pnpm
|
||||||
|
run: |
|
||||||
|
corepack enable
|
||||||
|
corepack prepare --activate pnpm@6.32.15
|
||||||
|
- name: Install
|
||||||
|
run: pnpm install --frozen-lockfile --reporter=silence --registry http://localhost:4873
|
||||||
|
- name: build
|
||||||
|
run: pnpm build
|
||||||
|
- name: Test UI
|
||||||
|
run: pnpm test:e2e:ui
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: videos
|
||||||
|
path: /home/runner/work/verdaccio/verdaccio/e2e/ui/cypress/videos
|
1
.npmrc
1
.npmrc
@ -1,5 +1,4 @@
|
|||||||
always-auth = true
|
always-auth = true
|
||||||
recursive-install = true
|
recursive-install = true
|
||||||
registry = https://registry.verdaccio.org
|
|
||||||
loglevel=info
|
loglevel=info
|
||||||
fetch-retries="10"
|
fetch-retries="10"
|
||||||
|
@ -3,18 +3,26 @@ web:
|
|||||||
title: verdaccio-server-e2e
|
title: verdaccio-server-e2e
|
||||||
login: true
|
login: true
|
||||||
|
|
||||||
log: { type: stdout, format: pretty, level: debug }
|
log: { type: stdout, format: json, level: info }
|
||||||
|
|
||||||
|
uplinks:
|
||||||
|
npmjs:
|
||||||
|
url: https://registry.npmjs.org/
|
||||||
|
|
||||||
auth:
|
auth:
|
||||||
htpasswd:
|
htpasswd:
|
||||||
file: ./htpasswd
|
file: ./htpasswd
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
'@verdaccio/*':
|
||||||
|
access: $all
|
||||||
|
publish: $authenticated
|
||||||
'@*/*':
|
'@*/*':
|
||||||
access: $all
|
access: $all
|
||||||
publish: $authenticated
|
publish: $authenticated
|
||||||
|
proxy: npmjs
|
||||||
'**':
|
'**':
|
||||||
access: $all
|
access: $all
|
||||||
publish: $authenticated
|
publish: $authenticated
|
||||||
|
proxy: npmjs
|
||||||
_debug: true
|
_debug: true
|
||||||
|
@ -29,8 +29,8 @@ export default defineConfig({
|
|||||||
});
|
});
|
||||||
|
|
||||||
on('task', {
|
on('task', {
|
||||||
publishScoped() {
|
publishScoped({ pkgName }) {
|
||||||
const scopedPackageMetadata = generatePackageMetadata('pkg-scoped', '1.0.6');
|
const scopedPackageMetadata = generatePackageMetadata(pkgName, '1.0.6');
|
||||||
const server = new ServerQuery(registry1.getRegistryUrl());
|
const server = new ServerQuery(registry1.getRegistryUrl());
|
||||||
server
|
server
|
||||||
.putPackage(scopedPackageMetadata.name, scopedPackageMetadata, {
|
.putPackage(scopedPackageMetadata.name, scopedPackageMetadata, {
|
||||||
|
@ -5,18 +5,19 @@ describe('publish spec', () => {
|
|||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
const registry = await cy.task('registry');
|
const registry = await cy.task('registry');
|
||||||
ctx.url = registry.registryUrl;
|
ctx.url = registry.registryUrl;
|
||||||
|
const pkgName = `@verdaccio/pkg-scoped`;
|
||||||
cy.intercept('POST', '/-/verdaccio/sec/login').as('sign');
|
cy.intercept('POST', '/-/verdaccio/sec/login').as('sign');
|
||||||
cy.intercept('GET', '/-/verdaccio/data/packages').as('pkgs');
|
cy.intercept('GET', '/-/verdaccio/data/packages').as('pkgs');
|
||||||
cy.intercept('GET', '/-/verdaccio/data/sidebar/pkg-scoped').as('sidebar');
|
cy.intercept('GET', `/-/verdaccio/data/sidebar/${pkgName}`).as('sidebar');
|
||||||
cy.intercept('GET', '/-/verdaccio/data/package/readme/pkg-scoped').as('readme');
|
cy.intercept('GET', `/-/verdaccio/data/package/readme/${pkgName}`).as('readme');
|
||||||
cy.task('publishScoped', { pkgName: 'pkg-protected' });
|
cy.task('publishScoped', { pkgName });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have one published package', () => {
|
it('should have one published package', () => {
|
||||||
cy.visit(ctx.url);
|
cy.visit(ctx.url);
|
||||||
cy.login(credentials.user, credentials.password);
|
cy.login(credentials.user, credentials.password);
|
||||||
cy.wait('@sign');
|
cy.wait('@sign');
|
||||||
cy.getByTestId('package-title').should('have.length', 1);
|
// cy.getByTestId('package-title').should('have.length', 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should navigate to page detail', () => {
|
it('should navigate to page detail', () => {
|
||||||
@ -25,9 +26,7 @@ describe('publish spec', () => {
|
|||||||
cy.wait('@sign');
|
cy.wait('@sign');
|
||||||
cy.wait('@pkgs');
|
cy.wait('@pkgs');
|
||||||
cy.wait(300);
|
cy.wait(300);
|
||||||
cy.getByTestId('package-title').click();
|
cy.getByTestId('package-title').first().click();
|
||||||
cy.wait('@sidebar');
|
|
||||||
cy.wait('@readme');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have readme content', () => {
|
it('should have readme content', () => {
|
||||||
@ -35,9 +34,9 @@ describe('publish spec', () => {
|
|||||||
cy.login(credentials.user, credentials.password);
|
cy.login(credentials.user, credentials.password);
|
||||||
cy.wait('@sign');
|
cy.wait('@sign');
|
||||||
cy.wait('@pkgs');
|
cy.wait('@pkgs');
|
||||||
cy.getByTestId('package-title').click();
|
cy.getByTestId('package-title').first().click();
|
||||||
cy.wait('@sidebar');
|
|
||||||
cy.wait('@readme');
|
cy.wait('@readme');
|
||||||
|
cy.wait('@sidebar');
|
||||||
cy.get('.markdown-body').should('have.length', 1);
|
cy.get('.markdown-body').should('have.length', 1);
|
||||||
cy.contains('.markdown-body', /test/);
|
cy.contains('.markdown-body', /test/);
|
||||||
});
|
});
|
||||||
@ -48,9 +47,9 @@ describe('publish spec', () => {
|
|||||||
cy.wait('@sign');
|
cy.wait('@sign');
|
||||||
cy.wait('@pkgs');
|
cy.wait('@pkgs');
|
||||||
cy.wait(300);
|
cy.wait(300);
|
||||||
cy.getByTestId('package-title').click();
|
cy.getByTestId('package-title').first().click();
|
||||||
cy.wait('@sidebar');
|
|
||||||
cy.wait('@readme');
|
cy.wait('@readme');
|
||||||
|
cy.wait('@sidebar');
|
||||||
cy.getByTestId('dependencies-tab').click();
|
cy.getByTestId('dependencies-tab').click();
|
||||||
cy.wait(100);
|
cy.wait(100);
|
||||||
cy.getByTestId('dependencies').should('have.length', 1);
|
cy.getByTestId('dependencies').should('have.length', 1);
|
||||||
@ -67,9 +66,9 @@ describe('publish spec', () => {
|
|||||||
cy.wait('@sign');
|
cy.wait('@sign');
|
||||||
cy.wait('@pkgs');
|
cy.wait('@pkgs');
|
||||||
cy.wait(300);
|
cy.wait(300);
|
||||||
cy.getByTestId('package-title').click();
|
cy.getByTestId('package-title').first().click();
|
||||||
cy.wait('@sidebar');
|
|
||||||
cy.wait('@readme');
|
cy.wait('@readme');
|
||||||
|
cy.wait('@sidebar');
|
||||||
cy.getByTestId('versions-tab').click();
|
cy.getByTestId('versions-tab').click();
|
||||||
cy.getByTestId('tag-latest').children().invoke('text').should('match', /1.0.6/);
|
cy.getByTestId('tag-latest').children().invoke('text').should('match', /1.0.6/);
|
||||||
cy.screenshot();
|
cy.screenshot();
|
||||||
@ -81,9 +80,9 @@ describe('publish spec', () => {
|
|||||||
cy.wait('@sign');
|
cy.wait('@sign');
|
||||||
cy.wait('@pkgs');
|
cy.wait('@pkgs');
|
||||||
cy.wait(300);
|
cy.wait(300);
|
||||||
cy.getByTestId('package-title').click();
|
cy.getByTestId('package-title').first().click();
|
||||||
cy.wait('@sidebar');
|
|
||||||
cy.wait('@readme');
|
cy.wait('@readme');
|
||||||
|
cy.wait('@sidebar');
|
||||||
cy.getByTestId('uplinks-tab').click();
|
cy.getByTestId('uplinks-tab').click();
|
||||||
cy.getByTestId('no-uplinks').should('be.visible');
|
cy.getByTestId('no-uplinks').should('be.visible');
|
||||||
cy.screenshot();
|
cy.screenshot();
|
||||||
|
@ -25,6 +25,7 @@ describe('sign spec', () => {
|
|||||||
cy.wait(100);
|
cy.wait(100);
|
||||||
cy.getByTestId('logOutDialogIcon').click();
|
cy.getByTestId('logOutDialogIcon').click();
|
||||||
cy.screenshot();
|
cy.screenshot();
|
||||||
|
cy.wait(200);
|
||||||
cy.getByTestId('header--button-login').contains('Login');
|
cy.getByTestId('header--button-login').contains('Login');
|
||||||
cy.screenshot();
|
cy.screenshot();
|
||||||
});
|
});
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
"@verdaccio/config": "workspace:6.0.0-6-next.50",
|
"@verdaccio/config": "workspace:6.0.0-6-next.50",
|
||||||
"@verdaccio/test-helper": "workspace:2.0.0-6-next.6",
|
"@verdaccio/test-helper": "workspace:2.0.0-6-next.6",
|
||||||
"debug": "4.3.4",
|
"debug": "4.3.4",
|
||||||
"cypress": "10.10.0"
|
"cypress": "11.0.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"cypress:open": "cypress open",
|
"cypress:open": "cypress open",
|
||||||
|
@ -6,4 +6,22 @@ export const handlers = [
|
|||||||
rest.get('http://localhost:9000/-/verdaccio/data/packages', (req, res, ctx) => {
|
rest.get('http://localhost:9000/-/verdaccio/data/packages', (req, res, ctx) => {
|
||||||
return res(ctx.json(packagesPayload));
|
return res(ctx.json(packagesPayload));
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
rest.post<{ username: string; password: string }, { token: string; username: string }>(
|
||||||
|
'http://localhost:9000/-/verdaccio/sec/login',
|
||||||
|
// @ts-ignore
|
||||||
|
async (req, res, ctx) => {
|
||||||
|
const body = await req.json();
|
||||||
|
if (body.username === 'fail') {
|
||||||
|
return ctx.status(401);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res(
|
||||||
|
ctx.json({
|
||||||
|
username: body.username,
|
||||||
|
token: 'valid token',
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
@ -13,30 +13,30 @@
|
|||||||
"homepage": "https://verdaccio.org",
|
"homepage": "https://verdaccio.org",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "17.0.50",
|
|
||||||
"@types/react-autosuggest": "10.1.5",
|
|
||||||
"@types/react-dom": "17.0.17",
|
|
||||||
"@types/react-helmet": "6.1.5",
|
|
||||||
"@types/redux": "3.6.0",
|
|
||||||
"@types/react-router-dom": "5.3.3",
|
|
||||||
"@types/react-virtualized": "9.21.21",
|
|
||||||
"@emotion/react": "11.10.4",
|
|
||||||
"@emotion/jest": "11.10.0",
|
|
||||||
"@emotion/styled": "11.10.4",
|
|
||||||
"@emotion/css": "11.10.0",
|
|
||||||
"@emotion/babel-plugin": "11.10.2",
|
"@emotion/babel-plugin": "11.10.2",
|
||||||
|
"@emotion/css": "11.10.0",
|
||||||
|
"@emotion/jest": "11.10.0",
|
||||||
|
"@emotion/react": "11.10.4",
|
||||||
|
"@emotion/styled": "11.10.4",
|
||||||
"@mui/icons-material": "5.10.9",
|
"@mui/icons-material": "5.10.9",
|
||||||
"@mui/material": "5.10.9",
|
"@mui/material": "5.10.9",
|
||||||
"@mui/styles": "5.10.9",
|
"@mui/styles": "5.10.9",
|
||||||
"@rematch/core": "2.2.0",
|
"@rematch/core": "2.2.0",
|
||||||
"@rematch/loading": "2.1.2",
|
"@rematch/loading": "2.1.2",
|
||||||
|
"@rematch/persist": "2.1.2",
|
||||||
"@testing-library/dom": "8.19.0",
|
"@testing-library/dom": "8.19.0",
|
||||||
"@testing-library/jest-dom": "5.16.5",
|
"@testing-library/jest-dom": "5.16.5",
|
||||||
"@testing-library/react": "12.1.5",
|
"@testing-library/react": "13.4.0",
|
||||||
|
"@types/react": "18.0.25",
|
||||||
|
"@types/react-dom": "18.0.8",
|
||||||
|
"@types/react-router-dom": "5.3.3",
|
||||||
|
"@types/react-virtualized": "9.21.21",
|
||||||
|
"@types/redux": "3.6.0",
|
||||||
"@verdaccio/node-api": "workspace:6.0.0-6-next.50",
|
"@verdaccio/node-api": "workspace:6.0.0-6-next.50",
|
||||||
"@verdaccio/types": "workspace:*",
|
"@verdaccio/types": "workspace:*",
|
||||||
"babel-loader": "8.2.5",
|
"babel-loader": "8.2.5",
|
||||||
"babel-plugin-dynamic-import-node": "2.3.3",
|
"babel-plugin-dynamic-import-node": "2.3.3",
|
||||||
|
"country-flag-icons": "1.5.5",
|
||||||
"css-loader": "6.7.1",
|
"css-loader": "6.7.1",
|
||||||
"dayjs": "1.11.5",
|
"dayjs": "1.11.5",
|
||||||
"friendly-errors-webpack-plugin": "1.7.0",
|
"friendly-errors-webpack-plugin": "1.7.0",
|
||||||
@ -46,33 +46,33 @@
|
|||||||
"html-webpack-plugin": "5.5.0",
|
"html-webpack-plugin": "5.5.0",
|
||||||
"i18next": "20.6.1",
|
"i18next": "20.6.1",
|
||||||
"in-publish": "2.0.1",
|
"in-publish": "2.0.1",
|
||||||
"country-flag-icons": "1.5.5",
|
|
||||||
"js-base64": "3.7.2",
|
"js-base64": "3.7.2",
|
||||||
"js-yaml": "3.14.1",
|
"js-yaml": "3.14.1",
|
||||||
"localstorage-memory": "1.0.3",
|
"localstorage-memory": "1.0.3",
|
||||||
"lodash": "4.17.21",
|
"lodash": "4.17.21",
|
||||||
"mini-css-extract-plugin": "2.6.1",
|
"mini-css-extract-plugin": "2.6.1",
|
||||||
|
"msw": "0.47.4",
|
||||||
"mutationobserver-shim": "0.3.7",
|
"mutationobserver-shim": "0.3.7",
|
||||||
"node-mocks-http": "1.11.0",
|
"node-mocks-http": "1.11.0",
|
||||||
"normalize.css": "8.0.1",
|
"normalize.css": "8.0.1",
|
||||||
"react-markdown": "8.0.3",
|
|
||||||
"react-json-view": "1.21.3",
|
|
||||||
"remark-gfm": "3.0.1",
|
|
||||||
"optimize-css-assets-webpack-plugin": "6.0.1",
|
"optimize-css-assets-webpack-plugin": "6.0.1",
|
||||||
"ora": "5.4.1",
|
"ora": "5.4.1",
|
||||||
"react": "17.0.2",
|
"raw-loader": "4.0.2",
|
||||||
"react-dom": "17.0.2",
|
"react": "18.2.0",
|
||||||
"react-hook-form": "7.37.0",
|
"react-dom": "18.2.0",
|
||||||
|
"react-hook-form": "7.39.2",
|
||||||
"react-hot-loader": "4.13.0",
|
"react-hot-loader": "4.13.0",
|
||||||
"react-i18next": "11.18.6",
|
"react-i18next": "12.0.0",
|
||||||
|
"react-json-view": "1.21.3",
|
||||||
|
"react-markdown": "8.0.3",
|
||||||
|
"react-redux": "7.2.9",
|
||||||
"react-router": "5.3.4",
|
"react-router": "5.3.4",
|
||||||
"react-router-dom": "5.3.4",
|
"react-router-dom": "5.3.4",
|
||||||
"react-virtualized": "9.22.3",
|
"react-virtualized": "9.22.3",
|
||||||
"react-redux": "7.2.9",
|
|
||||||
"redux": "4.2.0",
|
"redux": "4.2.0",
|
||||||
|
"redux-persist": "6.0.0",
|
||||||
|
"remark-gfm": "3.0.1",
|
||||||
"rimraf": "3.0.2",
|
"rimraf": "3.0.2",
|
||||||
"raw-loader": "4.0.2",
|
|
||||||
"msw": "0.47.4",
|
|
||||||
"style-loader": "3.3.1",
|
"style-loader": "3.3.1",
|
||||||
"stylelint": "14.14.0",
|
"stylelint": "14.14.0",
|
||||||
"stylelint-config-recommended": "7.0.0",
|
"stylelint-config-recommended": "7.0.0",
|
||||||
@ -86,7 +86,7 @@
|
|||||||
"webpack": "5.74.0",
|
"webpack": "5.74.0",
|
||||||
"webpack-bundle-analyzer": "4.6.1",
|
"webpack-bundle-analyzer": "4.6.1",
|
||||||
"webpack-bundle-size-analyzer": "3.1.0",
|
"webpack-bundle-size-analyzer": "3.1.0",
|
||||||
"webpack-cli": "^4.7.2",
|
"webpack-cli": "^4.10.0",
|
||||||
"webpack-dev-server": "3.11.3",
|
"webpack-dev-server": "3.11.3",
|
||||||
"webpack-manifest-plugin": "4.1.1",
|
"webpack-manifest-plugin": "4.1.1",
|
||||||
"webpack-merge": "5.8.0",
|
"webpack-merge": "5.8.0",
|
||||||
|
@ -1,14 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {
|
import { renderWithStore, screen } from 'verdaccio-ui/utils/test-react-testing-library';
|
||||||
act,
|
|
||||||
fireEvent,
|
|
||||||
renderWithStore,
|
|
||||||
screen,
|
|
||||||
waitFor,
|
|
||||||
} from 'verdaccio-ui/utils/test-react-testing-library';
|
|
||||||
|
|
||||||
// eslint-disable-next-line jest/no-mocks-import
|
|
||||||
import { generateTokenWithTimeRange } from '../../jest/unit/components/__mocks__/token';
|
|
||||||
import { store } from '../store';
|
import { store } from '../store';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
|
|
||||||
@ -41,84 +33,6 @@ jest.spyOn(HTMLElement.prototype, 'offsetWidth', 'get').mockReturnValue(600);
|
|||||||
|
|
||||||
/* eslint-disable react/jsx-no-bind*/
|
/* eslint-disable react/jsx-no-bind*/
|
||||||
describe('<App />', () => {
|
describe('<App />', () => {
|
||||||
describe('login - log out', () => {
|
|
||||||
test('handleLogout - logouts the user and clear localstorage', async () => {
|
|
||||||
const { queryByTestId } = renderWithStore(<App />, store);
|
|
||||||
store.dispatch.login.logInUser({
|
|
||||||
username: 'verdaccio',
|
|
||||||
token: generateTokenWithTimeRange(24),
|
|
||||||
});
|
|
||||||
|
|
||||||
// wait for the Account's circle element component appearance and return the element
|
|
||||||
const accountCircleElement = await waitFor(() => queryByTestId('logInDialogIcon'));
|
|
||||||
expect(accountCircleElement).toBeTruthy();
|
|
||||||
|
|
||||||
if (accountCircleElement) {
|
|
||||||
fireEvent.click(accountCircleElement);
|
|
||||||
|
|
||||||
// wait for the Button's logout element component appearance and return the element
|
|
||||||
const buttonLogoutElement = await waitFor(() => queryByTestId('logOutDialogIcon'));
|
|
||||||
expect(buttonLogoutElement).toBeTruthy();
|
|
||||||
|
|
||||||
if (buttonLogoutElement) {
|
|
||||||
fireEvent.click(buttonLogoutElement);
|
|
||||||
|
|
||||||
expect(queryByTestId('greetings-label')).toBeFalsy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 10000);
|
|
||||||
|
|
||||||
test('isUserAlreadyLoggedIn: token already available in storage', async () => {
|
|
||||||
const { queryByTestId, queryAllByText } = renderWithStore(<App />, store);
|
|
||||||
store.dispatch.login.logInUser({
|
|
||||||
username: 'verdaccio',
|
|
||||||
token: generateTokenWithTimeRange(24),
|
|
||||||
});
|
|
||||||
|
|
||||||
// wait for the Account's circle element component appearance and return the element
|
|
||||||
const accountCircleElement = await waitFor(() => queryByTestId('logInDialogIcon'));
|
|
||||||
expect(accountCircleElement).toBeTruthy();
|
|
||||||
|
|
||||||
if (accountCircleElement) {
|
|
||||||
fireEvent.click(accountCircleElement);
|
|
||||||
|
|
||||||
// wait for the Greeting's label element component appearance and return the element
|
|
||||||
const greetingsLabelElement = await waitFor(() => queryByTestId('greetings-label'));
|
|
||||||
expect(greetingsLabelElement).toBeTruthy();
|
|
||||||
|
|
||||||
if (greetingsLabelElement) {
|
|
||||||
expect(queryAllByText('verdaccio')).toBeTruthy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 10000);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('list packages', () => {
|
|
||||||
test('should display the Header component', async () => {
|
|
||||||
renderWithStore(<App />, store);
|
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(screen.queryByTestId('loading')).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
// wait for the Header component appearance and return the element
|
|
||||||
const headerElement = await waitFor(() => screen.queryByTestId('header'));
|
|
||||||
expect(headerElement).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should display package lists', async () => {
|
|
||||||
act(() => {
|
|
||||||
renderWithStore(<App />, store);
|
|
||||||
});
|
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(screen.getByTestId('package-item-list')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(store.getState().packages.response).toHaveLength(1);
|
|
||||||
}, 10000);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('footer', () => {
|
describe('footer', () => {
|
||||||
test('should display the Header component', () => {
|
test('should display the Header component', () => {
|
||||||
renderWithStore(<App />, store);
|
renderWithStore(<App />, store);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/* eslint-disable react/jsx-max-depth */
|
/* eslint-disable react/jsx-max-depth */
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
import React, { Suspense, useEffect } from 'react';
|
import React, { StrictMode, Suspense, useEffect } from 'react';
|
||||||
import { Router } from 'react-router-dom';
|
import { Router } from 'react-router-dom';
|
||||||
import Loading from 'verdaccio-ui/components/Loading';
|
import Loading from 'verdaccio-ui/components/Loading';
|
||||||
import StyleBaseline from 'verdaccio-ui/design-tokens/StyleBaseline';
|
import StyleBaseline from 'verdaccio-ui/design-tokens/StyleBaseline';
|
||||||
@ -34,20 +34,22 @@ const App: React.FC = () => {
|
|||||||
loadDayJSLocale();
|
loadDayJSLocale();
|
||||||
}, []);
|
}, []);
|
||||||
return (
|
return (
|
||||||
<Suspense fallback={<Loading />}>
|
<StrictMode>
|
||||||
<StyleBaseline />
|
<Suspense fallback={<Loading />}>
|
||||||
<StyledBox display="flex" flexDirection="column" height="100%">
|
<StyleBaseline />
|
||||||
<>
|
<StyledBox display="flex" flexDirection="column" height="100%">
|
||||||
<Router history={history}>
|
<>
|
||||||
<Header />
|
<Router history={history}>
|
||||||
<StyledBoxContent flexGrow={1}>
|
<Header />
|
||||||
<AppRoute />
|
<StyledBoxContent flexGrow={1}>
|
||||||
</StyledBoxContent>
|
<AppRoute />
|
||||||
</Router>
|
</StyledBoxContent>
|
||||||
{configOptions.showFooter && <Footer />}
|
</Router>
|
||||||
</>
|
{configOptions.showFooter && <Footer />}
|
||||||
</StyledBox>
|
</>
|
||||||
</Suspense>
|
</StyledBox>
|
||||||
|
</Suspense>
|
||||||
|
</StrictMode>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { BrowserRouter as Router } from 'react-router-dom';
|
import { BrowserRouter as Router } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
|
act,
|
||||||
cleanup,
|
cleanup,
|
||||||
fireEvent,
|
fireEvent,
|
||||||
renderWithStore,
|
renderWithStore,
|
||||||
@ -15,9 +16,15 @@ import Header from './Header';
|
|||||||
|
|
||||||
/* eslint-disable react/jsx-no-bind*/
|
/* eslint-disable react/jsx-no-bind*/
|
||||||
describe('<Header /> component with logged in state', () => {
|
describe('<Header /> component with logged in state', () => {
|
||||||
afterEach(cleanup);
|
beforeEach(() => {
|
||||||
|
store.dispatch.login.logOutUser();
|
||||||
|
});
|
||||||
|
|
||||||
test('should load the component in logged out state', () => {
|
afterEach(() => {
|
||||||
|
cleanup();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should load the component n logged out state', () => {
|
||||||
renderWithStore(
|
renderWithStore(
|
||||||
<Router>
|
<Router>
|
||||||
<Header />
|
<Header />
|
||||||
@ -53,15 +60,15 @@ describe('<Header /> component with logged in state', () => {
|
|||||||
store
|
store
|
||||||
);
|
);
|
||||||
|
|
||||||
store.dispatch.login.logOutUser();
|
|
||||||
|
|
||||||
const loginBtn = screen.getByTestId('header--button-login');
|
const loginBtn = screen.getByTestId('header--button-login');
|
||||||
fireEvent.click(loginBtn);
|
fireEvent.click(loginBtn);
|
||||||
|
|
||||||
const loginDialog = await waitFor(() => screen.getByTestId('login--dialog'));
|
const loginDialog = await waitFor(() => screen.getByTestId('login--dialog'));
|
||||||
|
|
||||||
expect(loginDialog).toBeTruthy();
|
expect(loginDialog).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should logout the user', async () => {
|
test('should login and logout the user', async () => {
|
||||||
const { getByText, getByTestId } = renderWithStore(
|
const { getByText, getByTestId } = renderWithStore(
|
||||||
<Router>
|
<Router>
|
||||||
<Header />
|
<Header />
|
||||||
@ -69,14 +76,27 @@ describe('<Header /> component with logged in state', () => {
|
|||||||
store
|
store
|
||||||
);
|
);
|
||||||
|
|
||||||
store.dispatch.login.logInUser({ username: 'store', token: '12345' });
|
fireEvent.click(screen.getByText('Login'));
|
||||||
|
const userNameInput = screen.getByPlaceholderText('Your username');
|
||||||
|
fireEvent.focus(userNameInput);
|
||||||
|
fireEvent.change(userNameInput, { target: { value: 'xyz' } });
|
||||||
|
const passwordInput = screen.getByPlaceholderText('Your strong password');
|
||||||
|
fireEvent.focus(passwordInput);
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.change(passwordInput, { target: { value: '1234' } });
|
||||||
|
});
|
||||||
|
const signInButton = screen.getByTestId('login-dialog-form-login-button');
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(signInButton);
|
||||||
|
});
|
||||||
|
await waitFor(() => getByTestId('logInDialogIcon'));
|
||||||
const headerMenuAccountCircle = getByTestId('logInDialogIcon');
|
const headerMenuAccountCircle = getByTestId('logInDialogIcon');
|
||||||
fireEvent.click(headerMenuAccountCircle);
|
fireEvent.click(headerMenuAccountCircle);
|
||||||
|
|
||||||
// wait for button Logout's appearance and return the element
|
// // wait for button Logout's appearance and return the element
|
||||||
const logoutBtn = await waitFor(() => getByText('Logout'));
|
const logoutBtn = await waitFor(() => getByText('Logout'));
|
||||||
fireEvent.click(logoutBtn);
|
fireEvent.click(logoutBtn);
|
||||||
|
await waitFor(() => getByText('Login'));
|
||||||
expect(getByText('Login')).toBeTruthy();
|
expect(getByText('Login')).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ const Header: React.FC = () => {
|
|||||||
const dispatch = useDispatch<Dispatch>();
|
const dispatch = useDispatch<Dispatch>();
|
||||||
const handleLogout = () => {
|
const handleLogout = () => {
|
||||||
dispatch.login.logOutUser();
|
dispatch.login.logOutUser();
|
||||||
|
setShowLoginModal(false);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -69,6 +69,7 @@ const LoginDialogForm = memo(({ onSubmit, error }: Props) => {
|
|||||||
required: { value: true, message: t('form-validation.required-field') },
|
required: { value: true, message: t('form-validation.required-field') },
|
||||||
minLength: { value: 2, message: t('form-validation.required-min-length', { length: 2 }) },
|
minLength: { value: 2, message: t('form-validation.required-min-length', { length: 2 }) },
|
||||||
})}
|
})}
|
||||||
|
data-testid="password"
|
||||||
label={t('form.password')}
|
label={t('form.password')}
|
||||||
margin="normal"
|
margin="normal"
|
||||||
name="password"
|
name="password"
|
||||||
|
@ -3,6 +3,7 @@ import BugReportIcon from '@mui/icons-material/BugReport';
|
|||||||
import DownloadIcon from '@mui/icons-material/CloudDownload';
|
import DownloadIcon from '@mui/icons-material/CloudDownload';
|
||||||
import HomeIcon from '@mui/icons-material/Home';
|
import HomeIcon from '@mui/icons-material/Home';
|
||||||
import RawOnIcon from '@mui/icons-material/RawOn';
|
import RawOnIcon from '@mui/icons-material/RawOn';
|
||||||
|
import FabMUI from '@mui/material/Fab';
|
||||||
import Tooltip from '@mui/material/Tooltip';
|
import Tooltip from '@mui/material/Tooltip';
|
||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@ -10,10 +11,9 @@ import { useDispatch } from 'react-redux';
|
|||||||
import { Theme } from 'verdaccio-ui/design-tokens/theme';
|
import { Theme } from 'verdaccio-ui/design-tokens/theme';
|
||||||
|
|
||||||
import { Dispatch } from '../../store/store';
|
import { Dispatch } from '../../store/store';
|
||||||
import FloatingActionButton from '../FloatingActionButton';
|
|
||||||
import Link from '../Link';
|
import Link from '../Link';
|
||||||
|
|
||||||
export const Fab = styled(FloatingActionButton)<{ theme?: Theme }>(({ theme }) => ({
|
export const Fab = styled(FabMUI)<{ theme?: Theme }>(({ theme }) => ({
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
theme?.palette.mode === 'light' ? theme?.palette.primary.main : theme?.palette.cyanBlue,
|
theme?.palette.mode === 'light' ? theme?.palette.primary.main : theme?.palette.cyanBlue,
|
||||||
color: theme?.palette.white,
|
color: theme?.palette.white,
|
||||||
|
@ -168,7 +168,6 @@ exports[`<ActionBar /> component should render the component in default state 1`
|
|||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="MuiButtonBase-root MuiFab-root MuiFab-circular MuiFab-sizeSmall MuiFab-default MuiFab-root MuiFab-circular MuiFab-sizeSmall MuiFab-default emotion-2 emotion-3"
|
class="MuiButtonBase-root MuiFab-root MuiFab-circular MuiFab-sizeSmall MuiFab-default MuiFab-root MuiFab-circular MuiFab-sizeSmall MuiFab-default emotion-2 emotion-3"
|
||||||
data-testid="fab"
|
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
@ -202,7 +201,6 @@ exports[`<ActionBar /> component should render the component in default state 1`
|
|||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="MuiButtonBase-root MuiFab-root MuiFab-circular MuiFab-sizeSmall MuiFab-default MuiFab-root MuiFab-circular MuiFab-sizeSmall MuiFab-default emotion-2 emotion-3"
|
class="MuiButtonBase-root MuiFab-root MuiFab-circular MuiFab-sizeSmall MuiFab-default MuiFab-root MuiFab-circular MuiFab-sizeSmall MuiFab-default emotion-2 emotion-3"
|
||||||
data-testid="fab"
|
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
@ -227,7 +225,7 @@ exports[`<ActionBar /> component should render the component in default state 1`
|
|||||||
aria-label="Download tarball"
|
aria-label="Download tarball"
|
||||||
class="MuiButtonBase-root MuiFab-root MuiFab-circular MuiFab-sizeSmall MuiFab-default MuiFab-root MuiFab-circular MuiFab-sizeSmall MuiFab-default emotion-2 emotion-3"
|
class="MuiButtonBase-root MuiFab-root MuiFab-circular MuiFab-sizeSmall MuiFab-default MuiFab-root MuiFab-circular MuiFab-sizeSmall MuiFab-default emotion-2 emotion-3"
|
||||||
data-mui-internal-clone-element="true"
|
data-mui-internal-clone-element="true"
|
||||||
data-testid="fab"
|
data-testid="download-tarball-btn"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
import Fab from '@mui/material/Fab';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
const FloatingActionButton = (props) => {
|
|
||||||
return <Fab {...props} data-testid="fab" />;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default FloatingActionButton;
|
|
@ -212,7 +212,7 @@ label[data-shrink=false]+.MuiInputBase-formControl .emotion-2:focus::-ms-input-p
|
|||||||
<input
|
<input
|
||||||
aria-invalid="false"
|
aria-invalid="false"
|
||||||
class="MuiInputBase-input MuiOutlinedInput-input emotion-2"
|
class="MuiInputBase-input MuiOutlinedInput-input emotion-2"
|
||||||
id="mui-1"
|
id=":r0:"
|
||||||
name="test"
|
name="test"
|
||||||
type="text"
|
type="text"
|
||||||
value="test"
|
value="test"
|
||||||
|
@ -22,7 +22,7 @@ function getDarkModeDefault(darkModeConfig) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ThemeProviderWrapper: React.FC = ({ children }) => {
|
const ThemeProviderWrapper: React.FC<{ children: any }> = ({ children }) => {
|
||||||
const currentLanguage = i18next.languages?.[0];
|
const currentLanguage = i18next.languages?.[0];
|
||||||
const { configOptions } = useConfig();
|
const { configOptions } = useConfig();
|
||||||
const isDarkModeDefault = getDarkModeDefault(configOptions.darkMode);
|
const isDarkModeDefault = getDarkModeDefault(configOptions.darkMode);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import { createRoot } from 'react-dom/client';
|
||||||
import { AppContainer } from 'react-hot-loader';
|
import { hot } from 'react-hot-loader/root';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import AppConfigurationContext from 'verdaccio-ui/providers/config';
|
import AppConfigurationContext from 'verdaccio-ui/providers/config';
|
||||||
|
|
||||||
@ -9,29 +9,23 @@ import StyleBaseline from './design-tokens/StyleBaseline';
|
|||||||
import ThemeProvider from './design-tokens/ThemeProvider';
|
import ThemeProvider from './design-tokens/ThemeProvider';
|
||||||
import { store } from './store';
|
import { store } from './store';
|
||||||
|
|
||||||
const rootNode = document.getElementById('root');
|
const container = document.getElementById('root');
|
||||||
const renderApp = (Component: React.ElementType): void => {
|
const root = createRoot(container as HTMLElement);
|
||||||
ReactDOM.render(
|
|
||||||
<Provider store={store}>
|
|
||||||
<AppContainer>
|
|
||||||
<AppConfigurationContext>
|
|
||||||
<ThemeProvider>
|
|
||||||
<StyleBaseline />
|
|
||||||
<Component />
|
|
||||||
</ThemeProvider>
|
|
||||||
</AppConfigurationContext>
|
|
||||||
</AppContainer>
|
|
||||||
</Provider>,
|
|
||||||
rootNode
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
renderApp(App);
|
const AppContainer = () => (
|
||||||
|
<Provider store={store}>
|
||||||
|
<AppConfigurationContext>
|
||||||
|
<ThemeProvider>
|
||||||
|
<StyleBaseline />
|
||||||
|
<App />
|
||||||
|
</ThemeProvider>
|
||||||
|
</AppConfigurationContext>
|
||||||
|
</Provider>
|
||||||
|
);
|
||||||
|
|
||||||
|
root.render(<AppContainer />);
|
||||||
|
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
if (module.hot) {
|
if (module.hot) {
|
||||||
// @ts-expect-error
|
hot(AppContainer);
|
||||||
module.hot.accept('./App', () => {
|
|
||||||
renderApp(App);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { renderWithStore, screen } from 'verdaccio-ui/utils/test-react-testing-library';
|
import { renderWithStore, screen, waitFor } from 'verdaccio-ui/utils/test-react-testing-library';
|
||||||
|
|
||||||
import { store } from '../../../store';
|
import { store } from '../../../store';
|
||||||
import { DetailContext } from '../context';
|
import { DetailContext } from '../context';
|
||||||
@ -15,6 +15,13 @@ const ComponentToBeRendered: React.FC<{ contextValue: DetailContextProps }> = ({
|
|||||||
</DetailContext.Provider>
|
</DetailContext.Provider>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// https://stackoverflow.com/a/54010619/308341
|
||||||
|
jest.mock('react', () => {
|
||||||
|
const React = jest.requireActual('react');
|
||||||
|
React.Suspense = ({ children }) => children;
|
||||||
|
return React;
|
||||||
|
});
|
||||||
|
|
||||||
const detailContextValue: DetailContextProps = {
|
const detailContextValue: DetailContextProps = {
|
||||||
packageName: 'foo',
|
packageName: 'foo',
|
||||||
readMe: 'test',
|
readMe: 'test',
|
||||||
@ -40,8 +47,8 @@ const detailContextValue: DetailContextProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
describe('DetailSidebar', () => {
|
describe('DetailSidebar', () => {
|
||||||
test('should render commonjs module icon', () => {
|
test('should render commonjs module icon', async () => {
|
||||||
renderWithStore(
|
const { getByAltText } = renderWithStore(
|
||||||
<ComponentToBeRendered
|
<ComponentToBeRendered
|
||||||
contextValue={_.merge(detailContextValue, {
|
contextValue={_.merge(detailContextValue, {
|
||||||
packageMeta: {
|
packageMeta: {
|
||||||
@ -53,7 +60,8 @@ describe('DetailSidebar', () => {
|
|||||||
/>,
|
/>,
|
||||||
store
|
store
|
||||||
);
|
);
|
||||||
expect(screen.getByAltText('commonjs')).toBeInTheDocument();
|
|
||||||
|
await waitFor(() => expect(getByAltText('commonjs')).toBeInTheDocument());
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should render ts module icon', () => {
|
test('should render ts module icon', () => {
|
||||||
|
@ -107,7 +107,7 @@ describe('test Developers', () => {
|
|||||||
// item2.simulate('click');
|
// item2.simulate('click');
|
||||||
|
|
||||||
expect(wrapper.getByText('Contributors')).toBeInTheDocument();
|
expect(wrapper.getByText('Contributors')).toBeInTheDocument();
|
||||||
fireEvent.click(wrapper.getByTestId('fab'));
|
fireEvent.click(wrapper.getByRole('button'));
|
||||||
|
|
||||||
expect(wrapper.getByLabelText(packageMeta.latest.contributors[0].name)).toBeInTheDocument();
|
expect(wrapper.getByLabelText(packageMeta.latest.contributors[0].name)).toBeInTheDocument();
|
||||||
expect(wrapper.getByLabelText(packageMeta.latest.contributors[1].name)).toBeInTheDocument();
|
expect(wrapper.getByLabelText(packageMeta.latest.contributors[1].name)).toBeInTheDocument();
|
||||||
|
@ -2,10 +2,10 @@ import styled from '@emotion/styled';
|
|||||||
import Add from '@mui/icons-material/Add';
|
import Add from '@mui/icons-material/Add';
|
||||||
import Avatar from '@mui/material/Avatar';
|
import Avatar from '@mui/material/Avatar';
|
||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
|
import FabMUI from '@mui/material/Fab';
|
||||||
import Tooltip from '@mui/material/Tooltip';
|
import Tooltip from '@mui/material/Tooltip';
|
||||||
import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import FloatingActionButton from 'verdaccio-ui/components/FloatingActionButton';
|
|
||||||
import { Theme } from 'verdaccio-ui/design-tokens/theme';
|
import { Theme } from 'verdaccio-ui/design-tokens/theme';
|
||||||
|
|
||||||
import { DetailContext } from '../..';
|
import { DetailContext } from '../..';
|
||||||
@ -17,7 +17,7 @@ export enum DeveloperType {
|
|||||||
MAINTAINERS = 'maintainers',
|
MAINTAINERS = 'maintainers',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Fab = styled(FloatingActionButton)<{ theme?: Theme }>((props) => ({
|
export const Fab = styled(FabMUI)<{ theme?: Theme }>((props) => ({
|
||||||
backgroundColor: props.theme?.palette.primary.main,
|
backgroundColor: props.theme?.palette.primary.main,
|
||||||
color: props.theme?.palette.white,
|
color: props.theme?.palette.white,
|
||||||
}));
|
}));
|
||||||
@ -70,11 +70,13 @@ const Developers: React.FC<Props> = ({ type, visibleMax = VISIBLE_MAX }) => {
|
|||||||
<>
|
<>
|
||||||
<DevelopersTitle type={type} />
|
<DevelopersTitle type={type} />
|
||||||
<StyledBox display="flex" flexWrap="wrap" margin="10px 0 10px 0">
|
<StyledBox display="flex" flexWrap="wrap" margin="10px 0 10px 0">
|
||||||
{visibleDevelopers.map((visibleDeveloper) => (
|
{visibleDevelopers.map((visibleDeveloper) => {
|
||||||
<Tooltip key={visibleDeveloper.email} title={visibleDeveloper.name}>
|
return (
|
||||||
<Avatar alt={visibleDeveloper.name} src={visibleDeveloper.avatar} />
|
<Tooltip key={visibleDeveloper.email} title={visibleDeveloper.name}>
|
||||||
</Tooltip>
|
<Avatar alt={visibleDeveloper.name} src={visibleDeveloper.avatar} />
|
||||||
))}
|
</Tooltip>
|
||||||
|
);
|
||||||
|
})}
|
||||||
{visibleDevelopersMax < developers.length && (
|
{visibleDevelopersMax < developers.length && (
|
||||||
<Fab onClick={handleSetVisibleDevelopersMax} size="small">
|
<Fab onClick={handleSetVisibleDevelopersMax} size="small">
|
||||||
<Add />
|
<Add />
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import FloatingActionButton from 'verdaccio-ui/components/FloatingActionButton';
|
import FabMUI from '@mui/material/Fab';
|
||||||
import Text from 'verdaccio-ui/components/Text';
|
import Text from 'verdaccio-ui/components/Text';
|
||||||
import { Theme } from 'verdaccio-ui/design-tokens/theme';
|
import { Theme } from 'verdaccio-ui/design-tokens/theme';
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ export const StyledText = styled(Text)<{ theme?: Theme }>((props) => ({
|
|||||||
textTransform: 'capitalize',
|
textTransform: 'capitalize',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const Fab = styled(FloatingActionButton)<{ theme?: Theme }>((props) => ({
|
export const Fab = styled(FabMUI)<{ theme?: Theme }>((props) => ({
|
||||||
backgroundColor: props.theme?.palette.primary.main,
|
backgroundColor: props.theme?.palette.primary.main,
|
||||||
color: props.theme?.palette.white,
|
color: props.theme?.palette.white,
|
||||||
}));
|
}));
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import Chip from '@mui/material/Chip';
|
import Chip from '@mui/material/Chip';
|
||||||
|
import FabMUI from '@mui/material/Fab';
|
||||||
import ListItem from '@mui/material/ListItem';
|
import ListItem from '@mui/material/ListItem';
|
||||||
import FloatingActionButton from 'verdaccio-ui/components/FloatingActionButton';
|
|
||||||
import Text from 'verdaccio-ui/components/Text';
|
import Text from 'verdaccio-ui/components/Text';
|
||||||
import { Theme } from 'verdaccio-ui/design-tokens/theme';
|
import { Theme } from 'verdaccio-ui/design-tokens/theme';
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ export const DistChips = styled(Chip)({
|
|||||||
marginTop: 5,
|
marginTop: 5,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const DownloadButton = styled(FloatingActionButton)<{ theme?: Theme }>((props) => ({
|
export const DownloadButton = styled(FabMUI)<{ theme?: Theme }>((props) => ({
|
||||||
backgroundColor: props.theme && props.theme.palette.primary.main,
|
backgroundColor: props.theme && props.theme.palette.primary.main,
|
||||||
color: props.theme && props.theme.palette.white,
|
color: props.theme && props.theme.palette.white,
|
||||||
}));
|
}));
|
||||||
|
@ -6,7 +6,6 @@ import List from '@mui/material/List';
|
|||||||
import ListItemText from '@mui/material/ListItemText';
|
import ListItemText from '@mui/material/ListItemText';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import Label from 'verdaccio-ui/components/Label';
|
import Label from 'verdaccio-ui/components/Label';
|
||||||
import { default as MuiText } from 'verdaccio-ui/components/Text';
|
|
||||||
import { Theme } from 'verdaccio-ui/design-tokens/theme';
|
import { Theme } from 'verdaccio-ui/design-tokens/theme';
|
||||||
|
|
||||||
export const OverviewItem = styled('span')<{ theme?: Theme }>(({ theme }) => ({
|
export const OverviewItem = styled('span')<{ theme?: Theme }>(({ theme }) => ({
|
||||||
@ -104,7 +103,7 @@ export const PackageListItemText = styled(ListItemText)({
|
|||||||
paddingRight: 0,
|
paddingRight: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const Description = styled(MuiText)<{ theme?: Theme }>(({ theme }) => ({
|
export const Description = styled('span')<{ theme?: Theme }>(({ theme }) => ({
|
||||||
color: theme?.palette.mode === 'light' ? theme?.palette.greyDark2 : theme?.palette.white,
|
color: theme?.palette.mode === 'light' ? theme?.palette.greyDark2 : theme?.palette.white,
|
||||||
fontSize: '14px',
|
fontSize: '14px',
|
||||||
paddingRight: 0,
|
paddingRight: 0,
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
import { createModel } from '@rematch/core';
|
import { createModel } from '@rematch/core';
|
||||||
|
|
||||||
import { Package } from '@verdaccio/types';
|
import { Manifest } from '@verdaccio/types';
|
||||||
|
|
||||||
import type { RootModel } from '.';
|
import type { RootModel } from '.';
|
||||||
import API from '../../providers/API/api';
|
import API from '../../providers/API/api';
|
||||||
|
|
||||||
export const packages = createModel<RootModel>()({
|
export const packages = createModel<RootModel>()({
|
||||||
state: {
|
state: {
|
||||||
response: [] as Package[],
|
response: [] as Manifest[],
|
||||||
},
|
},
|
||||||
reducers: {
|
reducers: {
|
||||||
savePackages(state, response: Package[]) {
|
savePackages(state, response: Manifest[]) {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
response,
|
response,
|
||||||
@ -21,7 +21,10 @@ export const packages = createModel<RootModel>()({
|
|||||||
async getPackages(_payload, state) {
|
async getPackages(_payload, state) {
|
||||||
const basePath = state.configuration.config.base;
|
const basePath = state.configuration.config.base;
|
||||||
try {
|
try {
|
||||||
const payload: Package[] = await API.request(`${basePath}-/verdaccio/data/packages`, 'GET');
|
const payload: Manifest[] = await API.request(
|
||||||
|
`${basePath}-/verdaccio/data/packages`,
|
||||||
|
'GET'
|
||||||
|
);
|
||||||
dispatch.packages.savePackages(payload);
|
dispatch.packages.savePackages(payload);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
|
661
pnpm-lock.yaml
generated
661
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user