Skip to content

Commit

Permalink
Merge pull request #51 from trurl-master/dont-error-on-other-envs
Browse files Browse the repository at this point in the history
Remove dependency on window during import time
  • Loading branch information
trurl-master authored Sep 3, 2023
2 parents 684f710 + 9b0dc92 commit 5a9b53b
Show file tree
Hide file tree
Showing 15 changed files with 163 additions and 39 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "jsdom-testing-mocks",
"version": "1.9.0",
"version": "1.10.0",
"author": "Ivan Galiatin",
"license": "MIT",
"description": "A set of tools for emulating browser behavior in jsdom environment",
Expand Down
16 changes: 14 additions & 2 deletions src/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,23 @@ export class UndefinedHookError extends Error {

// @ts-ignore
if (typeof global?.['vi'] !== 'undefined') {
message = `Jsdom Testing Mocks: ${hook} is not defined. You can enable globals in your config or pass the hook manually to the configMocks function`;
message = `jsdom-testing-mocks: ${hook} is not defined. You can enable globals in your config or pass the hook manually to the configMocks function`;
} else {
message = `Jsdom Testing Mocks: ${hook} is not defined. If you need to pass it manually, please use the configMocks function`;
message = `jsdom-testing-mocks: ${hook} is not defined. If you need to pass it manually, please use the configMocks function`;
}

super(message);
}
}

export class WrongEnvironmentError extends Error {
constructor() {
super(
'jsdom-testing-mocks: window is not defined. Please use this library in a browser environment'
);
}
}

export const isJsdomEnv = () => {
return typeof window !== 'undefined';
};
27 changes: 17 additions & 10 deletions src/mocks/MediaQueryListEvent.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
export class MockedMediaQueryListEvent
extends Event
implements MediaQueryListEvent
{
import { isJsdomEnv, WrongEnvironmentError } from '../helper';

class MockedMediaQueryListEvent extends Event implements MediaQueryListEvent {
readonly matches: boolean;
readonly media: string;

Expand All @@ -13,10 +12,18 @@ export class MockedMediaQueryListEvent
}
}

if (typeof MediaQueryListEvent === 'undefined') {
Object.defineProperty(window, 'MediaQueryListEvent', {
writable: true,
configurable: true,
value: MockedMediaQueryListEvent,
});
function mockMediaQueryListEvent() {
if (!isJsdomEnv()) {
throw new WrongEnvironmentError();
}

if (typeof MediaQueryListEvent === 'undefined') {
Object.defineProperty(window, 'MediaQueryListEvent', {
writable: true,
configurable: true,
value: MockedMediaQueryListEvent,
});
}
}

export { MockedMediaQueryListEvent, mockMediaQueryListEvent };
14 changes: 14 additions & 0 deletions src/mocks/intersection-observer.env.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* @jest-environment node
*/

import { WrongEnvironmentError } from '../helper';
import { mockIntersectionObserver } from './intersection-observer';

describe('mockIntersectionObserver', () => {
it('throws an error when used in a non jsdom environment', () => {
expect(() => {
mockIntersectionObserver();
}).toThrowError(WrongEnvironmentError);
});
});
9 changes: 8 additions & 1 deletion src/mocks/intersection-observer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Writable, PartialDeep } from 'type-fest';
import './size/DOMRect';
import { mockDOMRect } from './size/DOMRect';
import { getConfig } from '../tools';
import { isJsdomEnv, WrongEnvironmentError } from '../helper';

const config = getConfig();

Expand Down Expand Up @@ -192,6 +193,12 @@ export class MockedIntersectionObserver implements IntersectionObserver {
}

