diff --git a/packages/api-v4/.changeset/pr-11337-added-1732714186488.md b/packages/api-v4/.changeset/pr-11337-added-1732714186488.md
new file mode 100644
index 00000000000..b261294d469
--- /dev/null
+++ b/packages/api-v4/.changeset/pr-11337-added-1732714186488.md
@@ -0,0 +1,5 @@
+---
+"@linode/api-v4": Added
+---
+
+Linter rules for naming convention ([#11337](https://github.com/linode/manager/pull/11337))
diff --git a/packages/api-v4/.eslintrc.json b/packages/api-v4/.eslintrc.json
index 039685b3d24..f551347ff3f 100644
--- a/packages/api-v4/.eslintrc.json
+++ b/packages/api-v4/.eslintrc.json
@@ -13,6 +13,42 @@
"plugin:prettier/recommended"
],
"rules": {
+ "@typescript-eslint/naming-convention": [
+ "warn",
+ {
+ "format": ["camelCase", "UPPER_CASE", "PascalCase"],
+ "leadingUnderscore": "allow",
+ "selector": "variable",
+ "trailingUnderscore": "allow"
+ },
+ {
+ "format": null,
+ "modifiers": ["destructured"],
+ "selector": "variable"
+ },
+ {
+ "format": ["camelCase", "PascalCase"],
+ "selector": "function"
+ },
+ {
+ "format": ["camelCase"],
+ "leadingUnderscore": "allow",
+ "selector": "parameter"
+ },
+ {
+ "format": ["PascalCase"],
+ "selector": "typeLike"
+ }
+ ],
+ "@typescript-eslint/no-unused-vars": "off",
+ "@typescript-eslint/no-inferrable-types": "off",
+ "@typescript-eslint/no-namespace": "warn",
+ "@typescript-eslint/explicit-function-return-type": "off",
+ "@typescript-eslint/no-empty-interface": "warn",
+ "@typescript-eslint/no-non-null-assertion": "off",
+ "@typescript-eslint/no-explicit-any": "warn",
+ "@typescript-eslint/no-use-before-define": "off",
+ "@typescript-eslint/interface-name-prefix": "off",
"no-unused-vars": [
"warn",
{
@@ -33,15 +69,6 @@
"no-console": "error",
"no-undef-init": "off",
"radix": "error",
- "@typescript-eslint/no-unused-vars": "off",
- "@typescript-eslint/no-inferrable-types": "off",
- "@typescript-eslint/no-namespace": "warn",
- "@typescript-eslint/explicit-function-return-type": "off",
- "@typescript-eslint/no-empty-interface": "warn",
- "@typescript-eslint/no-non-null-assertion": "off",
- "@typescript-eslint/no-explicit-any": "warn",
- "@typescript-eslint/no-use-before-define": "off",
- "@typescript-eslint/interface-name-prefix": "off",
"sonarjs/cognitive-complexity": "warn",
"sonarjs/no-duplicate-string": "warn",
"sonarjs/prefer-immediate-return": "warn",
diff --git a/packages/manager/.changeset/pr-11336-added-1732711112187.md b/packages/manager/.changeset/pr-11336-added-1732711112187.md
new file mode 100644
index 00000000000..363797bb07a
--- /dev/null
+++ b/packages/manager/.changeset/pr-11336-added-1732711112187.md
@@ -0,0 +1,5 @@
+---
+"@linode/manager": Added
+---
+
+unit test cases for `DocsLink` component ([#11336](https://github.com/linode/manager/pull/11336))
diff --git a/packages/manager/.changeset/pr-11337-added-1732714227095.md b/packages/manager/.changeset/pr-11337-added-1732714227095.md
new file mode 100644
index 00000000000..9282e940f63
--- /dev/null
+++ b/packages/manager/.changeset/pr-11337-added-1732714227095.md
@@ -0,0 +1,5 @@
+---
+"@linode/manager": Added
+---
+
+Linter rules for naming convention ([#11337](https://github.com/linode/manager/pull/11337))
diff --git a/packages/manager/.eslintrc.cjs b/packages/manager/.eslintrc.cjs
index 37a8ee55d6c..99870119ff7 100644
--- a/packages/manager/.eslintrc.cjs
+++ b/packages/manager/.eslintrc.cjs
@@ -164,6 +164,33 @@ module.exports = {
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/interface-name-prefix': 'off',
+ '@typescript-eslint/naming-convention': [
+ 'warn',
+ {
+ format: ['camelCase', 'UPPER_CASE', 'PascalCase'],
+ leadingUnderscore: 'allow',
+ selector: 'variable',
+ trailingUnderscore: 'allow',
+ },
+ {
+ format: null,
+ modifiers: ['destructured'],
+ selector: 'variable',
+ },
+ {
+ format: ['camelCase', 'PascalCase'],
+ selector: 'function',
+ },
+ {
+ format: ['camelCase'],
+ leadingUnderscore: 'allow',
+ selector: 'parameter',
+ },
+ {
+ format: ['PascalCase'],
+ selector: 'typeLike',
+ },
+ ],
'@typescript-eslint/no-empty-interface': 'warn',
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-inferrable-types': 'off',
diff --git a/packages/manager/src/components/DocsLink/DocsLink.test.tsx b/packages/manager/src/components/DocsLink/DocsLink.test.tsx
new file mode 100644
index 00000000000..d8ddf2bee3f
--- /dev/null
+++ b/packages/manager/src/components/DocsLink/DocsLink.test.tsx
@@ -0,0 +1,45 @@
+import userEvent from '@testing-library/user-event';
+import React from 'react';
+
+import { sendHelpButtonClickEvent } from 'src/utilities/analytics/customEventAnalytics';
+import { renderWithTheme } from 'src/utilities/testHelpers';
+
+import { DocsLink } from './DocsLink';
+
+import type { DocsLinkProps } from './DocsLink';
+
+vi.mock('src/utilities/analytics/customEventAnalytics', () => ({
+ sendHelpButtonClickEvent: vi.fn(),
+}));
+
+const mockLabel = 'Custom Doc Link Label';
+const mockHref =
+ 'https://techdocs.akamai.com/cloud-computing/docs/faqs-for-compute-instances';
+const mockAnalyticsLabel = 'Label';
+
+const defaultProps: DocsLinkProps = {
+ analyticsLabel: mockAnalyticsLabel,
+ href: mockHref,
+ label: mockLabel,
+};
+
+describe('DocsLink', () => {
+ it('should render the label', () => {
+ const { getByText } = renderWithTheme();
+ expect(getByText(mockLabel)).toBeVisible();
+ });
+
+ it('should allow user to click the label and redirect to the url', async () => {
+ const { getByRole } = renderWithTheme();
+ const link = getByRole('link', {
+ name: 'Custom Doc Link Label - link opens in a new tab',
+ });
+ expect(link).toBeInTheDocument();
+ await userEvent.click(link);
+ expect(sendHelpButtonClickEvent).toHaveBeenCalledTimes(1);
+ expect(sendHelpButtonClickEvent).toHaveBeenCalledWith(
+ mockHref,
+ mockAnalyticsLabel
+ );
+ });
+});