Attention: Deprecation of "fdk test", Introduction of "fdk unit-test", and New Coverage Requirements

Hello Developers,

To improve testing standards and app quality across the Marketplace ecosystem, we are introducing changes to app testing and coverage requirements.

Starting July 9th, 2026, the fdk test command will be deprecated. fdk unit-test will be the supported framework for writing and executing unit tests.

Starting July 31, 2026, Marketplace apps must meet the following minimum coverage requirements:

  • fdk unit-test coverage: 80% or higher

  • Local simulation coverage: 50% or higher

Apps that do not meet the required coverage thresholds cannot be packaged using FDK (fdk pack) and may not pass Marketplace validation checks.

Why are we making this change?

Local simulation coverage has been useful for validating app behavior during development. However, simulation coverage alone does not provide sufficient visibility into how thoroughly application logic is tested.

By introducing fdk unit-test coverage requirements, we aim to encourage automated testing practices that help identify issues earlier in the development lifecycle, improve code quality, and reduce regressions before apps reach production.
These requirements also help establish a consistent testing baseline across Marketplace apps, resulting in a more reliable experience for customers.

Jest & Vitest

In addition to improving test quality, fdk unit-test provides greater flexibility in how tests are written and maintained. Support for popular testing frameworks such as Jest and Vitest enables easier integration with existing CI/CD workflows and modern testing practices while meeting Marketplace coverage requirements.

For guidance on writing unit tests with Vitest, including sample implementations for front-end components/scripts and serverless SMI/event functions, refer to the documentation:
https://developers.freshworks.com/docs/app-sdk/v3.0/support_ticket/basic-dev-tools/freshworks-cli/#4.-write-unit-tests-with-vitest

What do you need to do?

  • Upgrade to the latest FDK version. (v10.1.2)

  • Migrate existing tests from fdk test to fdk unit-test.

  • Ensure your app achieves at least 80% unit test coverage.

  • Continue maintaining at least 50% local simulation coverage.

If you have any questions or need assistance with migration, testing strategies, or coverage improvements, please raise a request through Dev-Assist: https://dev-assist.freshworks.com/support/catalog/items/61.
Our team will be happy to assist you.

Thank you for helping us build a stronger, more reliable Marketplace ecosystem!

1 Like

Hi Rohan,

Thanks for this update. This is very positive as fdk-test had a number of shortcomings we had discussed before.

Will Freddy write unit tests for this ?

Best

Rob

Three bugs in fdk unit-test + fdk pack that block TypeScript apps from building

Hi Freshworks team,

We’re building an app with a TypeScript server (server.ts → compiled to server.js). We integrated vitest as required for the June 2026 unit-test mandate. We hit three separate bugs that made fdk unit-test and fdk pack unusable as-is, and had to work around all three. Documenting them here so they can be fixed in the FDK.


Bug 1 — fdk unit-test lints TypeScript-compiled JS and aborts before tests run

fdk unit-test runs ESLint on server JS files before invoking the fdk-unit-test script. Our server is written in TypeScript and compiled to JS. The TypeScript compiler emits var declarations and async functions that have no await (because they call fire-and-forget helpers). These are flagged by no-var and require-await ESLint rules.

Result: fdk unit-test aborts on the lint step and never runs vitest at all, even when --skip-lint is passed to fdk pack.

Workaround: We run vitest directly (npx vitest run --coverage) and then call FDK’s own internal coverage utilities via Node to generate .report.json with the correct HMAC hash:


const cu = require('$FDK_ROOT/lib/utils/coverage');

const ru = require('$FDK_ROOT/lib/utils/report');

cu.processUnitTestCoverage();

This means we cannot use fdk unit-test at all and must reach into FDK internals to produce the .report.json that fdk pack requires.

Expected behaviour: fdk unit-test should skip linting of compiled JS output (it is not source code), or at minimum respect a --skip-lint flag the same way fdk pack does.


Bug 2 — fdk unit-test writes unitTestCoverageSummary but fdk pack reads coverageSummary

After running vitest and calling cu.processUnitTestCoverage(), the coverage summary is written to the FDK localstore under the key unitTestCoverageSummary. However, fdk pack reads the key coverageSummary when deciding whether the coverage threshold has been met.

Result: fdk pack always sees zero/no coverage and fails with “coverage is less than required” even when actual coverage is above 80%.

Workaround: We manually copy the key after processUnitTestCoverage() runs:


const s = ru.get('unitTestCoverageSummary');

if (s && s.data) { delete s.data.branchesTrue; ru.set('coverageSummary', s); }

We also have to delete branchesTrue from s.data because its presence causes fdk pack to miscount branch coverage.

Expected behaviour: fdk unit-test and fdk pack should use the same key. If unitTestCoverageSummary is intentional, fdk pack should read from it.


Bug 3 — fdk pack hangs indefinitely after printing “packed successfully”

fdk pack prints the success message and then never exits. The process stays alive because Vite’s internal file-system watchers (used during the frontend bundle step) are never closed.

Result: Any script that calls fdk pack synchronously will hang forever on success, making it impossible to use in CI or build pipelines without a timeout or force-kill.

Workaround: We run fdk pack as a background process, stream its output to a temp file, and poll for the success or failure string, then kill the process:


(cd "$APP_DIR" && fdk pack --skip-lint) >"$_pack_log" 2>&1 &

_pack_pid=$!

while sleep 0.5; do

grep -q "packed successfully" "$_pack_log" && { result=0; break; }

grep -qE "Packing failed|coverage is less" "$_pack_log" && { result=1; break; }

kill -0 "$_pack_pid" 2>/dev/null || { wait "$_pack_pid"; result=$?; break; }

done

kill "$_pack_pid" 2>/dev/null || true

Expected behaviour: fdk pack should call process.exit() (or close all handles) after it finishes packing, so the process exits cleanly with the correct exit code.


Environment

  • FDK version: 10.1.2

  • App type: Custom app with TypeScript server (packages/ts-server → compiled JS in server/)

  • Test runner: vitest ^4.1.8 with @vitest/coverage-v8

  • fdk-unit-test script: vitest run --coverage

All three bugs are independent and each one alone would block a TypeScript app from completing a build. Happy to provide more details or reproduce steps.

Thanks for the insights and sharing this @arunrajkumar235. Adding @sureshprasanna for visibility

Thanks we appreciate

@arunrajkumar235

For the above-mentioned bug, we didn’t support typescript in the server.js yet. So in the above case, it won’t work; I would suggest making the compiler fit with what we expect as JS and that would solve the lint issues, and automatically test will run

As we informed already, after July 9th we will add this to the coverage summary, and after July 31, we do mandate the coverage for packing.

We need more info on this, can you please share with us any sample to reporduce this issue.

Thanks
Santhosh B

Hi Santhosh, thanks for the detailed reply!

On Bug 1: Thanks for clarifying. I dug into the lint errors more closely after your response. I can made the changes you suggested and it worked.

On Bug 2: Understood — we’ll keep our workaround in place until the July 9th fix lands.

On Bug 3: This occurs consistently in my app: after fdk pack prints “packed successfully”, the process stays alive indefinitely.

possible, share the app with us app.zip, we can validate the root cause.

cc: @Annamalai_Shanmugam

Thanks

Hi All,

After playing with this we found that Codex 4.5 combined with the Freddy MCP server does a great job at helping to achieve the coverage and local simulation requirements really quickly. :grinning_face: