Skip to content

Commit 49b52d9

Browse files
committed
tests
1 parent 0f88a8d commit 49b52d9

File tree

8 files changed

+94
-59
lines changed

8 files changed

+94
-59
lines changed

jest.config.js

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ module.exports = {
1717
coverageDirectory: 'coverage',
1818
collectCoverageFrom: [
1919
'src/**/*.{ts,tsx,js,jsx}',
20+
'!src/**/*.cy.ts',
2021
'!src/**/*.d.ts',
2122
'!src/**/*.test.ts',
2223
],

package-lock.json

+6-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/packages/tour/showElement.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,7 @@ export default async function _showElement(tour: Tour, step: TourStep) {
566566
skipTooltipButton.innerHTML = tour.getOption("skipLabel");
567567

568568
skipTooltipButton.onclick = async () => {
569-
if (tour.isEnd()) {
569+
if (tour.isLastStep()) {
570570
await tour
571571
.callback("complete")
572572
?.call(tour, tour.getCurrentStep(), "skip");
@@ -656,7 +656,7 @@ export default async function _showElement(tour: Tour, step: TourStep) {
656656
prevTooltipButton,
657657
tour.getOption("buttonClass"),
658658
previousButtonClassName,
659-
disableInteractionClassName
659+
disabledButtonClassName
660660
);
661661
}
662662
}

src/packages/tour/steps.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export type TourStep = {
2626
intro: string;
2727
tooltipClass?: string;
2828
highlightClass?: string;
29-
element?: HTMLElement | string | null;
29+
element?: Element | HTMLElement | string | null;
3030
position: TooltipPosition;
3131
scrollTo: ScrollTo;
3232
disableInteraction?: boolean;

src/packages/tour/tour.test.ts

+68-30
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
import { queryElementByClassName } from "../../util/queryElement";
12
import {
2-
appendDummyElement,
33
className,
44
content,
55
doneButton,
@@ -8,12 +8,12 @@ import {
88
prevButton,
99
skipButton,
1010
tooltipText,
11+
waitFor,
1112
} from "../../../tests/jest/helper";
1213
import * as dontShowAgain from "./dontShowAgain";
1314
import { getMockPartialSteps, getMockTour } from "./tests/mock";
1415
import { Tour } from "./tour";
15-
16-
const flushPromises = () => new Promise(setImmediate);
16+
import { helperLayerClassName, overlayClassName } from "./classNames";
1717

1818
describe("Tour", () => {
1919
beforeEach(() => {
@@ -46,6 +46,13 @@ describe("Tour", () => {
4646

4747
beforeEach(() => {
4848
mockTour = getMockTour();
49+
50+
document.body.innerHTML = `<div>
51+
<h1 id='title'>Title</h1>
52+
<p id='paragraph'>Paragraph</p>
53+
<div id='position-absolute' style='position: absolute;'>Position Absolute</div>
54+
<div id='position-fixed' style='position: fixed;'>Position Fixed</div>
55+
</div>`;
4956
});
5057

5158
afterEach(async () => {
@@ -113,12 +120,12 @@ describe("Tour", () => {
113120

114121
test("should highlight the target element", async () => {
115122
// Arrange
116-
const p = appendDummyElement();
123+
const mockElement = document.querySelector("#paragraph");
117124
mockTour.setOptions({
118125
steps: [
119126
{
120127
intro: "step one",
121-
element: document.querySelector("p"),
128+
element: mockElement,
122129
},
123130
],
124131
});
@@ -127,18 +134,40 @@ describe("Tour", () => {
127134
await mockTour.start();
128135

129136
// Assert
130-
expect(p.className).toContain("introjs-showElement");
131-
expect(p.className).toContain("introjs-relativePosition");
137+
expect(mockElement?.className).toContain("introjs-showElement");
138+
expect(mockElement?.className).toContain("introjs-relativePosition");
139+
});
140+
141+
test("should remove the container element after exit() is called", async () => {
142+
// Arrange
143+
const mockElement = document.querySelector("#paragraph");
144+
mockTour.setOptions({
145+
steps: [
146+
{
147+
intro: "step one",
148+
element: mockElement,
149+
},
150+
],
151+
});
152+
153+
// Act
154+
await mockTour.start();
155+
await mockTour.exit();
156+
157+
// Assert
158+
expect(mockElement?.className).not.toContain("introjs-showElement");
159+
expect(queryElementByClassName(helperLayerClassName)).toBeNull();
160+
expect(queryElementByClassName(overlayClassName)).toBeNull();
132161
});
133162

134163
test("should not highlight the target element if queryString is incorrect", async () => {
135164
// Arrange
136-
const p = appendDummyElement();
165+
const mockElement = document.querySelector("#non-existing-element");
137166
mockTour.setOptions({
138167
steps: [
139168
{
140169
intro: "step one",
141-
element: document.querySelector("div"),
170+
element: mockElement,
142171
},
143172
],
144173
});
@@ -147,29 +176,19 @@ describe("Tour", () => {
147176
await mockTour.start();
148177

149178
// Assert
150-
expect(p.className).not.toContain("introjs-showElement");
151179
expect(className(".introjs-showElement")).toContain(
152180
"introjsFloatingElement"
153181
);
154182
});
155183

156-
test("should not add relativePosition if target element is fixed or absolute", async () => {
184+
test("should not add relativePosition if target element is fixed", async () => {
157185
// Arrange
158-
const absolute = appendDummyElement(
159-
"h1",
160-
"hello world",
161-
"position: absolute"
162-
);
163-
const fixed = appendDummyElement("h2", "hello world", "position: fixed");
186+
const fixedMockElement = document.querySelector("#position-fixed");
164187
mockTour.setOptions({
165188
steps: [
166189
{
167190
intro: "step one",
168-
element: document.querySelector("h1"),
169-
},
170-
{
171-
intro: "step two",
172-
element: document.querySelector("h2"),
191+
element: fixedMockElement,
173192
},
174193
],
175194
});
@@ -178,13 +197,32 @@ describe("Tour", () => {
178197
await mockTour.start();
179198

180199
// Assert
181-
expect(absolute.className).toContain("introjs-showElement");
182-
expect(absolute.className).not.toContain("introjs-relativePosition");
200+
expect(fixedMockElement?.className).toContain("introjs-showElement");
201+
expect(fixedMockElement?.className).not.toContain(
202+
"introjs-relativePosition"
203+
);
204+
});
205+
206+
test("should not add relativePosition if target element is fixed or absolute", async () => {
207+
// Arrange
208+
const absoluteMockElement = document.querySelector("#position-absolute");
209+
mockTour.setOptions({
210+
steps: [
211+
{
212+
intro: "step one",
213+
element: absoluteMockElement,
214+
},
215+
],
216+
});
183217

184-
await mockTour.nextStep();
218+
// Act
219+
await mockTour.start();
185220

186-
expect(fixed.className).toContain("introjs-showElement");
187-
expect(fixed.className).not.toContain("introjs-relativePosition");
221+
// Assert
222+
expect(absoluteMockElement?.className).toContain("introjs-showElement");
223+
expect(absoluteMockElement?.className).not.toContain(
224+
"introjs-relativePosition"
225+
);
188226
});
189227

190228
test("should call the onstart callback", async () => {
@@ -228,7 +266,7 @@ describe("Tour", () => {
228266
// Act
229267
await mockTour.start();
230268
nextButton().click();
231-
await flushPromises();
269+
await waitFor(1000);
232270

233271
// Assert
234272
expect(onexitMock).toBeCalledTimes(1);
@@ -254,7 +292,7 @@ describe("Tour", () => {
254292
// Act
255293
await mockTour.start();
256294
skipButton().click();
257-
await flushPromises();
295+
await waitFor(1000);
258296

259297
// Assert
260298
expect(onexitMock).toBeCalledTimes(1);
@@ -282,7 +320,7 @@ describe("Tour", () => {
282320
// Act
283321
await mockTour.start();
284322
skipButton().click();
285-
await flushPromises();
323+
await waitFor(1000);
286324

287325
// Assert
288326
expect(onexitMock).toBeCalledTimes(1);

src/packages/tour/tour.ts

+7
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,13 @@ export class Tour implements Package<TourOptions> {
244244
return this.getCurrentStep() >= this._steps.length;
245245
}
246246

247+
/**
248+
* Check if the current step is the last step of the tour
249+
*/
250+
isLastStep(): boolean {
251+
return this.getCurrentStep() === this._steps.length - 1;
252+
}
253+
247254
/**
248255
* Get the target element of the tour
249256
*/

src/util/removeChild.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ export const removeChild = (element: HTMLElement | null) => {
1010
};
1111

1212
export const removeAnimatedChild = async (element: HTMLElement | null) => {
13-
new Promise<void>((resolve) => {
14-
if (!element) return;
13+
if (!element) return;
1514

16-
setStyle(element, {
17-
opacity: "0",
18-
});
15+
setStyle(element, {
16+
opacity: "0",
17+
});
1918

20-
window.setTimeout(() => {
19+
return new Promise<void>((resolve) => {
20+
setTimeout(() => {
2121
try {
2222
// removeChild(..) throws an exception if the child has already been removed (https://developer.mozilla.org/en-US/docs/Web/API/Node/removeChild)
2323
// this try-catch is added to make sure this function doesn't throw an exception if the child has been removed

tests/jest/helper.ts

+3-14
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,6 @@ export function tooltipText() {
5050
return find(".introjs-tooltiptext");
5151
}
5252

53-
export function appendDummyElement(
54-
name?: string,
55-
text?: string,
56-
style?: string
57-
): HTMLElement {
58-
const el = document.createElement(name || "p");
59-
el.innerHTML = text || "hello world";
60-
el.setAttribute("style", style || "");
61-
62-
document.body.appendChild(el);
63-
64-
return el;
65-
}
66-
6753
export function getBoundingClientRectSpy(
6854
width: number,
6955
height: number,
@@ -84,3 +70,6 @@ export function getBoundingClientRectSpy(
8470
} as DOMRect)
8571
);
8672
}
73+
74+
export const waitFor = (timeout: number) =>
75+
new Promise((resolve) => setTimeout(resolve, timeout));

0 commit comments

Comments
 (0)