Skip to content

Commit

Permalink
chore: dotlottie-react tests (#411)
Browse files Browse the repository at this point in the history
  • Loading branch information
theashraf authored Nov 25, 2024
1 parent b616423 commit 1947d7a
Show file tree
Hide file tree
Showing 17 changed files with 4,802 additions and 198 deletions.
16 changes: 14 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,32 @@ jobs:
- name: 💅 Verify format (`pnpm format` committed?)
run: pnpm format

- name: 🛡️ Test
- name: 🛡️ Test (dotlottie-web)
run: |
npx playwright install --with-deps
pnpm test:coverage
working-directory: packages/web

- name: 📏 Report coverage
- name: 🛡️ Test (dotlottie-react)
run: pnpm test:coverage
working-directory: packages/react

- name: 📏 Report dotlottie-web coverage
if: always() && github.event_name == 'pull_request'
uses: davelosert/vitest-coverage-report-action@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
working-directory: packages/web
name: '@lottiefiles/dotlottie-web'

- name: 📏 Report dotlottie-react coverage
if: always() && github.event_name == 'pull_request'
uses: davelosert/vitest-coverage-report-action@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
working-directory: packages/react
name: '@lottiefiles/dotlottie-react'

- name: 📏 Report bundle size
if: github.event_name == 'pull_request'
uses: andresz1/size-limit-action@v1
Expand Down
8 changes: 4 additions & 4 deletions apps/dotlottie-react-example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
"@lottiefiles/dotlottie-react": "workspace:*",
"compression": "^1.7.4",
"express": "^4.19.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"sirv": "^2.0.4"
},
"devDependencies": {
"@types/react": "^18.2.37",
"@types/react-dom": "^18.2.15",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"@typescript-eslint/eslint-plugin": "^6.10.0",
"@typescript-eslint/parser": "^6.10.0",
"@vitejs/plugin-react-swc": "^3.5.0",
Expand Down
8 changes: 4 additions & 4 deletions apps/dotlottie-viewer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
"canvaskit-wasm": "^0.39.1",
"lottie-web": "^5.12.2",
"postcss": "8.4.32",
"react": "^18.2.0",
"react": "^18.0.0",
"react-device-detect": "^2.2.3",
"react-dom": "^18.2.0",
"react-dom": "^18.0.0",
"react-dropzone": "^14.2.3",
"react-icons": "^5.0.1",
"react-range": "^1.8.14",
Expand All @@ -32,8 +32,8 @@
"uuid": "^10.0.0"
},
"devDependencies": {
"@types/react": "^18.2.66",
"@types/react-dom": "^18.2.22",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"@types/uuid": "^10.0.0",
"@typescript-eslint/eslint-plugin": "^7.2.0",
"@typescript-eslint/parser": "^7.2.0",
Expand Down
20 changes: 15 additions & 5 deletions packages/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
"lint": "eslint --fix .",
"stats:eslint": "cross-env TIMING=1 eslint .",
"stats:ts": "tsc -p tsconfig.build.json --extendedDiagnostics",
"test": "vitest run --browser.headless",
"test:coverage": "vitest run --browser.headless --coverage",
"test:watch": "vitest",
"type-check": "tsc --noEmit"
},
"peerDependencies": {
Expand All @@ -48,13 +51,20 @@
"@lottiefiles/dotlottie-web": "workspace:*"
},
"devDependencies": {
"@types/react": "^18.2.37",
"@types/react-dom": "^18.2.15",
"@testing-library/user-event": "^14.5.2",
"@types/react": "^18",
"@types/react-dom": "^18",
"@vitejs/plugin-react": "^4.2.1",
"@vitest/browser": "2.1.0-beta.5",
"@vitest/coverage-istanbul": "2.1.0-beta.5",
"cross-env": "7.0.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"playwright": "^1.45.2",
"react": "^18",
"react-dom": "^18",
"tsup": "8.0.1",
"typescript": "5.0.4"
"typescript": "5.0.4",
"vitest": "2.1.0-beta.5",
"vitest-browser-react": "^0.0.3"
},
"publishConfig": {
"access": "public",
Expand Down
8 changes: 8 additions & 0 deletions packages/react/setup-file.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// eslint-disable-next-line import/no-unassigned-import
import 'vitest-browser-react';

import wasmUrl from '../web/src/core/dotlottie-player.wasm?url';

import { setWasmUrl } from './src';

setWasmUrl(`http://localhost:5173/${wasmUrl}`);
177 changes: 104 additions & 73 deletions packages/react/src/base-dotlottie-react.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client';

import type { Config, DotLottie, DotLottieWorker } from '@lottiefiles/dotlottie-web';
import { useState, useEffect, useCallback, useRef, type ComponentProps, type RefCallback, useMemo } from 'react';
import { useState, useEffect, useCallback, useRef, type ComponentProps, type RefCallback } from 'react';

export type BaseDotLottieProps<T extends DotLottie | DotLottieWorker> = Omit<Config, 'canvas'> &
ComponentProps<'canvas'> & {
Expand Down Expand Up @@ -45,8 +45,25 @@ export type BaseDotLottieProps<T extends DotLottie | DotLottieWorker> = Omit<Con
};

export const BaseDotLottieReact = <T extends DotLottie | DotLottieWorker>({
animationId,
autoplay,
backgroundColor,
className,
createDotLottie,
data,
dotLottieRefCallback,
loop,
mode,
playOnHover,
renderConfig,
segment,
speed,
src,
style,
themeData,
themeId,
useFrameInterpolation,
workerId,
...props
}: BaseDotLottieProps<T> & {
createDotLottie: (config: T extends DotLottieWorker ? Config & { workerId?: string } : Config) => T;
Expand All @@ -55,14 +72,32 @@ export const BaseDotLottieReact = <T extends DotLottie | DotLottieWorker>({
const canvasRef = useRef<HTMLCanvasElement | null>(null);
const dotLottieRef = useRef<T | null>(null);
const dotLottieRefCallbackRef = useRef<RefCallback<T | null> | undefined>(dotLottieRefCallback);
const configRef = useRef<Omit<BaseDotLottieProps<T>, 'createDotLottie' | 'dotLottieRefCallback'> | undefined>(props);

const config: Omit<Config, 'canvas'> & {
workerId?: T extends DotLottieWorker ? string : undefined;
} = {
speed,
mode,
loop,
useFrameInterpolation,
segment,
backgroundColor,
autoplay,
themeId,
workerId,
src,
data,
renderConfig,
};

const configRef = useRef<Omit<BaseDotLottieProps<T>, 'createDotLottie' | 'dotLottieRefCallback'> | undefined>(config);

dotLottieRefCallbackRef.current = dotLottieRefCallback;
dotLottieRef.current = dotLottie;
configRef.current = props;
configRef.current = config;

useEffect(() => {
if (typeof dotLottieRefCallbackRef.current === 'function') {
if (typeof dotLottieRefCallbackRef.current === 'function' && dotLottie) {
dotLottieRefCallbackRef.current(dotLottie);
}
}, [dotLottie]);
Expand All @@ -85,12 +120,14 @@ export const BaseDotLottieReact = <T extends DotLottie | DotLottieWorker>({

useEffect(() => {
const handlePlayOnHover = (event: MouseEvent): void => {
if (!configRef.current?.playOnHover || !dotLottieRef.current?.isLoaded) return;
if (!playOnHover) return;

if (event.type === 'mouseenter') {
dotLottieRef.current.play();
} else if (event.type === 'mouseleave') {
dotLottieRef.current.pause();
dotLottieRef.current?.play();
}

if (event.type === 'mouseleave') {
dotLottieRef.current?.pause();
}
};

Expand All @@ -101,7 +138,7 @@ export const BaseDotLottieReact = <T extends DotLottie | DotLottieWorker>({
canvasRef.current?.removeEventListener('mouseenter', handlePlayOnHover);
canvasRef.current?.removeEventListener('mouseleave', handlePlayOnHover);
};
}, []);
}, [playOnHover]);

useEffect(() => {
return () => {
Expand All @@ -113,101 +150,95 @@ export const BaseDotLottieReact = <T extends DotLottie | DotLottieWorker>({
}, [dotLottie]);

useEffect(() => {
if (!dotLottieRef.current || typeof props.speed !== 'number') return;

dotLottieRef.current.setSpeed(props.speed);
}, [props.speed]);
dotLottieRef.current?.setSpeed(speed ?? 1);
}, [speed]);

useEffect(() => {
if (!dotLottieRef.current || typeof props.mode !== 'string') return;

dotLottieRef.current.setMode(props.mode);
}, [props.mode]);
dotLottieRef.current?.setMode(mode ?? 'forward');
}, [mode]);

useEffect(() => {
if (!dotLottieRef.current || typeof props.loop !== 'boolean') return;

dotLottieRef.current.setLoop(props.loop);
}, [props.loop]);
dotLottieRef.current?.setLoop(loop ?? false);
}, [loop]);

useEffect(() => {
if (!dotLottieRef.current || typeof props.useFrameInterpolation !== 'boolean') return;

dotLottieRef.current.setUseFrameInterpolation(props.useFrameInterpolation);
}, [props.useFrameInterpolation]);
dotLottieRef.current?.setUseFrameInterpolation(useFrameInterpolation ?? true);
}, [useFrameInterpolation]);

useEffect(() => {
if (!dotLottieRef.current || typeof props.segment !== 'object') return;

const startFrame = props.segment[0];
const endFrame = props.segment[1];

dotLottieRef.current.setSegment(startFrame, endFrame);
}, [props.segment]);
if (typeof segment?.[0] === 'number' && typeof segment[1] === 'number') {
dotLottieRef.current?.setSegment(segment[0], segment[1]);
} else {
dotLottieRef.current?.resetSegment();
}
}, [segment]);

