Skip to content

Commit 071cc9a

Browse files
committed
chore: added test for useRiveFile
1 parent c26985a commit 071cc9a

File tree

6 files changed

+1305
-1308
lines changed

6 files changed

+1305
-1308
lines changed

example/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"build:ios": "react-native build-ios --mode Debug"
1111
},
1212
"dependencies": {
13+
"@react-native-picker/picker": "^2.11.4",
1314
"@react-navigation/native": "^7.1.9",
1415
"@react-navigation/stack": "^7.3.2",
1516
"react": "19.0.0",

jest-setup.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/* global jest */
2+
jest.mock('react-native-nitro-modules', () => ({
3+
NitroModules: {
4+
createHybridObject: jest.fn(),
5+
},
6+
getHostComponent: jest.fn(() => 'RiveView'),
7+
}));
8+
9+
jest.mock('./nitrogen/generated/shared/json/RiveViewConfig.json', () => ({}), {
10+
virtual: true,
11+
});

package.json

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@
7575
"@react-native/babel-preset": "0.79.2",
7676
"@react-native/eslint-config": "^0.78.0",
7777
"@release-it/conventional-changelog": "^9.0.2",
78+
"@testing-library/react-hooks": "^8.0.1",
79+
"@testing-library/react-native": "^13.3.3",
7880
"@types/jest": "^29.5.5",
7981
"@types/react": "^19.0.0",
8082
"commitlint": "^19.6.1",
@@ -89,6 +91,7 @@
8991
"react-native": "0.79.2",
9092
"react-native-builder-bob": "^0.40.10",
9193
"react-native-nitro-modules": "^0.31.3",
94+
"react-test-renderer": "19.0.0",
9295
"release-it": "^17.10.0",
9396
"turbo": "^1.10.7",
9497
"typescript": "^5.2.2"
@@ -104,10 +107,18 @@
104107
"packageManager": "yarn@3.6.1",
105108
"jest": {
106109
"preset": "react-native",
110+
"setupFilesAfterEnv": ["<rootDir>/jest-setup.js"],
111+
"testMatch": [
112+
"<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}",
113+
"<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}"
114+
],
107115
"modulePathIgnorePatterns": [
108116
"<rootDir>/example/node_modules",
109117
"<rootDir>/lib/"
110-
]
118+
],
119+
"moduleNameMapper": {
120+
"^../nitrogen/generated/shared/json/RiveViewConfig\\.json$": "<rootDir>/jest-setup.js"
121+
}
111122
},
112123
"commitlint": {
113124
"extends": [
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import { renderHook, waitFor } from '@testing-library/react-native';
2+
import { useRiveFile } from '../useRiveFile';
3+
import type { RiveFile } from '../../specs/RiveFile.nitro';
4+
5+
jest.mock('react-native/Libraries/Image/Image', () => ({
6+
resolveAssetSource: jest.fn((source: number) => ({
7+
uri: `asset://resolved/${source}`,
8+
})),
9+
}));
10+
11+
describe('useRiveFile - updateReferencedAssets', () => {
12+
const mockRiveFile: RiveFile = {
13+
release: jest.fn(),
14+
updateReferencedAssets: jest.fn(),
15+
viewModelCount: 0,
16+
viewModelByIndex: jest.fn(),
17+
viewModelByName: jest.fn(),
18+
defaultArtboardViewModel: jest.fn(),
19+
} as any;
20+
21+
beforeEach(() => {
22+
jest.clearAllMocks();
23+
(global as any).mockRiveFileFactory.fromURL.mockResolvedValue(mockRiveFile);
24+
(global as any).mockRiveFileFactory.fromResource.mockResolvedValue(
25+
mockRiveFile
26+
);
27+
});
28+
29+
it('should call updateReferencedAssets when referencedAssets change', async () => {
30+
const initialAssets = {
31+
'asset-1': { source: { uri: 'https://example.com/image1.png' } },
32+
};
33+
34+
const { result, rerender } = renderHook(
35+
(props: { referencedAssets: any }) =>
36+
useRiveFile('https://example.com/animation.riv', {
37+
referencedAssets: props.referencedAssets,
38+
}),
39+
{ initialProps: { referencedAssets: initialAssets } }
40+
);
41+
42+
await waitFor(() => {
43+
expect((result.current as any).isLoading).toBe(false);
44+
});
45+
46+
expect(mockRiveFile.updateReferencedAssets).not.toHaveBeenCalled();
47+
48+
const updatedAssets = {
49+
'asset-1': { source: { uri: 'https://example.com/image2.png' } },
50+
};
51+
52+
rerender({ referencedAssets: updatedAssets });
53+
54+
await waitFor(() => {
55+
expect(mockRiveFile.updateReferencedAssets).toHaveBeenCalledWith({
56+
data: {
57+
'asset-1': { sourceUrl: 'https://example.com/image2.png' },
58+
},
59+
});
60+
});
61+
});
62+
63+
it('should handle multiple asset changes', async () => {
64+
const initialAssets = {
65+
'asset-1': { source: { uri: 'https://example.com/image1.png' } },
66+
'asset-2': { source: { uri: 'https://example.com/image2.png' } },
67+
};
68+
69+
const { result, rerender } = renderHook(
70+
(props: { referencedAssets: any }) =>
71+
useRiveFile('https://example.com/animation.riv', {
72+
referencedAssets: props.referencedAssets,
73+
}),
74+
{ initialProps: { referencedAssets: initialAssets } }
75+
);
76+
77+
await waitFor(() => {
78+
expect((result.current as any).isLoading).toBe(false);
79+
});
80+
81+
const updatedAssets = {
82+
'asset-1': { source: { uri: 'https://example.com/image1-new.png' } },
83+
'asset-2': { source: { uri: 'https://example.com/image2-new.png' } },
84+
};
85+
86+
rerender({ referencedAssets: updatedAssets });
87+
88+
await waitFor(() => {
89+
expect(mockRiveFile.updateReferencedAssets).toHaveBeenCalledWith({
90+
data: {
91+
'asset-1': { sourceUrl: 'https://example.com/image1-new.png' },
92+
'asset-2': { sourceUrl: 'https://example.com/image2-new.png' },
93+
},
94+
});
95+
});
96+
});
97+
98+
it('should not call updateReferencedAssets if assets have not changed', async () => {
99+
const assets = {
100+
'asset-1': { source: { uri: 'https://example.com/image1.png' } },
101+
};
102+
103+
const { result, rerender } = renderHook(
104+
(props: { referencedAssets: any }) =>
105+
useRiveFile('https://example.com/animation.riv', {
106+
referencedAssets: props.referencedAssets,
107+
}),
108+
{ initialProps: { referencedAssets: assets } }
109+
);
110+
111+
await waitFor(() => {
112+
expect((result.current as any).isLoading).toBe(false);
113+
});
114+
115+
rerender({ referencedAssets: assets });
116+
117+
expect(mockRiveFile.updateReferencedAssets).not.toHaveBeenCalled();
118+
});
119+
});

src/hooks/useRiveFile.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -153,13 +153,15 @@ export function useRiveFile(
153153
};
154154
}, [input]);
155155

156-
if (initialReferencedAssets.current !== referencedAssets) {
157-
// TODO: if riveFile not yet loaded?!
158-
const { riveFile } = result;
159-
if (riveFile && referencedAssets) {
160-
riveFile.updateReferencedAssets(referencedAssets);
156+
const { riveFile } = result;
157+
useEffect(() => {
158+
if (initialReferencedAssets.current !== referencedAssets) {
159+
if (riveFile && referencedAssets) {
160+
riveFile.updateReferencedAssets({ data: referencedAssets });
161+
initialReferencedAssets.current = referencedAssets;
162+
}
161163
}
162-
}
164+
}, [referencedAssets, riveFile]);
163165

164166
if (initialInput.current !== input) {
165167
console.warn(

0 commit comments

Comments
 (0)