mirror of
https://github.com/logto-io/logto.git
synced 2024-12-16 20:26:19 -05:00
Merge pull request #3299 from logto-io/gao-improve-ui-test
test: improve ui test code
This commit is contained in:
commit
e5b055f173
6 changed files with 111 additions and 106 deletions
|
@ -51,7 +51,7 @@ const Tenants = ({ data, onAdd }: Props) => {
|
||||||
</a>
|
</a>
|
||||||
))}
|
))}
|
||||||
<h3>Create a tenant</h3>
|
<h3>Create a tenant</h3>
|
||||||
<Button title={<DangerousRaw>Create New</DangerousRaw>} onClick={createTenant} />
|
<Button title={<DangerousRaw>Create</DangerousRaw>} onClick={createTenant} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,8 +30,9 @@
|
||||||
"@silverhand/eslint-config": "2.0.1",
|
"@silverhand/eslint-config": "2.0.1",
|
||||||
"@silverhand/essentials": "2.4.0",
|
"@silverhand/essentials": "2.4.0",
|
||||||
"@silverhand/ts-config": "2.0.3",
|
"@silverhand/ts-config": "2.0.3",
|
||||||
|
"@types/expect-puppeteer": "^5.0.3",
|
||||||
"@types/jest": "^29.1.2",
|
"@types/jest": "^29.1.2",
|
||||||
"@types/jest-environment-puppeteer": "^5.0.2",
|
"@types/jest-environment-puppeteer": "^5.0.3",
|
||||||
"@types/node": "^18.11.18",
|
"@types/node": "^18.11.18",
|
||||||
"dotenv": "^16.0.0",
|
"dotenv": "^16.0.0",
|
||||||
"eslint": "^8.34.0",
|
"eslint": "^8.34.0",
|
||||||
|
|
|
@ -10,64 +10,78 @@ const appendPathname = (pathname: string, baseUrl: URL) =>
|
||||||
* NOTE: This test suite assumes test cases will run sequentially (which is Jest default).
|
* NOTE: This test suite assumes test cases will run sequentially (which is Jest default).
|
||||||
* Parallel execution will lead to errors.
|
* Parallel execution will lead to errors.
|
||||||
*/
|
*/
|
||||||
|
// Tip: See https://github.com/argos-ci/jest-puppeteer/blob/main/packages/expect-puppeteer/README.md
|
||||||
|
// for convenient expect methods
|
||||||
describe('smoke testing for cloud', () => {
|
describe('smoke testing for cloud', () => {
|
||||||
const consoleUsername = 'admin';
|
const consoleUsername = 'admin';
|
||||||
const consolePassword = generatePassword();
|
const consolePassword = generatePassword();
|
||||||
const logtoCloudUrl = new URL(logtoCloudUrlString);
|
const logtoCloudUrl = new URL(logtoCloudUrlString);
|
||||||
const adminTenantUrl = new URL(logtoConsoleUrl); // In dev mode, the console URL is actually for admin tenant
|
const adminTenantUrl = new URL(logtoConsoleUrl); // In dev mode, the console URL is actually for admin tenant
|
||||||
|
|
||||||
it('opens with app element and navigates to sign-in page', async () => {
|
it('can open with app element and navigate to register page', async () => {
|
||||||
const navigation = page.waitForNavigation({ waitUntil: 'networkidle0' });
|
|
||||||
await page.goto(logtoCloudUrl.href);
|
await page.goto(logtoCloudUrl.href);
|
||||||
await navigation;
|
await page.waitForNavigation({ waitUntil: 'networkidle0' });
|
||||||
|
|
||||||
await expect(page.waitForSelector('#app')).resolves.not.toBeNull();
|
await expect(page).toMatchElement('#app');
|
||||||
expect(page.url()).toBe(appendPathname('/register', adminTenantUrl).href);
|
expect(page.url()).toBe(appendPathname('/register', adminTenantUrl).href);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('registers the first admin account', async () => {
|
it('can register the first admin account', async () => {
|
||||||
const createAccountButton = await page.waitForSelector('button');
|
await expect(page).toClick('button', { text: 'Create account' });
|
||||||
expect(createAccountButton).not.toBeNull();
|
|
||||||
|
|
||||||
const usernameField = await page.waitForSelector('input[name=identifier]');
|
await expect(page).toFill('input[name=identifier]', consoleUsername);
|
||||||
const submitButton = await page.waitForSelector('button[name=submit]');
|
await expect(page).toClick('button[name=submit]');
|
||||||
|
|
||||||
await usernameField.type(consoleUsername);
|
|
||||||
|
|
||||||
const navigateToCreatePassword = page.waitForNavigation({ waitUntil: 'networkidle0' });
|
|
||||||
await submitButton.click();
|
|
||||||
await navigateToCreatePassword;
|
|
||||||
|
|
||||||
|
await page.waitForNavigation({ waitUntil: 'networkidle0' });
|
||||||
expect(page.url()).toBe(appendPathname('/register/password', adminTenantUrl).href);
|
expect(page.url()).toBe(appendPathname('/register/password', adminTenantUrl).href);
|
||||||
|
|
||||||
const passwordField = await page.waitForSelector('input[name=newPassword]');
|
await expect(page).toFillForm('form', {
|
||||||
const confirmPasswordField = await page.waitForSelector('input[name=confirmPassword]');
|
newPassword: consolePassword,
|
||||||
const saveButton = await page.waitForSelector('button[name=submit]');
|
confirmPassword: consolePassword,
|
||||||
await passwordField.type(consolePassword);
|
});
|
||||||
await confirmPasswordField.type(consolePassword);
|
await expect(page).toClick('button[name=submit]');
|
||||||
|
await page.waitForNavigation({ waitUntil: 'networkidle0' });
|
||||||
const navigateToCloud = page.waitForNavigation({ waitUntil: 'networkidle0' });
|
|
||||||
await saveButton.click();
|
|
||||||
await navigateToCloud;
|
|
||||||
|
|
||||||
expect(page.url()).toBe(logtoCloudUrl.href);
|
expect(page.url()).toBe(logtoCloudUrl.href);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shows a tenant-select page with two tenants', async () => {
|
it('shows a tenant-select page with two tenants', async () => {
|
||||||
const tenantsWrapper = await page.waitForSelector('div[class$=wrapper]');
|
const tenantsWrapper = await page.waitForSelector('div[class$=wrapper]');
|
||||||
const tenants = await tenantsWrapper.$$('a');
|
|
||||||
const hrefs = await Promise.all(
|
|
||||||
tenants.map(async (element) => {
|
|
||||||
const value = await element.getProperty('href');
|
|
||||||
|
|
||||||
return value.jsonValue();
|
await expect(tenantsWrapper).toMatchElement('a:nth-of-type(1)', { text: 'default' });
|
||||||
})
|
await expect(tenantsWrapper).toMatchElement('a:nth-of-type(2)', { text: 'admin' });
|
||||||
);
|
});
|
||||||
|
|
||||||
expect(
|
it('can create another tenant', async () => {
|
||||||
['default', 'admin'].every((tenantId) =>
|
await expect(page).toClick('button', { text: 'Create' });
|
||||||
hrefs.some((href) => String(href).endsWith('/' + tenantId))
|
|
||||||
)
|
await page.waitForTimeout(1000);
|
||||||
|
const tenants = await page.$$('div[class$=wrapper] > a');
|
||||||
|
expect(tenants.length).toBe(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can enter the tenant just created', async () => {
|
||||||
|
const button = await page.waitForSelector('div[class$=wrapper] > a:last-of-type');
|
||||||
|
const tenantId = await button.evaluate((element) => element.textContent);
|
||||||
|
|
||||||
|
await button.click();
|
||||||
|
|
||||||
|
// Wait for our beautiful logto to show up
|
||||||
|
await page.waitForSelector('div[class$=topbar] > svg[viewbox][class$=logo]');
|
||||||
|
expect(page.url()).toBe(new URL(`/${tenantId ?? ''}/onboard/welcome`, logtoCloudUrl).href);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can sign out of admin console', async () => {
|
||||||
|
await expect(page).toClick('div[class$=topbar] > div[class$=container]');
|
||||||
|
|
||||||
|
// Try awaiting for 500ms before clicking sign-out button
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
|
||||||
|
await expect(page).toClick(
|
||||||
|
'.ReactModalPortal div[class$=dropdownContainer] div[class$=dropdownItem]:last-child'
|
||||||
);
|
);
|
||||||
|
await page.waitForNavigation({ waitUntil: 'networkidle0' });
|
||||||
|
|
||||||
|
expect(page.url()).toBe(new URL('sign-in', logtoConsoleUrl).href);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,102 +1,87 @@
|
||||||
import { logtoConsoleUrl } from '#src/constants.js';
|
import path from 'path';
|
||||||
|
|
||||||
|
import { logtoConsoleUrl as logtoConsoleUrlString } from '#src/constants.js';
|
||||||
import { generatePassword } from '#src/utils.js';
|
import { generatePassword } from '#src/utils.js';
|
||||||
|
|
||||||
|
const appendPathname = (pathname: string, baseUrl: URL) =>
|
||||||
|
new URL(path.join(baseUrl.pathname, pathname), baseUrl);
|
||||||
|
|
||||||
|
const logtoConsoleUrl = new URL(logtoConsoleUrlString);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NOTE: This test suite assumes test cases will run sequentially (which is Jest default).
|
* NOTE: This test suite assumes test cases will run sequentially (which is Jest default).
|
||||||
* Parallel execution will lead to errors.
|
* Parallel execution will lead to errors.
|
||||||
*/
|
*/
|
||||||
|
// Tip: See https://github.com/argos-ci/jest-puppeteer/blob/main/packages/expect-puppeteer/README.md
|
||||||
|
// for convenient expect methods
|
||||||
describe('smoke testing', () => {
|
describe('smoke testing', () => {
|
||||||
const consoleUsername = 'admin';
|
const consoleUsername = 'admin';
|
||||||
const consolePassword = generatePassword();
|
const consolePassword = generatePassword();
|
||||||
|
|
||||||
it('opens with app element and navigates to welcome page', async () => {
|
it('can open with app element and navigate to welcome page', async () => {
|
||||||
const navigation = page.waitForNavigation({ waitUntil: 'networkidle0' });
|
await page.goto(logtoConsoleUrl.href);
|
||||||
await page.goto(logtoConsoleUrl);
|
await page.waitForNavigation({ waitUntil: 'networkidle0' });
|
||||||
await navigation;
|
|
||||||
|
|
||||||
await expect(page.waitForSelector('#app')).resolves.not.toBeNull();
|
await expect(page).toMatchElement('#app');
|
||||||
expect(page.url()).toBe(new URL('console/welcome', logtoConsoleUrl).href);
|
expect(page.url()).toBe(new URL('console/welcome', logtoConsoleUrl).href);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('registers a new admin account and automatically signs in', async () => {
|
it('can register a new admin account and automatically sign in', async () => {
|
||||||
const createAccountButton = await page.waitForSelector('button');
|
await expect(page).toClick('button', { text: 'Create account' });
|
||||||
expect(createAccountButton).not.toBeNull();
|
|
||||||
|
|
||||||
const navigateToRegister = page.waitForNavigation({ waitUntil: 'networkidle0' });
|
|
||||||
await createAccountButton.click();
|
|
||||||
await navigateToRegister;
|
|
||||||
|
|
||||||
|
await page.waitForNavigation({ waitUntil: 'networkidle0' });
|
||||||
expect(page.url()).toBe(new URL('register', logtoConsoleUrl).href);
|
expect(page.url()).toBe(new URL('register', logtoConsoleUrl).href);
|
||||||
|
|
||||||
const usernameField = await page.waitForSelector('input[name=identifier]');
|
await expect(page).toFill('input[name=identifier]', consoleUsername);
|
||||||
const submitButton = await page.waitForSelector('button[name=submit]');
|
await expect(page).toClick('button[name=submit]');
|
||||||
|
|
||||||
await usernameField.type(consoleUsername);
|
await page.waitForNavigation({ waitUntil: 'networkidle0' });
|
||||||
|
expect(page.url()).toBe(appendPathname('/register/password', logtoConsoleUrl).href);
|
||||||
|
|
||||||
const navigateToSignIn = page.waitForNavigation({ waitUntil: 'networkidle0' });
|
await expect(page).toFillForm('form', {
|
||||||
await submitButton.click();
|
newPassword: consolePassword,
|
||||||
await navigateToSignIn;
|
confirmPassword: consolePassword,
|
||||||
|
});
|
||||||
|
|
||||||
expect(page.url()).toBe(new URL('register/password', logtoConsoleUrl).href);
|
await expect(page).toClick('button[name=submit]');
|
||||||
|
await page.waitForNavigation({ waitUntil: 'networkidle0' });
|
||||||
const passwordField = await page.waitForSelector('input[name=newPassword]');
|
|
||||||
const confirmPasswordField = await page.waitForSelector('input[name=confirmPassword]');
|
|
||||||
const saveButton = await page.waitForSelector('button[name=submit]');
|
|
||||||
await passwordField.type(consolePassword);
|
|
||||||
await confirmPasswordField.type(consolePassword);
|
|
||||||
|
|
||||||
const navigateToGetStarted = page.waitForNavigation({ waitUntil: 'networkidle0' });
|
|
||||||
await saveButton.click();
|
|
||||||
await navigateToGetStarted;
|
|
||||||
|
|
||||||
expect(page.url()).toBe(new URL('console/get-started', logtoConsoleUrl).href);
|
expect(page.url()).toBe(new URL('console/get-started', logtoConsoleUrl).href);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('signs out of admin console', async () => {
|
it('can sign out of admin console', async () => {
|
||||||
const userElement = await page.waitForSelector('div[class$=topbar] > div[class$=container]');
|
await expect(page).toClick('div[class$=topbar] > div[class$=container]');
|
||||||
await userElement.click();
|
|
||||||
|
|
||||||
// Try awaiting for 500ms before clicking sign-out button
|
// Try awaiting for 500ms before clicking sign-out button
|
||||||
await page.waitForTimeout(500);
|
await page.waitForTimeout(500);
|
||||||
|
|
||||||
const signOutButton = await page.waitForSelector(
|
await expect(page).toClick(
|
||||||
'.ReactModalPortal div[class$=dropdownContainer] div[class$=dropdownItem]:last-child'
|
'.ReactModalPortal div[class$=dropdownContainer] div[class$=dropdownItem]:last-child'
|
||||||
);
|
);
|
||||||
const navigation = page.waitForNavigation({ waitUntil: 'networkidle0' });
|
await page.waitForNavigation({ waitUntil: 'networkidle0' });
|
||||||
await signOutButton.click();
|
|
||||||
await navigation;
|
|
||||||
|
|
||||||
expect(page.url()).toBe(new URL('sign-in', logtoConsoleUrl).href);
|
expect(page.url()).toBe(new URL('sign-in', logtoConsoleUrl).href);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('signs in to admin console', async () => {
|
it('can sign in to admin console', async () => {
|
||||||
const usernameField = await page.waitForSelector('input[name=identifier]');
|
await expect(page).toFillForm('form', {
|
||||||
const passwordField = await page.waitForSelector('input[name=password]');
|
identifier: consoleUsername,
|
||||||
const submitButton = await page.waitForSelector('button[name=submit]');
|
password: consolePassword,
|
||||||
|
});
|
||||||
await usernameField.type(consoleUsername);
|
await expect(page).toClick('button[name=submit]');
|
||||||
await passwordField.type(consolePassword);
|
await page.waitForNavigation({ waitUntil: 'networkidle0' });
|
||||||
|
|
||||||
const navigation = page.waitForNavigation({ waitUntil: 'networkidle0' });
|
|
||||||
await submitButton.click();
|
|
||||||
await navigation;
|
|
||||||
|
|
||||||
expect(page.url()).toBe(new URL('console/get-started', logtoConsoleUrl).href);
|
expect(page.url()).toBe(new URL('console/get-started', logtoConsoleUrl).href);
|
||||||
|
|
||||||
const userElement = await page.waitForSelector('div[class$=topbar] > div:last-child');
|
await expect(page).toClick('div[class$=topbar] > div:last-child');
|
||||||
await userElement.click();
|
|
||||||
|
|
||||||
const userMenu = await page.waitForSelector('.ReactModalPortal div[class$=dropdownContainer]');
|
const userMenu = await page.waitForSelector('.ReactModalPortal div[class$=dropdownContainer]');
|
||||||
const usernameString = await userMenu.$eval(
|
await expect(userMenu).toMatchElement('div[class$=nameWrapper] > div[class$=name]', {
|
||||||
'div[class$=nameWrapper] > div[class$=name]',
|
text: consoleUsername,
|
||||||
(element) => element.textContent
|
});
|
||||||
);
|
|
||||||
expect(usernameString).toBe(consoleUsername);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders SVG correctly with viewbox property', async () => {
|
it('renders SVG correctly with viewbox property', async () => {
|
||||||
const logoSvg = await page.waitForSelector('div[class$=topbar] > svg[viewbox]');
|
await page.waitForSelector('div[class$=topbar] > svg[viewbox][class$=logo]');
|
||||||
|
|
||||||
expect(logoSvg).not.toBeNull();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,7 +2,7 @@ const welcome = {
|
||||||
title: 'Welcome to Admin Console',
|
title: 'Welcome to Admin Console',
|
||||||
description:
|
description:
|
||||||
'Admin console is a web app to manage Logto without coding requirements. Let’s first create an account. With this account, you can manage Logto by yourself or on behalf of your company.',
|
'Admin console is a web app to manage Logto without coding requirements. Let’s first create an account. With this account, you can manage Logto by yourself or on behalf of your company.',
|
||||||
create_account: 'Create Account',
|
create_account: 'Create account',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default welcome;
|
export default welcome;
|
||||||
|
|
|
@ -551,8 +551,9 @@ importers:
|
||||||
'@silverhand/eslint-config': 2.0.1
|
'@silverhand/eslint-config': 2.0.1
|
||||||
'@silverhand/essentials': 2.4.0
|
'@silverhand/essentials': 2.4.0
|
||||||
'@silverhand/ts-config': 2.0.3
|
'@silverhand/ts-config': 2.0.3
|
||||||
|
'@types/expect-puppeteer': ^5.0.3
|
||||||
'@types/jest': ^29.1.2
|
'@types/jest': ^29.1.2
|
||||||
'@types/jest-environment-puppeteer': ^5.0.2
|
'@types/jest-environment-puppeteer': ^5.0.3
|
||||||
'@types/node': ^18.11.18
|
'@types/node': ^18.11.18
|
||||||
'@withtyped/server': ^0.8.0
|
'@withtyped/server': ^0.8.0
|
||||||
dotenv: ^16.0.0
|
dotenv: ^16.0.0
|
||||||
|
@ -579,8 +580,9 @@ importers:
|
||||||
'@silverhand/eslint-config': 2.0.1_kjzxg5porcw5dx54sezsklj5cy
|
'@silverhand/eslint-config': 2.0.1_kjzxg5porcw5dx54sezsklj5cy
|
||||||
'@silverhand/essentials': 2.4.0
|
'@silverhand/essentials': 2.4.0
|
||||||
'@silverhand/ts-config': 2.0.3_typescript@4.9.4
|
'@silverhand/ts-config': 2.0.3_typescript@4.9.4
|
||||||
|
'@types/expect-puppeteer': 5.0.3
|
||||||
'@types/jest': 29.1.2
|
'@types/jest': 29.1.2
|
||||||
'@types/jest-environment-puppeteer': 5.0.2
|
'@types/jest-environment-puppeteer': 5.0.3
|
||||||
'@types/node': 18.11.18
|
'@types/node': 18.11.18
|
||||||
dotenv: 16.0.0
|
dotenv: 16.0.0
|
||||||
eslint: 8.34.0
|
eslint: 8.34.0
|
||||||
|
@ -4135,6 +4137,13 @@ packages:
|
||||||
'@types/node': 18.11.18
|
'@types/node': 18.11.18
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@types/expect-puppeteer/5.0.3:
|
||||||
|
resolution: {integrity: sha512-NIqATm95VmFbc2s9v1L3yj9ZS9/rCrtptSgBsvW8mcw2KFpLFQqXPyEbo0Vju1eiBieI38jRGWgpbVuUKfQVoQ==}
|
||||||
|
dependencies:
|
||||||
|
'@types/jest': 29.1.2
|
||||||
|
'@types/puppeteer': 5.4.6
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@types/express-serve-static-core/4.17.26:
|
/@types/express-serve-static-core/4.17.26:
|
||||||
resolution: {integrity: sha512-zeu3tpouA043RHxW0gzRxwCHchMgftE8GArRsvYT0ByDMbn19olQHx5jLue0LxWY6iYtXb7rXmuVtSkhy9YZvQ==}
|
resolution: {integrity: sha512-zeu3tpouA043RHxW0gzRxwCHchMgftE8GArRsvYT0ByDMbn19olQHx5jLue0LxWY6iYtXb7rXmuVtSkhy9YZvQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -4224,8 +4233,8 @@ packages:
|
||||||
'@types/istanbul-lib-report': 3.0.0
|
'@types/istanbul-lib-report': 3.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@types/jest-environment-puppeteer/5.0.2:
|
/@types/jest-environment-puppeteer/5.0.3:
|
||||||
resolution: {integrity: sha512-YCdegQnDou6aIK8wqygDDctHgJZtlXd03fI9Bgbqkdu66EFKnImmt7auiR9OkxkSSiqS9smn0joX2pGpVs7ErA==}
|
resolution: {integrity: sha512-vWGfeb+0TOPZy7+VscKURWzE5lzYjclSWLxtjVpDAYcjUv8arAS1av06xK3mpgeNCDVx7XvavD8Elq1a4w9wIA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jest/types': 27.5.1
|
'@jest/types': 27.5.1
|
||||||
'@types/puppeteer': 5.4.6
|
'@types/puppeteer': 5.4.6
|
||||||
|
@ -4532,10 +4541,6 @@ packages:
|
||||||
resolution: {integrity: sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==}
|
resolution: {integrity: sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@types/yargs-parser/20.2.1:
|
|
||||||
resolution: {integrity: sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==}
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/@types/yargs-parser/21.0.0:
|
/@types/yargs-parser/21.0.0:
|
||||||
resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==}
|
resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==}
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -4543,7 +4548,7 @@ packages:
|
||||||
/@types/yargs/16.0.4:
|
/@types/yargs/16.0.4:
|
||||||
resolution: {integrity: sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==}
|
resolution: {integrity: sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/yargs-parser': 20.2.1
|
'@types/yargs-parser': 21.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@types/yargs/17.0.13:
|
/@types/yargs/17.0.13:
|
||||||
|
@ -9634,7 +9639,7 @@ packages:
|
||||||
'@jest/types': 27.5.1
|
'@jest/types': 27.5.1
|
||||||
'@types/node': 18.11.18
|
'@types/node': 18.11.18
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
ci-info: 3.5.0
|
ci-info: 3.8.0
|
||||||
graceful-fs: 4.2.10
|
graceful-fs: 4.2.10
|
||||||
picomatch: 2.3.1
|
picomatch: 2.3.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
Loading…
Reference in a new issue