useEffect(() => {
if (!dotLottieRef.current || typeof props.backgroundColor !== 'string') return;

dotLottieRef.current.setBackgroundColor(props.backgroundColor);
}, [props.backgroundColor]);

const renderConfig = useMemo(() => {
if (typeof props.renderConfig !== 'object') return undefined;

return props.renderConfig;
}, [props.renderConfig?.autoResize, props.renderConfig?.devicePixelRatio, props.renderConfig?.freezeOnOffscreen]);
dotLottieRef.current?.setBackgroundColor(backgroundColor ?? '');
}, [backgroundColor]);

useEffect(() => {
if (!dotLottieRef.current || !renderConfig) return;

dotLottieRef.current.setRenderConfig(renderConfig);
}, [renderConfig]);
dotLottieRef.current?.setRenderConfig(renderConfig ?? {});
}, [JSON.stringify(renderConfig)]);

useEffect(() => {
if (!dotLottieRef.current || typeof props.data !== 'string' || typeof props.data !== 'object') return;
if (typeof data !== 'string' && typeof data !== 'object') return;

dotLottieRef.current.load({
data: props.data,
...(configRef.current || {}),
dotLottieRef.current?.load({
data,
...configRef.current,
});
}, [props.data]);
}, [data]);

useEffect(() => {
if (!dotLottieRef.current || typeof props.src !== 'string') return;
if (typeof src !== 'string') return;

dotLottieRef.current.load({
src: props.src,
...(configRef.current || {}),
dotLottieRef.current?.load({
src,
...configRef.current,
});
}, [props.src]);
}, [src]);

