diff --git a/.github/workflows/k6.yml b/.github/workflows/k6.yml new file mode 100644 index 00000000..59dd977d --- /dev/null +++ b/.github/workflows/k6.yml @@ -0,0 +1,55 @@ +name: E2E tests - k6 +on: + pull_request: + types: [opened, reopened, synchronize] + branches: + - main + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Setup Node.js environment + uses: actions/setup-node@v3 + with: + node-version-file: .nvmrc + + - name: Install Mage + uses: magefile/mage-action@v3 + with: + install-only: true + + - name: Install yarn dependencies + run: yarn install + env: + NODE_OPTIONS: '--max_old_space_size=4096' + + - name: Build binaries + run: mage -v + + - name: Build frontend + run: yarn build + env: + NODE_OPTIONS: '--max_old_space_size=4096' + + - name: Setup k6 + run: | + sudo gpg -k + sudo gpg --no-default-keyring --keyring /usr/share/keyrings/k6-archive-keyring.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69 + echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list + sudo apt-get update + sudo apt-get install k6 + + - name: Start Grafana + run: docker run --rm -d -p 3000:3000 --name=grafana --env GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS=grafana-azure-data-explorer-datasource --volume "$PWD/dist:/var/lib/grafana/plugins/azure-data-explorer-datasource" grafana/grafana; sleep 30 + + - name: Run E2E tests + run: k6 run ./e2e/k6/k6.spec.js + env: + E2E_ADX_CLIENT_ID: ${{ secrets.E2E_ADX_CLIENT_ID }} + E2E_ADX_CLIENT_SECRET: ${{ secrets.E2E_ADX_CLIENT_SECRET }} + E2E_ADX_CLUSTER_URL: ${{ secrets.E2E_ADX_CLUSTER_URL }} + E2E_ADX_TENANT_ID: ${{ secrets.E2E_ADX_TENANT_ID }} + diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml new file mode 100644 index 00000000..cfd20c21 --- /dev/null +++ b/.github/workflows/playwright.yml @@ -0,0 +1,58 @@ +name: E2E tests - Playwright +on: + pull_request: + types: [opened, reopened, synchronize] + branches: + - main + +jobs: + test: + timeout-minutes: 60 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Setup Node.js environment + uses: actions/setup-node@v3 + with: + node-version-file: .nvmrc + + - name: Install Mage + uses: magefile/mage-action@v3 + with: + install-only: true + + - name: Install yarn dependencies + run: yarn install + env: + NODE_OPTIONS: '--max_old_space_size=4096' + + - name: Build binaries + run: mage -v + + - name: Build frontend + run: yarn build + env: + NODE_OPTIONS: '--max_old_space_size=4096' + + - name: Install Playwright Browsers + run: yarn playwright install --with-deps + + - name: Start Grafana + run: docker run --rm -d -p 3000:3000 --name=grafana --env GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS=grafana-azure-data-explorer-datasource --volume "$PWD/dist:/var/lib/grafana/plugins/grafana-azure-data-explorer-datasource" grafana/grafana; sleep 30 + + - name: Run Playwright tests + run: yarn playwright test + env: + E2E_ADX_CLIENT_ID: ${{ secrets.E2E_ADX_CLIENT_ID }} + E2E_ADX_CLIENT_SECRET: ${{ secrets.E2E_ADX_CLIENT_SECRET }} + E2E_ADX_CLUSTER_URL: ${{ secrets.E2E_ADX_CLUSTER_URL }} + E2E_ADX_TENANT_ID: ${{ secrets.E2E_ADX_TENANT_ID }} + + - uses: actions/upload-artifact@v3 + if: always() + with: + name: playwright-report + path: playwright-report/ + retention-days: 30 + diff --git a/.github/workflows/pull-request-image.yml b/.github/workflows/pull-request-image.yml index 663cefcd..b05659f2 100644 --- a/.github/workflows/pull-request-image.yml +++ b/.github/workflows/pull-request-image.yml @@ -105,6 +105,7 @@ jobs: with: issue-number: ${{ github.event.number }} body-includes: Use the following command to run this PR with Docker + - name: Update comment on PR if: steps.fc.outputs.comment-id != '' uses: peter-evans/create-or-update-comment@v3 @@ -118,6 +119,7 @@ jobs: ``` docker run --rm -p 3000:3000 grafana/plugin-builds:${{ github.event.pull_request.head.sha }}pre ``` + - name: Add comment to PR if: steps.fc.outputs.comment-id == '' uses: peter-evans/create-or-update-comment@v3 diff --git a/.gitignore b/.gitignore index eccda1d2..27d51517 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,6 @@ yarn.lock .idea pkg/__debug_bin provisioning +/test-results/ +/playwright-report/ +/playwright/.cache/ diff --git a/cspell.config.json b/cspell.config.json index 0d1947fb..72e91b58 100644 --- a/cspell.config.json +++ b/cspell.config.json @@ -1,170 +1,163 @@ { "ignorePaths": [ ".github/**", - "node_modules/**", - "dist/**", "cypress/**", - "provisioning/**", - "src/dashboards/**", - "yarn.lock", + "dist/**", + "e2e/**", "go.sum", "mage_output_file.go", - "src/libs/**", + "node_modules/**", + "pkg/azuredx/models/testdata/**", "pkg/azuredx/testdata/**", - "pkg/azuredx/models/testdata/**" + "provisioning/**", + "src/dashboards/**", + "src/libs/**", + "yarn.lock" ], "words": [ + "", + "aadapp", + "aadapp", + "aangelisc", "adxauth", "adxcredentials", + "Aggregable", + "AIAPI", + "AIURL", + "americ", + "andresmgot", + "atable", + "azcore", + "azcredentials", "azhttpclient", + "azidentity", + "azsettings", + "aztokenprovider", + "AZUREAD", + "azureauth", + "azuredx", + "azuremonitor", "azusercontext", + "barfoo", + "brik", + "buildschema", + "bypassbytes", + "chinaazuremonitor", "clientsecret", - "currentuser", "Codeowners", + "commitish", + "constainer", + "constainer", + "CRID", + "currentuser", + "Dataexplorer", + "dataframe", + "datapoints", "datasource", + "datasources", "datetime", + "datetimes", + "dcount", + "dcount", + "deinterpolate", + "duckdu", + "endswith", + "errgroup", + "Expan", + "Fabrikam", + "fieldandoperator", + "fillmode", + "fxxx", + "getschema", + "getschema", "gotest", + "govazuremonitor", "grafana", + "GRAFANAADXDEV", + "Grafanas", + "groupable", + "Groupable", + "groupbycol", "gtime", + "hasprefix", + "hassuffix", + "hitbytes", + "httpadapter", "httpclient", + "Idxs", + "inlinesvg", + "innererror", + "instancemgmt", + "isnotempty", + "isnotnull", + "jsoniter", + "kust", + "kusto", + "Kusto", + "kustodb", + "Ligthning", "logm", "maputil", - "sdkhttpclient", - "timeseries", - "inlinesvg", + "mgmt", + "missbytes", + "MSAL", + "mulit", + "mvexpand", + "mytable", + "myvar", "nexttoken", - "sunker", - "andresmgot", - "fillmode", - "timefilter", + "openai", + "Partsd", + "pascaldekloe", + "pickone", "plugincheck", - "instancemgmt", + "plugincontext", + "prismjs", + "queryconsistency", + "retrievebytes", + "rowstores", + "rubberduck", + "sdkhttpclient", + "servertimeout", + "Skippable", + "startsswith", + "startswith", + "steelduck", + "stretchr", + "strongconsistency", + "Suggestor", + "sunker", + "Tablename", + "Templating", + "tenantid", "testdata", - "tsdb", - "tsdb", - "httpadapter", - "errgroup", - "dataframe", - "Kusto", - "kusto", - "datasources", - "weakconsistency", - "timeshift", - "azuremonitor", - "govazuremonitor", - "chinaazuremonitor", - "testdynamictableobj", - "testdynamictable", - "timespan", - "testprop", "testdb", - "Tablename", - "datapoints", + "testdynamictable", + "testdynamictableobj", + "testfunction", "testid", + "testprop", "testtable", - "testfunction", - "kustodb", + "timefilter", "timerange", - "Expan", - "Partsd", - "todatetime", - "isnotempty", - "atable", - "groupbycol", - "dcount", - "atable", - "groupbycol", - "dcount", + "timeseries", + "timeshift", + "timespan", "timmar", + "Tmpl", + "todatetime", "toint", "tolong", - "buildschema", - "isnotnull", - "getschema", - "startswith", - "hassuffix", - "americ", - "brik", - "Fabrikam", - "deinterpolate", - "rubberduck", - "steelduck", - "duckdu", - "isnotnull", - "buildschema", - "getschema", - "mytable", - "barfoo", - "prismjs", - "mytable", - "endswith", - "hasprefix", - "Templating", - "mvexpand", "Torkel", - "startsswith", - "Groupable", - "groupable", - "Aggregable", - "Suggestor", - "Grafanas", - "constainer", - "Skippable", - "myvar", - "Ligthning", - "constainer", - "strongconsistency", - "fieldandoperator", - "aadapp", - "pickone", - "datetimes", "tostring", - "fxxx", - "aadapp", - "tenantid", - "azuredx", - "rowstores", - "Ymin", - "Ymax", - "aangelisc", - "MSAL", - "plugincontext", - "jsoniter", - "AZUREAD", - "plugincontext", - "jsoniter", + "tsdb", "typecheck", - "commitish", - "azureauth", - "azcore", - "azidentity", - "azcredentials", - "azsettings", - "MSAL", - "stretchr", - "mgmt", - "kust", - "servertimeout", - "queryconsistency", - "bypassbytes", - "missbytes", - "hitbytes", - "mulit", "vals", - "Dataexplorer", - "Idxs", - "aztokenprovider", - "Tmpl", - "GRAFANAADXDEV", - "CRID", - "innererror", - "retrievebytes", - "pascaldekloe", - "xorcare", - "openai", - "AIAPI", - "AIURL", + "viewports", + "weakconsistency", "workloadidentity", - "" + "xorcare", + "Ymax", + "Ymin" ] } diff --git a/e2e/k6/k6.spec.js b/e2e/k6/k6.spec.js new file mode 100644 index 00000000..521dc029 --- /dev/null +++ b/e2e/k6/k6.spec.js @@ -0,0 +1,220 @@ +import { browser } from 'k6/experimental/browser'; +import { check, fail, sleep } from 'k6'; + +import { URL } from 'https://jslib.k6.io/url/1.0.0/index.js'; +import { uuidv4 } from 'https://jslib.k6.io/k6-utils/1.4.0/index.js'; +import { selectors } from 'https://unpkg.com/@grafana/e2e-selectors@9.4.3/dist/index.js'; + +const DASHBOARD_TITLE = `e2e-test-dashboard-${uuidv4()}`; +const DATASOURCE_NAME = `adx-e2e-test-${uuidv4()}`; + +export const options = { + scenarios: { + ui: { + executor: 'shared-iterations', + options: { + browser: { + type: 'chromium', + }, + }, + }, + }, + thresholds: { + checks: ['rate==1.0'], + }, +}; + +const getDashboardUid = (url) => { + const matches = new URL(url).pathname.match(/\/d\/([^/]+)/); + + if (matches && Array.isArray(matches) && matches.length > 0) { + return matches[1]; + } else { + throw new Error(`Couldn't parse uid from ${url}`); + } +}; + +export async function login(page) { + try { + await page.goto(`http://localhost:3000${selectors.pages.Login.url}`, { + waitUntil: 'networkidle', + }); + + const fields = { + password: page.locator(`input[aria-label="${selectors.pages.Login.password}"]`), + username: page.locator(`input[aria-label="${selectors.pages.Login.username}"]`), + }; + + const buttons = { + skip: page.locator(`button[aria-label="${selectors.pages.Login.skip}"]`), + submit: page.locator(`button[aria-label="${selectors.pages.Login.submit}"]`), + }; + + // login + fields.username.type('admin'); + fields.password.type('admin'); + await buttons.submit.click(); + + // checks page for skip change password screen + check(page, { 'change password is presented': buttons.skip }); + + await Promise.all([page.waitForNavigation(), buttons.skip.click()]); + } catch (e) { + fail(`login failed: ${e}`); + } +} + +export async function addDatasource(page) { + try { + await page.goto(`http://localhost:3000${selectors.pages.AddDataSource.url}`, { + waitUntil: 'networkidle', + }); + + // select datasource + const label = selectors.pages.AddDataSource.dataSourcePluginsV2('Azure Data Explorer Datasource'); + const ds = page.locator(`button[aria-label="${label}"]`); + await Promise.all([page.waitForNavigation(), ds.click()]); + + // name datasource + const dsName = page.locator(`input[aria-label="${selectors.pages.DataSource.name}"]`); + dsName.fill(''); + dsName.type(`${DATASOURCE_NAME}`); + + // fill in form inputs + // you must use type() instead of fill() for the inputs to be filled in + await page.locator(`input[id="adx-cluster-url"]`).type(__ENV.E2E_ADX_CLUSTER_URL); + await page.locator(`input[id="aad-tenant-id"]`).type(__ENV.E2E_ADX_TENANT_ID); + await page.locator(`input[id="aad-client-id"]`).type(__ENV.E2E_ADX_CLIENT_ID); + await page.locator(`input[id="aad-client-secret"]`).type(__ENV.E2E_ADX_CLIENT_SECRET); + + // save and test + const saveBtn = page.locator(`button[data-testid="data-testid ${selectors.pages.DataSource.saveAndTest}"]`); + await saveBtn.click(); + + sleep(4); + + const text = await page.locator('[aria-label="Data source settings page Alert"]').textContent(); + + // checks the page for the data source is working message + check(page, { 'add datasource successful': text.includes('Success') === true }); + } catch (e) { + fail(`add datasource failed: ${e}`); + } +} + +export async function addDashboard(page) { + try { + await page.goto(`http://localhost:3000${selectors.pages.AddDashboard.url}`, { waitUntil: 'networkidle' }); + + // checks for the create dashboard button + const saveDashboardToolbarButton = page.locator( + `button[aria-label="${selectors.components.PageToolbar.item('Save dashboard')}"]` + ); + + // create dashboard + await saveDashboardToolbarButton.click(); + + // name dashboard + const dashboardTitleInput = page.locator(`input[aria-label="${selectors.pages.SaveDashboardAsModal.newName}"]`); + dashboardTitleInput.fill('') + dashboardTitleInput.type(DASHBOARD_TITLE); + + // save dashboard + const saveDashboardModalButton = page.locator(`button[aria-label="${selectors.pages.SaveDashboardAsModal.save}"]`); + await saveDashboardModalButton.click(); + + // checks that the dashboard is created successfully + check(page, { + 'dashboard created successfully': page.locator('div[data-testid="data-testid Alert success"]').isVisible(), + }); + } catch (e) { + fail(`add dashboard failed: ${e}`); + } +} + +export async function configurePanel(page) { + try { + // add panel + const addPanelButton = page.locator('button[data-testid="data-testid Create new panel button"]'); + await addPanelButton.click(); + + // select data source for panel + page.locator('input[placeholder="Select data source"]').type(`${DATASOURCE_NAME}`); + page.keyboard.down('Tab'); + page.keyboard.down('Enter'); + + // select database + const database = page.locator(`[aria-label="Database"]`); + await database.click(); + database.type('PerfTest'); + page.keyboard.down('Enter'); + + // select table + const table = page.locator(`[aria-label="Table"]`); + await table.click({ force: true }); + table.type('PerfTest'); + page.keyboard.down('Enter'); + + // run query + const runQueryBtn = page.locator(`[data-testid="data-testid run-query"]`); + await runQueryBtn.click(); + + sleep(10); + + // are there results? + const columns = page.locator(`[aria-label="Columns"]`); + await columns.click(); + + check(page, { + 'query successful': page.locator('[aria-label="Select options menu"]').innerHTML().includes('_val1_'), + }); + } catch (e) { + fail(`run query failed: ${e}`); + } +} + +export async function removeDashboard(page) { + try { + const dashboardUID = getDashboardUid(page.url()); + await page.goto(`http://localhost:3000/d/${dashboardUID}`, { waitUntil: 'networkidle' }); + + // open dashboard settings + const dashboardSettings = page.locator( + `button[aria-label="${selectors.components.PageToolbar.item('Dashboard settings')}"]` + ); + await dashboardSettings.click(); + + // delete dashboard + const deleteDashboardButton = page.locator( + `button[aria-label="${selectors.pages.Dashboard.Settings.General.deleteDashBoard}"]` + ); + await deleteDashboardButton.click(); + + // confirm delete dashboard + const deleteDashboardModalButton = page.locator( + `button[data-testid="data-testid ${selectors.pages.ConfirmModal.delete}"]` + ); + await deleteDashboardModalButton.click(); + + // checks for success alert message + check(page, { + 'dashboard deleted successfully': page.locator('div[data-testid="data-testid Alert success"]').isVisible(), + }); + } catch (e) { + fail(`remove datasource failed: ${e}`); + } +} + +export default async function () { + const page = browser.newPage(); + + try { + await login(page); + await addDatasource(page); + await addDashboard(page); + await configurePanel(page); + await removeDashboard(page); + } catch (e) { + fail(`e2e test failed: ${e}`); + } +} diff --git a/e2e/playwright/playwright.spec.ts b/e2e/playwright/playwright.spec.ts new file mode 100644 index 00000000..10e3a21f --- /dev/null +++ b/e2e/playwright/playwright.spec.ts @@ -0,0 +1,166 @@ +import { test, expect, Page } from '@playwright/test'; +import { selectors } from '@grafana/e2e-selectors'; +import { v4 as uuidv4 } from 'uuid'; + +const DASHBOARD_TITLE = `e2e-test-dashboard-${uuidv4()}`; +const DATASOURCE_NAME = `adx-e2e-test-${uuidv4()}`; + +const getDashboardUid = (url: string) => { + const matches = new URL(url).pathname.match(/\/d\/([^/]+)/); + + if (matches && Array.isArray(matches) && matches.length > 0) { + return matches[1]; + } else { + throw new Error(`Couldn't parse uid from ${url}`); + } +}; + +async function login(page: Page) { + await page.goto(`http://localhost:3000${selectors.pages.Login.url}`, { + waitUntil: 'networkidle', + }); + + const fields = { + password: page.locator(`input[aria-label="${selectors.pages.Login.password}"]`), + username: page.locator(`input[aria-label="${selectors.pages.Login.username}"]`), + }; + + const buttons = { + skip: page.locator(`button[aria-label="${selectors.pages.Login.skip}"]`), + submit: page.locator(`button[aria-label="${selectors.pages.Login.submit}"]`), + }; + + // login + await fields.username.fill('admin'); + await fields.password.fill('admin'); + await buttons.submit.click(); + + // checks page for skip change password screen + await expect(buttons.skip.isVisible()).toBeTruthy(); + + await buttons.skip.click(); +} + +async function addDatasource(page: Page) { + await page.goto(`http://localhost:3000${selectors.pages.AddDataSource.url}`, { + waitUntil: 'networkidle', + }); + + // select datasource + const label = selectors.pages.AddDataSource.dataSourcePluginsV2('Azure Data Explorer Datasource'); + const ds = page.locator(`button[aria-label="${label}"]`); + await ds.click(); + + // name datasource + const dsName = page.locator(`input[aria-label="${selectors.pages.DataSource.name}"]`); + await dsName.fill(''); + await dsName.fill(`${DATASOURCE_NAME}`); + + // fill in form inputs + await page.locator(`input[id="adx-cluster-url"]`).fill(process.env.E2E_ADX_CLUSTER_URL!); + await page.locator(`input[id="aad-tenant-id"]`).fill(process.env.E2E_ADX_TENANT_ID!); + await page.locator(`input[id="aad-client-id"]`).fill(process.env.E2E_ADX_CLIENT_ID!); + await page.locator(`input[id="aad-client-secret"]`).fill(process.env.E2E_ADX_CLIENT_SECRET!); + + // save and test + const saveBtn = page.locator(`button[data-testid="data-testid ${selectors.pages.DataSource.saveAndTest}"]`); + await saveBtn.click(); + + // checks the page for the data source is working message + await expect(page.locator(`[aria-label="Data source settings page Alert"]`)).toContainText('Success'); +} + +async function addDashboard(page: Page) { + await page.goto(`http://localhost:3000${selectors.pages.AddDashboard.url}`, { waitUntil: 'networkidle' }); + + // checks for the create dashboard button + const saveDashboardToolbarButton = page.locator( + `button[aria-label="${selectors.components.PageToolbar.item('Save dashboard')}"]` + ); + + // create dashboard + await saveDashboardToolbarButton.click(); + + // name dashboard + const dashboardTitleInput = page.locator(`input[aria-label="${selectors.pages.SaveDashboardAsModal.newName}"]`); + await dashboardTitleInput.fill(''); + await dashboardTitleInput.fill(DASHBOARD_TITLE); + + // save dashboard + const saveDashboardModalButton = page.locator(`button[aria-label="${selectors.pages.SaveDashboardAsModal.save}"]`); + await saveDashboardModalButton.click(); + + // checks that the dashboard is created successfully + await expect(page.locator(`div[data-testid="${selectors.pages.DataSource.alert}"]`).isVisible()).toBeTruthy(); +} + +async function configurePanel(page: Page) { + // add panel + const addPanelButton = page.locator('button[data-testid="data-testid Create new panel button"]'); + await addPanelButton.click(); + + // select data source for panel + const dsPanel = page.locator('input[placeholder="Select data source"]'); + await dsPanel.fill(`${DATASOURCE_NAME}`); + await page.keyboard.down('Tab'); + await page.keyboard.down('Enter'); + + // select database + const database = page.locator(`[aria-label="Database"]`); + await database.click({ force: true }); + await database.fill('PerfTest'); + + // select table + const table = page.locator(`[aria-label="Table"]`); + await table.click({ force: true }); + await table.fill('PerfTest'); + + // run query + const runQueryBtn = page.locator(`[data-testid="data-testid run-query"]`); + await runQueryBtn.click({ force: true }); + + // are there results? + const columns = page.locator(`[aria-label="Columns"]`); + await columns.click({ force: true }); + + await page.waitForTimeout(6000); + + const html = await page.locator('[aria-label="Select options menu"]').innerHTML(); + await expect(html).toContain('_val1_'); +} + +export async function removeDashboard(page: Page) { + const dashboardUID = getDashboardUid(page.url()); + await page.goto(`http://localhost:3000/d/${dashboardUID}`, { waitUntil: 'networkidle' }); + + // open dashboard settings + const dashboardSettings = page.locator( + `button[aria-label="${selectors.components.PageToolbar.item('Dashboard settings')}"]` + ); + await dashboardSettings.click(); + + // delete dashboard + const deleteDashboardButton = page.locator( + `button[aria-label="${selectors.pages.Dashboard.Settings.General.deleteDashBoard}"]` + ); + await deleteDashboardButton.click(); + + // confirm delete dashboard + const deleteDashboardModalButton = page.locator( + `button[data-testid="data-testid ${selectors.pages.ConfirmModal.delete}"]` + ); + await deleteDashboardModalButton.click(); + + // checks for success alert message + await expect( + page.locator(`div[data-testid="${selectors.components.Alert.alertV2('success')}"]`).isVisible() + ).toBeTruthy(); +} + +test('Azure Data Explorer dashboard', async ({ page }) => { + await login(page); + await addDatasource(page); + await addDashboard(page); + await configurePanel(page); + await removeDashboard(page); +}); diff --git a/package.json b/package.json index b5fc2dfc..dd7c924f 100644 --- a/package.json +++ b/package.json @@ -27,10 +27,11 @@ "license": "Apache", "devDependencies": { "@babel/core": "^7.21.4", - "@grafana/e2e": "9.4.3", - "@grafana/e2e-selectors": "9.4.3", + "@grafana/e2e": "9.5.13", + "@grafana/e2e-selectors": "9.5.13", "@grafana/eslint-config": "^6.0.0", "@grafana/tsconfig": "^1.2.0-rc1", + "@playwright/test": "^1.38.1", "@swc/core": "1.3.75", "@swc/helpers": "^0.5.0", "@swc/jest": "^0.2.26", @@ -42,6 +43,7 @@ "@types/glob": "^8.0.0", "@types/grafana": "github:CorpGlory/types-grafana.git", "@types/jest": "^29.5.0", + "@types/k6": "^0.47.1", "@types/lodash": "^4.14.194", "@types/node": "^18.15.11", "@types/prismjs": "1.26.1", diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 00000000..48cd101c --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,77 @@ +import { defineConfig, devices } from '@playwright/test'; + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// require('dotenv').config(); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: './e2e/playwright', + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: 'html', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + // baseURL: 'http://127.0.0.1:3000', + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + + // { + // name: 'firefox', + // use: { ...devices['Desktop Firefox'] }, + // }, + + // { + // name: 'webkit', + // use: { ...devices['Desktop Safari'] }, + // }, + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { ...devices['Pixel 5'] }, + // }, + // { + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { ...devices['Desktop Edge'], channel: 'msedge' }, + // }, + // { + // name: 'Google Chrome', + // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, + // }, + ], + + /* Run your local dev server before starting the tests */ + // webServer: { + // command: 'npm run start', + // url: 'http://127.0.0.1:3000', + // reuseExistingServer: !process.env.CI, + // }, +}); diff --git a/src/components/ConfigEditor/ConnectionConfig.tsx b/src/components/ConfigEditor/ConnectionConfig.tsx index 2ba7ecde..a99a88bc 100644 --- a/src/components/ConfigEditor/ConnectionConfig.tsx +++ b/src/components/ConfigEditor/ConnectionConfig.tsx @@ -23,6 +23,7 @@ const ConnectionConfig: React.FC = ({ options, updateJson invalid={!options.jsonData.clusterUrl} > =3.0.0 <4.0.0", chokidar@^3.5.3: optionalDependencies: fsevents "~2.3.2" -chrome-remote-interface@0.32.0: - version "0.32.0" - resolved "https://registry.yarnpkg.com/chrome-remote-interface/-/chrome-remote-interface-0.32.0.tgz#d7e59a9265d9a208d6b632b8f69c837e1ccc4241" - integrity sha512-g8xK3lKvAgEs3Hj/masMfYOyIFbDkXsMxD7e55TRUvbL7pAb6X9uo+0mKQFjZqQ7DN3b8DIdBfkKw1nwkeWHhw== +chrome-remote-interface@0.32.1: + version "0.32.1" + resolved "https://registry.yarnpkg.com/chrome-remote-interface/-/chrome-remote-interface-0.32.1.tgz#e3478ca712223e51c4df7294cbc536f868ca0aa6" + integrity sha512-CU3/K/8YlU2H0DjsLRbxPsG4piiSGUcIy6GkGXF11SqOYoIeuUBivOsGXScaZnTyC1p4wFSR+GNmAM434/ALWw== dependencies: commander "2.11.x" ws "^7.2.0" @@ -5727,17 +5671,6 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -5747,11 +5680,6 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" -crypt@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" - integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow== - crypto-random-string@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-4.0.0.tgz#5a3cc53d7dd86183df5da0312816ceeeb5bb1fc2" @@ -6488,10 +6416,10 @@ detect-newline@^3.0.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== -devtools-protocol@0.0.1065144: - version "0.0.1065144" - resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1065144.tgz#3ebceef449c5a611ef0972bf8b9b635e840b1a9b" - integrity sha512-SFQz0ecyNnXZlCGiVVpS6vkx/MOkIrsLHiuIvGSHH74KXdGtWPnh/WN3jwis77kepHzO6MufYmRrULLB/TWiXw== +devtools-protocol@0.0.1113774: + version "0.0.1113774" + resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1113774.tgz#bc3a3e29828bf8338e06f3c251cd986559d55eba" + integrity sha512-e8RTiY/W9+exY6T2bK9mLyJG/CfwCixDVof7MqOS2maLANTdihMr2LCf6wcBUvgQzmrImqHITyJB90ICiuJGwA== diff-sequences@^29.3.1: version "29.3.1" @@ -7430,6 +7358,11 @@ find-cache-dir@^3.3.2: make-dir "^3.0.2" pkg-dir "^4.1.0" +find-parent-dir@~0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/find-parent-dir/-/find-parent-dir-0.3.1.tgz#c5c385b96858c3351f95d446cab866cbf9f11125" + integrity sha512-o4UcykWV/XN9wm+jMEtWLPlV8RXCZnMhQI6F6OdHeSez7iiJWePw8ijOlskJZMsaQoGR/b7dH6lO02HhaTN7+A== + find-root@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" @@ -7547,7 +7480,7 @@ form-data@~2.3.2: combined-stream "^1.0.6" mime-types "^2.1.12" -fs-extra@^10.0.0, fs-extra@^10.1.0: +fs-extra@^10.0.0: version "10.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== @@ -7576,11 +7509,16 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@^2.3.2, fsevents@~2.3.2: +fsevents@2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== +fsevents@^2.3.2, fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -7788,6 +7726,16 @@ glob@^7.1.3, glob@^7.1.4: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^9.2.0: + version "9.3.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-9.3.5.tgz#ca2ed8ca452781a3009685607fdf025a899dfe21" + integrity sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q== + dependencies: + fs.realpath "^1.0.0" + minimatch "^8.0.2" + minipass "^4.2.4" + path-scurry "^1.6.1" + global-dirs@^3.0.0, global-dirs@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-3.0.1.tgz#0c488971f066baceda21447aecb1a8b911d22485" @@ -8276,11 +8224,6 @@ is-boolean-object@^1.1.0: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-buffer@~1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - is-builtin-module@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169" @@ -9486,15 +9429,6 @@ marked@5.1.1: resolved "https://registry.yarnpkg.com/marked/-/marked-5.1.1.tgz#40b3963bb9da225314f746d5012ba7e34942f636" integrity sha512-bTmmGdEINWmOMDjnPWDxGPQ4qkDLeYorpYbEtFOXzOruTwUE671q4Guiuchn4N8h/v6NGd7916kXsm3Iz4iUSg== -md5@2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" - integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g== - dependencies: - charenc "0.0.2" - crypt "0.0.2" - is-buffer "~1.1.6" - mdn-data@2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" @@ -9592,6 +9526,13 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" +minimatch@^8.0.2: + version "8.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-8.0.4.tgz#847c1b25c014d4e9a7f68aaf63dedd668a626229" + integrity sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA== + dependencies: + brace-expansion "^2.0.1" + minimatch@^9.0.1: version "9.0.3" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" @@ -9604,6 +9545,11 @@ minimist@^1.2.5, minimist@^1.2.6, minimist@^1.2.8: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== +minipass@^4.2.4: + version "4.2.8" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.2.8.tgz#f0010f64393ecfc1d1ccb5f582bcaf45f48e1a3a" + integrity sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ== + "minipass@^5.0.0 || ^6.0.2 || ^7.0.0": version "7.0.3" resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.3.tgz#05ea638da44e475037ed94d1c7efcc76a25e1974" @@ -9724,11 +9670,6 @@ neo-async@^2.6.2: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - node-abort-controller@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/node-abort-controller/-/node-abort-controller-3.0.1.tgz#f91fa50b1dee3f909afabb7e261b1e1d6b0cb74e" @@ -10081,11 +10022,6 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== -path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== - path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" @@ -10096,7 +10032,7 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-scurry@^1.10.1: +path-scurry@^1.10.1, path-scurry@^1.6.1: version "1.10.1" resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.1.tgz#9ba6bf5aa8500fe9fd67df4f0d9483b2b0bfc698" integrity sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ== @@ -10161,6 +10097,20 @@ pkg-dir@^4.1.0, pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" +playwright-core@1.38.1: + version "1.38.1" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.38.1.tgz#75a3c470aa9576b7d7c4e274de3d79977448ba08" + integrity sha512-tQqNFUKa3OfMf4b2jQ7aGLB8o9bS3bOY0yMEtldtC2+spf8QXG9zvXLTXUeRsoNuxEYMgLYR+NXfAa1rjKRcrg== + +playwright@1.38.1: + version "1.38.1" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.38.1.tgz#82ecd9bc4f4f64dbeee8a11c31793748e2528130" + integrity sha512-oRMSJmZrOu1FP5iu3UrCx8JEFRIMxLDM0c/3o4bpzU5Tz97BypefWf7TuTNPWeCe279TPal5RtPPZ+9lW/Qkow== + dependencies: + playwright-core "1.38.1" + optionalDependencies: + fsevents "2.3.2" + pngjs-image@~0.11.5: version "0.11.7" resolved "https://registry.yarnpkg.com/pngjs-image/-/pngjs-image-0.11.7.tgz#631dd59924569fc82ffebae0d5d53f85f54dab62" @@ -11286,12 +11236,12 @@ resize-observer-polyfill@^1.5.1: resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== -resolve-as-bin@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/resolve-as-bin/-/resolve-as-bin-2.1.0.tgz#25638f52e13203eae97125ab26f54082ab98c6e1" - integrity sha512-ileUuPIOP+xj+GS/d/EbB2XqRA8T2IeZTFkMggNIW2Mo72VyBMbq+HvIAxdW0ED9D44aEzJwHvUtbMm2PJT5Kw== +resolve-bin@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-bin/-/resolve-bin-1.0.1.tgz#795255591443e7007b21f2eadd8baa39b7378e50" + integrity sha512-4G9C3udcDB1c9qaopB+9dygm2bMyF2LeJ2JHBIc24N7ob+UuSSwX3ID1hQwpDEQep9ZRNdhT//rgEd6xbWA/SA== dependencies: - cross-spawn "^6.0.5" + find-parent-dir "~0.3.0" resolve-cwd@^3.0.0: version "3.0.0" @@ -11363,7 +11313,14 @@ rfdc@^1.3.0: resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== -rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: +rimraf@4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-4.4.0.tgz#c7a9f45bb2ec058d2e60ef9aca5167974313d605" + integrity sha512-X36S+qpCUR0HjXlkDe4NAOhS//aHH0Z+h8Ckf2auGJk3PTnx5rLmrHkwNdbVQuCSUhOyFrlRvFEllZOYE+yZGQ== + dependencies: + glob "^9.2.0" + +rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== @@ -11517,7 +11474,7 @@ selection-is-backward@^1.0.0: resolved "https://registry.yarnpkg.com/selection-is-backward/-/selection-is-backward-1.0.0.tgz#97a54633188a511aba6419fc5c1fa91b467e6be1" integrity sha512-C+6PCOO55NLCfS8uQjUKV/6E5XMuUcfOVsix5m0QqCCCKi495NgeQVNfWtAaD71NKHsdmFCJoXUGfir3qWdr9A== -semver@^5.3.0, semver@^5.5.0: +semver@^5.3.0: version "5.7.2" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== @@ -11574,13 +11531,6 @@ shallowequal@^1.1.0: resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg== - dependencies: - shebang-regex "^1.0.0" - shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -11588,11 +11538,6 @@ shebang-command@^2.0.0: dependencies: shebang-regex "^3.0.0" -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== - shebang-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" @@ -12320,11 +12265,6 @@ tsconfig-paths@^4.2.0: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@2.4.1, tslib@^2.0.0, tslib@^2.1.0, tslib@^2.4.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" - integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== - tslib@2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" @@ -12345,6 +12285,11 @@ tslib@^1.8.1, tslib@^1.9.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== +tslib@^2.0.0, tslib@^2.1.0, tslib@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" + integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== + tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" @@ -12729,11 +12674,6 @@ webpack-sources@^3.2.3: resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack-virtual-modules@^0.4.4: - version "0.4.6" - resolved "https://registry.yarnpkg.com/webpack-virtual-modules/-/webpack-virtual-modules-0.4.6.tgz#3e4008230731f1db078d9cb6f68baf8571182b45" - integrity sha512-5tyDlKLqPfMqjT3Q9TAqf2YqjwmnUleZwzJi1A5qXnlBCdj2AtOJ6wAWdglTIDOPgOiOrXeBeFcsQ8+aGQ6QbA== - webpack@^5.86.0: version "5.88.2" resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.88.2.tgz#f62b4b842f1c6ff580f3fcb2ed4f0b579f4c210e" @@ -12868,13 +12808,6 @@ which-typed-array@^1.1.8: has-tostringtag "^1.0.0" is-typed-array "^1.1.10" -which@^1.2.9: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - which@^2.0.1, which@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"