npm package: @koech/esm-core
Description: :wave: New to our project? Be sure to review the [OpenMRS 3 Frontend Developer Documentation](https://openmrs.atlassian.net/wiki/x/IABBHg). You may find the [Introduction](https://openmrs.atlassian.net/wiki/x/94ABCQ) especially helpful.
Latest version: 8.0.0

:wave: New to our project? Be sure to review the [OpenMRS 3 Frontend Developer Documentation](https://openmrs.atlassian.net/wiki/x/IABBHg). You may find the [Introduction](https://openmrs.atlassian.net/wiki/x/94ABCQ) especially helpful.

Also see the [API documentation](./packages/framework/esm-framework/docs/API.md) for `@openmrs/esm-framework`, which is contained in this repository.

![OpenMRS CI](https://github.com/openmrs/openmrs-esm-core/workflows/OpenMRS%20CI/badge.svg)
![Check documentation](https://github.com/openmrs/openmrs-esm-core/actions/workflows/docs.yml/badge.svg)

Below is the documentation for this repository.

# O3 Frontend Core

This is a [monorepo](https://yarnpkg.com/advanced/lexicon#monorepo) containing the core packages for the O3 frontend. These packages handle cross-cutting concerns such as the configuration and extension systems, the core framework, global state management, the styleguide, and more.

## Available Packages

### Application

This contains tooling and the app shell.

- [openmrs](packages/tooling/openmrs)
- [@openmrs/esm-app-shell](packages/shell/esm-app-shell)

### Framework

The following common libraries have been developed. They may also be used independently of the app shell.

- [@openmrs/esm-api](packages/framework/esm-api): helps make API calls to the backend
- [@openmrs/esm-config](packages/framework/esm-config): validation and storage of frontend configuration
- [@openmrs/esm-context](packages/framework/esm-context): provides the AppContext for sharing contextual state across the app
- [@openmrs/esm-dynamic-loading](packages/framework/esm-dynamic-loading): provides functionality for dynamically loading frontend modules using Webpack Module Federation dynamic remotes
- [@openmrs/esm-error-handling](packages/framework/esm-error-handling): handles errors
- [@openmrs/esm-expression-evaluator](packages/framework/esm-expression-evaluator): provides functions that allow evaluation of user-defined expressions in a safer way than eval()
- [@openmrs/esm-extensions](packages/framework/esm-extensions): implementation of a frontend component extension system
- [@openmrs/esm-feature-flags](packages/framework/esm-feature-flags): hide features that are in progress
- [@openmrs/esm-globals](packages/framework/esm-globals): useful global variables and types
- [@openmrs/esm-navigation](packages/framework/esm-navigation): navigation utilities, breadcrumbs, and history
- [@openmrs/esm-offline](packages/framework/esm-offline): provides offline functionality
- [@openmrs/esm-react-utils](packages/framework/esm-react-utils): utilities for React components
- [@openmrs/esm-routes](packages/framework/esm-routes): provides helper functions for working with `routes.json` files in O3
- [@openmrs/esm-state](packages/framework/esm-state): brings in state management
- [@openmrs/esm-styleguide](packages/framework/esm-styleguide): styling and UI capabilities
- [@openmrs/esm-translations](packages/framework/esm-translations): common translations and utilities
- [@openmrs/esm-utils](packages/framework/esm-utils): general utility and helper functions

All libraries are aggregated in the `@openmrs/esm-framework` package:

- [@openmrs/esm-framework](packages/framework/esm-framework)

### Frontend modules

A set of frontend modules provides the core technical functionality of the application.

- [@openmrs/esm-devtools-app](packages/apps/esm-devtools-app)
- [@openmrs/esm-help-menu-app](packages/apps/esm-help-menu-app)
- [@openmrs/esm-implementer-tools-app](packages/apps/esm-implementer-tools-app)
- [@openmrs/esm-login-app](packages/apps/esm-login-app)
- [@openmrs/esm-primary-navigation-app](packages/apps/esm-primary-navigation-app)
- [@openmrs/esm-offline-tools-app](packages/apps/esm-offline-tools-app)

## Development

### Getting Started

To set up the repository for development, run the following commands:

```sh
yarn
yarn setup
```

> **Note:** If `yarn setup` fails or causes system resource issues, use this alternative instead:
>
> ```sh
> yarn build --concurrency 1
> ```
>
> Both commands build all the packages — once either completes successfully, you can proceed to [running the app shell and the framework](#running-the-app-shell-and-the-framework).

### Building

To build all packages in the repository, run the following command:

```sh
yarn build
```

You can also verify all packages in one step using `yarn`:

```sh
yarn verify
```

### Running the app shell and the framework

```sh
yarn run:shell
```

`run:shell` runs only the shell and the framework (not the frontend modules).

### Running the frontend modules in `apps`

```sh
yarn start --sources packages/apps/<app folder>
```

For example, to run the Login app, run:

```sh
yarn start --sources packages/apps/esm-login-app
```

This will spin up a development server with hot module reloading so any changes you make to the code in the app will be reflected automatically in the browser.

### Running the tooling

```sh
cd packages/tooling/openmrs
yarn build
./dist/cli.js
```

### Running tests

#### Unit tests

To run tests for all packages, run:

```bash
yarn turbo run test
```

To run tests in `watch` mode, run:

```bash
yarn turbo run test:watch
```

To run tests for a specific package, pass the package name to the `--filter` flag. For example:

```bash
yarn turbo run test --filter="@openmrs/esm-styleguide"
```

To run a specific test file, run:

```bash
yarn turbo run test -- login
```

This command runs tests only in files whose names match the provided string.

You can also run those matching tests in watch mode by running:

```bash
yarn turbo run test:watch -- login.test
```

To generate a `coverage` report, run:

```bash
yarn turbo run coverage
```

By default, `turbo` will cache test runs. This means that re-running tests without changing any of the related files will return the cached logs from the last run. To bypass the cache, run tests with the `force` flag, as follows:

```bash
yarn turbo run test --force
```

#### Running End-to-End (E2E) tests

E2E tests run against a complete OpenMRS stack in Docker containers. The test runner handles everything automatically: building the frontend, starting containers, running tests, and cleanup.

**Prerequisites:**

Install Playwright browsers before your first run:

```bash
npx playwright install
```

**Running E2E tests:**

```bash
yarn test-e2e
```

This single command will:
1. Build the frontend with your local changes
2. Start Docker containers (backend, database, gateway, frontend)
3. Wait for the backend to be ready
4. Run all E2E tests in headless mode
5. Automatically stop and remove containers when done

**Common options:**

```bash
# Run tests with browser visible
yarn test-e2e -- --headed

# Run tests in Playwright's interactive UI mode
yarn test-e2e -- --ui

# Run a specific test file
yarn test-e2e -- login.spec.ts

# Keep containers running on test failure (for debugging)
yarn test-e2e --keep-on-failure

# CLI-friendly output (no browser popup, useful for LLM tools)
yarn test-e2e --list
```

**Running tests on multiple branches:**

You can run E2E tests on different branches simultaneously in separate terminal windows. Each run automatically uses a unique port and container names based on your git branch, so there's no interference between concurrent test runs.

**Testing against a remote instance:**

To test against a remote instance instead of Docker containers, set the `E2E_BASE_URL` environment variable:

```bash
E2E_BASE_URL=https://dev3.openmrs.org/openmrs yarn playwright test
```

Note: When testing against a remote instance, use `yarn playwright test` directly (not `yarn test-e2e`) since you don't need the Docker environment.

Read the [e2e testing guide](https://openmrs.atlassian.net/wiki/spaces/docs/pages/150962731/Testing+Frontend+Modules+O3) to learn more about End-to-End tests in this project.

### Linking the framework

You probably want to try out your changes to a framework library in a frontend module. Unfortunately, getting a working development environment for this is very finicky; no one technique works for all frontend modules all the time.

Note that even though frontend modules import from `@openmrs/esm-framework`, the package you need to link is the sub-library; for example, if you are trying to test changes in `packages/framework/esm-api`, you will need to link that sub-library.

If you're unsure whether your version of a core package is running, add a `console.log` at the top level of a file you're working on.

Here are the tools at your disposal for trying to get this to work:

#### Yarn link

This should be the first thing you try. To link the styleguide, for example, you would use

```sh
yarn link ../path/to/openmrs-esm-core/packages/framework/esm-styleguide
```

This will add a line to the "resolutions" section of the `package.json` file which uses the `portal:` protocol. The other protocol is `link:`. If you need to make changes to the `esm-framework` package, you will need to link it in as well. However, linking `@openmrs/esm-framework` as a portal created by `yarn link` will not work; instead manually add the line to the `resolutions` field in the `package.json` file:

```json
"resolutions": {
  "@openmrs/esm-framework": "link:../path/to/openmrs-esm-core/packages/framework/esm-framework"
}
```

#### Yalc

Sometimes, the build tooling will simply not work with `yarn link`. In this case, you will need to use `yalc`.
Install `yalc` on your computer with:

```sh
npm install -g yalc
```

Then, link the repository you are working on. For `esm-api`, for example, run:

```sh
# In this repository
cd packages/framework/esm-api
yalc publish
cd ../../../openmrs-esm-patient-chart  # for example
yalc link @openmrs/esm-api
```

In order for Patient Chart to receive further updates you make to esm-api, you will need to run `yalc push` in the esm-api directory and `yalc update` in the Patient Chart directory.

### Running with a local version of the core packages

After linking the packages (using `yarn link` or `yalc`), the build tooling is satisfied, but you must do one more step to get the frontend to load these dependencies at runtime.

Here, there are two options:

#### Method 1: Using the frontend dev server

In order to get your local version of the core packages to be served in your local dev server, you will need to link the tooling as well.

```sh
yarn link /path/to/esm-core/packages/tooling/openmrs
```

You can try using `yalc` for this as well, if `yarn link` doesn't work. Or manually create a `link:` resolution in `package.json`.
In `packages/shell/esm-app-shell`, run:

```sh
yarn build:development --watch
```

to ensure the built app shell is updated with your changes and available to Patient Chart. Then run your Patient Chart dev server as usual, with `yarn start`.

#### Method 2: Using import map overrides

In this repository, start the app shell with `yarn run:shell`. Then, in the Patient Chart repository, `cd` into whatever package(s) you are working on and run `yarn serve` from there. Then use the import map override tool in the browser to tell the frontend to load your local Patient Chart packages.

#### Once it's working

Please note that any of these techniques will modify the `package.json` file. These changes must be undone before creating your PR. If you used `yarn link`, you can undo these changes by running:

```sh
yarn unlink --all
```

in the Patient Chart repo.

### Version and release

We use Yarn [workspaces](https://yarnpkg.com/features/workspaces) to handle versioning in this monorepo.

To increment the version, run the following command:

```sh
yarn release [version]
```

Where version corresponds to:

- `patch` for bug fixes e.g., `3.2.0` → `3.2.1`
- `minor` for new features that are backwards-compatible e.g., `3.2.0` → `3.3.0`
- `major` for breaking changes e.g., `3.2.0` → `4.0.0`

Note that this command will not create a new tag, nor publish the packages. After running it, make a PR or merge to `main` with the resulting changeset. Note that the release commit message must resemble `(chore) Release vx.x.x` where `x.x.x` is the new version number prefixed with `v`. This is to avoid triggering a pre-release build when effecting a version bump.

Once the version bump commit is merged, go to GitHub and [draft a new release](https://github.com/openmrs/openmrs-esm-core/releases/new).

The tag should be prefixed with `v` (e.g., `v3.2.1`), while the release title should just be the version number (e.g., `3.2.1`). The creation of the GitHub release will cause GitHub Actions to publish the packages, completing the release process.

> Don't run `npm publish`, `yarn publish`, or `lerna publish`. Use the above process.

### Important Notes About Version Updates

When releasing a new major version (e.g., moving from v6 to v7), you must:

1. Update all peerDependencies that reference `@openmrs/` packages in every package that depends on them.
2. Change the version notation from the current major version to the new one (e.g., from `6.x` to `7.x`).

Example:

```jsonc
// Before (during v6)
"peerDependencies": {
  "@openmrs/esm-config": "6.x",
  "@openmrs/esm-utils": "6.x"
}

// After (for v7)
"peerDependencies": {
  "@openmrs/esm-config": "7.x",
  "@openmrs/esm-utils": "7.x"
}
```

This ensures that all packages use compatible versions and breaking changes are properly tracked.

## Design Patterns

For documentation about our design patterns, please visit our [design system documentation website](https://om.rs/o3ui).

## Bumping Playwright

Be sure to update the Playwright version in the [Bamboo Playwright Docker image](e2e/support/bamboo/playwright.Dockerfile) whenever making version changes.
Also, ensure you specify fixed (pinned) versions of Playwright in the `package.json` file to maintain consistency between the Playwright version used in the Docker image for Bamboo test execution and the version used in the codebase.