1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-09-05 17:53:12 +02:00

refactor: convert auth tests from Cypress to Jest (#864)

* refactor: replace data-test with data-testid

* refactor: add Jest tests for auth pages

* refactor: remove Cypress tests for auth pages

* refactor: remove questionable snapshots

* refactor: share test server setup/teardown

* refactor: restore auth page flex layout

* refactor: use toBeInTheDocument

* refactor: change recent data-test attrs to data-testid
This commit is contained in:
olav 2022-04-08 13:13:45 +02:00 committed by GitHub
parent 1132a79f6d
commit 49b8e7329e
51 changed files with 666 additions and 390 deletions

View File

@ -1,24 +0,0 @@
name: e2e:auth
# https://docs.github.com/en/actions/reference/events-that-trigger-workflows
on: [deployment_status]
jobs:
e2e:
# only runs this job on successful deploy
if: github.event_name == 'deployment_status' && github.event.deployment_status.state == 'success'
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: |
echo "$GITHUB_CONTEXT"
- name: Checkout
uses: actions/checkout@v3
- name: Run Cypress
uses: cypress-io/github-action@v2
with:
config: baseUrl=${{ github.event.deployment_status.target_url }}
record: true
spec: cypress/integration/auth/auth.spec.ts
env:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}

View File

@ -1,201 +0,0 @@
/// <reference types="cypress" />
export {};
describe('auth', () => {
it('renders the password login', () => {
cy.intercept('GET', '/api/admin/**', {
statusCode: 401,
body: {
defaultHidden: false,
message: 'You must sign in in order to use Unleash',
options: [],
path: '/auth/simple/login',
type: 'password',
},
});
cy.visit('/');
cy.intercept('POST', '/auth/simple/login', req => {
expect(req.body.username).to.equal('admin');
expect(req.body.password).to.equal('unleash4all');
}).as('passwordLogin');
cy.wait(1000);
cy.get('[data-test="LOGIN_EMAIL_ID"]').type('admin');
cy.get('[data-test="LOGIN_PASSWORD_ID"]').type('unleash4all');
cy.get("[data-test='LOGIN_BUTTON']").click();
});
it('renders does not render password login if defaultHidden is true', () => {
cy.intercept('GET', '/api/admin/**', {
statusCode: 401,
body: {
defaultHidden: true,
message: 'You must sign in in order to use Unleash',
options: [],
path: '/auth/simple/login',
type: 'password',
},
});
cy.visit('/');
cy.get('[data-test="LOGIN_EMAIL_ID"]').should('not.exist');
cy.get('[data-test="LOGIN_PASSWORD_ID"]').should('not.exist');
});
it('renders google auth when options are specified', () => {
const ssoPath = '/auth/google/login';
cy.intercept('GET', '/api/admin/**', {
statusCode: 401,
body: {
defaultHidden: true,
message: 'You must sign in in order to use Unleash',
options: [
{
type: 'google',
message: 'Sign in with Google',
path: ssoPath,
},
],
path: '/auth/simple/login',
type: 'password',
},
});
cy.visit('/');
cy.get('[data-test="LOGIN_EMAIL_ID"]').should('not.exist');
cy.get('[data-test="LOGIN_PASSWORD_ID"]').should('not.exist');
cy.get('[data-test="SSO_LOGIN_BUTTON-google"]')
.should('exist')
.should('have.attr', 'href', ssoPath);
});
it('renders oidc auth when options are specified', () => {
const ssoPath = '/auth/oidc/login';
cy.intercept('GET', '/api/admin/**', {
statusCode: 401,
body: {
defaultHidden: true,
message: 'You must sign in in order to use Unleash',
options: [
{
type: 'oidc',
message: 'Sign in with OpenId Connect',
path: ssoPath,
},
],
path: '/auth/simple/login',
type: 'password',
},
});
cy.visit('/');
cy.get('[data-test="LOGIN_EMAIL_ID"]').should('not.exist');
cy.get('[data-test="LOGIN_PASSWORD_ID"]').should('not.exist');
cy.get('[data-test="SSO_LOGIN_BUTTON-oidc"]')
.should('exist')
.should('have.attr', 'href', ssoPath);
});
it('renders saml auth when options are specified', () => {
const ssoPath = '/auth/saml/login';
cy.intercept('GET', '/api/admin/**', {
statusCode: 401,
body: {
defaultHidden: true,
message: 'You must sign in in order to use Unleash',
options: [
{
type: 'saml',
message: 'Sign in with SAML 2.0',
path: ssoPath,
},
],
path: '/auth/simple/login',
type: 'password',
},
});
cy.visit('/');
cy.get('[data-test="LOGIN_EMAIL_ID"]').should('not.exist');
cy.get('[data-test="LOGIN_PASSWORD_ID"]').should('not.exist');
cy.get('[data-test="SSO_LOGIN_BUTTON-saml"]')
.should('exist')
.should('have.attr', 'href', ssoPath);
});
it('can visit forgot password when password auth is enabled', () => {
cy.intercept('GET', '/api/admin/**', {
statusCode: 401,
body: {
defaultHidden: false,
message: 'You must sign in in order to use Unleash',
options: [],
path: '/auth/simple/login',
type: 'password',
},
});
cy.visit('/forgotten-password');
cy.get('[data-test="FORGOTTEN_PASSWORD_FIELD"').type('me@myemail.com');
});
it('renders demo auth correctly', () => {
const email = 'hello@hello.com';
cy.intercept('GET', '/api/admin/**', {
statusCode: 401,
body: {
defaultHidden: false,
message: 'You must sign in in order to use Unleash',
options: [],
path: '/auth/demo/login',
type: 'demo',
},
});
cy.intercept('POST', '/auth/demo/login', req => {
expect(req.body.email).to.equal(email);
}).as('passwordLogin');
cy.visit('/');
cy.get('[data-test="LOGIN_EMAIL_ID"]').type(email);
cy.get("[data-test='LOGIN_BUTTON']").click();
});
it('renders email auth correctly', () => {
const email = 'hello@hello.com';
cy.intercept('GET', '/api/admin/**', {
statusCode: 401,
body: {
defaultHidden: false,
message: 'You must sign in in order to use Unleash',
options: [],
path: '/auth/unsecure/login',
type: 'unsecure',
},
});
cy.intercept('POST', '/auth/unsecure/login', req => {
expect(req.body.email).to.equal(email);
}).as('passwordLogin');
cy.visit('/');
cy.get('[data-test="LOGIN_EMAIL_ID"]').type(email);
cy.get("[data-test='LOGIN_BUTTON']").click();
});
it('renders invalid token page when token is invalid', () => {
cy.visit('/new-user?token=hellotokenworld');
cy.get('[data-test="INVALID_TOKEN_BUTTON"]').should('be.visible');
});
});

View File

