Skip to content

Commit

Permalink
step tests
Browse files Browse the repository at this point in the history
  • Loading branch information
binrysearch committed Jun 23, 2024
1 parent 06680d3 commit c7b62f3
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 67 deletions.
114 changes: 60 additions & 54 deletions src/packages/tour/steps.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { fetchSteps, nextStep, previousStep } from "./steps";
import _showElement from "./showElement";
import { appendMockSteps, getMockSteps, getMockTour } from "./tests/mock";
import { appendMockSteps, getMockPartialSteps, getMockSteps, getMockTour } from "./tests/mock";
import createElement from "../../util/createElement";

jest.mock("./showElement");
Expand Down Expand Up @@ -51,6 +51,7 @@ describe("steps", () => {
const showElementMock = jest.fn();
(_showElement as jest.Mock).mockImplementation(showElementMock);
const mockTour = getMockTour();
mockTour.setSteps(getMockSteps());

// Act
await nextStep(mockTour);
Expand All @@ -62,6 +63,7 @@ describe("steps", () => {
test("should call the onBeforeChange callback", async () => {
// Arrange
const mockTour = getMockTour();
mockTour.setSteps(getMockSteps());
const fnBeforeChangeCallback = jest.fn();
mockTour.onBeforeChange(fnBeforeChangeCallback);

Expand All @@ -72,7 +74,7 @@ describe("steps", () => {
expect(fnBeforeChangeCallback).toHaveBeenCalledTimes(1);
expect(fnBeforeChangeCallback).toHaveBeenCalledWith(
undefined,
1,
0,
"forward"
);
});
Expand All @@ -85,7 +87,7 @@ describe("steps", () => {
const fnBeforeChangeCallback = jest.fn();
fnBeforeChangeCallback.mockReturnValue(false);

mockTour.onbeforechange(fnBeforeChangeCallback);
mockTour.onBeforeChange(fnBeforeChangeCallback);

// Act
await nextStep(mockTour);
Expand All @@ -98,13 +100,14 @@ describe("steps", () => {
test("should wait for the onBeforeChange promise object", async () => {
// Arrange
const mockTour = getMockTour();
mockTour.setSteps(getMockSteps());
const showElementMock = jest.fn();
(_showElement as jest.Mock).mockImplementation(showElementMock);

const onBeforeChangeMock = jest.fn();
const sideEffect: number[] = [];

mockTour.onbeforechange(async () => {
mockTour.onBeforeChange(async () => {
return new Promise<boolean>((res) => {
setTimeout(() => {
sideEffect.push(1);
Expand All @@ -127,12 +130,14 @@ describe("steps", () => {
test("should call the complete callback", async () => {
// Arrange
const mockTour = getMockTour();
mockTour.setSteps(getMockSteps().slice(0, 2));
const fnCompleteCallback = jest.fn();
mockTour.oncomplete(fnCompleteCallback);
mockTour.onComplete(fnCompleteCallback);

// Act
await nextStep(mockTour);
await nextStep(mockTour);
await nextStep(mockTour);

// Assert
expect(fnCompleteCallback).toBeCalledTimes(1);
Expand Down Expand Up @@ -189,62 +194,88 @@ describe("steps", () => {
const steps = fetchSteps(mockTour);

// Assert
expect(steps.length).toBe(4);
expect(steps.length).toBe(5);

expect(steps[0].position).toBe("floating");
expect(steps[0].title).toBe("Floating title 1");
expect(steps[0].intro).toBe("Step One of the tour");
expect(steps[0].step).toBe(1);

expect(steps[1].position).toBe("floating");
expect(steps[1].title).toBe("Floating title 2");
expect(steps[1].intro).toBe("Step Two of the tour");
expect(steps[1].step).toBe(2);
});

test("should find and add elements from options.steps to the list", () => {
// Arrange
document.body.appendChild(createElement("h1"));

const mockTour = getMockTour();
const [mockStepOneElement, mockStepTwoElement, _, __] = appendMockSteps();
mockTour.addSteps(getMockPartialSteps());

// Act
const steps = fetchSteps(mockTour);

// Assert
expect(steps.length).toBe(7);
expect(steps.length).toBe(5);

expect(steps[0].element).toBe(mockStepOneElement);
expect(steps[0].position).toBe("bottom");
expect(steps[0].intro).toBe("first");
expect(steps[0].position).toBe("floating");
expect(steps[0].title).toBe("Floating title 1");
expect(steps[0].intro).toBe("Step One of the tour");
expect(steps[0].step).toBe(1);

expect(steps[1].element).toBe(mockStepTwoElement);
expect(steps[1].position).toBe("top");
expect(steps[1].intro).toBe("second");
expect(steps[1].position).toBe("floating");
expect(steps[1].title).toBe("Floating title 2");
expect(steps[1].intro).toBe("Step Two of the tour");
expect(steps[1].step).toBe(2);

expect(steps[2].position).toBe("floating");
expect(steps[2].intro).toBe("third");
expect(steps[2].position).toBe("top");
expect(steps[2].title).toBe("First title");
expect(steps[2].intro).toBe("Step Three of the tour");
expect(steps[2].step).toBe(3);

expect(steps[3].element).toStrictEqual(getMockPartialSteps()[3].element);
expect(steps[3].position).toBe("right");
expect(steps[3].intro).toBe("Step Four of the tour");
expect(steps[3].step).toBe(4);

expect(steps[4].position).toBe("floating");
expect(steps[4].intro).toBe("Element not found");
expect(steps[4].step).toBe(5);
});

test("should find the data-* elements from the DOM", () => {
test("should find the data-* elements from the DOM with the correct order", () => {
// Arrange
const targetElement = createElement("div");
appendMockSteps(targetElement);
const [mockElementOne, mockElementTwo, mockElementThree, mockElementFour] = appendMockSteps(targetElement);
const mockTour = getMockTour(targetElement);

// Act
const steps = fetchSteps(mockTour);

// Assert
expect(steps.length).toBe(2);
expect(steps.length).toBe(4);

expect(steps[0].position).toBe("bottom");
expect(steps[0].intro).toBe("first");
expect(steps[0].intro).toBe("Mock element");
expect(steps[0].element).toBe(mockElementOne);
expect(steps[0].step).toBe(1);

expect(steps[1].position).toBe("left");
expect(steps[1].intro).toBe("second");
expect(steps[1].intro).toBe("Mock element left position");
expect(steps[1].element).toBe(mockElementTwo);
expect(steps[1].step).toBe(2);

expect(steps[2].position).toBe("bottom");
expect(steps[2].intro).toBe("Mock element second to last");
expect(steps[2].element).toBe(mockElementThree);
expect(steps[2].step).toBe(10);

expect(steps[3].position).toBe("bottom");
expect(steps[3].intro).toBe("Mock element last");
expect(steps[3].element).toBe(mockElementFour);
expect(steps[3].step).toBe(20);
});

test("should respect the custom step attribute (DOM)", () => {
Expand All @@ -257,13 +288,13 @@ describe("steps", () => {
const steps = fetchSteps(mockTour);

// Assert
expect(steps.length).toBe(2);
expect(steps.length).toBe(4);

expect(steps[0].intro).toBe("first");
expect(steps[0].step).toBe(1);
expect(steps[2].intro).toBe("Mock element second to last");
expect(steps[2].step).toBe(10);

expect(steps[1].intro).toBe("second");
expect(steps[1].step).toBe(5);
expect(steps[3].intro).toBe("Mock element last");
expect(steps[3].step).toBe(20);
});

test("should ignore DOM elements when options.steps is available", () => {
Expand All @@ -276,34 +307,9 @@ describe("steps", () => {
const steps = fetchSteps(mockTour);

// Assert
expect(steps.length).toBe(2);
expect(steps[0].intro).toBe("steps-first");
expect(steps[1].intro).toBe("steps-second");
});

it("should correctly sort based on data-step", () => {
// Arrange
const targetElement = document.createElement("div");
appendMockSteps(targetElement);
const mockTour = getMockTour(targetElement);

// Act
const steps = fetchSteps(mockTour);

// Assert
expect(steps.length).toBe(4);

expect(steps[0].intro).toBe("one");
expect(steps[0].step).toBe(1);

expect(steps[1].intro).toBe("two");
expect(steps[1].step).toBe(2);

expect(steps[2].intro).toBe("three");
expect(steps[2].step).toBe(3);

expect(steps[3].intro).toBe("four");
expect(steps[3].step).toBe(5);
expect(steps.length).toBe(5);
expect(steps[0].intro).toBe("Step One of the tour");
expect(steps[1].intro).toBe("Step Two of the tour");
});
});
});
4 changes: 3 additions & 1 deletion src/packages/tour/steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,9 @@ export const fetchSteps = (tour: Tour) => {
}
}
} else {
const elements = Array.from(queryElements(`*[${dataIntroAttribute}]`));
const elements = Array.from(
queryElements(`*[${dataIntroAttribute}]`, tour.getTargetElement())
);

// if there's no element to intro
if (elements.length < 1) {
Expand Down
58 changes: 51 additions & 7 deletions src/packages/tour/tests/mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ export const appendMockSteps = (targetElement: HTMLElement = document.body) => {
mockElementTwo.setAttribute(dataIntroAttribute, "Mock element left position");
mockElementTwo.setAttribute(dataPosition, "left");

const mockElementThree = createElement("a");
mockElementThree.setAttribute(dataIntroAttribute, "Mock element last");
mockElementThree.setAttribute(dataStepAttribute, "20");
const mockElementThree = createElement("h1");
mockElementThree.setAttribute(dataIntroAttribute, "Mock element second to last");
mockElementThree.setAttribute(dataStepAttribute, "10");

const mockElementFour = createElement("h1");
mockElementFour.setAttribute(dataIntroAttribute, "Mock element second to last");
mockElementFour.setAttribute(dataStepAttribute, "10");
const mockElementFour = createElement("a");
mockElementFour.setAttribute(dataIntroAttribute, "Mock element last");
mockElementFour.setAttribute(dataStepAttribute, "20");

targetElement.appendChild(mockElementOne);
targetElement.appendChild(mockElementTwo);
Expand All @@ -31,7 +31,7 @@ export const appendMockSteps = (targetElement: HTMLElement = document.body) => {
return [mockElementOne, mockElementTwo, mockElementThree, mockElementFour];
};

export const getMockSteps = (): Partial<TourStep>[] => {
export const getMockPartialSteps = (): Partial<TourStep>[] => {
return [
{
title: "Floating title 1",
Expand All @@ -46,6 +46,7 @@ export const getMockSteps = (): Partial<TourStep>[] => {
intro: "Step Three of the tour",
position: "top",
scrollTo: "tooltip",
element: "h1",
},
{
intro: "Step Four of the tour",
Expand All @@ -60,6 +61,49 @@ export const getMockSteps = (): Partial<TourStep>[] => {
];
};

export const getMockSteps = (): TourStep[] => {
return [
{
step: 1,
scrollTo: "tooltip",
position: "bottom",
title: "Floating title 1",
intro: "Step One of the tour",
},
{
step: 2,
scrollTo: "tooltip",
position: "bottom",
title: "Floating title 2",
intro: "Step Two of the tour",
},
{
step: 3,
position: "top",
scrollTo: "tooltip",
title: "First title",
intro: "Step Three of the tour",
},
{
step: 4,
position: "right",
scrollTo: "off",
title: "",
intro: "Step Four of the tour",
element: document.createElement("div"),
},
{
step: 5,
position: "right",
scrollTo: "off",
title: "",
intro: "Element not found",
element: ".not-found",
},
];
};


export const getMockTour = (targetElement: HTMLElement = document.body) => {
return new Tour(targetElement);
};
24 changes: 19 additions & 5 deletions src/packages/tour/tour.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ export class Tour implements Package<TourOptions> {
return this;
}

/**
* Add a step to the tour options.
* This method should be used in conjunction with the `render()` method.
* @param step Partial<TourStep>
*/
addStep(step: Partial<TourStep>) {
if (!this._options.steps) {
this._options.steps = [];
Expand All @@ -91,6 +96,11 @@ export class Tour implements Package<TourOptions> {
return this;
}

/**
* Add multiple steps to the tour options.
* This method should be used in conjunction with the `render()` method.
* @param steps Partial<TourStep>[]
*/
addSteps(steps: Partial<TourStep>[]) {
if (!steps.length) return this;

Expand All @@ -101,6 +111,15 @@ export class Tour implements Package<TourOptions> {
return this;
}

/**
* Set the steps of the tour
* @param steps TourStep[]
*/
setSteps(steps: TourStep[]): this {
this._steps = steps;
return this;
}

getSteps(): TourStep[] {
return this._steps;
}
Expand Down Expand Up @@ -172,11 +191,6 @@ export class Tour implements Package<TourOptions> {
return this._options[key];
}

setSteps(steps: TourStep[]): this {
this._steps = steps;
return this;
}

clone(): ThisType<this> {
return new Tour(this._targetElement);
}
Expand Down

0 comments on commit c7b62f3

Please sign in to comment.