From 0da7031e77963dc6c0dc8510f21e82340a4123f1 Mon Sep 17 00:00:00 2001 From: Juan Picado Date: Wed, 5 May 2021 23:23:03 +0200 Subject: [PATCH] feat: allow disable login on ui (#2228) --- .changeset/afraid-mice-obey.md | 15 +++++++ packages/core/types/index.d.ts | 1 + .../ui-theme/src/App/Header/Header.test.tsx | 25 +++++++++-- .../ui-theme/src/App/Header/Header.tsx | 1 + .../ui-theme/src/App/Header/HeaderRight.tsx | 33 +++++++++------ .../config/AppConfigurationProvider.tsx | 2 +- .../ui-theme/tools/_verdaccio.config.yaml | 1 + packages/plugins/ui-theme/types/index.ts | 1 + packages/web/src/api/package.ts | 11 ++++- packages/web/src/api/readme.ts | 2 +- packages/web/src/middleware/web-api.ts | 5 ++- packages/web/src/renderHTML.ts | 4 +- packages/web/src/utils/web-utils.ts | 6 ++- packages/web/test/api.user.test.ts | 13 ++++++ packages/web/test/config/login-disabled.yaml | 33 +++++++++++++++ pnpm-lock.yaml | 31 ++++---------- test/e2e-ui/config/config-protected-e2e.yaml | 4 +- test/e2e-ui/config/config-scoped-e2e.yaml | 4 +- test/e2e-ui/e2e.spec.js | 41 +++++++++++-------- test/e2e-ui/package.json | 2 +- 20 files changed, 168 insertions(+), 67 deletions(-) create mode 100644 .changeset/afraid-mice-obey.md create mode 100644 packages/web/test/config/login-disabled.yaml diff --git a/.changeset/afraid-mice-obey.md b/.changeset/afraid-mice-obey.md new file mode 100644 index 000000000..cf7cd6f16 --- /dev/null +++ b/.changeset/afraid-mice-obey.md @@ -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 +``` diff --git a/packages/core/types/index.d.ts b/packages/core/types/index.d.ts index 41da5ce00..461095e43 100644 --- a/packages/core/types/index.d.ts +++ b/packages/core/types/index.d.ts @@ -27,6 +27,7 @@ declare module '@verdaccio/types' { darkMode?: boolean; url_prefix?: string; language?: string; + login?: boolean; scope?: string; pkgManagers?: PackageManagers[]; }; diff --git a/packages/plugins/ui-theme/src/App/Header/Header.test.tsx b/packages/plugins/ui-theme/src/App/Header/Header.test.tsx index b30ed4e6d..638966c01 100644 --- a/packages/plugins/ui-theme/src/App/Header/Header.test.tsx +++ b/packages/plugins/ui-theme/src/App/Header/Header.test.tsx @@ -5,6 +5,7 @@ import { render, fireEvent, waitFor, + screen, waitForElementToBeRemoved, } from 'verdaccio-ui/utils/test-react-testing-library'; @@ -23,7 +24,7 @@ const props = { /* eslint-disable react/jsx-no-bind*/ describe('
component with logged in state', () => { test('should load the component in logged out state', () => { - const { queryByTestId, getByText } = render( + render(
@@ -31,8 +32,9 @@ describe('
component with logged in state', () => { ); - expect(queryByTestId('header--menu-accountcircle')).toBeNull(); - expect(getByText('Login')).toBeTruthy(); + expect(screen.queryByTestId('header--menu-accountcircle')).toBeNull(); + expect(screen.getByText('Login')).toBeTruthy(); + expect(screen.queryByTestId('header--button-login')).toBeInTheDocument(); }); test('should load the component in logged in state', () => { @@ -135,5 +137,22 @@ describe('
component with logged in state', () => { expect(hasRegistrationInfoModalBeenRemoved).not.toBeDefined(); }); + test('should hide login if is disabled', () => { + // @ts-expect-error + window.__VERDACCIO_BASENAME_UI_OPTIONS = { + base: 'foo', + login: false, + }; + render( + + +
+ + + ); + + expect(screen.queryByTestId('header--button-login')).not.toBeInTheDocument(); + }); + test.todo('autocompletion should display suggestions according to the type value'); }); diff --git a/packages/plugins/ui-theme/src/App/Header/Header.tsx b/packages/plugins/ui-theme/src/App/Header/Header.tsx index 0590cff03..f8494ecec 100644 --- a/packages/plugins/ui-theme/src/App/Header/Header.tsx +++ b/packages/plugins/ui-theme/src/App/Header/Header.tsx @@ -49,6 +49,7 @@ const Header: React.FC = ({ withoutSearch }) => { setOpenInfoDialog(true)} onToggleLogin={() => setShowLoginModal(!showLoginModal)} diff --git a/packages/plugins/ui-theme/src/App/Header/HeaderRight.tsx b/packages/plugins/ui-theme/src/App/Header/HeaderRight.tsx index 71c661553..b67def2db 100644 --- a/packages/plugins/ui-theme/src/App/Header/HeaderRight.tsx +++ b/packages/plugins/ui-theme/src/App/Header/HeaderRight.tsx @@ -12,6 +12,7 @@ import { RightSide } from './styles'; interface Props { withoutSearch?: boolean; username?: string | null; + hasLogin?: boolean; onToggleLogin: () => void; onOpenRegistryInfoDialog: () => void; onToggleMobileNav: () => void; @@ -22,6 +23,7 @@ const HeaderRight: React.FC = ({ withoutSearch = false, username, onToggleLogin, + hasLogin, onLogout, onToggleMobileNav, onOpenRegistryInfoDialog, @@ -29,6 +31,7 @@ const HeaderRight: React.FC = ({ const themeContext = useContext(ThemeContext); const [anchorEl, setAnchorEl] = useState(null); const [isMenuOpen, setIsMenuOpen] = useState(false); + const hideLoginSection = hasLogin === false; const { t } = useTranslation(); @@ -90,19 +93,23 @@ const HeaderRight: React.FC = ({ tooltipIconType={themeContext.isDarkMode ? 'dark-mode' : 'light-mode'} /> - {username ? ( - - ) : ( - + {!hideLoginSection && ( + <> + {username ? ( + + ) : ( + + )} + )} ); diff --git a/packages/plugins/ui-theme/src/providers/config/AppConfigurationProvider.tsx b/packages/plugins/ui-theme/src/providers/config/AppConfigurationProvider.tsx index 15eb63a7c..99f6fd13c 100644 --- a/packages/plugins/ui-theme/src/providers/config/AppConfigurationProvider.tsx +++ b/packages/plugins/ui-theme/src/providers/config/AppConfigurationProvider.tsx @@ -17,6 +17,7 @@ const defaultValues: ConfigProviderProps = { pkgManagers: ['yarn', 'pnpm', 'npm'], scope: '', base: '', + login: true, url_prefix: '', title: 'Verdaccio', }, @@ -46,7 +47,6 @@ const AppConfigurationProvider: FunctionComponent = ({ children }) => { [configOptions] ); - // @ts-ignore return ( {children} ); diff --git a/packages/plugins/ui-theme/tools/_verdaccio.config.yaml b/packages/plugins/ui-theme/tools/_verdaccio.config.yaml index b884640d5..cd05be58d 100644 --- a/packages/plugins/ui-theme/tools/_verdaccio.config.yaml +++ b/packages/plugins/ui-theme/tools/_verdaccio.config.yaml @@ -2,6 +2,7 @@ web: title: Verdaccio Local Dev sort_packages: asc primary_color: #CCC + login: true pkgManagers: - npm - yarn diff --git a/packages/plugins/ui-theme/types/index.ts b/packages/plugins/ui-theme/types/index.ts index 241828dc9..845306bda 100644 --- a/packages/plugins/ui-theme/types/index.ts +++ b/packages/plugins/ui-theme/types/index.ts @@ -9,6 +9,7 @@ export interface VerdaccioOptions { primaryColor: string; darkMode: boolean; uri?: string; + login?: boolean; language?: string; version?: string; protocol?: string; diff --git a/packages/web/src/api/package.ts b/packages/web/src/api/package.ts index 7920ad728..23f69da41 100644 --- a/packages/web/src/api/package.ts +++ b/packages/web/src/api/package.ts @@ -29,11 +29,20 @@ function addPackageWebApi( auth: IAuth, config: Config ): void { + const isLoginEnabled = config?.web?.login === true ?? true; + const anonymousRemoteUser: RemoteUser = { + name: undefined, + real_groups: [], + groups: [], + }; + debug('initialized package web api'); const checkAllow = (name: string, remoteUser: RemoteUser): Promise => new Promise((resolve, reject): void => { + debug('is login disabled %o', isLoginEnabled); + const remoteUserAccess = !isLoginEnabled ? anonymousRemoteUser : remoteUser; try { - auth.allow_access({ packageName: name }, remoteUser, (err, allowed): void => { + auth.allow_access({ packageName: name }, remoteUserAccess, (err, allowed): void => { if (err) { resolve(false); } diff --git a/packages/web/src/api/readme.ts b/packages/web/src/api/readme.ts index a25addcce..8f38efd21 100644 --- a/packages/web/src/api/readme.ts +++ b/packages/web/src/api/readme.ts @@ -37,7 +37,7 @@ function addReadmeWebApi(route: Router, storage: IStorageHandler, auth: IAuth): uplinksLook: true, req, callback: function (err, info): void { - debug('readme plg %o', info); + debug('readme plg %o', info?.name); if (err) { return next(err); } diff --git a/packages/web/src/middleware/web-api.ts b/packages/web/src/middleware/web-api.ts index a9bd67b48..a31253cde 100644 --- a/packages/web/src/middleware/web-api.ts +++ b/packages/web/src/middleware/web-api.ts @@ -11,6 +11,7 @@ import addPackageWebApi from '../api/package'; import addUserAuthApi from '../api/user'; import addReadmeWebApi from '../api/readme'; import addSidebarWebApi from '../api/sidebar'; +import { hasLogin } from '../utils/web-utils'; import { setSecurityWebHeaders } from './security'; 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); addSidebarWebApi(route, config, 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, // or it will auto expire after 24 hours. // This token is different with the token send to npm client. diff --git a/packages/web/src/renderHTML.ts b/packages/web/src/renderHTML.ts index d9e75990d..595e071b1 100644 --- a/packages/web/src/renderHTML.ts +++ b/packages/web/src/renderHTML.ts @@ -5,7 +5,7 @@ import { HEADERS } from '@verdaccio/commons-api'; import { getPublicUrl } from '@verdaccio/url'; import { WEB_TITLE } from '@verdaccio/config'; -import { validatePrimaryColor } from './utils/web-utils'; +import { hasLogin, validatePrimaryColor } from './utils/web-utils'; import renderTemplate from './template'; 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 darkMode = config?.web?.darkMode ?? false; const title = config?.web?.title ?? WEB_TITLE; + const login = hasLogin(config); const scope = config?.web?.scope ?? ''; // FIXME: logo URI is incomplete let logoURI = config?.web?.logo ?? ''; @@ -49,6 +50,7 @@ export default function renderHTML(config, manifest, manifestFiles, req, res) { primaryColor, version, logoURI, + login, pkgManagers, title, scope, diff --git a/packages/web/src/utils/web-utils.ts b/packages/web/src/utils/web-utils.ts index d18547df4..f200b6290 100644 --- a/packages/web/src/utils/web-utils.ts +++ b/packages/web/src/utils/web-utils.ts @@ -1,7 +1,7 @@ import _ from 'lodash'; import buildDebug from 'debug'; import { isObject } from '@verdaccio/utils'; -import { Package, Author } from '@verdaccio/types'; +import { Package, Author, ConfigYaml } from '@verdaccio/types'; import { normalizeContributors } from '@verdaccio/store'; 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; }); } + +export function hasLogin(config: ConfigYaml) { + return _.isNil(config?.web?.login) || config?.web?.login === true; +} diff --git a/packages/web/test/api.user.test.ts b/packages/web/test/api.user.test.ts index d6f52c8b1..6a6514d9b 100644 --- a/packages/web/test/api.user.test.ts +++ b/packages/web/test/api.user.test.ts @@ -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 not change password if flag is disabled'); }); diff --git a/packages/web/test/config/login-disabled.yaml b/packages/web/test/config/login-disabled.yaml new file mode 100644 index 000000000..acc7d1f72 --- /dev/null +++ b/packages/web/test/config/login-disabled.yaml @@ -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 diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c66bf1cef..886ff2ee0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1121,7 +1121,7 @@ importers: debug: 4.3.1 kleur: ^4.1.3 lodash: ^4.17.20 - puppeteer: ^7.1.0 + puppeteer: ^9.1.1 request: ^2.88.2 rimraf: ^3.0.2 devDependencies: @@ -1130,7 +1130,7 @@ importers: debug: 4.3.1 kleur: 4.1.3 lodash: 4.17.20 - puppeteer: 7.1.0 + puppeteer: 9.1.1 request: 2.88.2 rimraf: 3.0.2 @@ -7676,7 +7676,7 @@ packages: /@types/yauzl/2.9.1: resolution: {integrity: sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==} dependencies: - '@types/node': 14.14.21 + '@types/node': 14.14.41 dev: true optional: true @@ -12113,8 +12113,8 @@ packages: tslib: 1.13.0 dev: false - /devtools-protocol/0.0.847576: - resolution: {integrity: sha512-0M8kobnSQE0Jmly7Mhbeq0W/PpZfnuK+WjN2ZRVPbGqYwCHCioAVp84H0TcLimgECcN5H976y5QiXMGBC9JKmg==} + /devtools-protocol/0.0.869402: + resolution: {integrity: sha512-VvlVYY+VDJe639yHs5PHISzdWTLL3Aw8rO4cvUtwvoxFd6FHbE4OpHHcde52M6096uYYazAmd4l0o5VuFRO2WA==} dev: true /diacritic/0.0.2: @@ -22243,13 +22243,13 @@ packages: escape-goat: 2.1.1 dev: true - /puppeteer/7.1.0: - resolution: {integrity: sha512-lqOLzqCKdh7yUAHvK6LxgOpQrL8Bv1/jvS8MLDXxcNms2rlM3E8p/Wlwc7efbRZ0twxTzUeqjN5EqrTwxOwc9g==} + /puppeteer/9.1.1: + resolution: {integrity: sha512-W+nOulP2tYd/ZG99WuZC/I5ljjQQ7EUw/jQGcIb9eu8mDlZxNY2SgcJXTLG9h5gRvqA3uJOe4hZXYsd3EqioMw==} engines: {node: '>=10.18.1'} requiresBuild: true dependencies: debug: 4.3.1 - devtools-protocol: 0.0.847576 + devtools-protocol: 0.0.869402 extract-zip: 2.0.1 https-proxy-agent: 5.0.0 node-fetch: 2.6.1 @@ -22259,7 +22259,7 @@ packages: rimraf: 3.0.2 tar-fs: 2.1.0 unbzip2-stream: 1.4.3 - ws: 7.4.2 + ws: 7.4.4 transitivePeerDependencies: - bufferutil - supports-color @@ -27412,19 +27412,6 @@ packages: utf-8-validate: 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: resolution: {integrity: sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==} engines: {node: '>=8.3.0'} diff --git a/test/e2e-ui/config/config-protected-e2e.yaml b/test/e2e-ui/config/config-protected-e2e.yaml index e39da3782..18e636c3d 100644 --- a/test/e2e-ui/config/config-protected-e2e.yaml +++ b/test/e2e-ui/config/config-protected-e2e.yaml @@ -1,6 +1,7 @@ web: enable: true title: verdaccio-server-protected-e2e + login: true store: memory: @@ -13,8 +14,7 @@ auth: name: test password: test -logs: - - { type: stdout, format: pretty, level: info } +logs: { type: stdout, format: pretty, level: info } packages: 'protected-*': diff --git a/test/e2e-ui/config/config-scoped-e2e.yaml b/test/e2e-ui/config/config-scoped-e2e.yaml index a5a80c5c6..83f610ec8 100644 --- a/test/e2e-ui/config/config-scoped-e2e.yaml +++ b/test/e2e-ui/config/config-scoped-e2e.yaml @@ -1,6 +1,7 @@ web: enable: true title: verdaccio-server-e2e + login: true store: memory: @@ -13,8 +14,7 @@ auth: name: test password: test -logs: - - { type: stdout, format: pretty, level: info } +logs: { type: stdout, format: pretty, level: info } packages: '@*/*': diff --git a/test/e2e-ui/e2e.spec.js b/test/e2e-ui/e2e.spec.js index d92e6b329..d63b137ea 100644 --- a/test/e2e-ui/e2e.spec.js +++ b/test/e2e-ui/e2e.spec.js @@ -40,7 +40,7 @@ describe('/ (Verdaccio Page)', () => { expect(loginButton).toBeDefined(); await loginButton.focus(); await loginButton.click({ delay: 100 }); - await page.waitFor(500); + await page.waitForTimeout(500); }; beforeAll(async () => { @@ -55,7 +55,7 @@ describe('/ (Verdaccio Page)', () => { test('should display title', async () => { const text = await page.title(); - await page.waitFor(1000); + await page.waitForTimeout(1000); expect(text).toContain('verdaccio-server-e2e'); }); @@ -87,29 +87,34 @@ describe('/ (Verdaccio Page)', () => { test('should click on sign in button', async () => { const signInButton = await page.$('button[data-testid="header--button-login"]'); await signInButton.click(); - await page.waitFor(1000); + await page.waitForTimeout(1000); const signInDialog = await page.$('#login--dialog'); expect(signInDialog).not.toBeNull(); const closeButton = await page.$('button[data-testid="close-login-dialog-button"]'); await closeButton.click(); - await page.waitFor(500); + await page.waitForTimeout(500); }); // test('should log in an user', async () => { // we open the dialog await logIn(); + // verify if logged in + const accountButton = await page.$('#header--button-account'); + expect(accountButton).toBeDefined(); // check whether user is logged const buttonLogout = await page.$('#header--button-logout'); expect(buttonLogout).toBeDefined(); }); test('should logout an user', async () => { + // await wa + await page.waitForTimeout(10000); // we assume the user is logged already await clickElement('#header--button-account', { delay: 500 }); - await page.waitFor(1000); + await page.waitForTimeout(1000); await clickElement('#header--button-logout > span', { delay: 500 }); - await page.waitFor(1000); + await page.waitForTimeout(1000); await evaluateSignIn(); }); // @@ -117,7 +122,7 @@ describe('/ (Verdaccio Page)', () => { test('should check registry info dialog', async () => { const registryInfoButton = await page.$('#header--button-registryInfo'); registryInfoButton.click(); - await page.waitFor(500); + await page.waitForTimeout(500); const registryInfoDialog = await page.$('#registryInfo--dialog-container'); expect(registryInfoDialog).not.toBeNull(); @@ -129,9 +134,9 @@ describe('/ (Verdaccio Page)', () => { test('should publish a package', async () => { await global.__SERVER__.putPackage(scopedPackageMetadata.name, scopedPackageMetadata); - await page.waitFor(1000); + await page.waitForTimeout(1000); await page.reload(); - await page.waitFor(1000); + await page.waitForTimeout(1000); const packagesList = await getPackages(); expect(packagesList).toHaveLength(1); }); @@ -142,7 +147,7 @@ describe('/ (Verdaccio Page)', () => { // console.log("-->packagesList:", packagesList); const firstPackage = packagesList[0]; await firstPackage.click({ delay: 200 }); - await page.waitFor(1000); + await page.waitForTimeout(1000); const readmeText = await page.evaluate( () => document.querySelector('.markdown-body').textContent ); @@ -160,7 +165,7 @@ describe('/ (Verdaccio Page)', () => { const dependenciesTab = await page.$$('#dependencies-tab'); expect(dependenciesTab).toHaveLength(1); await dependenciesTab[0].click({ delay: 200 }); - await page.waitFor(1000); + await page.waitForTimeout(1000); const tags = await page.$$('.dep-tag'); const tag = tags[0]; const label = await page.evaluate((el) => el.innerText, tag); @@ -171,7 +176,7 @@ describe('/ (Verdaccio Page)', () => { const versionsTab = await page.$$('#versions-tab'); expect(versionsTab).toHaveLength(1); await versionsTab[0].click({ delay: 200 }); - await page.waitFor(1000); + await page.waitForTimeout(1000); const versionItems = await page.$$('.version-item'); expect(versionItems).toHaveLength(2); }); @@ -180,33 +185,33 @@ describe('/ (Verdaccio Page)', () => { const upLinksTab = await page.$$('#uplinks-tab'); expect(upLinksTab).toHaveLength(1); await upLinksTab[0].click({ delay: 200 }); - await page.waitFor(1000); + await page.waitForTimeout(1000); }); test('should display readme tab', async () => { const readmeTab = await page.$$('#readme-tab'); expect(readmeTab).toHaveLength(1); await readmeTab[0].click({ delay: 200 }); - await page.waitFor(1000); + await page.waitForTimeout(1000); }); test('should publish a protected package', async () => { await page.goto('http://0.0.0.0:55552'); - await page.waitFor(500); + await page.waitForTimeout(500); await global.__SERVER_PROTECTED__.putPackage( protectedPackageMetadata.name, protectedPackageMetadata ); - await page.waitFor(500); + await page.waitForTimeout(500); await page.reload(); - await page.waitFor(500); + await page.waitForTimeout(500); const text = await page.evaluate(() => document.querySelector('#help-card__title').textContent); expect(text).toMatch('No Package Published Yet'); }); test('should go to 404 page', async () => { 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); expect(text).toMatch("Sorry, we couldn't find it..."); }); diff --git a/test/e2e-ui/package.json b/test/e2e-ui/package.json index a7daecdee..2dd0ddcdc 100644 --- a/test/e2e-ui/package.json +++ b/test/e2e-ui/package.json @@ -10,7 +10,7 @@ "request": "^2.88.2", "lodash": "^4.17.20", "rimraf": "^3.0.2", - "puppeteer": "^7.1.0" + "puppeteer": "^9.1.1" }, "scripts": { "test": "jest --config jest.config.e2e.js"