Skip to content

Commit 2aa5ded

Browse files
author
Nir Maoz
authored
test: add vue3 responsive tests (#160)
1 parent 24dba96 commit 2aa5ded

3 files changed

Lines changed: 230 additions & 0 deletions

File tree

packages/vue3/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
"@cloudinary/html": "^1.0.1",
2525
"@cloudinary/url-gen": "^1.8.0",
2626
"@rollup/plugin-replace": "^4.0.0",
27+
"@sinonjs/fake-timers": "^9.1.2",
2728
"@types/jest": "^27.0.1",
29+
"@types/sinonjs__fake-timers": "^8.1.2",
2830
"@typescript-eslint/eslint-plugin": "^5.4.0",
2931
"@typescript-eslint/parser": "^5.4.0",
3032
"@vue/cli-plugin-babel": "~5.0.0",
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
import { AdvancedImage, lazyload, responsive } from "../../src/index";
2+
import { CloudinaryImage } from "@cloudinary/url-gen/assets/CloudinaryImage";
3+
import { mount } from "@vue/test-utils";
4+
import { waitTicks } from "./utils";
5+
import FakeTimers from "@sinonjs/fake-timers";
6+
import { dispatchResize } from "../../../../testUtils/dispatchResize";
7+
import { crop } from "@cloudinary/url-gen/actions/resize";
8+
9+
const cloudinaryImage = new CloudinaryImage(
10+
"sample",
11+
{ cloudName: "demo" },
12+
{ analytics: false }
13+
);
14+
15+
const waitForResize = async (
16+
clock: FakeTimers.InstalledClock,
17+
size: number
18+
) => {
19+
// Wait for plugins to finish
20+
await waitTicks(1);
21+
22+
dispatchResize(
23+
(document.getElementById("wrapper") as HTMLDivElement)
24+
.firstChild as HTMLDivElement,
25+
size
26+
);
27+
28+
// Wait for resize event
29+
await clock.tickAsync(100);
30+
};
31+
32+
describe("responsive", () => {
33+
// We are using clock to wait for events
34+
let clock: FakeTimers.InstalledClock;
35+
beforeEach(() => {
36+
clock = FakeTimers.install();
37+
38+
const rootDiv = document.createElement("div");
39+
rootDiv.id = "wrapper";
40+
document.body.appendChild(rootDiv);
41+
});
42+
afterEach(() => {
43+
clock.uninstall();
44+
45+
const wrapper = document.getElementById("wrapper");
46+
if (wrapper) {
47+
wrapper.remove();
48+
}
49+
});
50+
51+
it("should apply initial container width (default 250)", async () => {
52+
const component = mount(AdvancedImage, {
53+
props: { cldImg: cloudinaryImage, plugins: [responsive()] },
54+
attachTo: "#wrapper",
55+
});
56+
57+
await waitForResize(clock, 250);
58+
59+
expect(component.html()).toContain(
60+
"https://res.cloudinary.com/demo/image/upload/c_scale,w_250/sample"
61+
);
62+
});
63+
64+
it("Should respect single step and ignore default width of 250 (When Step < Width)", async () => {
65+
const component = mount(AdvancedImage, {
66+
props: { cldImg: cloudinaryImage, plugins: [responsive({ steps: 100 })] },
67+
attachTo: "#wrapper",
68+
});
69+
70+
await waitForResize(clock, 250);
71+
72+
// Output is exactly 300 due to internal rounding: ROUND_UP(CONTAINER / STEP) * STEP
73+
// When STEP < CONTAINER, output is always a multiplication of STEP
74+
expect(component.html()).toContain(
75+
'src="https://res.cloudinary.com/demo/image/upload/c_scale,w_300/sample"'
76+
);
77+
});
78+
79+
it("Should respect single step and ignore default width of 250 (When Step > Width)", async function () {
80+
const component = mount(AdvancedImage, {
81+
props: { cldImg: cloudinaryImage, plugins: [responsive({ steps: 251 })] },
82+
attachTo: "#wrapper",
83+
});
84+
85+
await waitForResize(clock, 250);
86+
87+
// Output is exactly 251 due to internal rounding: ROUND_UP(CONTAINER / STEP) * STEP
88+
// When STEP > CONTAINER, output is always STEP.
89+
expect(component.html()).toContain(
90+
'src="https://res.cloudinary.com/demo/image/upload/c_scale,w_251/sample"'
91+
);
92+
});
93+
94+
it("Should respect steps and ignore default width of 250", async function () {
95+
const component = mount(AdvancedImage, {
96+
props: {
97+
cldImg: cloudinaryImage,
98+
plugins: [responsive({ steps: [10, 20, 30] })],
99+
},
100+
attachTo: "#wrapper",
101+
});
102+
103+
await waitForResize(clock, 250);
104+
105+
// Output is closest number to parentElement, never exceeding the width of the max step )
106+
expect(component.html()).toContain(
107+
'src="https://res.cloudinary.com/demo/image/upload/c_scale,w_30/sample"'
108+
);
109+
});
110+
111+
it("should update container width on window resize", async () => {
112+
const component = mount(AdvancedImage, {
113+
props: {
114+
cldImg: cloudinaryImage,
115+
plugins: [responsive()],
116+
},
117+
attachTo: "#wrapper",
118+
});
119+
120+
await waitForResize(clock, 100);
121+
122+
// Output is closest number to parentElement, never exceeding the width of the max step )
123+
expect(component.html()).toContain(
124+
'src="https://res.cloudinary.com/demo/image/upload/c_scale,w_100/sample"'
125+
);
126+
});
127+
128+
it("should step by the 100th", async () => {
129+
const component = mount(AdvancedImage, {
130+
props: {
131+
cldImg: cloudinaryImage,
132+
plugins: [responsive({ steps: 100 })],
133+
},
134+
attachTo: "#wrapper",
135+
});
136+
137+
await waitForResize(clock, 250);
138+
139+
// Output is closest number to parentElement, never exceeding the width of the max step )
140+
expect(component.html()).toContain(
141+
'src="https://res.cloudinary.com/demo/image/upload/c_scale,w_300/sample"'
142+
);
143+
});
144+
145+
it("should step by breakpoints", async function () {
146+
const component = mount(AdvancedImage, {
147+
props: {
148+
cldImg: cloudinaryImage,
149+
plugins: [responsive({ steps: [800, 1000, 1200, 3000] })],
150+
},
151+
attachTo: "#wrapper",
152+
});
153+
154+
await waitForResize(clock, 250);
155+
156+
// Output is closest number to parentElement, never exceeding the width of the max step )
157+
expect(component.html()).toContain(
158+
'src="https://res.cloudinary.com/demo/image/upload/c_scale,w_800/sample"'
159+
);
160+
161+
await waitForResize(clock, 975);
162+
163+
expect(component.html()).toContain(
164+
'src="https://res.cloudinary.com/demo/image/upload/c_scale,w_1000/sample"'
165+
);
166+
});
167+
168+
it("should not resize to larger than provided breakpoints", async function () {
169+
const component = mount(AdvancedImage, {
170+
props: {
171+
cldImg: cloudinaryImage,
172+
plugins: [responsive({ steps: [800, 1000, 1200, 3000] })],
173+
},
174+
attachTo: "#wrapper",
175+
});
176+
177+
await waitForResize(clock, 4000);
178+
179+
expect(component.html()).toContain(
180+
'src="https://res.cloudinary.com/demo/image/upload/c_scale,w_3000/sample"'
181+
);
182+
});
183+
184+
it("should handle unordered breakpoints", async function () {
185+
const component = mount(AdvancedImage, {
186+
props: {
187+
cldImg: cloudinaryImage,
188+
plugins: [responsive({ steps: [1000, 800, 3000, 1200] })],
189+
},
190+
attachTo: "#wrapper",
191+
});
192+
193+
await waitForResize(clock, 5000);
194+
195+
expect(component.html()).toContain(
196+
'src="https://res.cloudinary.com/demo/image/upload/c_scale,w_3000/sample"'
197+
);
198+
});
199+
200+
it("should append to existing transformation", async function () {
201+
cloudinaryImage.resize(crop("500"));
202+
203+
const component = mount(AdvancedImage, {
204+
props: {
205+
cldImg: cloudinaryImage,
206+
plugins: [responsive()],
207+
},
208+
attachTo: "#wrapper",
209+
});
210+
211+
await waitForResize(clock, 250);
212+
213+
expect(component.html()).toContain(
214+
'src="https://res.cloudinary.com/demo/image/upload/c_crop,w_500/c_scale,w_250/sample"'
215+
);
216+
});
217+
});

testUtils/dispatchResize.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* Util function used to dispatch a resize event used in the responsive tests
3+
* @param component
4+
* @param resizeValue
5+
*/
6+
export function dispatchResize(component: HTMLDivElement, resizeValue:number){
7+
Object.defineProperty(component, 'clientWidth', {value: resizeValue, configurable: true});
8+
window.dispatchEvent(new Event('resize'));
9+
10+
return component;
11+
}

0 commit comments

Comments
 (0)