diff --git a/packages/shared/src/features/profile/components/ProfileSkills.spec.tsx b/packages/shared/src/features/profile/components/ProfileSkills.spec.tsx
new file mode 100644
index 0000000000..a1fbc8d0fe
--- /dev/null
+++ b/packages/shared/src/features/profile/components/ProfileSkills.spec.tsx
@@ -0,0 +1,83 @@
+import React, { type ReactNode } from 'react';
+import { act, fireEvent, render, screen } from '@testing-library/react';
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
+import { FormProvider, useForm } from 'react-hook-form';
+import ProfileSkills from './ProfileSkills';
+
+type FormWrapperProps = {
+ children: ReactNode;
+};
+
+const FormWrapper = ({ children }: FormWrapperProps) => {
+ const methods = useForm({
+ defaultValues: {
+ skills: [],
+ },
+ });
+
+ return (
+
+ {children}
+
+ );
+};
+
+const renderComponent = () =>
+ render(
+
+
+ ,
+ );
+
+const advanceDebounce = () => {
+ act(() => {
+ jest.advanceTimersByTime(300);
+ });
+};
+
+describe('ProfileSkills', () => {
+ beforeEach(() => {
+ jest.useFakeTimers();
+ });
+
+ afterEach(() => {
+ jest.clearAllTimers();
+ jest.useRealTimers();
+ });
+
+ it('keeps the input empty after clearing a pending debounced query', () => {
+ renderComponent();
+
+ const input = screen.getByPlaceholderText('Search skills');
+
+ fireEvent.change(input, { target: { value: 'R' } });
+ fireEvent.change(input, { target: { value: '' } });
+
+ expect(input).toHaveValue('');
+
+ advanceDebounce();
+
+ expect(input).toHaveValue('');
+ });
+
+ it('keeps the input empty after submitting while a debounced query is pending', () => {
+ renderComponent();
+
+ const input = screen.getByPlaceholderText('Search skills');
+
+ fireEvent.change(input, { target: { value: 'R' } });
+ advanceDebounce();
+
+ expect(input).toHaveValue('R');
+
+ fireEvent.change(input, { target: { value: 'A' } });
+ fireEvent.keyDown(input, { code: 'Enter', key: 'Enter' });
+
+ expect(screen.getByRole('button', { name: 'R' })).toBeInTheDocument();
+ expect(input).toHaveValue('');
+
+ advanceDebounce();
+
+ expect(input).toHaveValue('');
+ });
+});
diff --git a/packages/shared/src/features/profile/components/ProfileSkills.tsx b/packages/shared/src/features/profile/components/ProfileSkills.tsx
index 3039501f05..70412150b8 100644
--- a/packages/shared/src/features/profile/components/ProfileSkills.tsx
+++ b/packages/shared/src/features/profile/components/ProfileSkills.tsx
@@ -30,8 +30,17 @@ const ProfileSkills = ({ name }: ProfileSkillsProps): ReactElement => {
const { data: autocompleteKeywords, isFetching } = useQuery(
getKeywordAutocompleteOptions(query),
);
+ const hasAutocompleteKeywords = (autocompleteKeywords?.length ?? 0) > 0;
- const [debouncedQuery] = useDebounceFn((data) => setQuery(data), 300);
+ const [debouncedQuery, cancelDebouncedQuery] = useDebounceFn(
+ (data) => setQuery(data ?? ''),
+ 300,
+ );
+
+ const clearQuery = () => {
+ cancelDebouncedQuery();
+ setQuery('');
+ };
const handlePopoverClose: PopoverContentProps['onInteractOutside'] = (e) => {
if (e.target === inputRef.current) {
@@ -66,7 +75,7 @@ const ProfileSkills = ({ name }: ProfileSkillsProps): ReactElement => {
Skills
- 0}>
+
{
@@ -76,14 +85,16 @@ const ProfileSkills = ({ name }: ProfileSkillsProps): ReactElement => {
label="Search skills"
leftIcon={}
rightIcon={
- isFetching &&
+ isFetching ? (
+
+ ) : undefined
}
hint="Add commas (,) to add multiple skills. Press Enter to submit them."
hintIcon={}
value={query}
onChange={({ target }) => {
if (target.value === '') {
- return setQuery('');
+ return clearQuery();
}
return debouncedQuery(target.value);
@@ -105,13 +116,13 @@ const ProfileSkills = ({ name }: ProfileSkillsProps): ReactElement => {
if (newSkills.length === 0) {
if (query) {
- setQuery('');
+ clearQuery();
}
return;
}
field.onChange([...skills, ...newSkills]);
- setQuery('');
+ clearQuery();
return;
}
@@ -141,11 +152,11 @@ const ProfileSkills = ({ name }: ProfileSkillsProps): ReactElement => {
key={keyword}
tag={{ name: keyword }}
isSelected={isSelected}
- onClick={({ tag }) => {
+ onClick={() => {
if (isSelected) {
- removeSkill(tag.name);
+ removeSkill(keyword);
} else {
- addSkill(tag.name);
+ addSkill(keyword);
}
}}
/>
@@ -162,8 +173,8 @@ const ProfileSkills = ({ name }: ProfileSkillsProps): ReactElement => {
key={skill}
tag={{ name: skill }}
isSelected
- onClick={({ tag }) => {
- removeSkill(tag.name);
+ onClick={() => {
+ removeSkill(skill);
}}
/>
))}