Skip to content

Commit

Permalink
feat: Allow to specify a root class name as a label identifier in ana… (
Browse files Browse the repository at this point in the history
#97)

Co-authored-by: Francesco Longo <[email protected]>
  • Loading branch information
fralongo and Francesco Longo authored Sep 16, 2024
1 parent d5a6726 commit ba1e797
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 14 deletions.
1 change: 1 addition & 0 deletions src/internal/analytics-metadata/__tests__/components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export const ComponentThree = () => (
position: '2',
columnLabel: { selector: '.invalid-selector', root: 'self' },
anotherLabel: { root: 'self' },
yetAnotherLabel: { rootSelector: '.root-class-name' },
},
},
})}
Expand Down
49 changes: 45 additions & 4 deletions src/internal/analytics-metadata/__tests__/dom-utils.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import React from 'react';
import { render } from '@testing-library/react';
import { activateAnalyticsMetadata, getAnalyticsMetadataAttribute, METADATA_ATTRIBUTE } from '../attributes';
import { findLogicalParent, isNodeComponent, findComponentUp } from '../dom-utils';
import { findLogicalParent, isNodeComponent, findComponentUp, findSelectorUp } from '../dom-utils';

beforeAll(() => {
activateAnalyticsMetadata(true);
Expand All @@ -18,7 +18,7 @@ describe('findLogicalParent', () => {
</div>
);
const child = container.querySelector('#child');
expect(findLogicalParent(child as HTMLElement)?.id).toEqual('parent');
expect(findLogicalParent(child as HTMLElement)!.id).toEqual('parent');
});
test('returns null when child does not exist', () => {
const { container } = render(
Expand Down Expand Up @@ -88,7 +88,7 @@ describe('findComponentUp', () => {
<div id="target-element"></div>
</div>
);
expect(findComponentUp(container.querySelector('#target-element'))?.id).toBe('component-element');
expect(findComponentUp(container.querySelector('#target-element'))!.id).toBe('component-element');
});
test('returns parent component element with portals', () => {
const { container } = render(
Expand All @@ -101,7 +101,7 @@ describe('findComponentUp', () => {
</div>
</div>
);
expect(findComponentUp(container.querySelector('#target-element'))?.id).toBe('component-element');
expect(findComponentUp(container.querySelector('#target-element'))!.id).toBe('component-element');
});
test('returns null when element has no parent component', () => {
const { container } = render(
Expand All @@ -112,3 +112,44 @@ describe('findComponentUp', () => {
expect(findComponentUp(container.querySelector('#target-element'))).toBeNull();
});
});

describe('findSelectorUp', () => {
test('returns null when the node is null or the className is invalid', () => {
expect(findSelectorUp(null, 'abcd')).toBeNull();
const { container } = render(
<div id="root-element">
<div id="target-element"></div>
</div>
);
expect(findSelectorUp(container.querySelector('#target-element'), '.dummy')).toBeNull();
});
test('returns root element', () => {
const { container } = render(
<div id="root-element" className="test-class">
<div id="target-element"></div>
</div>
);
expect(findSelectorUp(container.querySelector('#target-element'), '.test-class')!.id).toBe('root-element');
});
test('returns parent component element with portals', () => {
const { container } = render(
<div>
<div id="root-element" className="test-class">
<div id=":rr5:"></div>
</div>
<div data-awsui-referrer-id=":rr5:">
<div id="target-element"></div>
</div>
</div>
);
expect(findSelectorUp(container.querySelector('#target-element'), '.test-class')!.id).toBe('root-element');
});
test('returns null when element has no parent element with className', () => {
const { container } = render(
<div>
<div id="target-element"></div>
</div>
);
expect(findSelectorUp(container.querySelector('#target-element'), '.test-class')).toBeNull();
});
});
37 changes: 37 additions & 0 deletions src/internal/analytics-metadata/__tests__/labels-utils.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,43 @@ describe('processLabel', () => {
expect(processLabel(target, { selector: '.outer-class', root: 'body' })).toEqual('label outside of the component');
});

test('respects the rootSelector property', () => {
const { container } = render(
<div className="root-class">
<div className="label-class">outer label</div>
<div id="target">
<div className="label-class">inner label</div>
</div>
</div>
);
const target = container.querySelector('#target') as HTMLElement;
expect(processLabel(target, { selector: '.label-class', rootSelector: '.root-class' })).toEqual('outer label');
});
test('rootSelector prevails over root property', () => {
const { container } = render(
<>
<div className="root-class">
<div className="label-class">root class label</div>
<div {...getAnalyticsMetadataAttribute({ component: { name: 'ComponentName' } })}>
<div className="label-class">component label</div>
<div id="target">
<div className="label-class">inner label</div>
</div>
</div>
</div>
<div className="outer-class">label outside of the component</div>
</>
);
const target = container.querySelector('#target') as HTMLElement;
expect(processLabel(target, { selector: '.label-class', root: 'self', rootSelector: '.root-class' })).toEqual(
'root class label'
);
expect(processLabel(target, { selector: '.label-class', root: 'component', rootSelector: '.root-class' })).toEqual(
'root class label'
);
expect(processLabel(target, { selector: '.outer-class', root: 'body', rootSelector: '.root-class' })).toEqual('');
});

test('forwards the label resolution with data-awsui-analytics-label', () => {
const { container } = render(
<div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ describe('getRawAnalyticsMetadata', () => {
anotherLabel: {
root: 'self',
},
yetAnotherLabel: {
rootSelector: '.root-class-name',
},
},
},
},
Expand All @@ -74,6 +77,7 @@ describe('getRawAnalyticsMetadata', () => {
'.component-label',
'.component-label',
'.invalid-selector',
'.root-class-name',
],
});
});
Expand Down
1 change: 1 addition & 0 deletions src/internal/analytics-metadata/__tests__/utils.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ describe('getGeneratedAnalyticsMetadata', () => {
position: '2',
columnLabel: '',
anotherLabel: 'sub labelanother text content to ignorecontentcomponent labelevent label',
yetAnotherLabel: '',
},
},
},
Expand Down
8 changes: 8 additions & 0 deletions src/internal/analytics-metadata/dom-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,11 @@ export const isNodeComponent = (node: HTMLElement): boolean => {
return false;
}
};

export function findSelectorUp(node: HTMLElement | null, selector: string): HTMLElement | null {
let current: HTMLElement | null = node;
while (current && current.tagName !== 'body' && !current.matches(selector)) {
current = findLogicalParent(current);
}
return current && current.tagName !== 'body' ? current : null;
}
1 change: 1 addition & 0 deletions src/internal/analytics-metadata/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ interface GeneratedAnalyticsMetadataComponentContext {
export interface LabelIdentifier {
selector?: string | Array<string>;
root?: 'component' | 'self' | 'body';
rootSelector?: string;
}

export interface GeneratedAnalyticsMetadataFragment extends Omit<Partial<GeneratedAnalyticsMetadata>, 'detail'> {
Expand Down
22 changes: 18 additions & 4 deletions src/internal/analytics-metadata/labels-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

import { LABEL_DATA_ATTRIBUTE } from './attributes';
import { findComponentUp } from './dom-utils';
import { findSelectorUp, findComponentUp } from './dom-utils';
import { LabelIdentifier } from './interfaces';

export const processLabel = (node: HTMLElement | null, labelIdentifier: string | LabelIdentifier | null): string => {
Expand All @@ -13,13 +13,23 @@ export const processLabel = (node: HTMLElement | null, labelIdentifier: string |
const selector = formattedLabelIdentifier.selector;
if (Array.isArray(selector)) {
for (const labelSelector of selector) {
const label = processSingleLabel(node, labelSelector, formattedLabelIdentifier.root);
const label = processSingleLabel(
node,
labelSelector,
formattedLabelIdentifier.root,
formattedLabelIdentifier.rootSelector
);
if (label) {
return label;
}
}
}
return processSingleLabel(node, selector as string, formattedLabelIdentifier.root);
return processSingleLabel(
node,
selector as string,
formattedLabelIdentifier.root,
formattedLabelIdentifier.rootSelector
);
};

const formatLabelIdentifier = (labelIdentifier: string | LabelIdentifier): LabelIdentifier => {
Expand All @@ -32,11 +42,15 @@ const formatLabelIdentifier = (labelIdentifier: string | LabelIdentifier): Label
const processSingleLabel = (
node: HTMLElement | null,
labelSelector: string,
root: LabelIdentifier['root'] = 'self'
root: LabelIdentifier['root'] = 'self',
rootSelector?: string
): string => {
if (!node) {
return '';
}
if (rootSelector) {
return processSingleLabel(findSelectorUp(node, rootSelector), labelSelector);
}
if (root === 'component') {
return processSingleLabel(findComponentUp(node), labelSelector);
}
Expand Down
19 changes: 13 additions & 6 deletions src/internal/analytics-metadata/testing-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,20 @@ const getLabelSelectors = (localMetadata: any): Array<string> => {
};

const getLabelSelectorsFromLabelIdentifier = (label: string | LabelIdentifier): Array<string> => {
let labels: Array<string> = [];
if (typeof label === 'string') {
return [label];
} else if (label.selector) {
if (typeof label.selector === 'string') {
return [label.selector];
labels.push(label);
} else {
if (label.selector) {
if (typeof label.selector === 'string') {
labels.push(label.selector);
} else {
labels = [...label.selector];
}
}
if (label.rootSelector) {
labels.push(label.rootSelector);
}
return label.selector;
}
return [];
return labels;
};

0 comments on commit ba1e797

Please sign in to comment.