useEffect(() => {
if (!dotLottieRef.current || typeof props.marker !== 'string') return;

dotLottieRef.current.setMarker(props.marker);
dotLottieRef.current?.setMarker(props.marker ?? '');
}, [props.marker]);

useEffect(() => {
if (!dotLottieRef.current || typeof props.animationId !== 'string') return;

dotLottieRef.current.loadAnimation(props.animationId);
}, [props.animationId]);
dotLottieRef.current?.loadAnimation(animationId ?? '');
}, [animationId]);

useEffect(() => {
if (!dotLottieRef.current || typeof props.themeId !== 'string') return;

dotLottieRef.current.setTheme(props.themeId);
}, [props.themeId]);
if (typeof themeId === 'string') {
dotLottieRef.current?.setTheme(themeId);
} else {
dotLottieRef.current?.resetTheme();
}
}, [themeId]);

useEffect(() => {
if (!dotLottieRef.current || typeof props.themeData !== 'string') return;

dotLottieRef.current.setThemeData(props.themeData);
}, [props.themeData]);
dotLottieRef.current?.setThemeData(themeData ?? '');
}, [themeData]);

return (
<div style={{ width: '100%', height: '100%', lineHeight: 0, ...props.style }}>
<canvas ref={setCanvasRef} {...props} style={{ width: '100%', height: '100%' }} />
<div
className={className}
{...(!className && {
style: {
width: '100%',
height: '100%',
lineHeight: 0,
...style,
},
})}
>
<canvas
ref={setCanvasRef}
style={{
width: '100%',
height: '100%',
}}
{...props}
/>
</div>
);
};
Loading

0 comments on commit 1947d7a

Please sign in to comment.