apache / apache/fineract-backoffice-ui

The admin, campaigns and interop features have 16 components and not one unit test

Open
#256 0 comments 0 reactions 0 assignees View on GitHub
angular good first issue javascript test-coverage typescript
Dominant language
TypeScript
Stars
15
Forks
60
Avg merge
10h 15m
Merged PRs (30d)
108

Description

## Business value

The project runs 143 component specs against 252 components, and CI runs them on every pull request — so unit tests here are load-bearing, not decoration. Three feature directories are not covered at all:

| Feature | Components | Specs |
| --- | --- | --- |
| `admin` | 6 | 0 |
| `campaigns` | 5 | 0 |
| `interop` | 5 | 0 |

What makes this worth fixing rather than just a number: these are the features least likely to be caught by anything else. The e2e suite reaches roughly 17% of routes and does not go near them, and they are not on a path anyone walks daily, so a regression here surfaces when someone tries to run a batch job or send a campaign — which is exactly the moment they need it to work.

There is also a specific class of bug that only a test catches here. Angular 22 makes `OnPush` the default, so a plain field assigned from an HTTP callback holds the right value while the view keeps showing the old one. `scripts/audit-async-state.mjs` counts those. A component with no spec has nothing standing between it and that failure, and the symptom — a dropdown that renders empty — looks like a backend problem.

## The components

```
admin/batch-operations/batch-operations.component.ts
admin/cob-tools/cob-tools.component.ts
admin/external-events/external-events.component.ts
admin/inline-job/inline-job.component.ts
admin/progressive-loan/progressive-loan-model.component.ts
admin/wc-cob-tools/wc-cob-tools.component.ts

campaigns/email-campaigns/email-campaign-form.component.ts
campaigns/email-campaigns/email-campaigns-list.component.ts
campaigns/email-messages/email-messages.component.ts
campaigns/sms-campaigns/sms-campaign-form.component.ts
campaigns/sms-campaigns/sms-campaigns-list.component.ts

interop/interop-account-view.component.ts
interop/interop-party-lookup.component.ts
interop/interop-quotes.component.ts
interop/interop-transfers.component.ts
interop/interop-health.component.ts
```

Verify with:

```
find src/app/features/admin src/app/features/campaigns src/app/features/interop \
-name '*.component.ts' ! -name '*.spec.ts' | wc -l # 16
find src/app/features/admin src/app/features/campaigns src/app/features/interop \
-name '*.component.spec.ts' | wc -l # 0
```

## Describing the change

Add a `*.component.spec.ts` beside each component. **One component per pull request** — a spec is only useful if someone reads it, and sixteen at once will not be read.

Worth asserting, in rough order of value:

1. **It renders what it loaded.** Not just that the service was called — that the value reaches the DOM. This is the assertion that catches the change-detection failure above; `expect(service.getX).toHaveBeenCalled()` does not.
2. **The request carries the right arguments.** The generated API client takes positional parameters, so a wrong-position argument still compiles. A spec that pins the arguments is the only thing that notices.
3. **A failed load leaves a usable screen** — an error state or a retry, not a permanent spinner.

Existing specs to copy the shape from:

- `src/app/features/groups/group-view.component.spec.ts` — a detail screen: `HttpTestingController`, dialogs through the adapter fakes, assertions on the request.
- `src/app/features/organization/**/*.spec.ts` — simpler list and form screens.

Use `provideFakeAdapters()` from `src/app/testing/adapters.ts` rather than a real translation catalogue or Ionic test module. It binds all four adapter tokens to recording fakes, so you assert on the *request* a component made — the toast it asked for, the modal it opened — instead of on whatever DOM Ionic built from it. `DOCS/ADAPTERS.md` explains the boundary.

## Scope

In scope: a unit spec per component in these three features.

Out of scope: e2e coverage for these screens, refactoring the components while testing them (if a component is hard to test, say so on the PR rather than reshaping it in the same change), and the other untested components elsewhere in the tree.

## Getting started

- Run one spec: `npx ng test fineract-backoffice-ui --watch=false --browsers=ChromeHeadless --include='**/your.component.spec.ts'`
- Run everything: `npm test`
- `npm run lint` must pass. Note `sonarjs/no-duplicate-string` fires on a literal repeated three times — hoist it to a `const` at the top of the spec.

Contributor guide

Open the contributing guide

Research direction

Choose one listed component, then read its implementation alongside src/app/features/groups/group-view.component.spec.ts or the organization specs. Run the focused npx ng test command from the issue and use provideFakeAdapters() from src/app/testing/adapters.ts. Done means the new spec checks rendered loaded data, request arguments, and the failed-load state, with npm run lint passing.

Written by the indexing model from the issue text.

Assessment

Tech stack
angular, typescript
Domain
frontend, testing
Issue type
Feature
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.