diff --git a/src/components/builder/lists/ListItem.js b/src/components/builder/lists/ListItem.js
index 7dfd406b5..fa51b7316 100644
--- a/src/components/builder/lists/ListItem.js
+++ b/src/components/builder/lists/ListItem.js
@@ -1,11 +1,14 @@
import { Menu, MenuItem } from '@material-ui/core';
import React, { memo, useState } from 'react';
+import { Draggable } from 'react-beautiful-dnd';
import { useTranslation } from 'react-i18next';
import { IoIosArrowDown, IoIosArrowUp } from 'react-icons/io';
import { MdMoreVert } from 'react-icons/md';
import { useDispatch } from '../../../contexts/ResumeContext';
import styles from './ListItem.module.css';
+const dataTestIdPrefix = 'list-item-';
+
const ListItem = ({
title,
subtitle,
@@ -15,6 +18,7 @@ const ListItem = ({
isFirst,
isLast,
onEdit,
+ index,
}) => {
const dispatch = useDispatch();
const { t } = useTranslation();
@@ -66,50 +70,68 @@ const ListItem = ({
};
return (
-
-
- {title}
-
- {subtitle && (
- {subtitle}
- )}
-
- {text && (
- {text}
- )}
-
-
-
-
-
+ )}
+
);
};
export default memo(ListItem);
+
+export { dataTestIdPrefix };
diff --git a/src/pages/app/__tests__/builder.skills.test.js b/src/pages/app/__tests__/builder.skills.test.js
new file mode 100644
index 000000000..1677ac366
--- /dev/null
+++ b/src/pages/app/__tests__/builder.skills.test.js
@@ -0,0 +1,63 @@
+import { get } from 'lodash';
+import { screen } from '@testing-library/react';
+
+import { DatabaseConstants } from 'gatsby-plugin-firebase';
+
+import { dataTestIdPrefix as listItemDataTestIdPrefix } from '../../../components/builder/lists/ListItem';
+
+import {
+ setupAndWait,
+ expectDatabaseUpdateToHaveCompleted,
+ dragAndDropDirectionDown,
+ dragAndDropListItem,
+} from './helpers/builder';
+
+const testTimeoutInMilliseconds = 20000;
+jest.setTimeout(testTimeoutInMilliseconds);
+
+test('allows to drag & drop', async () => {
+ const resumeId = DatabaseConstants.demoStateResume1Id;
+ const { resume, mockDatabaseUpdateFunction } = await setupAndWait(
+ resumeId,
+ true,
+ true,
+ );
+
+ const now = new Date().getTime();
+
+ const dataPath = 'skills.items';
+ const dataItems = get(resume, dataPath);
+ expect(dataItems.length).toBeGreaterThan(1);
+
+ const listItems = screen.getAllByTestId(
+ `${listItemDataTestIdPrefix}${dataPath}`,
+ );
+ const firstListItem = listItems[0];
+ expect(firstListItem).toHaveTextContent(dataItems[0].name);
+ const secondListItem = listItems[1];
+ expect(secondListItem).toHaveTextContent(dataItems[1].name);
+
+ dragAndDropListItem(firstListItem, dragAndDropDirectionDown);
+
+ const actualListItems = screen.getAllByTestId(
+ `${listItemDataTestIdPrefix}${dataPath}`,
+ );
+ const actualFirstListItem = actualListItems[0];
+ expect(actualFirstListItem).toHaveTextContent(dataItems[1].name);
+ const actualSecondListItem = actualListItems[1];
+ expect(actualSecondListItem).toHaveTextContent(dataItems[0].name);
+
+ await expectDatabaseUpdateToHaveCompleted(mockDatabaseUpdateFunction);
+ const mockDatabaseUpdateFunctionCallArgument =
+ mockDatabaseUpdateFunction.mock.calls[0][0];
+ expect(mockDatabaseUpdateFunctionCallArgument.id).toBe(resumeId);
+ expect(mockDatabaseUpdateFunctionCallArgument.skills.items[0]).toEqual(
+ dataItems[1],
+ );
+ expect(mockDatabaseUpdateFunctionCallArgument.skills.items[1]).toEqual(
+ dataItems[0],
+ );
+ expect(
+ mockDatabaseUpdateFunctionCallArgument.updatedAt,
+ ).toBeGreaterThanOrEqual(now);
+});
diff --git a/src/pages/app/__tests__/helpers/builder.js b/src/pages/app/__tests__/helpers/builder.js
index b05eca1b7..e63c93468 100644
--- a/src/pages/app/__tests__/helpers/builder.js
+++ b/src/pages/app/__tests__/helpers/builder.js
@@ -1,5 +1,6 @@
import React from 'react';
import {
+ fireEvent,
render,
screen,
waitFor,
@@ -46,6 +47,36 @@ const expectDatabaseUpdateToHaveCompleted = async (
);
};
+const dragAndDropDirectionUp = 'DND_DIRECTION_UP';
+const dragAndDropDirectionDown = 'DND_DIRECTION_DOWN';
+
+const dragAndDropListItem = (listItemElement, direction) => {
+ const spaceKey = { keyCode: 32 };
+ const arrowUpKey = { keyCode: 38 };
+ const arrowDownKey = { keyCode: 40 };
+ const getKeyForDirection = () => {
+ switch (direction) {
+ case dragAndDropDirectionUp:
+ return arrowUpKey;
+ case dragAndDropDirectionDown:
+ return arrowDownKey;
+ default:
+ throw new Error('Unhandled `direction`!');
+ }
+ };
+
+ listItemElement.focus();
+
+ // start the drag
+ fireEvent.keyDown(listItemElement, spaceKey);
+
+ // move element based on direction
+ fireEvent.keyDown(listItemElement, getKeyForDirection());
+
+ // drop
+ fireEvent.keyDown(listItemElement, spaceKey);
+};
+
// eslint-disable-next-line no-underscore-dangle
async function _setup(
resumeId,
@@ -124,4 +155,7 @@ export {
setupAndWait,
waitForDatabaseUpdateToHaveCompletedFn as waitForDatabaseUpdateToHaveCompleted,
expectDatabaseUpdateToHaveCompleted,
+ dragAndDropDirectionUp,
+ dragAndDropDirectionDown,
+ dragAndDropListItem,
};