# Testing

Project targets and manual flows


How tests run in `erxes/erxes`, which Community Edition projects can run them, and what to check manually before a pull request.
For the branch workflow, see [Contribute to codebase](https://erxes.io/docs/contribute-codebase).

## How Jest is set up

- `jest.preset.js` is a one-line spread of the `@nx/jest` preset; each project's `jest.config.ts` applies it and sets `displayName`, transform (`babel-jest` with `@nx/react/babel` for UI projects, `ts-jest` where configured), and `coverageDirectory`.
- The root `jest.config.ts` aggregates every project through `getJestProjectsAsync()`; it exists for IDE and whole-repo runs.
- `nx.json` registers `@nx/jest/plugin` with `targetName: "test"`, so any project containing a `jest.config.*` file gets an inferred `test` target. `@nx/eslint/plugin` similarly infers `lint`, and `@nx/webpack/plugin` infers `build`/`serve`/`preview`.

## Project targets

In the Community Edition, eight projects have a Jest config and therefore expose `pnpm nx test <project>`: `core-ui`, `erxes-ui`, `ui-modules`, `content_ui`, `frontline_ui`, `operation_ui`, `sales_ui` on the frontend, and `erxes-api-shared` on the backend, the only one that also declares an explicit `test` target in `project.json`. (Enterprise Edition plugin projects have their own configs.)

Most backend plugins have no Jest setup at all: `sales_api`, `core-api`, and `content_api` have no `jest.config.ts`, so their spec files do not run under `pnpm nx test`. Always check `project.json` or run `pnpm nx show project <name>` instead of assuming a target exists.

```bash
pnpm nx show project sales_ui          # list the project's targets
pnpm nx test erxes-api-shared          # run one project's tests
pnpm nx test core-ui
pnpm nx affected -t test               # tests for changed projects only
pnpm nx affected -t lint,build,test    # the full affected check before a PR
```

## Where tests live (CE)

Fifty-six spec/test files exist in the repo; these are the Community Edition ones:

| Project | Path | Specs |
| --- | --- | --- |
| `erxes-api-shared` | `backend/erxes-api-shared/src/**` (`core-modules/`, `utils/`) | 27 |
| `core-ui` | `frontend/core-ui/src/modules/**` | 5 |
| `content_api` | `backend/plugins/content_api/src/modules/cms/postiz/__tests__/`, `test/` | 5 |
| `content_ui` | `frontend/plugins/content_ui/src/modules/cms/**` | 4 |
| `sales_api` | `backend/plugins/sales_api/src/modules/pos/` | 2 |
| `saas-migrations` | `backend/saas-migrations/content/knowledgebase/__tests__/` | 2 |
| `core-api` | `backend/core-api/src/modules/documents/__tests__/` | 1 |
| `erxes-ui` | `frontend/libs/erxes-ui/src/modules/chat-viz/utils/` | 1 |

The rest belong to Enterprise plugin projects.

## Representative specs

Three projects cover most of the useful patterns:

- **`erxes-api-shared`**: the deepest suite in the repo, and the only backend project with a `test` target set up end to end (`jest.config.ts` + explicit `project.json` target). The `core-modules/segments/` specs alone show how to test a pure engine: [`evaluate.test.ts`](https://github.com/erxes/erxes/blob/f91e8c6f4714c910a32c6b6e14fe085f6435c89e/backend/erxes-api-shared/src/core-modules/segments/evaluate.test.ts) feeds segment definitions through the evaluator and asserts membership, with no MongoDB involved. Start here for backend logic.
- **`core-ui`**: five specs over pure utility modules. `src/modules/navigation/utils/pinnedNavigationActivities.spec.ts` exercises the navigation helpers with plain inputs and outputs. The frontend pattern is the same: pick a pure function, feed it states, assert outputs.
- **`sales_api`**: two specs (`modules/pos/fieldUtils.spec.ts`, `modules/pos/meta/automations/resolvers/resolvePosOrderPaymentUrl.spec.ts`) that exist without a project Jest config. They are dormant: readable as patterns, not runnable under `nx test` until the plugin adds a `jest.config.ts`.

`content_api` is the fourth pattern and the exception: its Postiz specs run through [`jest.postiz.cjs`](https://github.com/erxes/erxes/blob/f91e8c6f4714c910a32c6b6e14fe085f6435c89e/backend/plugins/content_api/jest.postiz.cjs), a standalone `ts-jest` config that matches only `src/modules/cms/postiz/__tests__/*.spec.ts`, outside the Nx target system entirely. [`test/dockerfile.test.cjs`](https://github.com/erxes/erxes/blob/f91e8c6f4714c910a32c6b6e14fe085f6435c89e/backend/plugins/content_api/test/dockerfile.test.cjs) is a `node:test` contract test asserting the Dockerfile's `NODE_OPTIONS=--jitless` workaround stays in the installer stage. Its validation commands:

```bash
pnpm nx build content_api
node --test backend/plugins/content_api/test/dockerfile.test.cjs
pnpm exec tsc --noEmit -p backend/plugins/content_api/tsconfig.json
pnpm exec jest --config backend/plugins/content_api/jest.postiz.cjs --runInBand
```

`saas-migrations` uses yet another runner: `tsx --test` (`npm run test:knowledgebase`), the Node built-in runner rather than Jest.

## What to cover

Co-locate specs under `__tests__/`. Backend service/model tests build tenant models with `generateModels('test')` and clean up in `afterEach`; frontend tests use `@testing-library/react` with Apollo's `MockedProvider`. Keep tests deterministic, isolated, and focused on behavior rather than implementation.

Whatever the module, the priorities are the same:

1. **Permissions and tenant isolation**: a resolver or procedure that leaks another tenant's data is the worst regression; test the `subdomain` scoping, not just the happy path.
2. **Validation at the boundary**: bad input rejected before it reaches the model layer.
3. **The behavior you changed**: [`CONTRIBUTING.md`](https://github.com/erxes/erxes/blob/f91e8c6f4714c910a32c6b6e14fe085f6435c89e/CONTRIBUTING.md) asks for a test whenever the contribution adds observable behavior that is not already covered; a regression spec for a bug fix is worth more than a broad suite.

## Manual verification checklist

Automated coverage is thin in most plugins, so `CONTRIBUTING.md` expects manual flows:

1. Reproduce the bug before fixing it, then confirm the same scenario passes.
2. Exercise every state your change touches: loading, success, empty, and error.
3. After each create, update, or delete, confirm the UI updates without a manual refresh (Apollo cache update, refetch, or `subscribeToMore`).
4. For widget and portal flows, test a fresh session, a reload, and a mobile viewport, and confirm no credentials leak into the URL or storage.
5. Re-run `pnpm nx lint <project>` and `pnpm nx build <project>` after review feedback, and record any check you could not run (with the reason) instead of describing it as passed.

Attach screenshots or recordings to the PR for any visible UI change.

