A Karma plugin for testing responsive features and layout
npx @tessl/cli install tessl/npm-karma-viewport@1.0.00
# karma-viewport
1
2
karma-viewport is a Karma plugin for testing responsive features and layout. It provides a global `viewport` object that allows tests to dynamically resize iframe dimensions, configure named breakpoints for different screen sizes, and iterate through multiple viewport configurations during test execution.
3
4
## Package Information
5
6
- **Package Name**: karma-viewport
7
- **Package Type**: npm
8
- **Language**: TypeScript
9
- **Installation**: `npm install karma-viewport`
10
11
## Core Imports
12
13
karma-viewport is a Karma plugin, so it doesn't use traditional imports for the main functionality. Instead, you configure it in your Karma configuration file and access the global `viewport` object in your tests.
14
15
For advanced usage, you can import utility functions:
16
17
```typescript
18
import { range, Viewport, ViewportConfiguration } from "karma-viewport";
19
```
20
21
### Karma Configuration
22
23
```javascript
24
// karma.conf.js
25
module.exports = function(config) {
26
config.set({
27
frameworks: ["viewport"],
28
29
// Optional viewport configuration
30
viewport: {
31
context: "#context", // iframe selector (default)
32
breakpoints: [
33
{
34
name: "mobile",
35
size: { width: 320, height: 480 }
36
},
37
{
38
name: "tablet",
39
size: { width: 768, height: 1024 }
40
},
41
{
42
name: "desktop",
43
size: { width: 1440, height: 900 }
44
}
45
]
46
}
47
});
48
};
49
```
50
51
### TypeScript Support
52
53
```typescript
54
/// <reference types="karma-viewport" />
55
```
56
57
## Basic Usage
58
59
```javascript
60
// Test file - viewport is available globally
61
describe("responsive layout", () => {
62
63
beforeEach(() => {
64
viewport.reset(); // Reset to default size
65
});
66
67
it("should work on mobile", () => {
68
viewport.set(320, 480); // Set specific dimensions
69
// Test mobile layout...
70
});
71
72
it("should work on tablet", () => {
73
viewport.set("tablet"); // Use named breakpoint
74
// Test tablet layout...
75
});
76
77
it("should test all breakpoints", () => {
78
viewport.each(name => {
79
// This runs for each configured breakpoint
80
console.log(`Testing ${name} viewport`);
81
// Test layout for current viewport...
82
});
83
});
84
});
85
```
86
87
## Capabilities
88
89
### Viewport Resizing
90
91
Core functionality for setting viewport dimensions using either pixel values or named breakpoints.
92
93
```typescript { .api }
94
/**
95
* Set viewport to specific width and optional height
96
* @param width - Width in pixels
97
* @param height - Optional height in pixels
98
*/
99
set(width: number, height?: number): void;
100
101
/**
102
* Set viewport to named breakpoint
103
* @param breakpoint - Name of configured breakpoint
104
*/
105
set(breakpoint: string): void;
106
107
/**
108
* Reset viewport to default size (100% x 100%)
109
*/
110
reset(): void;
111
```
112
113
### Document Loading
114
115
Load external HTML documents into the viewport iframe for testing complete pages.
116
117
```typescript { .api }
118
/**
119
* Load and embed document into viewport
120
* @param url - URL of document to load
121
* @param cb - Optional callback function called after load completes
122
* @returns Promise resolving with no result when load completes
123
*/
124
load(url: string, cb?: () => void): Promise<void>;
125
```
126
127
### Scroll Control
128
129
Control the scroll position within the viewport iframe.
130
131
```typescript { .api }
132
/**
133
* Change viewport scroll offset
134
* @param x - Horizontal offset in pixels
135
* @param y - Vertical offset in pixels (default: 0)
136
*/
137
offset(x: number, y?: number): void;
138
```
139
140
### Breakpoint Iteration
141
142
Execute test code across multiple viewport sizes using configured breakpoints.
143
144
```typescript { .api }
145
/**
146
* Execute callback for all configured breakpoints
147
* @param cb - Callback function receiving breakpoint name
148
* @returns Promise if callback returns Promise, void otherwise
149
*/
150
each<T>(cb: ViewportCallback<T>): void | Promise<void>;
151
152
/**
153
* Execute callback for breakpoints starting from specified breakpoint
154
* @param first - First breakpoint name
155
* @param cb - Callback function receiving breakpoint name
156
* @returns Promise if callback returns Promise, void otherwise
157
*/
158
from<T>(first: string, cb: ViewportCallback<T>): void | Promise<void>;
159
160
/**
161
* Execute callback for breakpoints up to specified breakpoint
162
* @param last - Last breakpoint name
163
* @param cb - Callback function receiving breakpoint name
164
* @returns Promise if callback returns Promise, void otherwise
165
*/
166
to<T>(last: string, cb: ViewportCallback<T>): void | Promise<void>;
167
168
/**
169
* Execute callback for breakpoints between two specified breakpoints (inclusive)
170
* @param first - First breakpoint name
171
* @param last - Last breakpoint name
172
* @param cb - Callback function receiving breakpoint name
173
* @returns Promise if callback returns Promise, void otherwise
174
*/
175
between<T>(first: string, last: string, cb: ViewportCallback<T>): void | Promise<void>;
176
```
177
178
**Iteration Examples:**
179
180
```javascript
181
// Test all breakpoints
182
viewport.each(name => {
183
console.log(`Testing ${name}`);
184
// Test logic here
185
});
186
187
// Test from tablet onwards
188
viewport.from("tablet", name => {
189
// Tests tablet, desktop, etc.
190
});
191
192
// Test up to tablet
193
viewport.to("tablet", name => {
194
// Tests mobile, tablet
195
});
196
197
// Test specific range
198
viewport.between("tablet", "desktop", name => {
199
// Tests tablet, desktop
200
});
201
202
// Async support
203
viewport.each(async name => {
204
await someAsyncTest();
205
});
206
```
207
208
## Configuration
209
210
### Viewport Configuration
211
212
Configure the plugin behavior in your Karma configuration file.
213
214
```typescript { .api }
215
interface ViewportConfiguration {
216
/** Context element selector (default: "#context") */
217
context: string;
218
/** Array of named breakpoints */
219
breakpoints: ViewportBreakpoint[];
220
}
221
222
interface ViewportBreakpoint {
223
/** Breakpoint name */
224
name: string;
225
/** Viewport dimensions */
226
size: {
227
width: number;
228
height: number;
229
};
230
}
231
```
232
233
### Utility Functions
234
235
Utility functions exported by the karma-viewport module for advanced usage.
236
237
```typescript { .api }
238
/**
239
* Resolve relevant breakpoint range between two breakpoints
240
* @param breakpoints - Array of viewport breakpoints
241
* @param first - First breakpoint name
242
* @param last - Last breakpoint name (defaults to first)
243
* @returns Array of breakpoints in the specified range
244
* @throws ReferenceError if breakpoint name is invalid
245
*/
246
function range(
247
breakpoints: ViewportBreakpoint[],
248
first: string,
249
last?: string
250
): ViewportBreakpoint[];
251
```
252
253
## Types
254
255
```typescript { .api }
256
/**
257
* Callback function type for viewport iteration methods
258
*/
259
type ViewportCallback<T> = (breakpoint: string) => T;
260
261
/**
262
* Main Viewport class - available as global 'viewport' instance
263
*/
264
class Viewport {
265
/** Viewport configuration (read-only) */
266
readonly config: Readonly<ViewportConfiguration>;
267
/** Target iframe element */
268
readonly context: HTMLIFrameElement;
269
270
/**
271
* Create viewport resizer
272
* @param config - Viewport configuration
273
* @param parent - Initialization context (window)
274
* @throws ReferenceError if context selector doesn't match HTMLIFrameElement
275
*/
276
constructor(config: ViewportConfiguration, parent: Window);
277
278
/** Set viewport to specific dimensions */
279
set(width: number, height?: number): void;
280
/** Set viewport to named breakpoint */
281
set(breakpoint: string): void;
282
/** Reset viewport to default size */
283
reset(): void;
284
/** Load and embed document into viewport */
285
load(url: string, cb?: () => void): Promise<void>;
286
/** Change viewport scroll offset */
287
offset(x: number, y?: number): void;
288
/** Execute callback for all breakpoints */
289
each<T>(cb: ViewportCallback<T>): void | Promise<void>;
290
/** Execute callback starting from specified breakpoint */
291
from<T>(first: string, cb: ViewportCallback<T>): void | Promise<void>;
292
/** Execute callback up to specified breakpoint */
293
to<T>(last: string, cb: ViewportCallback<T>): void | Promise<void>;
294
/** Execute callback between two specified breakpoints */
295
between<T>(first: string, last: string, cb: ViewportCallback<T>): void | Promise<void>;
296
}
297
298
/**
299
* Global viewport instance declaration
300
*/
301
declare const viewport: Viewport;
302
```
303
304
## Error Handling
305
306
karma-viewport performs extensive parameter validation and throws specific errors:
307
308
```typescript { .api }
309
/**
310
* Common errors thrown by karma-viewport
311
*/
312
313
// Invalid breakpoint name in set(), each(), from(), to(), between() methods
314
ReferenceError: `Invalid breakpoint: ${inspect(name)}`
315
316
// Invalid context selector during initialization
317
ReferenceError: `No match for selector: ${inspect(config.context)}`
318
319
// Invalid viewport width (must be positive number)
320
TypeError: `Invalid breakpoint width: ${width}`
321
322
// Invalid viewport height (must be positive number or undefined)
323
TypeError: `Invalid breakpoint height: ${height}`
324
325
// Invalid viewport configuration object
326
TypeError: `Invalid viewport configuration: ${viewport}`
327
328
// Configuration validation errors (uses jsonschema validation)
329
TypeError: `Invalid viewport configuration: ${result.errors[0].stack}`
330
331
// Karma iframe configuration requirement
332
Error: "Invalid configuration: client.useIframe must be set to true or a different context selector must be given"
333
```
334
335
**Parameter Validation Rules:**
336
- Viewport width must be a positive number > 0
337
- Viewport height must be a positive number > 0 or undefined
338
- Breakpoint names must exist in the configuration
339
- Context selector must match an existing HTMLIFrameElement
340
- Configuration must pass JSON schema validation
341
342
## Browser Compatibility
343
344
- Chrome
345
- Firefox
346
- Safari
347
- Edge 13-15
348
- IE 9-11
349
350
**Requirements:**
351
- Karma must be configured with `client.useIframe: true` when using default context
352
- The context iframe element must exist in the test environment