From 75fb80cb7d55d18a850d4b521de2e020cd95b25b Mon Sep 17 00:00:00 2001
From: Mikhail Malcev <47668236+Mishnya@users.noreply.github.com>
Date: Mon, 13 Nov 2023 13:20:14 +0300
Subject: [PATCH] feat: add id converter for getXpath (#1117)
---
src/components/utils/__tests__/xpath.test.tsx | 46 +++++++++++++++++++
src/components/utils/xpath.ts | 11 ++++-
2 files changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/components/utils/__tests__/xpath.test.tsx b/src/components/utils/__tests__/xpath.test.tsx
index 4eeb386967..d17b2656f0 100644
--- a/src/components/utils/__tests__/xpath.test.tsx
+++ b/src/components/utils/__tests__/xpath.test.tsx
@@ -313,5 +313,51 @@ describe('getXpath', () => {
expect(xpath).toBe(rootBuilder.append({className: 'class__div'}).xpath);
expect(hash).toMatchInlineSnapshot(`"bf5138ce0f335973b588b4c3029e1335"`);
});
+
+ it('should remove id if it was converted to undefined', () => {
+ const onClick = jest.fn();
+ render(
+
,
+ );
+ screen.getByText(clickText).click();
+
+ const {xpath, hash} = getXpath(onClick.mock.calls[0][0], {
+ idConverter: (id) => (id.startsWith('remove') ? undefined : id),
+ });
+ expect(xpath).toBe(
+ rootBuilder.append().append({id: 'keep-this'}).append({className: 'target class-3'})
+ .xpath,
+ );
+ expect(hash).toMatchInlineSnapshot(`"21df5cf9017ae106f30a9a6608a9cb4a"`);
+ });
+
+ it('should convert some ids', () => {
+ const onClick = jest.fn();
+ render(
+ ,
+ );
+ screen.getByText(clickText).click();
+
+ const {xpath, hash} = getXpath(onClick.mock.calls[0][0], {
+ idConverter: (id) => id.replace('convert', 'keep'),
+ });
+ expect(xpath).toBe(
+ rootBuilder.append({id: 'keep-too'}).append({id: 'keep-this'}).append({id: 'keep'})
+ .xpath,
+ );
+ expect(hash).toMatchInlineSnapshot(`"2ac575742aa22271a17b4e1efb375330"`);
+ });
});
});
diff --git a/src/components/utils/xpath.ts b/src/components/utils/xpath.ts
index 2bc5868436..4b8ff4c158 100644
--- a/src/components/utils/xpath.ts
+++ b/src/components/utils/xpath.ts
@@ -12,9 +12,13 @@ export type XpathClassConverter = (
strClass: string,
) => ElementClass | undefined;
+export type XpathIdConverter = (id: string) => string | undefined;
+
export interface XpathOptions {
/** Function for converting and filtering classes */
classConverter?: XpathClassConverter;
+ /** Function for converting and filtering ids */
+ idConverter?: XpathIdConverter;
/** Flag for managing replaces from tag[@class='...'] to tag[@id='...'] if id is exist */
withoutId?: boolean;
}
@@ -39,8 +43,10 @@ function getXpathByNode(node: Node | null, options: InternalXpathOptions): strin
const tag = node.tagName.toLowerCase();
let token = `/${tag}`;
- if (node.id && !options.withoutId) {
- token += `[@id='${node.id}']`;
+
+ const convertedId = node.id && !options.withoutId ? options.idConverter(node.id) : undefined;
+ if (convertedId) {
+ token += `[@id='${convertedId}']`;
} else {
const classes: string[] = [];
node.classList.forEach((className) => {
@@ -59,6 +65,7 @@ function getXpathByNode(node: Node | null, options: InternalXpathOptions): strin
const defaultXpathOptions: InternalXpathOptions = {
classConverter: (arg) => arg,
+ idConverter: (arg) => arg,
withoutId: false,
};