{"id":15017933,"url":"https://github.com/aspecto-io/malabi","last_synced_at":"2026-04-15T08:30:18.233Z","repository":{"id":43013544,"uuid":"359470624","full_name":"aspecto-io/malabi","owner":"aspecto-io","description":"Tracing Based JavaScript Assertions","archived":false,"fork":false,"pushed_at":"2024-05-16T09:29:02.000Z","size":545,"stargazers_count":203,"open_issues_count":4,"forks_count":6,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-10-10T17:46:20.423Z","etag":null,"topics":["javascript","nodejs","opentelemetry","testing","tracing"],"latest_commit_sha":null,"homepage":"https://aspecto-io.github.io/malabi/index.html","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aspecto-io.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-04-19T13:31:25.000Z","updated_at":"2024-09-27T03:04:06.000Z","dependencies_parsed_at":"2024-06-19T00:26:12.511Z","dependency_job_id":"765af7ab-b28a-4598-aa02-82df51eb4cf1","html_url":"https://github.com/aspecto-io/malabi","commit_stats":{"total_commits":65,"total_committers":8,"mean_commits":8.125,"dds":0.6615384615384615,"last_synced_commit":"132b9aa6b9c37d0e027db574f4690324a3c41d99"},"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aspecto-io%2Fmalabi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aspecto-io%2Fmalabi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aspecto-io%2Fmalabi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aspecto-io%2Fmalabi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aspecto-io","download_url":"https://codeload.github.com/aspecto-io/malabi/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":219847662,"owners_count":16556349,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["javascript","nodejs","opentelemetry","testing","tracing"],"created_at":"2024-09-24T19:51:13.078Z","updated_at":"2026-04-15T08:30:18.174Z","avatar_url":"https://github.com/aspecto-io.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align='center'\u003e\n  \u003cimg src='https://github.com/aspecto-io/malabi/blob/master/assets/malabilogo.png?raw=true' width=\"400px\" alt='Malabi'/\u003e\n\u003c/p\u003e\n\u003cp align='center'\u003e\n    OpenTelemetry based Javascript test framework\n\u003c/p\u003e\n\n\u003ca href=\"https://github.com/aspecto-io/malabi/blob/master/LICENSE\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/license/aspecto-io/malabi\" alt=\"Malabi is released under the Apache-2.0 license.\" /\u003e\n\u003c/a\u003e\n\n# Description\nThis library introduces a new way of testing services: \u003ca href=\"#tbt\"\u003e**Trace-based testing**\u003c/a\u003e (TBT). It is very useful when you want to validate integration between different parts. For example: make sure elasticsearch received the correct params on insert.\n\n- 💻 **Developer friendly**: Built by developers, for developers who love distributed applications.\n\n- ✅ **Validate integration**: Access to validate any backend interaction, fast, simple and reliable.\n\n- 🔗 **OpenTelemetry based**: Built based on OpenTelemetry to match the characteristics of distributed apps.\n\n\n## How it works\n\u003cimg src='https://github.com/aspecto-io/malabi/blob/master/assets/diagram.png?raw=true' alt='How it work diagram'\u003e\n\nThere are two main components to Malabi:\n\n1. An OpenTelemetry SDK Distribution - used to collect any activity in the service under test by instrumenting it. **It is stored in the memory of the asserted service or in a Jaeger instance **, and exposes and endpoint for the test runner to access \u0026 make assertions.\n\n2. An assertion library for OpenTelemetry data - by using the `malabi` wrapper function you will get access to any span created by the current test, then you will be able to validate the span and the service behavior\n\n## Getting started\n### In the microservice you want to test\n1. ```npm install --save malabi``` or ```yarn add malabi```\n2. Add the following code at the service initialization, for example: in index.js. needs to be before any other imports to work properly.\n\n```JS\nimport { instrument, serveMalabiFromHttpApp } from 'malabi';\nconst instrumentationConfig = {\n    serviceName: 'service-under-test',\n};\ninstrument(instrumentationConfig);\nserveMalabiFromHttpApp(18393, instrumentationConfig);\n\nimport axios from 'axios';\nimport express from 'express';\nimport User from \"./db\";\nconst PORT = process.env.PORT || 8080;\n\nconst app = express();\n\napp.get('/todo', async (req, res) =\u003e {\n    try {\n        const todoItem = await axios('https://jsonplaceholder.typicode.com/todos/1');\n        res.json({\n            title: todoItem.data.title,\n        });\n    } catch (e) {\n        res.sendStatus(500);\n        console.error(e, e);\n    }\n});\n```\n\n## In your test file\nCreate a tracing.ts file to set up instrumentation on the tests runner(this enables us to separate spans created in one test from other tests' spans from the other):\n```JS\nimport { instrument } from 'malabi';\n\ninstrument({\n    serviceName: 'tests-runner',\n});\n```\n\nAnd this is how the test file looks like(service-under-test.spec.ts):\nNote: this should be run with node --require.\n\nAlso, you must provide the MALABI_ENDPOINT_PORT_OR_URL env var (must start with http for url)\n```\nMALABI_ENDPOINT_PORT_OR_URL=http://localhost:18393 ts-mocha --paths \"./test/*.ts\" --require \"./test/tracing.ts\"\n```\nOr alternatively just with port(assuming localhost by default):\n```\nMALABI_ENDPOINT_PORT_OR_URL=18393 ts-mocha --paths \"./test/*.ts\" --require \"./test/tracing.ts\"\n```\n\nSample test code:\n```JS\nconst SERVICE_UNDER_TEST_PORT = process.env.PORT || 8080;\nimport { malabi } from 'malabi';\n\nimport { expect } from 'chai';\nimport axios from 'axios';\n\ndescribe('testing service-under-test remotely', () =\u003e {\n    it('successful /todo request', async () =\u003e {\n        // get spans created from the previous call\n        const telemetryRepo = await malabi(async () =\u003e {\n            await axios(`http://localhost:${SERVICE_UNDER_TEST_PORT}/todo`);\n        });\n\n        // Validate internal HTTP call\n        const todoInternalHTTPCall = telemetryRepo.spans.outgoing().first;\n        expect(todoInternalHTTPCall.httpFullUrl).equals('https://jsonplaceholder.typicode.com/todos/1')\n        expect(todoInternalHTTPCall.statusCode).equals(200);\n    });\n});\n```\n\nNotice the usage of the malabi function - any piece of code that we put inside the callback given to this function would be instrumented as part\nof a newly created trace (created by malabi), and the return value would be the telemetry repository for this test, meaning the \nOpen Telemetry data you can make assertions on (the spans that were created because of the code you put in the callback).\n\nTo sum it up, be sure that whenever you want to make assertions on a span - the code that created it must be in the callback the malabi function receives, and the malabi function returns the spans created.\n\n## Storage Backends\nMalabi supports 2 types of storage backends for the telemetry data created in your test (spans and traces).\n1. InMemory - In this mode malabi stores the data in memory.  \nTo select this mode, set MALABI_STORAGE_BACKEND env var to `InMemory`  \n2. Jaeger - To select this mode, set MALABI_STORAGE_BACKEND env var to `Jaeger` when running your service under test.  \n\nAlso, you can control additional env vars here:\n   1. OTEL_EXPORTER_JAEGER_AGENT_HOST - lets you control the hostname of the jaeger agent. it must be running somewhere for this mode to work and it's up to you to make it run. default: `localhost`  \n   Example values: `localhost`,`example.com`.\n   2. OTEL_EXPORTER_JAEGER_AGENT_PORT - port of jaeger agent. default: `6832`\n   3. MALABI_JAEGER_QUERY_PROTOCOL - the protocol used to query jaeger API for the spans. Either `http`(default) or `https`.\n   4. MALABI_JAEGER_QUERY_PORT - the port which we use to query jaeger. default: `16686`\n   5. MALABI_JAEGER_QUERY_HOST - ets you control the hostname of the jaeger query api. default: `localhost`\n\nFor both storage backends, malabi creates an endpoint (hosted inside the service-under-test) for the test runner to call query.\n\n## Caveat: Usage with Jest\n\nCurrently, Jest does not play out well with OpenTelemetry due to Jest's modifications of the way modules are required and OTEL's usage of \nrequire in the middle. \n\nUntil this is fixed, we recommend using Malabi with Mocha instead of Jest.\n\n## Documentation\n[Click to view documentation](https://aspecto-io.github.io/malabi/index.html)\n\n## Why should you care about Malabi\nMost distributed apps developers choose to have some kind of black box test (API, integration, end to end, UI, you name it!).\n\nBlack box test create real network activity which is instrumented by OpenTelemetry (which you should have regardless of Malabi).\n\nImagine that you can take any existing black box test and validate any backend activity created by it.\n\n#### Common use case\nYou are running an API call that create a new DB record, then you write dedicated test code to fetch the record created and validate it.\nNow you can rely on Malabi to validate that mongo got the right data with no special code.\n\n## \u003ca name=\"tbt\"\u003eTrace based testing explained\u003c/a\u003e\nTrace-based testing is a method that allows us to improve assertion capabilities by leveraging traces data and make it accessible while setting our expectations from a test. That enables us to **validate essential relationships between software components that otherwise are put to the test only in production**.\nTrace-based validation enables developers to become proactive to issues instead of reactive.\n## More examples\n\n```JS\nimport { malabi } from 'malabi';\n\nit('should select from db', async () =\u003e {\n    const { spans } = await malabi(async () =\u003e {\n        // some code here that makes db operations with sequelize\n    });\n    \n    // Validating that /users had ran a single select statement and responded with an array.\n    const sequelizeActivities = spans.sequelize();\n    expect(sequelizeActivities.length).toBe(1);\n    expect(sequelizeActivities.first.dbOperation).toBe(\"SELECT\");\n    expect(Array.isArray(JSON.parse(sequelizeActivities.first.dbResponse))).toBe(true);\n});\n```\n\n[See in-repo live example](https://github.com/aspecto-io/malabi/tree/master/examples/README.md)\n\n## Project Status\nMalabi project is actively maintained by [Aspecto](https://www.aspecto.io), and is currently in it's initial days. We would love to receive your feedback, ideas \u0026 contributions in the [discussions](https://github.com/aspecto-io/malabi/discussions) section.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faspecto-io%2Fmalabi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faspecto-io%2Fmalabi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faspecto-io%2Fmalabi/lists"}