diff --git a/catalog/dags/common/ingestion_server.py b/catalog/dags/common/ingestion_server.py
index 2edb8731ef3..e8ba9f4c42d 100644
--- a/catalog/dags/common/ingestion_server.py
+++ b/catalog/dags/common/ingestion_server.py
@@ -6,7 +6,7 @@
from airflow.decorators import task
from airflow.exceptions import AirflowSkipException
-from airflow.providers.http.operators.http import SimpleHttpOperator
+from airflow.providers.http.operators.http import HttpOperator
from airflow.providers.http.sensors.http import HttpSensor
from requests import Response
@@ -95,8 +95,8 @@ def generate_index_suffix(default_suffix: str | None = None) -> str:
def get_current_index(
target_alias: str, http_conn_id: str = "data_refresh"
-) -> SimpleHttpOperator:
- return SimpleHttpOperator(
+) -> HttpOperator:
+ return HttpOperator(
task_id="get_current_index",
http_conn_id=http_conn_id,
endpoint=f"stat/{target_alias}",
@@ -111,13 +111,13 @@ def trigger_task(
model: str,
data: dict | None = None,
http_conn_id: str = "data_refresh",
-) -> SimpleHttpOperator:
+) -> HttpOperator:
data = {
**(data or {}),
"model": model,
"action": action.upper(),
}
- return SimpleHttpOperator(
+ return HttpOperator(
task_id=f"trigger_{action.lower()}",
http_conn_id=http_conn_id,
endpoint="task",
@@ -129,7 +129,7 @@ def trigger_task(
def wait_for_task(
action: str,
- task_trigger: SimpleHttpOperator,
+ task_trigger: HttpOperator,
timeout: timedelta,
poke_interval: int = REFRESH_POKE_INTERVAL,
http_conn_id: str = "data_refresh",
@@ -153,7 +153,7 @@ def trigger_and_wait_for_task(
data: dict | None = None,
poke_interval: int = REFRESH_POKE_INTERVAL,
http_conn_id: str = "data_refresh",
-) -> tuple[SimpleHttpOperator, HttpSensor]:
+) -> tuple[HttpOperator, HttpSensor]:
trigger = trigger_task(action, model, data, http_conn_id)
waiter = wait_for_task(action, trigger, timeout, poke_interval, http_conn_id)
trigger >> waiter
diff --git a/catalog/env.template b/catalog/env.template
index b3b8ac0286f..8e94e24716a 100644
--- a/catalog/env.template
+++ b/catalog/env.template
@@ -106,6 +106,9 @@ AIRFLOW_VAR_CATCHUP_ENABLED=false
# Number of records to expect in a healthy ES index. Used during the data refresh to verify that
# a new index is healthy before promoting.
ES_INDEX_READINESS_RECORD_COUNT=1000
+# Warning in dependency, nothing we can do
+# https://docs.sqlalchemy.org/en/20/errors.html#error-b8d9
+SQLALCHEMY_SILENCE_UBER_WARNING=1
AIRFLOW_VAR_AIRFLOW_RDS_ARN=unset
AIRFLOW_VAR_AIRFLOW_RDS_SNAPSHOTS_TO_RETAIN=7
diff --git a/catalog/pytest.ini b/catalog/pytest.ini
index 96cafe324bc..feb60734788 100644
--- a/catalog/pytest.ini
+++ b/catalog/pytest.ini
@@ -18,11 +18,6 @@ addopts =
--disable-socket
--allow-unix-socket
-# sqlalchemy
-# Warning in dependency, nothing we can do
-# https://docs.sqlalchemy.org/en/20/errors.html#error-b8d9
-# airflow
-# Warning within Airflow for an internal call, nothing we can do
# flask
# https://docs.sqlalchemy.org/en/20/errors.html#error-b8d9
# Warning in dependency, nothing we can do
@@ -30,8 +25,6 @@ addopts =
# distutils
# Warning in dependency, nothing we can do
filterwarnings=
- ignore::sqlalchemy.exc.MovedIn20Warning
- ignore:Calling `DAG.create_dagrun\(\)` without an explicit data interval is deprecated:airflow.exceptions.RemovedInAirflow3Warning
ignore:.*is deprecated and will be (remoevd|removed) in Flask 2.3.:DeprecationWarning
ignore:distutils Version classes are deprecated. Use packaging.version instead:DeprecationWarning
diff --git a/frontend/package.json b/frontend/package.json
index 8c1662f7799..0c019a0f6e1 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -112,7 +112,7 @@
"@testing-library/vue": "^5.8.2",
"@types/express-useragent": "^1.0.2",
"@types/jest": "^29.5.4",
- "@types/node": "18.19.0",
+ "@types/node": "18.19.4",
"@types/throttle-debounce": "^5.0.0",
"@types/uuid": "^9.0.6",
"@vue/test-utils": "^1.1.3",
diff --git a/frontend/src/components/VIconButton/VOldIconButton.vue b/frontend/src/components/VIconButton/VOldIconButton.vue
deleted file mode 100644
index f58711f7018..00000000000
--- a/frontend/src/components/VIconButton/VOldIconButton.vue
+++ /dev/null
@@ -1,100 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/frontend/src/components/VIconButton/meta/VOldIconButton.stories.mdx b/frontend/src/components/VIconButton/meta/VOldIconButton.stories.mdx
deleted file mode 100644
index 173f6be9462..00000000000
--- a/frontend/src/components/VIconButton/meta/VOldIconButton.stories.mdx
+++ /dev/null
@@ -1,83 +0,0 @@
-import {
- ArgsTable,
- Canvas,
- Description,
- Meta,
- Story,
-} from "@storybook/addon-docs"
-
-import VOldIconButton from "~/components/VIconButton/VOldIconButton.vue"
-
-
-
-export const Template = (args) => ({
- template: `
-
- `,
- components: { VOldIconButton },
- setup() {
- return { args }
- },
-})
-
-export const sizesTemplate = (args) => ({
- template: `
-
- `,
- components: { VOldIconButton },
- setup() {
- return { args }
- },
-})
-
-# Icon Button
-
-
-
-
-
-
-
-## Sizes
-
-
diff --git a/frontend/test/playwright/e2e/attribution.spec.ts b/frontend/test/playwright/e2e/attribution.spec.ts
index c6a4e50f280..b12eaab755c 100644
--- a/frontend/test/playwright/e2e/attribution.spec.ts
+++ b/frontend/test/playwright/e2e/attribution.spec.ts
@@ -1,76 +1,75 @@
import { test, expect } from "@playwright/test"
-import { turnOnAnalytics } from "~~/test/playwright/utils/navigation"
+import { preparePageForTests } from "~~/test/playwright/utils/navigation"
+import {
+ collectAnalyticsEvents,
+ expectEventPayloadToMatch,
+} from "~~/test/playwright/utils/analytics"
test.describe.configure({ mode: "parallel" })
-test.beforeEach(async ({ context }) => {
- await context.grantPermissions(["clipboard-read", "clipboard-write"])
-})
-
-test("can copy rich text attribution", async ({ page }) => {
- await page.goto("image/e9d97a98-621b-4ec2-bf70-f47a74380452")
- await page.click('[aria-controls="panel-rich"]')
- await page.click('[id="copyattr-rich"]')
- const clippedText = await page.evaluate(async () => {
- return navigator.clipboard.readText()
+test.describe("attribution", () => {
+ test.beforeEach(async ({ context, page }) => {
+ await preparePageForTests(page, "xl", { features: { analytics: "on" } })
+ await context.grantPermissions(["clipboard-read", "clipboard-write"])
})
- // The Clipboard API returns a plain-text-ified version of the rich text.
- expect(clippedText).toContain('"bubbles in honey" by mutednarayan')
-})
-test("can copy HTML attribution", async ({ page }) => {
- await page.goto("image/e9d97a98-621b-4ec2-bf70-f47a74380452")
- await page.click('[aria-controls="panel-html"]')
- await page.click('[id="copyattr-html"]')
- const clippedText = await page.evaluate(async () => {
- return navigator.clipboard.readText()
- })
- const snippets = [
- '',
- ">bubbles in honey",
- ">mutednarayan",
- ]
- snippets.forEach((snippet) => {
- expect(clippedText).toContain(snippet)
+ test("can copy rich text attribution", async ({ page }) => {
+ await page.goto("image/e9d97a98-621b-4ec2-bf70-f47a74380452")
+ await page.click('[aria-controls="panel-rich"]')
+ await page.click('[id="copyattr-rich"]')
+ const clippedText = await page.evaluate(async () => {
+ return navigator.clipboard.readText()
+ })
+ // The Clipboard API returns a plain-text-ified version of the rich text.
+ expect(clippedText).toContain('"bubbles in honey" by mutednarayan')
})
-})
-test("can copy plain text attribution", async ({ page }) => {
- await page.goto("image/e9d97a98-621b-4ec2-bf70-f47a74380452")
- await page.click('[aria-controls="panel-plain"]')
- await page.click('[id="copyattr-plain"]')
- const clippedText = await page.evaluate(async () => {
- return navigator.clipboard.readText()
+ test("can copy HTML attribution", async ({ page }) => {
+ await page.goto("image/e9d97a98-621b-4ec2-bf70-f47a74380452")
+ await page.click('[aria-controls="panel-html"]')
+ await page.click('[id="copyattr-html"]')
+ const clippedText = await page.evaluate(async () => {
+ return navigator.clipboard.readText()
+ })
+ const snippets = [
+ '
',
+ ">bubbles in honey",
+ ">mutednarayan",
+ ]
+ snippets.forEach((snippet) => {
+ expect(clippedText).toContain(snippet)
+ })
})
- // Only the plain-text license contains the "To view" bit.
- expect(clippedText).toContain("To view a copy of this license")
-})
-test("sends analytics event on copy", async ({ page }) => {
- let copyAttributionEventData: {
- id: string
- format: string
- mediaType: string
- } = { id: "", format: "", mediaType: "" }
- page.on("request", (req) => {
- if (req.method() === "POST") {
- const requestData = req.postDataJSON()
- if (requestData?.n == "COPY_ATTRIBUTION") {
- copyAttributionEventData = JSON.parse(requestData?.p)
- }
- }
+ test("can copy plain text attribution", async ({ page }) => {
+ await page.goto("image/e9d97a98-621b-4ec2-bf70-f47a74380452")
+ await page.click('[aria-controls="panel-plain"]')
+ await page.click('[id="copyattr-plain"]')
+ const clippedText = await page.evaluate(async () => {
+ return navigator.clipboard.readText()
+ })
+ // Only the plain-text license contains the "To view" bit.
+ expect(clippedText).toContain("To view a copy of this license")
})
- const mediaType = "image"
- const id = "e9d97a98-621b-4ec2-bf70-f47a74380452"
- const format = "rich"
- await turnOnAnalytics(page)
+ test("sends analytics event on copy", async ({ page }) => {
+ const analyticsEvents = collectAnalyticsEvents(page.context())
- await page.goto(`${mediaType}/${id}?ff_analytics=on`)
- await page.click(`[id="copyattr-${format}"]`)
+ const mediaType = "image"
+ const id = "e9d97a98-621b-4ec2-bf70-f47a74380452"
+ const format = "rich"
- expect(copyAttributionEventData.id).toEqual(id)
- expect(copyAttributionEventData.format).toEqual(format)
- expect(copyAttributionEventData.mediaType).toEqual(mediaType)
+ await page.goto(`${mediaType}/${id}?ff_analytics=on`)
+ await page.click(`[id="copyattr-${format}"]`)
+
+ const copyAttributionEvent = analyticsEvents.find(
+ (event) => event.n === "COPY_ATTRIBUTION"
+ )
+ expectEventPayloadToMatch(copyAttributionEvent, {
+ id,
+ format,
+ mediaType,
+ })
+ })
})
diff --git a/frontend/test/playwright/e2e/collections.spec.ts b/frontend/test/playwright/e2e/collections.spec.ts
index 9b12c4676ef..e2c604a1ba2 100644
--- a/frontend/test/playwright/e2e/collections.spec.ts
+++ b/frontend/test/playwright/e2e/collections.spec.ts
@@ -1,55 +1,64 @@
import { test, expect } from "@playwright/test"
-import { setCookies, t } from "~~/test/playwright/utils/navigation"
+import { preparePageForTests, t } from "~~/test/playwright/utils/navigation"
test.describe.configure({ mode: "parallel" })
-test.beforeEach(async ({ context, page }) => {
- await setCookies(context, {
- features: { additional_search_views: "on", analytics: "off" },
+test.describe("collections", () => {
+ test.beforeEach(async ({ page }) => {
+ await preparePageForTests(page, "xl", {
+ features: {
+ additional_search_views: "on",
+ },
+ })
+ await page.goto("/image/f9384235-b72e-4f1e-9b05-e1b116262a29?q=cat")
})
- await page.goto("/image/f9384235-b72e-4f1e-9b05-e1b116262a29?q=cat")
-})
-test("can open tags collection page from image page", async ({ page }) => {
- // Using the href because there are multiple links with the same text.
- await page.click('[href*="/tag/cat"]')
- await expect(
- page.getByRole("button", { name: t("browsePage.load") })
- ).toBeEnabled()
+ test("can open tags collection page from image page", async ({ page }) => {
+ // Using the href because there are multiple links with the same text.
+ await page.click('[href*="/tag/cat"]')
- await expect(page.getByRole("heading", { name: /cat/i })).toBeVisible()
- expect(await page.locator("figure").count()).toEqual(20)
- expect(page.url()).toMatch(/image\/tag\/cat/)
-})
-test("can open source collection page from image page", async ({ page }) => {
- const sourcePattern = /flickr/i
+ await expect(
+ page.getByRole("button", { name: t("browsePage.load") })
+ ).toBeEnabled()
- await page.getByRole("link", { name: sourcePattern }).first().click()
+ await expect(
+ page.getByRole("heading", { level: 1, name: /cat/i })
+ ).toBeVisible()
+ expect(await page.locator("figure").count()).toEqual(20)
+ expect(page.url()).toMatch(/image\/tag\/cat/)
+ })
+ test("can open source collection page from image page", async ({ page }) => {
+ const sourcePattern = /flickr/i
- await expect(
- page.getByRole("button", { name: t("browsePage.load") })
- ).toBeEnabled()
+ await page.getByRole("link", { name: sourcePattern }).first().click()
- await expect(page.getByRole("heading", { name: sourcePattern })).toBeVisible()
+ await expect(
+ page.getByRole("button", { name: t("browsePage.load") })
+ ).toBeEnabled()
- expect(await page.locator("figure").count()).toEqual(20)
+ await expect(
+ page.getByRole("heading", { name: sourcePattern })
+ ).toBeVisible()
- expect(page.url()).toMatch(/image\/source\/flickr\/$/)
-})
-test("can open creator collection page from image page", async ({ page }) => {
- const creatorPattern = /strogoscope/i
- await page.getByRole("link", { name: creatorPattern }).first().click()
+ expect(await page.locator("figure").count()).toEqual(20)
- await expect(
- page.getByRole("button", { name: t("browsePage.load") })
- ).toBeEnabled()
+ expect(page.url()).toMatch(/image\/source\/flickr\/$/)
+ })
+ test("can open creator collection page from image page", async ({ page }) => {
+ const creatorPattern = /strogoscope/i
+ await page.getByRole("link", { name: creatorPattern }).first().click()
+
+ await expect(
+ page.getByRole("button", { name: t("browsePage.load") })
+ ).toBeEnabled()
- await expect(
- page.getByRole("heading", { name: creatorPattern })
- ).toBeVisible()
+ await expect(
+ page.getByRole("heading", { level: 1, name: creatorPattern })
+ ).toBeVisible()
- expect(await page.locator("figure").count()).toEqual(20)
+ expect(await page.locator("figure").count()).toEqual(20)
- expect(page.url()).toMatch(/image\/source\/flickr\/creator\/strogoscope\//)
+ expect(page.url()).toMatch(/image\/source\/flickr\/creator\/strogoscope\//)
+ })
})
diff --git a/frontend/test/playwright/e2e/external-sources.spec.ts b/frontend/test/playwright/e2e/external-sources.spec.ts
index 11c0557de35..51f669d0aeb 100644
--- a/frontend/test/playwright/e2e/external-sources.spec.ts
+++ b/frontend/test/playwright/e2e/external-sources.spec.ts
@@ -2,8 +2,8 @@ import { test } from "@playwright/test"
import {
goToSearchTerm,
+ preparePageForTests,
t,
- turnOnAnalytics,
} from "~~/test/playwright/utils/navigation"
import {
@@ -11,58 +11,64 @@ import {
expectEventPayloadToMatch,
} from "~~/test/playwright/utils/analytics"
-test("sends VIEW_EXTERNAL_SOURCES analytics events", async ({
- page,
- context,
-}) => {
- await turnOnAnalytics(page)
- const events = collectAnalyticsEvents(context)
+test.describe("analytics", () => {
+ test.beforeEach(async ({ page }) => {
+ await preparePageForTests(page, "xl", { features: { analytics: "on" } })
+ })
+
+ test("sends VIEW_EXTERNAL_SOURCES analytics events", async ({
+ page,
+ context,
+ }) => {
+ const events = collectAnalyticsEvents(context)
- await goToSearchTerm(page, "cat", { searchType: "image", mode: "SSR" })
+ await goToSearchTerm(page, "cat", { searchType: "image", mode: "SSR" })
- await page
- .getByRole("button", { name: t("externalSources.form.supportedTitle") })
- .click()
- await page.getByRole("button", { name: /close/i }).click()
+ await page
+ .getByRole("button", { name: t("externalSources.form.supportedTitle") })
+ .click()
+ await page.getByRole("button", { name: /close/i }).click()
- const viewEvent = events.find((event) => event.n === "VIEW_EXTERNAL_SOURCES")
+ const viewEvent = events.find(
+ (event) => event.n === "VIEW_EXTERNAL_SOURCES"
+ )
- expectEventPayloadToMatch(viewEvent, {
- searchType: "image",
- query: "cat",
- resultPage: 1,
+ expectEventPayloadToMatch(viewEvent, {
+ searchType: "image",
+ query: "cat",
+ resultPage: 1,
+ })
})
-})
-test("sends SELECT_EXTERNAL_SOURCE analytics events", async ({
- page,
- context,
-}) => {
- await turnOnAnalytics(page)
- const pagePromise = page.context().waitForEvent("page")
+ test("sends SELECT_EXTERNAL_SOURCE analytics events", async ({
+ page,
+ context,
+ }) => {
+ const pagePromise = page.context().waitForEvent("page")
- const events = collectAnalyticsEvents(context)
+ const events = collectAnalyticsEvents(context)
- await goToSearchTerm(page, "cat", { searchType: "image", mode: "SSR" })
+ await goToSearchTerm(page, "cat", { searchType: "image", mode: "SSR" })
- await page
- .getByRole("button", {
- name: new RegExp(t("externalSources.form.supportedTitleSm"), "i"),
- })
- .click()
- await page.getByRole("link", { name: "Centre for Ageing Better" }).click()
+ await page
+ .getByRole("button", {
+ name: new RegExp(t("externalSources.form.supportedTitleSm"), "i"),
+ })
+ .click()
+ await page.getByRole("link", { name: "Centre for Ageing Better" }).click()
- const newPage = await pagePromise
- await newPage.close()
+ const newPage = await pagePromise
+ await newPage.close()
- const selectEvent = events.find(
- (event) => event.n === "SELECT_EXTERNAL_SOURCE"
- )
+ const selectEvent = events.find(
+ (event) => event.n === "SELECT_EXTERNAL_SOURCE"
+ )
- expectEventPayloadToMatch(selectEvent, {
- name: "Centre For Ageing Better",
- mediaType: "image",
- query: "cat",
- component: "VExternalSourceList",
+ expectEventPayloadToMatch(selectEvent, {
+ name: "Centre For Ageing Better",
+ mediaType: "image",
+ query: "cat",
+ component: "VExternalSourceList",
+ })
})
})
diff --git a/frontend/test/playwright/e2e/filters-sidebar-keyboard.spec.ts b/frontend/test/playwright/e2e/filters-sidebar-keyboard.spec.ts
index bb203c64d5c..1315c89e39d 100644
--- a/frontend/test/playwright/e2e/filters-sidebar-keyboard.spec.ts
+++ b/frontend/test/playwright/e2e/filters-sidebar-keyboard.spec.ts
@@ -4,7 +4,7 @@ import {
LanguageDirection,
languageDirections,
pathWithDir,
- setBreakpointCookie,
+ preparePageForTests,
t,
} from "~~/test/playwright/utils/navigation"
@@ -32,7 +32,7 @@ test.describe.configure({ mode: "parallel" })
for (const dir of languageDirections) {
test.describe(`search header keyboard accessibility test in ${dir}`, () => {
test.beforeEach(async ({ page }) => {
- await setBreakpointCookie(page, "lg")
+ await preparePageForTests(page, "lg", { dismissFilter: false })
/**
* To simplify finding the last focusable element in the filters sidebar,
* we use the image search page. The last element on the all media search
diff --git a/frontend/test/playwright/e2e/filters.spec.ts b/frontend/test/playwright/e2e/filters.spec.ts
index e5c781d32ee..327c46670a6 100644
--- a/frontend/test/playwright/e2e/filters.spec.ts
+++ b/frontend/test/playwright/e2e/filters.spec.ts
@@ -5,7 +5,7 @@ import {
goToSearchTerm,
isPageDesktop,
filters,
- dismissAllBannersUsingCookies,
+ preparePageForTests,
} from "~~/test/playwright/utils/navigation"
import { mockProviderApis } from "~~/test/playwright/utils/route"
@@ -44,10 +44,10 @@ const FILTER_COUNTS = {
[IMAGE]: 73,
}
-breakpoints.describeMobileAndDesktop(() => {
+breakpoints.describeMobileAndDesktop(({ breakpoint }) => {
test.beforeEach(async ({ context, page }) => {
await mockProviderApis(context)
- await dismissAllBannersUsingCookies(page)
+ await preparePageForTests(page, breakpoint)
})
for (const searchType of supportedSearchTypes) {
test(`correct total number of filters is displayed for ${searchType}`, async ({
diff --git a/frontend/test/playwright/e2e/global-audio.spec.ts b/frontend/test/playwright/e2e/global-audio.spec.ts
index 404d9a65952..84cd844b01b 100644
--- a/frontend/test/playwright/e2e/global-audio.spec.ts
+++ b/frontend/test/playwright/e2e/global-audio.spec.ts
@@ -1,11 +1,18 @@
import { expect, test } from "@playwright/test"
-import { sleep, t } from "~~/test/playwright/utils/navigation"
+import {
+ preparePageForTests,
+ sleep,
+ t,
+} from "~~/test/playwright/utils/navigation"
import breakpoints from "~~/test/playwright/utils/breakpoints"
import audio from "~~/test/playwright/utils/audio"
test.describe("Global Audio", () => {
breakpoints.describeXs(() => {
+ test.beforeEach(async ({ page }) => {
+ await preparePageForTests(page, "xs")
+ })
test("track continues playing when navigating from search to details page", async ({
page,
}) => {
diff --git a/frontend/test/playwright/e2e/header-internal.spec.ts b/frontend/test/playwright/e2e/header-internal.spec.ts
index bc6ad91ba28..c6c3f45834c 100644
--- a/frontend/test/playwright/e2e/header-internal.spec.ts
+++ b/frontend/test/playwright/e2e/header-internal.spec.ts
@@ -5,7 +5,6 @@ import {
LanguageDirection,
preparePageForTests,
scrollToBottom,
- setBreakpointCookie,
t,
} from "~~/test/playwright/utils/navigation"
import breakpoints from "~~/test/playwright/utils/breakpoints"
@@ -110,7 +109,7 @@ test.describe("Header internal", () => {
test("can open and close the popover on sm breakpoint", async ({
page,
}) => {
- await setBreakpointCookie(page, "sm")
+ await preparePageForTests(page, "sm")
await page.goto("/about")
await clickMenuButton(page)
expect(await isPagesPopoverOpen(page)).toBe(true)
diff --git a/frontend/test/playwright/e2e/image-detail.spec.ts b/frontend/test/playwright/e2e/image-detail.spec.ts
index a2186454023..6d11c53130d 100644
--- a/frontend/test/playwright/e2e/image-detail.spec.ts
+++ b/frontend/test/playwright/e2e/image-detail.spec.ts
@@ -1,11 +1,7 @@
import { test, expect, Page } from "@playwright/test"
import { mockProviderApis } from "~~/test/playwright/utils/route"
-import {
- setCookies,
- t,
- turnOnAnalytics,
-} from "~~/test/playwright/utils/navigation"
+import { preparePageForTests, t } from "~~/test/playwright/utils/navigation"
import {
collectAnalyticsEvents,
expectEventPayloadToMatch,
@@ -30,7 +26,7 @@ test.beforeEach(async ({ context }) => {
})
test("shows the author and title of the image", async ({ page }) => {
- await setCookies(page.context(), {
+ await preparePageForTests(page, "xl", {
features: { additional_search_views: "off" },
})
await goToCustomImagePage(page)
@@ -72,11 +68,13 @@ test("shows the 404 error page when no id", async ({ page }) => {
})
test.describe("analytics", () => {
+ test.beforeEach(async ({ page }) => {
+ await preparePageForTests(page, "xl", { features: { analytics: "on" } })
+ })
test("sends GET_MEDIA event on CTA button click", async ({
context,
page,
}) => {
- await turnOnAnalytics(page)
const analyticsEvents = collectAnalyticsEvents(context)
await goToCustomImagePage(page)
@@ -98,7 +96,6 @@ test.describe("analytics", () => {
context,
page,
}) => {
- await turnOnAnalytics(page)
const analyticsEvents = collectAnalyticsEvents(context)
await goToCustomImagePage(page)
diff --git a/frontend/test/playwright/e2e/skip-to-content.spec.ts b/frontend/test/playwright/e2e/skip-to-content.spec.ts
index f1e1cb3d239..b8a1948b2b7 100644
--- a/frontend/test/playwright/e2e/skip-to-content.spec.ts
+++ b/frontend/test/playwright/e2e/skip-to-content.spec.ts
@@ -2,10 +2,7 @@ import { expect, test } from "@playwright/test"
import breakpoints from "~~/test/playwright/utils/breakpoints"
-import {
- dismissBannersUsingCookies,
- setBreakpointCookie,
-} from "~~/test/playwright/utils/navigation"
+import { preparePageForTests } from "~~/test/playwright/utils/navigation"
import { keycodes } from "~/constants/key-codes"
import { skipToContentTargetId } from "~/constants/window"
@@ -29,8 +26,9 @@ const pages = [
for (const pageUrl of pages) {
breakpoints.describeMobileAndDesktop(async ({ breakpoint }) => {
test(`can skip to content on ${pageUrl}`, async ({ page }) => {
- await dismissBannersUsingCookies(page)
- await setBreakpointCookie(page, breakpoint)
+ await preparePageForTests(page, breakpoint, {
+ features: { fetch_sensitive: "off" },
+ })
await page.goto(pageUrl)
diff --git a/frontend/test/playwright/e2e/translation-banner.spec.ts b/frontend/test/playwright/e2e/translation-banner.spec.ts
index 9b0879bed8c..e635b903a45 100644
--- a/frontend/test/playwright/e2e/translation-banner.spec.ts
+++ b/frontend/test/playwright/e2e/translation-banner.spec.ts
@@ -1,6 +1,6 @@
import { test, expect } from "@playwright/test"
-import { dismissBannersUsingCookies } from "~~/test/playwright/utils/navigation"
+import { preparePageForTests } from "~~/test/playwright/utils/navigation"
const russianSearchPath = "/ru/search?q=dog"
@@ -29,7 +29,7 @@ test.describe("translation banner", () => {
test("Banner is not shown if dismissed state is saved in a cookie", async ({
page,
}) => {
- await dismissBannersUsingCookies(page)
+ await preparePageForTests(page, "xl")
await page.goto(russianSearchPath)
await expect(page.locator('[data-testid="banner-translation"]')).toBeHidden(
diff --git a/frontend/test/playwright/utils/navigation.ts b/frontend/test/playwright/utils/navigation.ts
index 3c63402a113..ddc76bb2032 100644
--- a/frontend/test/playwright/utils/navigation.ts
+++ b/frontend/test/playwright/utils/navigation.ts
@@ -225,42 +225,6 @@ export const currentContentType = async (page: Page) => {
return currentContentType
}
-export const dismissAllBannersUsingCookies = async (page: Page) => {
- const uiDismissedBanners = [
- ...["ru", "en", "ar", "es"].map((lang) => `translation-${lang}`),
- "analytics",
- ]
- await setCookies(page.context(), { uiDismissedBanners })
-}
-
-/**
- * Dismisses the translation banner if it is visible. It does not wait for the banner to become visible,
- * so the page should finish rendering before calling `dismissTranslationBanner`.
- */
-export const dismissTranslationBanner = async (page: Page) => {
- await dismissAllBannersUsingCookies(page)
- const bannerCloseButton = page.locator(
- '[data-testid="banner-translation"] button'
- )
- if (await bannerCloseButton.isVisible()) {
- await bannerCloseButton.click()
- }
-}
-
-/**
- * Dismisses the analytics banner if it is visible. It does not wait for the banner to become visible,
- * so the page should finish rendering before calling `dismissAnalyticsBanner`.
- */
-export const dismissAnalyticsBanner = async (page: Page) => {
- await dismissAllBannersUsingCookies(page)
- const bannerCloseButton = page.locator(
- '[data-testid="banner-analytics"] button'
- )
- if (await bannerCloseButton.isVisible()) {
- await bannerCloseButton.click()
- }
-}
-
export const selectHomepageSearchType = async (
page: Page,
searchType: SupportedSearchType,
@@ -274,18 +238,32 @@ export const selectHomepageSearchType = async (
.click()
}
-export const dismissBannersUsingCookies = async (page: Page) => {
- await dismissAnalyticsBanner(page)
- await dismissTranslationBanner(page)
-}
-
+const ALL_TEST_BANNERS = [
+ ...["ru", "en", "ar", "es"].map((lang) => `translation-${lang}`),
+ "analytics",
+]
export const preparePageForTests = async (
page: Page,
- breakpoint: Breakpoint
+ breakpoint: Breakpoint,
+ options: Partial<{
+ features: Record
+ dismissBanners: boolean
+ dismissFilter: boolean
+ }> = {}
) => {
- await dismissAllBannersUsingCookies(page)
- await closeFiltersUsingCookies(page)
- await setBreakpointCookie(page, breakpoint)
+ const { features = {}, dismissBanners = true, dismissFilter = true } = options
+ const featuresCookie: Record = {}
+ if (options.features) {
+ for (const [feature, status] of Object.entries(features)) {
+ featuresCookie[feature] = status
+ }
+ }
+ await setCookies(page.context(), {
+ features: featuresCookie,
+ uiDismissedBanners: dismissBanners ? ALL_TEST_BANNERS : [],
+ uiIsFilterDismissed: dismissFilter ?? false,
+ uiBreakpoint: breakpoint,
+ })
}
export const goToSearchTerm = async (
@@ -303,7 +281,6 @@ export const goToSearchTerm = async (
const mode = options.mode ?? "SSR"
const query = options.query ? `&${options.query}` : ""
- await dismissAllBannersUsingCookies(page)
if (mode === "SSR") {
const path = `${searchPath(searchType)}?q=${term}${query}`
await page.goto(pathWithDir(path, dir))
@@ -426,31 +403,44 @@ export const setCookies = async (
context: BrowserContext,
cookies: CookieMap
) => {
- await context.addCookies(
- Object.entries(cookies).map(([name, value]) => ({
+ const existingCookies = await context.cookies()
+ const cookiesToSet = Object.entries(cookies).map(([name, value]) => {
+ let existingValue = existingCookies.find((c) => c.name === name)?.value
+
+ // If cookie was URI encoded, it starts with %7B%22 `{"` or %5B%22 `["`
+ if (
+ existingValue &&
+ (existingValue.includes("%7B%22") || existingValue.includes("%5B%22"))
+ ) {
+ existingValue = decodeURIComponent(existingValue)
+ }
+ let newCookieValue = ""
+ if (existingValue) {
+ if (Array.isArray(value)) {
+ newCookieValue = JSON.stringify(
+ Array.from(new Set([...JSON.parse(existingValue), ...value]))
+ )
+ } else if (typeof value === "string") {
+ newCookieValue = value
+ } else if (typeof value === "object") {
+ newCookieValue = JSON.stringify({
+ ...JSON.parse(existingValue),
+ ...value,
+ })
+ } else if (typeof value === "boolean") {
+ newCookieValue = String(value)
+ }
+ } else {
+ newCookieValue = typeof value === "string" ? value : JSON.stringify(value)
+ }
+
+ return {
name,
- value: typeof value === "string" ? value : JSON.stringify(value),
+ value: newCookieValue,
domain: "localhost",
path: "/",
maxAge: 60 * 5,
- }))
- )
-}
-
-export const closeFiltersUsingCookies = async (page: Page) => {
- await setCookies(page.context(), { uiIsFilterDismissed: true })
-}
-
-export const setBreakpointCookie = async (page: Page, breakpoint: string) => {
- await setCookies(page.context(), { uiBreakpoint: breakpoint })
-}
-
-export const turnOnAnalytics = async (page: Page) => {
- await page.goto("/preferences")
- const analyticsCheckbox = page.getByLabel(
- "Record custom events and page views."
- )
- if (!(await analyticsCheckbox.isChecked())) {
- await analyticsCheckbox.click()
- }
+ }
+ })
+ await context.addCookies(cookiesToSet)
}
diff --git a/frontend/test/playwright/visual-regression/components/content-report-form.spec.ts b/frontend/test/playwright/visual-regression/components/content-report-form.spec.ts
index d2481b2f14c..7215b3ef8f5 100644
--- a/frontend/test/playwright/visual-regression/components/content-report-form.spec.ts
+++ b/frontend/test/playwright/visual-regression/components/content-report-form.spec.ts
@@ -1,6 +1,6 @@
import { Page, test } from "@playwright/test"
-import { t } from "~~/test/playwright/utils/navigation"
+import { preparePageForTests, t } from "~~/test/playwright/utils/navigation"
import breakpoints from "~~/test/playwright/utils/breakpoints"
const imageUrl = "/image/feb91b13-422d-46fa-8ef4-cbf1e6ddee9b"
@@ -19,6 +19,7 @@ const getReportForm = (page: Page) => {
breakpoints.describeMd(({ expectSnapshot }) => {
test("unfocused close button", async ({ page }) => {
+ await preparePageForTests(page, "md")
await page.goto(imageUrl)
await getReportButton(page).click()
@@ -33,6 +34,7 @@ test.describe("content report form", () => {
breakpoints.describeMd(({ expectSnapshot }) => {
test("focused close button", async ({ page }) => {
+ await preparePageForTests(page, "md")
await page.goto(imageUrl)
await getReportButton(page).click()
diff --git a/frontend/test/playwright/visual-regression/components/external-sources-section.spec.ts b/frontend/test/playwright/visual-regression/components/external-sources-section.spec.ts
index ad07a95d782..741f22bce02 100644
--- a/frontend/test/playwright/visual-regression/components/external-sources-section.spec.ts
+++ b/frontend/test/playwright/visual-regression/components/external-sources-section.spec.ts
@@ -3,6 +3,7 @@ import { test } from "@playwright/test"
import {
goToSearchTerm,
languageDirections,
+ preparePageForTests,
t,
} from "~~/test/playwright/utils/navigation"
@@ -14,34 +15,38 @@ test.describe.configure({ mode: "parallel" })
for (const dir of languageDirections) {
for (const mediaType of supportedMediaTypes) {
- breakpoints.describeMobileAndDesktop(async ({ expectSnapshot }) => {
- test(`External ${mediaType} sources popover - ${dir}`, async ({
- page,
- }) => {
- await goToSearchTerm(page, "birds", { searchType: mediaType, dir })
-
- const externalSourcesButton = page.getByRole("button", {
- name: new RegExp(
- t("externalSources.form.supportedTitleSm", dir),
- "i"
- ),
+ breakpoints.describeMobileAndDesktop(
+ async ({ breakpoint, expectSnapshot }) => {
+ test(`external ${mediaType} sources popover - ${dir}`, async ({
+ page,
+ }) => {
+ await preparePageForTests(page, breakpoint)
+
+ await goToSearchTerm(page, "birds", { searchType: mediaType, dir })
+
+ const externalSourcesButton = page.getByRole("button", {
+ name: new RegExp(
+ t("externalSources.form.supportedTitleSm", dir),
+ "i"
+ ),
+ })
+
+ await page
+ .getByRole("contentinfo")
+ .getByRole("link", { name: "Openverse" })
+ .scrollIntoViewIfNeeded()
+
+ await externalSourcesButton.click()
+ await page.mouse.move(0, 0)
+
+ await expectSnapshot(
+ `external-${mediaType}-sources-popover-${dir}`,
+ page.getByRole("dialog"),
+ {},
+ { maxDiffPixelRatio: 0.01, maxDiffPixels: undefined }
+ )
})
-
- await page
- .getByRole("contentinfo")
- .getByRole("link", { name: "Openverse" })
- .scrollIntoViewIfNeeded()
-
- await externalSourcesButton.click()
- await page.mouse.move(0, 0)
-
- await expectSnapshot(
- `external-${mediaType}-sources-popover-${dir}`,
- page.getByRole("dialog"),
- {},
- { maxDiffPixelRatio: 0.01 }
- )
- })
- })
+ }
+ )
}
}
diff --git a/frontend/test/playwright/visual-regression/components/filters.spec.ts b/frontend/test/playwright/visual-regression/components/filters.spec.ts
index ebc0a04548b..1a4e2d9f68e 100644
--- a/frontend/test/playwright/visual-regression/components/filters.spec.ts
+++ b/frontend/test/playwright/visual-regression/components/filters.spec.ts
@@ -1,11 +1,10 @@
import { test } from "@playwright/test"
import {
- dismissAllBannersUsingCookies,
filters,
languageDirections,
pathWithDir,
- setBreakpointCookie,
+ preparePageForTests,
} from "~~/test/playwright/utils/navigation"
import breakpoints from "~~/test/playwright/utils/breakpoints"
@@ -21,8 +20,7 @@ for (const dir of languageDirections) {
({ breakpoint, expectSnapshot }) => {
const isDesktop = breakpoint === "lg"
test.beforeEach(async ({ page }) => {
- await setBreakpointCookie(page, breakpoint)
- await dismissAllBannersUsingCookies(page)
+ await preparePageForTests(page, breakpoint)
await page.goto(pathWithDir("/search/?q=birds", dir))
await filters.open(page, dir)
})
diff --git a/frontend/test/playwright/visual-regression/components/global-audio-player.spec.ts b/frontend/test/playwright/visual-regression/components/global-audio-player.spec.ts
index 211c86a852f..92f8cc1ab57 100644
--- a/frontend/test/playwright/visual-regression/components/global-audio-player.spec.ts
+++ b/frontend/test/playwright/visual-regression/components/global-audio-player.spec.ts
@@ -1,11 +1,10 @@
import { test } from "@playwright/test"
import {
- dismissTranslationBanner,
- dismissAnalyticsBanner,
languageDirections,
pathWithDir,
t,
+ preparePageForTests,
} from "~~/test/playwright/utils/navigation"
import breakpoints from "~~/test/playwright/utils/breakpoints"
import audio from "~~/test/playwright/utils/audio"
@@ -15,8 +14,7 @@ for (const dir of languageDirections) {
test(`Global audio player on the search page - ${dir}`, async ({
page,
}) => {
- await dismissTranslationBanner(page)
- await dismissAnalyticsBanner(page)
+ await preparePageForTests(page, "xs")
await page.goto(
pathWithDir("/search/audio/?q=honey&length=shortest", dir)
)
diff --git a/frontend/test/playwright/visual-regression/components/header.spec.ts b/frontend/test/playwright/visual-regression/components/header.spec.ts
index ffbec5f758e..7ff3ae034d6 100644
--- a/frontend/test/playwright/visual-regression/components/header.spec.ts
+++ b/frontend/test/playwright/visual-regression/components/header.spec.ts
@@ -8,8 +8,8 @@ import {
filters,
goToSearchTerm,
languageDirections,
+ preparePageForTests,
scrollToBottom,
- setBreakpointCookie,
sleep,
} from "~~/test/playwright/utils/navigation"
@@ -21,7 +21,7 @@ for (const dir of languageDirections) {
test.describe(`header-${dir}`, () => {
breakpoints.describeEvery(({ breakpoint, expectSnapshot }) => {
test.beforeEach(async ({ page }) => {
- await setBreakpointCookie(page, breakpoint)
+ await preparePageForTests(page, breakpoint, { dismissFilter: false })
await goToSearchTerm(page, "birds", { dir })
})
diff --git a/frontend/test/playwright/visual-regression/pages/homepage.spec.ts b/frontend/test/playwright/visual-regression/pages/homepage.spec.ts
index 49ba95aaede..0064b41d5fc 100644
--- a/frontend/test/playwright/visual-regression/pages/homepage.spec.ts
+++ b/frontend/test/playwright/visual-regression/pages/homepage.spec.ts
@@ -3,10 +3,10 @@ import { test, Page } from "@playwright/test"
import breakpoints from "~~/test/playwright/utils/breakpoints"
import { hideInputCursors } from "~~/test/playwright/utils/page"
import {
- dismissTranslationBanner,
- dismissAnalyticsBanner,
languageDirections,
pathWithDir,
+ preparePageForTests,
+ setCookies,
} from "~~/test/playwright/utils/navigation"
test.describe.configure({ mode: "parallel" })
@@ -25,24 +25,24 @@ const cleanImageCarousel = async (page: Page) => {
}
for (const dir of languageDirections) {
- test.describe(`${dir} homepage snapshots`, () => {
- const path = pathWithDir("/?ff_additional_search_types=off", dir)
- test.beforeEach(async ({ page }) => {
- await page.goto(path)
- await dismissTranslationBanner(page)
- await dismissAnalyticsBanner(page)
- await cleanImageCarousel(page)
- await page.mouse.move(0, 0)
- })
+ const path = pathWithDir("/", dir)
+
+ breakpoints.describeEvery(({ breakpoint, expectSnapshot }) => {
+ test.describe(`${dir} homepage`, () => {
+ test.beforeEach(async ({ page }) => {
+ await preparePageForTests(page, breakpoint, {
+ features: { additional_search_types: "off" },
+ })
+ await page.goto(path)
+ await cleanImageCarousel(page)
+ await page.mouse.move(0, 0)
+ })
- breakpoints.describeEvery(({ expectSnapshot }) =>
test(`${dir} full page`, async ({ page }) => {
await expectSnapshot(`index-${dir}`, page)
})
- )
- test.describe("search input", () => {
- breakpoints.describeEvery(({ expectSnapshot }) => {
+ test.describe("search input", () => {
test("unfocused", async ({ page }) => {
await expectSnapshot(
`unfocused-search-${dir}`,
@@ -68,7 +68,11 @@ for (const dir of languageDirections) {
test("content switcher with external sources open", async ({
page,
}) => {
- await page.goto(pathWithDir("/?ff_additional_search_types=on", dir))
+ await setCookies(page.context(), {
+ features: { additional_search_types: "on" },
+ })
+
+ await page.goto(path)
await cleanImageCarousel(page)
await page.locator("#search-type-button").click()
diff --git a/frontend/test/playwright/visual-regression/pages/pages-single-result.spec.ts b/frontend/test/playwright/visual-regression/pages/pages-single-result.spec.ts
index 9b01828e545..be24e026aad 100644
--- a/frontend/test/playwright/visual-regression/pages/pages-single-result.spec.ts
+++ b/frontend/test/playwright/visual-regression/pages/pages-single-result.spec.ts
@@ -7,7 +7,6 @@ import {
openFirstResult,
pathWithDir,
preparePageForTests,
- setCookies,
} from "~~/test/playwright/utils/navigation"
import { supportedMediaTypes } from "~/constants/media"
@@ -21,10 +20,10 @@ for (const isOn of [true, false]) {
test(`${mediaType} ${dir} single-result page snapshots from search results, additional search views: ${isOn}`, async ({
page,
}) => {
- await setCookies(page.context(), {
+ await preparePageForTests(page, breakpoint, {
features: { additional_search_views: isOn ? "on" : "off" },
})
- await preparePageForTests(page, breakpoint)
+
await page.route("**", (route) => {
const url = route.request().url()
// For audio, use the generated image instead of requesting the
diff --git a/frontend/test/playwright/visual-regression/pages/pages.spec.ts b/frontend/test/playwright/visual-regression/pages/pages.spec.ts
index 258252c012e..627f64706f4 100644
--- a/frontend/test/playwright/visual-regression/pages/pages.spec.ts
+++ b/frontend/test/playwright/visual-regression/pages/pages.spec.ts
@@ -2,7 +2,6 @@ import { expect, test } from "@playwright/test"
import breakpoints from "~~/test/playwright/utils/breakpoints"
import {
- dismissBannersUsingCookies,
languageDirections,
pathWithDir,
preparePageForTests,
@@ -40,7 +39,7 @@ for (const contentPage of contentPages) {
test.describe("Layout color is set correctly", () => {
breakpoints.describeLg(() => {
test.beforeEach(async ({ page }) => {
- await dismissBannersUsingCookies(page)
+ await preparePageForTests(page, "lg", { dismissFilter: false })
})
test("Change language on homepage and search", async ({ page }) => {
diff --git a/frontend/test/playwright/visual-regression/pages/search-with-banners.spec.ts b/frontend/test/playwright/visual-regression/pages/search-with-banners.spec.ts
index 8a83bff59ea..7e0c6bccf4d 100644
--- a/frontend/test/playwright/visual-regression/pages/search-with-banners.spec.ts
+++ b/frontend/test/playwright/visual-regression/pages/search-with-banners.spec.ts
@@ -1,13 +1,16 @@
import { test } from "@playwright/test"
import breakpoints from "~~/test/playwright/utils/breakpoints"
-import { setBreakpointCookie } from "~~/test/playwright/utils/navigation"
+import { preparePageForTests } from "~~/test/playwright/utils/navigation"
test.describe.configure({ mode: "parallel" })
breakpoints.describeEvery(({ breakpoint, expectSnapshot }) => {
test.beforeEach(async ({ page }) => {
- await setBreakpointCookie(page, breakpoint)
+ await preparePageForTests(page, breakpoint, {
+ dismissBanners: false,
+ dismissFilter: false,
+ })
await page.goto("/ru/search/?q=birds&referrer=creativecommons.org")
})
diff --git a/frontend/test/storybook/visual-regression/v-old-icon-button.spec.ts b/frontend/test/storybook/visual-regression/v-old-icon-button.spec.ts
deleted file mode 100644
index 226c6394100..00000000000
--- a/frontend/test/storybook/visual-regression/v-old-icon-button.spec.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { expect, test } from "@playwright/test"
-
-test.describe("VOldIconButton", () => {
- const url = "/iframe.html?id=components-voldiconbutton--sizes"
-
- test("old icon button sizes", async ({ page }) => {
- await page.goto(url)
- expect(await page.screenshot()).toMatchSnapshot({
- name: "v-old-icon-button-sizes.png",
- })
- })
-})
diff --git a/frontend/test/storybook/visual-regression/v-old-icon-button.spec.ts-snapshots/v-old-icon-button-sizes-linux.png b/frontend/test/storybook/visual-regression/v-old-icon-button.spec.ts-snapshots/v-old-icon-button-sizes-linux.png
deleted file mode 100644
index 6a8a22dd9c5..00000000000
Binary files a/frontend/test/storybook/visual-regression/v-old-icon-button.spec.ts-snapshots/v-old-icon-button-sizes-linux.png and /dev/null differ
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index deeafff6ab3..9fea211f212 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -215,8 +215,8 @@ importers:
specifier: ^29.5.4
version: 29.5.4
'@types/node':
- specifier: 18.19.0
- version: 18.19.0
+ specifier: 18.19.4
+ version: 18.19.4
'@types/throttle-debounce':
specifier: ^5.0.0
version: 5.0.0
@@ -282,7 +282,7 @@ importers:
version: 3.0.1
ts-node:
specifier: ^10.9.1
- version: 10.9.1(@types/node@18.19.0)(typescript@5.2.2)
+ version: 10.9.1(@types/node@18.19.4)(typescript@5.2.2)
typescript:
specifier: ^5.2.2
version: 5.2.2
@@ -4127,7 +4127,7 @@ packages:
engines: {node: '>= 10.14.2'}
dependencies:
'@jest/types': 26.6.2
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
chalk: 4.1.2
jest-message-util: 26.6.2
jest-util: 26.6.2
@@ -4139,7 +4139,7 @@ packages:
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
dependencies:
'@jest/types': 29.6.3
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
chalk: 4.1.2
jest-message-util: 29.6.3
jest-util: 29.6.3
@@ -4154,7 +4154,7 @@ packages:
'@jest/test-result': 26.6.2
'@jest/transform': 26.6.2
'@jest/types': 26.6.2
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
ansi-escapes: 4.3.2
chalk: 4.1.2
exit: 0.1.2
@@ -4199,14 +4199,14 @@ packages:
'@jest/test-result': 29.6.4
'@jest/transform': 29.6.4
'@jest/types': 29.6.3
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
ansi-escapes: 4.3.2
chalk: 4.1.2
ci-info: 3.8.0
exit: 0.1.2
graceful-fs: 4.2.11
jest-changed-files: 29.6.3
- jest-config: 29.6.4(@types/node@18.19.0)
+ jest-config: 29.6.4(@types/node@18.19.4)
jest-haste-map: 29.6.4
jest-message-util: 29.6.3
jest-regex-util: 29.6.3
@@ -4240,7 +4240,7 @@ packages:
dependencies:
'@jest/fake-timers': 26.6.2
'@jest/types': 26.6.2
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
jest-mock: 26.6.2
dev: true
@@ -4250,7 +4250,7 @@ packages:
dependencies:
'@jest/fake-timers': 29.6.4
'@jest/types': 29.6.3
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
jest-mock: 29.6.3
/@jest/expect-utils@29.6.4:
@@ -4274,7 +4274,7 @@ packages:
dependencies:
'@jest/types': 26.6.2
'@sinonjs/fake-timers': 6.0.1
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
jest-message-util: 26.6.2
jest-mock: 26.6.2
jest-util: 26.6.2
@@ -4286,7 +4286,7 @@ packages:
dependencies:
'@jest/types': 29.6.3
'@sinonjs/fake-timers': 10.3.0
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
jest-message-util: 29.6.3
jest-mock: 29.6.3
jest-util: 29.6.3
@@ -4360,7 +4360,7 @@ packages:
'@jest/transform': 29.6.4
'@jest/types': 29.6.3
'@jridgewell/trace-mapping': 0.3.18
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
chalk: 4.1.2
collect-v8-coverage: 1.0.1
exit: 0.1.2
@@ -4500,7 +4500,7 @@ packages:
dependencies:
'@types/istanbul-lib-coverage': 2.0.3
'@types/istanbul-reports': 3.0.1
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
'@types/yargs': 15.0.14
chalk: 4.1.2
dev: true
@@ -4511,7 +4511,7 @@ packages:
dependencies:
'@types/istanbul-lib-coverage': 2.0.3
'@types/istanbul-reports': 3.0.1
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
'@types/yargs': 16.0.4
chalk: 4.1.2
dev: true
@@ -4522,7 +4522,7 @@ packages:
dependencies:
'@types/istanbul-lib-coverage': 2.0.3
'@types/istanbul-reports': 3.0.1
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
'@types/yargs': 16.0.4
chalk: 4.1.2
dev: true
@@ -4534,7 +4534,7 @@ packages:
'@jest/schemas': 29.6.3
'@types/istanbul-lib-coverage': 2.0.3
'@types/istanbul-reports': 3.0.1
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
'@types/yargs': 17.0.24
chalk: 4.1.2
@@ -5690,7 +5690,7 @@ packages:
engines: {node: '>=14'}
hasBin: true
dependencies:
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
playwright-core: 1.30.0
dev: true
@@ -7336,7 +7336,7 @@ packages:
resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==}
dependencies:
'@types/connect': 3.4.37
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
dev: true
/@types/cacheable-request@6.0.3:
@@ -7344,14 +7344,14 @@ packages:
dependencies:
'@types/http-cache-semantics': 4.0.1
'@types/keyv': 3.1.4
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
'@types/responselike': 1.0.0
dev: true
/@types/clean-css@4.2.5:
resolution: {integrity: sha512-NEzjkGGpbs9S9fgC4abuBvTpVwE3i+Acu9BBod3PUyjDVZcNsGx61b8r2PphR61QGPnn0JHVs5ey6/I4eTrkxw==}
dependencies:
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
source-map: 0.6.1
dev: true
@@ -7364,7 +7364,7 @@ packages:
/@types/connect@3.4.37:
resolution: {integrity: sha512-zBUSRqkfZ59OcwXon4HVxhx5oWCJmc0OtBTK05M+p0dYjgN6iTwIL2T/WbsQZrEsdnwaF9cWQ+azOnpPvIqY3Q==}
dependencies:
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
dev: true
/@types/cookie@0.3.3:
@@ -7374,13 +7374,13 @@ packages:
/@types/etag@1.8.2:
resolution: {integrity: sha512-z8Pbo2e+EZWMpuRPYSjhSivp2OEkqrMZBUfEAWlJC31WUCKveZ8ioWXHAC5BXRZfwxCBfYRhPij1YJHK1W6oDA==}
dependencies:
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
dev: true
/@types/express-serve-static-core@4.17.26:
resolution: {integrity: sha512-zeu3tpouA043RHxW0gzRxwCHchMgftE8GArRsvYT0ByDMbn19olQHx5jLue0LxWY6iYtXb7rXmuVtSkhy9YZvQ==}
dependencies:
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
'@types/qs': 6.9.7
'@types/range-parser': 1.2.4
dev: true
@@ -7410,13 +7410,13 @@ packages:
resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==}
dependencies:
'@types/minimatch': 3.0.5
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
dev: true
/@types/graceful-fs@4.1.5:
resolution: {integrity: sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==}
dependencies:
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
/@types/hast@2.3.4:
resolution: {integrity: sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==}
@@ -7446,7 +7446,7 @@ packages:
/@types/http-proxy@1.17.10:
resolution: {integrity: sha512-Qs5aULi+zV1bwKAg5z1PWnDXWmsn+LxIvUGv6E2+OOMYhclZMO+OXd9pYVf2gLykf2I7IV2u7oTHwChPNsvJ7g==}
dependencies:
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
dev: false
/@types/is-function@1.0.1:
@@ -7489,7 +7489,7 @@ packages:
/@types/keyv@3.1.4:
resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
dependencies:
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
dev: true
/@types/less@3.0.5:
@@ -7517,7 +7517,7 @@ packages:
/@types/node-fetch@2.6.1:
resolution: {integrity: sha512-oMqjURCaxoSIsHSr1E47QHzbmzNR5rK8McHuNb11BOM9cHcIK3Avy0s/b2JlXHoQGTYS3NsvWzV1M0iK7l0wbA==}
dependencies:
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
form-data: 3.0.1
dev: true
@@ -7529,8 +7529,8 @@ packages:
resolution: {integrity: sha512-ZOzvDRWp8dCVBmgnkIqYCArgdFOO9YzocZp8Ra25N/RStKiWvMOXHMz+GjSeVNe5TstaTmTWPucGJkDw0XXJWA==}
dev: true
- /@types/node@18.19.0:
- resolution: {integrity: sha512-667KNhaD7U29mT5wf+TZUnrzPrlL2GNQ5N0BMjO2oNULhBxX0/FKCkm6JMu0Jh7Z+1LwUlR21ekd7KhIboNFNw==}
+ /@types/node@18.19.4:
+ resolution: {integrity: sha512-xNzlUhzoHotIsnFoXmJB+yWmBvFZgKCI9TtPIEdYIMM1KWfwuY8zh7wvc1u1OAXlC7dlf6mZVx/s+Y5KfFz19A==}
dependencies:
undici-types: 5.26.5
@@ -7585,13 +7585,13 @@ packages:
/@types/responselike@1.0.0:
resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==}
dependencies:
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
dev: true
/@types/sax@1.2.3:
resolution: {integrity: sha512-+QSw6Tqvs/KQpZX8DvIl3hZSjNFLW/OqE5nlyHXtTwODaJvioN2rOWpBNEWZp2HZUFhOh+VohmJku/WxEXU2XA==}
dependencies:
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
dev: false
/@types/semver@7.5.0:
@@ -7601,7 +7601,7 @@ packages:
resolution: {integrity: sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==}
dependencies:
'@types/mime': 1.3.2
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
dev: true
/@types/serve-static@1.15.4:
@@ -7609,7 +7609,7 @@ packages:
dependencies:
'@types/http-errors': 2.0.3
'@types/mime': 1.3.2
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
dev: true
/@types/source-list-map@0.1.2:
@@ -7683,14 +7683,14 @@ packages:
/@types/webpack-sources@3.2.0:
resolution: {integrity: sha512-Ft7YH3lEVRQ6ls8k4Ff1oB4jN6oy/XmU6tQISKdhfh+1mR+viZFphS6WL0IrtDOzvefmJg5a0s7ZQoRXwqTEFg==}
dependencies:
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
'@types/source-list-map': 0.1.2
source-map: 0.7.3
/@types/webpack@4.41.35:
resolution: {integrity: sha512-XRC6HLGHtNfN8/xWeu1YUQV1GSE+28q8lSqvcJ+0xt/zW9Wmn4j9pCSvaXPyRlCKrl5OuqECQNEJUy2vo8oWqg==}
dependencies:
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
'@types/tapable': 1.0.8
'@types/uglify-js': 3.13.1
'@types/webpack-sources': 3.2.0
@@ -14286,7 +14286,7 @@ packages:
'@jest/expect': 29.6.4
'@jest/test-result': 29.6.4
'@jest/types': 29.6.3
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
chalk: 4.1.2
co: 4.6.0
dedent: 1.5.1
@@ -14349,7 +14349,7 @@ packages:
exit: 0.1.2
graceful-fs: 4.2.11
import-local: 3.0.3
- jest-config: 29.6.4(@types/node@18.19.0)
+ jest-config: 29.6.4(@types/node@18.19.4)
jest-util: 29.6.3
jest-validate: 29.6.3
prompts: 2.4.2
@@ -14387,7 +14387,7 @@ packages:
jest-validate: 26.6.2
micromatch: 4.0.5
pretty-format: 26.6.2
- ts-node: 10.9.1(@types/node@18.19.0)(typescript@5.2.2)
+ ts-node: 10.9.1(@types/node@18.19.4)(typescript@5.2.2)
transitivePeerDependencies:
- bufferutil
- canvas
@@ -14395,7 +14395,7 @@ packages:
- utf-8-validate
dev: true
- /jest-config@29.6.4(@types/node@18.19.0):
+ /jest-config@29.6.4(@types/node@18.19.4):
resolution: {integrity: sha512-JWohr3i9m2cVpBumQFv2akMEnFEPVOh+9L2xIBJhJ0zOaci2ZXuKJj0tgMKQCBZAKA09H049IR4HVS/43Qb19A==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
peerDependencies:
@@ -14410,7 +14410,7 @@ packages:
'@babel/core': 7.22.5
'@jest/test-sequencer': 29.6.4
'@jest/types': 29.6.3
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
babel-jest: 29.6.4(@babel/core@7.22.5)
chalk: 4.1.2
ci-info: 3.8.0
@@ -14494,7 +14494,7 @@ packages:
'@jest/environment': 26.6.2
'@jest/fake-timers': 26.6.2
'@jest/types': 26.6.2
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
jest-mock: 26.6.2
jest-util: 26.6.2
jsdom: 16.7.0
@@ -14512,7 +14512,7 @@ packages:
'@jest/environment': 26.6.2
'@jest/fake-timers': 26.6.2
'@jest/types': 26.6.2
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
jest-mock: 26.6.2
jest-util: 26.6.2
dev: true
@@ -14524,7 +14524,7 @@ packages:
'@jest/environment': 29.6.4
'@jest/fake-timers': 29.6.4
'@jest/types': 29.6.3
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
jest-mock: 29.6.3
jest-util: 29.6.3
@@ -14549,7 +14549,7 @@ packages:
dependencies:
'@jest/types': 26.6.2
'@types/graceful-fs': 4.1.5
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
anymatch: 3.1.3
fb-watchman: 2.0.1
graceful-fs: 4.2.11
@@ -14572,7 +14572,7 @@ packages:
dependencies:
'@jest/types': 29.6.3
'@types/graceful-fs': 4.1.5
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
anymatch: 3.1.3
fb-watchman: 2.0.1
graceful-fs: 4.2.11
@@ -14593,7 +14593,7 @@ packages:
'@jest/source-map': 26.6.2
'@jest/test-result': 26.6.2
'@jest/types': 26.6.2
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
chalk: 4.1.2
co: 4.6.0
expect: 26.6.2
@@ -14682,7 +14682,7 @@ packages:
engines: {node: '>= 10.14.2'}
dependencies:
'@jest/types': 26.6.2
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
dev: true
/jest-mock@29.6.3:
@@ -14690,7 +14690,7 @@ packages:
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
dependencies:
'@jest/types': 29.6.3
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
jest-util: 29.6.3
/jest-pnp-resolver@1.2.2(jest-resolve@26.6.2):
@@ -14781,7 +14781,7 @@ packages:
'@jest/environment': 26.6.2
'@jest/test-result': 26.6.2
'@jest/types': 26.6.2
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
chalk: 4.1.2
emittery: 0.7.2
exit: 0.1.2
@@ -14814,7 +14814,7 @@ packages:
'@jest/test-result': 29.6.4
'@jest/transform': 29.6.4
'@jest/types': 29.6.3
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
chalk: 4.1.2
emittery: 0.13.1
graceful-fs: 4.2.11
@@ -14884,7 +14884,7 @@ packages:
'@jest/test-result': 29.6.4
'@jest/transform': 29.6.4
'@jest/types': 29.6.3
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
chalk: 4.1.2
cjs-module-lexer: 1.2.3
collect-v8-coverage: 1.0.1
@@ -14906,7 +14906,7 @@ packages:
resolution: {integrity: sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==}
engines: {node: '>= 10.14.2'}
dependencies:
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
graceful-fs: 4.2.11
dev: true
@@ -14970,7 +14970,7 @@ packages:
engines: {node: '>= 10.14.2'}
dependencies:
'@jest/types': 26.6.2
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
chalk: 4.1.2
graceful-fs: 4.2.11
is-ci: 2.0.0
@@ -14982,7 +14982,7 @@ packages:
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
dependencies:
'@jest/types': 29.6.3
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
chalk: 4.1.2
ci-info: 3.8.0
graceful-fs: 4.2.11
@@ -15017,7 +15017,7 @@ packages:
dependencies:
'@jest/test-result': 26.6.2
'@jest/types': 26.6.2
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
ansi-escapes: 4.3.2
chalk: 4.1.2
jest-util: 26.6.2
@@ -15030,7 +15030,7 @@ packages:
dependencies:
'@jest/test-result': 29.6.4
'@jest/types': 29.6.3
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
ansi-escapes: 4.3.2
chalk: 4.1.2
emittery: 0.13.1
@@ -15041,7 +15041,7 @@ packages:
resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==}
engines: {node: '>= 10.13.0'}
dependencies:
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
merge-stream: 2.0.0
supports-color: 7.2.0
@@ -15049,7 +15049,7 @@ packages:
resolution: {integrity: sha512-6dpvFV4WjcWbDVGgHTWo/aupl8/LbBx2NSKfiwqf79xC/yeJjKHT1+StcKy/2KTmW16hE68ccKVOtXf+WZGz7Q==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
dependencies:
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
jest-util: 29.6.3
merge-stream: 2.0.0
supports-color: 8.1.1
@@ -17557,7 +17557,7 @@ packages:
dependencies:
lilconfig: 2.1.0
postcss: 8.4.31
- ts-node: 10.9.1(@types/node@18.19.0)(typescript@5.2.2)
+ ts-node: 10.9.1(@types/node@18.19.4)(typescript@5.2.2)
yaml: 2.3.1
dev: true
@@ -20773,7 +20773,7 @@ packages:
resolution: {integrity: sha512-vDWbsl26LIcPGmDpoVzjEP6+hvHZkBkLW7JpvwbCv/5IYPJlsbzCVXY3wsCeAxAUeTclNOUZxnLdGh3VBD/J6w==}
dev: true
- /ts-node@10.9.1(@types/node@18.19.0)(typescript@5.2.2):
+ /ts-node@10.9.1(@types/node@18.19.4)(typescript@5.2.2):
resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==}
hasBin: true
peerDependencies:
@@ -20792,7 +20792,7 @@ packages:
'@tsconfig/node12': 1.0.11
'@tsconfig/node14': 1.0.3
'@tsconfig/node16': 1.0.4
- '@types/node': 18.19.0
+ '@types/node': 18.19.4
acorn: 8.10.0
acorn-walk: 8.2.0
arg: 4.1.3