{"id":14957701,"url":"https://github.com/redpelicans/farso","last_synced_at":"2026-02-03T06:35:44.376Z","repository":{"id":31867924,"uuid":"129638332","full_name":"redpelicans/farso","owner":"redpelicans","description":"express middleware library to mock http server","archived":false,"fork":false,"pushed_at":"2023-01-06T01:57:56.000Z","size":2083,"stargazers_count":0,"open_issues_count":20,"forks_count":0,"subscribers_count":1,"default_branch":"develop","last_synced_at":"2025-03-15T06:35:47.749Z","etag":null,"topics":["express-middleware","expressjs","http","mocking","testing"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/redpelicans.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-04-15T18:23:30.000Z","updated_at":"2020-11-16T09:50:53.000Z","dependencies_parsed_at":"2023-01-14T19:57:25.969Z","dependency_job_id":null,"html_url":"https://github.com/redpelicans/farso","commit_stats":null,"previous_names":["redpelicans/trip"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redpelicans%2Ffarso","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redpelicans%2Ffarso/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redpelicans%2Ffarso/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redpelicans%2Ffarso/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/redpelicans","download_url":"https://codeload.github.com/redpelicans/farso/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247653249,"owners_count":20973790,"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":["express-middleware","expressjs","http","mocking","testing"],"created_at":"2024-09-24T13:15:21.913Z","updated_at":"2026-02-03T06:35:39.348Z","avatar_url":"https://github.com/redpelicans.png","language":"JavaScript","readme":"# farso\n\n[![Build Status](https://travis-ci.org/redpelicans/farso.svg?branch=develop)](https://travis-ci.org/redpelicans/farso)\n[![Coverage Status](https://coveralls.io/repos/github/redpelicans/farso/badge.svg?branch=develop)](https://coveralls.io/github/redpelicans/farso?branch=develop)\n\n`farso` is an HTTP mocking library for nodeJS.\n\n`farso` is mainly used to craft e2e/human tests of HTTP services.\n\n# How does it work?\n\n`farso` is made for developers and avoid the use of tons of json files to setup mocks, it offers a comprehensive DSL and a low level api based on [expressjs](http://expressjs.com) so developers can precisely tweak their mock services to their needs where DSL do not cover use cases.\n\nMocking with `farso` invite you to travel in different vibes!\n\nFirst of all, you have to define `endpoints` (destinations) you want to mock.\n\nThen define all the `vibes` (scenarios) of your farso.\n\nA `vibe` is made of mocks (mocked endpoints). Definition of mocks are inspired by [nock](https://github.com/node-nock/nock)\n\n`farso` library is bundled with an http server api (also bin script) to run your vibes.\n\nThen manually or from your testing framework you can select the desired vibe and request endpoints, `farso` will try to select an eligible mock and execute it. Because many `mocks` can be associated to an `endpoint`, `farso` will in the order of definition run the first that matches (see check methods below). If no eligible `mock` matches in current vibe `farso` will search in the default vibe to look for one.\n\nRun tests on it, change the vibe and ...\n\n# Install\n\n```\n$ npm install farso\n```\n\n# farso at first glance\n\nLet's say your system is using a CRM backoffice with an HTTP API offering an endpoint `GET /public/v0/people`.\n\nYou have to mock this endpoint.\n\nFirst install `farso`, then add config files below: \n\n```\n// ./endpoints.js\n\nconst { endpoint } = require('farso');\nendpoint('people', { uri: '/public/v0/people', method: 'get' });\n\n// vibes.js\nconst { vibe } = require('farso');\nconst faker = require('faker');\nconst people = [\n  {id: 1, name: faker.name.lastName()},\n  {id: 2, name: faker.name.lastName()},\n];\n\nvibe.default('Main', mock =\u003e {\n  mock('people')\n    .checkHeader({ 'x-corporis': /^\\d+-\\w+$/ })\n    .reply([200, people]);\n});\n\n\n// farso.config.js\nmodule.exports = {\n  host: 'localhost',\n  // port: 8181,\n  vibes: path.join(__dirname, './vibes.js'),\n  endpoints: path.join(__dirname, './endpoints.js'),\n};\n```\n\nThen run:\n\n```\n$ DEBUG=farso* npx farso-server --config ./farso.config.js \n  farso Creating Vibe 'Main'\n  farso Endpoint 'people:/public/v0/people' created\n  farso Vibe 'Main' is now active\n  farso server started on 'http://localhost:33811'\n```\n\nAnd now:\n\n```\n$ curl http://localhost:33811/public/v0/people\n[{\"id\":1,\"name\":\"Mohr\"},{\"id\":2,\"name\":\"Muller\"}]                  \n```\n\nHere it is, you made your first farso mock.\n\n# DSL API\n\n## config\n\nWith DSL api we will use the embendded server and will setup farso library with setup files like above sample. \n\n`config` file must export and object with those properties:\n\n* `host`: default to localhost\n* `port`: optional, server's binding port, when no set server will bind dynamically to an available port\n* `bodySizeLimit`: see [limit property](http://expressjs.com/fr/api.html#express.json)\n* `errorCode`: optional, http status code to return when an `endpoint` matches without a `mock`.\n* `vibes`: glob partern to select vibe's files to load (see below) ex : `path.join(__dirname, './data/**/*.vibes.js')` or just `path.join(__dirname, './vibes.js')`\n* `endpoint`: glob partern to select endpoint's files to load (see below)\n* `globals`: optional, data injected to vibes (see below) to share states between http calls and vibes.\n\n\n```\nconst path = require('path');\nconst faker = require('faker');\n\nmodule.exports = {\n  host: 'localhost',\n  port: 8181,\n  vibes: path.join(__dirname, './mock/**/*.vibe.js'),\n  endpoints: path.join(__dirname, './mock/endpoints.js'),\n  globals: {\n    api: {\n      clientId: faker.random.uuid(),\n      clientSecret: faker.random.uuid(),\n    },\n  },\n};\n\n```\n\nfarso's server must be launched with: ``` $ DEBUG=farso* npx farso-server --config ./farso.config.js ```\n\nServer can be also setup and launched thanks { initTrip, initServer, runServer } functions exported from \n'farso-mock/server' (see Low Level API section below)\n\n## endpoint\n\n`endpoint` files are used to define ..., endpoints, aka `expressjs` routes.\n\n```\n\tconst { endpoint } = require('farso-mock');\n\tendpoint('people:list', { uri: '/public/v0/people', method: 'get' });\n\tendpoint('people:get', { uri: '/public/v0/people/:id', method: 'get' });\n\tendpoint('people:create', { uri: '/public/v0/people', method: 'post' });\n\tendpoint('people:update', { uri: '/public/v0/people/:id', method: 'patch' });\n```\n\nex: First call to `endpoint` will register an expressjs route on GET '/public/v0/people'\n\n**function endpoint(name, params)**\n* `name`: String to identify an endpoint\n* `params`: \n\t* `uri`: endpoint's path\n\t* `method`: optional, endpoint's http method name\n\t* `use`: optional, expressjs middleware(s) associated with endpoint, could be useful to serve static files or code specific behaviour like ```endpoint('configs', { uri: '/configs', use: express.static(path.join(__dirname, './')) });```\n\t\n\t\n## vibe\n\n`endpoints` are useless without `vibe`, an endpoint will be associated with many vibes made of mocks:\n\n```\nconst personSchema = { \n\tfirstname: /\\w+/,\n\tlastname: /\\w+/\n};\n\t\nvibe('Main', (mock, {globals: { api: { clientId, clientSecret } } }) =\u003e { \n\tmock('people:list').reply([200, people]);\n\tmock('people:get').checkParams({ id: /\\d+/ }).reply([200, person]);\n\tmock('people:create').checkBoby(personSchema).reply([200, person]);\n\tmock('people:update').checkParams({ id: /\\d+/ }).checkBoby(personSchema).reply([200, person]);\n})\n```\n\n**function vibe(name, fn, options) or vibe.default(name, fn)**\n* `name`: String **must** match an existing `endpoint`\n* `options`: { isDefault }, set vibe as default\n* `fn`: function(mock, { globals, lget, lvalue })\n\t* `mock`: function to define new mocks (see below)\n\t* `globals`: config's `globals` property \n\t* `lget`: function(String|Array): Object (see below)\n\t* `lvalue`: function(String|Array): Object (see below) \n\t\nreturns the current `farso`.\n\nA default `vibe` will become the current one to search mocks, to switch to another one use `farso#select(name)` or HTTP API.\n\nWhen a non default `vibe` is selected, eligible mocks are first searched in former `vibe` then in the default one.\n\nfarso's server offers a minimalist http api to list existing vibes:\n\n```\n$ curl http://[host:port]/_vibes_\n{\n\tcurrentVibe: \"Main\",\n\tvibes: [\n\t\t\"Main\", \"Wrong_auth\"\n\t]\n}\n```\n\nand select one:\n\n```\n$ curl http://[host:port]/_vibes_/Wrong_auth\n{\n\tcurrentVibe: \"Wrong_auth\"\n}\n```\n\n## mock\n\nA `mock` defines the behaviour of an `endpoint`:\n\n```\nvibe('V1', mock =\u003e mock('people:list').reply(200));\n```\nRequesting endpoint 'people:list' will return HTTP status code 200.\n\nWe can define many mocks per `endpoint`:\n\n```\nvibe('V1', mock =\u003e {\n\tmock('people:list').reply(200);\n\tmock('people:get').reply([200, person]);\n});\n```\nor like this:\n\n```\nvibe('V1', mock =\u003e mock('people:list').reply(200));\nvibe('V1', mock =\u003e \tmock('people:get').reply([200, person]));\n```\n\nWe can define many mocks for the same `endpoint`:\n\n```\nvibe('V1', mock =\u003e mock('people:get').checkParams({ id: '12'}).reply([200, person]));\nvibe('V1', mock =\u003e \tmock('people:get').checkParams({ id: '13'}).reply(404));\n```\n\nOrder of definition matters.\n\n\nWe can define many mocks for the same `endpoint` in many vibes, in case you overwrite a mock already defined in the default endpoint, former wil be used. With a default `vibe`, an eligible mock is first look into current vibe, then if not found, in the default one.\n\n\n### checkParams\n\nCheck url [params](https://expressjs.com/en/4x/api.html#req.params)\n\nEx: param `id`\n\n```\nendpoint('people:get', { uri: '/public/v0/people/:a/:b', method: 'get' });\nvibe('V1', mock =\u003e  {\n\tmock('people:get')\n\t\t.checkParams({ a: '12', b: '13'})\n\t\t.checkParams({ a: /\\d+/ b: :\\w+X$/})\n\t\t.checkParams(({ a }) =\u003e Number(a) \u003c 5)\n\t\t.reply(200);\n})\n```\n\nendpoint's `uri` property use expressjs route's syntax definition.\n\n**function checkParams(options)**\n* `options`: Object | Function\n\t* Object: if key/value do not match req.params `mock` will not be eligible, values can be a String or a RegExp\n\t* Function: `function(params): Boolean`, if returns false `mock` will not be eligible.\n\nreturns the current `mock`.\n\n### checkHeaders\n\nCheck that requested headers match request.\n\n**function checkHeaders(options)**\n* `options`: Object | Function\n\t* Object: if key/value do not match sent headers `mock` will not be eligible, values can be a String or a RegExp, keys are converted to lower case.\n\t* Function: `function(headers): Boolean`, if it returns false `mock` will not be eligible.\n\n\n### checkQuery\n\nCheck that requested query match request.\n\n**function checkQuery(options)**\n* `options`: Object | Function\n\t* Object: if key/value do not match [req.body](https://expressjs.com/en/4x/api.html#req.body) `mock` will not be eligible, values can be a String or a RegExp.\n\t* Function: `function(query): Boolean`, if it returns false `mock` will not be eligible.\n\n\n### checkBody\n\nCheck that requested body match request.\n\n**function checkBody(options)**\n* `options`: Object | Function\n\t* Object: if key/value do not **deeply** match [req.query](https://expressjs.com/en/4x/api.html#req.query) `mock` will not be eligible, values can be a String or a RegExp. Object can be a nested object, is this case comparaison will be made using `farso.deepMatch`.\n\t* Function: `function(body): Boolean`, if it returns false `mock` will not be eligible.\n\n### reply\n\nFunction executed when a mock is eligible.\n\n**function reply(options)**\n* options: Number | Function | Array\n\t* Number: status code to return: ``` res.sendStatus(options)```\n\t* Array: [status, data]: ```res.status(options[0]).send(options[1])```\n\t* Function: `function(req, res)`\n\nreturns current `mock`\n\n### lset/lget\n\n`lset/lget/lvalue` allow to manage a local context between requests for the current vibe.\n\nWe can share global data thanks to `globals` prop in config and use it in vibes definition:\n\n```\n// farso.config.js\nconst path = require('path');\nconst faker = require('faker');\n\nmodule.exports = {\n  host: 'localhost',\n  port: 8181,\n  vibes: path.join(__dirname, './examples/**/*.vibe.js'),\n  endpoints: path.join(__dirname, './examples/endpoints.js'),\n  globals: {\n    api: {\n      clientId: faker.random.uuid(),\n      clientSecret: faker.random.uuid(),\n    },\n  },\n};\n\n// main.vibe.js\n\nvibe('Main', (mock, globals)  =\u003e { \n\tmock('people:list').reply((req, res) =\u003e {\n\t\tglobals.propA = valueA;\n\t\tres.send(200);\n\t});\n})\n\n```\n\nBut to avoid dirty side effect here comes `lset/lget/lvalue`:\n\n```\nvibe.default('Main', (mock, { lget, globals: { token }}) =\u003e {\n\n  mock('token')\n    .lset(({ body }) =\u003e [['data', 'firstname'], body.firstname])\n    .lset(({ body }) =\u003e [['data', 'lastname'], body.lastname])\n    .reply([201, token]);\n\n  const req_create_claim = {\n    firstname: lget['data', 'firstname']),\n   \tlastname: lget(['data', 'lastname']),\n  };\n\n  mock('claim:create')\n    .checkBody(req_create_claim)\n    .lset(({ body }) =\u003e [['data', 'claim'], body])\n    .reply(201);\n```\n\n**function lget(fn)**\n* fn: `function(Object): Object`, returns a getter on current vibe's `locals`\nuse case: ```lget(['data', 'lastname'))``` returns a getter on ```farso.currentVibe.locals.data.lastname```\ngetter will be evaluated by checker (check* methods)\n\n**function lset(fn)**\n* fn: `function(req): returns [path, value]`\nUse case : ```mock('token').lset(({ body }) =\u003e [['data', 'firstname'], body.firstname])``` will  exec ``` farso.currentVibe.locals.data.firstname = body.firstname```\n\n**function lvalue(fn)**\n* fn: `function(Object): Object`, returns value from current vibe's `locals`\nuse case: ```lvalue(['data', 'lastname'))``` returns ```lget(['data', 'lastname')).value```\n\n\n\n## GraphQL\n\nSince version 1.2.0 `farso` allow to mock GraphQL queries/mutations\n\nFirst define an endpoint:\n\n\n```\n// cat ./schema.graphql\ntype Query {\n  echo(message: String): String\n}\n```\n\n```\nimport { GraphQL } rom 'farso/graphql');\nconst schema = join(__dirname, './schema.graphql');\nendpoint('graphql', { uri: '/graphql', use: GraphQL({ schemaPath: schema }) });                                \n```\n\nGraphQL endpoints use a special middleware `GraphQL`, with the path of our graphql's schema.\n\nThen mock in vibes:\n\n```\nvibe.default('main', mock =\u003e {\n  const mocks = {\n    Query: () =\u003e ({\n      echo: (_, { message }) =\u003e message,\n    })\n  }\n  mock('graphql').resolve(mocks);\n});\n```\n\nMocking is made at resolver level and use [addMocksToSchema](https://www.graphql-tools.com/docs/mocking/)\n\nUnlike HTTP mocks, we cannot define many mocks for a single endpoint in one vibe, onlu first call of `resolve` will be used.\n\nYou can get a full example in `__tests__/graphql.test.js`\n\n# Low level API\n\n## server\n\n`farso` server can be launched thanks to `farso-server` script, like:\n\n```\n$ DEBUG=farso* npx farso-server --config ./farso.config.js\n```\n\nBut also with API entries, it could be useful if we want to start a mock server within test and not before:\n\n```\nconst { runServer } = require('farso/server');\n\nlet farsoServer;\n\nconst config = {\n  vibes: path.join(__dirname, '../../examples/api.vibe.js'),\n  endpoints: path.join(__dirname, '../../examples/endpoints.js'),\n  globals,\n};\n\nbeforeAll(() =\u003e runServer(config).then(({ server }) =\u003e (farsoServer = server)));\nafterAll(() =\u003e farsoServer.close());\n```\n\n\n## farso\n\nWe can dynamically register `endpoints` and create `vibes`, see unit tests for different samples.\n\n```\nconst { initServer } = require('farso/server');\nconst Farso = require('farso');\n\nlet ctx;\nlet farso;\nconst initFarso = () =\u003e {\n  farso = Farso({ errorCode });\n  farso.createEndpoint('test', { uri: '/test', method: 'post' });\n  farso.registerEndpoints();\n  return Promise.resolve({ farso });\n};\n\nbeforeAll(() =\u003e\n  initFarso()\n    .then(initServer)\n    .then(c =\u003e (ctx = c)));\nafterAll(() =\u003e ctx.server.close());\n\ndescribe('...', () =\u003e {\n  it('should ...', () =\u003e {\n    farso\n      .createVibe('v1', mock =\u003e mock('test').reply(200))\n      .select('v1');\n    return axios({ method: 'post', url: `${ctx.server.url}/test` });\n  });\n\n```\n\n\nThat's all folks...\n\n\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredpelicans%2Ffarso","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fredpelicans%2Ffarso","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredpelicans%2Ffarso/lists"}