From 16a31522bc6ca85883d8897eca3762183c495515 Mon Sep 17 00:00:00 2001 From: muhammad-ammar Date: Thu, 12 Sep 2024 15:33:36 +0500 Subject: [PATCH 1/2] feat: translate chart hovertemplate and legend --- .../AdvanceAnalyticsV2/data/utils.js | 14 ++++++++ .../AdvanceAnalyticsV2/data/utils.test.js | 15 ++++++++ src/components/AdvanceAnalyticsV2/messages.js | 34 +++++++++++++++++++ .../AdvanceAnalyticsV2/tabs/Completions.jsx | 16 +++++++-- .../AdvanceAnalyticsV2/tabs/Engagements.jsx | 16 +++++++-- .../AdvanceAnalyticsV2/tabs/Enrollments.jsx | 15 ++++++-- .../AdvanceAnalyticsV2/tabs/Skills.jsx | 17 ++++++++-- 7 files changed, 116 insertions(+), 11 deletions(-) create mode 100644 src/components/AdvanceAnalyticsV2/messages.js diff --git a/src/components/AdvanceAnalyticsV2/data/utils.js b/src/components/AdvanceAnalyticsV2/data/utils.js index fc1014cf0c..5c68827b64 100644 --- a/src/components/AdvanceAnalyticsV2/data/utils.js +++ b/src/components/AdvanceAnalyticsV2/data/utils.js @@ -6,6 +6,7 @@ import { CHART_TYPES, CALCULATION } from './constants'; dayjs.extend(utc); dayjs.extend(quarterOfYear); +import messages from '../messages'; const simulateURL = (activeTab, chartType) => { if (!Object.values(CHART_TYPES).includes(chartType)) { @@ -14,6 +15,19 @@ const simulateURL = (activeTab, chartType) => { return `${activeTab}/stats`; }; +/** + * Constructs a chart hover template. + * + * @param {Object} intl - Internationalization object. + * @param {Object} hoverInfo - Object containing hover information to show over chart data points. + * @returns {string} The constructed chart hover template. + */ +export function constructChartHoverTemplate(intl, hoverInfo) { + return Object.entries(hoverInfo) + .map(([key, value]) => `${intl.formatMessage(messages[key])}: ${value}`) + .join('
'); +} + export default simulateURL; /** diff --git a/src/components/AdvanceAnalyticsV2/data/utils.test.js b/src/components/AdvanceAnalyticsV2/data/utils.test.js index 9ae642a8e9..abaefbb757 100644 --- a/src/components/AdvanceAnalyticsV2/data/utils.test.js +++ b/src/components/AdvanceAnalyticsV2/data/utils.test.js @@ -201,3 +201,18 @@ describe('utils', () => { }); }); }); +import { createIntl } from '@edx/frontend-platform/i18n'; +import { constructChartHoverTemplate } from './utils'; + +describe('constructChartHoverTemplate', () => { + const intl = createIntl({ + locale: 'en', + messages: {}, + }); + + it('should construct a hover template', () => { + const hoverInfo = { skill: 'value1', enrollments: 'value2' }; + const result = constructChartHoverTemplate(intl, hoverInfo); + expect(result).toBe('Skill: value1
Enrollments: value2'); + }); +}); diff --git a/src/components/AdvanceAnalyticsV2/messages.js b/src/components/AdvanceAnalyticsV2/messages.js new file mode 100644 index 0000000000..1fefaa0d48 --- /dev/null +++ b/src/components/AdvanceAnalyticsV2/messages.js @@ -0,0 +1,34 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + skill: { + id: 'advance.analytics.skill.label', + defaultMessage: 'Skill', + }, + enrollments: { + id: 'advance.analytics.enrollments.label', + defaultMessage: 'Enrollments', + }, + completions: { + id: 'advance.analytics.completions.label', + defaultMessage: 'Completions', + }, + date: { + id: 'advance.analytics.date.label', + defaultMessage: 'Date', + }, + course: { + id: 'advance.analytics.course.label', + defaultMessage: 'Course', + }, + subject: { + id: 'advance.analytics.subject.label', + defaultMessage: 'Subject', + }, + learningHours: { + id: 'advance.analytics.learning.hours.label', + defaultMessage: 'Learning Hours', + }, +}); + +export default messages; diff --git a/src/components/AdvanceAnalyticsV2/tabs/Completions.jsx b/src/components/AdvanceAnalyticsV2/tabs/Completions.jsx index ecdfcd2907..5d7a1adac7 100644 --- a/src/components/AdvanceAnalyticsV2/tabs/Completions.jsx +++ b/src/components/AdvanceAnalyticsV2/tabs/Completions.jsx @@ -7,6 +7,7 @@ import AnalyticsTable from './AnalyticsTable'; import ChartWrapper from '../charts/ChartWrapper'; import { useEnterpriseAnalyticsData } from '../data/hooks'; import DownloadCSV from '../DownloadCSV'; +import { constructChartHoverTemplate } from '../data/utils'; const Completions = ({ startDate, endDate, granularity, calculation, enterpriseId, @@ -62,7 +63,10 @@ const Completions = ({ colorMap: chartColorMap, xAxisTitle: '', yAxisTitle: 'Number of Completions', - hovertemplate: 'Date: %{x}
Number of Completions: %{y}', + hovertemplate: constructChartHoverTemplate(intl, { + date: '%{x}', + completions: '%{y}', + }), }} loadingMessage={intl.formatMessage({ id: 'advance.analytics.completions.tab.chart.top.courses.by.completions.loading.message', @@ -110,7 +114,10 @@ const Completions = ({ defaultMessage: 'Number of Completions', description: 'Y-axis title for the top courses by completions chart.', }), - hovertemplate: 'Course: %{x}
Number of Completions: %{y}', + hovertemplate: constructChartHoverTemplate(intl, { + course: '%{x}', + completions: '%{y}', + }), }} loadingMessage={intl.formatMessage({ id: 'advance.analytics.completions.tab.chart.top.10.courses.by.completions.loading.message', @@ -158,7 +165,10 @@ const Completions = ({ defaultMessage: 'Number of Completions', description: 'Y-axis title for the top subjects by completions chart.', }), - hovertemplate: 'Subject: %{x}
Number of Completions: %{y}', + hovertemplate: constructChartHoverTemplate(intl, { + subject: '%{x}', + completions: '%{y}', + }), }} loadingMessage={intl.formatMessage({ id: 'advance.analytics.completions.tab.chart.top.subjects.by.completions.loading.message', diff --git a/src/components/AdvanceAnalyticsV2/tabs/Engagements.jsx b/src/components/AdvanceAnalyticsV2/tabs/Engagements.jsx index f25dfe9d3e..0d18f6f912 100644 --- a/src/components/AdvanceAnalyticsV2/tabs/Engagements.jsx +++ b/src/components/AdvanceAnalyticsV2/tabs/Engagements.jsx @@ -7,6 +7,7 @@ import AnalyticsTable from './AnalyticsTable'; import ChartWrapper from '../charts/ChartWrapper'; import { useEnterpriseAnalyticsData } from '../data/hooks'; import DownloadCSV from '../DownloadCSV'; +import { constructChartHoverTemplate } from '../data/utils'; const Engagements = ({ startDate, endDate, granularity, calculation, enterpriseId, @@ -61,7 +62,10 @@ const Engagements = ({ colorMap: chartColorMap, xAxisTitle: '', yAxisTitle: 'Number of Learning Hours', - hovertemplate: 'Date: %{x}
Learning Hours: %{y}', + hovertemplate: constructChartHoverTemplate(intl, { + date: '%{x}', + learningHours: '%{y}', + }), }} loadingMessage={intl.formatMessage({ id: 'advance.analytics.engagements.tab.chart.learning.hours.over.time.loading.message', @@ -109,7 +113,10 @@ const Engagements = ({ defaultMessage: 'Number of Learning Hours', description: 'Y-axis title for the top 10 courses by learning hours chart.', }), - hovertemplate: 'Course: %{x}
Learning Hours: %{y}', + hovertemplate: constructChartHoverTemplate(intl, { + course: '%{x}', + learningHours: '%{y}', + }), }} loadingMessage={intl.formatMessage({ id: 'advance.analytics.engagements.tab.chart.top.10.courses.by.learning.hours.loading.message', @@ -157,7 +164,10 @@ const Engagements = ({ defaultMessage: 'Number of Learning Hours', description: 'Y-axis title for the top 10 subjects by learning hours chart.', }), - hovertemplate: 'Subject: %{x}
Learning Hours: %{y}', + hovertemplate: constructChartHoverTemplate(intl, { + subject: '%{x}', + learningHours: '%{y}', + }), }} loadingMessage={intl.formatMessage({ id: 'advance.analytics.engagements.tab.chart.top.10.subjects.by.learning.hours.loading.message', diff --git a/src/components/AdvanceAnalyticsV2/tabs/Enrollments.jsx b/src/components/AdvanceAnalyticsV2/tabs/Enrollments.jsx index 332e91144a..b238610ee7 100644 --- a/src/components/AdvanceAnalyticsV2/tabs/Enrollments.jsx +++ b/src/components/AdvanceAnalyticsV2/tabs/Enrollments.jsx @@ -12,6 +12,7 @@ import DownloadCSVButton from '../DownloadCSVButton'; import { modifyDataToIntroduceEnrollTypeCount } from '../data/utils'; dayjs.extend(utc); +import { constructChartHoverTemplate } from '../data/utils'; const Enrollments = ({ startDate, endDate, granularity, calculation, enterpriseId, @@ -101,7 +102,10 @@ const Enrollments = ({ colorMap: chartColorMap, xAxisTitle: '', yAxisTitle: 'Number of Enrollments', - hovertemplate: 'Date: %{x}
Enrolls: %{y}', + hovertemplate: constructChartHoverTemplate(intl, { + date: '%{x}', + enrollments: '%{y}', + }), }} loadingMessage={intl.formatMessage({ id: 'advance.analytics.enrollments.tab.chart.enrollments.over.time.loading.message', @@ -141,7 +145,10 @@ const Enrollments = ({ colorMap: chartColorMap, xAxisTitle: '', yAxisTitle: 'Number of Enrollments', - hovertemplate: 'Course: %{x}
Enrolls: %{y}', + hovertemplate: constructChartHoverTemplate(intl, { + course: '%{x}', + enrollments: '%{y}', + }), }} loadingMessage={intl.formatMessage({ id: 'advance.analytics.enrollments.tab.chart.top.courses.by.enrollments.loading.message', @@ -182,6 +189,10 @@ const Enrollments = ({ xAxisTitle: '', yAxisTitle: 'Number of Enrollments', hovertemplate: 'Subject: %{x}
Enrolls: %{y}', + hovertemplate: constructChartHoverTemplate(intl, { + subject: '%{x}', + enrollments: '%{y}', + }), }} loadingMessage={intl.formatMessage({ id: 'advance.analytics.enrollments.tab.chart.top.subjects.by.enrollments.loading.message', diff --git a/src/components/AdvanceAnalyticsV2/tabs/Skills.jsx b/src/components/AdvanceAnalyticsV2/tabs/Skills.jsx index caf9315337..63fff9c8e9 100644 --- a/src/components/AdvanceAnalyticsV2/tabs/Skills.jsx +++ b/src/components/AdvanceAnalyticsV2/tabs/Skills.jsx @@ -8,6 +8,7 @@ import { import { useEnterpriseAnalyticsData } from '../data/hooks'; import ChartWrapper from '../charts/ChartWrapper'; import DownloadCSV from '../DownloadCSV'; +import { constructChartHoverTemplate } from '../data/utils'; const Skills = ({ startDate, endDate, enterpriseId }) => { const intl = useIntl(); @@ -68,7 +69,11 @@ const Skills = ({ startDate, endDate, enterpriseId }) => { }), markerSizeKey: 'completions', customDataKeys: ['skillName', 'skillType'], - hovertemplate: 'Skill: %{customdata[0]}
Enrolls: %{x}
Completions: %{y}', + hovertemplate: constructChartHoverTemplate(intl, { + skill: '%{customdata[0]}', + enrollments: '%{x}', + completions: '%{y}', + }), }} loadingMessage={intl.formatMessage({ id: 'advance.analytics.skills.tab.chart.top.skills.loading.message', @@ -102,7 +107,10 @@ const Skills = ({ startDate, endDate, enterpriseId }) => { defaultMessage: 'Number of Enrollments', description: 'Y-axis title for the top skills by enrollment chart.', }), - hovertemplate: 'Skill: %{x}
Enrolls: %{y}', + hovertemplate: constructChartHoverTemplate(intl, { + skill: '%{x}', + enrollments: '%{y}', + }), }} loadingMessage={intl.formatMessage({ id: 'advance.analytics.skills.tab.chart.top.skills.by.enrollment.loading.message', @@ -136,7 +144,10 @@ const Skills = ({ startDate, endDate, enterpriseId }) => { defaultMessage: 'Number of Completions', description: 'Y-axis title for the top skills by completion chart.', }), - hovertemplate: 'Skill: %{x}
Completions: %{y}', + hovertemplate: constructChartHoverTemplate(intl, { + skill: '%{x}', + completions: '%{y}', + }), }} loadingMessage={intl.formatMessage({ id: 'advance.analytics.skills.tab.chart.top.skills.by.completion.loading.message', From 566a9e3cedd08b074d2d40aacc35ce96768bc706 Mon Sep 17 00:00:00 2001 From: muhammad-ammar Date: Fri, 13 Sep 2024 12:16:09 +0500 Subject: [PATCH 2/2] feat: translate scatter chart legend in skills tab --- .../charts/ChartWrapper.jsx | 13 +++++++++++- .../charts/ScatterChart.jsx | 7 +++++-- .../charts/ScatterChart.test.jsx | 9 ++++++--- .../AdvanceAnalyticsV2/data/utils.js | 2 +- .../AdvanceAnalyticsV2/data/utils.test.js | 5 ++--- src/components/AdvanceAnalyticsV2/messages.js | 20 +++++++++++++++++++ .../tabs/Completions.test.jsx | 1 + .../tabs/Engagements.test.jsx | 1 + .../AdvanceAnalyticsV2/tabs/Enrollments.jsx | 4 +--- .../tabs/Enrollments.test.jsx | 1 + .../tabs/Leaderboard.test.jsx | 1 + 11 files changed, 51 insertions(+), 13 deletions(-) diff --git a/src/components/AdvanceAnalyticsV2/charts/ChartWrapper.jsx b/src/components/AdvanceAnalyticsV2/charts/ChartWrapper.jsx index 4979239a15..ea00b26b4c 100644 --- a/src/components/AdvanceAnalyticsV2/charts/ChartWrapper.jsx +++ b/src/components/AdvanceAnalyticsV2/charts/ChartWrapper.jsx @@ -40,7 +40,18 @@ ChartWrapper.propTypes = { isFetching: PropTypes.bool.isRequired, isError: PropTypes.bool.isRequired, chartType: PropTypes.oneOf(['ScatterChart', 'LineChart', 'BarChart']).isRequired, - chartProps: PropTypes.shape({ data: PropTypes.shape({}) }).isRequired, + chartProps: PropTypes.shape({ + data: PropTypes.arrayOf(PropTypes.shape({})).isRequired, + xKey: PropTypes.string.isRequired, + yKey: PropTypes.string.isRequired, + colorKey: PropTypes.string.isRequired, + colorMap: PropTypes.objectOf(PropTypes.string).isRequired, + hovertemplate: PropTypes.string.isRequired, + xAxisTitle: PropTypes.string, + yAxisTitle: PropTypes.string, + markerSizeKey: PropTypes.string, + customDataKeys: PropTypes.arrayOf(PropTypes.string), + }).isRequired, loadingMessage: PropTypes.string.isRequired, }; diff --git a/src/components/AdvanceAnalyticsV2/charts/ScatterChart.jsx b/src/components/AdvanceAnalyticsV2/charts/ScatterChart.jsx index 3cd27aba19..d26e53b2b5 100644 --- a/src/components/AdvanceAnalyticsV2/charts/ScatterChart.jsx +++ b/src/components/AdvanceAnalyticsV2/charts/ScatterChart.jsx @@ -1,6 +1,8 @@ import React, { useMemo } from 'react'; import Plot from 'react-plotly.js'; import PropTypes from 'prop-types'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import messages from '../messages'; /** * ScatterChart component renders a scatter chart using Plotly.js. @@ -21,6 +23,7 @@ import PropTypes from 'prop-types'; const ScatterChart = ({ data, xKey, yKey, colorKey, colorMap, hovertemplate, xAxisTitle, yAxisTitle, markerSizeKey, customDataKeys, }) => { + const intl = useIntl(); const categories = Object.keys(colorMap); const traces = useMemo(() => categories.map(category => { @@ -30,7 +33,7 @@ const ScatterChart = ({ y: filteredData.map(item => item[yKey]), type: 'scatter', mode: 'markers', - name: category, + name: messages[category] ? intl.formatMessage(messages[category]) : category, marker: { color: colorMap[category], size: filteredData.map(item => item[markerSizeKey] * 0.015).map(size => (size < 5 ? size + 6 : size)), @@ -38,7 +41,7 @@ const ScatterChart = ({ customdata: customDataKeys.length ? filteredData.map(item => customDataKeys.map(key => item[key])) : [], hovertemplate, }; - }), [data, xKey, yKey, colorKey, colorMap, hovertemplate, categories, markerSizeKey, customDataKeys]); + }), [data, xKey, yKey, colorKey, colorMap, hovertemplate, categories, markerSizeKey, customDataKeys, intl]); const layout = { margin: { t: 0 }, diff --git a/src/components/AdvanceAnalyticsV2/charts/ScatterChart.test.jsx b/src/components/AdvanceAnalyticsV2/charts/ScatterChart.test.jsx index f728425027..39cc252232 100644 --- a/src/components/AdvanceAnalyticsV2/charts/ScatterChart.test.jsx +++ b/src/components/AdvanceAnalyticsV2/charts/ScatterChart.test.jsx @@ -1,6 +1,7 @@ import React from 'react'; -import { shallow } from 'enzyme'; +import { mount } from 'enzyme'; import Plot from 'react-plotly.js'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; import ScatterChart from './ScatterChart'; describe('ScatterChart', () => { @@ -28,8 +29,10 @@ describe('ScatterChart', () => { }; it('renders correctly', () => { - const wrapper = shallow( - , + const wrapper = mount( + + , + , ); const plotComponent = wrapper.find(Plot); const traces = plotComponent.prop('data'); diff --git a/src/components/AdvanceAnalyticsV2/data/utils.js b/src/components/AdvanceAnalyticsV2/data/utils.js index 5c68827b64..a17b9bd7cf 100644 --- a/src/components/AdvanceAnalyticsV2/data/utils.js +++ b/src/components/AdvanceAnalyticsV2/data/utils.js @@ -3,10 +3,10 @@ import { sum } from 'lodash'; import utc from 'dayjs/plugin/utc'; import quarterOfYear from 'dayjs/plugin/quarterOfYear'; import { CHART_TYPES, CALCULATION } from './constants'; +import messages from '../messages'; dayjs.extend(utc); dayjs.extend(quarterOfYear); -import messages from '../messages'; const simulateURL = (activeTab, chartType) => { if (!Object.values(CHART_TYPES).includes(chartType)) { diff --git a/src/components/AdvanceAnalyticsV2/data/utils.test.js b/src/components/AdvanceAnalyticsV2/data/utils.test.js index abaefbb757..b0f6713f28 100644 --- a/src/components/AdvanceAnalyticsV2/data/utils.test.js +++ b/src/components/AdvanceAnalyticsV2/data/utils.test.js @@ -1,6 +1,7 @@ // Jest test for utils.js -import { applyCalculation, applyGranularity } from './utils'; +import { createIntl } from '@edx/frontend-platform/i18n'; +import { applyCalculation, applyGranularity, constructChartHoverTemplate } from './utils'; import { CALCULATION, GRANULARITY } from './constants'; describe('utils', () => { @@ -201,8 +202,6 @@ describe('utils', () => { }); }); }); -import { createIntl } from '@edx/frontend-platform/i18n'; -import { constructChartHoverTemplate } from './utils'; describe('constructChartHoverTemplate', () => { const intl = createIntl({ diff --git a/src/components/AdvanceAnalyticsV2/messages.js b/src/components/AdvanceAnalyticsV2/messages.js index 1fefaa0d48..b49ee50b1c 100644 --- a/src/components/AdvanceAnalyticsV2/messages.js +++ b/src/components/AdvanceAnalyticsV2/messages.js @@ -29,6 +29,26 @@ const messages = defineMessages({ id: 'advance.analytics.learning.hours.label', defaultMessage: 'Learning Hours', }, + 'Common Skill': { + id: 'advance.analytics.common.skill.label', + defaultMessage: 'Common Skill', + }, + 'Specialized Skill': { + id: 'advance.analytics.specialized.skill.label', + defaultMessage: 'Specialized Skill', + }, + 'Hard Skill': { + id: 'advance.analytics.hard.skill.label', + defaultMessage: 'Hard Skill', + }, + 'Soft Skill': { + id: 'advance.analytics.soft.skill.label', + defaultMessage: 'Soft Skill', + }, + Certification: { + id: 'advance.analytics.certification.label', + defaultMessage: 'Certification', + }, }); export default messages; diff --git a/src/components/AdvanceAnalyticsV2/tabs/Completions.test.jsx b/src/components/AdvanceAnalyticsV2/tabs/Completions.test.jsx index 8cbf6037e7..428969b949 100644 --- a/src/components/AdvanceAnalyticsV2/tabs/Completions.test.jsx +++ b/src/components/AdvanceAnalyticsV2/tabs/Completions.test.jsx @@ -1,3 +1,4 @@ +/* eslint-disable import/no-extraneous-dependencies */ import { render, screen, waitFor, within, } from '@testing-library/react'; diff --git a/src/components/AdvanceAnalyticsV2/tabs/Engagements.test.jsx b/src/components/AdvanceAnalyticsV2/tabs/Engagements.test.jsx index 42327c1e38..a8f0b33d1f 100644 --- a/src/components/AdvanceAnalyticsV2/tabs/Engagements.test.jsx +++ b/src/components/AdvanceAnalyticsV2/tabs/Engagements.test.jsx @@ -1,3 +1,4 @@ +/* eslint-disable import/no-extraneous-dependencies */ import { render, screen, waitFor, within, } from '@testing-library/react'; diff --git a/src/components/AdvanceAnalyticsV2/tabs/Enrollments.jsx b/src/components/AdvanceAnalyticsV2/tabs/Enrollments.jsx index b238610ee7..357d083d2e 100644 --- a/src/components/AdvanceAnalyticsV2/tabs/Enrollments.jsx +++ b/src/components/AdvanceAnalyticsV2/tabs/Enrollments.jsx @@ -9,10 +9,9 @@ import AnalyticsTable from './AnalyticsTable'; import ChartWrapper from '../charts/ChartWrapper'; import { useEnterpriseEnrollmentsData } from '../data/hooks'; import DownloadCSVButton from '../DownloadCSVButton'; -import { modifyDataToIntroduceEnrollTypeCount } from '../data/utils'; +import { modifyDataToIntroduceEnrollTypeCount, constructChartHoverTemplate } from '../data/utils'; dayjs.extend(utc); -import { constructChartHoverTemplate } from '../data/utils'; const Enrollments = ({ startDate, endDate, granularity, calculation, enterpriseId, @@ -188,7 +187,6 @@ const Enrollments = ({ colorMap: chartColorMap, xAxisTitle: '', yAxisTitle: 'Number of Enrollments', - hovertemplate: 'Subject: %{x}
Enrolls: %{y}', hovertemplate: constructChartHoverTemplate(intl, { subject: '%{x}', enrollments: '%{y}', diff --git a/src/components/AdvanceAnalyticsV2/tabs/Enrollments.test.jsx b/src/components/AdvanceAnalyticsV2/tabs/Enrollments.test.jsx index b37aecce61..2cd633244a 100644 --- a/src/components/AdvanceAnalyticsV2/tabs/Enrollments.test.jsx +++ b/src/components/AdvanceAnalyticsV2/tabs/Enrollments.test.jsx @@ -1,3 +1,4 @@ +/* eslint-disable import/no-extraneous-dependencies */ import { render, screen, waitFor, within, } from '@testing-library/react'; diff --git a/src/components/AdvanceAnalyticsV2/tabs/Leaderboard.test.jsx b/src/components/AdvanceAnalyticsV2/tabs/Leaderboard.test.jsx index 93520b6031..7af2e74066 100644 --- a/src/components/AdvanceAnalyticsV2/tabs/Leaderboard.test.jsx +++ b/src/components/AdvanceAnalyticsV2/tabs/Leaderboard.test.jsx @@ -1,3 +1,4 @@ +/* eslint-disable import/no-extraneous-dependencies */ import { render, screen, waitFor, within, } from '@testing-library/react';