Skip to content
Merged
64 changes: 64 additions & 0 deletions packages/react/testing-library/src/__tests__/worklet.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -551,4 +551,68 @@ describe('worklet', () => {
`);
vi.resetAllMocks();
});

it('multiple main-thread worklets should work together when background thread is enabled', () => {
vi.spyOn(lynx.getNativeApp(), 'callLepusMethod');
const callLepusMethodCalls = lynx.getNativeApp().callLepusMethod.mock.calls;
expect(callLepusMethodCalls).toMatchInlineSnapshot(`[]`);

globalThis.firstCb = vi.fn();
globalThis.secondCb = vi.fn();

const Comp = () => {
return (
<view>
<view
main-thread:bindtap={(event) => {
'main thread';
globalThis.firstCb(event.key);
}}
>
<text>first</text>
</view>
<view
main-thread:bindtap={(event) => {
'main thread';
globalThis.secondCb(event.key);
}}
>
<text>second</text>
</view>
</view>
);
};

const { container, getByText } = render(<Comp />, {
enableMainThread: true,
enableBackgroundThread: true,
});

expect(callLepusMethodCalls).toHaveLength(1);
expect(callLepusMethodCalls[0][0]).toBe('rLynxChange');

const patchData = JSON.parse(callLepusMethodCalls[0][1].data);
const workletIds = patchData.patchList
.flatMap(item => Array.isArray(item.snapshotPatch) ? item.snapshotPatch : [])
.filter(item => typeof item === 'object' && item !== null && '_wkltId' in item)
.map(item => item._wkltId);

expect(workletIds).toHaveLength(2);
expect(new Set(workletIds).size).toBe(2);

const firstView = getByText('first').parentNode;
const secondView = getByText('second').parentNode;
fireEvent.tap(firstView, {
key: 'first-key',
});
fireEvent.tap(secondView, {
key: 'second-key',
});

expect(globalThis.firstCb).toBeCalledTimes(1);
expect(globalThis.firstCb).toBeCalledWith('first-key');
expect(globalThis.secondCb).toBeCalledTimes(1);
expect(globalThis.secondCb).toBeCalledWith('second-key');
vi.resetAllMocks();
});
});
50 changes: 50 additions & 0 deletions packages/react/transform/__test__/fixture.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1453,6 +1453,29 @@ class X extends Component {
});

describe('worklet', () => {
const lepusWorkletOptions = {
pluginName: '',
filename: '',
sourcemap: false,
cssScope: false,
jsx: false,
directiveDCE: true,
defineDCE: {
define: {
__LEPUS__: 'true',
__JS__: 'false',
},
},
shake: false,
compat: true,
refresh: false,
worklet: {
target: 'LEPUS',
filename: '',
runtimePkg: '@lynx-js/react',
},
};

it('should error on unsupported runtime import attribute', async () => {
const result = await transformReactLynx(
`\
Expand Down Expand Up @@ -1570,6 +1593,21 @@ export function bar() {
);
});

it('should not inject runtime when no worklet exists', async () => {
const { code } = await transformReactLynx(
`\
export function getCurrentDelta(event) {
return foo.bar.baz;
}
`,
lepusWorkletOptions,
);

expect(code).not.toContain('loadWorkletRuntime');
expect(code).not.toContain('registerWorkletInternal');
expect(code).not.toContain('_wkltId');
});

for (const target of ['LEPUS', 'JS', 'MIXED']) {
it('member expression', async () => {
const { code } = await transformReactLynx(
Expand Down Expand Up @@ -1626,6 +1664,8 @@ export function bar() {
});
"
`);
expect(code).toContain('loadWorkletRuntime');
expect(code).toContain('registerWorkletInternal("main-thread"');
} else if (target === 'JS') {
expect(code).toMatchInlineSnapshot(`
"export let getCurrentDelta = {
Expand All @@ -1640,6 +1680,8 @@ export function bar() {
};
"
`);
expect(code).not.toContain('loadWorkletRuntime');
expect(code).not.toContain('registerWorkletInternal');
} else if (target === 'MIXED') {
expect(code).toMatchInlineSnapshot(`
"import { loadWorkletRuntime as __loadWorkletRuntime } from "@lynx-js/react";
Expand All @@ -1663,6 +1705,8 @@ export function bar() {
});
"
`);
expect(code).toContain('loadWorkletRuntime');
expect(code).toContain('registerWorkletInternal("main-thread"');
}
});
}
Expand Down Expand Up @@ -1729,6 +1773,8 @@ export function foo(event) {
});
"
`);
expect((code.match(/registerWorkletInternal/g) ?? []).length).toBe(1);
expect((code.match(/const __workletRuntimeLoaded = loadWorkletRuntime/g) ?? []).length).toBe(1);
});