function mockIntersectionObserver() {
if (!isJsdomEnv()) {
throw new WrongEnvironmentError();
}

mockDOMRect();

const savedImplementation = window.IntersectionObserver;

Object.defineProperty(window, 'IntersectionObserver', {
Expand Down
14 changes: 14 additions & 0 deletions src/mocks/resize-observer.env.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* @jest-environment node
*/

import { WrongEnvironmentError } from '../helper';
import { mockResizeObserver } from './resize-observer';

describe('mockResizeObserver', () => {
it('throws an error when used in a non jsdom environment', () => {
expect(() => {
mockResizeObserver();
}).toThrowError(WrongEnvironmentError);
});
});
14 changes: 8 additions & 6 deletions src/mocks/resize-observer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { RequireAtLeastOne } from 'type-fest';
import { mockDOMRect } from './size/DOMRect';
import { isJsdomEnv, WrongEnvironmentError } from '../helper';
import { getConfig } from '../tools';

const config = getConfig();
Expand Down Expand Up @@ -142,6 +144,12 @@ function elementToEntry(element: HTMLElement): ResizeObserverEntry | null {
}

function mockResizeObserver() {
if (!isJsdomEnv()) {
throw new WrongEnvironmentError();
}

mockDOMRect();

const savedImplementation = window.ResizeObserver;

Object.defineProperty(window, 'ResizeObserver', {
Expand Down Expand Up @@ -290,10 +298,4 @@ function mockResizeObserver() {
};
}

const { mockElementSize } = mockResizeObserver();

mockElementSize(document.body, {
contentBoxSize: [{ blockSize: 100, inlineSize: 100 }],
});

export { mockResizeObserver };
14 changes: 14 additions & 0 deletions src/mocks/size/DOMRect.env.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* @jest-environment node
*/

import { WrongEnvironmentError } from '../../helper';
import { mockDOMRect } from './DOMRect';

describe('mockDOMRect', () => {
it('throws an error when used in a non jsdom environment', () => {
expect(() => {
mockDOMRect();
}).toThrowError(WrongEnvironmentError);
});
});
4 changes: 3 additions & 1 deletion src/mocks/size/DOMRect.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
import './DOMRect';
import { mockDOMRect } from './DOMRect';

mockDOMRect();

describe('DOMRectReadOnly', () => {
test('constructor and props', () => {
Expand Down
38 changes: 24 additions & 14 deletions src/mocks/size/DOMRect.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { isJsdomEnv, WrongEnvironmentError } from '../../helper';

const protectedProps = ['_x', '_y', '_width', '_height'];

class MockedDOMRectReadOnly implements DOMRectReadOnly {
Expand Down Expand Up @@ -107,7 +109,7 @@ class MockedDOMRectReadOnly implements DOMRectReadOnly {
}
}

export class MockedDOMRect extends MockedDOMRectReadOnly implements DOMRect {
class MockedDOMRect extends MockedDOMRectReadOnly implements DOMRect {
constructor(x = 0, y = 0, width = 0, height = 0) {
super(x, y, width, height);
}
Expand Down Expand Up @@ -149,18 +151,26 @@ export class MockedDOMRect extends MockedDOMRectReadOnly implements DOMRect {
}
}

if (typeof DOMRectReadOnly === 'undefined') {
Object.defineProperty(window, 'DOMRectReadOnly', {
writable: true,
configurable: true,
value: MockedDOMRectReadOnly,
});
}
function mockDOMRect() {
if (!isJsdomEnv()) {
throw new WrongEnvironmentError();
}

if (typeof DOMRect === 'undefined') {
Object.defineProperty(window, 'DOMRect', {
writable: true,
configurable: true,
value: MockedDOMRect,
});
if (typeof DOMRectReadOnly === 'undefined') {
Object.defineProperty(window, 'DOMRectReadOnly', {
writable: true,
configurable: true,
value: MockedDOMRectReadOnly,
});
}

if (typeof DOMRect === 'undefined') {
Object.defineProperty(window, 'DOMRect', {
writable: true,
configurable: true,
value: MockedDOMRect,
});
}
}

export { MockedDOMRectReadOnly, MockedDOMRect, mockDOMRect };
4 changes: 3 additions & 1 deletion src/mocks/size/size.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import './DOMRect';
import { mockDOMRect } from './DOMRect';

export const mockElementBoundingClientRect = (
element: HTMLElement,
Expand All @@ -9,6 +9,8 @@ export const mockElementBoundingClientRect = (
height = 0,
}: Partial<Pick<DOMRect, 'x' | 'y' | 'width' | 'height'>>
) => {
mockDOMRect();

const savedImplementation = element.getBoundingClientRect;

element.getBoundingClientRect = () =>
Expand Down
14 changes: 14 additions & 0 deletions src/mocks/viewport.env.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* @jest-environment node
*/

import { WrongEnvironmentError } from '../helper';
import { mockViewport } from './viewport';

describe('mockViewport', () => {
it('throws an error when used in a non jsdom environment', () => {
expect(() => {
mockViewport({ width: 0, height: 0 });
}).toThrowError(WrongEnvironmentError);
});
});
13 changes: 10 additions & 3 deletions src/mocks/viewport.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import mediaQuery, { MediaValues } from 'css-mediaquery';
import './MediaQueryListEvent';
import { mockMediaQueryListEvent } from './MediaQueryListEvent';
import { getConfig } from '../tools';
import { isJsdomEnv, WrongEnvironmentError } from '../helper';

const config = getConfig();

/**
* A tool that allows testing components that use js media queries (matchMedia)
* A tool that allows testing components that use js media queries (matchMedia)
* `mockViewport` must be called before rendering the component
* @example using react testing library
* @example using react testing library
*
* const viewport = mockViewport({ width: '320px', height: '568px' })
*
Expand Down Expand Up @@ -46,6 +47,12 @@ function isEventListenerObject(
}

function mockViewport(desc: ViewportDescription): MockViewport {
if (!isJsdomEnv()) {
throw new WrongEnvironmentError();
}

mockMediaQueryListEvent();

const state: {
currentDesc: ViewportDescription;
oldListeners: {
Expand Down
14 changes: 14 additions & 0 deletions src/mocks/web-animations-api/__tests__/index.env.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* @jest-environment node
*/

import { WrongEnvironmentError } from '../../../helper';
import { mockAnimationsApi } from '../';

describe('mockAnimationsApi', () => {
it('throws an error when used in a non jsdom environment', () => {
expect(() => {
mockAnimationsApi();
}).toThrowError(WrongEnvironmentError);
});
});
5 changes: 5 additions & 0 deletions src/mocks/web-animations-api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
clearAnimations,
} from './elementAnimations';
import { getConfig } from '../../tools';
import { isJsdomEnv, WrongEnvironmentError } from '../../helper';

const config = getConfig();

Expand All @@ -26,6 +27,10 @@ function animate(
}

function mockAnimationsApi() {
if (!isJsdomEnv()) {
throw new WrongEnvironmentError();
}

const savedAnimate = Element.prototype.animate;
const savedGetAnimations = Element.prototype.getAnimations;
const savedGetAllAnimations = Document.prototype.getAnimations;
Expand Down

0 comments on commit 5a9b53b

Please sign in to comment.