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',