it('nested', async () => {
Expand Down Expand Up @@ -1795,6 +1841,8 @@ console.log(bar)
});
"
`);
expect((code.match(/registerWorkletInternal/g) ?? []).length).toBe(2);
expect((code.match(/const __workletRuntimeLoaded = loadWorkletRuntime/g) ?? []).length).toBe(1);
});

it('use multiple times', async () => {
Expand Down Expand Up @@ -1845,6 +1893,8 @@ function getCurrentDelta(event) {
});
"
`);
expect((code.match(/registerWorkletInternal/g) ?? []).length).toBe(1);
expect((code.match(/const __workletRuntimeLoaded = loadWorkletRuntime/g) ?? []).length).toBe(1);
});

it('should keep webpack runtime variables', async () => {
Expand Down
16 changes: 16 additions & 0 deletions packages/react/worklet-runtime/__test__/workletRuntime.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,22 @@ describe('Worklet', () => {
expect(fn).toBeCalled();
});

it('latest registration should win when the same worklet id is reused', () => {
initWorklet();

const first = vi.fn();
const second = vi.fn();
globalThis.registerWorklet('main-thread', '1', first);
globalThis.registerWorklet('main-thread', '1', second);

globalThis.runWorklet({
_wkltId: '1',
});

expect(first).not.toBeCalled();
expect(second).toBeCalled();
});

it('worklet should be called with arguments', async () => {
initWorklet();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,16 @@ export function a2() {
const onTapMT = () => {
'main thread';
};
const onLongPressMT = () => {
'main thread';
};

return (
<view>
<text bindtap={onTapMT}>
<text
bindtap={onTapMT}
bindlongpress={onLongPressMT}
Comment thread
Yradex marked this conversation as resolved.
>
hello world
</text>
</view>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1 @@
/// <reference types="vitest/globals" />
// @ts-check

import fs from 'node:fs/promises';
import path from 'node:path';

import './a.jsx';

it('should have worklet-runtime', async () => {
const source = await fs.readFile(
path.resolve(
path.join(
path.dirname(__filename),
'.rspeedy',
'tasm.json',
),
),
'utf-8',
);
const json = JSON.parse(source);
expect(json['lepusCode']['lepusChunk']['worklet-runtime'].length > 0)
.toBe(true);
});
export { a2 } from './a.jsx';
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
/** @type {import("@lynx-js/test-tools").TConfigCaseConfig} */
module.exports = {
bundlePath: [
'main__main-thread.js',
'main__background.js',
],
// This case only asserts encoded output artifacts in worklet-runtime.test.ts.
bundlePath: [],
};
Original file line number Diff line number Diff line change
@@ -1,23 +1 @@
/// <reference types="vitest/globals" />
// @ts-check

import fs from 'node:fs/promises';
import path from 'node:path';

import './a.jsx';

it('should not have worklet-runtime', async () => {
const source = await fs.readFile(
path.resolve(
path.join(
path.dirname(__filename),
'.rspeedy',
'tasm.json',
),
),
'utf-8',
);
const json = JSON.parse(source);
expect(json['lepusCode']['lepusChunk']['worklet-runtime'])
.toBe(undefined);
});
export { a2 } from './a.jsx';
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
/** @type {import("@lynx-js/test-tools").TConfigCaseConfig} */
module.exports = {
bundlePath: [
'main__main-thread.js',
'main__background.js',
],
// This case only asserts encoded output artifacts in worklet-runtime.test.ts.
bundlePath: [],
};
Loading
Loading