Skip to content

Commit

Permalink
reset inputHTMLElement to allow duplicate files
Browse files Browse the repository at this point in the history
  • Loading branch information
elileto committed Jan 16, 2019
1 parent 1484752 commit 3ace71a
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 76 deletions.
4 changes: 4 additions & 0 deletions UNRELEASED.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ Use [the changelog guidelines](https://git.io/polaris-changelog-guidelines) to f

### Bug fixes

<<<<<<< HEAD
- Ensure disabled `Button` components with a `url` prop output valid HTML ([#773](https://github.com/Shopify/polaris-react/pull/773))
=======
- Fixed `DropZone` which was unable to add a duplicate file back to back or add a file again once removed [#782](https://github.com/Shopify/polaris-react/pull/782)
>>>>>>> reset inputHTMLElement to allow duplicate files
### Documentation

Expand Down
1 change: 1 addition & 0 deletions src/components/DropZone/DropZone.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,7 @@ export class DropZone extends React.Component<CombinedProps, State> {
if (onDropRejected && rejectedFiles.length) {
onDropRejected(rejectedFiles);
}
(event.target as HTMLInputElement).value = '';
}

@autobind
Expand Down
177 changes: 101 additions & 76 deletions src/components/DropZone/tests/DropZone.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,87 +5,73 @@ import {Label, Labelled, DisplayText, Caption} from 'components';
import {mountWithAppProvider} from 'test-utilities';
import DropZone from '../DropZone';

const files = [
{
name: 'jpeg file',
type: 'image/jpeg',
},
{
name: 'svg file',
type: 'image/svg',
},
];
const duplicateFiles = [
{
name: 'jpegs files',
type: 'image/jpeg',
},
{
name: 'svg file',
type: 'image/svg',
},
];
const acceptedFiles = [files[0]];
const rejectedFiles = [files[1]];
const origGetBoundingClientRect = Element.prototype.getBoundingClientRect;
const widths = {
small: 99,
medium: 159,
large: 299,
extraLarge: 1024,
};

describe('<DropZone />', () => {
let spy: jest.Mock;
let files: {}[];
let acceptedFiles: {}[];
let rejectedFiles: {}[];
let createEvent: any;
let setBoundingClientRect: any;
let origGetBoundingClientRect: any;
const widths = {
small: 99,
medium: 159,
large: 299,
extraLarge: 1024,
};

const fireEvent = (eventType: string, element: any) => {
spy.mockReset();
const event = createEvent(eventType);
element.getDOMNode().dispatchEvent(event);
};

const triggerDragEnter = (element: ReactWrapper<any, any>) => {
const event = createEvent('dragenter');
element.getDOMNode().dispatchEvent(event);
clock.tick(50);
element.update();
};

beforeEach(() => {
spy = jest.fn();
clock.mock();
files = [
{
name: 'jpeg file',
type: 'image/jpeg',
},
{
name: 'svg file',
type: 'image/svg',
},
];
acceptedFiles = [files[0]];
rejectedFiles = [files[1]];
createEvent = (name: string) => {
const evt = new CustomEvent(name);
Object.defineProperty(evt, 'dataTransfer', {
enumerable: true,
value: {files},
});
return evt;
};
origGetBoundingClientRect = Element.prototype.getBoundingClientRect;
setBoundingClientRect = (size: keyof typeof widths) => {
Element.prototype.getBoundingClientRect = jest.fn(() => {
return {
width: widths[size],
height: 100,
top: 0,
left: 0,
bottom: 0,
right: 0,
};
});
};
});

afterEach(() => {
clock.restore();
});

afterAll(() => {
Element.prototype.getBoundingClientRect = origGetBoundingClientRect;
});

it('calls the onDrop callback when a drop event is fired', () => {
const dropZone = mountWithAppProvider(<DropZone onDrop={spy} />);
const event = createEvent('drop');
const event = createEvent('drop', files);
dropZone.getDOMNode().dispatchEvent(event);
expect(spy).toBeCalledWith(files, files, []);
});

it('calls the onDrop callback when a drop event is fired on document twice when a duplicate file is added consecutively', () => {
const dropZone = mountWithAppProvider(<DropZone onDrop={spy} />);
const event1 = createEvent('drop', files);
dropZone.getDOMNode().dispatchEvent(event1);
expect(spy).toBeCalledWith(files, files, []);

const event2 = createEvent('drop', duplicateFiles);
dropZone.getDOMNode().dispatchEvent(event2);
expect(spy).toBeCalledWith(duplicateFiles, duplicateFiles, []);
});

it('calls the onDrop callback when a drop event is fired on document', () => {
mountWithAppProvider(<DropZone dropOnPage onDrop={spy} />);
const event = createEvent('drop');
const event = createEvent('drop', files);
document.dispatchEvent(event);
expect(spy).toBeCalledWith(files, files, []);
});
Expand All @@ -94,7 +80,7 @@ describe('<DropZone />', () => {
const dropZone = mountWithAppProvider(
<DropZone onDrop={spy} accept="image/jpeg" />,
);
const event = createEvent('drop');
const event = createEvent('drop', files);
dropZone.getDOMNode().dispatchEvent(event);
expect(spy).toBeCalledWith(files, acceptedFiles, rejectedFiles);
});
Expand All @@ -103,7 +89,7 @@ describe('<DropZone />', () => {
const dropZone = mountWithAppProvider(
<DropZone onDropAccepted={spy} accept="image/jpeg" />,
);
const event = createEvent('drop');
const event = createEvent('drop', files);
dropZone.getDOMNode().dispatchEvent(event);
expect(spy).toBeCalledWith(acceptedFiles);
});
Expand All @@ -112,28 +98,28 @@ describe('<DropZone />', () => {
const dropZone = mountWithAppProvider(
<DropZone onDropRejected={spy} accept="image/jpeg" />,
);
const event = createEvent('drop');
const event = createEvent('drop', files);
dropZone.getDOMNode().dispatchEvent(event);
expect(spy).toBeCalledWith(rejectedFiles);
});

it('calls the onDragEnter callback when a dragEnter event is fired', () => {
const dropZone = mountWithAppProvider(<DropZone onDragEnter={spy} />);
const event = createEvent('dragenter');
const event = createEvent('dragenter', files);
dropZone.getDOMNode().dispatchEvent(event);
expect(spy).toBeCalled();
});

it('calls the onDragOver callback when a dragOver event is fired', () => {
const dropZone = mountWithAppProvider(<DropZone onDragOver={spy} />);
const event = createEvent('dragover');
const event = createEvent('dragover', files);
dropZone.getDOMNode().dispatchEvent(event);
expect(spy).toBeCalled();
});

it('calls the onDragLeave callback when a dragLeave event is fired', () => {
const dropZone = mountWithAppProvider(<DropZone onDragLeave={spy} />);
const event = createEvent('dragleave');
const event = createEvent('dragleave', files);
dropZone.getDOMNode().dispatchEvent(event);
expect(spy).toBeCalled();
});
Expand All @@ -145,7 +131,7 @@ describe('<DropZone />', () => {
const dropZone = mountWithAppProvider(
<DropZone onDrop={spy} customValidator={customValidator} />,
);
const event = createEvent('drop');
const event = createEvent('drop', files);
dropZone.getDOMNode().dispatchEvent(event);
expect(spy).toBeCalledWith(files, acceptedFiles, rejectedFiles);
});
Expand All @@ -162,13 +148,13 @@ describe('<DropZone />', () => {
onDragOver={spy}
/>,
);
fireEvent('drop', dropZone);
fireEvent('drop', dropZone, spy);
expect(spy).not.toBeCalled();
fireEvent('dragenter', dropZone);
fireEvent('dragenter', dropZone, spy);
expect(spy).not.toBeCalled();
fireEvent('dragleave', dropZone);
fireEvent('dragleave', dropZone, spy);
expect(spy).not.toBeCalled();
fireEvent('dragover', dropZone);
fireEvent('dragover', dropZone, spy);
expect(spy).not.toBeCalled();
});

Expand All @@ -185,17 +171,17 @@ describe('<DropZone />', () => {
);

// Initial event to populate zone with data (should succeed)
fireEvent('drop', dropZone);
fireEvent('drop', dropZone, spy);
expect(spy).toBeCalledWith(files, acceptedFiles, rejectedFiles);

// All events should now be ignored
fireEvent('drop', dropZone);
fireEvent('drop', dropZone, spy);
expect(spy).not.toBeCalled();
fireEvent('dragenter', dropZone);
fireEvent('dragenter', dropZone, spy);
expect(spy).not.toBeCalled();
fireEvent('dragleave', dropZone);
fireEvent('dragleave', dropZone, spy);
expect(spy).not.toBeCalled();
fireEvent('dragover', dropZone);
fireEvent('dragover', dropZone, spy);
expect(spy).not.toBeCalled();
});

Expand Down Expand Up @@ -334,3 +320,42 @@ describe('<DropZone />', () => {
});
});
});

function createEvent(name: string, files: any) {
const evt = new CustomEvent(name);
Object.defineProperty(evt, 'dataTransfer', {
enumerable: true,
value: {files},
});
return evt;
}

function setBoundingClientRect(size: keyof typeof widths) {
Element.prototype.getBoundingClientRect = jest.fn(() => {
return {
width: widths[size],
height: 100,
top: 0,
left: 0,
bottom: 0,
right: 0,
};
});
}

function triggerDragEnter(element: ReactWrapper<any, any>) {
const event = createEvent('dragenter', files);
element.getDOMNode().dispatchEvent(event);
clock.tick(50);
element.update();
}

function fireEvent(
eventType: string,
element: ReactWrapper<any, any>,
spy: jest.Mock,
) {
spy.mockReset();
const event = createEvent(eventType, files);
element.getDOMNode().dispatchEvent(event);
}

0 comments on commit 3ace71a

Please sign in to comment.