diff --git a/packages/manager/.changeset/pr-11508-tests-1736539546177.md b/packages/manager/.changeset/pr-11508-tests-1736539546177.md
new file mode 100644
index 00000000000..5fc77bd8126
--- /dev/null
+++ b/packages/manager/.changeset/pr-11508-tests-1736539546177.md
@@ -0,0 +1,5 @@
+---
+"@linode/manager": Tests
+---
+
+Add component tests for PasswordInput ([#11508](https://github.com/linode/manager/pull/11508))
diff --git a/packages/manager/cypress/component/components/password-input.spec.tsx b/packages/manager/cypress/component/components/password-input.spec.tsx
new file mode 100644
index 00000000000..1313a09052c
--- /dev/null
+++ b/packages/manager/cypress/component/components/password-input.spec.tsx
@@ -0,0 +1,176 @@
+import * as React from 'react';
+import { checkComponentA11y } from 'support/util/accessibility';
+import { componentTests, visualTests } from 'support/util/components';
+
+import PasswordInput from 'src/components/PasswordInput/PasswordInput';
+
+const fakePassword = 'this is a password';
+const props = {
+ label: 'Password Input',
+ value: fakePassword,
+};
+
+componentTests('PasswordInput', (mount) => {
+ describe('PasswordInput interactions', () => {
+ /**
+ * - Confirms password text starts hidden
+ * - Confirms password text can be revealed or hidden when toggling visibility icon
+ */
+ it('can show and hide password text', () => {
+ mount();
+
+ // Password textfield starts off as 'password' type
+ cy.get('[type="password"]').should('be.visible');
+ cy.findByTestId('VisibilityIcon').should('be.visible').click();
+ cy.findByTestId('VisibilityIcon').should('not.exist');
+
+ // After clicking the visibility icon, textfield becomes a normal textfield
+ cy.get('[type="password"]').should('not.exist');
+ cy.get('[type="text"]').should('be.visible');
+
+ // Clicking VisibilityOffIcon changes input type to password again
+ cy.findByTestId('VisibilityOffIcon').should('be.visible').click();
+ cy.findByTestId('VisibilityOffIcon').should('not.exist');
+ cy.findByTestId('VisibilityIcon').should('be.visible');
+ cy.get('[type="password"]').should('be.visible');
+ cy.get('[type="text"]').should('not.exist');
+ });
+
+ /**
+ * - Confirms password input displays when a weak password is entered
+ */
+ it('displays an indicator for a weak password', () => {
+ const TestWeakStrength = () => {
+ const [password, setPassword] = React.useState('');
+ return (
+ setPassword(e.target.value)}
+ value={password}
+ />
+ );
+ };
+
+ mount();
+
+ // Starts off as 'Weak' if no password entered
+ cy.findByText('Weak').should('be.visible');
+
+ cy.findByTestId('textfield-input').should('be.visible').type('weak');
+ cy.findByText('Weak').should('be.visible');
+ });
+
+ /**
+ * - Confirm password indicator can update when a password is entered
+ * - Confirms password input can display indicator for a fair password
+ */
+ it('displays an indicator for a fair password', () => {
+ const TestMediumStrength = () => {
+ const [password, setPassword] = React.useState('');
+ return (
+ setPassword(e.target.value)}
+ value={password}
+ />
+ );
+ };
+
+ mount();
+
+ // Starts off as 'Weak' when no password entered
+ cy.findByText('Weak').should('be.visible');
+
+ cy.findByTestId('textfield-input')
+ .should('be.visible')
+ .type('fair-pass1');
+
+ // After typing in a fair password, the strength indicator updates
+ cy.findByText('Fair').should('be.visible');
+ cy.findByText('Weak').should('not.exist');
+ });
+
+ /**
+ * - Confirm password indicator can update when a password is entered
+ * - Confirms password input can display indicator for a good password
+ */
+ it('displays an indicator for a "good" password', () => {
+ const TestGoodStrength = () => {
+ const [password, setPassword] = React.useState('');
+ return (
+ setPassword(e.target.value)}
+ value={password}
+ />
+ );
+ };
+
+ mount();
+
+ // Starts off as 'Weak' when no password entered
+ cy.findByText('Weak').should('be.visible');
+
+ cy.findByTestId('textfield-input')
+ .should('be.visible')
+ .type('str0ng!!-password1!!');
+
+ // After typing in a strong password, the strength indicator updates
+ cy.findByText('Good').should('be.visible');
+ cy.findByText('Weak').should('not.exist');
+ });
+ });
+
+ visualTests((mount) => {
+ describe('Accessibility checks', () => {
+ it('passes aXe check when password input is visible', () => {
+ mount();
+ cy.findByTestId('VisibilityIcon').should('be.visible').click();
+
+ checkComponentA11y();
+ });
+
+ it('passes aXe check when password input is not visible', () => {
+ mount();
+
+ checkComponentA11y();
+ });
+
+ it('passes aXe check for a weak password', () => {
+ mount();
+
+ checkComponentA11y();
+ });
+
+ it('passes aXe check for a fair password', () => {
+ mount();
+
+ checkComponentA11y();
+ });
+
+ it('passes aXe check for a "good" password', () => {
+ mount();
+
+ checkComponentA11y();
+ });
+
+ it('passes aXe check when password input is designated as required', () => {
+ mount();
+
+ checkComponentA11y();
+ });
+
+ it('passes aXe check when strength value is hidden', () => {
+ mount();
+
+ checkComponentA11y();
+ });
+
+ it('passes aXe check when strength label is shown', () => {
+ mount();
+
+ checkComponentA11y();
+ });
+ });
+ });
+});
diff --git a/packages/manager/src/components/PasswordInput/HideShowText.stories.tsx b/packages/manager/src/components/PasswordInput/HideShowText.stories.tsx
index b2561a58866..5608aa6bd4e 100644
--- a/packages/manager/src/components/PasswordInput/HideShowText.stories.tsx
+++ b/packages/manager/src/components/PasswordInput/HideShowText.stories.tsx
@@ -1,9 +1,10 @@
/* eslint-disable react-hooks/rules-of-hooks */
-import { Meta, StoryObj } from '@storybook/react';
import React, { useState } from 'react';
import { HideShowText } from './HideShowText';
+import type { Meta, StoryObj } from '@storybook/react';
+
const meta: Meta = {
component: HideShowText,
title: 'Components/Input/Hide Show Text',
diff --git a/packages/manager/src/components/PasswordInput/PasswordInput.stories.tsx b/packages/manager/src/components/PasswordInput/PasswordInput.stories.tsx
index 67a76b58e8e..12ec8a4e7be 100644
--- a/packages/manager/src/components/PasswordInput/PasswordInput.stories.tsx
+++ b/packages/manager/src/components/PasswordInput/PasswordInput.stories.tsx
@@ -1,9 +1,10 @@
/* eslint-disable react-hooks/rules-of-hooks */
-import { Meta, StoryObj } from '@storybook/react';
import React, { useState } from 'react';
import PasswordInput from './PasswordInput';
+import type { Meta, StoryObj } from '@storybook/react';
+
const meta: Meta = {
component: PasswordInput,
title: 'Components/Input/Password Input',
diff --git a/packages/manager/src/components/PasswordInput/StrengthIndicator.stories.tsx b/packages/manager/src/components/PasswordInput/StrengthIndicator.stories.tsx
index 227b36af4e1..bd41bb63e86 100644
--- a/packages/manager/src/components/PasswordInput/StrengthIndicator.stories.tsx
+++ b/packages/manager/src/components/PasswordInput/StrengthIndicator.stories.tsx
@@ -1,8 +1,9 @@
-import { Meta, StoryObj } from '@storybook/react';
import React from 'react';
import { StrengthIndicator } from './StrengthIndicator';
+import type { Meta, StoryObj } from '@storybook/react';
+
const meta: Meta = {
component: StrengthIndicator,
title: 'Components/Strength Indicator',