Skip to content

Commit

Permalink
refactor OL tests to use a sweet harness (#2981)
Browse files Browse the repository at this point in the history
  • Loading branch information
giladgray authored Sep 27, 2018
1 parent 8f13ff2 commit 6fe1ac6
Showing 1 changed file with 90 additions and 71 deletions.
161 changes: 90 additions & 71 deletions packages/core/test/overflow-list/overflowListTests.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,134 +5,153 @@
*/

import { assert } from "chai";
import { mount, ReactWrapper } from "enzyme";
import { mount } from "enzyme";
import * as React from "react";

import { IOverflowListProps, OverflowList } from "../../src/components/overflow-list/overflowList";
import { IOverflowListProps, IOverflowListState, OverflowList } from "../../src/components/overflow-list/overflowList";

type OverflowProps = IOverflowListProps<ITestItem>;

interface ITestItem {
id: number;
}

const ITEMS: ITestItem[] = [{ id: 0 }, { id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 }];
const IDS = [0, 1, 2, 3, 4, 5];
const ITEMS: ITestItem[] = IDS.map(id => ({ id }));

const TestItem: React.SFC = () => <div style={{ width: 10 }} />;
const TestItem: React.SFC<ITestItem> = () => <div style={{ width: 10, flex: "0 0 auto" }} />;
const TestOverflow: React.SFC<{ items: ITestItem[] }> = () => <div />;

describe("<OverflowList>", function(this) {
// these tests rely on DOM measurement which can be flaky, so we allow some retries
this.retries(3);

let list: ReactWrapper<IOverflowListProps<{}>, any> | undefined;
const testsContainerElement = document.createElement("div");
document.documentElement.appendChild(testsContainerElement);

afterEach(() => {
// clean up list after each test, if it was used
if (list !== undefined) {
list.unmount();
list.detach();
list = undefined;
}
});

it("adds className to itself", () => {
list = renderOverflowList({ className: "winner" });
assert.lengthOf(list.find(".winner").hostNodes(), 1);
assert.isTrue(
overflowList(30, { className: "winner" })
.wrapper.find(".winner")
.exists(),
);
});

it("overflows correctly on initial mount", () => {
list = renderOverflowList({ style: { width: 35 } });
assert.lengthOf(list.find(TestItem), 3);
overflowList().assertVisibleItemSplit(4);
});

it("shows more after growing", done => {
list = renderOverflowList({ style: { width: 35 } });
assert.lengthOf(list.find(TestItem), 3);
list.setProps({ style: { width: 45 } });
setTimeout(() => {
list.update();
assert.lengthOf(list.find(TestItem), 4);
done();
}, 30);
});

it("shows all after growing", done => {
list = renderOverflowList({ style: { width: 15 } });
assert.lengthOf(list.find(TestItem), 1);
list.setProps({ style: { width: 200 } });
setTimeout(() => {
list.update();
assert.lengthOf(list.find(TestItem), ITEMS.length);
done();
}, 30);
it("shows more after growing", async () => {
// :O it sure reads synchronously
return (await (await overflowList(15)
.assertVisibleItemSplit(1)
.setWidth(35)
.waitForResize())
.assertVisibleItemSplit(3)
.setWidth(200)
.waitForResize()).assertVisibleItems(...IDS);
});

it("shows fewer after shrinking", () => {
list = renderOverflowList({ style: { width: 45 } });
assert.lengthOf(list.find(TestItem), 4);
list.setProps({ style: { width: 15 } });
list.update();
assert.lengthOf(list.find(TestItem), 1);
overflowList(45)
.assertVisibleItemSplit(4)
.setWidth(15)
.assertVisibleItemSplit(1);
});

it("shows at least minVisibleItems", () => {
list = renderOverflowList({ minVisibleItems: 5, style: { width: 15 } });
assert.lengthOf(list.find(TestItem), 5);
overflowList(15, { minVisibleItems: 5 }).assertVisibleItemSplit(5);
});

it("shows more after increasing minVisibleItems", () => {
list = renderOverflowList({ minVisibleItems: 2, style: { width: 35 } });
assert.lengthOf(list.find(TestItem), 3);
list.setProps({ minVisibleItems: 5 });
list.update();
assert.lengthOf(list.find(TestItem), 5);
overflowList(35, { minVisibleItems: 2 })
.assertVisibleItemSplit(3)
.setProps({ minVisibleItems: 5 })
.assertVisibleItemSplit(5);
});

it("does not render the overflow if all items are displayed", () => {
list = renderOverflowList();
assert.lengthOf(list.find(TestOverflow), 0);
overflowList(200).assertHasOverflow(false);
});

it("renders the overflow if not all items are displayed", () => {
list = renderOverflowList({ style: { width: 45 } });
assert.lengthOf(list.find(TestOverflow), 1);
overflowList().assertHasOverflow(true);
});

it("renders overflow items in the correct order (collapse from start)", () => {
list = renderOverflowList({ collapseFrom: "start", style: { width: 45 } });
const overflowItems = list.find(TestOverflow).prop("items");
assert.lengthOf(overflowItems, 2);
assert.strictEqual(overflowItems[0].id, 0);
assert.strictEqual(overflowItems[1].id, 1);
overflowList(45, { collapseFrom: "start" }).assertOverflowItems(0, 1);
});

it("renders overflow items in the correct order (collapse from end)", () => {
list = renderOverflowList({ collapseFrom: "end", style: { width: 45 } });
const overflowItems = list.find(TestOverflow).prop("items");
assert.lengthOf(overflowItems, 2);
assert.strictEqual(overflowItems[0].id, 4);
assert.strictEqual(overflowItems[1].id, 5);
overflowList(45, { collapseFrom: "end" }).assertOverflowItems(4, 5);
});

function renderOverflow(items: ITestItem[]): React.ReactNode {
function renderOverflow(items: ITestItem[]) {
return <TestOverflow items={items} />;
}

function renderItem(_props: {}, index: number) {
return <TestItem key={index} />;
function renderVisibleItem(item: ITestItem, index: number) {
return <TestItem key={index} {...item} />;
}

function renderOverflowList(props?: Partial<IOverflowListProps<{}>>) {
return mount(
function overflowList(initialWidth = 45, props: Partial<OverflowProps> = {}) {
const wrapper = mount<OverflowProps, IOverflowListState<ITestItem>>(
<OverflowList
items={ITEMS}
overflowRenderer={renderOverflow}
visibleItemRenderer={renderItem}
visibleItemRenderer={renderVisibleItem}
style={{ width: initialWidth }}
{...props}
/>,
// measuring elements only works in the DOM, so this element actually needs to be attached
{ attachTo: testsContainerElement },
);
).update();

const harness = {
/** Assert existence of overflow element. */
assertHasOverflow(exists: boolean) {
assert.equal(wrapper.find(TestOverflow).exists(), exists, "has overflow");
return harness;
},
/**
* Invokes both assertions below with the expected visible and
* overflow ids assuming `collapseFrom="start"`.
*/
assertVisibleItemSplit(visibleCount: number) {
return harness
.assertOverflowItems(...IDS.slice(0, -visibleCount))
.assertVisibleItems(...IDS.slice(-visibleCount));
},
/** Assert ordered ids of overflow items. */
assertOverflowItems(...ids: number[]) {
const overflowItems = wrapper.find(TestOverflow).prop("items");
assert.sameMembers(overflowItems.map(it => it.id), ids, "overflow items");
return harness;
},
/** Assert ordered ids of visible items. */
assertVisibleItems(...ids: number[]) {
const visibleItems = wrapper.find(TestItem).map(div => div.prop("id"));
assert.sameMembers(visibleItems, ids, "visible items");
return harness;
},
setProps<K extends keyof OverflowProps>(newProps: Pick<OverflowProps, K>) {
wrapper.setProps(newProps).update();
return harness;
},
setWidth(width: number) {
return harness.setProps({ style: { width } });
},
/** Promise that resolves after DOM has a chance to settle. */
waitForResize() {
return new Promise<typeof harness>(resolve =>
setTimeout(() => {
wrapper.update();
resolve(harness);
}, 30),
);
},
wrapper,
};
return harness;
}
});

1 comment on commit 6fe1ac6

@blueprint-bot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refactor OL tests to use a sweet harness (#2981)

Previews: documentation | landing | table

Please sign in to comment.