Testing
What exists
| Suite | Status | Detail |
|---|---|---|
Unit tests |
Maintained |
Karma + Jasmine, ~400 spec files, run by |
E2E tests |
Not maintained |
Cypress 7.x, 10 spec files. Marked NOT MAINTAINED in capitals in the repository README. |
|
The deploy buildspec has |
Running unit tests
| Command | Use |
|---|---|
|
Watch mode, for interactive development. |
|
One run. Prefer this in CI and agent loops. |
|
Headless with coverage and reports ( |
|
|
|
The repository README says |
Karma configuration
karma.conf.js:
process.env.CHROME_BIN = require('puppeteer').executablePath(); // Chrome comes from Puppeteer
frameworks: ['jasmine', '@angular-devkit/build-angular']
browsers: ['ChromeHeadlessNoSandbox']
client: { jasmine: { random: false }, clearContext: false, args: ['--sourcemaps=false'] }
reporters: ['progress', 'coverage', 'junit']
port: 9876
singleRun: false
autoWatch: true
Points that matter:
-
Chrome is Puppeteer’s. No system Chrome needed, but the Puppeteer install must have succeeded.
-
ChromeHeadlessNoSandboxpasses--no-sandbox --disable-setuid-sandbox --disable-gpu --disable-translate --disable-extensions --no-proxy-server— required in containers. -
random: false. Specs run in a deterministic order, which means a spec can accidentally depend on another’s side effects. Given that several reducers touchlocalStorageat module-evaluation time andcerializecasing is global state, this is not hypothetical — see data modelling. -
Coverage reporters:
html,lcov,text-summary,cobertura, written tocoverage/. -
specReportersis configured withfailFast: true, butjasmine-spec-reporteris not in thereporterslist, so those options are inert.
src/test.ts
The Karma entry point. It imports the zone.js testing shims, initialises the Angular
TestBed, then discovers specs with
require.context('./', true, /\.spec\.ts$/) and starts Karma manually
(karma.loaded = function () {} prevents a premature start).
So every *.spec.ts under src/ is picked up automatically — there is no manual
registry.
Spec idioms
The house pattern uses ng-bullet and ng-mocks:
import { TestBed } from '@angular/core/testing';
import { configureTestSuite } from 'ng-bullet';
import { MockProvider } from 'ng-mocks';
describe('FeatureFlagsService', () => {
let service: FeatureFlagsService;
configureTestSuite(() => {
TestBed.configureTestingModule({
providers: [FeatureFlagsService, MockProvider(GlobalSettingsService)],
});
service = TestBed.inject(FeatureFlagsService);
});
it('should be created', () => { … });
});
| Tool | Why |
|---|---|
|
Configures the |
|
Auto-mock a dependency without hand-writing a stub. |
|
Import this instead of thirty individual Material modules — that is its stated purpose. |
|
~30 hand-written doubles, provided by token. Several services have an
|
|
Store slice stubs: |
|
Shared test doubles and mock pipes. |
|
|
Naming convention for test constants
From the repository’s own conventions: production constants are UPPERCASE;
constants that exist only for tests or mocks are wrapped in double underscores.
const SOME_PRODUCTION_CONSTANT = 'some value';
const __SOME_MOCKED_CONSTANT__ = 'some value';
feature-flags.service.spec.ts follows it: TEST_DISABLED_FLAGS,
TEST_PAYLOAD, TEST_MODULE1.
Testing private members
Existing specs reach into privates via a cast, and use spyOn on private methods:
spyOn(service as any, 'getFeatureFlagsFromEnv').and.returnValue(__TEST_DISABLED_FLAGS__);
(service as any).initFF();
expect((service as any).featureFlags.length).toEqual(0);
Not ideal, but it is the local convention. getFeatureFlagsFromEnv exists as a
private method specifically so specs can stub the environment.
What is well tested, and what is not
| Area | State |
|---|---|
Advance calculator |
|
Feature flags |
|
Card model |
|
Real-time validation |
Both the validator and the input factory have specs and mocks. |
Auth guard |
|
Effects |
Thinly covered. The large effect classes ( |
Components |
~400 spec files exist for ~420 components, but many are generated "should create" smoke tests rather than behavioural. |
Writing a new test
-
Put it next to the unit under test as
<name>.spec.ts. It is discovered automatically. -
Use
configureTestSuitefromng-bullet. -
Mock dependencies with
ng-mocksMockProvider, or provide the existing*-mock.service.tsby token. -
Import
PybMaterialModulerather than individual Material modules. -
Prefix test-only constants with
…. -
Assert behaviour, not that the component exists. A
should createtest alone does not satisfy the definition of done. -
For a reducer, follow
calculator.spec.ts: construct the action, run the reducer, assert on the returned state. -
Run
npm run test-singlebefore pushing — Husky’spre-pushhook runs it anyway.
|
Because |
Coverage
npm run test:ci writes to coverage/:
| Output | Consumer |
|---|---|
|
Human-readable HTML; published as a CodeBuild artifact. |
|
CodeBuild’s |
|
CodeBuild’s |
There is no enforced coverage threshold.
Cypress (unmaintained)
|
The repository README marks the E2E suite NOT MAINTAINED. Treat the specs as documentation of intent rather than a working gate. Do not add a Cypress test as the only proof of a change. |
Configuration
cypress.json:
{
"env": { "LOCAL": false, "ENV_NAME": "staging", "ENV_TYPE": "dev" },
"chromeWebSecurity": false,
"reporter": "junit",
"reporterOptions": { "mochaFile": "cypress/reports/test-report-[hash].xml" },
"fixturesFolder": false,
"pluginsFile": false,
"defaultCommandTimeout": 30000
}
| Setting | Why |
|---|---|
|
Required because the app embeds EVA in cross-origin iframes. |
|
The app is slow to settle — many screens fan out to several backends. |
|
|
|
Which environment to point at. |
|
Not in the file — it must not be versioned. Retrieve it from Secrets Manager
( |
Commands
| Command | Does |
|---|---|
|
Interactive / headless against the configured environment. |
|
Start the app ( |
|
As above with |
|
|
|
|
Note the README refers to cy:clean-reports; the script is cy:clear-reports.
Suite layout
cypress/
├── constants.js URLS, QA_TEAM_CREDENTIALS, FINAL_ENV, ENV_VAR_KEYS
├── utils.js
├── support/
│ ├── commands.js custom commands, incl. setupToken()
│ └── index.js
└── integration/
├── login.spec.js
├── search.spec.js
├── crm-notes.spec.js
├── marketplaces.spec.js
├── eva-menu.spec.js
├── awx-disputes.spec.js
└── general/
├── change-password.spec.js
├── contact-data-form.spec.js
├── supplier-main-bar.spec.js
└── suspension.spec.js
support/commands.js imports from the application source:
import { AMAZON_SELLER_CENTRAL_MARKETPLACE_KEY } from '../../src/app/suppliers/…/supplier-onboarding.service';
import { AMAZON_SELLER_CENTRAL } from '../../src/app/shared/enums/marketplace.enum';
So renaming those exports breaks the E2E suite silently. It also holds an
ffTempStorage = { eva: null, ia: null } for saving and restoring feature flags
around a test, and setupToken() authenticates by calling the internal API’s
auth/login with a Basic header built from the QA credentials — the same flow as
authentication.
Driving the real backend, or stubbing it
Most specs act against a deployed environment and the TEST_CYPRESS_SUPPLIER fixture,
undoing whatever they create. awx-disputes.spec.js does not: it stubs the three Airwallex
dispute endpoints its create-then-submit path touches — list, create and submit — with
cy.intercept, swapping the list response as the flow progresses so each reload reflects
the mutation. Evidence upload and cancel are covered by unit tests rather than here.
The reason is that the flow is not reversible. An Airwallex dispute cannot be deleted —
cancelling is the only unwind, and only before it reaches IN_PROGRESS — so a live run
would leave permanent records on the test supplier and would not be idempotent. See
Airwallex disputes.
Prefer the real backend when a flow can clean up after itself, and stub when it cannot.
data-test attributes
The convention, from the README: whenever a test needs to act on an element, add
data-test="uniqueName" to it. The sidebar is thoroughly annotated
(sidebarSearch, sidebarActions, sidebarMarketplaces, …).
|
|
Definition of done, testing part
New behaviour needs a unit test. A user-facing flow should have a Cypress test, but
given the suite’s state, a unit test plus a described manual check is the practical
bar. See conventions and the definition of done in
CLAUDE.md.