Skip to content

Commit

Permalink
chore(react-tag): adds e2e tests
Browse files Browse the repository at this point in the history
  • Loading branch information
bsunderhus committed Apr 10, 2024
1 parent 889bb44 commit 14b107f
Show file tree
Hide file tree
Showing 7 changed files with 202 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { baseConfig } from '@fluentui/scripts-cypress';

export default baseConfig;
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
"storybook": "start-storybook",
"test": "jest --passWithNoTests",
"test-ssr": "test-ssr \"./stories/**/*.stories.tsx\"",
"type-check": "tsc -b tsconfig.json"
"type-check": "tsc -b tsconfig.json",
"e2e": "cypress run --component",
"e2e:local": "cypress open --component"
},
"devDependencies": {
"@fluentui/eslint-plugin": "*",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/// <reference types="cypress" />
/// <reference types="cypress-real-events" />

import * as React from 'react';
import { mount as mountBase } from '@cypress/react';
import { FluentProvider } from '@fluentui/react-provider';
import { teamsLightTheme } from '@fluentui/react-theme';
import { TagPickerProps } from './TagPicker.types';
import { TagPicker } from './TagPicker';
import { TagPickerControl } from '../TagPickerControl/TagPickerControl';
import { TagPickerGroup } from '../TagPickerGroup/TagPickerGroup';
import { Tag } from '@fluentui/react-tags';
import { TagPickerInput } from '../TagPickerInput/TagPickerInput';
import { TagPickerList } from '../TagPickerList/TagPickerList';
import { TagPickerOption } from '../TagPickerOption/TagPickerOption';
import { Avatar } from '@fluentui/react-avatar';
import { Button } from '@fluentui/react-button';

const mount = (element: JSX.Element) => {
mountBase(<FluentProvider theme={teamsLightTheme}>{element}</FluentProvider>);
};

const options = [
'John Doe',
'Jane Doe',
'Max Mustermann',
'Erika Mustermann',
'Pierre Dupont',
'Amelie Dupont',
'Mario Rossi',
'Maria Rossi',
];

const TagPickerControlled = ({ open, defaultOpen }: Pick<TagPickerProps, 'open' | 'defaultOpen'>) => {
const [selectedOptions, setSelectedOptions] = React.useState<string[]>([]);
const onOptionSelect: TagPickerProps['onOptionSelect'] = (e, data) => {
setSelectedOptions(data.selectedOptions);
};
const handleAllClear: React.MouseEventHandler = event => {
setSelectedOptions([]);
};

return (
<div style={{ maxWidth: 400 }}>
<TagPicker
onOptionSelect={onOptionSelect}
selectedOptions={selectedOptions}
open={open}
defaultOpen={defaultOpen}
>
<TagPickerControl
expandIcon={{ 'data-testid': 'tag-picker-control__expandIcon' } as {}}
data-testid="tag-picker-control"
secondaryAction={
<Button
data-testid="tag-picker-control__secondaryAction"
appearance="transparent"
size="small"
shape="rounded"
onClick={handleAllClear}
>
All Clear
</Button>
}
>
<TagPickerGroup>
{selectedOptions.map(option => (
<Tag
data-testid={`tag:${option}`}
key={option}
shape="rounded"
media={<Avatar name={option} color="colorful" />}
value={option}
>
{option}
</Tag>
))}
</TagPickerGroup>
<TagPickerInput data-testid="tag-picker-input" />
</TagPickerControl>
<TagPickerList data-testid="tag-picker-list">
{options
.filter(option => !selectedOptions.includes(option))
.map(option => (
<TagPickerOption
data-testid={`tag-picker-option:${option}`}
secondaryContent="Microsoft FTE"
media={<Avatar name={option} color="colorful" />}
value={option}
key={option}
>
{option}
</TagPickerOption>
))}
</TagPickerList>
</TagPicker>
</div>
);
};

describe('TagPicker', () => {
it('should render a closed listbox', () => {
mount(<TagPickerControlled />);
cy.get('[data-testid="tag-picker-control"]').should('exist');
cy.get('[data-testid="tag-picker-list"]').should('not.exist');
});
it('should render an opened listbox', () => {
mount(<TagPickerControlled open />);
cy.get('[data-testid="tag-picker-control"]').should('exist');
cy.get('[data-testid="tag-picker-list"]').should('be.visible');
});
describe('Mouse navigation', () => {
it('should open/close a listbox once trigger is clicked', () => {
mount(<TagPickerControlled />);
cy.get('[data-testid="tag-picker-list"]').should('not.exist');
cy.get('[data-testid="tag-picker-input"]').realClick();
cy.get('[data-testid="tag-picker-list"]').should('be.visible');
cy.get('[data-testid="tag-picker-input"]').should('be.focused');
cy.get('[data-testid="tag-picker-input"]').realClick();
cy.get('[data-testid="tag-picker-list"]').should('not.be.visible');
});
it('should open/close a listbox once expandIcon is clicked', () => {
mount(<TagPickerControlled />);
cy.get('[data-testid="tag-picker-list"]').should('not.exist');
cy.get('[data-testid="tag-picker-control__expandIcon"]').realClick();
cy.get('[data-testid="tag-picker-list"]').should('be.visible');
cy.get('[data-testid="tag-picker-input"]').should('be.focused');
cy.get('[data-testid="tag-picker-control__expandIcon"]').realClick();
cy.get('[data-testid="tag-picker-list"]').should('not.be.visible');
});
it('should select a tag on option click', () => {
mount(<TagPickerControlled defaultOpen />);
cy.get('[data-testid="tag-picker-list"]').should('be.visible');
cy.get(`[data-testid="tag-picker-option:${options[0]}"]`).should('exist').realClick();
cy.get('[data-testid="tag-picker-list"]').should('not.be.visible');
cy.get(`[data-testid="tag:${options[0]}"]`).should('exist');
cy.get('[data-testid="tag-picker-input"]').should('be.focused');
});
it('should dismiss a tag on tag click', () => {
mount(<TagPickerControlled defaultOpen />);
cy.get(`[data-testid="tag-picker-option:${options[0]}"]`).realClick();
cy.get(`[data-testid="tag:${options[0]}"]`).should('exist').realClick().should('not.exist');
cy.get('[data-testid="tag-picker-input"]').should('be.focused');
});
it('should dismiss a tag on clear all click', () => {
mount(<TagPickerControlled defaultOpen />);
cy.get(`[data-testid="tag-picker-option:${options[0]}"]`).realClick();
cy.get(`[data-testid="tag:${options[0]}"]`).should('exist').realClick();
cy.get('[data-testid="tag-picker-input"]').should('be.focused');
cy.get('[data-testid="tag-picker-control__secondaryAction"]').should('exist').realClick();
cy.get(`[data-testid="tag:${options[0]}"]`).should('not.exist');
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
TagPickerOption,
TagPickerGroup,
} from '@fluentui/react-tag-picker-preview';
import { Tag, Avatar, Field } from '@fluentui/react-components';
import { Tag, Avatar } from '@fluentui/react-components';

const options = [
'John Doe',
Expand All @@ -29,34 +29,32 @@ export const Default = () => {

return (
<div style={{ maxWidth: 400 }}>
<Field label={'Select User'} validationState={'error'} validationMessage={'User must be selected'}>
<TagPicker onOptionSelect={onOptionSelect} selectedOptions={selectedOptions}>
<TagPickerControl>
<TagPickerGroup>
{selectedOptions.map(option => (
<Tag key={option} shape="rounded" media={<Avatar name={option} color="colorful" />} value={option}>
{option}
</Tag>
))}
</TagPickerGroup>
<TagPickerInput />
</TagPickerControl>
<TagPickerList>
{options
.filter(option => !selectedOptions.includes(option))
.map(option => (
<TagPickerOption
secondaryContent="Microsoft FTE"
media={<Avatar name={option} color="colorful" />}
value={option}
key={option}
>
{option}
</TagPickerOption>
))}
</TagPickerList>
</TagPicker>
</Field>
<TagPicker onOptionSelect={onOptionSelect} selectedOptions={selectedOptions}>
<TagPickerControl>
<TagPickerGroup>
{selectedOptions.map(option => (
<Tag key={option} shape="rounded" media={<Avatar name={option} color="colorful" />} value={option}>
{option}
</Tag>
))}
</TagPickerGroup>
<TagPickerInput />
</TagPickerControl>
<TagPickerList>
{options
.filter(option => !selectedOptions.includes(option))
.map(option => (
<TagPickerOption
secondaryContent="Microsoft FTE"
media={<Avatar name={option} color="colorful" />}
value={option}
key={option}
>
{option}
</TagPickerOption>
))}
</TagPickerList>
</TagPicker>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"isolatedModules": false,
"types": ["node", "cypress", "cypress-storybook/cypress", "cypress-real-events"],
"lib": ["ES2019", "dom"]
},
"include": ["**/*.cy.ts", "**/*.cy.tsx"]
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
},
{
"path": "./.storybook/tsconfig.json"
},
{
"path": "./tsconfig.cy.json"
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
"**/*.test.ts",
"**/*.test.tsx",
"**/*.stories.ts",
"**/*.stories.tsx"
"**/*.stories.tsx",
"**/*.cy.ts",
"**/*.cy.tsx"
],
"include": ["./src/**/*.ts", "./src/**/*.tsx"]
}

0 comments on commit 14b107f

Please sign in to comment.