@ -42,61 +42,61 @@ describe('feature', () => {
beforeEach(() => {
cy.visit('/');
cy.get('[data-test="LOGIN_EMAIL_ID"]').type(AUTH_USER);
cy.get('[data-testid="LOGIN_EMAIL_ID"]').type(AUTH_USER);
if (AUTH_PASSWORD) {
cy.get('[data-test="LOGIN_PASSWORD_ID"]').type(AUTH_PASSWORD);
cy.get('[data-testid="LOGIN_PASSWORD_ID"]').type(AUTH_PASSWORD);
}
cy.get("[data-test='LOGIN_BUTTON']").click();
cy.get("[data-testid='LOGIN_BUTTON']").click();
// Wait for the login redirect to complete.
cy.get('[data-test=HEADER_USER_AVATAR');
cy.get('[data-testid=HEADER_USER_AVATAR');
});
it('can create a feature toggle', () => {
if (document.querySelector("[data-test='CLOSE_SPLASH']")) {
cy.get("[data-test='CLOSE_SPLASH']").click();
if (document.querySelector("[data-testid='CLOSE_SPLASH']")) {
cy.get("[data-testid='CLOSE_SPLASH']").click();
}
cy.get('[data-test=NAVIGATE_TO_CREATE_FEATURE').click();
cy.get('[data-testid=NAVIGATE_TO_CREATE_FEATURE').click();
cy.intercept('POST', '/api/admin/projects/default/features').as(
'createFeature'
);
cy.get("[data-test='CF_NAME_ID'").type(featureToggleName);
cy.get("[data-test='CF_DESC_ID'").type('hello-world');
cy.get("[data-test='CF_CREATE_BTN_ID']").click();
cy.get("[data-testid='CF_NAME_ID'").type(featureToggleName);
cy.get("[data-testid='CF_DESC_ID'").type('hello-world');
cy.get("[data-testid='CF_CREATE_BTN_ID']").click();
cy.wait('@createFeature');
cy.url().should('include', featureToggleName);
});
it('gives an error if a toggle exists with the same name', () => {
cy.get('[data-test=NAVIGATE_TO_CREATE_FEATURE').click();
cy.get('[data-testid=NAVIGATE_TO_CREATE_FEATURE').click();
cy.intercept('POST', '/api/admin/projects/default/features').as(
'createFeature'
);
cy.get("[data-test='CF_NAME_ID'").type(featureToggleName);
cy.get("[data-test='CF_DESC_ID'").type('hello-world');
cy.get("[data-test='CF_CREATE_BTN_ID']").click();
cy.get("[data-test='INPUT_ERROR_TEXT']").contains(
cy.get("[data-testid='CF_NAME_ID'").type(featureToggleName);
cy.get("[data-testid='CF_DESC_ID'").type('hello-world');
cy.get("[data-testid='CF_CREATE_BTN_ID']").click();
cy.get("[data-testid='INPUT_ERROR_TEXT']").contains(
'A feature with this name already exists'
);
});
it('gives an error if a toggle name is url unsafe', () => {
cy.get('[data-test=NAVIGATE_TO_CREATE_FEATURE').click();
cy.get('[data-testid=NAVIGATE_TO_CREATE_FEATURE').click();
cy.intercept('POST', '/api/admin/projects/default/features').as(
'createFeature'
);
cy.get("[data-test='CF_NAME_ID'").type('featureToggleUnsafe####$#//');
cy.get("[data-test='CF_DESC_ID'").type('hello-world');
cy.get("[data-test='CF_CREATE_BTN_ID']").click();
cy.get("[data-test='INPUT_ERROR_TEXT']").contains(
cy.get("[data-testid='CF_NAME_ID'").type('featureToggleUnsafe####$#//');
cy.get("[data-testid='CF_DESC_ID'").type('hello-world');
cy.get("[data-testid='CF_CREATE_BTN_ID']").click();
cy.get("[data-testid='INPUT_ERROR_TEXT']").contains(
`"name" must be URL friendly`
);
});
@ -107,16 +107,16 @@ describe('feature', () => {
);
cy.wait(1000);
cy.get('[data-test=ROLLOUT_SLIDER_ID')
cy.get('[data-testid=ROLLOUT_SLIDER_ID')
.click()
.type('{leftarrow}'.repeat(20));
if (ENTERPRISE) {
cy.get('[data-test=ADD_CONSTRAINT_ID]').click();
cy.get('[data-test=CONSTRAINT_AUTOCOMPLETE_ID]')
cy.get('[data-testid=ADD_CONSTRAINT_ID]').click();
cy.get('[data-testid=CONSTRAINT_AUTOCOMPLETE_ID]')
.type('{downArrow}'.repeat(1))
.type('{enter}');
cy.get('[data-test=DIALOGUE_CONFIRM_ID]').click();
cy.get('[data-testid=DIALOGUE_CONFIRM_ID]').click();
}
cy.intercept(
@ -140,7 +140,7 @@ describe('feature', () => {
}
).as('addStrategyToFeature');
cy.get(`[data-test=STRATEGY_FORM_SUBMIT_ID]`).first().click();
cy.get(`[data-testid=STRATEGY_FORM_SUBMIT_ID]`).first().click();
cy.wait('@addStrategyToFeature');
});
@ -150,18 +150,18 @@ describe('feature', () => {
);
cy.wait(1000);
cy.get('[data-test=ROLLOUT_SLIDER_ID')
cy.get('[data-testid=ROLLOUT_SLIDER_ID')
.click()
.type('{rightArrow}'.repeat(10));
cy.get('[data-test=FLEXIBLE_STRATEGY_STICKINESS_ID]')
cy.get('[data-testid=FLEXIBLE_STRATEGY_STICKINESS_ID]')
.first()
.click()
.get('[data-test=SELECT_ITEM_ID-sessionId')
.get('[data-testid=SELECT_ITEM_ID-sessionId')
.first()
.click();
cy.get('[data-test=FLEXIBLE_STRATEGY_GROUP_ID]')
cy.get('[data-testid=FLEXIBLE_STRATEGY_GROUP_ID]')
.first()
.clear()
.type('new-group-id');
@ -186,7 +186,7 @@ describe('feature', () => {
}
).as('updateStrategy');
cy.get(`[data-test=STRATEGY_FORM_SUBMIT_ID]`).first().click();
cy.get(`[data-testid=STRATEGY_FORM_SUBMIT_ID]`).first().click();
cy.wait('@updateStrategy');
});
@ -203,9 +203,11 @@ describe('feature', () => {
}
).as('deleteStrategy');
cy.get('[data-test=FEATURE_ENVIRONMENT_ACCORDION_development]').click();
cy.get('[data-test=STRATEGY_FORM_REMOVE_ID]').click();
cy.get('[data-test=DIALOGUE_CONFIRM_ID]').click();
cy.get(
'[data-testid=FEATURE_ENVIRONMENT_ACCORDION_development]'
).click();
cy.get('[data-testid=STRATEGY_FORM_REMOVE_ID]').click();
cy.get('[data-testid=DIALOGUE_CONFIRM_ID]').click();
cy.wait('@deleteStrategy');
});
@ -215,19 +217,19 @@ describe('feature', () => {
);
if (ENTERPRISE) {
cy.get('[data-test=ADD_CONSTRAINT_ID]').click();
cy.get('[data-test=CONSTRAINT_AUTOCOMPLETE_ID]')
cy.get('[data-testid=ADD_CONSTRAINT_ID]').click();
cy.get('[data-testid=CONSTRAINT_AUTOCOMPLETE_ID]')
.type('{downArrow}'.repeat(1))
.type('{enter}');
cy.get('[data-test=DIALOGUE_CONFIRM_ID]').click();
cy.get('[data-testid=DIALOGUE_CONFIRM_ID]').click();
}
cy.get('[data-test=STRATEGY_INPUT_LIST]')
cy.get('[data-testid=STRATEGY_INPUT_LIST]')
.type('user1')
.type('{enter}')
.type('user2')
.type('{enter}');
cy.get('[data-test=ADD_TO_STRATEGY_INPUT_LIST]').click();
cy.get('[data-testid=ADD_TO_STRATEGY_INPUT_LIST]').click();
cy.intercept(
'POST',
@ -249,7 +251,7 @@ describe('feature', () => {
}
).as('addStrategyToFeature');
cy.get(`[data-test=STRATEGY_FORM_SUBMIT_ID]`).first().click();
cy.get(`[data-testid=STRATEGY_FORM_SUBMIT_ID]`).first().click();
cy.wait('@addStrategyToFeature');
});
@ -278,32 +280,32 @@ describe('feature', () => {
}
).as('variantCreation');
cy.get('[data-test=ADD_VARIANT_BUTTON]').click();
cy.get('[data-testid=ADD_VARIANT_BUTTON]').click();
cy.wait(1000);
cy.get('[data-test=VARIANT_NAME_INPUT]').type(variantName);
cy.get('[data-test=DIALOGUE_CONFIRM_ID]').click();
cy.get('[data-testid=VARIANT_NAME_INPUT]').type(variantName);
cy.get('[data-testid=DIALOGUE_CONFIRM_ID]').click();
cy.wait('@variantCreation');
cy.get('[data-test=ADD_VARIANT_BUTTON]').click();
cy.get('[data-testid=ADD_VARIANT_BUTTON]').click();
cy.wait(1000);
cy.get('[data-test=VARIANT_NAME_INPUT]').type(secondVariantName);
cy.get('[data-test=DIALOGUE_CONFIRM_ID]').click();
cy.get('[data-testid=VARIANT_NAME_INPUT]').type(secondVariantName);
cy.get('[data-testid=DIALOGUE_CONFIRM_ID]').click();
cy.wait('@variantCreation');
});
it('can set weight to fixed value for one of the variants', () => {
cy.visit(`/projects/default/features/${featureToggleName}/variants`);
cy.get('[data-test=VARIANT_EDIT_BUTTON]').first().click();
cy.get('[data-testid=VARIANT_EDIT_BUTTON]').first().click();
cy.wait(1000);
cy.get('[data-test=VARIANT_NAME_INPUT]')
cy.get('[data-testid=VARIANT_NAME_INPUT]')
.children()
.find('input')
.should('have.attr', 'disabled');
cy.get('[data-test=VARIANT_WEIGHT_TYPE]')
cy.get('[data-testid=VARIANT_WEIGHT_TYPE]')
.children()
.find('input')
.check();
cy.get('[data-test=VARIANT_WEIGHT_INPUT]').clear().type('15');
cy.get('[data-testid=VARIANT_WEIGHT_INPUT]').clear().type('15');
cy.intercept(
'PATCH',
@ -321,9 +323,9 @@ describe('feature', () => {
}
).as('variantUpdate');
cy.get('[data-test=DIALOGUE_CONFIRM_ID]').click();
cy.get('[data-testid=DIALOGUE_CONFIRM_ID]').click();
cy.wait('@variantUpdate');
cy.get('[data-test=VARIANT_WEIGHT]')
cy.get('[data-testid=VARIANT_WEIGHT]')
.first()
.should('have.text', '15 %');
});
@ -332,10 +334,10 @@ describe('feature', () => {
const variantName = 'to-be-deleted';
cy.visit(`/projects/default/features/${featureToggleName}/variants`);
cy.get('[data-test=ADD_VARIANT_BUTTON]').click();
cy.get('[data-testid=ADD_VARIANT_BUTTON]').click();
cy.wait(1000);
cy.get('[data-test=VARIANT_NAME_INPUT]').type(variantName);
cy.get('[data-test=DIALOGUE_CONFIRM_ID]').click();
cy.get('[data-testid=VARIANT_NAME_INPUT]').type(variantName);
cy.get('[data-testid=DIALOGUE_CONFIRM_ID]').click();
cy.intercept(
'PATCH',
@ -348,8 +350,8 @@ describe('feature', () => {
}
).as('delete');
cy.get(`[data-test=VARIANT_DELETE_BUTTON_${variantName}]`).click();
cy.get('[data-test=DIALOGUE_CONFIRM_ID]').click();
cy.get(`[data-testid=VARIANT_DELETE_BUTTON_${variantName}]`).click();
cy.get('[data-testid=DIALOGUE_CONFIRM_ID]').click();
cy.wait('@delete');
});
});

