From cf286011e8a24ea6b5cc750106d5427b518ac107 Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Wed, 29 Nov 2023 11:27:20 +0000 Subject: [PATCH 01/39] chore: refactor and speed up resetting scenarios --- e2e/admin.ts | 16 ---- e2e/coupon-fraud.spec.ts | 7 +- e2e/credential-stuffing.spec.ts | 7 +- e2e/home.spec.ts | 2 +- e2e/loan-risk.spec.ts | 9 +- e2e/payment-fraud.spec.ts | 8 +- e2e/paywall.spec.ts | 8 +- e2e/personalization.spec.ts | 9 +- e2e/resetHelper.ts | 9 ++ e2e/scraping/protected.spec.ts | 2 +- e2e/scraping/unprotected.spec.ts | 2 +- src/client/components/common/Alert/Alert.tsx | 2 +- src/client/components/common/Cart/Cart.tsx | 2 +- .../components/common/Header/Header.tsx | 2 + .../common/MobileNavbar/MobileNavbar.tsx | 2 + .../common/UseCaseWrapper/UseCaseWrapper.tsx | 2 + src/client/components/paywall/ArticleGrid.tsx | 2 +- .../personalization/productCard.tsx | 2 +- .../personalization/searchComponents.tsx | 2 +- .../components/web-scraping/FlightCard.tsx | 2 +- src/client/hooks/useReset/useReset.tsx | 3 +- src/client/{e2eTestIDs.ts => testIDs.ts} | 5 + src/pages/admin/index.tsx | 92 ------------------- src/pages/index.tsx | 2 +- src/pages/loan-risk/index.tsx | 2 +- src/pages/paywall/article/[id]/index.tsx | 2 +- 26 files changed, 55 insertions(+), 148 deletions(-) delete mode 100644 e2e/admin.ts create mode 100644 e2e/resetHelper.ts rename src/client/{e2eTestIDs.ts => testIDs.ts} (90%) delete mode 100644 src/pages/admin/index.tsx diff --git a/e2e/admin.ts b/e2e/admin.ts deleted file mode 100644 index 772b7813..00000000 --- a/e2e/admin.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { BrowserContext } from '@playwright/test'; - -/** - * @param {import('@playwright/test').BrowserContext} context - * */ -export async function reset(context: BrowserContext) { - const page = await context.newPage(); - - await page.goto('/admin'); - - await page.click('#reset'); - - await page.waitForSelector('text=Reset all data for this visitorId'); - - await page.close(); -} diff --git a/e2e/coupon-fraud.spec.ts b/e2e/coupon-fraud.spec.ts index 517e7a0c..e18528ae 100644 --- a/e2e/coupon-fraud.spec.ts +++ b/e2e/coupon-fraud.spec.ts @@ -1,11 +1,10 @@ import { test } from '@playwright/test'; -import { reset } from './admin'; +import { resetScenarios } from './resetHelper'; test.describe('Coupon fraud', () => { - test.beforeEach(async ({ page, context }) => { - await reset(context); - + test.beforeEach(async ({ page }) => { await page.goto('/coupon-fraud'); + await resetScenarios(page); }); test('should apply correct coupon only once', async ({ page }) => { diff --git a/e2e/credential-stuffing.spec.ts b/e2e/credential-stuffing.spec.ts index f539dfb8..754c3138 100644 --- a/e2e/credential-stuffing.spec.ts +++ b/e2e/credential-stuffing.spec.ts @@ -1,11 +1,10 @@ import { test } from '@playwright/test'; -import { reset } from './admin'; +import { resetScenarios } from './resetHelper'; test.describe('Credential stuffing', () => { - test.beforeEach(async ({ page, context }) => { - await reset(context); - + test.beforeEach(async ({ page }) => { await page.goto('/credential-stuffing'); + await resetScenarios(page); }); test('should prevent login even with correct credentials', async ({ page }) => { diff --git a/e2e/home.spec.ts b/e2e/home.spec.ts index b5f1aecd..dd987564 100644 --- a/e2e/home.spec.ts +++ b/e2e/home.spec.ts @@ -1,5 +1,5 @@ import { expect, test } from '@playwright/test'; -import { TEST_IDS } from '../src/client/e2eTestIDs'; +import { TEST_IDS } from '../src/client/testIDs'; test.describe('Home page', () => { test('should list cards with use-cases', async ({ page }) => { diff --git a/e2e/loan-risk.spec.ts b/e2e/loan-risk.spec.ts index 848fac05..fafac2b1 100644 --- a/e2e/loan-risk.spec.ts +++ b/e2e/loan-risk.spec.ts @@ -1,6 +1,6 @@ import { Page, expect, test } from '@playwright/test'; -import { reset } from './admin'; -import { TEST_IDS } from '../src/client/e2eTestIDs'; +import { resetScenarios } from './resetHelper'; +import { TEST_IDS } from '../src/client/testIDs'; const testIds = TEST_IDS.loanRisk; @@ -40,10 +40,9 @@ test.describe('Loan risk', () => { }, ]; - test.beforeEach(async ({ page, context }) => { - await reset(context); - + test.beforeEach(async ({ page }) => { await page.goto('/loan-risk'); + await resetScenarios(page); }); test('should correctly calculate loan and approve it on first submit', async ({ page }) => { diff --git a/e2e/payment-fraud.spec.ts b/e2e/payment-fraud.spec.ts index 5bd081ea..e68a365a 100644 --- a/e2e/payment-fraud.spec.ts +++ b/e2e/payment-fraud.spec.ts @@ -1,9 +1,8 @@ import { Page, test } from '@playwright/test'; -import { reset } from './admin'; +import { resetScenarios } from './resetHelper'; async function waitForSuccessfulSubmit(page: Page) { await page.click('[type="submit"]'); - await page.waitForSelector('text="Thank you for your payment. Everything is OK."'); } @@ -13,10 +12,9 @@ async function waitForInvalidCardSubmit(page: Page) { } test.describe('Payment fraud', () => { - test.beforeEach(async ({ page, context }) => { - await reset(context); - + test.beforeEach(async ({ page }) => { await page.goto('/payment-fraud'); + await resetScenarios(page); }); test('should pass payment with prefilled details', async ({ page }) => { diff --git a/e2e/paywall.spec.ts b/e2e/paywall.spec.ts index fbe06d15..67d00fa2 100644 --- a/e2e/paywall.spec.ts +++ b/e2e/paywall.spec.ts @@ -1,11 +1,11 @@ import { test, expect } from '@playwright/test'; -import { reset } from './admin'; -import { TEST_IDS } from '../src/client/e2eTestIDs'; +import { resetScenarios } from './resetHelper'; +import { TEST_IDS } from '../src/client/testIDs'; test.describe('Paywall', () => { - test.beforeEach(async ({ page, context }) => { - await reset(context); + test.beforeEach(async ({ page }) => { await page.goto('/paywall'); + await resetScenarios(page); }); test('Should show two articles, then show a paywall', async ({ page }) => { diff --git a/e2e/personalization.spec.ts b/e2e/personalization.spec.ts index e096d014..b85b18fa 100644 --- a/e2e/personalization.spec.ts +++ b/e2e/personalization.spec.ts @@ -1,18 +1,17 @@ import { expect, test } from '@playwright/test'; -import { reset } from './admin'; -import { TEST_IDS } from '../src/client/e2eTestIDs'; +import { resetScenarios } from './resetHelper'; +import { TEST_IDS } from '../src/client/testIDs'; const CART_ID = TEST_IDS.common.cart; const PERS_ID = TEST_IDS.personalization; test.describe('Personalization', () => { - test.beforeEach(async ({ page, context }) => { - await reset(context); - + test.beforeEach(async ({ page }) => { await page.goto('/personalization', { waitUntil: 'networkidle', }); await page.click('text="Okay, I understand"'); + await resetScenarios(page); }); test('should add and remove items from cart', async ({ page }) => { diff --git a/e2e/resetHelper.ts b/e2e/resetHelper.ts new file mode 100644 index 00000000..956b7f3c --- /dev/null +++ b/e2e/resetHelper.ts @@ -0,0 +1,9 @@ +import { Page } from '@playwright/test'; +import { TEST_IDS } from '../src/client/testIDs'; + +// Assumes you already are on a use case page with the Reset button present +export async function resetScenarios(page: Page) { + await page.getByTestId(TEST_IDS.reset.resetButton).click(); + await page.waitForLoadState('networkidle'); + await page.getByTestId(TEST_IDS.reset.resetSuccess).waitFor({ timeout: 10000 }); +} diff --git a/e2e/scraping/protected.spec.ts b/e2e/scraping/protected.spec.ts index b2051963..13f3f6c1 100644 --- a/e2e/scraping/protected.spec.ts +++ b/e2e/scraping/protected.spec.ts @@ -1,5 +1,5 @@ import { expect, test } from '@playwright/test'; -import { TEST_IDS } from '../../src/client/e2eTestIDs'; +import { TEST_IDS } from '../../src/client/testIDs'; test.describe('Scraping flights', () => { test('is not possible with Bot detection on', async ({ page }) => { diff --git a/e2e/scraping/unprotected.spec.ts b/e2e/scraping/unprotected.spec.ts index 81fdda6b..01355b51 100644 --- a/e2e/scraping/unprotected.spec.ts +++ b/e2e/scraping/unprotected.spec.ts @@ -1,6 +1,6 @@ import { Locator, expect, test } from '@playwright/test'; import { writeFileSync } from 'fs'; -import { TEST_IDS } from './../../src/client/e2eTestIDs'; +import { TEST_IDS } from '../../src/client/testIDs'; const TEST_ID = TEST_IDS.webScraping; diff --git a/src/client/components/common/Alert/Alert.tsx b/src/client/components/common/Alert/Alert.tsx index bda2bd26..5a8a3b91 100644 --- a/src/client/components/common/Alert/Alert.tsx +++ b/src/client/components/common/Alert/Alert.tsx @@ -6,7 +6,7 @@ import WarningIcon from './warning.svg'; import styles from './alert.module.scss'; import Image from 'next/image'; import classNames from 'classnames'; -import { TEST_IDS } from '../../../e2eTestIDs'; +import { TEST_IDS } from '../../../testIDs'; type AlertProps = { severity: Severity; diff --git a/src/client/components/common/Cart/Cart.tsx b/src/client/components/common/Cart/Cart.tsx index 7bc2ea1d..954e64f1 100644 --- a/src/client/components/common/Cart/Cart.tsx +++ b/src/client/components/common/Cart/Cart.tsx @@ -4,7 +4,7 @@ import styles from './cart.module.scss'; import { ButtonMinusSvg } from '../../../img/buttonMinusSvg'; import { ButtonPlusSvg } from '../../../img/buttonPlusSvg'; import Image from 'next/image'; -import { TEST_IDS } from '../../../e2eTestIDs'; +import { TEST_IDS } from '../../../testIDs'; const format$ = (price: number) => { return new Intl.NumberFormat('en-US', { diff --git a/src/client/components/common/Header/Header.tsx b/src/client/components/common/Header/Header.tsx index ee88983d..ac922570 100644 --- a/src/client/components/common/Header/Header.tsx +++ b/src/client/components/common/Header/Header.tsx @@ -16,6 +16,7 @@ import Link from 'next/link'; import Button from '../Button/Button'; import { useReset } from '../../../hooks/useReset/useReset'; import { Tooltip } from '@mui/material'; +import { TEST_IDS } from '../../../testIDs'; interface HeaderProps { notificationBar?: { @@ -113,6 +114,7 @@ export default function Header({ notificationBar, darkMode }: HeaderProps) { onClick={() => mutate()} disabled={isResetLoading} id="click_top_nav_restart" + data-test={TEST_IDS.reset.resetButton} > Restart Restart button diff --git a/src/client/components/common/MobileNavbar/MobileNavbar.tsx b/src/client/components/common/MobileNavbar/MobileNavbar.tsx index 45b8b406..92019cea 100644 --- a/src/client/components/common/MobileNavbar/MobileNavbar.tsx +++ b/src/client/components/common/MobileNavbar/MobileNavbar.tsx @@ -7,6 +7,7 @@ import DropdownMenu from '../DropdownMenu/DropdownMenu'; import Image from 'next/image'; import Restart from '../../../img/restart.svg'; import { useReset } from '../../../hooks/useReset/useReset'; +import { TEST_IDS } from '../../../testIDs'; interface MobileNavbarProps { darkMode?: boolean; @@ -28,6 +29,7 @@ export default function MobileNavbar({ darkMode, closeMobileMenu }: MobileNavbar size={'medium'} title="Click Restart to remove all information obtained from this browser. This will reenable some scenarios for you if you were locked out of a specific action." buttonId="click_top_nav_restart" + data-test={TEST_IDS.reset.resetButton} > Restart Restart button diff --git a/src/client/components/common/UseCaseWrapper/UseCaseWrapper.tsx b/src/client/components/common/UseCaseWrapper/UseCaseWrapper.tsx index c45ebd6c..bf98effa 100644 --- a/src/client/components/common/UseCaseWrapper/UseCaseWrapper.tsx +++ b/src/client/components/common/UseCaseWrapper/UseCaseWrapper.tsx @@ -12,6 +12,7 @@ import { useReset } from '../../../hooks/useReset/useReset'; import classNames from 'classnames'; import { RestartHint } from './RestartHint'; import { SEO } from '../seo'; +import { TEST_IDS } from '../../../testIDs'; type UseCaseWrapperProps = { useCase: Partial; @@ -49,6 +50,7 @@ export const UseCaseWrapper: FunctionComponent = ({ pulseResetButton && styles.pulse, ])} onClick={() => !isLoading && mutate()} + data-test={TEST_IDS.reset.resetButton} >
Restart
Reset scenario diff --git a/src/client/components/paywall/ArticleGrid.tsx b/src/client/components/paywall/ArticleGrid.tsx index 8273f665..4af25673 100644 --- a/src/client/components/paywall/ArticleGrid.tsx +++ b/src/client/components/paywall/ArticleGrid.tsx @@ -2,7 +2,7 @@ import classNames from 'classnames'; import { useRouter } from 'next/router'; import { FunctionComponent } from 'react'; import { ArticleData } from '../../../server/paywall/articles'; -import { TEST_IDS } from '../../e2eTestIDs'; +import { TEST_IDS } from '../../testIDs'; import Image from 'next/image'; import styles from './articleGrid.module.scss'; import BylineDot from './dot.svg'; diff --git a/src/client/components/personalization/productCard.tsx b/src/client/components/personalization/productCard.tsx index 320540b7..af512f44 100644 --- a/src/client/components/personalization/productCard.tsx +++ b/src/client/components/personalization/productCard.tsx @@ -8,7 +8,7 @@ import Image from 'next/image'; import styles from './productCard.module.scss'; import Button from '../common/Button/Button'; import HeartIcon from '../../img/heart.svg'; -import { TEST_IDS } from '../../e2eTestIDs'; +import { TEST_IDS } from '../../testIDs'; import { UserCartItem } from '../../../server/personalization/database'; type Product = { diff --git a/src/client/components/personalization/searchComponents.tsx b/src/client/components/personalization/searchComponents.tsx index 1c563649..ffc77c41 100644 --- a/src/client/components/personalization/searchComponents.tsx +++ b/src/client/components/personalization/searchComponents.tsx @@ -2,7 +2,7 @@ import { FunctionComponent } from 'react'; import Image from 'next/image'; import SearchIcon from '../../img/search.svg'; import styles from './searchComponents.module.scss'; -import { TEST_IDS } from '../../e2eTestIDs'; +import { TEST_IDS } from '../../testIDs'; type SearchProps = { search: string; diff --git a/src/client/components/web-scraping/FlightCard.tsx b/src/client/components/web-scraping/FlightCard.tsx index a8476c88..51a8e8eb 100644 --- a/src/client/components/web-scraping/FlightCard.tsx +++ b/src/client/components/web-scraping/FlightCard.tsx @@ -6,7 +6,7 @@ import AirCanada from '../../img/airCanada.svg'; import Image from 'next/image'; import Button from '../common/Button/Button'; import StarIcon from '../../img/star.svg'; -import { TEST_IDS } from '../../e2eTestIDs'; +import { TEST_IDS } from '../../testIDs'; import { HOUR_MS, MINUTE_MS } from '../../../shared/timeUtils'; const TEST_ID = TEST_IDS.webScraping; diff --git a/src/client/hooks/useReset/useReset.tsx b/src/client/hooks/useReset/useReset.tsx index a8691abc..5a15dd42 100644 --- a/src/client/hooks/useReset/useReset.tsx +++ b/src/client/hooks/useReset/useReset.tsx @@ -5,6 +5,7 @@ import { useSnackbar } from 'notistack'; import styles from './userReset.module.scss'; import { useRouter } from 'next/router'; import { PLAYGROUND_METADATA, USE_CASES } from '../../components/common/content'; +import { TEST_IDS } from '../../testIDs'; type UseResetParams = { onError?: () => void; @@ -44,7 +45,7 @@ export const useReset = ({ onError, onSuccess }: UseResetParams) => { onSuccess ?? ((data) => { enqueueSnackbar( -
+

Scenarios reset successfully!

{data.message}

, { diff --git a/src/client/e2eTestIDs.ts b/src/client/testIDs.ts similarity index 90% rename from src/client/e2eTestIDs.ts rename to src/client/testIDs.ts index 4a68af61..b2918c3d 100644 --- a/src/client/e2eTestIDs.ts +++ b/src/client/testIDs.ts @@ -11,6 +11,11 @@ export const TEST_IDS = { }, alert: 'alert', }, + reset: { + resetButton: 'resetButton', + resetSuccess: 'resetSuccess', + resetError: 'resetError', + }, homepageCard: { useCaseTitle: 'useCaseTitle', }, diff --git a/src/pages/admin/index.tsx b/src/pages/admin/index.tsx deleted file mode 100644 index 737207d9..00000000 --- a/src/pages/admin/index.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import { useState } from 'react'; -import Alert from '@mui/material/Alert'; -import Button from '@mui/material/Button'; -import { UseCaseWrapper } from '../../client/components/common/UseCaseWrapper/UseCaseWrapper'; -import { Severity } from '../../server/checkResult'; -import { useVisitorData } from '@fingerprintjs/fingerprintjs-pro-react'; - -export default function Index() { - const [statusMessage, setStatusMessage] = useState(); - const [severity, setSeverity] = useState(); - const [isWaitingForResponse, setIsWaitingForResponse] = useState(false); - const [httpResponseStatus, setHttpResponseStatus] = useState(); - - const { getData } = useVisitorData({ ignoreCache: true }, { immediate: false }); - - async function handleSubmit(e: React.FormEvent) { - e.preventDefault(); - setIsWaitingForResponse(true); - - const fpResult = await getData(); - const visitorId = fpResult?.visitorId; - const requestId = fpResult?.requestId; - - const orderData = { - visitorId, - requestId, - }; - - const response = await fetch('/api/admin/reset', { - method: 'POST', - body: JSON.stringify(orderData), - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, - }); - - const responseJson = await response.json(); - const responseStatus = response.status; - setStatusMessage(responseJson.message); - setSeverity(responseJson.severity); - setHttpResponseStatus(responseStatus); - setIsWaitingForResponse(false); - } - - return ( - - On this page, you can remove all info obtained from this browser. This will reenable some scenarios for you - if you were locked out of a specific action. -

- ), - doNotMentionResetButton: true, - }} - contentSx={{ - minHeight: '40vh', - }} - > -
- -
- {httpResponseStatus ? ( - - {statusMessage} - - ) : null} -
- ); -} diff --git a/src/pages/index.tsx b/src/pages/index.tsx index c7635e25..435b4155 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -5,7 +5,7 @@ import Container from '../client/components/common/Container'; import { HOMEPAGE_CARDS } from '../client/components/common/content'; import LinkArrow from '../client/img/externalLinkArrow.svg'; import Image from 'next/image'; -import { TEST_IDS } from '../client/e2eTestIDs'; +import { TEST_IDS } from '../client/testIDs'; import { Fragment } from 'react'; import { SEO } from '../client/components/common/seo'; import { useRouter } from 'next/router'; diff --git a/src/pages/loan-risk/index.tsx b/src/pages/loan-risk/index.tsx index 44ada1c0..bcaa8254 100644 --- a/src/pages/loan-risk/index.tsx +++ b/src/pages/loan-risk/index.tsx @@ -18,7 +18,7 @@ import { Slider } from '../../client/components/common/Slider/Slider'; import { NumberInputWithUnits } from '../../client/components/common/InputNumberWithUnits/InputNumberWithUnits'; import styles from './loanRisk.module.scss'; import classNames from 'classnames'; -import { TEST_IDS } from '../../client/e2eTestIDs'; +import { TEST_IDS } from '../../client/testIDs'; import { useVisitorData } from '@fingerprintjs/fingerprintjs-pro-react'; type SliderFieldProps = { diff --git a/src/pages/paywall/article/[id]/index.tsx b/src/pages/paywall/article/[id]/index.tsx index aff98fcc..ead05d7a 100644 --- a/src/pages/paywall/article/[id]/index.tsx +++ b/src/pages/paywall/article/[id]/index.tsx @@ -12,7 +12,7 @@ import { ARTICLES } from '../../../../server/paywall/articles'; import { useVisitorData } from '@fingerprintjs/fingerprintjs-pro-react'; import { useQuery } from 'react-query'; import { ArticleResponse } from '../../../api/paywall/article/[id]'; -import { TEST_IDS } from '../../../../client/e2eTestIDs'; +import { TEST_IDS } from '../../../../client/testIDs'; import { ArticleGrid, Byline } from '../../../../client/components/paywall/ArticleGrid'; function ArticleSkeleton({ animation = false }: { animation?: SkeletonTypeMap['props']['animation'] }) { From fc38c4a9ffaf453fd75f17705dea7e5b94a92639 Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Wed, 29 Nov 2023 13:23:24 +0000 Subject: [PATCH 02/39] chore: use default attribute data-testid --- e2e/home.spec.ts | 4 +--- e2e/loan-risk.spec.ts | 2 +- e2e/personalization.spec.ts | 8 +++++--- e2e/playground.spec.ts | 8 ++++---- playwright.config.js | 2 -- src/client/components/CodeSnippet.tsx | 2 +- src/client/components/common/Alert/Alert.tsx | 2 +- src/client/components/common/Cart/Cart.tsx | 14 +++++++------- src/client/components/common/Header/Header.tsx | 2 +- .../common/MobileNavbar/MobileNavbar.tsx | 2 +- .../common/UseCaseWrapper/UseCaseWrapper.tsx | 2 +- src/client/components/paywall/ArticleGrid.tsx | 2 +- .../components/personalization/productCard.tsx | 8 ++++---- .../personalization/searchComponents.tsx | 4 ++-- src/client/components/playground/RefreshButton.tsx | 2 +- src/client/components/web-scraping/FlightCard.tsx | 14 +++++++------- src/client/hooks/useReset/useReset.tsx | 2 +- src/pages/index.tsx | 2 +- src/pages/loan-risk/index.tsx | 2 +- src/pages/paywall/article/[id]/index.tsx | 4 ++-- 20 files changed, 43 insertions(+), 45 deletions(-) diff --git a/e2e/home.spec.ts b/e2e/home.spec.ts index dd987564..23b440fc 100644 --- a/e2e/home.spec.ts +++ b/e2e/home.spec.ts @@ -4,9 +4,7 @@ import { TEST_IDS } from '../src/client/testIDs'; test.describe('Home page', () => { test('should list cards with use-cases', async ({ page }) => { await page.goto('/'); - - const cards = await page.locator(`[data-test="${TEST_IDS.homepageCard.useCaseTitle}"]`); - + const cards = await page.getByTestId(TEST_IDS.homepageCard.useCaseTitle); expect(await cards.count()).toBeGreaterThan(5); }); }); diff --git a/e2e/loan-risk.spec.ts b/e2e/loan-risk.spec.ts index fafac2b1..6759977c 100644 --- a/e2e/loan-risk.spec.ts +++ b/e2e/loan-risk.spec.ts @@ -50,7 +50,7 @@ test.describe('Loan risk', () => { await page.fill('[name="monthlyIncome"]', '20000'); await page.fill('[name="loanDuration"]', '4'); - const monthInstallmentValue = page.locator(`[data-test="${testIds.monthlyInstallmentValue}"]`); + const monthInstallmentValue = page.getByTestId(testIds.monthlyInstallmentValue); await expect(monthInstallmentValue).toHaveText('$ 575'); await waitForSuccessfulSubmit(page); diff --git a/e2e/personalization.spec.ts b/e2e/personalization.spec.ts index b85b18fa..4712963c 100644 --- a/e2e/personalization.spec.ts +++ b/e2e/personalization.spec.ts @@ -30,9 +30,11 @@ test.describe('Personalization', () => { await product.getByTestId(PERS_ID.addToCart).click(); const cartItem = cartItems.first(); - await expect(cartItem.getByTestId(CART_ID.cartItemName)).toHaveText( - (await product.getByTestId(PERS_ID.coffeeProductName).textContent()) ?? 'Product name not found', - ); + const cartItemName = (await cartItem.getByTestId(CART_ID.cartItemName).textContent()) ?? 'Cart item name not found'; + const productName = + (await product.getByTestId(PERS_ID.coffeeProductName).textContent()) ?? 'Product name not found'; + expect(cartItemName).toBe(productName); + const subTotal = await getSubTotal(); expect(subTotal).toBe(productPrice); diff --git a/e2e/playground.spec.ts b/e2e/playground.spec.ts index f8e97f57..06033fd7 100644 --- a/e2e/playground.spec.ts +++ b/e2e/playground.spec.ts @@ -4,18 +4,18 @@ import { isAgentResponse, isServerResponse } from './zodUtils'; const getAgentResponse = async (page: Page) => { const agentResponse = - (await page.textContent(`[data-test="${PLAYGROUND_TAG.agentResponseJSON}"]`)) ?? 'Agent response not found'; + (await (await page.getByTestId(PLAYGROUND_TAG.agentResponseJSON)).textContent()) ?? 'Agent response not found'; return JSON.parse(agentResponse); }; const getServerResponse = async (page: Page) => { const serverResponse = - (await page.textContent(`[data-test="${PLAYGROUND_TAG.serverResponseJSON}"]`)) ?? 'Server response not found'; + (await (await page.getByTestId(PLAYGROUND_TAG.serverResponseJSON)).textContent()) ?? 'Server response not found'; return JSON.parse(serverResponse); }; const clickRefreshButton = async (page: Page) => { - await page.click(`[data-test="${PLAYGROUND_TAG.refreshButton}"]`); + await page.getByTestId(PLAYGROUND_TAG.refreshButton).first().click(); await page.waitForLoadState('networkidle'); await page.waitForTimeout(3000); }; @@ -28,7 +28,7 @@ test.describe('Playground page page', () => { test('Page renders basic skeleton elements', async ({ page }) => { await page.waitForSelector('text="Fingerprint Pro Playground"'); await page.waitForSelector('text="Welcome, your visitor ID is"'); - await page.waitForSelector(`[data-test="${PLAYGROUND_TAG.refreshButton}"]`); + await page.waitForSelector(`[data-testid="${PLAYGROUND_TAG.refreshButton}"]`); await page.waitForSelector('text="Base signals (Pro plan)"'); await page.waitForSelector('text="Smart signals (Pro Plus plan)"'); diff --git a/playwright.config.js b/playwright.config.js index 02dd8ffa..fd13d738 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -40,8 +40,6 @@ module.exports = defineConfig({ /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ trace: 'on-first-retry', - - testIdAttribute: 'data-test', }, /* Configure projects for major browsers */ diff --git a/src/client/components/CodeSnippet.tsx b/src/client/components/CodeSnippet.tsx index 3e6462ac..be7025cf 100644 --- a/src/client/components/CodeSnippet.tsx +++ b/src/client/components/CodeSnippet.tsx @@ -48,7 +48,7 @@ export function CodeSnippet({ customStyle={PRISM_CUSTOM_STYLE} codeTagProps={PRISM_CODE_TAG_PROPS} className={className} - data-test={dataTestId} + data-testid={dataTestId} > {children} diff --git a/src/client/components/common/Alert/Alert.tsx b/src/client/components/common/Alert/Alert.tsx index 5a8a3b91..d4e9e5e6 100644 --- a/src/client/components/common/Alert/Alert.tsx +++ b/src/client/components/common/Alert/Alert.tsx @@ -30,7 +30,7 @@ const Alert: FunctionComponent = ({ severity, children, className, d return (
diff --git a/src/client/components/common/Cart/Cart.tsx b/src/client/components/common/Cart/Cart.tsx index 954e64f1..4de53fa4 100644 --- a/src/client/components/common/Cart/Cart.tsx +++ b/src/client/components/common/Cart/Cart.tsx @@ -28,21 +28,21 @@ const CartProduct: FunctionComponent<{ product: CartProduct }> = ({ product: { name, subheadline, price, image, count, increaseCount, decreaseCount }, }) => { return ( -
+
{name}
-
+
{name}
{subheadline}
-
+
{format$(price)}
- - {String(count).padStart(2, '0')} - + + {String(count).padStart(2, '0')} +
@@ -72,7 +72,7 @@ export const Cart: FunctionComponent = ({ items, discount, taxPerItem
Subtotal - + {format$(subTotal)}
diff --git a/src/client/components/common/Header/Header.tsx b/src/client/components/common/Header/Header.tsx index ac922570..950034a8 100644 --- a/src/client/components/common/Header/Header.tsx +++ b/src/client/components/common/Header/Header.tsx @@ -114,7 +114,7 @@ export default function Header({ notificationBar, darkMode }: HeaderProps) { onClick={() => mutate()} disabled={isResetLoading} id="click_top_nav_restart" - data-test={TEST_IDS.reset.resetButton} + data-testid={TEST_IDS.reset.resetButton} > Restart Restart button diff --git a/src/client/components/common/MobileNavbar/MobileNavbar.tsx b/src/client/components/common/MobileNavbar/MobileNavbar.tsx index 92019cea..446acef7 100644 --- a/src/client/components/common/MobileNavbar/MobileNavbar.tsx +++ b/src/client/components/common/MobileNavbar/MobileNavbar.tsx @@ -29,7 +29,7 @@ export default function MobileNavbar({ darkMode, closeMobileMenu }: MobileNavbar size={'medium'} title="Click Restart to remove all information obtained from this browser. This will reenable some scenarios for you if you were locked out of a specific action." buttonId="click_top_nav_restart" - data-test={TEST_IDS.reset.resetButton} + data-testid={TEST_IDS.reset.resetButton} > Restart Restart button diff --git a/src/client/components/common/UseCaseWrapper/UseCaseWrapper.tsx b/src/client/components/common/UseCaseWrapper/UseCaseWrapper.tsx index bf98effa..e7e7e9a8 100644 --- a/src/client/components/common/UseCaseWrapper/UseCaseWrapper.tsx +++ b/src/client/components/common/UseCaseWrapper/UseCaseWrapper.tsx @@ -50,7 +50,7 @@ export const UseCaseWrapper: FunctionComponent = ({ pulseResetButton && styles.pulse, ])} onClick={() => !isLoading && mutate()} - data-test={TEST_IDS.reset.resetButton} + data-testid={TEST_IDS.reset.resetButton} >
Restart
Reset scenario diff --git a/src/client/components/paywall/ArticleGrid.tsx b/src/client/components/paywall/ArticleGrid.tsx index 4af25673..88ee8431 100644 --- a/src/client/components/paywall/ArticleGrid.tsx +++ b/src/client/components/paywall/ArticleGrid.tsx @@ -47,7 +47,7 @@ export const ArticleCard: FunctionComponent = ({ article, embe
router.push(link)} - data-test={TEST_IDS.paywall.articleCard} + data-testid={TEST_IDS.paywall.articleCard} >
diff --git a/src/client/components/personalization/productCard.tsx b/src/client/components/personalization/productCard.tsx index af512f44..92a358fc 100644 --- a/src/client/components/personalization/productCard.tsx +++ b/src/client/components/personalization/productCard.tsx @@ -68,7 +68,7 @@ export const ProductCard: FunctionComponent<{ product: Product }> = ({ product } ); return ( -
+
{product.name} = ({ product } />
-
+
{product.name}
Big
@@ -87,7 +87,7 @@ export const ProductCard: FunctionComponent<{ product: Product }> = ({ product }
${product.price.toFixed(2)} @@ -96,7 +96,7 @@ export const ProductCard: FunctionComponent<{ product: Product }> = ({ product } {cartItem ? ( ) : ( - )} diff --git a/src/client/components/personalization/searchComponents.tsx b/src/client/components/personalization/searchComponents.tsx index ffc77c41..7b4d146a 100644 --- a/src/client/components/personalization/searchComponents.tsx +++ b/src/client/components/personalization/searchComponents.tsx @@ -19,7 +19,7 @@ export const Search: FunctionComponent = ({ search, setSearch }) => placeholder="Search for your favorite coffee" onChange={(e) => setSearch(e.target.value)} value={search} - data-test={TEST_IDS.personalization.search} + data-testid={TEST_IDS.personalization.search} />
@@ -48,7 +48,7 @@ export const SearchHistory: FunctionComponent = ({ searchHis key={index} onClick={() => setSearchHistory(searchTerm)} className={styles.searchTerm} - data-test={TEST_IDS.personalization.searchHistoryItem} + data-testid={TEST_IDS.personalization.searchHistoryItem} > {searchTerm} diff --git a/src/client/components/playground/RefreshButton.tsx b/src/client/components/playground/RefreshButton.tsx index d6013f82..eca3db7f 100644 --- a/src/client/components/playground/RefreshButton.tsx +++ b/src/client/components/playground/RefreshButton.tsx @@ -13,7 +13,7 @@ const RefreshButton: FunctionComponent<{ loading: boolean; getAgentData: () => v sx={{ mr: 'auto', ml: 'auto', mt: (t) => t.spacing(4), mb: (t) => t.spacing(8), display: 'flex' }} onClick={() => getAgentData()} disabled={loading} - data-test={PLAYGROUND_TAG.refreshButton} + data-testid={PLAYGROUND_TAG.refreshButton} > {loading ? ( <> diff --git a/src/client/components/web-scraping/FlightCard.tsx b/src/client/components/web-scraping/FlightCard.tsx index 51a8e8eb..3e96c3ca 100644 --- a/src/client/components/web-scraping/FlightCard.tsx +++ b/src/client/components/web-scraping/FlightCard.tsx @@ -63,16 +63,16 @@ const SingleFlight: FunctionComponent = ({
- {airline} + {airline}
-
+
{fromCode}
{fromCity}
-
+
{formatTime(departureTime)}
@@ -81,11 +81,11 @@ const SingleFlight: FunctionComponent = ({
{formatDurationTime(arrivalTime - departureTime)}
-
+
{toCode}
{toCity}
-
+
{formatTime(arrivalTime)}
@@ -119,7 +119,7 @@ export const FlightCard: FunctionComponent = ({ flight }) => { const total = flight.price; return ( -
+
= ({ flight }) => {
Total - ${total} + ${total}
diff --git a/src/client/hooks/useReset/useReset.tsx b/src/client/hooks/useReset/useReset.tsx index 5a15dd42..955ba368 100644 --- a/src/client/hooks/useReset/useReset.tsx +++ b/src/client/hooks/useReset/useReset.tsx @@ -45,7 +45,7 @@ export const useReset = ({ onError, onSuccess }: UseResetParams) => { onSuccess ?? ((data) => { enqueueSnackbar( -
+

Scenarios reset successfully!

{data.message}

, { diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 435b4155..33a800b3 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -38,7 +38,7 @@ export default function Index() {
router.push(card.url)}>
- + {card.title}
diff --git a/src/pages/loan-risk/index.tsx b/src/pages/loan-risk/index.tsx index bcaa8254..595bfd0c 100644 --- a/src/pages/loan-risk/index.tsx +++ b/src/pages/loan-risk/index.tsx @@ -159,7 +159,7 @@ export default function LoanRisk({ embed }: CustomPageProps) { />
Your monthly installment is: -
+
$ {monthlyInstallment.toFixed(0)}
diff --git a/src/pages/paywall/article/[id]/index.tsx b/src/pages/paywall/article/[id]/index.tsx index ead05d7a..a3fa8047 100644 --- a/src/pages/paywall/article/[id]/index.tsx +++ b/src/pages/paywall/article/[id]/index.tsx @@ -45,7 +45,7 @@ export default function Article({ embed }: CustomPageProps) { return (
-
+
Back to articles @@ -63,7 +63,7 @@ export default function Article({ embed }: CustomPageProps) { )} {article && ( -
+
{article.title}

{article.title}

From d370d768a131efa547af69ccaf14c85aab4fac3d Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Tue, 5 Dec 2023 20:19:39 +0000 Subject: [PATCH 03/39] feat: turn pro signals into links --- src/pages/playground/index.tsx | 75 +++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 29 deletions(-) diff --git a/src/pages/playground/index.tsx b/src/pages/playground/index.tsx index bae33003..46ac6361 100644 --- a/src/pages/playground/index.tsx +++ b/src/pages/playground/index.tsx @@ -1,4 +1,4 @@ -import { useMemo } from 'react'; +import { FunctionComponent, ReactNode, useMemo } from 'react'; import { UseCaseWrapper } from '../../client/components/common/UseCaseWrapper/UseCaseWrapper'; import { Accordion, @@ -30,6 +30,18 @@ import { getLocationName } from '../../shared/utils/getLocationName'; import { PLAYGROUND_TAG } from '../../client/components/playground/playgroundTags'; import { CustomPageProps } from '../_app'; import { PLAYGROUND_METADATA } from '../../client/components/common/content'; +import Link from 'next/link'; +import externalLinkArrow from '../../client/img/externalLinkArrow.svg'; +import Image from 'next/image'; + +const DocsLink: FunctionComponent<{ children: ReactNode; href: string }> = ({ children, href }) => { + return ( + + {children} + + + ); +}; // Map cannot be server-side rendered const Map = dynamic(() => import('../../client/components/playground/Map'), { ssr: false }); @@ -81,7 +93,10 @@ function Playground() { const baseSignals: TableCellData[][] = [ [ { - content: ['Visitor ID', A unique and stable identifier of your browser.], + content: [ + 'Visitor ID', + A unique and stable identifier for your browser or mobile device., + ], }, { content: agentResponse?.visitorId }, ], @@ -119,7 +134,9 @@ function Playground() { const smartSignalsProPlus: TableCellData[][] = [ [ { - content: ['Geolocation', Your geographic location based on your IP address.], + content: ( + Geolocation + ), }, { content: ( @@ -136,7 +153,13 @@ function Playground() { }, ], [ - { content: 'Incognito Mode' }, + { + content: ( + + Incognito Mode + + ), + }, { content: agentResponse?.incognito ? 'You are incognito šŸ•¶' : 'Not detected', cellStyle: { @@ -147,11 +170,9 @@ function Playground() { [ { content: [ - 'Bot', - - Fingerprint detects if the browser is driven by a human, a browser automation tool like Selenium or headless - Chrome (bad bot) or search engine crawler (good bot). - , + + Bot Detection + , ], }, { @@ -164,11 +185,9 @@ function Playground() { [ { content: [ - 'VPN', - - The visitor is using a VPN (browser timezone does not match IP address timezone or IP address is owned by a - public VPN service provider). - , + + VPN Detection + , ], }, { @@ -179,11 +198,9 @@ function Playground() { [ { content: [ - 'Browser Tampering', - - Browser tampering was detected according to our internal thresholds. For example, if the reported user agent - is not consistent with other browser attributes. - , + + Browser Tampering + , ], }, { @@ -195,10 +212,11 @@ function Playground() { ], [ { - content: [ - 'Virtual machine', - The browser is running inside a virtual machine (e.g., VMWare)., - ], + content: ( + + Virtual Machine + + ), }, { content: usedIdentificationEvent?.products?.virtualMachine?.data?.result === true ? 'Yes ā˜ļøšŸ’»' : 'Not detected', @@ -209,12 +227,11 @@ function Playground() { ], [ { - content: [ - 'Privacy settings', - - The visitor is using a privacy aware browser (e.g., Tor) or a browser in which fingerprinting is blocked. - , - ], + content: ( + + Privacy Settings + + ), }, { content: From 0f89f2ce76a405d375ece4b0473efc19bc9a91ec Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Wed, 6 Dec 2023 20:21:36 +0000 Subject: [PATCH 04/39] feat: turn enterprise signals into links --- .../playground/IpBlocklistResult.tsx | 6 + src/pages/playground/index.tsx | 119 ++++++++++-------- src/pages/playground/playground.module.scss | 20 +++ 3 files changed, 91 insertions(+), 54 deletions(-) create mode 100644 src/pages/playground/playground.module.scss diff --git a/src/client/components/playground/IpBlocklistResult.tsx b/src/client/components/playground/IpBlocklistResult.tsx index 517b48be..3df5f98c 100644 --- a/src/client/components/playground/IpBlocklistResult.tsx +++ b/src/client/components/playground/IpBlocklistResult.tsx @@ -15,6 +15,12 @@ const IpBlocklistResult: FunctionComponent<{ event: EventResponse | undefined }> if (blocklistData?.details?.emailSpam) { return <>Your IP is on a blocklist šŸš« (it was part of a spam attack); } + if (event?.products?.tor?.data?.result === true) { + return <>Your IP is a Tor exit node šŸ§…; + } + if (event?.products?.proxy?.data?.result === true) { + return <>Your IP is used by a public proxy provider šŸ”„; + } return <>Unknown; }; diff --git a/src/pages/playground/index.tsx b/src/pages/playground/index.tsx index 46ac6361..172242fb 100644 --- a/src/pages/playground/index.tsx +++ b/src/pages/playground/index.tsx @@ -33,12 +33,17 @@ import { PLAYGROUND_METADATA } from '../../client/components/common/content'; import Link from 'next/link'; import externalLinkArrow from '../../client/img/externalLinkArrow.svg'; import Image from 'next/image'; +import styles from './playground.module.scss'; -const DocsLink: FunctionComponent<{ children: ReactNode; href: string }> = ({ children, href }) => { +const DocsLink: FunctionComponent<{ children: ReactNode; href: string; style?: React.CSSProperties }> = ({ + children, + href, + style, +}) => { return ( - + {children} - + ); }; @@ -105,10 +110,7 @@ function Playground() { [{ content: 'IP Address' }, { content: }], [ { - content: [ - 'Last seen', - The last time the Fingerprint has encountered that visitor ID (globally)., - ], + content: Last seen, }, { content: agentResponse?.lastSeenAt.global ? timeAgoLabel(agentResponse?.lastSeenAt.global) : 'Unknown', @@ -117,11 +119,10 @@ function Playground() { [ { content: [ - 'Confidence Score', - - A value between 0 and 1 representing how confident we are about this identification, depending on the - available signals. - , + + Confidence
+ Score +
, ], }, { @@ -170,9 +171,7 @@ function Playground() { [ { content: [ - - Bot Detection - , + Bot, ], }, { @@ -185,9 +184,7 @@ function Playground() { [ { content: [ - - VPN Detection - , + VPN, ], }, { @@ -247,89 +244,103 @@ function Playground() { [ { content: [ - 'IP Blocklist', - - IP address was part of a known email (SMTP) spam attack or network (SSH/HTTP) attack.{' '} - , + + IP Blocklist + , ], }, { content: , cellStyle: { - backgroundColor: usedIdentificationEvent?.products?.ipBlocklist?.data?.result === true ? RED : GREEN, + backgroundColor: + usedIdentificationEvent?.products?.ipBlocklist?.data?.result || + usedIdentificationEvent?.products?.proxy?.data?.result || + usedIdentificationEvent?.products?.tor?.data?.result + ? RED + : GREEN, }, }, ], [ { - content: ['Proxy', The request IP address is used by a public proxy provider.], - }, - { - content: - usedIdentificationEvent?.products?.proxy?.data?.result === true ? 'You are using a proxy šŸ”„' : 'Not detected', - cellStyle: { backgroundColor: usedIdentificationEvent?.products?.proxy?.data?.result === true ? RED : GREEN }, + content: [ + + Raw device attributes + , + ], }, + { content: 'Applicable only to browsers. See the JSON below.', cellStyle: { backgroundColor: GRAY } }, ], [ { - content: ['Tor Network', The request IP address is a known Tor network exit node.], - }, - { - content: - usedIdentificationEvent?.products?.tor?.data?.result === true ? 'You are using Tor šŸ§…' : 'Not detected', - cellStyle: { backgroundColor: usedIdentificationEvent?.products?.tor?.data?.result === true ? RED : GREEN }, + content: [ + + App is instrumented by Frida + , + ], }, + { content: 'Applicable only for iOS and Android devices', cellStyle: { backgroundColor: GRAY } }, ], [ { - content: ['Android Emulator', Android specific emulator detection.], + content: [ + + Factory Reset Timestamp + , + ], }, - { content: 'Not applicable to browsers', cellStyle: { backgroundColor: GRAY } }, + { content: 'Applicable only for iOS and Android devices', cellStyle: { backgroundColor: GRAY } }, ], [ { content: [ - 'Android Tampering', - Android specific root management apps detection, for example, Magisk., + + Location spoofing + , ], }, - { content: 'Not applicable to browsers', cellStyle: { backgroundColor: GRAY } }, + { content: 'Applicable only for iOS and Android devices', cellStyle: { backgroundColor: GRAY } }, ], [ { content: [ - 'Android Cloned Application', - Android-specific detection of a fully cloned application present on the device., + + Cloned App + , ], }, - { content: 'Not applicable to browsers', cellStyle: { backgroundColor: GRAY } }, + { content: 'Applicable only to Android devices', cellStyle: { backgroundColor: GRAY } }, ], [ { content: [ - 'Android Factory Reset', - Timestamp of a recent factory reset on an Android device., + + Emulator + , ], }, - { content: 'Not applicable to browsers', cellStyle: { backgroundColor: GRAY } }, + { content: 'Applicable only to Android devices', cellStyle: { backgroundColor: GRAY } }, ], [ { - content: ['iOS Jailbreak', Jailbreak detected on an iOS device.], + content: [ + + Rooted device + , + ], }, - { content: 'Not applicable to browsers', cellStyle: { backgroundColor: GRAY } }, + { content: 'Applicable only to Android devices', cellStyle: { backgroundColor: GRAY } }, ], + [ { content: [ - 'iOS Frida installation', - - Frida installation detected on an iOS device. Frida is a code-orchestration tool allowing to inject - arbitrary code into the operating system. - , + + Jailbroken device + , ], }, - { content: 'Not applicable to browsers', cellStyle: { backgroundColor: GRAY } }, + { content: 'Applicable only to iOS devices', cellStyle: { backgroundColor: GRAY } }, ], ]; diff --git a/src/pages/playground/playground.module.scss b/src/pages/playground/playground.module.scss new file mode 100644 index 00000000..84522932 --- /dev/null +++ b/src/pages/playground/playground.module.scss @@ -0,0 +1,20 @@ +.docsLink { + color: v('dark-black'); + + text-decoration: underline; + + &:hover { + color: v('orange-gradient'); + img { + opacity: 1; + } + } + + img { + opacity: 0; + margin-left: rem(2px); + vertical-align: baseline; + height: rem(10px); + color: v('dark-black'); + } +} From e0ad27cb3a3622422e88cce220f8a72287e47a2f Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Wed, 6 Dec 2023 20:44:13 +0000 Subject: [PATCH 05/39] chore: fix tests --- e2e/playground.spec.ts | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/e2e/playground.spec.ts b/e2e/playground.spec.ts index f8e97f57..5251d2e4 100644 --- a/e2e/playground.spec.ts +++ b/e2e/playground.spec.ts @@ -26,28 +26,28 @@ test.describe('Playground page page', () => { }); test('Page renders basic skeleton elements', async ({ page }) => { - await page.waitForSelector('text="Fingerprint Pro Playground"'); - await page.waitForSelector('text="Welcome, your visitor ID is"'); - await page.waitForSelector(`[data-test="${PLAYGROUND_TAG.refreshButton}"]`); + await page.getByText('Fingerprint Pro Playground', { exact: true }).waitFor(); + await page.getByText('Welcome, your visitor ID is').waitFor(); + await page.getByTestId(PLAYGROUND_TAG.refreshButton).first().waitFor(); - await page.waitForSelector('text="Base signals (Pro plan)"'); - await page.waitForSelector('text="Smart signals (Pro Plus plan)"'); - await page.waitForSelector('text="Smart signals (Enterprise plan)"'); + await page.getByText('Base signals (Pro plan)', { exact: true }).waitFor(); + await page.getByText('Smart signals (Pro Plus plan)', { exact: true }).waitFor(); + await page.getByText('Smart signals (Enterprise plan)', { exact: true }).waitFor(); - await page.waitForSelector('text="JavaScript Agent Response"'); - await page.waitForSelector('text="Server API Response"'); + await page.getByText('JavaScript Agent Response', { exact: true }).waitFor(); + await page.getByText('Server API Response', { exact: true }).waitFor(); }); test('Page renders signal tables', async ({ page }) => { - await page.waitForSelector('text="Visitor ID"'); - await page.waitForSelector('text="Last seen"'); - await page.waitForSelector('text="Confidence Score"'); + await page.getByText('Visitor ID', { exact: true }).waitFor(); + await page.getByText('Last seen', { exact: true }).waitFor(); + await page.getByText('Confidence Score', { exact: true }).waitFor(); - await page.waitForSelector('text="Geolocation"'); - await page.waitForSelector('text="VPN"'); + await page.getByText('Geolocation', { exact: true }).waitFor(); + await page.getByText('VPN', { exact: true }).waitFor(); - await page.waitForSelector('text="IP Blocklist"'); - await page.waitForSelector('text="Android Emulator"'); + await page.getByText('IP Blocklist', { exact: true }).waitFor(); + await page.getByText('Emulator', { exact: true }).waitFor(); }); test('Page renders agent response', async ({ page }) => { From 9a0d437bad06ceb8c7a494742bbe9d3455c2054b Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Thu, 7 Dec 2023 11:25:19 +0000 Subject: [PATCH 06/39] chore: remove more waitForSelectors --- e2e/coupon-fraud.spec.ts | 8 ++--- e2e/credential-stuffing.spec.ts | 36 +++++++++---------- e2e/paywall.spec.ts | 9 +++-- src/client/testIDs.ts | 4 +++ .../api/credential-stuffing/authenticate.ts | 15 +++++--- src/pages/credential-stuffing/index.tsx | 4 ++- 6 files changed, 44 insertions(+), 32 deletions(-) diff --git a/e2e/coupon-fraud.spec.ts b/e2e/coupon-fraud.spec.ts index e18528ae..dcc9de7c 100644 --- a/e2e/coupon-fraud.spec.ts +++ b/e2e/coupon-fraud.spec.ts @@ -13,23 +13,23 @@ test.describe('Coupon fraud', () => { await page.click('button:has-text("Apply")'); await page.waitForLoadState('networkidle'); - await page.waitForSelector('text="Coupon claimed"'); + await page.getByText('Coupon claimed').waitFor(); await page.click('button:has-text("Apply")'); await page.waitForLoadState('networkidle'); - await page.waitForSelector('text="The visitor used this coupon before."'); + await page.getByText('The visitor used this coupon before.').waitFor(); }); test('should prevent spamming multiple coupons', async ({ page }) => { await page.fill('#coupon_code', 'Promo3000'); await page.click('button:has-text("Apply")'); await page.waitForLoadState('networkidle'); - await page.waitForSelector('text="Coupon claimed"'); + await page.getByText('Coupon claimed').waitFor(); await page.fill('#coupon_code', 'BlackFriday', {}); await page.click('button:has-text("Apply")'); await page.waitForLoadState('networkidle'); - await page.waitForSelector('text="The visitor claimed another coupon recently."'); + await page.getByText('The visitor claimed another coupon recently.').waitFor(); }); }); diff --git a/e2e/credential-stuffing.spec.ts b/e2e/credential-stuffing.spec.ts index 754c3138..32c704bd 100644 --- a/e2e/credential-stuffing.spec.ts +++ b/e2e/credential-stuffing.spec.ts @@ -1,5 +1,12 @@ -import { test } from '@playwright/test'; +import { Page, test } from '@playwright/test'; import { resetScenarios } from './resetHelper'; +import { TEST_IDS } from '../src/client/testIDs'; +import { CREDENTIAL_STUFFING_COPY } from '../src/pages/api/credential-stuffing/authenticate'; + +const submitForm = async (page: Page) => { + // Waits for the button to be clickable out of the box + await page.getByTestId(TEST_IDS.credentialStuffing.login).click(); +}; test.describe('Credential stuffing', () => { test.beforeEach(async ({ page }) => { @@ -8,28 +15,21 @@ test.describe('Credential stuffing', () => { }); test('should prevent login even with correct credentials', async ({ page }) => { - await page.click('[type="submit"]'); - - await page.waitForSelector( - 'text="Provided credentials are correct but we\'ve never seen you logging in using this device. Confirm your identity with a second factor."', - ); + await submitForm(page); + await page.getByText(CREDENTIAL_STUFFING_COPY.differentVisitorIdUseMFA).waitFor(); }); test('should lock user after 5 invalid login attempts', async ({ page }) => { - const submitForm = async () => { - await page.click('[type="submit"]'); - await page.waitForSelector('text=Log in'); - }; - - await page.fill('[name="password"]', 'wrong-password'); + await page.getByTestId(TEST_IDS.credentialStuffing.password).fill('wrong-password'); - // 6 attempts, last one should be blocked - for (let i = 0; i < 7; i++) { - await submitForm(); + // 5 attempts with incorrect password tried and rejected + for (let i = 0; i < 5; i++) { + await submitForm(page); + await page.getByText(CREDENTIAL_STUFFING_COPY.invalidCredentials).waitFor(); } - await page.waitForSelector( - 'text="You had more than 5 attempts during the last 24 hours. This login attempt was not performed."', - ); + // 6th attempt with incorrect password not performed at all + await submitForm(page); + await page.getByText(CREDENTIAL_STUFFING_COPY.tooManyAttempts).waitFor(); }); }); diff --git a/e2e/paywall.spec.ts b/e2e/paywall.spec.ts index 67d00fa2..a476cb17 100644 --- a/e2e/paywall.spec.ts +++ b/e2e/paywall.spec.ts @@ -22,11 +22,10 @@ test.describe('Paywall', () => { await page.goBack(); await articles.nth(2).click(); - await expect( - page.getByText( - 'You have reached your daily view limit, purchase our membership plan to view unlimited articles.', - ), - ).toBeVisible(); + + await page + .getByText('You have reached your daily view limit, purchase our membership plan to view unlimited articles.') + .waitFor(); await expect(page.getByTestId(TEST_IDS.paywall.articleContent)).toBeHidden(); }); }); diff --git a/src/client/testIDs.ts b/src/client/testIDs.ts index b2918c3d..0206dfe9 100644 --- a/src/client/testIDs.ts +++ b/src/client/testIDs.ts @@ -45,4 +45,8 @@ export const TEST_IDS = { arrivalTime: 'arrivalTime', airline: 'airline', }, + credentialStuffing: { + login: 'login', + password: 'password', + }, } as const; diff --git a/src/pages/api/credential-stuffing/authenticate.ts b/src/pages/api/credential-stuffing/authenticate.ts index ac427eab..0a7a49f9 100644 --- a/src/pages/api/credential-stuffing/authenticate.ts +++ b/src/pages/api/credential-stuffing/authenticate.ts @@ -25,6 +25,13 @@ const mockedUser = { knownVisitorIds: getKnownVisitorIds(), }; +export const CREDENTIAL_STUFFING_COPY = { + tooManyAttempts: 'You had 5 or more attempts during the last 24 hours. This login attempt was not performed.', + differentVisitorIdUseMFA: + "Provided credentials are correct but we've never seen you logging in using this device. Confirm your identity with a second factor.", + invalidCredentials: 'Incorrect credentials, try again.', +} as const; + // Defines db model for login attempt. export const LoginAttemptDbModel = sequelize.define('login-attempt', { visitorId: { @@ -121,9 +128,9 @@ const checkUnsuccessfulIdentifications: RuleCheck = async (eventResponse) => { // If the visitorId performed 5 unsuccessful login attempts during the last 24 hours we do not perform the login. // The count of attempts and time window might vary. - if (visitorLoginAttemptCountQueryResult.count > 5) { + if (visitorLoginAttemptCountQueryResult.count >= 5) { return new CheckResult( - 'You had more than 5 attempts during the last 24 hours. This login attempt was not performed.', + CREDENTIAL_STUFFING_COPY.tooManyAttempts, messageSeverity.Error, checkResultType.TooManyLoginAttempts, ); @@ -135,7 +142,7 @@ const checkCredentialsAndKnownVisitorIds: RuleCheck = async (eventResponse, requ if (!areCredentialsCorrect(request.body.userName, request.body.password)) { return new CheckResult( - 'Incorrect credentials, try again.', + CREDENTIAL_STUFFING_COPY.invalidCredentials, messageSeverity.Error, checkResultType.IncorrectCredentials, ); @@ -154,7 +161,7 @@ const checkCredentialsAndKnownVisitorIds: RuleCheck = async (eventResponse, requ // If they provided valid credentials but they never logged in using this visitorId, // we recommend using an additional way of verification, e.g. 2FA or email. return new CheckResult( - "Provided credentials are correct but we've never seen you logging in using this device. Confirm your identity with a second factor.", + CREDENTIAL_STUFFING_COPY.differentVisitorIdUseMFA, messageSeverity.Warning, checkResultType.Challenged, ); diff --git a/src/pages/credential-stuffing/index.tsx b/src/pages/credential-stuffing/index.tsx index 723b4041..cd61ad32 100644 --- a/src/pages/credential-stuffing/index.tsx +++ b/src/pages/credential-stuffing/index.tsx @@ -11,6 +11,7 @@ import hiddenIcon from './iconHidden.svg'; import shownIcon from './iconShown.svg'; import Image from 'next/image'; import { useVisitorData } from '@fingerprintjs/fingerprintjs-pro-react'; +import { TEST_IDS } from '../../client/testIDs'; export default function Index() { const { getData } = useVisitorData( @@ -83,6 +84,7 @@ export default function Index() { className={styles.password} type={showPassword ? 'text' : 'password'} defaultValue={password} + data-testid={TEST_IDS.credentialStuffing.password} onChange={(e) => setPassword(e.target.value)} /> From a22bdd49c51812b6f893ae97304d894ade787dcb Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Thu, 7 Dec 2023 12:22:22 +0000 Subject: [PATCH 07/39] chore: update selectors in Loan Risk --- e2e/loan-risk.spec.ts | 70 ++++++++----------- .../InputNumberWithUnits.tsx | 11 ++- src/client/testIDs.ts | 6 ++ src/pages/api/loan-risk/request-loan.ts | 21 +++--- src/pages/loan-risk/index.tsx | 15 +++- src/pages/loan-risk/loanRisk.module.scss | 2 +- 6 files changed, 70 insertions(+), 55 deletions(-) diff --git a/e2e/loan-risk.spec.ts b/e2e/loan-risk.spec.ts index 6759977c..a0b65a71 100644 --- a/e2e/loan-risk.spec.ts +++ b/e2e/loan-risk.spec.ts @@ -1,55 +1,30 @@ import { Page, expect, test } from '@playwright/test'; import { resetScenarios } from './resetHelper'; import { TEST_IDS } from '../src/client/testIDs'; +import { LOAN_RISK_COPY } from '../src/pages/api/loan-risk/request-loan'; const testIds = TEST_IDS.loanRisk; async function waitForSuccessfulSubmit(page: Page) { - await page.click('[type="submit"]'); - await page.waitForLoadState('networkidle'); - await page.waitForSelector('text="Congratulations, your loan has been approved!"'); + await page.getByTestId(testIds.submitApplication).click(); + await page.getByText(LOAN_RISK_COPY.approved).waitFor(); } async function waitForBlockedLoanSubmit(page: Page) { - await page.click('[type="submit"]'); - await page.waitForLoadState('networkidle'); - await page.waitForSelector( - 'text="We are unable to approve your loan automatically since you had requested a loan with a different income or personal details before. We need to verify provided information manually this time. Please, reach out to our agent."', - ); + await page.getByTestId(testIds.submitApplication).click(); + await page.getByText(LOAN_RISK_COPY.inconsistentApplicationChallenged).waitFor(); } test.describe('Loan risk', () => { - const blockLoanCases = [ - { - name: 'first name', - fillForm: async (page: Page) => { - await page.fill('[name="firstName"]', 'Greg'); - }, - }, - { - name: 'last name', - fillForm: async (page: Page) => { - await page.fill('[name="lastName"]', 'Wick'); - }, - }, - { - name: 'income', - fillForm: async (page: Page) => { - await page.fill('[name="monthlyIncome"]', '30000'); - }, - }, - ]; - test.beforeEach(async ({ page }) => { await page.goto('/loan-risk'); await resetScenarios(page); }); test('should correctly calculate loan and approve it on first submit', async ({ page }) => { - await page.fill('[name="loanValue"]', '2000'); - await page.fill('[name="monthlyIncome"]', '20000'); - await page.fill('[name="loanDuration"]', '4'); - + await page.getByTestId(TEST_IDS.loanRisk.loanValue).fill('2000'); + await page.getByTestId(TEST_IDS.loanRisk.monthlyIncome).fill('20000'); + await page.getByTestId(TEST_IDS.loanRisk.loanTerm).fill('4'); const monthInstallmentValue = page.getByTestId(testIds.monthlyInstallmentValue); await expect(monthInstallmentValue).toHaveText('$ 575'); @@ -57,23 +32,36 @@ test.describe('Loan risk', () => { }); test('should approve loan if only loan value or loan duration changes', async ({ page }) => { - await page.fill('[name="loanValue"]', '2000'); + await page.getByTestId(TEST_IDS.loanRisk.loanValue).fill('2000'); await waitForSuccessfulSubmit(page); - await page.fill('[name="loanValue"]', '3000'); + await page.getByTestId(TEST_IDS.loanRisk.loanValue).fill('3000'); await waitForSuccessfulSubmit(page); - await page.fill('[name="loanValue"]', '4000'); - await page.fill('[name="loanDuration"]', '4'); + await page.getByTestId(TEST_IDS.loanRisk.loanValue).fill('4000'); + await page.getByTestId(TEST_IDS.loanRisk.loanTerm).fill('4'); await waitForSuccessfulSubmit(page); }); + const blockLoanCases = [ + { + field: TEST_IDS.loanRisk.name, + value: 'Greg', + }, + { + field: TEST_IDS.loanRisk.surname, + value: 'Wick', + }, + { + field: TEST_IDS.loanRisk.monthlyIncome, + value: '30000', + }, + ] as const; + blockLoanCases.forEach((testCase) => { - test(`should not approve loan if ${testCase.name} changes after first submit`, async ({ page }) => { + test(`should not approve loan if ${testCase.field} changes after first submit`, async ({ page }) => { await waitForSuccessfulSubmit(page); - - await testCase.fillForm(page); - + await page.getByTestId(testCase.field).fill(testCase.value); await waitForBlockedLoanSubmit(page); }); }); diff --git a/src/client/components/common/InputNumberWithUnits/InputNumberWithUnits.tsx b/src/client/components/common/InputNumberWithUnits/InputNumberWithUnits.tsx index b39603fd..28a111f7 100644 --- a/src/client/components/common/InputNumberWithUnits/InputNumberWithUnits.tsx +++ b/src/client/components/common/InputNumberWithUnits/InputNumberWithUnits.tsx @@ -7,9 +7,17 @@ interface NumberInputWithUnitsProps { value?: number; onChange?: (value: number) => void; name?: string; + dataTestId?: string; } -export const NumberInputWithUnits: FC = ({ prefix, suffix, value, onChange, name }) => { +export const NumberInputWithUnits: FC = ({ + prefix, + suffix, + value, + onChange, + name, + dataTestId, +}) => { return (
{prefix &&
{prefix}
} @@ -19,6 +27,7 @@ export const NumberInputWithUnits: FC = ({ prefix, su value={value} name={name} onChange={(event) => onChange?.(Number(event.target.value))} + data-testid={dataTestId} /> {suffix &&
{suffix}
}
diff --git a/src/client/testIDs.ts b/src/client/testIDs.ts index 0206dfe9..a0866988 100644 --- a/src/client/testIDs.ts +++ b/src/client/testIDs.ts @@ -21,6 +21,12 @@ export const TEST_IDS = { }, loanRisk: { monthlyInstallmentValue: 'monthlyInstallmentValue', + submitApplication: 'submitApplication', + name: 'name', + surname: 'surname', + loanValue: 'loanValue', + monthlyIncome: 'monthlyIncome', + loanTerm: 'loanTerm', }, personalization: { coffeeProduct: 'coffeeProduct', diff --git a/src/pages/api/loan-risk/request-loan.ts b/src/pages/api/loan-risk/request-loan.ts index 9a9dc5d4..c494cde3 100644 --- a/src/pages/api/loan-risk/request-loan.ts +++ b/src/pages/api/loan-risk/request-loan.ts @@ -6,6 +6,13 @@ import { calculateLoanValues } from '../../../server/loan-risk/calculate-loan-va import { CheckResult, checkResultType } from '../../../server/checkResult'; import { RuleCheck } from '../../../server/checks'; +export const LOAN_RISK_COPY = { + approved: 'Congratulations, your loan has been approved!', + incomeLow: 'Sorry, your monthly income is too low for this loan.', + inconsistentApplicationChallenged: + 'We are unable to approve your loan automatically since you had requested a loan with a different income or personal details before. We need to verify provided information manually this time. Please, reach out to our agent.', +} as const; + /** * Validates previous loan requests sent by a given user. * @@ -48,7 +55,7 @@ const checkPreviousLoanRequests: RuleCheck = async (eventResponse, req) => { // In our case, we just return a warning. if (!hasValidFields) { return new CheckResult( - 'We are unable to approve your loan automatically since you had requested a loan with a different income or personal details before. We need to verify provided information manually this time. Please, reach out to our agent.', + LOAN_RISK_COPY.inconsistentApplicationChallenged, messageSeverity.Warning, checkResultType.PossibleLoanFraud, ); @@ -87,17 +94,9 @@ export default loanRiskEndpoint( let result; if (calculations.approved) { - result = new CheckResult( - 'Congratulations, your loan has been approved!', - messageSeverity.Success, - checkResultType.Passed, - ); + result = new CheckResult(LOAN_RISK_COPY.approved, messageSeverity.Success, checkResultType.Passed); } else { - result = new CheckResult( - 'Sorry, your monthly income is too low for this loan.', - messageSeverity.Warning, - checkResultType.Challenged, - ); + result = new CheckResult(LOAN_RISK_COPY.incomeLow, messageSeverity.Warning, checkResultType.Challenged); } return res.status(200).json({ diff --git a/src/pages/loan-risk/index.tsx b/src/pages/loan-risk/index.tsx index 595bfd0c..6a9c7174 100644 --- a/src/pages/loan-risk/index.tsx +++ b/src/pages/loan-risk/index.tsx @@ -30,6 +30,7 @@ type SliderFieldProps = { prefix?: string; suffix?: string; name?: string; + dataTestId?: string; }; const SliderField: FunctionComponent = ({ @@ -41,6 +42,7 @@ const SliderField: FunctionComponent = ({ prefix, suffix, name, + dataTestId, }) => { return (
@@ -56,6 +58,7 @@ const SliderField: FunctionComponent = ({ suffix={suffix} prefix={prefix} name={name} + dataTestId={dataTestId} />
@@ -118,6 +121,7 @@ export default function LoanRisk({ embed }: CustomPageProps) { value={firstName} onChange={(event) => setFirstName(event.target.value)} required + data-testid={TEST_IDS.loanRisk.name} /> setLastName(event.target.value)} required + data-testid={TEST_IDS.loanRisk.surname} />
@@ -138,6 +143,7 @@ export default function LoanRisk({ embed }: CustomPageProps) { label="How much money do you need?" value={loanValue} onChange={setLoanValue} + dataTestId={TEST_IDS.loanRisk.loanValue} />
Your monthly installment is: @@ -167,7 +175,12 @@ export default function LoanRisk({ embed }: CustomPageProps) { {loanRequestMutation.data?.message && !loanRequestMutation.isLoading && ( {loanRequestMutation.data.message} )} -
diff --git a/src/pages/loan-risk/loanRisk.module.scss b/src/pages/loan-risk/loanRisk.module.scss index 7bc164ed..01652cea 100644 --- a/src/pages/loan-risk/loanRisk.module.scss +++ b/src/pages/loan-risk/loanRisk.module.scss @@ -87,6 +87,6 @@ white-space: nowrap; } -.requestLoadButton { +.requestLoanButton { margin-left: auto; } From 7471ffaae77d83a8a5201e832b3551d4cb67a3ae Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Thu, 7 Dec 2023 13:33:18 +0000 Subject: [PATCH 08/39] chore: update selectors in Payment fraud --- e2e/payment-fraud.spec.ts | 42 ++++++++++------------ src/client/testIDs.ts | 8 +++++ src/pages/api/payment-fraud/place-order.ts | 27 +++++++------- src/pages/payment-fraud/index.tsx | 13 ++++++- 4 files changed, 52 insertions(+), 38 deletions(-) diff --git a/e2e/payment-fraud.spec.ts b/e2e/payment-fraud.spec.ts index e68a365a..38878e44 100644 --- a/e2e/payment-fraud.spec.ts +++ b/e2e/payment-fraud.spec.ts @@ -1,14 +1,18 @@ import { Page, test } from '@playwright/test'; import { resetScenarios } from './resetHelper'; +import { PAYMENT_FRAUD_COPY } from '../src/pages/api/payment-fraud/place-order'; +import { TEST_IDS } from '../src/client/testIDs'; + +const submit = (page: Page) => page.getByTestId(TEST_IDS.paymentFraud.submitPayment).click(); async function waitForSuccessfulSubmit(page: Page) { - await page.click('[type="submit"]'); - await page.waitForSelector('text="Thank you for your payment. Everything is OK."'); + await submit(page); + await page.getByText(PAYMENT_FRAUD_COPY.successfulPayment).waitFor(); } async function waitForInvalidCardSubmit(page: Page) { - await page.click('[type="submit"]'); - await page.waitForSelector('text="Incorrect card details, try again."'); + await submit(page); + await page.getByText(PAYMENT_FRAUD_COPY.incorrectCardDetails).waitFor(); } test.describe('Payment fraud', () => { @@ -22,39 +26,29 @@ test.describe('Payment fraud', () => { }); test('should allow only two chargebacks', async ({ page }) => { - await page.check('[name="applyChargeback"]'); - + await page.getByTestId(TEST_IDS.paymentFraud.askForChargeback).check(); await waitForSuccessfulSubmit(page); await waitForSuccessfulSubmit(page); - await page.click('[type="submit"]'); - - await page.waitForSelector( - 'text="You performed more than 1 chargeback during the last 1 year, we did not perform the payment."', - ); + await submit(page); + await page.getByText(PAYMENT_FRAUD_COPY.previousChargeback).waitFor(); }); test('should prevent card cracking after 3 attempts', async ({ page }) => { - await page.fill('[name="cardNumber"]', '4242 4242 4242 4243'); - + await page.getByTestId(TEST_IDS.paymentFraud.cardNumber).fill('4242 4242 4242 4243'); await waitForInvalidCardSubmit(page); await waitForInvalidCardSubmit(page); await waitForInvalidCardSubmit(page); - await page.click('[type="submit"]'); - await page.waitForSelector( - 'text="You placed more than 3 unsuccessful payment attempts during the last 365 days. This payment attempt was not performed."', - ); + await submit(page); + await page.getByText(PAYMENT_FRAUD_COPY.tooManyUnsuccessfulPayments).waitFor(); }); - test('should prevent purchase if card was flagged as stolen', async ({ page }) => { - await page.check('[name="usingStolenCard"]'); - + test('should prevent another purchase if card was flagged as stolen', async ({ page }) => { + await page.getByTestId(TEST_IDS.paymentFraud.usingStolenCard).check(); await waitForSuccessfulSubmit(page); - await page.click('[type="submit"]'); - await page.waitForSelector( - 'text="According to our records, you paid with a stolen card. We did not process the payment."', - ); + await submit(page); + await page.getByText(PAYMENT_FRAUD_COPY.stolenCard).waitFor(); }); }); diff --git a/src/client/testIDs.ts b/src/client/testIDs.ts index a0866988..0ee03d6d 100644 --- a/src/client/testIDs.ts +++ b/src/client/testIDs.ts @@ -36,6 +36,14 @@ export const TEST_IDS = { search: 'search', searchHistoryItem: 'searchHistoryItem', }, + paymentFraud: { + submitPayment: 'submitPayment', + cardNumber: 'cardNumber', + cardExpiration: 'cardExpiration', + cardCvv: 'cardCvv', + usingStolenCard: 'usingStolenCard', + askForChargeback: 'askForChargeback', + }, paywall: { articleCard: 'articleCard', articleContent: 'articleContent', diff --git a/src/pages/api/payment-fraud/place-order.ts b/src/pages/api/payment-fraud/place-order.ts index 396e7323..4c837d9f 100644 --- a/src/pages/api/payment-fraud/place-order.ts +++ b/src/pages/api/payment-fraud/place-order.ts @@ -18,6 +18,15 @@ import { import { sendForbiddenResponse, sendOkResponse } from '../../../server/response'; import { NextApiRequest, NextApiResponse } from 'next'; +export const PAYMENT_FRAUD_COPY = { + stolenCard: 'According to our records, you paid with a stolen card. We did not process the payment.', + tooManyUnsuccessfulPayments: + 'You placed more than 3 unsuccessful payment attempts during the last 365 days. This payment attempt was not performed.', + previousChargeback: 'You performed more than 1 chargeback during the last 1 year, we did not perform the payment.', + successfulPayment: 'Thank you for your payment. Everything is OK.', + incorrectCardDetails: 'Incorrect card details, try again.', +} as const; + interface PaymentAttemptAttributes extends Model, InferCreationAttributes> { visitorId: string; @@ -122,11 +131,7 @@ const checkVisitorIdForStolenCard: RuleCheck = async (eventResponse) => { // If the visitorId performed more than 1 payment with a stolen card during the last 1 year we do not process the payment. // The time window duration might vary. if (stolenCardUsedCount.count > 0) { - return new CheckResult( - 'According to our records, you paid with a stolen card. We did not process the payment.', - messageSeverity.Error, - checkResultType.PaidWithStolenCard, - ); + return new CheckResult(PAYMENT_FRAUD_COPY.stolenCard, messageSeverity.Error, checkResultType.PaidWithStolenCard); } }; @@ -148,7 +153,7 @@ const checkForCardCracking: RuleCheck = async (eventResponse) => { // The count of attempts and time window might vary. if (invalidCardAttemptCountQueryResult.count > 2) { return new CheckResult( - 'You placed more than 3 unsuccessful payment attempts during the last 365 days. This payment attempt was not performed.', + PAYMENT_FRAUD_COPY.tooManyUnsuccessfulPayments, messageSeverity.Error, checkResultType.TooManyUnsuccessfulPayments, ); @@ -171,7 +176,7 @@ const checkVisitorIdForChargebacks: RuleCheck = async (eventResponse) => { // The count of chargebacks and time window might vary. if (countOfChargebacksForVisitorId.count > 1) { return new CheckResult( - 'You performed more than 1 chargeback during the last 1 year, we did not perform the payment.', + PAYMENT_FRAUD_COPY.previousChargeback, messageSeverity.Error, checkResultType.TooManyChargebacks, ); @@ -181,14 +186,10 @@ const checkVisitorIdForChargebacks: RuleCheck = async (eventResponse) => { const processPayment: RuleCheck = async (_eventResponse, request) => { // Checks if the provided card details are correct. if (areCardDetailsCorrect(request)) { - return new CheckResult( - 'Thank you for your payment. Everything is OK.', - messageSeverity.Success, - checkResultType.Passed, - ); + return new CheckResult(PAYMENT_FRAUD_COPY.successfulPayment, messageSeverity.Success, checkResultType.Passed); } else { return new CheckResult( - 'Incorrect card details, try again.', + PAYMENT_FRAUD_COPY.incorrectCardDetails, messageSeverity.Error, checkResultType.IncorrectCardDetails, ); diff --git a/src/pages/payment-fraud/index.tsx b/src/pages/payment-fraud/index.tsx index 2cba7fad..2bdfd89c 100644 --- a/src/pages/payment-fraud/index.tsx +++ b/src/pages/payment-fraud/index.tsx @@ -11,6 +11,7 @@ import { CustomPageProps } from '../_app'; import classNames from 'classnames'; import { Severity } from '../../server/checkResult'; import { useVisitorData } from '@fingerprintjs/fingerprintjs-pro-react'; +import { TEST_IDS } from '../../client/testIDs'; export default function Index({ embed }: CustomPageProps) { const { getData } = useVisitorData( @@ -79,6 +80,7 @@ export default function Index({ embed }: CustomPageProps) { defaultValue={cardNumber} onChange={(e) => setCardNumber(e.target.value)} required + data-testid={TEST_IDS.paymentFraud.cardNumber} />
@@ -90,6 +92,7 @@ export default function Index({ embed }: CustomPageProps) { defaultValue={cardExpiration} onChange={(e) => setCardExpiration(e.target.value)} required + data-testid={TEST_IDS.paymentFraud.cardExpiration} />
@@ -101,6 +104,7 @@ export default function Index({ embed }: CustomPageProps) { defaultValue={cardCvv} onChange={(e) => setCardCvv(e.target.value)} required + data-testid={TEST_IDS.paymentFraud.cardCvv} />
@@ -113,6 +117,7 @@ export default function Index({ embed }: CustomPageProps) { type="checkbox" name="applyChargeback" onChange={(event) => setApplyChargeback(event.target.checked)} + data-testid={TEST_IDS.paymentFraud.askForChargeback} /> Ask for chargeback after purchase @@ -124,13 +129,19 @@ export default function Index({ embed }: CustomPageProps) { onChange={(event) => { setUsingStolenCard(event.target.checked); }} + data-testid={TEST_IDS.paymentFraud.usingStolenCard} /> Flag this visitor using stolen card after purchase
{httpResponseStatus ? {orderStatusMessage} : null} - From 83622caae657e1d941437ece2218310324890579 Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Thu, 7 Dec 2023 13:56:56 +0000 Subject: [PATCH 09/39] chore: update selectors in Coupon fraud --- e2e/coupon-fraud.spec.ts | 49 +++++++++++++++++------------ e2e/personalization.spec.ts | 2 +- src/client/testIDs.ts | 4 +++ src/pages/api/coupon-fraud/claim.ts | 23 +++++++------- src/pages/coupon-fraud/index.tsx | 10 ++++-- 5 files changed, 53 insertions(+), 35 deletions(-) diff --git a/e2e/coupon-fraud.spec.ts b/e2e/coupon-fraud.spec.ts index dcc9de7c..b2a2446d 100644 --- a/e2e/coupon-fraud.spec.ts +++ b/e2e/coupon-fraud.spec.ts @@ -1,5 +1,15 @@ -import { test } from '@playwright/test'; +import { Page, test } from '@playwright/test'; import { resetScenarios } from './resetHelper'; +import { TEST_IDS } from '../src/client/testIDs'; +import { COUPON_FRAUD_COPY } from '../src/pages/api/coupon-fraud/claim'; + +const insertCoupon = async (page: Page, coupon: string) => { + await page.getByTestId(TEST_IDS.couponFraud.couponCode).fill(coupon); +}; + +const submitCoupon = async (page: Page) => { + await page.getByTestId(TEST_IDS.couponFraud.submitCoupon).click(); +}; test.describe('Coupon fraud', () => { test.beforeEach(async ({ page }) => { @@ -7,29 +17,28 @@ test.describe('Coupon fraud', () => { await resetScenarios(page); }); - test('should apply correct coupon only once', async ({ page }) => { - await page.fill('#coupon_code', 'Promo3000'); - - await page.click('button:has-text("Apply")'); - await page.waitForLoadState('networkidle'); - - await page.getByText('Coupon claimed').waitFor(); + test('should not allow to claim coupon that does not exist', async ({ page }) => { + await insertCoupon(page, 'Does not exist'); + await submitCoupon(page); + await page.getByText(COUPON_FRAUD_COPY.doesNotExist).waitFor(); + }); - await page.click('button:has-text("Apply")'); - await page.waitForLoadState('networkidle'); + test('should apply correct coupon only once', async ({ page }) => { + await insertCoupon(page, 'Promo3000'); + await submitCoupon(page); + await page.getByText(COUPON_FRAUD_COPY.success).waitFor(); - await page.getByText('The visitor used this coupon before.').waitFor(); + await submitCoupon(page); + await page.getByText(COUPON_FRAUD_COPY.usedBefore).waitFor(); }); test('should prevent spamming multiple coupons', async ({ page }) => { - await page.fill('#coupon_code', 'Promo3000'); - await page.click('button:has-text("Apply")'); - await page.waitForLoadState('networkidle'); - await page.getByText('Coupon claimed').waitFor(); - - await page.fill('#coupon_code', 'BlackFriday', {}); - await page.click('button:has-text("Apply")'); - await page.waitForLoadState('networkidle'); - await page.getByText('The visitor claimed another coupon recently.').waitFor(); + await insertCoupon(page, 'Promo3000'); + await submitCoupon(page); + await page.getByText(COUPON_FRAUD_COPY.success).waitFor(); + + await insertCoupon(page, 'BlackFriday'); + await submitCoupon(page); + await page.getByText(COUPON_FRAUD_COPY.usedAnotherCouponRecently).waitFor(); }); }); diff --git a/e2e/personalization.spec.ts b/e2e/personalization.spec.ts index 4712963c..246dec23 100644 --- a/e2e/personalization.spec.ts +++ b/e2e/personalization.spec.ts @@ -10,7 +10,7 @@ test.describe('Personalization', () => { await page.goto('/personalization', { waitUntil: 'networkidle', }); - await page.click('text="Okay, I understand"'); + await page.getByText('Okay, I understand').click(); await resetScenarios(page); }); diff --git a/src/client/testIDs.ts b/src/client/testIDs.ts index 0ee03d6d..2c786b64 100644 --- a/src/client/testIDs.ts +++ b/src/client/testIDs.ts @@ -49,6 +49,10 @@ export const TEST_IDS = { articleContent: 'articleContent', goBack: 'goBack', }, + couponFraud: { + couponCode: 'couponCode', + submitCoupon: 'submitCoupon', + }, webScraping: { search: 'search', card: 'card', diff --git a/src/pages/api/coupon-fraud/claim.ts b/src/pages/api/coupon-fraud/claim.ts index 53ec3aff..f00d157f 100644 --- a/src/pages/api/coupon-fraud/claim.ts +++ b/src/pages/api/coupon-fraud/claim.ts @@ -6,6 +6,13 @@ import { CheckResult, checkResultType } from '../../../server/checkResult'; import { sendOkResponse } from '../../../server/response'; import { RuleCheck } from '../../../server/checks'; +export const COUPON_FRAUD_COPY = { + doesNotExist: 'Provided coupon code does not exist.', + usedBefore: 'The visitor used this coupon before.', + usedAnotherCouponRecently: 'The visitor claimed another coupon recently.', + success: 'Coupon claimed', +} as const; + async function checkVisitorClaimedRecently(visitorId: string) { const oneHourBefore = new Date(); oneHourBefore.setHours(oneHourBefore.getHours() - 1); @@ -52,11 +59,7 @@ const checkIfCouponExists: RuleCheck = async (_visitorData, _req, couponCode: Co // Check if the coupon exists. if (!coupon) { - return new CheckResult( - 'Provided coupon code does not exist.', - messageSeverity.Error, - checkResultType.CouponDoesNotExist, - ); + return new CheckResult(COUPON_FRAUD_COPY.doesNotExist, messageSeverity.Error, checkResultType.CouponDoesNotExist); } }; @@ -70,11 +73,7 @@ const checkIfCouponWasClaimed: RuleCheck = async (eventResponse, _req, couponCod // Check if the visitor claimed this coupon before. if (wasCouponClaimedByVisitor) { - return new CheckResult( - 'The visitor used this coupon before.', - messageSeverity.Error, - checkResultType.CouponAlreadyClaimed, - ); + return new CheckResult(COUPON_FRAUD_COPY.usedBefore, messageSeverity.Error, checkResultType.CouponAlreadyClaimed); } }; @@ -88,7 +87,7 @@ const checkIfClaimedAnotherCouponRecently: RuleCheck = async (eventData) => { if (visitorClaimedAnotherCouponRecently) { return new CheckResult( - 'The visitor claimed another coupon recently.', + COUPON_FRAUD_COPY.usedAnotherCouponRecently, messageSeverity.Error, checkResultType.AnotherCouponClaimedRecently, ); @@ -101,7 +100,7 @@ export default couponEndpoint( await claimCoupon(validateCouponResult.visitorId, validateCouponResult.couponCode); } - const result = new CheckResult('Coupon claimed', messageSeverity.Success, checkResultType.Passed); + const result = new CheckResult(COUPON_FRAUD_COPY.success, messageSeverity.Success, checkResultType.Passed); return sendOkResponse(res, result); }, diff --git a/src/pages/coupon-fraud/index.tsx b/src/pages/coupon-fraud/index.tsx index a4ff654c..597c360d 100644 --- a/src/pages/coupon-fraud/index.tsx +++ b/src/pages/coupon-fraud/index.tsx @@ -14,6 +14,7 @@ import Alert from '../../client/components/common/Alert/Alert'; import Button from '../../client/components/common/Button/Button'; import { Cart } from '../../client/components/common/Cart/Cart'; import { useVisitorData } from '@fingerprintjs/fingerprintjs-pro-react'; +import { TEST_IDS } from '../../client/testIDs'; const AIRMAX_PRICE = 356.02; const ALLSTAR_PRICE = 102.5; @@ -92,12 +93,17 @@ export default function CouponFraudUseCase({ embed }: CustomPageProps) {
setCouponCode(e.target.value)} required + data-testid={TEST_IDS.couponFraud.couponCode} /> -
From 25a5127f41ba6ba872b270c761d8a921166cba9b Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Thu, 7 Dec 2023 14:18:40 +0000 Subject: [PATCH 10/39] chore: update selectors in Paywall --- e2e/paywall.spec.ts | 9 ++++----- e2e/personalization.spec.ts | 3 ++- src/pages/paywall/article/[id]/index.tsx | 5 ++--- src/pages/personalization/index.tsx | 6 +++++- src/server/paywall/article-views.ts | 7 ++----- src/server/paywall/paywallCopy.ts | 7 +++++++ 6 files changed, 22 insertions(+), 15 deletions(-) create mode 100644 src/server/paywall/paywallCopy.ts diff --git a/e2e/paywall.spec.ts b/e2e/paywall.spec.ts index a476cb17..4f2b230c 100644 --- a/e2e/paywall.spec.ts +++ b/e2e/paywall.spec.ts @@ -1,6 +1,7 @@ import { test, expect } from '@playwright/test'; import { resetScenarios } from './resetHelper'; import { TEST_IDS } from '../src/client/testIDs'; +import { PAYWALL_COPY } from '../src/server/paywall/paywallCopy'; test.describe('Paywall', () => { test.beforeEach(async ({ page }) => { @@ -12,20 +13,18 @@ test.describe('Paywall', () => { const articles = await page.getByTestId(TEST_IDS.paywall.articleCard); await articles.first().click(); - await page.getByText('You have 1 remaining free article views.').waitFor(); + await page.getByText(PAYWALL_COPY.nArticlesRemaining(1)).waitFor(); await expect(page.getByTestId(TEST_IDS.paywall.articleContent)).toBeVisible(); await page.goBack(); await articles.nth(1).click(); - await page.getByText('This is your last free article today.').waitFor(); + await page.getByText(PAYWALL_COPY.lastArticle).waitFor(); await expect(page.getByTestId(TEST_IDS.paywall.articleContent)).toBeVisible(); await page.goBack(); await articles.nth(2).click(); - await page - .getByText('You have reached your daily view limit, purchase our membership plan to view unlimited articles.') - .waitFor(); + await page.getByText(PAYWALL_COPY.limitReached).waitFor(); await expect(page.getByTestId(TEST_IDS.paywall.articleContent)).toBeHidden(); }); }); diff --git a/e2e/personalization.spec.ts b/e2e/personalization.spec.ts index 246dec23..3d60d583 100644 --- a/e2e/personalization.spec.ts +++ b/e2e/personalization.spec.ts @@ -1,6 +1,7 @@ import { expect, test } from '@playwright/test'; import { resetScenarios } from './resetHelper'; import { TEST_IDS } from '../src/client/testIDs'; +import { PERSONALIZATION_COPY } from '../src/pages/personalization'; const CART_ID = TEST_IDS.common.cart; const PERS_ID = TEST_IDS.personalization; @@ -10,7 +11,7 @@ test.describe('Personalization', () => { await page.goto('/personalization', { waitUntil: 'networkidle', }); - await page.getByText('Okay, I understand').click(); + await page.getByText(PERSONALIZATION_COPY.okay).click(); await resetScenarios(page); }); diff --git a/src/pages/paywall/article/[id]/index.tsx b/src/pages/paywall/article/[id]/index.tsx index a3fa8047..70c74abb 100644 --- a/src/pages/paywall/article/[id]/index.tsx +++ b/src/pages/paywall/article/[id]/index.tsx @@ -14,6 +14,7 @@ import { useQuery } from 'react-query'; import { ArticleResponse } from '../../../api/paywall/article/[id]'; import { TEST_IDS } from '../../../../client/testIDs'; import { ArticleGrid, Byline } from '../../../../client/components/paywall/ArticleGrid'; +import { PAYWALL_COPY } from '../../../../server/paywall/paywallCopy'; function ArticleSkeleton({ animation = false }: { animation?: SkeletonTypeMap['props']['animation'] }) { const skeletons = Array.from({ length: 4 }).map((_, index) => ); @@ -57,9 +58,7 @@ export default function Article({ embed }: CustomPageProps) { )} {articleData && articleData.severity === 'success' && remainingViews !== undefined && ( - {remainingViews > 0 - ? `You have ${remainingViews} remaining free article views.` - : 'This is your last free article today.'} + {remainingViews > 0 ? PAYWALL_COPY.nArticlesRemaining(remainingViews) : PAYWALL_COPY.lastArticle} )} {article && ( diff --git a/src/pages/personalization/index.tsx b/src/pages/personalization/index.tsx index da71f8e1..28d95f5a 100644 --- a/src/pages/personalization/index.tsx +++ b/src/pages/personalization/index.tsx @@ -20,6 +20,10 @@ import { Search, SearchHistory } from '../../client/components/personalization/s import { ProductCard } from '../../client/components/personalization/productCard'; import { useVisitorData } from '@fingerprintjs/fingerprintjs-pro-react'; +export const PERSONALIZATION_COPY = { + okay: 'Okay, I understand', +}; + export default function Index({ embed }: CustomPageProps) { const { enqueueSnackbar } = useSnackbar(); @@ -99,7 +103,7 @@ export default function Index({ embed }: CustomPageProps) { - + diff --git a/src/server/paywall/article-views.ts b/src/server/paywall/article-views.ts index b8316945..4a4a011b 100644 --- a/src/server/paywall/article-views.ts +++ b/src/server/paywall/article-views.ts @@ -4,6 +4,7 @@ import { getTodayDateRange } from '../../shared/utils/date'; import { messageSeverity } from '../server'; import { CheckResult, checkResultType } from '../checkResult'; import { RuleCheck } from '../checks'; +import { PAYWALL_COPY } from './paywallCopy'; export const ARTICLE_VIEW_LIMIT = 2; @@ -87,10 +88,6 @@ export const checkCountOfViewedArticles: RuleCheck = async (eventResponse, req) ]); if (!existingView && count >= ARTICLE_VIEW_LIMIT) { - return new CheckResult( - 'You have reached your daily view limit, purchase our membership plan to view unlimited articles.', - messageSeverity.Error, - checkResultType.ArticleViewLimitExceeded, - ); + return new CheckResult(PAYWALL_COPY.limitReached, messageSeverity.Error, checkResultType.ArticleViewLimitExceeded); } }; diff --git a/src/server/paywall/paywallCopy.ts b/src/server/paywall/paywallCopy.ts new file mode 100644 index 00000000..8d065fe1 --- /dev/null +++ b/src/server/paywall/paywallCopy.ts @@ -0,0 +1,7 @@ +export const PAYWALL_COPY = { + limitReached: 'You have reached your daily view limit, purchase our membership plan to view unlimited articles.', + lastArticle: 'This is your last free article today.', + nArticlesRemaining(n: number) { + return `You have ${n} remaining free article views.`; + }, +} as const; From b14f68618776fbcd0000c2387bcaa4b5aa6a70fa Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Thu, 7 Dec 2023 14:34:13 +0000 Subject: [PATCH 11/39] chore: remove artificial timeouts --- e2e/personalization.spec.ts | 4 +--- e2e/playground.spec.ts | 1 - e2e/scraping/unprotected.spec.ts | 1 - src/pages/personalization/index.tsx | 6 +----- 4 files changed, 2 insertions(+), 10 deletions(-) diff --git a/e2e/personalization.spec.ts b/e2e/personalization.spec.ts index 3d60d583..1cd4fe05 100644 --- a/e2e/personalization.spec.ts +++ b/e2e/personalization.spec.ts @@ -1,7 +1,6 @@ import { expect, test } from '@playwright/test'; import { resetScenarios } from './resetHelper'; import { TEST_IDS } from '../src/client/testIDs'; -import { PERSONALIZATION_COPY } from '../src/pages/personalization'; const CART_ID = TEST_IDS.common.cart; const PERS_ID = TEST_IDS.personalization; @@ -11,7 +10,7 @@ test.describe('Personalization', () => { await page.goto('/personalization', { waitUntil: 'networkidle', }); - await page.getByText(PERSONALIZATION_COPY.okay).click(); + await page.getByText('Okay, I understand').click(); await resetScenarios(page); }); @@ -76,7 +75,6 @@ test.describe('Personalization', () => { const products = page.getByTestId(PERS_ID.coffeeProduct); const checkFoundProducts = async () => { - await page.waitForTimeout(3000); await expect .poll(async () => { const textContents = await Promise.all((await products.all()).map((p) => p.textContent())); diff --git a/e2e/playground.spec.ts b/e2e/playground.spec.ts index 9175c622..35679205 100644 --- a/e2e/playground.spec.ts +++ b/e2e/playground.spec.ts @@ -17,7 +17,6 @@ const getServerResponse = async (page: Page) => { const clickRefreshButton = async (page: Page) => { await page.getByTestId(PLAYGROUND_TAG.refreshButton).first().click(); await page.waitForLoadState('networkidle'); - await page.waitForTimeout(3000); }; test.describe('Playground page page', () => { diff --git a/e2e/scraping/unprotected.spec.ts b/e2e/scraping/unprotected.spec.ts index 01355b51..da397909 100644 --- a/e2e/scraping/unprotected.spec.ts +++ b/e2e/scraping/unprotected.spec.ts @@ -13,7 +13,6 @@ test.describe('Scraping flights', () => { test('is possible with Bot detection off', async ({ page }) => { await page.goto('/web-scraping?disableBotDetection=1'); await page.waitForLoadState('networkidle'); - await page.waitForTimeout(3000); const flightCards = await page.getByTestId(TEST_ID.card).all(); console.log('Found flight cards: ', flightCards.length); diff --git a/src/pages/personalization/index.tsx b/src/pages/personalization/index.tsx index 28d95f5a..da71f8e1 100644 --- a/src/pages/personalization/index.tsx +++ b/src/pages/personalization/index.tsx @@ -20,10 +20,6 @@ import { Search, SearchHistory } from '../../client/components/personalization/s import { ProductCard } from '../../client/components/personalization/productCard'; import { useVisitorData } from '@fingerprintjs/fingerprintjs-pro-react'; -export const PERSONALIZATION_COPY = { - okay: 'Okay, I understand', -}; - export default function Index({ embed }: CustomPageProps) { const { enqueueSnackbar } = useSnackbar(); @@ -103,7 +99,7 @@ export default function Index({ embed }: CustomPageProps) { - + From 414641903a2c0f9cfbdf83bab2eb57f0594de1b7 Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Thu, 7 Dec 2023 18:17:05 +0000 Subject: [PATCH 12/39] chore: put playground timeout back --- e2e/playground.spec.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/e2e/playground.spec.ts b/e2e/playground.spec.ts index 35679205..45a757cb 100644 --- a/e2e/playground.spec.ts +++ b/e2e/playground.spec.ts @@ -17,6 +17,8 @@ const getServerResponse = async (page: Page) => { const clickRefreshButton = async (page: Page) => { await page.getByTestId(PLAYGROUND_TAG.refreshButton).first().click(); await page.waitForLoadState('networkidle'); + // Artificial wait necessary to make sure you get the updated response every time + await page.waitForTimeout(3000); }; test.describe('Playground page page', () => { From 8698b3e56216e0750a7414a9a9ca462440cef17f Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Thu, 7 Dec 2023 18:27:10 +0000 Subject: [PATCH 13/39] chore: put scraping timeout back --- e2e/scraping/unprotected.spec.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/e2e/scraping/unprotected.spec.ts b/e2e/scraping/unprotected.spec.ts index da397909..6ec236ef 100644 --- a/e2e/scraping/unprotected.spec.ts +++ b/e2e/scraping/unprotected.spec.ts @@ -13,6 +13,8 @@ test.describe('Scraping flights', () => { test('is possible with Bot detection off', async ({ page }) => { await page.goto('/web-scraping?disableBotDetection=1'); await page.waitForLoadState('networkidle'); + // Artificial wait necessary to prevent flakiness + await page.waitForTimeout(3000); const flightCards = await page.getByTestId(TEST_ID.card).all(); console.log('Found flight cards: ', flightCards.length); From 12af190a6c70c79e19e81879606433d0317e0dbe Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Thu, 7 Dec 2023 19:51:11 +0000 Subject: [PATCH 14/39] ci: add unit tests --- .github/workflows/{playwright.yml => tests.yml} | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) rename .github/workflows/{playwright.yml => tests.yml} (81%) diff --git a/.github/workflows/playwright.yml b/.github/workflows/tests.yml similarity index 81% rename from .github/workflows/playwright.yml rename to .github/workflows/tests.yml index 3a12782c..5b30146c 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/tests.yml @@ -1,4 +1,4 @@ -name: Playwright Tests +name: Tests on: push: branches: [main] @@ -8,7 +8,17 @@ env: # Playwright headless browsers running in CI get low confidence scores, causing flaky tests. Lower the confidence score threshold for CI testing. MIN_CONFIDENCE_SCORE: 0 jobs: - test: + unit-tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install dependencies + run: yarn --frozen-lockfile + + - name: Run unit tests + run: yarn test + e2e-tests: timeout-minutes: 60 runs-on: ubuntu-latest strategy: @@ -20,7 +30,7 @@ jobs: - uses: actions/checkout@v3 - name: Install dependencies - run: yarn + run: yarn --frozen-lockfile - name: Install Playwright Browsers run: yarn playwright install --with-deps From 5cd3910830e804db13ef6bf48cddd134d22539f0 Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Fri, 8 Dec 2023 12:23:12 +0000 Subject: [PATCH 15/39] add eslint to ci, fix eslint errors --- .eslintrc.json | 3 +- .github/workflows/tests.yml | 10 + package.json | 14 +- playwright.config.js | 4 +- .../components/common/Select/Select.tsx | 4 + src/client/components/common/content.tsx | 3 +- src/pages/api/personalization/get-products.ts | 2 +- src/pages/coupon-fraud/index.tsx | 2 +- src/pages/index.tsx | 2 +- src/pages/loan-risk/index.tsx | 2 +- yarn.lock | 1429 ++++++++++++----- 11 files changed, 1048 insertions(+), 427 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index dccc2ec6..95c859c2 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -12,7 +12,8 @@ "react-hooks/exhaustive-deps": "warn", "prettier/prettier": "error", "@typescript-eslint/ban-ts-comment": "off", - "@typescript-eslint/no-explicit-any": "off" + "@typescript-eslint/no-explicit-any": "off", + "react/no-unescaped-entities": "off" }, "env": { "es6": true diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5b30146c..0d0f635f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -8,6 +8,16 @@ env: # Playwright headless browsers running in CI get low confidence scores, causing flaky tests. Lower the confidence score threshold for CI testing. MIN_CONFIDENCE_SCORE: 0 jobs: + eslint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install dependencies + run: yarn --frozen-lockfile + + - name: Run eslint + run: yarn lint unit-tests: runs-on: ubuntu-latest steps: diff --git a/package.json b/package.json index 95203a30..2b4357be 100644 --- a/package.json +++ b/package.json @@ -54,19 +54,19 @@ "zod": "^3.21.4" }, "devDependencies": { - "@playwright/test": "^1.39.0", + "@playwright/test": "^1.40.1", "@types/leaflet": "^1.9.3", "@types/node": "^18.11.18", "@types/react": "^18.0.27", - "@typescript-eslint/eslint-plugin": "^5.60.1", + "@typescript-eslint/eslint-plugin": "^6.13.2", "@vitejs/plugin-react": "^3.0.1", - "eslint": "^8.17.0", - "eslint-config-next": "^13.1.6", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-prettier": "^4.2.1", + "eslint": "^8.55.0", + "eslint-config-next": "^14.0.4", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.0.1", "eslint-plugin-react-hooks": "^4.6.0", "jsdom": "^21.1.0", - "prettier": "^3.0.1", + "prettier": "^3.1.0", "sass": "^1.64.1", "typescript": "^4.9.5", "vitest": "^0.28.3" diff --git a/playwright.config.js b/playwright.config.js index 02dd8ffa..96f6d45b 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -1,4 +1,4 @@ -const { defineConfig, devices } = require('@playwright/test'); +import { defineConfig, devices } from '@playwright/test'; /** * Read environment variables from file. @@ -10,7 +10,7 @@ const isCi = !!process.env.CI; /** * @see https://playwright.dev/docs/test-configuration */ -module.exports = defineConfig({ +export default defineConfig({ testDir: './e2e', /* Maximum time one test can run for. */ timeout: 30 * 1000, diff --git a/src/client/components/common/Select/Select.tsx b/src/client/components/common/Select/Select.tsx index abc10446..9295beac 100644 --- a/src/client/components/common/Select/Select.tsx +++ b/src/client/components/common/Select/Select.tsx @@ -37,6 +37,8 @@ export const Select = React.forwardRef< ); }); +Select.displayName = 'Select'; + export const SelectItem = React.forwardRef< HTMLDivElement, RadixSelect.SelectItemProps & React.RefAttributes @@ -47,3 +49,5 @@ export const SelectItem = React.forwardRef< ); }); + +SelectItem.displayName = 'SelectItem'; diff --git a/src/client/components/common/content.tsx b/src/client/components/common/content.tsx index 6d371d94..006538fe 100644 --- a/src/client/components/common/content.tsx +++ b/src/client/components/common/content.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react/jsx-key */ import Link from 'next/link'; import SmartSignalsIcon from '../../img/smartSignalsIcon.svg'; import CouponFraudIcon from '../../img/couponFraudIcon.svg'; @@ -145,7 +146,7 @@ export const USE_CASES = {

,

Use Fingerprint to check for consistency between applications and ignore submissions from previously rejected - applicants.Ā  + applicants.

, ], description: diff --git a/src/pages/api/personalization/get-products.ts b/src/pages/api/personalization/get-products.ts index fb819fba..5b0032c7 100644 --- a/src/pages/api/personalization/get-products.ts +++ b/src/pages/api/personalization/get-products.ts @@ -60,7 +60,7 @@ export default personalizationEndpoint(async (req, res, { usePersonalizedData, v const { query } = JSON.parse(req.body); - let productsCount = await ProductDbModel.count(); + const productsCount = await ProductDbModel.count(); if (!productsCount) { await seedProducts(); diff --git a/src/pages/coupon-fraud/index.tsx b/src/pages/coupon-fraud/index.tsx index a4ff654c..dcc5d292 100644 --- a/src/pages/coupon-fraud/index.tsx +++ b/src/pages/coupon-fraud/index.tsx @@ -50,7 +50,7 @@ export default function CouponFraudUseCase({ embed }: CustomPageProps) { setIsWaitingForResponse(false); } }, - [couponClaimMutation, couponCode], + [couponClaimMutation, couponCode, getData], ); useEffect(() => { diff --git a/src/pages/index.tsx b/src/pages/index.tsx index c7635e25..53e78d28 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -24,7 +24,7 @@ export default function Index() {

Explore the wide range of major use cases supported by Fingerprint, including a comprehensive demo that - showcases both frontend and backend sample implementations with a persistent data layer for each use case.Ā  + showcases both frontend and backend sample implementations with a persistent data layer for each use case.

diff --git a/src/pages/loan-risk/index.tsx b/src/pages/loan-risk/index.tsx index 44ada1c0..6001b358 100644 --- a/src/pages/loan-risk/index.tsx +++ b/src/pages/loan-risk/index.tsx @@ -101,7 +101,7 @@ export default function LoanRisk({ embed }: CustomPageProps) { body: { loanValue, monthlyIncome, loanDuration, firstName, lastName }, }); }, - [firstName, lastName, loanDuration, loanRequestMutation, loanValue, monthlyIncome], + [firstName, lastName, loanDuration, loanRequestMutation, loanValue, monthlyIncome, getData], ); const isLoading = isVisitorDataLoading || loanRequestMutation.isLoading; diff --git a/yarn.lock b/yarn.lock index 1cbfe727..21e7b74c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,11 @@ # yarn lockfile v1 +"@aashutoshrathi/word-wrap@^1.2.3": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" + integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== + "@ampproject/remapping@^2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" @@ -176,7 +181,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.19.0" -"@babel/runtime@^7.1.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.7", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2": +"@babel/runtime@^7.1.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673" integrity sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw== @@ -197,6 +202,13 @@ dependencies: regenerator-runtime "^0.13.11" +"@babel/runtime@^7.23.2": + version "7.23.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.5.tgz#11edb98f8aeec529b82b211028177679144242db" + integrity sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/template@^7.20.7": version "7.20.7" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.20.7.tgz#a15090c2839a83b02aa996c0b4994005841fd5a8" @@ -498,26 +510,26 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz#c5a1a4bfe1b57f0c3e61b29883525c6da3e5c091" integrity sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q== -"@eslint-community/eslint-utils@^4.2.0": +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== dependencies: eslint-visitor-keys "^3.3.0" -"@eslint-community/regexpp@^4.4.0": - version "4.5.1" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.5.1.tgz#cdd35dce4fa1a89a4fd42b1599eb35b3af408884" - integrity sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ== +"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": + version "4.10.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" + integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== -"@eslint/eslintrc@^1.4.1": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.4.1.tgz#af58772019a2d271b7e2d4c23ff4ddcba3ccfb3e" - integrity sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA== +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.4.0" + espree "^9.6.0" globals "^13.19.0" ignore "^5.2.0" import-fresh "^3.2.1" @@ -525,6 +537,11 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" +"@eslint/js@8.55.0": + version "8.55.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.55.0.tgz#b721d52060f369aa259cf97392403cb9ce892ec6" + integrity sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA== + "@fingerprintjs/fingerprintjs-pro-react@^2.6.2": version "2.6.2" resolved "https://registry.yarnpkg.com/@fingerprintjs/fingerprintjs-pro-react/-/fingerprintjs-pro-react-2.6.2.tgz#55a045afe64a4fd3fbfb8d01e3c28622104c6604" @@ -587,12 +604,12 @@ resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== -"@humanwhocodes/config-array@^0.11.8": - version "0.11.8" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9" - integrity sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g== +"@humanwhocodes/config-array@^0.11.13": + version "0.11.13" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.13.tgz#075dc9684f40a531d9b26b0822153c1e832ee297" + integrity sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ== dependencies: - "@humanwhocodes/object-schema" "^1.2.1" + "@humanwhocodes/object-schema" "^2.0.1" debug "^4.1.1" minimatch "^3.0.5" @@ -601,10 +618,10 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@humanwhocodes/object-schema@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz#e5211452df060fa8522b55c7b3c0c4d1981cb044" + integrity sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw== "@jridgewell/gen-mapping@^0.1.0": version "0.1.1" @@ -773,10 +790,10 @@ resolved "https://registry.yarnpkg.com/@next/env/-/env-14.0.3.tgz#9a58b296e7ae04ffebce8a4e5bd0f87f71de86bd" integrity sha512-7xRqh9nMvP5xrW4/+L0jgRRX+HoNRGnfJpD+5Wq6/13j3dsdzxO3BCXn7D3hMqsDb+vjZnJq+vI7+EtgrYZTeA== -"@next/eslint-plugin-next@13.2.1": - version "13.2.1" - resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-13.2.1.tgz#58dea4d53c0adfc59c10195f51eb8d3575fce414" - integrity sha512-r0i5rcO6SMAZtqiGarUVMr3k256X0R0j6pEkKg4PxqUW+hG0qgMxRVAJsuoRG5OBFkCOlSfWZJ0mP9fQdCcyNg== +"@next/eslint-plugin-next@14.0.4": + version "14.0.4" + resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-14.0.4.tgz#474fd88d92209270021186043513fbdc4203f5ec" + integrity sha512-U3qMNHmEZoVmHA0j/57nRfi3AscXNvkOnxDmle/69Jz/G0o/gWjXTDdlgILZdrxQ0Lw/jv2mPW8PGy0EGIHXhQ== dependencies: glob "7.1.7" @@ -874,12 +891,24 @@ tiny-glob "^0.2.9" tslib "^2.4.0" -"@playwright/test@^1.39.0": - version "1.39.0" - resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.39.0.tgz#d10ba8e38e44104499e25001945f07faa9fa91cd" - integrity sha512-3u1iFqgzl7zr004bGPYiN/5EZpRUSFddQBra8Rqll5N0/vfpqlP9I9EXqAoGacuAbX6c9Ulg/Cjqglp5VkK6UQ== +"@pkgr/utils@^2.4.2": + version "2.4.2" + resolved "https://registry.yarnpkg.com/@pkgr/utils/-/utils-2.4.2.tgz#9e638bbe9a6a6f165580dc943f138fd3309a2cbc" + integrity sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw== + dependencies: + cross-spawn "^7.0.3" + fast-glob "^3.3.0" + is-glob "^4.0.3" + open "^9.1.0" + picocolors "^1.0.0" + tslib "^2.6.0" + +"@playwright/test@^1.40.1": + version "1.40.1" + resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.40.1.tgz#9e66322d97b1d74b9f8718bacab15080f24cde65" + integrity sha512-EaaawMTOeEItCRvfmkI9v6rBkF1svM8wjl/YPRrg2N2Wmp+4qJYkWtJsbew1szfKKDm6fPLy4YAanBhIlf9dWw== dependencies: - playwright "1.39.0" + playwright "1.40.1" "@popperjs/core@^2.11.8": version "2.11.8" @@ -1162,10 +1191,10 @@ resolved "https://registry.yarnpkg.com/@react-leaflet/core/-/core-2.1.0.tgz#383acd31259d7c9ae8fb1b02d5e18fe613c2a13d" integrity sha512-Qk7Pfu8BSarKGqILj4x7bCSZ1pjuAPZ+qmRwH5S7mDS91VSbVVsJSrW4qA+GPrro8t69gFYVMWb1Zc4yFmPiVg== -"@rushstack/eslint-patch@^1.1.3": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz#8be36a1f66f3265389e90b5f9c9962146758f728" - integrity sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg== +"@rushstack/eslint-patch@^1.3.3": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.6.0.tgz#1898e7a7b943680d757417a47fb10f5fcc230b39" + integrity sha512-2/U3GXA6YiPYQDLGwtGlnNgKYBSwCFIHf8Y9LUY5VATHdtbLlU0Y1R3QoBnT0aB4qv/BEiVVsj7LJXoQCgJ2vA== "@socket.io/component-emitter@~3.1.0": version "3.1.0" @@ -1244,10 +1273,10 @@ resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-2.2.7.tgz#226a9e31680835a6188e887f3988e60c04d3f6a3" integrity sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA== -"@types/json-schema@^7.0.9": - version "7.0.12" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" - integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== +"@types/json-schema@^7.0.12": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== "@types/json5@^0.0.29": version "0.0.29" @@ -1326,10 +1355,10 @@ resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== -"@types/semver@^7.3.12": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.0.tgz#591c1ce3a702c45ee15f47a42ade72c2fd78978a" - integrity sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw== +"@types/semver@^7.5.0": + version "7.5.6" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.6.tgz#c65b2bfce1bec346582c07724e3f8c1017a20339" + integrity sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A== "@types/unist@*": version "2.0.6" @@ -1341,123 +1370,95 @@ resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.7.12.tgz#a285379b432cc8d103b69d223cbb159a253cf2f7" integrity sha512-YVtyAPqpefU+Mm/qqnOANW6IkqKpCSrarcyV269C8MA8Ux0dbkEuQwM/4CjL47kVEM2LgBef/ETfkH+c6+moFA== -"@typescript-eslint/eslint-plugin@^5.60.1": - version "5.60.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.60.1.tgz#81382d6ecb92b8dda70e91f9035611cb2fecd1c3" - integrity sha512-KSWsVvsJsLJv3c4e73y/Bzt7OpqMCADUO846bHcuWYSYM19bldbAeDv7dYyV0jwkbMfJ2XdlzwjhXtuD7OY6bw== +"@typescript-eslint/eslint-plugin@^6.13.2": + version "6.13.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.13.2.tgz#2e03506c5362a65e43cb132c37c9ce2d3cb51470" + integrity sha512-3+9OGAWHhk4O1LlcwLBONbdXsAhLjyCFogJY/cWy2lxdVJ2JrcTF2pTGMaLl2AE7U1l31n8Py4a8bx5DLf/0dQ== dependencies: - "@eslint-community/regexpp" "^4.4.0" - "@typescript-eslint/scope-manager" "5.60.1" - "@typescript-eslint/type-utils" "5.60.1" - "@typescript-eslint/utils" "5.60.1" + "@eslint-community/regexpp" "^4.5.1" + "@typescript-eslint/scope-manager" "6.13.2" + "@typescript-eslint/type-utils" "6.13.2" + "@typescript-eslint/utils" "6.13.2" + "@typescript-eslint/visitor-keys" "6.13.2" debug "^4.3.4" - grapheme-splitter "^1.0.4" - ignore "^5.2.0" - natural-compare-lite "^1.4.0" - semver "^7.3.7" - tsutils "^3.21.0" - -"@typescript-eslint/parser@^5.42.0": - version "5.53.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.53.0.tgz#a1f2b9ae73b83181098747e96683f1b249ecab52" - integrity sha512-MKBw9i0DLYlmdOb3Oq/526+al20AJZpANdT6Ct9ffxcV8nKCHz63t/S0IhlTFNsBIHJv+GY5SFJ0XfqVeydQrQ== - dependencies: - "@typescript-eslint/scope-manager" "5.53.0" - "@typescript-eslint/types" "5.53.0" - "@typescript-eslint/typescript-estree" "5.53.0" + graphemer "^1.4.0" + ignore "^5.2.4" + natural-compare "^1.4.0" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/parser@^5.4.2 || ^6.0.0": + version "6.13.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.13.2.tgz#390b79cc9a57a5f904d197a201cc4b6bc4f9afb9" + integrity sha512-MUkcC+7Wt/QOGeVlM8aGGJZy1XV5YKjTpq9jK6r6/iLsGXhBVaGP5N0UYvFsu9BFlSpwY9kMretzdBH01rkRXg== + dependencies: + "@typescript-eslint/scope-manager" "6.13.2" + "@typescript-eslint/types" "6.13.2" + "@typescript-eslint/typescript-estree" "6.13.2" + "@typescript-eslint/visitor-keys" "6.13.2" debug "^4.3.4" -"@typescript-eslint/scope-manager@5.53.0": - version "5.53.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.53.0.tgz#42b54f280e33c82939275a42649701024f3fafef" - integrity sha512-Opy3dqNsp/9kBBeCPhkCNR7fmdSQqA+47r21hr9a14Bx0xnkElEQmhoHga+VoaoQ6uDHjDKmQPIYcUcKJifS7w== - dependencies: - "@typescript-eslint/types" "5.53.0" - "@typescript-eslint/visitor-keys" "5.53.0" - -"@typescript-eslint/scope-manager@5.60.1": - version "5.60.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.60.1.tgz#35abdb47f500c68c08f2f2b4f22c7c79472854bb" - integrity sha512-Dn/LnN7fEoRD+KspEOV0xDMynEmR3iSHdgNsarlXNLGGtcUok8L4N71dxUgt3YvlO8si7E+BJ5Fe3wb5yUw7DQ== +"@typescript-eslint/scope-manager@6.13.2": + version "6.13.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.13.2.tgz#5fa4e4adace028dafac212c770640b94e7b61052" + integrity sha512-CXQA0xo7z6x13FeDYCgBkjWzNqzBn8RXaE3QVQVIUm74fWJLkJkaHmHdKStrxQllGh6Q4eUGyNpMe0b1hMkXFA== dependencies: - "@typescript-eslint/types" "5.60.1" - "@typescript-eslint/visitor-keys" "5.60.1" + "@typescript-eslint/types" "6.13.2" + "@typescript-eslint/visitor-keys" "6.13.2" -"@typescript-eslint/type-utils@5.60.1": - version "5.60.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.60.1.tgz#17770540e98d65ab4730c7aac618003f702893f4" - integrity sha512-vN6UztYqIu05nu7JqwQGzQKUJctzs3/Hg7E2Yx8rz9J+4LgtIDFWjjl1gm3pycH0P3mHAcEUBd23LVgfrsTR8A== +"@typescript-eslint/type-utils@6.13.2": + version "6.13.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.13.2.tgz#ebec2da14a6bb7122e0fd31eea72a382c39c6102" + integrity sha512-Qr6ssS1GFongzH2qfnWKkAQmMUyZSyOr0W54nZNU1MDfo+U4Mv3XveeLZzadc/yq8iYhQZHYT+eoXJqnACM1tw== dependencies: - "@typescript-eslint/typescript-estree" "5.60.1" - "@typescript-eslint/utils" "5.60.1" + "@typescript-eslint/typescript-estree" "6.13.2" + "@typescript-eslint/utils" "6.13.2" debug "^4.3.4" - tsutils "^3.21.0" + ts-api-utils "^1.0.1" -"@typescript-eslint/types@5.53.0": - version "5.53.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.53.0.tgz#f79eca62b97e518ee124086a21a24f3be267026f" - integrity sha512-5kcDL9ZUIP756K6+QOAfPkigJmCPHcLN7Zjdz76lQWWDdzfOhZDTj1irs6gPBKiXx5/6O3L0+AvupAut3z7D2A== +"@typescript-eslint/types@6.13.2": + version "6.13.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.13.2.tgz#c044aac24c2f6cefb8e921e397acad5417dd0ae6" + integrity sha512-7sxbQ+EMRubQc3wTfTsycgYpSujyVbI1xw+3UMRUcrhSy+pN09y/lWzeKDbvhoqcRbHdc+APLs/PWYi/cisLPg== -"@typescript-eslint/types@5.60.1": - version "5.60.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.60.1.tgz#a17473910f6b8d388ea83c9d7051af89c4eb7561" - integrity sha512-zDcDx5fccU8BA0IDZc71bAtYIcG9PowaOwaD8rjYbqwK7dpe/UMQl3inJ4UtUK42nOCT41jTSCwg76E62JpMcg== - -"@typescript-eslint/typescript-estree@5.53.0": - version "5.53.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.53.0.tgz#bc651dc28cf18ab248ecd18a4c886c744aebd690" - integrity sha512-eKmipH7QyScpHSkhbptBBYh9v8FxtngLquq292YTEQ1pxVs39yFBlLC1xeIZcPPz1RWGqb7YgERJRGkjw8ZV7w== +"@typescript-eslint/typescript-estree@6.13.2": + version "6.13.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.2.tgz#ae556ee154c1acf025b48d37c3ef95a1d55da258" + integrity sha512-SuD8YLQv6WHnOEtKv8D6HZUzOub855cfPnPMKvdM/Bh1plv1f7Q/0iFUDLKKlxHcEstQnaUU4QZskgQq74t+3w== dependencies: - "@typescript-eslint/types" "5.53.0" - "@typescript-eslint/visitor-keys" "5.53.0" + "@typescript-eslint/types" "6.13.2" + "@typescript-eslint/visitor-keys" "6.13.2" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" - semver "^7.3.7" - tsutils "^3.21.0" - -"@typescript-eslint/typescript-estree@5.60.1": - version "5.60.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.60.1.tgz#8c71824b7165b64d5ebd7aa42968899525959834" - integrity sha512-hkX70J9+2M2ZT6fhti5Q2FoU9zb+GeZK2SLP1WZlvUDqdMbEKhexZODD1WodNRyO8eS+4nScvT0dts8IdaBzfw== - dependencies: - "@typescript-eslint/types" "5.60.1" - "@typescript-eslint/visitor-keys" "5.60.1" - debug "^4.3.4" - globby "^11.1.0" - is-glob "^4.0.3" - semver "^7.3.7" - tsutils "^3.21.0" - -"@typescript-eslint/utils@5.60.1": - version "5.60.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.60.1.tgz#6861ebedbefba1ac85482d2bdef6f2ff1eb65b80" - integrity sha512-tiJ7FFdFQOWssFa3gqb94Ilexyw0JVxj6vBzaSpfN/8IhoKkDuSAenUKvsSHw2A/TMpJb26izIszTXaqygkvpQ== - dependencies: - "@eslint-community/eslint-utils" "^4.2.0" - "@types/json-schema" "^7.0.9" - "@types/semver" "^7.3.12" - "@typescript-eslint/scope-manager" "5.60.1" - "@typescript-eslint/types" "5.60.1" - "@typescript-eslint/typescript-estree" "5.60.1" - eslint-scope "^5.1.1" - semver "^7.3.7" - -"@typescript-eslint/visitor-keys@5.53.0": - version "5.53.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.53.0.tgz#8a5126623937cdd909c30d8fa72f79fa56cc1a9f" - integrity sha512-JqNLnX3leaHFZEN0gCh81sIvgrp/2GOACZNgO4+Tkf64u51kTpAyWFOY8XHx8XuXr3N2C9zgPPHtcpMg6z1g0w== - dependencies: - "@typescript-eslint/types" "5.53.0" - eslint-visitor-keys "^3.3.0" - -"@typescript-eslint/visitor-keys@5.60.1": - version "5.60.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.60.1.tgz#19a877358bf96318ec35d90bfe6bd1445cce9434" - integrity sha512-xEYIxKcultP6E/RMKqube11pGjXH1DCo60mQoWhVYyKfLkwbIVVjYxmOenNMxILx0TjCujPTjjnTIVzm09TXIw== - dependencies: - "@typescript-eslint/types" "5.60.1" - eslint-visitor-keys "^3.3.0" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/utils@6.13.2": + version "6.13.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.13.2.tgz#8eb89e53adc6d703a879b131e528807245486f89" + integrity sha512-b9Ptq4eAZUym4idijCRzl61oPCwwREcfDI8xGk751Vhzig5fFZR9CyzDz4Sp/nxSLBYxUPyh4QdIDqWykFhNmQ== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@types/json-schema" "^7.0.12" + "@types/semver" "^7.5.0" + "@typescript-eslint/scope-manager" "6.13.2" + "@typescript-eslint/types" "6.13.2" + "@typescript-eslint/typescript-estree" "6.13.2" + semver "^7.5.4" + +"@typescript-eslint/visitor-keys@6.13.2": + version "6.13.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.2.tgz#e0a4a80cf842bb08e6127b903284166ac4a5594c" + integrity sha512-OGznFs0eAQXJsp+xSd6k/O1UbFi/K/L7WjqeRoFE7vadjAF9y0uppXhYNQNEqygjou782maGClOoZwPqF0Drlw== + dependencies: + "@typescript-eslint/types" "6.13.2" + eslint-visitor-keys "^3.4.1" + +"@ungap/structured-clone@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" + integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== "@vitejs/plugin-react@^3.0.1": version "3.1.0" @@ -1547,11 +1548,16 @@ acorn-walk@^8.0.2, acorn-walk@^8.2.0: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== -acorn@^8.1.0, acorn@^8.8.0, acorn@^8.8.1, acorn@^8.8.2: +acorn@^8.1.0, acorn@^8.8.1, acorn@^8.8.2: version "8.8.2" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== +acorn@^8.9.0: + version "8.11.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.2.tgz#ca0d78b51895be5390a5903c5b3bdcdaf78ae40b" + integrity sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w== + agent-base@6, agent-base@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -1576,7 +1582,7 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" -ajv@^6.10.0, ajv@^6.12.4: +ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -1661,12 +1667,20 @@ aria-hidden@^1.1.1: dependencies: tslib "^2.0.0" -aria-query@^5.1.3: - version "5.1.3" - resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.1.3.tgz#19db27cd101152773631396f7a95a3b58c22c35e" - integrity sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ== +aria-query@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.0.tgz#650c569e41ad90b51b3d7df5e5eed1c7549c103e" + integrity sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A== dependencies: - deep-equal "^2.0.5" + dequal "^2.0.3" + +array-buffer-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" + integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== + dependencies: + call-bind "^1.0.2" + is-array-buffer "^3.0.1" array-includes@^3.1.5, array-includes@^3.1.6: version "3.1.6" @@ -1679,11 +1693,33 @@ array-includes@^3.1.5, array-includes@^3.1.6: get-intrinsic "^1.1.3" is-string "^1.0.7" +array-includes@^3.1.7: + version "3.1.7" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.7.tgz#8cd2e01b26f7a3086cbc87271593fe921c62abda" + integrity sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + is-string "^1.0.7" + array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== +array.prototype.findlastindex@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz#b37598438f97b579166940814e2c0493a4f50207" + integrity sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + get-intrinsic "^1.2.1" + array.prototype.flat@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz#ffc6576a7ca3efc2f46a143b9d1dda9b4b3cf5e2" @@ -1694,6 +1730,16 @@ array.prototype.flat@^1.3.1: es-abstract "^1.20.4" es-shim-unscopables "^1.0.0" +array.prototype.flat@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" + integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + array.prototype.flatmap@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz#1aae7903c2100433cb8261cd4ed310aab5c4a183" @@ -1704,6 +1750,16 @@ array.prototype.flatmap@^1.3.1: es-abstract "^1.20.4" es-shim-unscopables "^1.0.0" +array.prototype.flatmap@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" + integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + array.prototype.tosorted@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz#ccf44738aa2b5ac56578ffda97c03fd3e23dd532" @@ -1715,15 +1771,35 @@ array.prototype.tosorted@^1.1.1: es-shim-unscopables "^1.0.0" get-intrinsic "^1.1.3" +arraybuffer.prototype.slice@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz#98bd561953e3e74bb34938e77647179dfe6e9f12" + integrity sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw== + dependencies: + array-buffer-byte-length "^1.0.0" + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + is-array-buffer "^3.0.2" + is-shared-array-buffer "^1.0.2" + assertion-error@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== -ast-types-flow@^0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" - integrity sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag== +ast-types-flow@^0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.8.tgz#0a85e1c92695769ac13a428bb653e7538bea27d6" + integrity sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ== + +asynciterator.prototype@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz#8c5df0514936cdd133604dfcc9d3fb93f09b2b62" + integrity sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg== + dependencies: + has-symbols "^1.0.3" asynckit@^0.4.0: version "0.4.0" @@ -1735,17 +1811,17 @@ available-typed-arrays@^1.0.5: resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== -axe-core@^4.6.2: - version "4.6.3" - resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.6.3.tgz#fc0db6fdb65cc7a80ccf85286d91d64ababa3ece" - integrity sha512-/BQzOX780JhsxDnPpH4ZiyrJAzcd8AfzFPkv+89veFSr1rcMjuq2JDCwypKaPeB6ljHp9KjXhPpjgCvQlWYuqg== +axe-core@=4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.0.tgz#34ba5a48a8b564f67e103f0aa5768d76e15bbbbf" + integrity sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ== -axobject-query@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-3.1.1.tgz#3b6e5c6d4e43ca7ba51c5babf99d22a9c68485e1" - integrity sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg== +axobject-query@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-3.2.1.tgz#39c378a6e3b06ca679f29138151e45b2b32da62a" + integrity sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg== dependencies: - deep-equal "^2.0.5" + dequal "^2.0.3" babel-plugin-macros@^3.1.0: version "3.1.0" @@ -1771,11 +1847,23 @@ big-integer@^1.6.16: resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686" integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg== +big-integer@^1.6.44: + version "1.6.52" + resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.52.tgz#60a887f3047614a8e1bffe5d7173490a97dc8c85" + integrity sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg== + binary-extensions@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== +bplist-parser@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/bplist-parser/-/bplist-parser-0.2.0.tgz#43a9d183e5bf9d545200ceac3e712f79ebbe8d0e" + integrity sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw== + dependencies: + big-integer "^1.6.44" + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -1820,6 +1908,13 @@ 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== +bundle-name@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bundle-name/-/bundle-name-3.0.0.tgz#ba59bcc9ac785fb67ccdbf104a2bf60c099f0e1a" + integrity sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw== + dependencies: + run-applescript "^5.0.0" + busboy@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" @@ -1864,6 +1959,15 @@ call-bind@^1.0.0, call-bind@^1.0.2: function-bind "^1.1.1" get-intrinsic "^1.0.2" +call-bind@^1.0.4, call-bind@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" + integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ== + dependencies: + function-bind "^1.1.2" + get-intrinsic "^1.2.1" + set-function-length "^1.1.1" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -2150,39 +2254,48 @@ deep-eql@^4.1.2: dependencies: type-detect "^4.0.0" -deep-equal@^2.0.5: - version "2.2.0" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.2.0.tgz#5caeace9c781028b9ff459f33b779346637c43e6" - integrity sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw== - dependencies: - call-bind "^1.0.2" - es-get-iterator "^1.1.2" - get-intrinsic "^1.1.3" - is-arguments "^1.1.1" - is-array-buffer "^3.0.1" - is-date-object "^1.0.5" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" - isarray "^2.0.5" - object-is "^1.1.5" - object-keys "^1.1.1" - object.assign "^4.1.4" - regexp.prototype.flags "^1.4.3" - side-channel "^1.0.4" - which-boxed-primitive "^1.0.2" - which-collection "^1.0.1" - which-typed-array "^1.1.9" - deep-is@^0.1.3, deep-is@~0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== +default-browser-id@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/default-browser-id/-/default-browser-id-3.0.0.tgz#bee7bbbef1f4e75d31f98f4d3f1556a14cea790c" + integrity sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA== + dependencies: + bplist-parser "^0.2.0" + untildify "^4.0.0" + +default-browser@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/default-browser/-/default-browser-4.0.0.tgz#53c9894f8810bf86696de117a6ce9085a3cbc7da" + integrity sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA== + dependencies: + bundle-name "^3.0.0" + default-browser-id "^3.0.0" + execa "^7.1.1" + titleize "^3.0.0" + +define-data-property@^1.0.1, define-data-property@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3" + integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ== + dependencies: + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + 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" integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== +define-lazy-prop@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz#dbb19adfb746d7fc6d734a06b72f4a00d021255f" + integrity sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg== + define-properties@^1.1.3, define-properties@^1.1.4: version "1.2.0" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5" @@ -2191,6 +2304,15 @@ define-properties@^1.1.3, define-properties@^1.1.4: has-property-descriptors "^1.0.0" object-keys "^1.1.1" +define-properties@^1.2.0, define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -2206,6 +2328,11 @@ depd@^1.1.2: resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== +dequal@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" + integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== + detect-libc@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.1.tgz#e1897aa88fa6ad197862937fbc0441ef352ee0cd" @@ -2402,20 +2529,70 @@ es-abstract@^1.19.0, es-abstract@^1.20.4: unbox-primitive "^1.0.2" which-typed-array "^1.1.9" -es-get-iterator@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.3.tgz#3ef87523c5d464d41084b2c3c9c214f1199763d6" - integrity sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw== +es-abstract@^1.22.1: + version "1.22.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.3.tgz#48e79f5573198de6dee3589195727f4f74bc4f32" + integrity sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA== dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.3" + array-buffer-byte-length "^1.0.0" + arraybuffer.prototype.slice "^1.0.2" + available-typed-arrays "^1.0.5" + call-bind "^1.0.5" + es-set-tostringtag "^2.0.1" + es-to-primitive "^1.2.1" + function.prototype.name "^1.1.6" + get-intrinsic "^1.2.2" + get-symbol-description "^1.0.0" + globalthis "^1.0.3" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + has-proto "^1.0.1" has-symbols "^1.0.3" - is-arguments "^1.1.1" - is-map "^2.0.2" - is-set "^2.0.2" + hasown "^2.0.0" + internal-slot "^1.0.5" + is-array-buffer "^3.0.2" + is-callable "^1.2.7" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" is-string "^1.0.7" - isarray "^2.0.5" - stop-iteration-iterator "^1.0.0" + is-typed-array "^1.1.12" + is-weakref "^1.0.2" + object-inspect "^1.13.1" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.5.1" + safe-array-concat "^1.0.1" + safe-regex-test "^1.0.0" + string.prototype.trim "^1.2.8" + string.prototype.trimend "^1.0.7" + string.prototype.trimstart "^1.0.7" + typed-array-buffer "^1.0.0" + typed-array-byte-length "^1.0.0" + typed-array-byte-offset "^1.0.0" + typed-array-length "^1.0.4" + unbox-primitive "^1.0.2" + which-typed-array "^1.1.13" + +es-iterator-helpers@^1.0.12, es-iterator-helpers@^1.0.15: + version "1.0.15" + resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.15.tgz#bd81d275ac766431d19305923707c3efd9f1ae40" + integrity sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g== + dependencies: + asynciterator.prototype "^1.0.0" + call-bind "^1.0.2" + define-properties "^1.2.1" + es-abstract "^1.22.1" + es-set-tostringtag "^2.0.1" + function-bind "^1.1.1" + get-intrinsic "^1.2.1" + globalthis "^1.0.3" + has-property-descriptors "^1.0.0" + has-proto "^1.0.1" + has-symbols "^1.0.3" + internal-slot "^1.0.5" + iterator.prototype "^1.1.2" + safe-array-concat "^1.0.1" es-set-tostringtag@^2.0.1: version "2.0.1" @@ -2497,27 +2674,27 @@ escodegen@^2.0.0: optionalDependencies: source-map "~0.6.1" -eslint-config-next@^13.1.6: - version "13.2.1" - resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-13.2.1.tgz#644fb3496b832bc1e32f2c57cce1ec3eeb7bb7a1" - integrity sha512-2GAx7EjSiCzJN6H2L/v1kbYrNiwQxzkyjy6eWSjuhAKt+P6d3nVNHGy9mON8ZcYd72w/M8kyMjm4UB9cvijgrw== +eslint-config-next@^14.0.4: + version "14.0.4" + resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-14.0.4.tgz#7cd2c0a3b310203d41cf0dbf9d31f9b0a6235b4a" + integrity sha512-9/xbOHEQOmQtqvQ1UsTQZpnA7SlDMBtuKJ//S4JnoyK3oGLhILKXdBgu/UO7lQo/2xOykQULS1qQ6p2+EpHgAQ== dependencies: - "@next/eslint-plugin-next" "13.2.1" - "@rushstack/eslint-patch" "^1.1.3" - "@typescript-eslint/parser" "^5.42.0" + "@next/eslint-plugin-next" "14.0.4" + "@rushstack/eslint-patch" "^1.3.3" + "@typescript-eslint/parser" "^5.4.2 || ^6.0.0" eslint-import-resolver-node "^0.3.6" eslint-import-resolver-typescript "^3.5.2" - eslint-plugin-import "^2.26.0" - eslint-plugin-jsx-a11y "^6.5.1" - eslint-plugin-react "^7.31.7" - eslint-plugin-react-hooks "^4.5.0" + eslint-plugin-import "^2.28.1" + eslint-plugin-jsx-a11y "^6.7.1" + eslint-plugin-react "^7.33.2" + eslint-plugin-react-hooks "^4.5.0 || 5.0.0-canary-7118f5dd7-20230705" -eslint-config-prettier@^8.5.0: - version "8.6.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.6.0.tgz#dec1d29ab728f4fa63061774e1672ac4e363d207" - integrity sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA== +eslint-config-prettier@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz#31af3d94578645966c082fcb71a5846d3c94867f" + integrity sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw== -eslint-import-resolver-node@^0.3.6, eslint-import-resolver-node@^0.3.7: +eslint-import-resolver-node@^0.3.6: version "0.3.7" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz#83b375187d412324a1963d84fa664377a23eb4d7" integrity sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA== @@ -2526,6 +2703,15 @@ eslint-import-resolver-node@^0.3.6, eslint-import-resolver-node@^0.3.7: is-core-module "^2.11.0" resolve "^1.22.1" +eslint-import-resolver-node@^0.3.9: + version "0.3.9" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" + integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== + dependencies: + debug "^3.2.7" + is-core-module "^2.13.0" + resolve "^1.22.4" + eslint-import-resolver-typescript@^3.5.2: version "3.5.3" resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.5.3.tgz#db5ed9e906651b7a59dd84870aaef0e78c663a05" @@ -2539,77 +2725,81 @@ eslint-import-resolver-typescript@^3.5.2: is-glob "^4.0.3" synckit "^0.8.4" -eslint-module-utils@^2.7.4: - version "2.7.4" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz#4f3e41116aaf13a20792261e61d3a2e7e0583974" - integrity sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA== +eslint-module-utils@^2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz#e439fee65fc33f6bba630ff621efc38ec0375c49" + integrity sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw== dependencies: debug "^3.2.7" -eslint-plugin-import@^2.26.0: - version "2.27.5" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz#876a6d03f52608a3e5bb439c2550588e51dd6c65" - integrity sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow== +eslint-plugin-import@^2.28.1: + version "2.29.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz#8133232e4329ee344f2f612885ac3073b0b7e155" + integrity sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg== dependencies: - array-includes "^3.1.6" - array.prototype.flat "^1.3.1" - array.prototype.flatmap "^1.3.1" + array-includes "^3.1.7" + array.prototype.findlastindex "^1.2.3" + array.prototype.flat "^1.3.2" + array.prototype.flatmap "^1.3.2" debug "^3.2.7" doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.7" - eslint-module-utils "^2.7.4" - has "^1.0.3" - is-core-module "^2.11.0" + eslint-import-resolver-node "^0.3.9" + eslint-module-utils "^2.8.0" + hasown "^2.0.0" + is-core-module "^2.13.1" is-glob "^4.0.3" minimatch "^3.1.2" - object.values "^1.1.6" - resolve "^1.22.1" - semver "^6.3.0" - tsconfig-paths "^3.14.1" - -eslint-plugin-jsx-a11y@^6.5.1: - version "6.7.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz#fca5e02d115f48c9a597a6894d5bcec2f7a76976" - integrity sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA== - dependencies: - "@babel/runtime" "^7.20.7" - aria-query "^5.1.3" - array-includes "^3.1.6" - array.prototype.flatmap "^1.3.1" - ast-types-flow "^0.0.7" - axe-core "^4.6.2" - axobject-query "^3.1.1" + object.fromentries "^2.0.7" + object.groupby "^1.0.1" + object.values "^1.1.7" + semver "^6.3.1" + tsconfig-paths "^3.14.2" + +eslint-plugin-jsx-a11y@^6.7.1: + version "6.8.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz#2fa9c701d44fcd722b7c771ec322432857fcbad2" + integrity sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA== + dependencies: + "@babel/runtime" "^7.23.2" + aria-query "^5.3.0" + array-includes "^3.1.7" + array.prototype.flatmap "^1.3.2" + ast-types-flow "^0.0.8" + axe-core "=4.7.0" + axobject-query "^3.2.1" damerau-levenshtein "^1.0.8" emoji-regex "^9.2.2" - has "^1.0.3" - jsx-ast-utils "^3.3.3" - language-tags "=1.0.5" + es-iterator-helpers "^1.0.15" + hasown "^2.0.0" + jsx-ast-utils "^3.3.5" + language-tags "^1.0.9" minimatch "^3.1.2" - object.entries "^1.1.6" - object.fromentries "^2.0.6" - semver "^6.3.0" + object.entries "^1.1.7" + object.fromentries "^2.0.7" -eslint-plugin-prettier@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz#651cbb88b1dab98bfd42f017a12fa6b2d993f94b" - integrity sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ== +eslint-plugin-prettier@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.1.tgz#a3b399f04378f79f066379f544e42d6b73f11515" + integrity sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg== dependencies: prettier-linter-helpers "^1.0.0" + synckit "^0.8.5" -eslint-plugin-react-hooks@^4.5.0, eslint-plugin-react-hooks@^4.6.0: +"eslint-plugin-react-hooks@^4.5.0 || 5.0.0-canary-7118f5dd7-20230705", eslint-plugin-react-hooks@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3" integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g== -eslint-plugin-react@^7.31.7: - version "7.32.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz#e71f21c7c265ebce01bcbc9d0955170c55571f10" - integrity sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg== +eslint-plugin-react@^7.33.2: + version "7.33.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz#69ee09443ffc583927eafe86ffebb470ee737608" + integrity sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw== dependencies: array-includes "^3.1.6" array.prototype.flatmap "^1.3.1" array.prototype.tosorted "^1.1.1" doctrine "^2.1.0" + es-iterator-helpers "^1.0.12" estraverse "^5.3.0" jsx-ast-utils "^2.4.1 || ^3.0.0" minimatch "^3.1.2" @@ -2619,105 +2809,89 @@ eslint-plugin-react@^7.31.7: object.values "^1.1.6" prop-types "^15.8.1" resolve "^2.0.0-next.4" - semver "^6.3.0" + semver "^6.3.1" string.prototype.matchall "^4.0.8" -eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-scope@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" - integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" -eslint-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" - integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== - dependencies: - eslint-visitor-keys "^2.0.0" - -eslint-visitor-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== - eslint-visitor-keys@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== -eslint@^8.17.0: - version "8.34.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.34.0.tgz#fe0ab0ef478104c1f9ebc5537e303d25a8fb22d6" - integrity sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg== +eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint@^8.55.0: + version "8.55.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.55.0.tgz#078cb7b847d66f2c254ea1794fa395bf8e7e03f8" + integrity sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA== dependencies: - "@eslint/eslintrc" "^1.4.1" - "@humanwhocodes/config-array" "^0.11.8" + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.55.0" + "@humanwhocodes/config-array" "^0.11.13" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" - ajv "^6.10.0" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" debug "^4.3.2" doctrine "^3.0.0" escape-string-regexp "^4.0.0" - eslint-scope "^7.1.1" - eslint-utils "^3.0.0" - eslint-visitor-keys "^3.3.0" - espree "^9.4.0" - esquery "^1.4.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" + esquery "^1.4.2" esutils "^2.0.2" fast-deep-equal "^3.1.3" file-entry-cache "^6.0.1" find-up "^5.0.0" glob-parent "^6.0.2" globals "^13.19.0" - grapheme-splitter "^1.0.4" + graphemer "^1.4.0" ignore "^5.2.0" - import-fresh "^3.0.0" imurmurhash "^0.1.4" is-glob "^4.0.0" is-path-inside "^3.0.3" - js-sdsl "^4.1.4" js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" lodash.merge "^4.6.2" minimatch "^3.1.2" natural-compare "^1.4.0" - optionator "^0.9.1" - regexpp "^3.2.0" + optionator "^0.9.3" strip-ansi "^6.0.1" - strip-json-comments "^3.1.0" text-table "^0.2.0" -espree@^9.4.0: - version "9.4.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.1.tgz#51d6092615567a2c2cff7833445e37c28c0065bd" - integrity sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg== +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== dependencies: - acorn "^8.8.0" + acorn "^8.9.0" acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.3.0" + eslint-visitor-keys "^3.4.1" esprima@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.4.0: - version "1.4.2" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.2.tgz#c6d3fee05dd665808e2ad870631f221f5617b1d1" - integrity sha512-JVSoLdTlTDkmjFmab7H/9SL9qGSyjElT3myyKp7krqjVFQCDLmj1QFaCLRFBszBKI0XVZaiiXvuPIX3ZwHe1Ng== +esquery@^1.4.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== dependencies: estraverse "^5.1.0" @@ -2728,11 +2902,6 @@ esrecurse@^4.3.0: dependencies: estraverse "^5.2.0" -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" @@ -2743,6 +2912,36 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +execa@^7.1.1: + version "7.2.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-7.2.0.tgz#657e75ba984f42a70f38928cedc87d6f2d4fe4e9" + integrity sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.1" + human-signals "^4.3.0" + is-stream "^3.0.0" + merge-stream "^2.0.0" + npm-run-path "^5.1.0" + onetime "^6.0.0" + signal-exit "^3.0.7" + strip-final-newline "^3.0.0" + fast-deep-equal@3.1.3, fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -2764,6 +2963,17 @@ fast-glob@^3.2.11, fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.4" +fast-glob@^3.3.0: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -2895,6 +3105,11 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + function.prototype.name@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" @@ -2905,7 +3120,17 @@ function.prototype.name@^1.1.5: es-abstract "^1.19.0" functions-have-names "^1.2.2" -functions-have-names@^1.2.2: +function.prototype.name@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" + integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + functions-have-names "^1.2.3" + +functions-have-names@^1.2.2, functions-have-names@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== @@ -2958,11 +3183,26 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@ has "^1.0.3" has-symbols "^1.0.3" +get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b" + integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA== + dependencies: + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + get-nonce@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3" integrity sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q== +get-stream@^6.0.0, get-stream@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + get-symbol-description@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" @@ -3093,10 +3333,10 @@ graceful-fs@^4.2.4, graceful-fs@^4.2.6: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== -grapheme-splitter@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" - integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== has-bigints@^1.0.1, has-bigints@^1.0.2: version "1.0.2" @@ -3149,6 +3389,13 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +hasown@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" + integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== + dependencies: + function-bind "^1.1.2" + hast-util-parse-selector@^2.0.0: version "2.2.5" resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz#d57c23f4da16ae3c63b3b6ca4616683313499c3a" @@ -3215,6 +3462,16 @@ https-proxy-agent@^5.0.0, https-proxy-agent@^5.0.1: agent-base "6" debug "4" +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +human-signals@^4.3.0: + version "4.3.1" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2" + integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ== + humanize-ms@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" @@ -3239,12 +3496,17 @@ ignore@^5.2.0: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== +ignore@^5.2.4: + version "5.3.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.0.tgz#67418ae40d34d6999c95ff56016759c718c82f78" + integrity sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg== + immutable@^4.0.0: version "4.3.1" resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.1.tgz#17988b356097ab0719e2f741d56f3ec6c317f9dc" integrity sha512-lj9cnmB/kVS0QHsJnYKD1uo3o39nrbKxszjnqS9Fr6NB7bZzW45U6WSGBPKXDL/CvDKqDNPA4r3DoDQ8GTxo2A== -import-fresh@^3.0.0, import-fresh@^3.2.1: +import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== @@ -3307,6 +3569,15 @@ internal-slot@^1.0.3, internal-slot@^1.0.4: has "^1.0.3" side-channel "^1.0.4" +internal-slot@^1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.6.tgz#37e756098c4911c5e912b8edbf71ed3aa116f930" + integrity sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg== + dependencies: + get-intrinsic "^1.2.2" + hasown "^2.0.0" + side-channel "^1.0.4" + invariant@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" @@ -3332,14 +3603,6 @@ is-alphanumerical@^1.0.0: is-alphabetical "^1.0.0" is-decimal "^1.0.0" -is-arguments@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" - integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - is-array-buffer@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.1.tgz#deb1db4fcae48308d54ef2442706c0393997052a" @@ -3349,11 +3612,27 @@ is-array-buffer@^3.0.1: get-intrinsic "^1.1.3" is-typed-array "^1.1.10" +is-array-buffer@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" + integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.0" + is-typed-array "^1.1.10" + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== +is-async-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.0.0.tgz#8e4418efd3e5d3a6ebb0164c05ef5afb69aa9646" + integrity sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA== + dependencies: + has-tostringtag "^1.0.0" + is-bigint@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" @@ -3388,6 +3667,13 @@ is-core-module@^2.10.0, is-core-module@^2.11.0, is-core-module@^2.9.0: dependencies: has "^1.0.3" +is-core-module@^2.13.0, is-core-module@^2.13.1: + version "2.13.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== + dependencies: + hasown "^2.0.0" + is-date-object@^1.0.1, is-date-object@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" @@ -3405,11 +3691,23 @@ is-docker@^2.0.0, is-docker@^2.1.1: resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== +is-docker@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-3.0.0.tgz#90093aa3106277d8a77a5910dbae71747e15a200" + integrity sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ== + is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== +is-finalizationregistry@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz#c8749b65f17c133313e661b1289b95ad3dbd62e6" + integrity sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw== + dependencies: + call-bind "^1.0.2" + is-fullwidth-code-point@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" @@ -3420,6 +3718,13 @@ is-fullwidth-code-point@^4.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz#fae3167c729e7463f8461ce512b080a49268aa88" integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== +is-generator-function@^1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" + integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== + dependencies: + has-tostringtag "^1.0.0" + is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" @@ -3432,12 +3737,19 @@ is-hexadecimal@^1.0.0: resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== +is-inside-container@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-inside-container/-/is-inside-container-1.0.0.tgz#e81fba699662eb31dbdaf26766a61d4814717ea4" + integrity sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA== + dependencies: + is-docker "^3.0.0" + is-lambda@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== -is-map@^2.0.1, is-map@^2.0.2: +is-map@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== @@ -3477,7 +3789,7 @@ is-regex@^1.1.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-set@^2.0.1, is-set@^2.0.2: +is-set@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== @@ -3489,6 +3801,16 @@ is-shared-array-buffer@^1.0.2: dependencies: call-bind "^1.0.2" +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" + integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== + is-string@^1.0.5, is-string@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" @@ -3514,6 +3836,13 @@ is-typed-array@^1.1.10, is-typed-array@^1.1.9: gopd "^1.0.1" has-tostringtag "^1.0.0" +is-typed-array@^1.1.12: + version "1.1.12" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" + integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== + dependencies: + which-typed-array "^1.1.11" + is-weakmap@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" @@ -3551,16 +3880,22 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +iterator.prototype@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.2.tgz#5e29c8924f01916cb9335f1ff80619dcff22b0c0" + integrity sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w== + dependencies: + define-properties "^1.2.1" + get-intrinsic "^1.2.1" + has-symbols "^1.0.3" + reflect.getprototypeof "^1.0.4" + set-function-name "^2.0.1" + js-cookie@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ== -js-sdsl@^4.1.4: - version "4.3.0" - resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.3.0.tgz#aeefe32a451f7af88425b11fdb5f58c90ae1d711" - integrity sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ== - js-sha3@0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" @@ -3630,7 +3965,7 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== -json5@^1.0.1: +json5@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== @@ -3647,7 +3982,7 @@ jsonc-parser@^3.2.0: resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w== -"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.3: +"jsx-ast-utils@^2.4.1 || ^3.0.0": version "3.3.3" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz#76b3e6e6cece5c69d49a5792c3d01bd1a0cdc7ea" integrity sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw== @@ -3655,17 +3990,27 @@ jsonc-parser@^3.2.0: array-includes "^3.1.5" object.assign "^4.1.3" -language-subtag-registry@~0.3.2: +jsx-ast-utils@^3.3.5: + version "3.3.5" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz#4766bd05a8e2a11af222becd19e15575e52a853a" + integrity sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ== + dependencies: + array-includes "^3.1.6" + array.prototype.flat "^1.3.1" + object.assign "^4.1.4" + object.values "^1.1.6" + +language-subtag-registry@^0.3.20: version "0.3.22" resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz#2e1500861b2e457eba7e7ae86877cbd08fa1fd1d" integrity sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w== -language-tags@=1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.5.tgz#d321dbc4da30ba8bf3024e040fa5c14661f9193a" - integrity sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ== +language-tags@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.9.tgz#1ffdcd0ec0fafb4b1be7f8b11f306ad0f9c08777" + integrity sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA== dependencies: - language-subtag-registry "~0.3.2" + language-subtag-registry "^0.3.20" leaflet@^1.9.4: version "1.9.4" @@ -3800,6 +4145,11 @@ mdn-data@2.0.14: resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" @@ -3830,6 +4180,16 @@ mime-types@^2.1.12, mime-types@~2.1.34: dependencies: mime-db "1.52.0" +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mimic-fn@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" + integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== + minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -3974,11 +4334,6 @@ nanoid@^3.3.6: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== -natural-compare-lite@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" - integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== - natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -4079,6 +4434,20 @@ notistack@^3.0.1: clsx "^1.1.0" goober "^2.0.33" +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +npm-run-path@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.1.0.tgz#bc62f7f3f6952d9894bd08944ba011a6ee7b7e00" + integrity sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q== + dependencies: + path-key "^4.0.0" + npmlog@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0" @@ -4114,13 +4483,10 @@ object-inspect@^1.12.2, object-inspect@^1.9.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== -object-is@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" - integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" +object-inspect@^1.13.1: + version "1.13.1" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" + integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== object-keys@^1.1.1: version "1.1.1" @@ -4146,6 +4512,15 @@ object.entries@^1.1.6: define-properties "^1.1.4" es-abstract "^1.20.4" +object.entries@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.7.tgz#2b47760e2a2e3a752f39dd874655c61a7f03c131" + integrity sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + object.fromentries@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.6.tgz#cdb04da08c539cffa912dcd368b886e0904bfa73" @@ -4155,6 +4530,25 @@ object.fromentries@^2.0.6: define-properties "^1.1.4" es-abstract "^1.20.4" +object.fromentries@^2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.7.tgz#71e95f441e9a0ea6baf682ecaaf37fa2a8d7e616" + integrity sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +object.groupby@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.1.tgz#d41d9f3c8d6c778d9cbac86b4ee9f5af103152ee" + integrity sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + object.hasown@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.2.tgz#f919e21fad4eb38a57bc6345b3afd496515c3f92" @@ -4172,6 +4566,15 @@ object.values@^1.1.6: define-properties "^1.1.4" es-abstract "^1.20.4" +object.values@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.7.tgz#617ed13272e7e1071b43973aa1655d9291b8442a" + integrity sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + oblivious-set@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/oblivious-set/-/oblivious-set-1.0.0.tgz#c8316f2c2fb6ff7b11b6158db3234c49f733c566" @@ -4184,6 +4587,20 @@ once@^1.3.0: dependencies: wrappy "1" +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +onetime@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4" + integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== + dependencies: + mimic-fn "^4.0.0" + open@^8.4.0: version "8.4.2" resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9" @@ -4193,6 +4610,16 @@ open@^8.4.0: is-docker "^2.1.1" is-wsl "^2.2.0" +open@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/open/-/open-9.1.0.tgz#684934359c90ad25742f5a26151970ff8c6c80b6" + integrity sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg== + dependencies: + default-browser "^4.0.0" + define-lazy-prop "^3.0.0" + is-inside-container "^1.0.0" + is-wsl "^2.2.0" + optionator@^0.8.1: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" @@ -4205,17 +4632,17 @@ optionator@^0.8.1: type-check "~0.3.2" word-wrap "~1.2.3" -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== +optionator@^0.9.3: + version "0.9.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" + integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== dependencies: + "@aashutoshrathi/word-wrap" "^1.2.3" deep-is "^0.1.3" fast-levenshtein "^2.0.6" levn "^0.4.1" prelude-ls "^1.2.1" type-check "^0.4.0" - word-wrap "^1.2.3" p-limit@^3.0.2: version "3.1.0" @@ -4291,11 +4718,16 @@ 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@^3.1.0: +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" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== +path-key@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" + integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== + path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" @@ -4340,17 +4772,17 @@ pkg-types@^1.0.1: mlly "^1.1.1" pathe "^1.1.0" -playwright-core@1.39.0: - version "1.39.0" - resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.39.0.tgz#efeaea754af4fb170d11845b8da30b2323287c63" - integrity sha512-+k4pdZgs1qiM+OUkSjx96YiKsXsmb59evFoqv8SKO067qBA+Z2s/dCzJij/ZhdQcs2zlTAgRKfeiiLm8PQ2qvw== +playwright-core@1.40.1: + version "1.40.1" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.40.1.tgz#442d15e86866a87d90d07af528e0afabe4c75c05" + integrity sha512-+hkOycxPiV534c4HhpfX6yrlawqVUzITRKwHAmYfmsVreltEl6fAZJ3DPfLMOODw0H3s1Itd6MDCWmP1fl/QvQ== -playwright@1.39.0: - version "1.39.0" - resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.39.0.tgz#184c81cd6478f8da28bcd9e60e94fcebf566e077" - integrity sha512-naE5QT11uC/Oiq0BwZ50gDmy8c8WLPRTEWuSSFVG2egBka/1qMoSqYQcROMT9zLwJ86oPofcTH2jBY/5wWOgIw== +playwright@1.40.1: + version "1.40.1" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.40.1.tgz#a11bf8dca15be5a194851dbbf3df235b9f53d7ae" + integrity sha512-2eHI7IioIpQ0bS1Ovg/HszsN/XKNwEG1kbzSDDmADpclKc7CyqkHw7Mg2JCz/bbCxg25QUPcjksoMW7JcIFQmw== dependencies: - playwright-core "1.39.0" + playwright-core "1.40.1" optionalDependencies: fsevents "2.3.2" @@ -4389,10 +4821,10 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.1.tgz#65271fc9320ce4913c57747a70ce635b30beaa40" - integrity sha512-fcOWSnnpCrovBsmFZIGIy9UqK2FaI7Hqax+DIO0A9UxeVoY4iweyaFjS5TavZN97Hfehph0nhsZnjlVKzEQSrQ== +prettier@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.1.0.tgz#c6d16474a5f764ea1a4a373c593b779697744d5e" + integrity sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw== pretty-format@^27.5.1: version "27.5.1" @@ -4603,6 +5035,18 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" +reflect.getprototypeof@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz#aaccbf41aca3821b87bb71d9dcbc7ad0ba50a3f3" + integrity sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + globalthis "^1.0.3" + which-builtin-type "^1.1.3" + refractor@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/refractor/-/refractor-3.6.0.tgz#ac318f5a0715ead790fcfb0c71f4dd83d977935a" @@ -4631,10 +5075,14 @@ regexp.prototype.flags@^1.4.3: define-properties "^1.1.3" functions-have-names "^1.2.2" -regexpp@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== +regexp.prototype.flags@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz#90ce989138db209f81492edd734183ce99f9677e" + integrity sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + set-function-name "^2.0.0" remove-accents@0.4.2: version "0.4.2" @@ -4665,6 +5113,15 @@ resolve@^1.19.0, resolve@^1.22.1: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +resolve@^1.22.4: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + resolve@^2.0.0-next.4: version "2.0.0-next.4" resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.4.tgz#3d37a113d6429f496ec4752d2a2e58efb1fd4660" @@ -4710,6 +5167,13 @@ rtl-css-js@^1.14.0: dependencies: "@babel/runtime" "^7.1.2" +run-applescript@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/run-applescript/-/run-applescript-5.0.0.tgz#e11e1c932e055d5c6b40d98374e0268d9b11899c" + integrity sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg== + dependencies: + execa "^5.0.0" + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -4717,6 +5181,16 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +safe-array-concat@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.0.1.tgz#91686a63ce3adbea14d61b14c99572a8ff84754c" + integrity sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + has-symbols "^1.0.3" + isarray "^2.0.5" + safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" @@ -4769,13 +5243,25 @@ semver@^6.0.0, 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.5, semver@^7.3.7: +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.3.5: version "7.3.8" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== dependencies: lru-cache "^6.0.0" +semver@^7.5.4: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + sequelize-pool@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/sequelize-pool/-/sequelize-pool-7.1.0.tgz#210b391af4002762f823188fd6ecfc7413020768" @@ -4808,6 +5294,25 @@ set-blocking@^2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== +set-function-length@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.1.1.tgz#4bc39fafb0307224a33e106a7d35ca1218d659ed" + integrity sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ== + dependencies: + define-data-property "^1.1.1" + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + +set-function-name@^2.0.0, set-function-name@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.1.tgz#12ce38b7954310b9f61faa12701620a0c882793a" + integrity sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA== + dependencies: + define-data-property "^1.0.1" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.0" + set-harmonic-interval@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/set-harmonic-interval/-/set-harmonic-interval-1.0.1.tgz#e1773705539cdfb80ce1c3d99e7f298bb3995249" @@ -4839,7 +5344,7 @@ siginfo@^2.0.0: resolved "https://registry.yarnpkg.com/siginfo/-/siginfo-2.0.0.tgz#32e76c70b79724e3bb567cb9d543eb858ccfaf30" integrity sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g== -signal-exit@^3.0.0, signal-exit@^3.0.7: +signal-exit@^3.0.0, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== @@ -5016,13 +5521,6 @@ std-env@^3.3.1: resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.3.2.tgz#af27343b001616015534292178327b202b9ee955" integrity sha512-uUZI65yrV2Qva5gqE0+A7uVAvO40iPo6jGhs7s8keRfHCmtg+uB2X6EiLGCI9IgL1J17xGhvoOqSz79lzICPTA== -stop-iteration-iterator@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz#6a60be0b4ee757d1ed5254858ec66b10c49285e4" - integrity sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ== - dependencies: - internal-slot "^1.0.4" - streamsearch@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" @@ -5060,6 +5558,15 @@ string.prototype.matchall@^4.0.8: regexp.prototype.flags "^1.4.3" side-channel "^1.0.4" +string.prototype.trim@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz#f9ac6f8af4bd55ddfa8895e6aea92a96395393bd" + integrity sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + string.prototype.trimend@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" @@ -5069,6 +5576,15 @@ string.prototype.trimend@^1.0.6: define-properties "^1.1.4" es-abstract "^1.20.4" +string.prototype.trimend@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz#1bb3afc5008661d73e2dc015cd4853732d6c471e" + integrity sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + string.prototype.trimstart@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4" @@ -5078,6 +5594,15 @@ string.prototype.trimstart@^1.0.6: define-properties "^1.1.4" es-abstract "^1.20.4" +string.prototype.trimstart@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz#d4cdb44b83a4737ffbac2d406e405d43d0184298" + integrity sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" @@ -5104,7 +5629,17 @@ strip-bom@^3.0.0: resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-final-newline@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" + integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== + +strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -5170,6 +5705,14 @@ synckit@^0.8.4: "@pkgr/utils" "^2.3.1" tslib "^2.5.0" +synckit@^0.8.5: + version "0.8.6" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.8.6.tgz#b69b7fbce3917c2673cbdc0d87fb324db4a5b409" + integrity sha512-laHF2savN6sMeHCjLRkheIU4wo3Zg9Ln5YOjOo7sZ5dVQW8yF5pPE5SIw1dsPhq3TRp1jisKRCdPhfs/1WMqDA== + dependencies: + "@pkgr/utils" "^2.4.2" + tslib "^2.6.2" + tapable@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" @@ -5220,6 +5763,11 @@ tinyspy@^1.0.2: resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-1.1.1.tgz#0cb91d5157892af38cb2d217f5c7e8507a5bf092" integrity sha512-UVq5AXt/gQlti7oxoIg5oi/9r0WpF7DGEVwXgqWSMmyN16+e3tl5lIvTaOpJ3TAtu5xFzWccFRM4R5NaWHF+4g== +titleize@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/titleize/-/titleize-3.0.0.tgz#71c12eb7fdd2558aa8a44b0be83b8a76694acd53" + integrity sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ== + to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" @@ -5264,27 +5812,27 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== +ts-api-utils@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.3.tgz#f12c1c781d04427313dbac808f453f050e54a331" + integrity sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg== + ts-easing@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/ts-easing/-/ts-easing-0.2.0.tgz#c8a8a35025105566588d87dbda05dd7fbfa5a4ec" integrity sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ== -tsconfig-paths@^3.14.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" - integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== +tsconfig-paths@^3.14.2: + version "3.14.2" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz#6e32f1f79412decd261f92d633a9dc1cfa99f088" + integrity sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g== dependencies: "@types/json5" "^0.0.29" - json5 "^1.0.1" + json5 "^1.0.2" minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^1.8.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -tslib@^2.0.0, tslib@^2.4.1: +tslib@^2.0.0, tslib@^2.4.1, tslib@^2.6.0, tslib@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== @@ -5294,13 +5842,6 @@ tslib@^2.1.0, tslib@^2.4.0, tslib@^2.5.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== -tsutils@^3.21.0: - version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== - dependencies: - tslib "^1.8.1" - type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -5325,6 +5866,36 @@ type-fest@^0.20.2: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== +typed-array-buffer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" + integrity sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + is-typed-array "^1.1.10" + +typed-array-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz#d787a24a995711611fb2b87a4052799517b230d0" + integrity sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + has-proto "^1.0.1" + is-typed-array "^1.1.10" + +typed-array-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz#cbbe89b51fdef9cd6aaf07ad4707340abbc4ea0b" + integrity sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + has-proto "^1.0.1" + is-typed-array "^1.1.10" + typed-array-length@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" @@ -5381,6 +5952,11 @@ unload@2.2.0: "@babel/runtime" "^7.6.2" detect-node "^2.0.4" +untildify@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" + integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== + update-browserslist-db@^1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3" @@ -5559,6 +6135,24 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" +which-builtin-type@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.1.3.tgz#b1b8443707cc58b6e9bf98d32110ff0c2cbd029b" + integrity sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw== + dependencies: + function.prototype.name "^1.1.5" + has-tostringtag "^1.0.0" + is-async-function "^2.0.0" + is-date-object "^1.0.5" + is-finalizationregistry "^1.0.2" + is-generator-function "^1.0.10" + is-regex "^1.1.4" + is-weakref "^1.0.2" + isarray "^2.0.5" + which-boxed-primitive "^1.0.2" + which-collection "^1.0.1" + which-typed-array "^1.1.9" + which-collection@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906" @@ -5569,6 +6163,17 @@ which-collection@^1.0.1: is-weakmap "^2.0.1" is-weakset "^2.0.1" +which-typed-array@^1.1.11, which-typed-array@^1.1.13: + version "1.1.13" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.13.tgz#870cd5be06ddb616f504e7b039c4c24898184d36" + integrity sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.4" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + which-typed-array@^1.1.9: version "1.1.9" resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6" @@ -5610,7 +6215,7 @@ wkx@^0.5.0: dependencies: "@types/node" "*" -word-wrap@^1.2.3, word-wrap@~1.2.3: +word-wrap@~1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== From 2d5522efef652b78705e3437f927dc73dc186575 Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Fri, 8 Dec 2023 12:37:38 +0000 Subject: [PATCH 16/39] chore: try using yarn cache --- .github/workflows/tests.yml | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0d0f635f..96da2c6e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -8,23 +8,35 @@ env: # Playwright headless browsers running in CI get low confidence scores, causing flaky tests. Lower the confidence score threshold for CI testing. MIN_CONFIDENCE_SCORE: 0 jobs: - eslint: + lint: + name: Lint runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - name: Install dependencies - run: yarn --frozen-lockfile + - uses: actions/setup-node@v3 + with: + node-version: 18 + cache: 'yarn' + + - name: Install packages + run: yarn install --prefer-offline --frozen-lockfile - - name: Run eslint + - name: Lint run: yarn lint unit-tests: + name: Unit tests runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - name: Install dependencies - run: yarn --frozen-lockfile + - uses: actions/setup-node@v3 + with: + node-version: 18 + cache: 'yarn' + + - name: Install packages + run: yarn install --prefer-offline --frozen-lockfile - name: Run unit tests run: yarn test From a3aaeb70d26bb445abcfbdf7642b9d6fa01b5b56 Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Fri, 8 Dec 2023 12:59:08 +0000 Subject: [PATCH 17/39] chore: try using cache action --- .github/workflows/tests.yml | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 96da2c6e..57313e79 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -14,10 +14,17 @@ jobs: steps: - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + # - uses: actions/setup-node@v3 + # with: + # node-version: 18 + # cache: 'yarn' + + - name: 'Cache' + uses: actions/cache@v3 with: - node-version: 18 - cache: 'yarn' + path: node_modules + key: nodemodules-${{ hashFiles('yarn.lock') }} + restore-keys: nodemodules- - name: Install packages run: yarn install --prefer-offline --frozen-lockfile @@ -35,6 +42,13 @@ jobs: node-version: 18 cache: 'yarn' + - name: 'Cache' + uses: actions/cache@v3 + with: + path: node_modules + key: nodemodules-${{ hashFiles('yarn.lock') }} + restore-keys: nodemodules- + - name: Install packages run: yarn install --prefer-offline --frozen-lockfile From e60ec93fbce11cf54fa72ab188e735eba043d4a3 Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Fri, 8 Dec 2023 13:10:35 +0000 Subject: [PATCH 18/39] chore: enable node modules cache for playwright tests --- .github/workflows/tests.yml | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 57313e79..45e7b3ad 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -14,6 +14,8 @@ jobs: steps: - uses: actions/checkout@v3 + # This takes 20s but does not seem necessary for our current setup + # Add this to all jobs if you encounter problems with Node installation # - uses: actions/setup-node@v3 # with: # node-version: 18 @@ -37,11 +39,6 @@ jobs: steps: - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: 18 - cache: 'yarn' - - name: 'Cache' uses: actions/cache@v3 with: @@ -54,7 +51,8 @@ jobs: - name: Run unit tests run: yarn test - e2e-tests: + e2e: + name: Playwright e2e tests timeout-minutes: 60 runs-on: ubuntu-latest strategy: @@ -65,8 +63,15 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Install dependencies - run: yarn --frozen-lockfile + - name: 'Cache' + uses: actions/cache@v3 + with: + path: node_modules + key: nodemodules-${{ hashFiles('yarn.lock') }} + restore-keys: nodemodules- + + - name: Install packages + run: yarn install --prefer-offline --frozen-lockfile - name: Install Playwright Browsers run: yarn playwright install --with-deps From 41035f7c587b87ff4335ff9510cc2cdba04ef1fa Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Fri, 8 Dec 2023 13:34:05 +0000 Subject: [PATCH 19/39] chore: try using container --- .github/workflows/tests.yml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 45e7b3ad..18de05f7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -14,8 +14,10 @@ jobs: steps: - uses: actions/checkout@v3 - # This takes 20s but does not seem necessary for our current setup + # This takes 20s but does not seem necessary for our current setup, + # as ubuntu-latest already has a reasonable version of Node # Add this to all jobs if you encounter problems with Node installation + # This also makes use of global yarn cache # - uses: actions/setup-node@v3 # with: # node-version: 18 @@ -51,10 +53,20 @@ jobs: - name: Run unit tests run: yarn test + # run_vercel_tests: + # name: Run e2e tests + # container: mcr.microsoft.com/playwright:v1.36.2 + + # steps: + # - uses: actions/checkout@v3 + # - uses: actions/setup-node@v3 + # with: + # node-version: '18.x' e2e: name: Playwright e2e tests timeout-minutes: 60 - runs-on: ubuntu-latest + # runs-on: ubuntu-latest + container: mcr.microsoft.com/playwright:v1.40.0-jammy strategy: fail-fast: false matrix: From 98653e5bf701e4eccf32be884da326ee312abcef Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Fri, 8 Dec 2023 13:36:36 +0000 Subject: [PATCH 20/39] chore: put runs on back --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 18de05f7..a8d761d5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -65,7 +65,7 @@ jobs: e2e: name: Playwright e2e tests timeout-minutes: 60 - # runs-on: ubuntu-latest + runs-on: ubuntu-latest container: mcr.microsoft.com/playwright:v1.40.0-jammy strategy: fail-fast: false From 7caff77248609b998b2b47fc9f9311a4bedfb9d3 Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Fri, 8 Dec 2023 13:56:04 +0000 Subject: [PATCH 21/39] chore: try caching playwright manually --- .github/workflows/tests.yml | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a8d761d5..6a2d2e63 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -53,20 +53,10 @@ jobs: - name: Run unit tests run: yarn test - # run_vercel_tests: - # name: Run e2e tests - # container: mcr.microsoft.com/playwright:v1.36.2 - - # steps: - # - uses: actions/checkout@v3 - # - uses: actions/setup-node@v3 - # with: - # node-version: '18.x' e2e: name: Playwright e2e tests timeout-minutes: 60 runs-on: ubuntu-latest - container: mcr.microsoft.com/playwright:v1.40.0-jammy strategy: fail-fast: false matrix: @@ -75,18 +65,31 @@ jobs: steps: - uses: actions/checkout@v3 - - name: 'Cache' + - name: 'Cache node modules' uses: actions/cache@v3 with: path: node_modules key: nodemodules-${{ hashFiles('yarn.lock') }} restore-keys: nodemodules- - - name: Install packages + - name: Install node modules run: yarn install --prefer-offline --frozen-lockfile - - name: Install Playwright Browsers + - name: Get installed Playwright version + id: playwright-version + run: echo "PLAYWRIGHT_VERSION=$(node -e "console.log(require('./package-lock.json').dependencies['@playwright/test'].version)")" >> $GITHUB_ENV + + - name: Cache playwright binaries + uses: actions/cache@v3 + id: playwright-cache + with: + path: | + ~/.cache/ms-playwright + key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }} + + - name: Install Playwright Browsers if cache miss run: yarn playwright install --with-deps + if: steps.playwright-cache.outputs.cache-hit != 'true' - name: Build website run: yarn build From 5e6adc9a51ec8ce316baba53f29d3ff29b0fff62 Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Fri, 8 Dec 2023 15:04:10 +0000 Subject: [PATCH 22/39] chore: fix playwright version --- .github/workflows/tests.yml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6a2d2e63..fee8fb05 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -65,7 +65,7 @@ jobs: steps: - uses: actions/checkout@v3 - - name: 'Cache node modules' + - name: Cache node modules uses: actions/cache@v3 with: path: node_modules @@ -75,11 +75,11 @@ jobs: - name: Install node modules run: yarn install --prefer-offline --frozen-lockfile - - name: Get installed Playwright version + - name: Get installed Playwright version (used in cache key) id: playwright-version - run: echo "PLAYWRIGHT_VERSION=$(node -e "console.log(require('./package-lock.json').dependencies['@playwright/test'].version)")" >> $GITHUB_ENV + run: echo "PLAYWRIGHT_VERSION=$(node -e "process.stdout.write(require('@playwright/test/package.json').version)")" >> $GITHUB_ENV - - name: Cache playwright binaries + - name: Cache Playwright browser binaries uses: actions/cache@v3 id: playwright-cache with: @@ -87,7 +87,7 @@ jobs: ~/.cache/ms-playwright key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }} - - name: Install Playwright Browsers if cache miss + - name: Install Playwright browsers binaries if cache missed run: yarn playwright install --with-deps if: steps.playwright-cache.outputs.cache-hit != 'true' @@ -108,7 +108,8 @@ jobs: - name: Run Playwright tests run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} - - uses: actions/upload-artifact@v3 + - name: Upload Playwright report + uses: actions/upload-artifact@v3 if: always() with: name: playwright-report From c7f4a2883e62f23f6be7b800a83e8b3b5ede440e Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Fri, 8 Dec 2023 15:23:03 +0000 Subject: [PATCH 23/39] chore: fix dependencies install --- .github/workflows/tests.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index fee8fb05..d8e2959a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -91,6 +91,10 @@ jobs: run: yarn playwright install --with-deps if: steps.playwright-cache.outputs.cache-hit != 'true' + - name: Install Playwright dependencies without browsers if cache hit + run: yarn playwright install + if: steps.playwright-cache.outputs.cache-hit == 'true' + - name: Build website run: yarn build From e050d79adc3078e99dceb2d3c9adc287e4b63d21 Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Fri, 8 Dec 2023 15:31:27 +0000 Subject: [PATCH 24/39] chore: fix dependencies install 2nd attempt --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d8e2959a..a0f7bf90 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -92,7 +92,7 @@ jobs: if: steps.playwright-cache.outputs.cache-hit != 'true' - name: Install Playwright dependencies without browsers if cache hit - run: yarn playwright install + run: yarn playwright install-deps if: steps.playwright-cache.outputs.cache-hit == 'true' - name: Build website From f5ebec67299c945918590b24ac72cfb36feb2fff Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Fri, 8 Dec 2023 15:36:03 +0000 Subject: [PATCH 25/39] chore: fix eslint error --- src/pages/playground/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/playground/index.tsx b/src/pages/playground/index.tsx index bae33003..b5bf6abc 100644 --- a/src/pages/playground/index.tsx +++ b/src/pages/playground/index.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react/jsx-key */ import { useMemo } from 'react'; import { UseCaseWrapper } from '../../client/components/common/UseCaseWrapper/UseCaseWrapper'; import { From f2214cf744291864ced54402b343d0d408d81dfe Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Fri, 8 Dec 2023 15:57:11 +0000 Subject: [PATCH 26/39] chore: try instal deps just for chrome --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a0f7bf90..20d01bea 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -92,7 +92,7 @@ jobs: if: steps.playwright-cache.outputs.cache-hit != 'true' - name: Install Playwright dependencies without browsers if cache hit - run: yarn playwright install-deps + run: yarn playwright install-deps chromium if: steps.playwright-cache.outputs.cache-hit == 'true' - name: Build website From 0cc4dab23240b5e5286cfe37ccd9ec8979471abf Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Fri, 8 Dec 2023 16:03:29 +0000 Subject: [PATCH 27/39] install webkit dependencies --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 20d01bea..c0d819f9 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -91,8 +91,8 @@ jobs: run: yarn playwright install --with-deps if: steps.playwright-cache.outputs.cache-hit != 'true' - - name: Install Playwright dependencies without browsers if cache hit - run: yarn playwright install-deps chromium + - name: If browser binaries cache hit, install just webkit dependencies + run: yarn playwright install-deps webkit if: steps.playwright-cache.outputs.cache-hit == 'true' - name: Build website From 739bad260749c27ee8b954b30ff368766bf0629a Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Fri, 8 Dec 2023 16:25:16 +0000 Subject: [PATCH 28/39] try caching next build --- .github/workflows/tests.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c0d819f9..46a91766 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -91,10 +91,22 @@ jobs: run: yarn playwright install --with-deps if: steps.playwright-cache.outputs.cache-hit != 'true' + # Annoying that this has to be here, alternative is using a Playwright docker container which should have this already - name: If browser binaries cache hit, install just webkit dependencies run: yarn playwright install-deps webkit if: steps.playwright-cache.outputs.cache-hit == 'true' + - name: Cache Next build + uses: actions/cache@v3 + with: + # See here for caching with `yarn` https://github.com/actions/cache/blob/main/examples.md#node---yarn or you can leverage caching with actions/setup-node https://github.com/actions/setup-node + path: ${{ github.workspace }}/.next/cache + # Generate a new cache whenever packages or source files change. + key: ${{ runner.os }}-nextjs-${{ hashFiles('**/yarn.lock') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }} + # If source files changed but packages didn't, rebuild from a prior cache. + restore-keys: | + ${{ runner.os }}-nextjs-${{ hashFiles('**/yarn.lock') }}- + - name: Build website run: yarn build From b1c53d46be5b03c1b6db10f0839ed73d0ba8e448 Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Fri, 8 Dec 2023 16:37:58 +0000 Subject: [PATCH 29/39] narrow down hash files --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 46a91766..2d6818c0 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -102,10 +102,10 @@ jobs: # See here for caching with `yarn` https://github.com/actions/cache/blob/main/examples.md#node---yarn or you can leverage caching with actions/setup-node https://github.com/actions/setup-node path: ${{ github.workspace }}/.next/cache # Generate a new cache whenever packages or source files change. - key: ${{ runner.os }}-nextjs-${{ hashFiles('**/yarn.lock') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }} + key: ${{ runner.os }}-nextjs-${{ hashFiles('yarn.lock') }}-${{ hashFiles('src/*') }} # If source files changed but packages didn't, rebuild from a prior cache. restore-keys: | - ${{ runner.os }}-nextjs-${{ hashFiles('**/yarn.lock') }}- + ${{ runner.os }}-nextjs-${{ hashFiles('yarn.lock') }}- - name: Build website run: yarn build From 62c46e2b9b2cd292ca0abfb39f7e4f82f8240f1e Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Fri, 8 Dec 2023 16:48:15 +0000 Subject: [PATCH 30/39] tech next cache miss --- .github/workflows/tests.yml | 1 - src/client/api/coupon-fraud/use-coupon-claim.ts | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2d6818c0..cd1f4d8a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -99,7 +99,6 @@ jobs: - name: Cache Next build uses: actions/cache@v3 with: - # See here for caching with `yarn` https://github.com/actions/cache/blob/main/examples.md#node---yarn or you can leverage caching with actions/setup-node https://github.com/actions/setup-node path: ${{ github.workspace }}/.next/cache # Generate a new cache whenever packages or source files change. key: ${{ runner.os }}-nextjs-${{ hashFiles('yarn.lock') }}-${{ hashFiles('src/*') }} diff --git a/src/client/api/coupon-fraud/use-coupon-claim.ts b/src/client/api/coupon-fraud/use-coupon-claim.ts index 38578ecb..b00457cd 100644 --- a/src/client/api/coupon-fraud/use-coupon-claim.ts +++ b/src/client/api/coupon-fraud/use-coupon-claim.ts @@ -2,6 +2,8 @@ import { FingerprintJSPro } from '@fingerprintjs/fingerprintjs-pro-react'; import { apiRequest } from '../api'; import { useMutation } from 'react-query'; +// This is a test, should not hit cache + function claimCoupon({ fpData, body }: CouponClaim) { return apiRequest('/api/coupon-fraud/claim', fpData, body); } From 9d3982d617a6bbdf160b57130d600c7b4de899fc Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Sun, 10 Dec 2023 18:27:17 +0000 Subject: [PATCH 31/39] try using container --- .github/workflows/tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index cd1f4d8a..8623cd39 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -57,6 +57,8 @@ jobs: name: Playwright e2e tests timeout-minutes: 60 runs-on: ubuntu-latest + container: + image: mcr.microsoft.com/playwright:v1.40.0-jammy strategy: fail-fast: false matrix: From 593b92eda8efc568a053db9b8a64eca6e54b024a Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Sun, 10 Dec 2023 18:38:58 +0000 Subject: [PATCH 32/39] fix home env? --- .github/workflows/tests.yml | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8623cd39..9057d9c6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -77,26 +77,26 @@ jobs: - name: Install node modules run: yarn install --prefer-offline --frozen-lockfile - - name: Get installed Playwright version (used in cache key) - id: playwright-version - run: echo "PLAYWRIGHT_VERSION=$(node -e "process.stdout.write(require('@playwright/test/package.json').version)")" >> $GITHUB_ENV + # - name: Get installed Playwright version (used in cache key) + # id: playwright-version + # run: echo "PLAYWRIGHT_VERSION=$(node -e "process.stdout.write(require('@playwright/test/package.json').version)")" >> $GITHUB_ENV - - name: Cache Playwright browser binaries - uses: actions/cache@v3 - id: playwright-cache - with: - path: | - ~/.cache/ms-playwright - key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }} + # - name: Cache Playwright browser binaries + # uses: actions/cache@v3 + # id: playwright-cache + # with: + # path: | + # ~/.cache/ms-playwright + # key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }} - - name: Install Playwright browsers binaries if cache missed - run: yarn playwright install --with-deps - if: steps.playwright-cache.outputs.cache-hit != 'true' + # - name: Install Playwright browsers binaries if cache missed + # run: yarn playwright install --with-deps + # if: steps.playwright-cache.outputs.cache-hit != 'true' - # Annoying that this has to be here, alternative is using a Playwright docker container which should have this already - - name: If browser binaries cache hit, install just webkit dependencies - run: yarn playwright install-deps webkit - if: steps.playwright-cache.outputs.cache-hit == 'true' + # # Annoying that this has to be here, alternative is using a Playwright docker container which should have this already + # - name: If browser binaries cache hit, install just webkit dependencies + # run: yarn playwright install-deps webkit + # if: steps.playwright-cache.outputs.cache-hit == 'true' - name: Cache Next build uses: actions/cache@v3 @@ -124,6 +124,8 @@ jobs: - name: Run Playwright tests run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} + env: + HOME: /root - name: Upload Playwright report uses: actions/upload-artifact@v3 From 76dfe5363ed77dfc92e2139b710146f86f86d4e0 Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Sun, 10 Dec 2023 19:02:24 +0000 Subject: [PATCH 33/39] try starting web server using playwright --- .github/workflows/tests.yml | 26 +++++++++++++------------- playwright.config.js | 9 +++++++++ 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9057d9c6..3c548fff 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -108,19 +108,19 @@ jobs: restore-keys: | ${{ runner.os }}-nextjs-${{ hashFiles('yarn.lock') }}- - - name: Build website - run: yarn build - - - name: Start website - run: yarn start & - - - name: Wait for website - timeout-minutes: 1 - run: | - while ! curl -s http://localhost:3000 > /dev/null; do - echo "Waiting for website..." - sleep 1 - done + # - name: Build website + # run: yarn build + + # - name: Start website + # run: yarn start & + + # - name: Wait for website + # timeout-minutes: 1 + # run: | + # while ! curl -s http://localhost:3000 > /dev/null; do + # echo "Waiting for website..." + # sleep 1 + # done - name: Run Playwright tests run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} diff --git a/playwright.config.js b/playwright.config.js index 1bc8cf3b..0ecec2a6 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -7,6 +7,8 @@ import { defineConfig, devices } from '@playwright/test'; // require('dotenv').config(); const isCi = !!process.env.CI; +const PORT = process.env.PORT || 3000; +const BASE_URL = process.env.BASE_URL || `http://localhost:${PORT}`; /** * @see https://playwright.dev/docs/test-configuration */ @@ -42,6 +44,13 @@ export default defineConfig({ trace: 'on-first-retry', }, + webServer: { + command: `yarn dev`, + url: BASE_URL, + timeout: 120 * 1000, + reuseExistingServer: !isCi, + }, + /* Configure projects for major browsers */ projects: [ { From bafa784f684fa3338ebd6d7360b609835770bfb6 Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Sun, 10 Dec 2023 19:13:49 +0000 Subject: [PATCH 34/39] use yarn start --- .github/workflows/tests.yml | 4 ++-- playwright.config.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3c548fff..f5ff29e6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -108,8 +108,8 @@ jobs: restore-keys: | ${{ runner.os }}-nextjs-${{ hashFiles('yarn.lock') }}- - # - name: Build website - # run: yarn build + - name: Build website + run: yarn build # - name: Start website # run: yarn start & diff --git a/playwright.config.js b/playwright.config.js index 0ecec2a6..5c73b308 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -45,7 +45,7 @@ export default defineConfig({ }, webServer: { - command: `yarn dev`, + command: `yarn start`, url: BASE_URL, timeout: 120 * 1000, reuseExistingServer: !isCi, From 029e8ad00f1a9336ae69ae6596439301546c0e0d Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Sun, 10 Dec 2023 19:33:42 +0000 Subject: [PATCH 35/39] Don't use a container --- .github/workflows/tests.yml | 53 +++++++++++++++---------------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f5ff29e6..4a3a0202 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -57,8 +57,8 @@ jobs: name: Playwright e2e tests timeout-minutes: 60 runs-on: ubuntu-latest - container: - image: mcr.microsoft.com/playwright:v1.40.0-jammy + # container: + # image: mcr.microsoft.com/playwright:v1.40.0-jammy strategy: fail-fast: false matrix: @@ -77,26 +77,26 @@ jobs: - name: Install node modules run: yarn install --prefer-offline --frozen-lockfile - # - name: Get installed Playwright version (used in cache key) - # id: playwright-version - # run: echo "PLAYWRIGHT_VERSION=$(node -e "process.stdout.write(require('@playwright/test/package.json').version)")" >> $GITHUB_ENV + - name: Get installed Playwright version (used in cache key) + id: playwright-version + run: echo "PLAYWRIGHT_VERSION=$(node -e "process.stdout.write(require('@playwright/test/package.json').version)")" >> $GITHUB_ENV - # - name: Cache Playwright browser binaries - # uses: actions/cache@v3 - # id: playwright-cache - # with: - # path: | - # ~/.cache/ms-playwright - # key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }} + - name: Cache Playwright browser binaries + uses: actions/cache@v3 + id: playwright-cache + with: + path: | + ~/.cache/ms-playwright + key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }} - # - name: Install Playwright browsers binaries if cache missed - # run: yarn playwright install --with-deps - # if: steps.playwright-cache.outputs.cache-hit != 'true' + - name: Install Playwright browsers binaries if cache missed + run: yarn playwright install --with-deps + if: steps.playwright-cache.outputs.cache-hit != 'true' - # # Annoying that this has to be here, alternative is using a Playwright docker container which should have this already - # - name: If browser binaries cache hit, install just webkit dependencies - # run: yarn playwright install-deps webkit - # if: steps.playwright-cache.outputs.cache-hit == 'true' + # Annoying that this has to be here, alternative is using a Playwright docker container which should have this already + - name: If browser binaries cache hit, install just webkit dependencies + run: yarn playwright install-deps webkit + if: steps.playwright-cache.outputs.cache-hit == 'true' - name: Cache Next build uses: actions/cache@v3 @@ -111,21 +111,10 @@ jobs: - name: Build website run: yarn build - # - name: Start website - # run: yarn start & - - # - name: Wait for website - # timeout-minutes: 1 - # run: | - # while ! curl -s http://localhost:3000 > /dev/null; do - # echo "Waiting for website..." - # sleep 1 - # done - - name: Run Playwright tests run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} - env: - HOME: /root + # env: + # HOME: /root - name: Upload Playwright report uses: actions/upload-artifact@v3 From 46573835614873f8dd9e4ca39839bf0fe03362d1 Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Mon, 11 Dec 2023 10:49:36 +0000 Subject: [PATCH 36/39] chore: improve eslintrc.js --- .eslintrc.js | 22 ++++++++++++++++++++++ .eslintrc.json | 21 --------------------- .gitignore | 3 +++ package.json | 2 +- 4 files changed, 26 insertions(+), 22 deletions(-) create mode 100644 .eslintrc.js delete mode 100644 .eslintrc.json diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..d2cd62fe --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,22 @@ +/** @type {import("eslint").Linter.Config} */ +module.exports = { + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/eslint-recommended', + 'plugin:@typescript-eslint/recommended', + 'next/core-web-vitals', + 'prettier', + ], + plugins: ['react-hooks', 'prettier'], + rules: { + 'react-hooks/rules-of-hooks': 'error', + 'react-hooks/exhaustive-deps': 'warn', + 'prettier/prettier': 'error', + '@typescript-eslint/ban-ts-comment': 'off', + '@typescript-eslint/no-explicit-any': 'off', + 'react/no-unescaped-entities': 'off', + }, + env: { + es6: true, + }, +}; diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 95c859c2..00000000 --- a/.eslintrc.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended", - "next/core-web-vitals", - "prettier" - ], - "plugins": ["react-hooks", "prettier"], - "rules": { - "react-hooks/rules-of-hooks": "error", - "react-hooks/exhaustive-deps": "warn", - "prettier/prettier": "error", - "@typescript-eslint/ban-ts-comment": "off", - "@typescript-eslint/no-explicit-any": "off", - "react/no-unescaped-entities": "off" - }, - "env": { - "es6": true - } -} diff --git a/.gitignore b/.gitignore index 8c56889d..b4fa38bf 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,6 @@ tsconfig.tsbuildinfo # VS code workspace settings .vscode + +# MacOS Finder +.DS_Store diff --git a/package.json b/package.json index 2b4357be..08fba4a3 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "eslint . --ext .ts,.tsx,.js,.jsx", + "lint": "next lint", "lint:fix": "yarn lint --fix", "prettier": "prettier src --check", "prettier:fix": "yarn prettier --write", From 302d3bc6d251de10a44c72473d9c1e9965b68304 Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Mon, 11 Dec 2023 11:11:59 +0000 Subject: [PATCH 37/39] chore: clean up --- .github/workflows/{tests.yml => ci.yml} | 0 src/client/api/coupon-fraud/use-coupon-claim.ts | 2 -- 2 files changed, 2 deletions(-) rename .github/workflows/{tests.yml => ci.yml} (100%) diff --git a/.github/workflows/tests.yml b/.github/workflows/ci.yml similarity index 100% rename from .github/workflows/tests.yml rename to .github/workflows/ci.yml diff --git a/src/client/api/coupon-fraud/use-coupon-claim.ts b/src/client/api/coupon-fraud/use-coupon-claim.ts index b00457cd..38578ecb 100644 --- a/src/client/api/coupon-fraud/use-coupon-claim.ts +++ b/src/client/api/coupon-fraud/use-coupon-claim.ts @@ -2,8 +2,6 @@ import { FingerprintJSPro } from '@fingerprintjs/fingerprintjs-pro-react'; import { apiRequest } from '../api'; import { useMutation } from 'react-query'; -// This is a test, should not hit cache - function claimCoupon({ fpData, body }: CouponClaim) { return apiRequest('/api/coupon-fraud/claim', fpData, body); } From e94b16b779c86e3f2495a57be98e20bfb7c8c2bf Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Mon, 11 Dec 2023 11:26:15 +0000 Subject: [PATCH 38/39] cleanup ci.yaml --- .github/workflows/ci.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4a3a0202..5ff3b1fb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,8 +57,6 @@ jobs: name: Playwright e2e tests timeout-minutes: 60 runs-on: ubuntu-latest - # container: - # image: mcr.microsoft.com/playwright:v1.40.0-jammy strategy: fail-fast: false matrix: @@ -93,7 +91,8 @@ jobs: run: yarn playwright install --with-deps if: steps.playwright-cache.outputs.cache-hit != 'true' - # Annoying that this has to be here, alternative is using a Playwright docker container which should have this already + # Ubuntu needs extra stuff to run webkit tests, alternative is using a Playwright docker container but + # that is slower in CI. - name: If browser binaries cache hit, install just webkit dependencies run: yarn playwright install-deps webkit if: steps.playwright-cache.outputs.cache-hit == 'true' @@ -113,8 +112,6 @@ jobs: - name: Run Playwright tests run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} - # env: - # HOME: /root - name: Upload Playwright report uses: actions/upload-artifact@v3 From c8703c9cae0b9977e3deefae8a77a70581a4c49b Mon Sep 17 00:00:00 2001 From: Juraj Uhlar Date: Mon, 11 Dec 2023 12:28:51 +0000 Subject: [PATCH 39/39] chore: review fixes --- playwright.config.js | 2 +- src/client/components/common/content.tsx | 34 ++++++++++++------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/playwright.config.js b/playwright.config.js index 3ecc0f13..aacebcd8 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -1,7 +1,7 @@ import { defineConfig, devices } from '@playwright/test'; /** * Read environment variables from file. - * https://github.com/motdotla/dotenv; + * https://github.com/motdotla/dotenv */ import 'dotenv/config'; diff --git a/src/client/components/common/content.tsx b/src/client/components/common/content.tsx index 006538fe..7f3c7d3f 100644 --- a/src/client/components/common/content.tsx +++ b/src/client/components/common/content.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react/jsx-key */ import Link from 'next/link'; import SmartSignalsIcon from '../../img/smartSignalsIcon.svg'; import CouponFraudIcon from '../../img/couponFraudIcon.svg'; @@ -38,11 +37,11 @@ export const USE_CASES = { url: '/coupon-fraud', iconSvg: CouponFraudIcon, descriptionHomepage: [ -

+

Safeguard campaign funds from abuse by implementing Fingerprint to identify bad faith users who repeatedly use coupon codes

, -

+

Accurately identify coupon fraud by signed-in customers or guests to ensure your marketing campaign yields its full potential.

, @@ -97,12 +96,11 @@ export const USE_CASES = { ], iconSvg: CredentialStuffingIcon, descriptionHomepage: [ -

+

Protect your users against credential stuffing using Fingerprintā€™s unique visitor ID provided for each user that visits your site.

, - -

+

Fingerprint's accurate identification prevents fraudsters from unauthorized account access, minimizing disruption for legitimate users.

, @@ -141,10 +139,10 @@ export const USE_CASES = { articleUrl: 'https://fingerprint.com/blog/detect-repeat-applications-loan-risk/', iconSvg: LoanRiskIcon, descriptionHomepage: [ -

+

Validate loan applications against prior submissions by users, whether they are anonymous or authenticated.

, -

+

Use Fingerprint to check for consistency between applications and ignore submissions from previously rejected applicants.

, @@ -181,7 +179,7 @@ export const USE_CASES = { articleUrl: 'https://fingerprint.com/blog/reducing-payment-fraud-with-reliable-visitor-identification/', iconSvg: PaymentFraudIcon, descriptionHomepage: [ -

+

Identify anonymous visitors behind every transaction. Use Fingerprintā€™s Identification to recognize repeated card testing activity and link it to specific users. Protect your users and your business against various forms of payment fraud. @@ -231,11 +229,13 @@ export const USE_CASES = { url: '/paywall', iconSvg: PaywallIcon, descriptionHomepage: [ -

+

Accurately identify returning users to provide limited access to your content and ensure users arenā€™t able to exceed their predetermined limits.

, -

Your content limit for each user will work even if the user clears cookies or browses in incognito mode.

, +

+ Your content limit for each user will work even if the user clears cookies or browses in incognito mode. +

, ], description: 'Use the demo below to see how Fingerprint protects your content from users trying to circumvent your paywall.Ā ', @@ -261,10 +261,10 @@ export const USE_CASES = { articleUrl: 'https://fingerprint.com/blog/providing-personalization-to-anonymous-users/', iconSvg: PersonalizationIcon, descriptionHomepage: [ -

+

Improve user experience and boost sales by personalizing your website with Fingerprint device intelligence.

, -

+

Provide your visitors with their search history, interface customization, or a persistent shopping cart without having to rely on cookies or logins.

, @@ -307,11 +307,11 @@ export const USE_CASES = { articleUrl: 'https://fingerprint.com/blog/preventing-content-scraping/', iconSvg: ScrapingIcon, descriptionHomepage: [ -

+

Web scraping extracts data using automated scripts. Data that is valuable to competitors can be stolen, directly impacting your business.

, -

+

Fingerprint Smart Signal bot detection offers advanced protection without compromising user experience or relying on IP-based solutions.

, @@ -381,8 +381,8 @@ export const PLAYGROUND_METADATA: Pick< url: '/playground', iconSvg: SmartSignalsIcon, descriptionHomepage: [ -

Analyze your own browser with Fingerprintā€™s identification and Smart Signals.

, -

+

Analyze your own browser with Fingerprintā€™s identification and Smart Signals.

, +

Test and examine Fingerprintā€™s signals including IP geolocation, browser bot detection, incognito mode detection, VPN detection, browser tampering detection, IP blocklist matching, and more.

,