diff --git a/packages/codemod/transformations/core/v2-to-v3/__tests__/text-field-component-migration.test.ts b/packages/codemod/transformations/core/v2-to-v3/__tests__/text-field-component-migration.test.ts new file mode 100644 index 0000000000..9f7c098c4b --- /dev/null +++ b/packages/codemod/transformations/core/v2-to-v3/__tests__/text-field-component-migration.test.ts @@ -0,0 +1,319 @@ +import transform from "../text-field-component-migration"; +import { defineInlineTest } from "jscodeshift/src/testUtils"; + +function prependImport(source: string): string { + return ` + import { TextField } from "monday-ui-react-core"; + ${source} + `; +} + +describe("TextField component migration", () => { + describe("dataTestId to data-testId", () => { + defineInlineTest( + transform, + {}, + prependImport(``), + prependImport(``), + "should update 'dataTestId' to 'data-testid'" + ); + + defineInlineTest( + transform, + {}, + prependImport(`
`), + prependImport(`
`), + "should update 'dataTestId' to 'data-testid' in a nested structure" + ); + + defineInlineTest( + transform, + {}, + prependImport(``), + prependImport(``), + "should update 'dataTestId' to 'data-testid' while maintaining other props" + ); + + defineInlineTest( + transform, + {}, + prependImport( + ` + <> + + + ` + ), + prependImport(` + <> + + + `), + "should handle multiple instances of TextField each with 'dataTestId'" + ); + + defineInlineTest( + transform, + {}, + prependImport(``), + prependImport(``), + "should not change when when both 'dataTestId' and 'data-testid' props exist with different literal values" + ); + + defineInlineTest( + transform, + {}, + prependImport(``), + prependImport(``), + "should remove 'dataTestId' when both 'dataTestId' and 'data-testid' props exist and have same values" + ); + + defineInlineTest( + transform, + {}, + prependImport(``), + prependImport(``), + "should not change when when both 'dataTestId' and 'data-testid' props exist and have different complex values" + ); + + defineInlineTest( + transform, + {}, + prependImport(``), + prependImport(``), + "should remove 'dataTestId' when when both 'dataTestId' and 'data-testid' props exist with same literal values while one is inside an expression" + ); + + defineInlineTest( + transform, + {}, + ``, + ``, + "should not change when no import even if 'dataTestId' prop exists" + ); + + defineInlineTest( + transform, + {}, + prependImport(``), + prependImport(``), + "should not affect other components with 'dataTestId'" + ); + + defineInlineTest( + transform, + {}, + ` + import { TextField } from "other-library"; + + `, + ` + import { TextField } from "other-library"; + + `, + "should not change when 'TextField' is not imported from vibe" + ); + + defineInlineTest( + transform, + {}, + ` + import { OtherComponent as TextField } from "other-library"; + + `, + ` + import { OtherComponent as TextField } from "other-library"; + + `, + "should not change when 'TextField' is an alias for another component that is not from vibe" + ); + + defineInlineTest( + transform, + {}, + ` + import { OtherComponent as TextField } from "monday-ui-react-core"; + + `, + ` + import { OtherComponent as TextField } from "monday-ui-react-core"; + + `, + "should not change when 'TextField' is an alias for another component from vibe" + ); + + defineInlineTest( + transform, + {}, + ` + import { TextField as VibeComponent } from "monday-ui-react-core"; + + `, + ` + import { TextField as VibeComponent } from "monday-ui-react-core"; + + `, + "should change when 'TextField' is imported with alias from vibe" + ); + }); + + describe('remove "withReadOnlyStyle" prop', () => { + defineInlineTest( + transform, + {}, + prependImport(``), + prependImport(``), + "should remove 'withReadOnlyStyle' prop" + ); + + defineInlineTest( + transform, + {}, + prependImport(``), + prependImport(``), + "should remove 'withReadOnlyStyle' prop if given with a value" + ); + + defineInlineTest( + transform, + {}, + prependImport( + ` + <> + + + ` + ), + prependImport(` + <> + + + `), + "should handle multiple instances of TextField each with 'withReadOnlyStyle'" + ); + + defineInlineTest( + transform, + {}, + ``, + ``, + "should not change when no import even if 'withReadOnlyStyle' prop exists" + ); + + defineInlineTest( + transform, + {}, + prependImport(``), + prependImport(``), + "should not affect other components with 'withReadOnlyStyle'" + ); + + defineInlineTest( + transform, + {}, + ` + import { TextField } from "other-library"; + + `, + ` + import { TextField } from "other-library"; + + `, + "should not change when 'TextField' is not imported from vibe" + ); + + defineInlineTest( + transform, + {}, + ` + import { OtherComponent as TextField } from "other-library"; + + `, + ` + import { OtherComponent as TextField } from "other-library"; + + `, + "should not change when 'TextField' is an alias for another component that is not from vibe" + ); + + defineInlineTest( + transform, + {}, + ` + import { OtherComponent as TextField } from "monday-ui-react-core"; + + `, + ` + import { OtherComponent as TextField } from "monday-ui-react-core"; + + `, + "should not change when 'TextField' is an alias for another component from vibe" + ); + + defineInlineTest( + transform, + {}, + ` + import { TextField as VibeComponent } from "monday-ui-react-core"; + + `, + ` + import { TextField as VibeComponent } from "monday-ui-react-core"; + + `, + "should change when 'TextField' is imported with alias from vibe" + ); + }); + + describe('remove "requiredAsterisk" if "required" prop is given', () => { + defineInlineTest( + transform, + {}, + prependImport(``), + prependImport(``), + "should remove 'requiredAsterisk' prop when 'required' prop exists" + ); + + defineInlineTest( + transform, + {}, + prependImport(``), + prependImport(``), + "should not remove 'requiredAsterisk' when 'required' prop does not exist" + ); + + defineInlineTest( + transform, + {}, + prependImport(` + <> + + + + `), + prependImport(` + <> + + + + `), + "should not remove 'requiredAsterisk' when 'required' prop is not present in the same component" + ); + + defineInlineTest( + transform, + {}, + prependImport(``), + prependImport(``), + "should remove 'requiredAsterisk' when 'required' exists with multiple other props" + ); + + defineInlineTest( + transform, + {}, + ``, + ``, + "should not remove 'requiredAsterisk' when no import even if 'required' prop exists" + ); + }); +}); diff --git a/packages/codemod/transformations/core/v2-to-v3/text-field-component-migration.ts b/packages/codemod/transformations/core/v2-to-v3/text-field-component-migration.ts new file mode 100644 index 0000000000..74aa0204e5 --- /dev/null +++ b/packages/codemod/transformations/core/v2-to-v3/text-field-component-migration.ts @@ -0,0 +1,34 @@ +import { + wrap, + getCoreImportsForFile, + getComponentNameOrAliasFromImports, + findComponentElements, + migratePropsNames, + removeProp, + isPropExists +} from "../../../src/utils"; +import { TransformationContext } from "../../../types"; + +/** + * 1. Change the 'dataTestId' prop to 'data-testid' + * 2. Remove 'withReadOnlyStyle' prop + * 3. Remove 'requiredAsterisk' prop if 'required' prop exists + */ +function transform({ j, root, filePath }: TransformationContext) { + const imports = getCoreImportsForFile(root); + const componentName = getComponentNameOrAliasFromImports(j, imports, "TextField"); + if (!componentName) return; + + const elements = findComponentElements(root, componentName); + if (!elements.length) return; + + elements.forEach(elementPath => { + migratePropsNames(j, elementPath, filePath, componentName, { dataTestId: "data-testid" }); + removeProp(j, elementPath, "withReadOnlyStyle"); + if (isPropExists(j, elementPath, "required")) { + removeProp(j, elementPath, "requiredAsterisk"); + } + }); +} + +export default wrap(transform); diff --git a/packages/core/docs/vibe-3-changelog.md b/packages/core/docs/vibe-3-changelog.md index cdf9ce4e08..df7a71930a 100644 --- a/packages/core/docs/vibe-3-changelog.md +++ b/packages/core/docs/vibe-3-changelog.md @@ -282,13 +282,12 @@ codemod: `tab-panels-import-migration` ### TextField -- `dataTestId` -> `data-testid` [codemod] -- `iconsNames` prop removed `layout` [codemod] +- `dataTestId` -> `data-testid` [codemod ✅] +- `iconsNames` prop removed `layout` - Behavior of asterisk is now controlled by `required` prop, which means a field with asterisk will have to be required. - - Removed `requiredAsterisk` [codemod] (codemod should replace only if `requiredAsterisk` is used with `required`) -- Remove `withReadOnlyStyle` prop, new read only style will apply when using `readOnly` prop [codemod - remove withReadOnlyStyle] + - Removed `requiredAsterisk` [codemod ✅] +- Remove `withReadOnlyStyle` prop, new read only style will apply when using `readOnly` prop [codemod ✅] - Removed `sm`, `md`, `lg` sizes, use `small`, `medium`, `large` respectively -- ### ThemeProvider