View File

@ -25,52 +25,52 @@ describe('segments', () => {
cy.session(AUTH_USER, () => {
cy.visit('/');
cy.wait(1000);
cy.get("[data-test='LOGIN_EMAIL_ID']").type(AUTH_USER);
cy.get("[data-testid='LOGIN_EMAIL_ID']").type(AUTH_USER);
if (AUTH_PASSWORD) {
cy.get("[data-test='LOGIN_PASSWORD_ID']").type(AUTH_PASSWORD);
cy.get("[data-testid='LOGIN_PASSWORD_ID']").type(AUTH_PASSWORD);
}
cy.get("[data-test='LOGIN_BUTTON']").click();
cy.get("[data-testid='LOGIN_BUTTON']").click();
// Wait for the login redirect to complete.
cy.get("[data-test='HEADER_USER_AVATAR']");
cy.get("[data-testid='HEADER_USER_AVATAR']");
});
cy.visit('/segments');
});
it('can create a segment', () => {
if (document.querySelector("[data-test='CLOSE_SPLASH']")) {
cy.get("[data-test='CLOSE_SPLASH']").click();
if (document.querySelector("[data-testid='CLOSE_SPLASH']")) {
cy.get("[data-testid='CLOSE_SPLASH']").click();
}
cy.get("[data-test='NAVIGATE_TO_CREATE_SEGMENT']").click();
cy.get("[data-testid='NAVIGATE_TO_CREATE_SEGMENT']").click();
cy.intercept('POST', '/api/admin/segments').as('createSegment');
cy.get("[data-test='SEGMENT_NAME_ID']").type(segmentName);
cy.get("[data-test='SEGMENT_DESC_ID']").type('hello-world');
cy.get("[data-test='SEGMENT_NEXT_BTN_ID']").click();
cy.get("[data-test='SEGMENT_CREATE_BTN_ID']").click();
cy.get("[data-testid='SEGMENT_NAME_ID']").type(segmentName);
cy.get("[data-testid='SEGMENT_DESC_ID']").type('hello-world');
cy.get("[data-testid='SEGMENT_NEXT_BTN_ID']").click();
cy.get("[data-testid='SEGMENT_CREATE_BTN_ID']").click();
cy.wait('@createSegment');
cy.contains(segmentName);
});
it('gives an error if a segment exists with the same name', () => {
cy.get("[data-test='NAVIGATE_TO_CREATE_SEGMENT']").click();
cy.get("[data-testid='NAVIGATE_TO_CREATE_SEGMENT']").click();
cy.get("[data-test='SEGMENT_NAME_ID']").type(segmentName);
cy.get("[data-test='SEGMENT_NEXT_BTN_ID']").should('be.disabled');
cy.get("[data-test='INPUT_ERROR_TEXT']").contains(
cy.get("[data-testid='SEGMENT_NAME_ID']").type(segmentName);
cy.get("[data-testid='SEGMENT_NEXT_BTN_ID']").should('be.disabled');
cy.get("[data-testid='INPUT_ERROR_TEXT']").contains(
'Segment name already exists'
);
});
it('can delete a segment', () => {
cy.get(`[data-test='SEGMENT_DELETE_BTN_ID_${segmentName}']`).click();
cy.get(`[data-testid='SEGMENT_DELETE_BTN_ID_${segmentName}']`).click();
cy.get("[data-test='SEGMENT_DIALOG_NAME_ID']").type(segmentName);
cy.get("[data-test='DIALOGUE_CONFIRM_ID'").click();
cy.get("[data-testid='SEGMENT_DIALOG_NAME_ID']").type(segmentName);
cy.get("[data-testid='DIALOGUE_CONFIRM_ID'").click();
cy.contains(segmentName).should('not.exist');
});

View File

@ -68,6 +68,7 @@
"http-proxy-middleware": "2.0.4",
"immer": "^9.0.12",
"lodash.clonedeep": "4.5.0",
"msw": "^0.39.2",
"prettier": "2.6.1",
"prop-types": "15.8.1",
"react": "17.0.2",

View File

@ -247,7 +247,7 @@ export const ApiTokenList = () => {
'/admin/api/create-token'
)
}
data-test={CREATE_API_TOKEN_BUTTON}
data-testid={CREATE_API_TOKEN_BUTTON}
>
New API token
</Button>

View File

@ -81,7 +81,7 @@ const Dialogue: React.FC<IDialogue> = ({
onClick={handleClick}
autoFocus={!formId}
disabled={disabledPrimaryButton}
data-test={DIALOGUE_CONFIRM_ID}
data-testid={DIALOGUE_CONFIRM_ID}
type={formId ? 'submit' : 'button'}
>
{primaryButtonText || "Yes, I'm sure"}

View File

@ -52,7 +52,7 @@ const GeneralSelect: React.FC<ISelectMenuProps> = ({
key={option.key}
value={option.key}
title={option.title || ''}
data-test={`${SELECT_ITEM_ID}-${option.label}`}
data-testid={`${SELECT_ITEM_ID}-${option.label}`}
disabled={option.disabled}
>
{option.label}

View File

@ -48,7 +48,7 @@ const Input = ({
onChange={onChange}
FormHelperTextProps={{
// @ts-expect-error
['data-test']: INPUT_ERROR_TEXT,
['data-testid']: INPUT_ERROR_TEXT,
classes: {
root: styles.helperText,
},

View File

@ -29,7 +29,7 @@ export const SidebarModal = ({
aria-label={label}
BackdropComponent={Backdrop}
BackdropProps={{ timeout: TRANSITION_DURATION }}
data-test={SIDEBAR_MODAL_ID}
data-testid={SIDEBAR_MODAL_ID}
>
<Fade timeout={TRANSITION_DURATION} in={open}>
<div className={styles.modal}>{children}</div>

View File

@ -80,7 +80,7 @@ export const FormButtons = ({
}) => (
<div>
<Button
data-test={primaryButtonTestId}
data-testid={primaryButtonTestId}
type="submit"
color="primary"
variant="contained"

View File

@ -41,7 +41,7 @@ const SelectMenu: React.FC<ISelectMenuProps> = ({
key={option.key}
value={option.key}
title={option.title || ''}
data-test={`${SELECT_ITEM_ID}-${option.label}`}
data-testid={`${SELECT_ITEM_ID}-${option.label}`}
>
{option.label}
</MenuItem>

View File

@ -105,7 +105,7 @@ const CreateFeature = () => {
name="Feature"
permission={CREATE_FEATURE}
projectId={project}
data-test={CF_CREATE_BTN_ID}
data-testid={CF_CREATE_BTN_ID}
/>
</FeatureForm>
</FormTemplate>

View File

@ -32,7 +32,7 @@ export const CreateFeatureButton = ({
<IconButton
component={Link}
to={createFeature.path}
data-test={NAVIGATE_TO_CREATE_FEATURE}
data-testid={NAVIGATE_TO_CREATE_FEATURE}
disabled={!createFeature.access}
>
<Add titleAccess="New" />
@ -45,7 +45,7 @@ export const CreateFeatureButton = ({
color="primary"
variant="contained"
component={Link}
data-test={NAVIGATE_TO_CREATE_FEATURE}
data-testid={NAVIGATE_TO_CREATE_FEATURE}
disabled={!createFeature.access}
className={classnames({ skeleton: loading })}
>

View File

@ -84,7 +84,7 @@ const FeatureForm: React.FC<IFeatureToggleForm> = ({
onFocus={() => clearErrors()}
value={name}
onChange={e => setName(trim(e.target.value))}
data-test={CF_NAME_ID}
data-testid={CF_NAME_ID}
onBlur={validateToggleName}
/>
<p className={styles.inputDescription}>
@ -97,7 +97,7 @@ const FeatureForm: React.FC<IFeatureToggleForm> = ({
label={'Toggle type'}
id="feature-type-select"
editable
data-test={CF_TYPE_ID}
data-testid={CF_TYPE_ID}
IconComponent={KeyboardArrowDownOutlined}
className={styles.selectInput}
/>
@ -137,7 +137,7 @@ const FeatureForm: React.FC<IFeatureToggleForm> = ({
label="Description"
placeholder="A short description of the feature toggle"
value={description}
data-test={CF_DESC_ID}
data-testid={CF_DESC_ID}
onChange={e => setDescription(e.target.value)}
/>
<FormControl className={styles.input}>

View File

@ -135,7 +135,7 @@ export const FeatureStrategyForm = ({
color="primary"
type="submit"
disabled={loading || !hasValidConstraints}
data-test={STRATEGY_FORM_SUBMIT_ID}
data-testid={STRATEGY_FORM_SUBMIT_ID}
>
Save strategy
</PermissionButton>

View File

@ -68,7 +68,7 @@ export const FeatureStrategyRemove = ({
environmentId={environmentId}
disabled={disabled}
permission={DELETE_FEATURE_STRATEGY}
data-test={STRATEGY_FORM_REMOVE_ID}
data-testid={STRATEGY_FORM_REMOVE_ID}
type="button"
>
<Delete titleAccess="Delete strategy" />
@ -81,7 +81,7 @@ export const FeatureStrategyRemove = ({
environmentId={environmentId}
disabled={disabled}
permission={DELETE_FEATURE_STRATEGY}
data-test={STRATEGY_FORM_REMOVE_ID}
data-testid={STRATEGY_FORM_REMOVE_ID}
color="secondary"
variant="text"
type="button"

View File

@ -89,7 +89,7 @@ const FeatureOverviewEnvironment = ({
<div className={styles.featureOverviewEnvironment}>
<Accordion
style={{ boxShadow: 'none' }}
data-test={`${FEATURE_ENVIRONMENT_ACCORDION}_${env.name}`}
data-testid={`${FEATURE_ENVIRONMENT_ACCORDION}_${env.name}`}
>
<AccordionSummary
className={styles.accordionHeader}

View File

@ -277,7 +277,7 @@ export const AddVariant = ({
type="name"
disabled={editing}
onChange={setVariantValue}
data-test={'VARIANT_NAME_INPUT'}
data-testid={'VARIANT_NAME_INPUT'}
/>
<br />
<Grid container>
@ -299,7 +299,7 @@ export const AddVariant = ({
projectId={projectId}
name="weightType"
checked={isFixWeight}
data-test={
data-testid={
'VARIANT_WEIGHT_TYPE'
}
onChange={setVariantWeightType}
@ -320,7 +320,7 @@ export const AddVariant = ({
id="weight"
label="Weight"
name="weight"
data-test={'VARIANT_WEIGHT_INPUT'}
data-testid={'VARIANT_WEIGHT_INPUT'}
InputProps={{
endAdornment: (
<InputAdornment position="start">
@ -373,7 +373,7 @@ export const AddVariant = ({
className={commonStyles.fullWidth}
value={payload.value}
onChange={onPayload}
data-test={'VARIANT_PAYLOAD_VALUE'}
data-testid={'VARIANT_PAYLOAD_VALUE'}
placeholder={
payload.type === 'json'
? '{ "hello": "world" }'

View File

@ -292,7 +292,7 @@ const FeatureOverviewVariants = () => {
setShowAddVariant(true);
}}
className={styles.addVariantButton}
data-test={'ADD_VARIANT_BUTTON'}
data-testid={'ADD_VARIANT_BUTTON'}
permission={UPDATE_FEATURE_VARIANTS}
projectId={projectId}
>

View File

@ -23,7 +23,7 @@ const FeatureVariantListItem = ({
return (
<TableRow>
<TableCell data-test={'VARIANT_NAME'}>{variant.name}</TableCell>
<TableCell data-testid={'VARIANT_NAME'}>{variant.name}</TableCell>
<TableCell className={styles.chipContainer}>
<ConditionallyRender
condition={Boolean(variant.payload)}
@ -43,10 +43,10 @@ const FeatureVariantListItem = ({
}
/>
</TableCell>
<TableCell data-test={'VARIANT_WEIGHT'}>
<TableCell data-testid={'VARIANT_WEIGHT'}>
{variant.weight / 10.0} %
</TableCell>
<TableCell data-test={'VARIANT_WEIGHT_TYPE'}>
<TableCell data-testid={'VARIANT_WEIGHT_TYPE'}>
{variant.weightType === FIX ? 'Fix' : 'Variable'}
</TableCell>
<ConditionallyRender
@ -55,13 +55,13 @@ const FeatureVariantListItem = ({
<TableCell className={styles.actions}>
<div className={styles.actionsContainer}>
<IconButton
data-test={'VARIANT_EDIT_BUTTON'}
data-testid={'VARIANT_EDIT_BUTTON'}
onClick={() => editVariant(variant.name)}
>
<Edit />
</IconButton>
<IconButton
data-test={`VARIANT_DELETE_BUTTON_${variant.name}`}
data-testid={`VARIANT_DELETE_BUTTON_${variant.name}`}
onClick={e => {
e.stopPropagation();
setDelDialog({

View File

@ -117,7 +117,7 @@ const StrategyConstraintInputField = ({
multiple
size="small"
options={options}
data-test={CONSTRAINT_AUTOCOMPLETE_ID}
data-testid={CONSTRAINT_AUTOCOMPLETE_ID}
value={values || []}
getOptionLabel={option => option.label}
onBlur={onBlur}

View File

@ -104,7 +104,7 @@ const FlexibleStrategy = ({
options={stickinessOptions}
value={stickiness}
disabled={!editable}
data-test={FLEXIBLE_STRATEGY_STICKINESS_ID}
data-testid={FLEXIBLE_STRATEGY_STICKINESS_ID}
onChange={e =>
onUpdate('stickiness')(e, e.target.value as number)
}
@ -136,7 +136,7 @@ const FlexibleStrategy = ({
value={groupId || ''}
disabled={!editable}
onChange={e => onUpdate('groupId')(e, e.target.value)}
data-test={FLEXIBLE_STRATEGY_GROUP_ID}
data-testid={FLEXIBLE_STRATEGY_GROUP_ID}
/>
</div>
</div>

View File

@ -101,7 +101,7 @@ const RolloutSlider = ({
getAriaValueText={valuetext}
aria-labelledby="discrete-slider-always"
step={1}
data-test={ROLLOUT_SLIDER_ID}
data-testid={ROLLOUT_SLIDER_ID}
marks={marks}
onChange={onChange}
valueLabelDisplay="on"

View File

@ -100,12 +100,12 @@ const StrategyInputList = ({
onChange={onChange}
// @ts-expect-error
onKeyDown={onKeyDown}
data-test={STRATEGY_INPUT_LIST}
data-testid={STRATEGY_INPUT_LIST}
/>
{/* @ts-expect-error */}
<Button
onClick={setValue}
data-test={ADD_TO_STRATEGY_INPUT_LIST}
data-testid={ADD_TO_STRATEGY_INPUT_LIST}
color="secondary"
startIcon={<Add />}
>

View File

@ -97,7 +97,7 @@ export const CreateSegment = () => {
name="segment"
permission={CREATE_SEGMENT}
disabled={!hasValidConstraints || atSegmentValuesLimit}
data-test={SEGMENT_CREATE_BTN_ID}
data-testid={SEGMENT_CREATE_BTN_ID}
/>
</SegmentForm>
</FormTemplate>

View File

@ -99,7 +99,7 @@ export const EditSegment = () => {
<UpdateButton
permission={UPDATE_SEGMENT}
disabled={!hasValidConstraints || atSegmentValuesLimit}
data-test={SEGMENT_SAVE_BTN_ID}
data-testid={SEGMENT_SAVE_BTN_ID}
/>
</SegmentForm>
</FormTemplate>

View File

@ -55,7 +55,7 @@ export const SegmentDeleteConfirm = ({
value={confirmName}
label="Segment name"
className={styles.deleteInput}
data-test={SEGMENT_DIALOG_NAME_ID}
data-testid={SEGMENT_DIALOG_NAME_ID}
/>
</form>
</Dialogue>

View File

@ -48,7 +48,7 @@ export const SegmentFormStepOne: React.FC<ISegmentFormPartOneProps> = ({
errorText={errors.name}
autoFocus
required
data-test={SEGMENT_NAME_ID}
data-testid={SEGMENT_NAME_ID}
/>
<p className={styles.inputDescription}>
What is the segment description?
@ -60,7 +60,7 @@ export const SegmentFormStepOne: React.FC<ISegmentFormPartOneProps> = ({
onChange={e => setDescription(e.target.value)}
error={Boolean(errors.description)}
errorText={errors.description}
data-test={SEGMENT_DESC_ID}
data-testid={SEGMENT_DESC_ID}
/>
</div>
<div className={styles.buttonContainer}>
@ -70,7 +70,7 @@ export const SegmentFormStepOne: React.FC<ISegmentFormPartOneProps> = ({
color="primary"
onClick={() => setCurrentStep(2)}
disabled={name.length === 0 || Boolean(errors.name)}
data-test={SEGMENT_NEXT_BTN_ID}
data-testid={SEGMENT_NEXT_BTN_ID}
>
Next
</Button>

View File

@ -102,7 +102,7 @@ export const SegmentsList = () => {
<PermissionButton
onClick={() => history.push('/segments/create')}
permission={CREATE_SEGMENT}
data-test={NAVIGATE_TO_CREATE_SEGMENT}
data-testid={NAVIGATE_TO_CREATE_SEGMENT}
>
New Segment
</PermissionButton>

View File

@ -83,7 +83,7 @@ export const SegmentListItem = ({
setDelDialog(true);
}}
permission={ADMIN}
data-test={`${SEGMENT_DELETE_BTN_ID}_${name}`}
data-testid={`${SEGMENT_DELETE_BTN_ID}_${name}`}
>
<Delete />
</PermissionIconButton>

View File

@ -73,7 +73,7 @@ export const SplashPageEnvironmentsContent: React.FC<
<IconButton
className={styles.closeButton}
onClick={onClose}
data-test={CLOSE_SPLASH}
data-testid={CLOSE_SPLASH}
>
<CloseOutlined titleAccess="Close" />
</IconButton>

View File

@ -69,7 +69,7 @@ export const StrategiesList = () => {
condition={smallScreen}
show={
<PermissionIconButton
data-test={ADD_NEW_STRATEGY_ID}
data-testid={ADD_NEW_STRATEGY_ID}
onClick={() => history.push('/strategies/create')}
permission={CREATE_STRATEGY}
>
@ -81,7 +81,7 @@ export const StrategiesList = () => {
onClick={() => history.push('/strategies/create')}
color="primary"
permission={CREATE_STRATEGY}
data-test={ADD_NEW_STRATEGY_ID}
data-testid={ADD_NEW_STRATEGY_ID}
>
New strategy
</PermissionButton>

View File

@ -42,7 +42,7 @@ exports[`renders correctly with one strategy 1`] = `
>
<button
className="MuiButtonBase-root MuiButton-root MuiButton-contained MuiButton-containedPrimary"
data-test="ADD_NEW_STRATEGY_ID"
data-testid="ADD_NEW_STRATEGY_ID"
disabled={false}
onBlur={[Function]}
onClick={[Function]}
@ -317,7 +317,7 @@ exports[`renders correctly with one strategy without permissions 1`] = `
>
<button
className="MuiButtonBase-root MuiButton-root MuiButton-contained MuiButton-containedPrimary"
data-test="ADD_NEW_STRATEGY_ID"
data-testid="ADD_NEW_STRATEGY_ID"
disabled={false}
onBlur={[Function]}
onClick={[Function]}

View File

@ -0,0 +1,135 @@
import Authentication from 'component/user/Authentication/Authentication';
import { render, screen } from '@testing-library/react';
import {
LOGIN_PASSWORD_ID,
LOGIN_EMAIL_ID,
LOGIN_BUTTON,
AUTH_PAGE_ID,
SSO_LOGIN_BUTTON,
} from 'utils/testIds';
import React from 'react';
import { TestContext } from 'utils/testContext';
import { testServerSetup, testServerRoute } from 'utils/testServer';
const server = testServerSetup();
test('should render password auth', async () => {
testServerRoute(server, '*', {
defaultHidden: false,
message: 'You must sign in in order to use Unleash',
path: '/auth/simple/login',
type: 'password',
options: [],
});
render(
<TestContext>
<Authentication redirect="/" />
</TestContext>
);
await screen.findByTestId(AUTH_PAGE_ID);
expect(screen.getByTestId(LOGIN_EMAIL_ID)).toBeInTheDocument();
expect(screen.getByTestId(LOGIN_PASSWORD_ID)).toBeInTheDocument();
expect(screen.getByTestId(LOGIN_BUTTON)).toBeInTheDocument();
});
test('should not render password auth if defaultHidden is true', async () => {
testServerRoute(server, '*', {
defaultHidden: true,
message: 'You must sign in in order to use Unleash',
path: '/auth/simple/login',
type: 'password',
options: [],
});
render(
<TestContext>
<Authentication redirect="/" />
</TestContext>
);
await screen.findByTestId(AUTH_PAGE_ID);
expect(screen.queryByTestId(LOGIN_EMAIL_ID)).not.toBeInTheDocument();
expect(screen.queryByTestId(LOGIN_PASSWORD_ID)).not.toBeInTheDocument();
expect(screen.queryByTestId(LOGIN_BUTTON)).not.toBeInTheDocument();
});
test('should render demo auth', async () => {
testServerRoute(server, '*', {
defaultHidden: false,
message: 'You must sign in in order to use Unleash',
path: '/auth/demo/login',
type: 'demo',
options: [],
});
render(
<TestContext>
<Authentication redirect="/" />
</TestContext>
);
await screen.findByTestId(AUTH_PAGE_ID);
expect(screen.getByTestId(LOGIN_EMAIL_ID)).toBeInTheDocument();
expect(screen.queryByTestId(LOGIN_PASSWORD_ID)).not.toBeInTheDocument();
expect(screen.getByTestId(LOGIN_BUTTON)).toBeInTheDocument();
});
test('should render email auth', async () => {
testServerRoute(server, '*', {
defaultHidden: false,
message: 'You must sign in in order to use Unleash',
path: '/auth/unsecure/login',
type: 'unsecure',
options: [],
});
render(
<TestContext>
<Authentication redirect="/" />
</TestContext>
);
await screen.findByTestId(AUTH_PAGE_ID);
expect(screen.getByTestId(LOGIN_EMAIL_ID)).toBeInTheDocument();
expect(screen.queryByTestId(LOGIN_PASSWORD_ID)).not.toBeInTheDocument();
expect(screen.getByTestId(LOGIN_BUTTON)).toBeInTheDocument();
});
test('should render Google auth', async () => {
await testSSOAuthOption('google');
});
test('should render OIDC auth', async () => {
await testSSOAuthOption('oidc');
});
test('should render SAML auth', async () => {
await testSSOAuthOption('saml');
});
const testSSOAuthOption = async (authOption: string) => {
const path = `/auth/${authOption}/login`;
const testId = `${SSO_LOGIN_BUTTON}-${authOption}`;
testServerRoute(server, '*', {
defaultHidden: true,
message: 'You must sign in in order to use Unleash',
options: [{ type: authOption, message: '...', path: path }],
path: '/auth/simple/login',
type: 'password',
});
render(
<TestContext>
<Authentication redirect="/" />
</TestContext>
);
const ssoLink = await screen.findByTestId(testId);
expect(ssoLink.getAttribute('href')).toEqual(path);
expect(screen.queryByTestId(LOGIN_EMAIL_ID)).not.toBeInTheDocument();
expect(screen.queryByTestId(LOGIN_PASSWORD_ID)).not.toBeInTheDocument();
expect(screen.queryByTestId(LOGIN_BUTTON)).not.toBeInTheDocument();
};

View File

@ -14,16 +14,20 @@ import useQueryParams from 'hooks/useQueryParams';
import ConditionallyRender from 'component/common/ConditionallyRender';
import { Alert } from '@material-ui/lab';
import { useAuthDetails } from 'hooks/api/getters/useAuth/useAuthDetails';
import { AUTH_PAGE_ID } from 'utils/testIds';
interface IAuthenticationProps {
redirect: string;
}
const Authentication = ({ redirect }: IAuthenticationProps) => {
const { authDetails } = useAuthDetails();
const params = useQueryParams();
const error = params.get('errorMsg');
if (!authDetails) return null;
if (!authDetails) {
return null;
}
let content;
if (authDetails.type === PASSWORD_TYPE) {
@ -53,9 +57,10 @@ const Authentication = ({ redirect }: IAuthenticationProps) => {
} else {
content = <AuthenticationCustomComponent authDetails={authDetails} />;
}
return (
<>
<div style={{ maxWidth: '350px' }}>
<div style={{ maxWidth: '350px' }} data-testid={AUTH_PAGE_ID}>
<ConditionallyRender
condition={Boolean(error)}
show={<Alert severity="error">{error}</Alert>}

View File

@ -45,12 +45,12 @@ const DemoAuth = ({ authDetails, redirect }) => {
value={email}
className={styles.emailField}
onChange={handleChange}
inputProps={{ 'data-test': 'email-input-field' }}
inputProps={{ 'data-testid': 'email-input-field' }}
size="small"
variant="outlined"
label="Email"
name="email"
data-test={LOGIN_EMAIL_ID}
data-testid={LOGIN_EMAIL_ID}
required
type="email"
/>
@ -60,7 +60,7 @@ const DemoAuth = ({ authDetails, redirect }) => {
variant="contained"
color="primary"
className={styles.button}
data-test={LOGIN_BUTTON}
data-testid={LOGIN_BUTTON}
>
Sign in
</Button>

View File

@ -0,0 +1,15 @@
import { render, screen } from '@testing-library/react';
import { FORGOTTEN_PASSWORD_FIELD } from 'utils/testIds';
import React from 'react';
import { TestContext } from 'utils/testContext';
import ForgottenPassword from 'component/user/ForgottenPassword/ForgottenPassword';
test('should render password auth', async () => {
render(
<TestContext>
<ForgottenPassword />
</TestContext>
);
await screen.findByTestId(FORGOTTEN_PASSWORD_FIELD);
});

View File

@ -96,7 +96,7 @@ const ForgottenPassword = () => {
placeholder="email"
type="email"
data-loading
data-test={FORGOTTEN_PASSWORD_FIELD}
data-testid={FORGOTTEN_PASSWORD_FIELD}
value={email}
onChange={e => {
setEmail(e.target.value);

View File

@ -109,7 +109,7 @@ const HostedAuth = ({ authDetails, redirect }) => {
helperText={usernameError}
variant="outlined"
size="small"
data-test={LOGIN_EMAIL_ID}
data-testid={LOGIN_EMAIL_ID}
/>
<PasswordField
label="Password"
@ -118,7 +118,7 @@ const HostedAuth = ({ authDetails, redirect }) => {
value={password}
error={!!passwordError}
helperText={passwordError}
data-test={LOGIN_PASSWORD_ID}
data-testid={LOGIN_PASSWORD_ID}
/>
<Grid container>
<Button
@ -126,7 +126,7 @@ const HostedAuth = ({ authDetails, redirect }) => {
color="primary"
type="submit"
className={styles.button}
data-test={LOGIN_BUTTON}
data-testid={LOGIN_BUTTON}
>
Sign in
</Button>

View File

@ -108,7 +108,7 @@ const PasswordAuth = ({ authDetails, redirect }) => {
error={!!usernameError}
helperText={usernameError}
autoComplete="true"
data-test={LOGIN_EMAIL_ID}
data-testid={LOGIN_EMAIL_ID}
variant="outlined"
size="small"
/>
@ -120,14 +120,14 @@ const PasswordAuth = ({ authDetails, redirect }) => {
error={!!passwordError}
helperText={passwordError}
autoComplete="true"
data-test={LOGIN_PASSWORD_ID}
data-testid={LOGIN_PASSWORD_ID}
/>
<Button
variant="contained"
color="primary"
type="submit"
style={{ width: '150px', margin: '1rem auto' }}
data-test={LOGIN_BUTTON}
data-testid={LOGIN_BUTTON}
>
Sign in
</Button>

View File

@ -0,0 +1,26 @@
import { render, screen } from '@testing-library/react';
import { INVALID_TOKEN_BUTTON } from 'utils/testIds';
import React from 'react';
import { TestContext } from 'utils/testContext';
import ResetPassword from 'component/user/ResetPassword/ResetPassword';
import { MemoryRouter } from 'react-router-dom';
import { INVALID_TOKEN_ERROR } from 'hooks/api/getters/useResetPassword/useResetPassword';
import { testServerSetup, testServerRoute } from 'utils/testServer';
const server = testServerSetup();
test('should render password auth', async () => {
testServerRoute(server, '/auth/reset/validate', {
name: INVALID_TOKEN_ERROR,
});
render(
<TestContext>
<MemoryRouter initialEntries={['/new-user?token=invalid']}>
<ResetPassword />
</MemoryRouter>
</TestContext>
);
await screen.findByTestId(INVALID_TOKEN_BUTTON);
});

View File

@ -51,14 +51,14 @@ const SimpleAuth = ({ authDetails, redirect }) => {
<TextField
value={email}
onChange={handleChange}
inputProps={{ 'data-test': 'email-input-field' }}
inputProps={{ 'data-testid': 'email-input-field' }}
size="small"
variant="outlined"
label="Email"
name="email"
required
type="email"
data-test={LOGIN_EMAIL_ID}
data-testid={LOGIN_EMAIL_ID}
/>
<br />
@ -68,7 +68,7 @@ const SimpleAuth = ({ authDetails, redirect }) => {
variant="contained"
color="primary"
className={styles.button}
data-test={LOGIN_BUTTON}
data-testid={LOGIN_BUTTON}
>
Sign in
</Button>

View File

@ -71,7 +71,7 @@ const UserProfile = ({
<Avatar
alt="user image"
src={imageUrl}
data-test={HEADER_USER_AVATAR}
data-testid={HEADER_USER_AVATAR}
/>
<KeyboardArrowDownIcon />
</Button>

View File

@ -29,7 +29,7 @@ const AuthOptions = ({ options }: IAuthOptionProps) => {
variant="outlined"
href={o.path}
size="small"
data-test={`${SSO_LOGIN_BUTTON}-${o.type}`}
data-testid={`${SSO_LOGIN_BUTTON}-${o.type}`}
style={{ height: '40px', color: '#000' }}
startIcon={
<ConditionallyRender

View File

@ -27,7 +27,7 @@ const InvalidToken = () => {
color="primary"
component={Link}
to="forgotten-password"
data-test={INVALID_TOKEN_BUTTON}
data-testid={INVALID_TOKEN_BUTTON}
>
Reset password
</Button>

View File

@ -11,7 +11,7 @@ const getFetcher = (token: string) => () => {
}).then(res => res.json());
};
const INVALID_TOKEN_ERROR = 'InvalidTokenError';
export const INVALID_TOKEN_ERROR = 'InvalidTokenError';
const USED_TOKEN_ERROR = 'UsedTokenError';
const useResetPassword = (options: SWRConfiguration = {}) => {

View File

@ -0,0 +1,15 @@
import { SWRConfig } from 'swr';
import { MemoryRouter } from 'react-router-dom';
import { ThemeProvider } from '@material-ui/core/styles';
import theme from 'themes/mainTheme';
import React from 'react';
export const TestContext: React.FC = ({ children }) => {
return (
<SWRConfig value={{ provider: () => new Map() }}>
<MemoryRouter>
<ThemeProvider theme={theme}>{children}</ThemeProvider>
</MemoryRouter>
</SWRConfig>
);
};

View File

@ -48,3 +48,4 @@ export const CLOSE_SPLASH = 'CLOSE_SPLASH';
export const INPUT_ERROR_TEXT = 'INPUT_ERROR_TEXT';
export const HEADER_USER_AVATAR = 'HEADER_USER_AVATAR';
export const SIDEBAR_MODAL_ID = 'SIDEBAR_MODAL_ID';
export const AUTH_PAGE_ID = 'AUTH_PAGE_ID';

View File

@ -0,0 +1,24 @@
import { SetupServerApi, setupServer } from 'msw/node';
import { rest } from 'msw';
export const testServerSetup = (): SetupServerApi => {
const server = setupServer();
beforeAll(() => server.listen());
afterAll(() => server.close());
afterEach(() => server.resetHandlers());
return server;
};
export const testServerRoute = (
server: SetupServerApi,
path: string,
json: object
) => {
server.use(
rest.get(path, (req, res, ctx) => {
return res(ctx.json(json));
})
);
};

View File

@ -1482,6 +1482,26 @@
prop-types "^15.7.2"
react-is "^16.8.0 || ^17.0.0"
"@mswjs/cookies@^0.2.0":
version "0.2.0"
resolved "https://registry.yarnpkg.com/@mswjs/cookies/-/cookies-0.2.0.tgz#7ef2b5d7e444498bb27cf57720e61f76a4ce9f23"
integrity sha512-GTKYnIfXVP8GL8HRWrse+ujqDXCLKvu7+JoL6pvZFzS/d2i9pziByoWD69cOe35JNoSrx2DPNqrhUF+vgV3qUA==
dependencies:
"@types/set-cookie-parser" "^2.4.0"
set-cookie-parser "^2.4.6"
"@mswjs/interceptors@^0.15.1":
version "0.15.1"
resolved "https://registry.yarnpkg.com/@mswjs/interceptors/-/interceptors-0.15.1.tgz#4a0009f56e51bc2cd3176f1507065c7d2f6c0d5e"
integrity sha512-D5B+ZJNlfvBm6ZctAfRBdNJdCHYAe2Ix4My5qfbHV5WH+3lkt3mmsjiWJzEh5ZwGDauzY487TldI275If7DJVw==
dependencies:
"@open-draft/until" "^1.0.3"
"@xmldom/xmldom" "^0.7.5"
debug "^4.3.3"
headers-polyfill "^3.0.4"
outvariant "^1.2.1"
strict-event-emitter "^0.2.0"
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
@ -1503,6 +1523,11 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
"@open-draft/until@^1.0.3":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@open-draft/until/-/until-1.0.3.tgz#db9cc719191a62e7d9200f6e7bab21c5b848adca"
integrity sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q==
"@pmmmwh/react-refresh-webpack-plugin@^0.5.3":
version "0.5.5"
resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.5.tgz#e77aac783bd079f548daa0a7f080ab5b5a9741ca"
@ -1848,6 +1873,11 @@
dependencies:
"@types/node" "*"
"@types/cookie@^0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d"
integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==
"@types/debounce@1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@types/debounce/-/debounce-1.2.1.tgz#79b65710bc8b6d44094d286aecf38e44f9627852"
@ -1962,6 +1992,11 @@
jest-matcher-utils "^27.0.0"
pretty-format "^27.0.0"
"@types/js-levenshtein@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@types/js-levenshtein/-/js-levenshtein-1.1.1.tgz#ba05426a43f9e4e30b631941e0aa17bf0c890ed5"
integrity sha512-qC4bCqYGy1y/NP7dDVr7KJarn+PbX1nSpwA7JXdu0HxT3QYjO8MJ+cntENtHFVy2dRAyBV23OZ6MxsW1AM1L8g==
"@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9":
version "7.0.11"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3"
@ -2141,6 +2176,13 @@
"@types/mime" "^1"
"@types/node" "*"
"@types/set-cookie-parser@^2.4.0":
version "2.4.2"
resolved "https://registry.yarnpkg.com/@types/set-cookie-parser/-/set-cookie-parser-2.4.2.tgz#b6a955219b54151bfebd4521170723df5e13caad"
integrity sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w==
dependencies:
"@types/node" "*"
"@types/sinonjs__fake-timers@8.1.1":
version "8.1.1"
resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz#b49c2c70150141a15e0fa7e79cf1f92a72934ce3"
@ -2409,6 +2451,11 @@
"@webassemblyjs/ast" "1.11.1"
"@xtuc/long" "4.2.2"
"@xmldom/xmldom@^0.7.5":
version "0.7.5"
resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.7.5.tgz#09fa51e356d07d0be200642b0e4f91d8e6dd408d"
integrity sha512-V3BIhmY36fXZ1OtVcI9W+FxQqxVLsPKcNjWigIaa81dLC9IolJl5Mt4Cvhmr0flUnjSpTdrbMTSbXqYqV5dT6A==
"@xtuc/ieee754@^1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
@ -2950,6 +2997,15 @@ binary-extensions@^2.0.0:
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
bl@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a"
integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==
dependencies:
buffer "^5.5.0"
inherits "^2.0.4"
readable-stream "^3.4.0"
blob-util@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/blob-util/-/blob-util-2.0.2.tgz#3b4e3c281111bb7f11128518006cdc60b403a1eb"
@ -3039,7 +3095,7 @@ buffer-from@^1.0.0:
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
buffer@^5.6.0:
buffer@^5.5.0, buffer@^5.6.0:
version "5.7.1"
resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
@ -3128,6 +3184,14 @@ caseless@~0.12.0:
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
chalk@4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad"
integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==
dependencies:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
chalk@^2.0.0, chalk@^2.4.1:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
@ -3145,7 +3209,7 @@ chalk@^3.0.0:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.2:
chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
@ -3168,6 +3232,11 @@ charcodes@^0.2.0:
resolved "https://registry.yarnpkg.com/charcodes/-/charcodes-0.2.0.tgz#5208d327e6cc05f99eb80ffc814707572d1f14e4"
integrity sha512-Y4kiDb+AM4Ecy58YkuZrrSRJBDQdQ2L+NyS1vHHFtNtUjgutcZfx3yp1dAONI/oPaPmyGfCLx5CxL+zauIMyKQ==
chardet@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
chart.js@3.7.1:
version "3.7.1"
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-3.7.1.tgz#0516f690c6a8680c6c707e31a4c1807a6f400ada"
@ -3242,6 +3311,11 @@ cli-cursor@^3.1.0:
dependencies:
restore-cursor "^3.1.0"
cli-spinners@^2.5.0:
version "2.6.1"
resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d"
integrity sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==
cli-table3@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.1.tgz#36ce9b7af4847f288d3cdd081fbd09bf7bd237b8"
@ -3259,6 +3333,11 @@ cli-truncate@^2.1.0:
slice-ansi "^3.0.0"
string-width "^4.2.0"
cli-width@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6"
integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==
cliui@^7.0.2:
version "7.0.4"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
@ -3268,6 +3347,11 @@ cliui@^7.0.2:
strip-ansi "^6.0.0"
wrap-ansi "^7.0.0"
clone@^1.0.2:
version "1.0.4"
resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4=
clsx@^1.0.4:
version "1.1.1"
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188"
@ -3432,7 +3516,7 @@ cookie-signature@1.0.6:
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
cookie@0.4.2:
cookie@0.4.2, cookie@^0.4.2:
version "0.4.2"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432"
integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==
@ -3816,7 +3900,7 @@ debug@2.6.9, debug@^2.6.0, debug@^2.6.9:
dependencies:
ms "2.0.0"
debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2:
debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.3:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
@ -3867,6 +3951,13 @@ default-gateway@^6.0.3:
dependencies:
execa "^5.0.0"
defaults@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d"
integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=
dependencies:
clone "^1.0.2"
define-lazy-prop@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f"
@ -4520,7 +4611,7 @@ eventemitter3@^4.0.0:
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
events@^3.2.0:
events@^3.2.0, events@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
@ -4618,6 +4709,15 @@ extend@~3.0.2:
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
external-editor@^3.0.3:
version "3.1.0"
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==
dependencies:
chardet "^0.7.0"
iconv-lite "^0.4.24"
tmp "^0.0.33"
extract-zip@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a"
@ -4698,7 +4798,7 @@ fd-slicer@~1.1.0:
dependencies:
pend "~1.2.0"
figures@^3.2.0:
figures@^3.0.0, figures@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af"
integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==
@ -5056,6 +5156,11 @@ graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4,
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
graphql@^16.3.0:
version "16.3.0"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.3.0.tgz#a91e24d10babf9e60c706919bb182b53ccdffc05"
integrity sha512-xm+ANmA16BzCT5pLjuXySbQVFwH3oJctUVdy81w1sV0vBU0KgDdBGtxQOUd5zqOBk/JayAFeG8Dlmeq74rjm/A==
gzip-size@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462"
@ -5112,6 +5217,11 @@ he@^1.2.0:
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
headers-polyfill@^3.0.4:
version "3.0.7"
resolved "https://registry.yarnpkg.com/headers-polyfill/-/headers-polyfill-3.0.7.tgz#725c4f591e6748f46b036197eae102c92b959ff4"
integrity sha512-JoLCAdCEab58+2/yEmSnOlficyHFpIl0XJqwu3l+Unkm1gXpFUYsThz6Yha3D6tNhocWkCPfyW0YVIGWFqTi7w==
history@^4.9.0:
version "4.10.1"
resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3"
@ -5289,7 +5399,7 @@ hyphenate-style-name@^1.0.3:
resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz#691879af8e220aea5750e8827db4ef62a54e361d"
integrity sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==
iconv-lite@0.4.24:
iconv-lite@0.4.24, iconv-lite@^0.4.24:
version "0.4.24"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
@ -5394,6 +5504,26 @@ ini@^1.3.5:
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
inquirer@^8.2.0:
version "8.2.2"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.2.tgz#1310517a87a0814d25336c78a20b44c3d9b7629d"
integrity sha512-pG7I/si6K/0X7p1qU+rfWnpTE1UIkTONN1wxtzh0d+dHXtT/JG6qBgLxoyHVsQa8cFABxAPh0pD6uUUHiAoaow==
dependencies:
ansi-escapes "^4.2.1"
chalk "^4.1.1"
cli-cursor "^3.1.0"
cli-width "^3.0.0"
external-editor "^3.0.3"
figures "^3.0.0"
lodash "^4.17.21"
mute-stream "0.0.8"
ora "^5.4.1"
run-async "^2.4.0"
rxjs "^7.5.5"
string-width "^4.1.0"
strip-ansi "^6.0.0"
through "^2.3.6"
internal-slot@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c"
@ -5506,6 +5636,11 @@ is-installed-globally@~0.4.0:
global-dirs "^3.0.0"
is-path-inside "^3.0.2"
is-interactive@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e"
integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==
is-module@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
@ -5516,6 +5651,11 @@ is-negative-zero@^2.0.2:
resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150"
integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==
is-node-process@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-node-process/-/is-node-process-1.0.1.tgz#4fc7ac3a91e8aac58175fe0578abbc56f2831b23"
integrity sha512-5IcdXuf++TTNt3oGl9EBdkvndXA8gmc4bz/Y+mdEpWh3Mcn/+kOw6hI7LD5CocqJWMzeb0I0ClndRVNdEPuJXQ==
is-number-object@^1.0.4:
version "1.0.7"
resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc"
@ -6115,6 +6255,11 @@ jest@^27.4.3:
import-local "^3.0.2"
jest-cli "^27.5.1"
js-levenshtein@^1.1.6:
version "1.1.6"
resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d"
integrity sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@ -6498,7 +6643,7 @@ lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
log-symbols@^4.0.0:
log-symbols@^4.0.0, log-symbols@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503"
integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==
@ -6535,11 +6680,6 @@ lru-cache@^7.4.0:
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.7.3.tgz#98cd19eef89ce6a4a3c4502c17c833888677c252"
integrity sha512-WY9wjJNQt9+PZilnLbuFKM+SwDull9+6IAguOrarOMoOHTcJ9GnXSO11+Gw6c7xtDkBkthR57OZMtZKYr+1CEw==
lru-cache@^7.4.0:
version "7.7.3"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.7.3.tgz#98cd19eef89ce6a4a3c4502c17c833888677c252"
integrity sha512-WY9wjJNQt9+PZilnLbuFKM+SwDull9+6IAguOrarOMoOHTcJ9GnXSO11+Gw6c7xtDkBkthR57OZMtZKYr+1CEw==
lz-string@^1.4.4:
version "1.4.4"
resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26"
@ -6704,6 +6844,31 @@ ms@2.1.3, ms@^2.1.1:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
msw@^0.39.2:
version "0.39.2"
resolved "https://registry.yarnpkg.com/msw/-/msw-0.39.2.tgz#832e9274db62c43cb79854d5a69dce031c700de8"
integrity sha512-ju/HpqQpE4/qCxZ23t5Gaau0KREn4QuFzdG28nP1EpidMrymMJuIvNd32+2uGTGG031PMwrC41YW7vCxHOwyHA==
dependencies:
"@mswjs/cookies" "^0.2.0"
"@mswjs/interceptors" "^0.15.1"
"@open-draft/until" "^1.0.3"
"@types/cookie" "^0.4.1"
"@types/js-levenshtein" "^1.1.1"
chalk "4.1.1"
chokidar "^3.4.2"
cookie "^0.4.2"
graphql "^16.3.0"
headers-polyfill "^3.0.4"
inquirer "^8.2.0"
is-node-process "^1.0.1"
js-levenshtein "^1.1.6"
node-fetch "^2.6.7"
path-to-regexp "^6.2.0"
statuses "^2.0.0"
strict-event-emitter "^0.2.0"
type-fest "^1.2.2"
yargs "^17.3.1"
multicast-dns@^7.2.4:
version "7.2.4"
resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-7.2.4.tgz#cf0b115c31e922aeb20b64e6556cbeb34cf0dd19"
@ -6712,6 +6877,11 @@ multicast-dns@^7.2.4:
dns-packet "^5.2.2"
thunky "^1.0.2"
mute-stream@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
nanoid@^3.3.1:
version "3.3.2"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.2.tgz#c89622fafb4381cd221421c69ec58547a1eec557"
@ -6740,6 +6910,13 @@ no-case@^3.0.4:
lower-case "^2.0.2"
tslib "^2.0.3"
node-fetch@^2.6.7:
version "2.6.7"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
dependencies:
whatwg-url "^5.0.0"
node-forge@^1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3"
@ -6934,11 +7111,36 @@ optionator@^0.9.1:
type-check "^0.4.0"
word-wrap "^1.2.3"
ora@^5.4.1:
version "5.4.1"
resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18"
integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==
dependencies:
bl "^4.1.0"
chalk "^4.1.0"
cli-cursor "^3.1.0"
cli-spinners "^2.5.0"
is-interactive "^1.0.0"
is-unicode-supported "^0.1.0"
log-symbols "^4.1.0"
strip-ansi "^6.0.0"
wcwidth "^1.0.1"
os-tmpdir@~1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
ospath@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/ospath/-/ospath-1.2.2.tgz#1276639774a3f8ef2572f7fe4280e0ea4550c07b"
integrity sha1-EnZjl3Sj+O8lcvf+QoDg6kVQwHs=
outvariant@^1.2.1:
version "1.3.0"
resolved "https://registry.yarnpkg.com/outvariant/-/outvariant-1.3.0.tgz#c39723b1d2cba729c930b74bf962317a81b9b1c9"
integrity sha512-yeWM9k6UPfG/nzxdaPlJkB2p08hCg4xP6Lx99F+vP8YF7xyZVfTmJjrrNalkmzudD4WFvNLVudQikqUmF8zhVQ==
p-limit@^1.1.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
@ -7093,6 +7295,11 @@ path-to-regexp@^1.7.0:
dependencies:
isarray "0.0.1"
path-to-regexp@^6.2.0:
version "6.2.0"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.0.tgz#f7b3803336104c346889adece614669230645f38"
integrity sha512-f66KywYG6+43afgE/8j/GoiNyygk/bnoCbps++3ErRKsIYkGGupyv07R2Ok5m9i67Iqc+T2g1eAUGUPzWhYTyg==
path-type@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
@ -8097,7 +8304,7 @@ readable-stream@^2.0.1:
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
readable-stream@^3.0.6:
readable-stream@^3.0.6, readable-stream@^3.4.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
@ -8341,6 +8548,11 @@ rollup@^2.43.1:
optionalDependencies:
fsevents "~2.3.2"
run-async@^2.4.0:
version "2.4.1"
resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455"
integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==
run-parallel@^1.1.9:
version "1.2.0"
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
@ -8348,7 +8560,7 @@ run-parallel@^1.1.9:
dependencies:
queue-microtask "^1.2.2"
rxjs@^7.5.1:
rxjs@^7.5.1, rxjs@^7.5.5:
version "7.5.5"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.5.tgz#2ebad89af0f560f460ad5cc4213219e1f7dd4e9f"
integrity sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==
@ -8466,7 +8678,7 @@ semver@7.0.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
semver@7.3.6:
semver@7.3.6, semver@^7.3.2, semver@^7.3.5:
version "7.3.6"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.6.tgz#5d73886fb9c0c6602e79440b97165c29581cbb2b"
integrity sha512-HZWqcgwLsjaX1HBD31msI/rXktuIhS+lWvdE4kN9z+8IVT4Itc7vqU2WvYsyD6/sjYCt4dEKH/m1M3dwI9CC5w==
@ -8478,13 +8690,6 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
semver@^7.3.2, semver@^7.3.5:
version "7.3.6"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.6.tgz#5d73886fb9c0c6602e79440b97165c29581cbb2b"
integrity sha512-HZWqcgwLsjaX1HBD31msI/rXktuIhS+lWvdE4kN9z+8IVT4Itc7vqU2WvYsyD6/sjYCt4dEKH/m1M3dwI9CC5w==
dependencies:
lru-cache "^7.4.0"
send@0.17.2:
version "0.17.2"
resolved "https://registry.yarnpkg.com/send/-/send-0.17.2.tgz#926622f76601c41808012c8bf1688fe3906f7820"
@ -8541,6 +8746,11 @@ serve-static@1.14.2:
parseurl "~1.3.3"
send "0.17.2"
set-cookie-parser@^2.4.6:
version "2.4.8"
resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.4.8.tgz#d0da0ed388bc8f24e706a391f9c9e252a13c58b2"
integrity sha512-edRH8mBKEWNVIVMKejNnuJxleqYE/ZSdcT8/Nem9/mmosx12pctd80s2Oy00KNZzrogMZS5mauK2/ymL1bvlvg==
setprototypeof@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
@ -8751,6 +8961,18 @@ stackframe@^1.1.1:
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
statuses@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
strict-event-emitter@^0.2.0:
version "0.2.4"
resolved "https://registry.yarnpkg.com/strict-event-emitter/-/strict-event-emitter-0.2.4.tgz#365714f0c95f059db31064ca745d5b33e5b30f6e"
integrity sha512-xIqTLS5azUH1djSUsLH9DbP6UnM/nI18vu8d43JigCQEoVsnY+mrlE+qv6kYqs6/1OkMnMIiL6ffedQSZStuoQ==
dependencies:
events "^3.3.0"
string-length@^4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a"
@ -8772,7 +8994,7 @@ string-natural-compare@^3.0.1:
resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4"
integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==
string-width@^4.1.0, string-width@^4.2.0:
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@ -9079,7 +9301,7 @@ throttleit@^1.0.0:
resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c"
integrity sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=
through@^2.3.8:
through@^2.3.6, through@^2.3.8:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
@ -9099,6 +9321,13 @@ tiny-warning@^1.0.0, tiny-warning@^1.0.2, tiny-warning@^1.0.3:
resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
tmp@^0.0.33:
version "0.0.33"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==
dependencies:
os-tmpdir "~1.0.2"
tmp@~0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14"
@ -9164,6 +9393,11 @@ tr46@^2.1.0:
dependencies:
punycode "^2.1.1"
tr46@~0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=
tryer@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8"
@ -9242,6 +9476,11 @@ type-fest@^0.21.3:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
type-fest@^1.2.2:
version "1.4.0"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1"
integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==
type-is@~1.6.18:
version "1.6.18"
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
@ -9438,6 +9677,18 @@ wbuf@^1.1.0, wbuf@^1.7.3:
dependencies:
minimalistic-assert "^1.0.0"
wcwidth@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8"
integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=
dependencies:
defaults "^1.0.3"
webidl-conversions@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=
webidl-conversions@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
@ -9589,6 +9840,14 @@ whatwg-mimetype@^2.3.0:
resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf"
integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==
whatwg-url@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0=
dependencies:
tr46 "~0.0.3"
webidl-conversions "^3.0.0"
whatwg-url@^7.0.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06"
@ -9879,6 +10138,11 @@ yargs-parser@^20.2.2:
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
yargs-parser@^21.0.0:
version "21.0.1"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.1.tgz#0267f286c877a4f0f728fceb6f8a3e4cb95c6e35"
integrity sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==
yargs@^16.2.0:
version "16.2.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66"
@ -9892,6 +10156,19 @@ yargs@^16.2.0:
y18n "^5.0.5"
yargs-parser "^20.2.2"
yargs@^17.3.1:
version "17.4.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.4.0.tgz#9fc9efc96bd3aa2c1240446af28499f0e7593d00"
integrity sha512-WJudfrk81yWFSOkZYpAZx4Nt7V4xp7S/uJkX0CnxovMCt1wCE8LNftPpNuF9X/u9gN5nsD7ycYtRcDf2pL3UiA==
dependencies:
cliui "^7.0.2"
escalade "^3.1.1"
get-caller-file "^2.0.5"
require-directory "^2.1.1"
string-width "^4.2.3"
y18n "^5.0.5"
yargs-parser "^21.0.0"
yauzl@^2.10.0:
version "2.10.0"
resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9"