mirror of
https://github.com/verdaccio/verdaccio.git
synced 2025-03-11 02:15:57 -05:00
feat: allow disable login on ui (#2228)
This commit is contained in:
parent
393125baa1
commit
0da7031e77
20 changed files with 168 additions and 67 deletions
15
.changeset/afraid-mice-obey.md
Normal file
15
.changeset/afraid-mice-obey.md
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
---
|
||||||
|
'@verdaccio/types': minor
|
||||||
|
'@verdaccio/ui-theme': minor
|
||||||
|
'@verdaccio/web': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
allow disable login on ui and endpoints
|
||||||
|
|
||||||
|
To be able disable the login, set `login: false`, anything else would enable login. This flag will disable access via UI and web endpoints.
|
||||||
|
|
||||||
|
```yml
|
||||||
|
web:
|
||||||
|
title: verdaccio
|
||||||
|
login: false
|
||||||
|
```
|
1
packages/core/types/index.d.ts
vendored
1
packages/core/types/index.d.ts
vendored
|
@ -27,6 +27,7 @@ declare module '@verdaccio/types' {
|
||||||
darkMode?: boolean;
|
darkMode?: boolean;
|
||||||
url_prefix?: string;
|
url_prefix?: string;
|
||||||
language?: string;
|
language?: string;
|
||||||
|
login?: boolean;
|
||||||
scope?: string;
|
scope?: string;
|
||||||
pkgManagers?: PackageManagers[];
|
pkgManagers?: PackageManagers[];
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,6 +5,7 @@ import {
|
||||||
render,
|
render,
|
||||||
fireEvent,
|
fireEvent,
|
||||||
waitFor,
|
waitFor,
|
||||||
|
screen,
|
||||||
waitForElementToBeRemoved,
|
waitForElementToBeRemoved,
|
||||||
} from 'verdaccio-ui/utils/test-react-testing-library';
|
} from 'verdaccio-ui/utils/test-react-testing-library';
|
||||||
|
|
||||||
|
@ -23,7 +24,7 @@ const props = {
|
||||||
/* 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', () => {
|
||||||
test('should load the component in logged out state', () => {
|
test('should load the component in logged out state', () => {
|
||||||
const { queryByTestId, getByText } = render(
|
render(
|
||||||
<Router>
|
<Router>
|
||||||
<AppContextProvider>
|
<AppContextProvider>
|
||||||
<Header />
|
<Header />
|
||||||
|
@ -31,8 +32,9 @@ describe('<Header /> component with logged in state', () => {
|
||||||
</Router>
|
</Router>
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(queryByTestId('header--menu-accountcircle')).toBeNull();
|
expect(screen.queryByTestId('header--menu-accountcircle')).toBeNull();
|
||||||
expect(getByText('Login')).toBeTruthy();
|
expect(screen.getByText('Login')).toBeTruthy();
|
||||||
|
expect(screen.queryByTestId('header--button-login')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should load the component in logged in state', () => {
|
test('should load the component in logged in state', () => {
|
||||||
|
@ -135,5 +137,22 @@ describe('<Header /> component with logged in state', () => {
|
||||||
expect(hasRegistrationInfoModalBeenRemoved).not.toBeDefined();
|
expect(hasRegistrationInfoModalBeenRemoved).not.toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should hide login if is disabled', () => {
|
||||||
|
// @ts-expect-error
|
||||||
|
window.__VERDACCIO_BASENAME_UI_OPTIONS = {
|
||||||
|
base: 'foo',
|
||||||
|
login: false,
|
||||||
|
};
|
||||||
|
render(
|
||||||
|
<Router>
|
||||||
|
<AppContextProvider user={props.user}>
|
||||||
|
<Header />
|
||||||
|
</AppContextProvider>
|
||||||
|
</Router>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.queryByTestId('header--button-login')).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
test.todo('autocompletion should display suggestions according to the type value');
|
test.todo('autocompletion should display suggestions according to the type value');
|
||||||
});
|
});
|
||||||
|
|
|
@ -49,6 +49,7 @@ const Header: React.FC<Props> = ({ withoutSearch }) => {
|
||||||
<InnerNavBar>
|
<InnerNavBar>
|
||||||
<HeaderLeft />
|
<HeaderLeft />
|
||||||
<HeaderRight
|
<HeaderRight
|
||||||
|
hasLogin={configOptions?.login}
|
||||||
onLogout={handleLogout}
|
onLogout={handleLogout}
|
||||||
onOpenRegistryInfoDialog={() => setOpenInfoDialog(true)}
|
onOpenRegistryInfoDialog={() => setOpenInfoDialog(true)}
|
||||||
onToggleLogin={() => setShowLoginModal(!showLoginModal)}
|
onToggleLogin={() => setShowLoginModal(!showLoginModal)}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { RightSide } from './styles';
|
||||||
interface Props {
|
interface Props {
|
||||||
withoutSearch?: boolean;
|
withoutSearch?: boolean;
|
||||||
username?: string | null;
|
username?: string | null;
|
||||||
|
hasLogin?: boolean;
|
||||||
onToggleLogin: () => void;
|
onToggleLogin: () => void;
|
||||||
onOpenRegistryInfoDialog: () => void;
|
onOpenRegistryInfoDialog: () => void;
|
||||||
onToggleMobileNav: () => void;
|
onToggleMobileNav: () => void;
|
||||||
|
@ -22,6 +23,7 @@ const HeaderRight: React.FC<Props> = ({
|
||||||
withoutSearch = false,
|
withoutSearch = false,
|
||||||
username,
|
username,
|
||||||
onToggleLogin,
|
onToggleLogin,
|
||||||
|
hasLogin,
|
||||||
onLogout,
|
onLogout,
|
||||||
onToggleMobileNav,
|
onToggleMobileNav,
|
||||||
onOpenRegistryInfoDialog,
|
onOpenRegistryInfoDialog,
|
||||||
|
@ -29,6 +31,7 @@ const HeaderRight: React.FC<Props> = ({
|
||||||
const themeContext = useContext(ThemeContext);
|
const themeContext = useContext(ThemeContext);
|
||||||
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);
|
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);
|
||||||
const [isMenuOpen, setIsMenuOpen] = useState<boolean>(false);
|
const [isMenuOpen, setIsMenuOpen] = useState<boolean>(false);
|
||||||
|
const hideLoginSection = hasLogin === false;
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
@ -90,19 +93,23 @@ const HeaderRight: React.FC<Props> = ({
|
||||||
tooltipIconType={themeContext.isDarkMode ? 'dark-mode' : 'light-mode'}
|
tooltipIconType={themeContext.isDarkMode ? 'dark-mode' : 'light-mode'}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{username ? (
|
{!hideLoginSection && (
|
||||||
<HeaderMenu
|
<>
|
||||||
anchorEl={anchorEl}
|
{username ? (
|
||||||
isMenuOpen={isMenuOpen}
|
<HeaderMenu
|
||||||
onLoggedInMenu={handleLoggedInMenu}
|
anchorEl={anchorEl}
|
||||||
onLoggedInMenuClose={handleLoggedInMenuClose}
|
isMenuOpen={isMenuOpen}
|
||||||
onLogout={onLogout}
|
onLoggedInMenu={handleLoggedInMenu}
|
||||||
username={username}
|
onLoggedInMenuClose={handleLoggedInMenuClose}
|
||||||
/>
|
onLogout={onLogout}
|
||||||
) : (
|
username={username}
|
||||||
<Button color="inherit" data-testid="header--button-login" onClick={handleToggleLogin}>
|
/>
|
||||||
{t('button.login')}
|
) : (
|
||||||
</Button>
|
<Button color="inherit" data-testid="header--button-login" onClick={handleToggleLogin}>
|
||||||
|
{t('button.login')}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</RightSide>
|
</RightSide>
|
||||||
);
|
);
|
||||||
|
|
|
@ -17,6 +17,7 @@ const defaultValues: ConfigProviderProps = {
|
||||||
pkgManagers: ['yarn', 'pnpm', 'npm'],
|
pkgManagers: ['yarn', 'pnpm', 'npm'],
|
||||||
scope: '',
|
scope: '',
|
||||||
base: '',
|
base: '',
|
||||||
|
login: true,
|
||||||
url_prefix: '',
|
url_prefix: '',
|
||||||
title: 'Verdaccio',
|
title: 'Verdaccio',
|
||||||
},
|
},
|
||||||
|
@ -46,7 +47,6 @@ const AppConfigurationProvider: FunctionComponent = ({ children }) => {
|
||||||
[configOptions]
|
[configOptions]
|
||||||
);
|
);
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
return (
|
return (
|
||||||
<AppConfigurationContext.Provider value={value}>{children}</AppConfigurationContext.Provider>
|
<AppConfigurationContext.Provider value={value}>{children}</AppConfigurationContext.Provider>
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,6 +2,7 @@ web:
|
||||||
title: Verdaccio Local Dev
|
title: Verdaccio Local Dev
|
||||||
sort_packages: asc
|
sort_packages: asc
|
||||||
primary_color: #CCC
|
primary_color: #CCC
|
||||||
|
login: true
|
||||||
pkgManagers:
|
pkgManagers:
|
||||||
- npm
|
- npm
|
||||||
- yarn
|
- yarn
|
||||||
|
|
|
@ -9,6 +9,7 @@ export interface VerdaccioOptions {
|
||||||
primaryColor: string;
|
primaryColor: string;
|
||||||
darkMode: boolean;
|
darkMode: boolean;
|
||||||
uri?: string;
|
uri?: string;
|
||||||
|
login?: boolean;
|
||||||
language?: string;
|
language?: string;
|
||||||
version?: string;
|
version?: string;
|
||||||
protocol?: string;
|
protocol?: string;
|
||||||
|
|
|
@ -29,11 +29,20 @@ function addPackageWebApi(
|
||||||
auth: IAuth,
|
auth: IAuth,
|
||||||
config: Config
|
config: Config
|
||||||
): void {
|
): void {
|
||||||
|
const isLoginEnabled = config?.web?.login === true ?? true;
|
||||||
|
const anonymousRemoteUser: RemoteUser = {
|
||||||
|
name: undefined,
|
||||||
|
real_groups: [],
|
||||||
|
groups: [],
|
||||||
|
};
|
||||||
|
|
||||||
debug('initialized package web api');
|
debug('initialized package web api');
|
||||||
const checkAllow = (name: string, remoteUser: RemoteUser): Promise<boolean> =>
|
const checkAllow = (name: string, remoteUser: RemoteUser): Promise<boolean> =>
|
||||||
new Promise((resolve, reject): void => {
|
new Promise((resolve, reject): void => {
|
||||||
|
debug('is login disabled %o', isLoginEnabled);
|
||||||
|
const remoteUserAccess = !isLoginEnabled ? anonymousRemoteUser : remoteUser;
|
||||||
try {
|
try {
|
||||||
auth.allow_access({ packageName: name }, remoteUser, (err, allowed): void => {
|
auth.allow_access({ packageName: name }, remoteUserAccess, (err, allowed): void => {
|
||||||
if (err) {
|
if (err) {
|
||||||
resolve(false);
|
resolve(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ function addReadmeWebApi(route: Router, storage: IStorageHandler, auth: IAuth):
|
||||||
uplinksLook: true,
|
uplinksLook: true,
|
||||||
req,
|
req,
|
||||||
callback: function (err, info): void {
|
callback: function (err, info): void {
|
||||||
debug('readme plg %o', info);
|
debug('readme plg %o', info?.name);
|
||||||
if (err) {
|
if (err) {
|
||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import addPackageWebApi from '../api/package';
|
||||||
import addUserAuthApi from '../api/user';
|
import addUserAuthApi from '../api/user';
|
||||||
import addReadmeWebApi from '../api/readme';
|
import addReadmeWebApi from '../api/readme';
|
||||||
import addSidebarWebApi from '../api/sidebar';
|
import addSidebarWebApi from '../api/sidebar';
|
||||||
|
import { hasLogin } from '../utils/web-utils';
|
||||||
import { setSecurityWebHeaders } from './security';
|
import { setSecurityWebHeaders } from './security';
|
||||||
|
|
||||||
export function webAPI(config: Config, auth: IAuth, storage: IStorageHandler): Router {
|
export function webAPI(config: Config, auth: IAuth, storage: IStorageHandler): Router {
|
||||||
|
@ -33,7 +34,9 @@ export function webAPI(config: Config, auth: IAuth, storage: IStorageHandler): R
|
||||||
addReadmeWebApi(route, storage, auth);
|
addReadmeWebApi(route, storage, auth);
|
||||||
addSidebarWebApi(route, config, storage, auth);
|
addSidebarWebApi(route, config, storage, auth);
|
||||||
addSearchWebApi(route, storage, auth);
|
addSearchWebApi(route, storage, auth);
|
||||||
addUserAuthApi(route, auth, config);
|
if (hasLogin(config)) {
|
||||||
|
addUserAuthApi(route, auth, config);
|
||||||
|
}
|
||||||
// What are you looking for? logout? client side will remove token when user click logout,
|
// What are you looking for? logout? client side will remove token when user click logout,
|
||||||
// or it will auto expire after 24 hours.
|
// or it will auto expire after 24 hours.
|
||||||
// This token is different with the token send to npm client.
|
// This token is different with the token send to npm client.
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { HEADERS } from '@verdaccio/commons-api';
|
||||||
import { getPublicUrl } from '@verdaccio/url';
|
import { getPublicUrl } from '@verdaccio/url';
|
||||||
|
|
||||||
import { WEB_TITLE } from '@verdaccio/config';
|
import { WEB_TITLE } from '@verdaccio/config';
|
||||||
import { validatePrimaryColor } from './utils/web-utils';
|
import { hasLogin, validatePrimaryColor } from './utils/web-utils';
|
||||||
import renderTemplate from './template';
|
import renderTemplate from './template';
|
||||||
|
|
||||||
const pkgJSON = require('../package.json');
|
const pkgJSON = require('../package.json');
|
||||||
|
@ -26,6 +26,7 @@ export default function renderHTML(config, manifest, manifestFiles, req, res) {
|
||||||
const language = config?.i18n?.web ?? DEFAULT_LANGUAGE;
|
const language = config?.i18n?.web ?? DEFAULT_LANGUAGE;
|
||||||
const darkMode = config?.web?.darkMode ?? false;
|
const darkMode = config?.web?.darkMode ?? false;
|
||||||
const title = config?.web?.title ?? WEB_TITLE;
|
const title = config?.web?.title ?? WEB_TITLE;
|
||||||
|
const login = hasLogin(config);
|
||||||
const scope = config?.web?.scope ?? '';
|
const scope = config?.web?.scope ?? '';
|
||||||
// FIXME: logo URI is incomplete
|
// FIXME: logo URI is incomplete
|
||||||
let logoURI = config?.web?.logo ?? '';
|
let logoURI = config?.web?.logo ?? '';
|
||||||
|
@ -49,6 +50,7 @@ export default function renderHTML(config, manifest, manifestFiles, req, res) {
|
||||||
primaryColor,
|
primaryColor,
|
||||||
version,
|
version,
|
||||||
logoURI,
|
logoURI,
|
||||||
|
login,
|
||||||
pkgManagers,
|
pkgManagers,
|
||||||
title,
|
title,
|
||||||
scope,
|
scope,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import buildDebug from 'debug';
|
import buildDebug from 'debug';
|
||||||
import { isObject } from '@verdaccio/utils';
|
import { isObject } from '@verdaccio/utils';
|
||||||
import { Package, Author } from '@verdaccio/types';
|
import { Package, Author, ConfigYaml } from '@verdaccio/types';
|
||||||
import { normalizeContributors } from '@verdaccio/store';
|
import { normalizeContributors } from '@verdaccio/store';
|
||||||
|
|
||||||
import sanitizyReadme from '@verdaccio/readme';
|
import sanitizyReadme from '@verdaccio/readme';
|
||||||
|
@ -109,3 +109,7 @@ export function sortByName(packages: any[], orderAscending: boolean | void = tru
|
||||||
return orderAscending ? (comparatorNames ? -1 : 1) : comparatorNames ? 1 : -1;
|
return orderAscending ? (comparatorNames ? -1 : 1) : comparatorNames ? 1 : -1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function hasLogin(config: ConfigYaml) {
|
||||||
|
return _.isNil(config?.web?.login) || config?.web?.login === true;
|
||||||
|
}
|
||||||
|
|
|
@ -62,6 +62,19 @@ describe('test web server', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('log in should be disabled', async () => {
|
||||||
|
return supertest(await initializeServer('login-disabled.yaml'))
|
||||||
|
.post('/-/verdaccio/login')
|
||||||
|
.send(
|
||||||
|
JSON.stringify({
|
||||||
|
username: 'test',
|
||||||
|
password: 'test',
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON)
|
||||||
|
.expect(HTTP_STATUS.NOT_FOUND);
|
||||||
|
});
|
||||||
|
|
||||||
test.todo('should change password');
|
test.todo('should change password');
|
||||||
test.todo('should not change password if flag is disabled');
|
test.todo('should not change password if flag is disabled');
|
||||||
});
|
});
|
||||||
|
|
33
packages/web/test/config/login-disabled.yaml
Normal file
33
packages/web/test/config/login-disabled.yaml
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
store:
|
||||||
|
memory:
|
||||||
|
limit: 1000
|
||||||
|
|
||||||
|
auth:
|
||||||
|
auth-memory:
|
||||||
|
users:
|
||||||
|
test:
|
||||||
|
name: test
|
||||||
|
password: test
|
||||||
|
|
||||||
|
web:
|
||||||
|
title: verdaccio
|
||||||
|
login: false
|
||||||
|
|
||||||
|
publish:
|
||||||
|
allow_offline: false
|
||||||
|
|
||||||
|
uplinks:
|
||||||
|
|
||||||
|
logs: { type: stdout, format: pretty, level: trace }
|
||||||
|
|
||||||
|
packages:
|
||||||
|
'@*/*':
|
||||||
|
access: $anonymous
|
||||||
|
publish: $anonymous
|
||||||
|
'**':
|
||||||
|
access: $anonymous
|
||||||
|
publish: $anonymous
|
||||||
|
_debug: true
|
||||||
|
|
||||||
|
flags:
|
||||||
|
changePassword: true
|
31
pnpm-lock.yaml
generated
31
pnpm-lock.yaml
generated
|
@ -1121,7 +1121,7 @@ importers:
|
||||||
debug: 4.3.1
|
debug: 4.3.1
|
||||||
kleur: ^4.1.3
|
kleur: ^4.1.3
|
||||||
lodash: ^4.17.20
|
lodash: ^4.17.20
|
||||||
puppeteer: ^7.1.0
|
puppeteer: ^9.1.1
|
||||||
request: ^2.88.2
|
request: ^2.88.2
|
||||||
rimraf: ^3.0.2
|
rimraf: ^3.0.2
|
||||||
devDependencies:
|
devDependencies:
|
||||||
|
@ -1130,7 +1130,7 @@ importers:
|
||||||
debug: 4.3.1
|
debug: 4.3.1
|
||||||
kleur: 4.1.3
|
kleur: 4.1.3
|
||||||
lodash: 4.17.20
|
lodash: 4.17.20
|
||||||
puppeteer: 7.1.0
|
puppeteer: 9.1.1
|
||||||
request: 2.88.2
|
request: 2.88.2
|
||||||
rimraf: 3.0.2
|
rimraf: 3.0.2
|
||||||
|
|
||||||
|
@ -7676,7 +7676,7 @@ packages:
|
||||||
/@types/yauzl/2.9.1:
|
/@types/yauzl/2.9.1:
|
||||||
resolution: {integrity: sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==}
|
resolution: {integrity: sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 14.14.21
|
'@types/node': 14.14.41
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
@ -12113,8 +12113,8 @@ packages:
|
||||||
tslib: 1.13.0
|
tslib: 1.13.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/devtools-protocol/0.0.847576:
|
/devtools-protocol/0.0.869402:
|
||||||
resolution: {integrity: sha512-0M8kobnSQE0Jmly7Mhbeq0W/PpZfnuK+WjN2ZRVPbGqYwCHCioAVp84H0TcLimgECcN5H976y5QiXMGBC9JKmg==}
|
resolution: {integrity: sha512-VvlVYY+VDJe639yHs5PHISzdWTLL3Aw8rO4cvUtwvoxFd6FHbE4OpHHcde52M6096uYYazAmd4l0o5VuFRO2WA==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/diacritic/0.0.2:
|
/diacritic/0.0.2:
|
||||||
|
@ -22243,13 +22243,13 @@ packages:
|
||||||
escape-goat: 2.1.1
|
escape-goat: 2.1.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/puppeteer/7.1.0:
|
/puppeteer/9.1.1:
|
||||||
resolution: {integrity: sha512-lqOLzqCKdh7yUAHvK6LxgOpQrL8Bv1/jvS8MLDXxcNms2rlM3E8p/Wlwc7efbRZ0twxTzUeqjN5EqrTwxOwc9g==}
|
resolution: {integrity: sha512-W+nOulP2tYd/ZG99WuZC/I5ljjQQ7EUw/jQGcIb9eu8mDlZxNY2SgcJXTLG9h5gRvqA3uJOe4hZXYsd3EqioMw==}
|
||||||
engines: {node: '>=10.18.1'}
|
engines: {node: '>=10.18.1'}
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.3.1
|
debug: 4.3.1
|
||||||
devtools-protocol: 0.0.847576
|
devtools-protocol: 0.0.869402
|
||||||
extract-zip: 2.0.1
|
extract-zip: 2.0.1
|
||||||
https-proxy-agent: 5.0.0
|
https-proxy-agent: 5.0.0
|
||||||
node-fetch: 2.6.1
|
node-fetch: 2.6.1
|
||||||
|
@ -22259,7 +22259,7 @@ packages:
|
||||||
rimraf: 3.0.2
|
rimraf: 3.0.2
|
||||||
tar-fs: 2.1.0
|
tar-fs: 2.1.0
|
||||||
unbzip2-stream: 1.4.3
|
unbzip2-stream: 1.4.3
|
||||||
ws: 7.4.2
|
ws: 7.4.4
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- bufferutil
|
- bufferutil
|
||||||
- supports-color
|
- supports-color
|
||||||
|
@ -27412,19 +27412,6 @@ packages:
|
||||||
utf-8-validate:
|
utf-8-validate:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/ws/7.4.2:
|
|
||||||
resolution: {integrity: sha512-T4tewALS3+qsrpGI/8dqNMLIVdq/g/85U98HPMa6F0m6xTbvhXU6RCQLqPH3+SlomNV/LdY6RXEbBpMH6EOJnA==}
|
|
||||||
engines: {node: '>=8.3.0'}
|
|
||||||
peerDependencies:
|
|
||||||
bufferutil: ^4.0.1
|
|
||||||
utf-8-validate: ^5.0.2
|
|
||||||
peerDependenciesMeta:
|
|
||||||
bufferutil:
|
|
||||||
optional: true
|
|
||||||
utf-8-validate:
|
|
||||||
optional: true
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/ws/7.4.4:
|
/ws/7.4.4:
|
||||||
resolution: {integrity: sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==}
|
resolution: {integrity: sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==}
|
||||||
engines: {node: '>=8.3.0'}
|
engines: {node: '>=8.3.0'}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
web:
|
web:
|
||||||
enable: true
|
enable: true
|
||||||
title: verdaccio-server-protected-e2e
|
title: verdaccio-server-protected-e2e
|
||||||
|
login: true
|
||||||
|
|
||||||
store:
|
store:
|
||||||
memory:
|
memory:
|
||||||
|
@ -13,8 +14,7 @@ auth:
|
||||||
name: test
|
name: test
|
||||||
password: test
|
password: test
|
||||||
|
|
||||||
logs:
|
logs: { type: stdout, format: pretty, level: info }
|
||||||
- { type: stdout, format: pretty, level: info }
|
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
'protected-*':
|
'protected-*':
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
web:
|
web:
|
||||||
enable: true
|
enable: true
|
||||||
title: verdaccio-server-e2e
|
title: verdaccio-server-e2e
|
||||||
|
login: true
|
||||||
|
|
||||||
store:
|
store:
|
||||||
memory:
|
memory:
|
||||||
|
@ -13,8 +14,7 @@ auth:
|
||||||
name: test
|
name: test
|
||||||
password: test
|
password: test
|
||||||
|
|
||||||
logs:
|
logs: { type: stdout, format: pretty, level: info }
|
||||||
- { type: stdout, format: pretty, level: info }
|
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
'@*/*':
|
'@*/*':
|
||||||
|
|
|
@ -40,7 +40,7 @@ describe('/ (Verdaccio Page)', () => {
|
||||||
expect(loginButton).toBeDefined();
|
expect(loginButton).toBeDefined();
|
||||||
await loginButton.focus();
|
await loginButton.focus();
|
||||||
await loginButton.click({ delay: 100 });
|
await loginButton.click({ delay: 100 });
|
||||||
await page.waitFor(500);
|
await page.waitForTimeout(500);
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
|
@ -55,7 +55,7 @@ describe('/ (Verdaccio Page)', () => {
|
||||||
|
|
||||||
test('should display title', async () => {
|
test('should display title', async () => {
|
||||||
const text = await page.title();
|
const text = await page.title();
|
||||||
await page.waitFor(1000);
|
await page.waitForTimeout(1000);
|
||||||
|
|
||||||
expect(text).toContain('verdaccio-server-e2e');
|
expect(text).toContain('verdaccio-server-e2e');
|
||||||
});
|
});
|
||||||
|
@ -87,29 +87,34 @@ describe('/ (Verdaccio Page)', () => {
|
||||||
test('should click on sign in button', async () => {
|
test('should click on sign in button', async () => {
|
||||||
const signInButton = await page.$('button[data-testid="header--button-login"]');
|
const signInButton = await page.$('button[data-testid="header--button-login"]');
|
||||||
await signInButton.click();
|
await signInButton.click();
|
||||||
await page.waitFor(1000);
|
await page.waitForTimeout(1000);
|
||||||
const signInDialog = await page.$('#login--dialog');
|
const signInDialog = await page.$('#login--dialog');
|
||||||
expect(signInDialog).not.toBeNull();
|
expect(signInDialog).not.toBeNull();
|
||||||
const closeButton = await page.$('button[data-testid="close-login-dialog-button"]');
|
const closeButton = await page.$('button[data-testid="close-login-dialog-button"]');
|
||||||
await closeButton.click();
|
await closeButton.click();
|
||||||
await page.waitFor(500);
|
await page.waitForTimeout(500);
|
||||||
});
|
});
|
||||||
//
|
//
|
||||||
|
|
||||||
test('should log in an user', async () => {
|
test('should log in an user', async () => {
|
||||||
// we open the dialog
|
// we open the dialog
|
||||||
await logIn();
|
await logIn();
|
||||||
|
// verify if logged in
|
||||||
|
const accountButton = await page.$('#header--button-account');
|
||||||
|
expect(accountButton).toBeDefined();
|
||||||
// check whether user is logged
|
// check whether user is logged
|
||||||
const buttonLogout = await page.$('#header--button-logout');
|
const buttonLogout = await page.$('#header--button-logout');
|
||||||
expect(buttonLogout).toBeDefined();
|
expect(buttonLogout).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should logout an user', async () => {
|
test('should logout an user', async () => {
|
||||||
|
// await wa
|
||||||
|
await page.waitForTimeout(10000);
|
||||||
// we assume the user is logged already
|
// we assume the user is logged already
|
||||||
await clickElement('#header--button-account', { delay: 500 });
|
await clickElement('#header--button-account', { delay: 500 });
|
||||||
await page.waitFor(1000);
|
await page.waitForTimeout(1000);
|
||||||
await clickElement('#header--button-logout > span', { delay: 500 });
|
await clickElement('#header--button-logout > span', { delay: 500 });
|
||||||
await page.waitFor(1000);
|
await page.waitForTimeout(1000);
|
||||||
await evaluateSignIn();
|
await evaluateSignIn();
|
||||||
});
|
});
|
||||||
//
|
//
|
||||||
|
@ -117,7 +122,7 @@ describe('/ (Verdaccio Page)', () => {
|
||||||
test('should check registry info dialog', async () => {
|
test('should check registry info dialog', async () => {
|
||||||
const registryInfoButton = await page.$('#header--button-registryInfo');
|
const registryInfoButton = await page.$('#header--button-registryInfo');
|
||||||
registryInfoButton.click();
|
registryInfoButton.click();
|
||||||
await page.waitFor(500);
|
await page.waitForTimeout(500);
|
||||||
|
|
||||||
const registryInfoDialog = await page.$('#registryInfo--dialog-container');
|
const registryInfoDialog = await page.$('#registryInfo--dialog-container');
|
||||||
expect(registryInfoDialog).not.toBeNull();
|
expect(registryInfoDialog).not.toBeNull();
|
||||||
|
@ -129,9 +134,9 @@ describe('/ (Verdaccio Page)', () => {
|
||||||
|
|
||||||
test('should publish a package', async () => {
|
test('should publish a package', async () => {
|
||||||
await global.__SERVER__.putPackage(scopedPackageMetadata.name, scopedPackageMetadata);
|
await global.__SERVER__.putPackage(scopedPackageMetadata.name, scopedPackageMetadata);
|
||||||
await page.waitFor(1000);
|
await page.waitForTimeout(1000);
|
||||||
await page.reload();
|
await page.reload();
|
||||||
await page.waitFor(1000);
|
await page.waitForTimeout(1000);
|
||||||
const packagesList = await getPackages();
|
const packagesList = await getPackages();
|
||||||
expect(packagesList).toHaveLength(1);
|
expect(packagesList).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
@ -142,7 +147,7 @@ describe('/ (Verdaccio Page)', () => {
|
||||||
// console.log("-->packagesList:", packagesList);
|
// console.log("-->packagesList:", packagesList);
|
||||||
const firstPackage = packagesList[0];
|
const firstPackage = packagesList[0];
|
||||||
await firstPackage.click({ delay: 200 });
|
await firstPackage.click({ delay: 200 });
|
||||||
await page.waitFor(1000);
|
await page.waitForTimeout(1000);
|
||||||
const readmeText = await page.evaluate(
|
const readmeText = await page.evaluate(
|
||||||
() => document.querySelector('.markdown-body').textContent
|
() => document.querySelector('.markdown-body').textContent
|
||||||
);
|
);
|
||||||
|
@ -160,7 +165,7 @@ describe('/ (Verdaccio Page)', () => {
|
||||||
const dependenciesTab = await page.$$('#dependencies-tab');
|
const dependenciesTab = await page.$$('#dependencies-tab');
|
||||||
expect(dependenciesTab).toHaveLength(1);
|
expect(dependenciesTab).toHaveLength(1);
|
||||||
await dependenciesTab[0].click({ delay: 200 });
|
await dependenciesTab[0].click({ delay: 200 });
|
||||||
await page.waitFor(1000);
|
await page.waitForTimeout(1000);
|
||||||
const tags = await page.$$('.dep-tag');
|
const tags = await page.$$('.dep-tag');
|
||||||
const tag = tags[0];
|
const tag = tags[0];
|
||||||
const label = await page.evaluate((el) => el.innerText, tag);
|
const label = await page.evaluate((el) => el.innerText, tag);
|
||||||
|
@ -171,7 +176,7 @@ describe('/ (Verdaccio Page)', () => {
|
||||||
const versionsTab = await page.$$('#versions-tab');
|
const versionsTab = await page.$$('#versions-tab');
|
||||||
expect(versionsTab).toHaveLength(1);
|
expect(versionsTab).toHaveLength(1);
|
||||||
await versionsTab[0].click({ delay: 200 });
|
await versionsTab[0].click({ delay: 200 });
|
||||||
await page.waitFor(1000);
|
await page.waitForTimeout(1000);
|
||||||
const versionItems = await page.$$('.version-item');
|
const versionItems = await page.$$('.version-item');
|
||||||
expect(versionItems).toHaveLength(2);
|
expect(versionItems).toHaveLength(2);
|
||||||
});
|
});
|
||||||
|
@ -180,33 +185,33 @@ describe('/ (Verdaccio Page)', () => {
|
||||||
const upLinksTab = await page.$$('#uplinks-tab');
|
const upLinksTab = await page.$$('#uplinks-tab');
|
||||||
expect(upLinksTab).toHaveLength(1);
|
expect(upLinksTab).toHaveLength(1);
|
||||||
await upLinksTab[0].click({ delay: 200 });
|
await upLinksTab[0].click({ delay: 200 });
|
||||||
await page.waitFor(1000);
|
await page.waitForTimeout(1000);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should display readme tab', async () => {
|
test('should display readme tab', async () => {
|
||||||
const readmeTab = await page.$$('#readme-tab');
|
const readmeTab = await page.$$('#readme-tab');
|
||||||
expect(readmeTab).toHaveLength(1);
|
expect(readmeTab).toHaveLength(1);
|
||||||
await readmeTab[0].click({ delay: 200 });
|
await readmeTab[0].click({ delay: 200 });
|
||||||
await page.waitFor(1000);
|
await page.waitForTimeout(1000);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should publish a protected package', async () => {
|
test('should publish a protected package', async () => {
|
||||||
await page.goto('http://0.0.0.0:55552');
|
await page.goto('http://0.0.0.0:55552');
|
||||||
await page.waitFor(500);
|
await page.waitForTimeout(500);
|
||||||
await global.__SERVER_PROTECTED__.putPackage(
|
await global.__SERVER_PROTECTED__.putPackage(
|
||||||
protectedPackageMetadata.name,
|
protectedPackageMetadata.name,
|
||||||
protectedPackageMetadata
|
protectedPackageMetadata
|
||||||
);
|
);
|
||||||
await page.waitFor(500);
|
await page.waitForTimeout(500);
|
||||||
await page.reload();
|
await page.reload();
|
||||||
await page.waitFor(500);
|
await page.waitForTimeout(500);
|
||||||
const text = await page.evaluate(() => document.querySelector('#help-card__title').textContent);
|
const text = await page.evaluate(() => document.querySelector('#help-card__title').textContent);
|
||||||
expect(text).toMatch('No Package Published Yet');
|
expect(text).toMatch('No Package Published Yet');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should go to 404 page', async () => {
|
test('should go to 404 page', async () => {
|
||||||
await page.goto('http://0.0.0.0:55552/-/web/detail/@verdaccio/not-found');
|
await page.goto('http://0.0.0.0:55552/-/web/detail/@verdaccio/not-found');
|
||||||
await page.waitFor(500);
|
await page.waitForTimeout(500);
|
||||||
const text = await page.evaluate(() => document.querySelector('.not-found-text').textContent);
|
const text = await page.evaluate(() => document.querySelector('.not-found-text').textContent);
|
||||||
expect(text).toMatch("Sorry, we couldn't find it...");
|
expect(text).toMatch("Sorry, we couldn't find it...");
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
"request": "^2.88.2",
|
"request": "^2.88.2",
|
||||||
"lodash": "^4.17.20",
|
"lodash": "^4.17.20",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"puppeteer": "^7.1.0"
|
"puppeteer": "^9.1.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "jest --config jest.config.e2e.js"
|
"test": "jest --config jest.config.e2e.js"
|
||||||
|
|
Loading…
Add table
Reference in a new issue