Browse Source

ref(replays): fix aria label parsing (#58663)

before:
<img width="505" alt="SCR-20231023-mjvk"
src="https://github.com/getsentry/sentry/assets/56095982/4a987cdc-5b36-4527-a9a4-8053f6c4b4ae">

after:
<img width="356" alt="SCR-20231023-ofet"
src="https://github.com/getsentry/sentry/assets/56095982/aa4a9f66-d8f5-45d3-98d5-0f91a75664bb">
Michelle Zhang 1 year ago
parent
commit
4696469ad8

+ 1 - 1
static/app/views/replays/deadRageClick/constructSelector.spec.tsx

@@ -1,4 +1,4 @@
-import {constructSelector} from 'sentry/views/replays/deadRageClick/selectorTable';
+import {constructSelector} from 'sentry/views/replays/detail/utils';
 
 describe('constructSelector', () => {
   it.each([

+ 21 - 0
static/app/views/replays/deadRageClick/getAriaLabel.spec.tsx

@@ -0,0 +1,21 @@
+import {getAriaLabel} from 'sentry/views/replays/detail/utils';
+
+describe('getAriaLabel', () => {
+  it.each([
+    {
+      element:
+        'button#ID1.classA[role="button"][aria="View More"][data-test-id="button-test"][alt="view more"][title="cool title"]',
+      ariaLabel: 'View More',
+    },
+    {
+      element:
+        'button#ID1.classA[role="button"][data-test-id="button-test"][alt="view more"][title="cool title"]',
+      ariaLabel: '',
+    },
+  ])(
+    'should construct the correct aria label for each element in the list',
+    ({element, ariaLabel}) => {
+      expect(getAriaLabel(element)).toStrictEqual(ariaLabel);
+    }
+  );
+});

+ 2 - 44
static/app/views/replays/deadRageClick/selectorTable.tsx

@@ -19,56 +19,14 @@ import {useLocation} from 'sentry/utils/useLocation';
 import useOrganization from 'sentry/utils/useOrganization';
 import useProjects from 'sentry/utils/useProjects';
 import {normalizeUrl} from 'sentry/utils/withDomainRequired';
-import {DeadRageSelectorItem, ReplayClickElement} from 'sentry/views/replays/types';
+import {constructSelector, getAriaLabel} from 'sentry/views/replays/detail/utils';
+import {DeadRageSelectorItem} from 'sentry/views/replays/types';
 import {WiderHovercard} from 'sentry/views/starfish/components/tableCells/spanDescriptionCell';
 
 export interface UrlState {
   widths: string[];
 }
 
-export function getAriaLabel(str: string) {
-  const pre = str.split('aria="')[1];
-  if (!pre) {
-    return '';
-  }
-  return pre.substring(0, pre.lastIndexOf('"]'));
-}
-
-function trimAttribute(elementAttribute, fullAlltribute) {
-  return elementAttribute === '' ? '' : fullAlltribute;
-}
-
-export function constructSelector(element: ReplayClickElement) {
-  const fullAlt = '[alt="' + element.alt + '"]';
-  const alt = trimAttribute(element.alt, fullAlt);
-
-  const fullAriaLabel = '[aria="' + element.aria_label + '"]';
-  const ariaLabel = trimAttribute(element.aria_label, fullAriaLabel);
-
-  const trimClass = element.class.filter(e => e !== '');
-  const classWithPeriod = trimClass.join('.');
-  const classNoPeriod = classWithPeriod.replace('.', '');
-  const classes = trimAttribute(classNoPeriod, '.' + classWithPeriod);
-
-  const id = trimAttribute(element.id, '#' + element.id);
-
-  const fullRole = '[role="' + element.role + '"]';
-  const role = trimAttribute(element.role, fullRole);
-
-  const tag = element.tag;
-
-  const fullTestId = '[data-test-id="' + element.testid + '"]';
-  const testId = trimAttribute(element.testid, fullTestId);
-
-  const fullTitle = '[title="' + element.title + '"]';
-  const title = trimAttribute(element.title, fullTitle);
-
-  const fullSelector =
-    tag + id + classes + fullRole + fullAriaLabel + fullTestId + fullAlt + fullTitle;
-  const selector = tag + id + classes + role + ariaLabel + testId + alt + title;
-  return {fullSelector, selector};
-}
-
 export function hydratedSelectorData(data, clickType?): DeadRageSelectorItem[] {
   return data.map(d => ({
     ...(clickType

+ 46 - 0
static/app/views/replays/detail/utils.tsx

@@ -1,3 +1,5 @@
+import {ReplayClickElement} from 'sentry/views/replays/types';
+
 export function filterItems<I extends object, K extends string>({
   filterFns,
   filterVals,
@@ -24,3 +26,47 @@ export function filterItems<I extends object, K extends string>({
 export function operationName(op: string) {
   return op.split('.')?.[1] ?? op;
 }
+
+export function getAriaLabel(str: string) {
+  const matches = str.match(/\[aria=(.*?)\]/g);
+  if (!matches) {
+    return '';
+  }
+  const pre = matches[0];
+  return matches[0].substring(pre.indexOf('aria="') + 6, pre.lastIndexOf('"]'));
+}
+
+function trimAttribute(elementAttribute, fullAlltribute) {
+  return elementAttribute === '' ? '' : fullAlltribute;
+}
+
+export function constructSelector(element: ReplayClickElement) {
+  const fullAlt = '[alt="' + element.alt + '"]';
+  const alt = trimAttribute(element.alt, fullAlt);
+
+  const fullAriaLabel = '[aria="' + element.aria_label + '"]';
+  const ariaLabel = trimAttribute(element.aria_label, fullAriaLabel);
+
+  const trimClass = element.class.filter(e => e !== '');
+  const classWithPeriod = trimClass.join('.');
+  const classNoPeriod = classWithPeriod.replace('.', '');
+  const classes = trimAttribute(classNoPeriod, '.' + classWithPeriod);
+
+  const id = trimAttribute(element.id, '#' + element.id);
+
+  const fullRole = '[role="' + element.role + '"]';
+  const role = trimAttribute(element.role, fullRole);
+
+  const tag = element.tag;
+
+  const fullTestId = '[data-test-id="' + element.testid + '"]';
+  const testId = trimAttribute(element.testid, fullTestId);
+
+  const fullTitle = '[title="' + element.title + '"]';
+  const title = trimAttribute(element.title, fullTitle);
+
+  const fullSelector =
+    tag + id + classes + fullRole + fullAriaLabel + fullTestId + fullAlt + fullTitle;
+  const selector = tag + id + classes + role + ariaLabel + testId + alt + title;
+  return {fullSelector, selector};
+}