## DEV Community

Nicolas DUBIEN

Posted on • Updated on

# Advent of PBT 2021 - Day 14 - Solution

Our algorithm was: reorderTabs.
Go to the subject itself for more details

CodeSandbox with a possible set of properties you may have come with: https://codesandbox.io/s/advent-of-pbt-day-14-solution-ng2b?file=/src/index.spec.ts&previewwindow=tests

For this algorithm I chose to generate the entries requested by the algorithm and not try to build them from intermediate inputs. In other words, I will re-use the same arbitrary in all the properties and check whether or not the algorithm does what it says as checking it did it is simpler than doing it.

The arbitrary we will re-use over and over for this algorithm is:

``````function tabsWithSelectionArb() {
return fc
.set(fc.nat(), { minLength: 2 })
.chain((tabs) =>
fc.record({
tabs: fc.constant(tabs),
selectedTabs: fc.subarray(tabs, {
minLength: 1,
maxLength: tabs.length - 1
})
})
)
.chain(({ tabs, selectedTabs }) =>
fc.record({
tabs: fc.constant(tabs),
selectedTabs: fc.constant(selectedTabs),
movePosition: fc.constantFrom(
...tabs.filter((t) => !selectedTabs.includes(t))
)
})
);
}
``````

It just computes three valid and mutually compatible values for `tabs`, `selectedTabs` and `movePosition`.

Now we have it, let's see which properties we could create thanks to it.

## Property 1: should group selected tabs together

for any constraints
it should move the selected tabs close to each others
in other words we should not have any other tabs between them after the move

Written with fast-check:

``````it("should group selected tabs together", () => {
fc.assert(
fc.property(
tabsWithSelectionArb(),
({ tabs, selectedTabs, movePosition }) => {
// Arrange / Act
const newTabs = reorderTabs(tabs, selectedTabs, movePosition);

// Assert
const startMovedSelection = newTabs.indexOf(selectedTabs[0]);
expect(
newTabs.slice(
startMovedSelection,
startMovedSelection + selectedTabs.length
)
).toEqual(selectedTabs);
}
)
);
});
``````

## Property 2: should insert all the selected tabs before the move position

for any constraints
it should move all the selected tabs before the requested position

Written with fast-check:

``````it("should insert all the selected tabs before the move position", () => {
fc.assert(
fc.property(
tabsWithSelectionArb(),
({ tabs, selectedTabs, movePosition }) => {
// Arrange / Act
const newTabs = reorderTabs(tabs, selectedTabs, movePosition);

// Assert
const movePositionIndex = newTabs.indexOf(movePosition);
for (const selected of selectedTabs) {
const selectedIndex = newTabs.indexOf(selected);
expect(selectedIndex).toBeLessThan(movePositionIndex);
}
}
)
);
});
``````

## Property 3: should not alter non-selected tabs

for any constraints
it should not impact other tabs (non selected ones)

Written with fast-check:

``````it("should not alter non-selected tabs", () => {
fc.assert(
fc.property(
tabsWithSelectionArb(),
({ tabs, selectedTabs, movePosition }) => {
// Arrange / Act
const newTabs = reorderTabs(tabs, selectedTabs, movePosition);

// Assert
expect(newTabs.filter((t) => !selectedTabs.includes(t))).toEqual(
tabs.filter((t) => !selectedTabs.includes(t))
);
}
)
);
});
``````

## Property 4: should not change the list of tabs, just its order

for any constraints
it should not change the list of tabs but just re-order them

Written with fast-check:

``````it("should not change the list of tabs, just its order", () => {
fc.assert(
fc.property(
tabsWithSelectionArb(),
({ tabs, selectedTabs, movePosition }) => {
// Arrange / Act
const newTabs = reorderTabs(tabs, selectedTabs, movePosition);

// Assert
expect([...newTabs].sort()).toEqual([...tabs].sort());
}
)
);
});
``````

Back to "Advent of PBT 2021" to see topics covered during the other days and their solutions.