Skip to content

ci(react-sdk): add contract tests#1160

Draft
joker23 wants to merge 4 commits intomainfrom
skz/sdk-1773/react-contract-test
Draft

ci(react-sdk): add contract tests#1160
joker23 wants to merge 4 commits intomainfrom
skz/sdk-1773/react-contract-test

Conversation

@joker23
Copy link
Contributor

@joker23 joker23 commented Mar 6, 2026

This PR will add the initial contract tests for react sdk

Current limitation of the contract tests is that they are basically just testing the underlying browser sdk. We will iterate these tests to be more idiomatic to the react SDK.


Open with Devin

Note

Medium Risk
Primarily adds CI/test-only infrastructure, but it also introduces a new Next.js/Playwright workspace and updates React type dependencies, which could affect installs/CI stability and TypeScript checks.

Overview
Adds an initial contract-test implementation for @launchdarkly/react-sdk by introducing a new packages/sdk/react/contract-tests workspace that spins up the existing browser adapter, a Next.js “entity” app, and a headless Playwright browser to execute SDK Test Harness commands over WebSocket.

Updates sdk/react CI (react.yaml) to install/build the new workspaces, install Playwright browsers, start the local test services, and run the shared contract-tests GitHub Action with a suppressions list. Also adds React package lint config overrides for the contract-test TS project and bumps @types/react/adds @types/react-dom in the React SDK dev deps.

Written by Cursor Bugbot for commit 9d0544a. This will update automatically on new commits. Configure here.

@joker23 joker23 requested a review from a team as a code owner March 6, 2026 17:57
@github-actions
Copy link
Contributor

github-actions bot commented Mar 6, 2026

@launchdarkly/js-sdk-common size report
This is the brotli compressed size of the ESM build.
Compressed size: 25566 bytes
Compressed size limit: 26000
Uncompressed size: 125383 bytes

@github-actions
Copy link
Contributor

github-actions bot commented Mar 6, 2026

@launchdarkly/browser size report
This is the brotli compressed size of the ESM build.
Compressed size: 172130 bytes
Compressed size limit: 200000
Uncompressed size: 800872 bytes

@github-actions
Copy link
Contributor

github-actions bot commented Mar 6, 2026

@launchdarkly/js-client-sdk size report
This is the brotli compressed size of the ESM build.
Compressed size: 24212 bytes
Compressed size limit: 25000
Uncompressed size: 83755 bytes

@github-actions
Copy link
Contributor

github-actions bot commented Mar 6, 2026

@launchdarkly/js-client-sdk-common size report
This is the brotli compressed size of the ESM build.
Compressed size: 21281 bytes
Compressed size limit: 24000
Uncompressed size: 110213 bytes

devin-ai-integration[bot]

This comment was marked as resolved.

cursor[bot]

This comment was marked as resolved.

cursor[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

<ClientInner
clientId={id}
handlers={commandHandlers.current}
onReady={(readyId) => handlerReadyMap.current.get(readyId)?.()}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unstable onReady callback causes effect re-runs and handler gaps

Medium Severity

The onReady prop is an inline arrow function (readyId) => handlerReadyMap.current.get(readyId)?.() that creates a new reference on every render. Since ClientInner's useEffect lists onReady as a dependency, the effect re-runs on every parent re-render. Each re-run first executes cleanup (deleting the command handler from the map), then re-registers it. This creates a brief window where no handler exists for that client. When a new client is added via setClients, all existing ClientInner components re-render, causing all their handlers to be momentarily removed — any runCommand arriving during that gap gets a 404 response. The onReady callback needs to be stabilized (e.g., via useCallback).

Additional Locations (1)

Fix in Cursor Fix in Web

record.client.close();
}
return prev.filter((r) => r.id !== id);
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Side effect in React state updater may execute multiple times

Low Severity

The _onDeleteClient callback calls record.client.close() inside a setClients state updater function. React state updaters are expected to be pure — React may invoke them more than once (e.g., in StrictMode or concurrent rendering), which would call close() on the same client multiple times. The close() call is a side effect that belongs outside the updater.

Fix in Cursor Fix in Web

@joker23 joker23 force-pushed the skz/sdk-1773/react-contract-test branch 2 times, most recently from 28e9506 to 88315e6 Compare March 6, 2026 20:20
setTimeout(() => {
this.connect();
}, 1000);
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WebSocket reconnects after intentional disconnect in StrictMode

Medium Severity

The onclose handler unconditionally schedules a reconnect via setTimeout. When layout.tsx's useEffect cleanup calls ws.disconnect(), this triggers onclose, which schedules a reconnect after 1 second. Under React StrictMode (active in Next.js dev mode), the effect mounts, unmounts, and remounts — creating a second TestHarnessWebSocket instance. The first instance also reconnects 1 second later, resulting in two active WebSocket connections processing commands in parallel and sending duplicate responses.

Additional Locations (1)

Fix in Cursor Fix in Web

@joker23 joker23 force-pushed the skz/sdk-1773/react-contract-test branch from 88315e6 to fd066db Compare March 6, 2026 20:43
devin-ai-integration[bot]

This comment was marked as resolved.

@joker23 joker23 force-pushed the skz/sdk-1773/react-contract-test branch 4 times, most recently from f582c85 to 50833ff Compare March 6, 2026 22:13
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

@joker23 joker23 force-pushed the skz/sdk-1773/react-contract-test branch from 50833ff to 9d0544a Compare March 6, 2026 22:20
@joker23 joker23 marked this pull request as draft March 6, 2026 22:22
@joker23 joker23 force-pushed the skz/sdk-1773/react-contract-test branch 5 times, most recently from 8dcb7b8 to 0c9f3f2 Compare March 7, 2026 00:32
@joker23 joker23 force-pushed the skz/sdk-1773/react-contract-test branch 2 times, most recently from 080fdde to 28d9696 Compare March 7, 2026 04:58
@joker23 joker23 force-pushed the skz/sdk-1773/react-contract-test branch from 28d9696 to a16497c Compare March 7, 2026 05:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant