{"id":13789201,"url":"https://github.com/jirutka/nginx-testing","last_synced_at":"2025-07-12T23:01:49.991Z","repository":{"id":65458222,"uuid":"325879194","full_name":"jirutka/nginx-testing","owner":"jirutka","description":"Support for integration/acceptance testing of nginx configuration in TypeScript/JavaScript.","archived":false,"fork":false,"pushed_at":"2023-07-19T00:55:28.000Z","size":325,"stargazers_count":22,"open_issues_count":3,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-11-15T04:13:00.961Z","etag":null,"topics":["nginx","njs","test-server","testing","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jirutka.png","metadata":{"files":{"readme":"README.adoc","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":"jirutka"}},"created_at":"2020-12-31T21:59:19.000Z","updated_at":"2024-09-24T11:55:51.000Z","dependencies_parsed_at":"2024-03-31T23:44:26.580Z","dependency_job_id":null,"html_url":"https://github.com/jirutka/nginx-testing","commit_stats":{"total_commits":73,"total_committers":1,"mean_commits":73.0,"dds":0.0,"last_synced_commit":"2f1c1b7fdc1e95c8c46791594439776d0f293a56"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jirutka%2Fnginx-testing","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jirutka%2Fnginx-testing/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jirutka%2Fnginx-testing/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jirutka%2Fnginx-testing/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jirutka","download_url":"https://codeload.github.com/jirutka/nginx-testing/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253668021,"owners_count":21944962,"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":["nginx","njs","test-server","testing","typescript"],"created_at":"2024-08-03T21:00:59.975Z","updated_at":"2025-05-12T03:31:29.561Z","avatar_url":"https://github.com/jirutka.png","language":"TypeScript","funding_links":["https://github.com/sponsors/jirutka"],"categories":["Tools"],"sub_categories":["Lua Modules"],"readme":"= nginx testing\n:toc: macro\n:toc-title:\n// custom\n:npm-name: nginx-testing\n:gh-name: jirutka/{npm-name}\n\nifdef::env-github[]\nimage:https://github.com/{gh-name}/workflows/CI/badge.svg[Build Status, link=https://github.com/{gh-name}/actions?query=workflow%3A%22CI%22]\nimage:https://img.shields.io/npm/v/{npm-name}.svg[npm Version, link=\"https://www.npmjs.org/package/{npm-name}\"]\nimage:https://badgen.net/bundlephobia/dependency-count/{npm-name}[Dependency Count, link=\"https://bundlephobia.com/result?p={npm-name}\"]\nendif::env-github[]\n\nThis project provides support for easy integration/acceptance testing of https://nginx.org/[nginx] configuration using TypeScript or JavaScript, primarily for testing https://nginx.org/en/docs/njs/[njs] (NGINX JavaScript) scripts.\n\nIt allows you to run tests against various nginx versions on any Linux, macOS or Windows (x64) system without need to install nginx or use some overcomplex methods such as Docker footnote:[Yes, that’s right, you don’t need Docker to run a damn binary!].\n{npm-name} automatically downloads a precompiled nginx binary for your system and architecture from project https://github.com/jirutka/nginx-binaries[nginx-binaries].\n\n\nifndef::npm-readme[]\n[discrete]\n== Table of Contents\n\ntoc::[]\nendif::npm-readme[]\n\n\n== Installation\n\n[source, sh, subs=\"+attributes\"]\n----\n# using npm:\nnpm install --save-dev {npm-name}\n# or using yarn:\nyarn add --dev {npm-name}\n----\n\n\n== Usage Examples\n\n=== Testing with Mocha\n\n._example.test.ts:_\n[source, ts]\n----\nimport { strict as assert } from 'assert'\nimport { after, afterEach, before, beforeEach, test } from 'mocha'\nimport { startNginx, NginxServer } from 'nginx-testing'\nimport fetch from 'node-fetch'\n\nlet nginx: NginxServer\n\nbefore(async () =\u003e {\n  nginx = await startNginx({ version: '1.24.x', configPath: './nginx.conf' })\n})\n\nafter(async () =\u003e {\n  await nginx.stop()\n})\n\nbeforeEach(async () =\u003e {\n  // Consume logs (i.e. clean them before the test).\n  await nginx.readAccessLog()\n  await nginx.readErrorLog()\n})\n\nafterEach(async function () {\n  // Print logs if the test failed.\n  if (this.currentTest?.state === 'failed') {\n    console.error('Access log:\\n' + await nginx.readAccessLog())\n    console.error('Error log:\\n' + await nginx.readErrorLog())\n  }\n})\n\ntest('GET / results in HTTP 200', async () =\u003e {\n  const resp = await fetch(`http://localhost:${nginx.port}/`)\n  assert.equal(resp.status, 200)\n})\n----\n\n._nginx.conf:_\n[source, nginx]\n----\nevents {\n}\nhttp {\n  server {\n    listen localhost:__PORT__;\n\n    location / {\n      return 200 \"OK\";\n    }\n  }\n}\n----\n\n\n== API\n:Writable: link:https://nodejs.org/api/stream.html#stream_class_stream_writable[stream.Writable]\n\n// NOTE: Keep the API section in sync with TSDoc comments in the sources (until I figure out how to generate it).\n\n// Pandoc conversion to Markdown doesn't handle definition lists.\nifdef::npm-readme[]\nhttps://github.com/{gh-name}#api[See on GitHub].\n\nendif::npm-readme[]\nifndef::npm-readme[]\n\n[[startNginx]] startNginx `(opts: \u003c\u003cNginxOptions\u003e\u003e) =\u003e Promise\u003c\u003c\u003cNginxServer\u003e\u003e\u003e`::\nStarts nginx server with the given configuration.\n+\n.Example:\n[source, ts]\n----\nimport { startNginx, NginxServer } from 'nginx-testing'\nimport fetch from 'node-fetch'\n\nlet nginx: NginxServer\n\nbefore(async () =\u003e {\n  nginx = await startNginx({ version: '1.24.x', configPath: './nginx.conf' })\n})\nafter(nginx.stop)\n\ntest('GET / results in HTTP 200', async () =\u003e {\n  const resp = await fetch(`http://localhost:${nginx.port}/`)\n  assert(resp.status === 200)\n})\n----\n\n[[nginxVersionInfo]] nginxVersionInfo `(nginxBinPath: string) =\u003e Promise\u003c\u003c\u003cNginxVersionInfo\u003e\u003e\u003e`::\nExecutes the nginx binary `nginxBinPath` with option `-V` and returns parsed version and info about the modules it was compiled with(out).\n\n[[parseConf]] parseConf `(source: string) =\u003e \u003c\u003cNginxConfEditor\u003e\u003e`::\nParses the given nginx config.\n\n[[setLogger]] setLogger `(logger: object) =\u003e void`::\nUse the given logger -- an object with functions `debug`, `info`, `warn`, and `error`.\nUndefined logging functions will be replaced with no-op.\n+\nSee section \u003c\u003cLogging\u003e\u003e for more information.\n\n\n=== NginxOptions\n\nOptions for \u003c\u003cstartNginx, `startNginx()`\u003e\u003e.\n\nbinPath `(?string)`::\nName or path of the nginx binary to start.\nDefaults to `'nginx'`.\n+\nThis option is ignored if `version` is provided.\n\nversion `(?string)`::\nA SemVer version range specifying the nginx version to run.\n+\nNginx binary for your OS and architecture will be downloaded from https://github.com/jirutka/nginx-binaries[nginx-binaries].\nIt will be stored in directory `.cache/nginx-binaries/` inside the nearest writeable `node_modules` directory or in `nginx-binaries/` inside the system-preferred temp directory.\n+\nNot all versions are available.\nYou can find a list of available binaries at https://jirutka.github.io/nginx-binaries/[nginx-binaries].\n\nconfig `(?string)`::\n+\n--\nNginx configuration to use.\n\nIf `configPath` is provided, the processed config will be written to a temporary file `.\u003cfilename\u003e~` (where `\u003cfilename\u003e` is a filename from `configPath`) in the `configPath`’s directory (e.g. `conf/nginx.conf` -\u003e `conf/.nginx.conf~`).\nOtherwise it will be written into `nginx.conf` file in `workDir`.\nIn either case, this file will be automatically deleted after stopping the nginx.\n\nThe config may include the following placeholders which will be replaced with\ncorresponding values:\n\n* `++__ADDRESS__++` -- The address as specified in `bindAddress`.\n* `++__CONFDIR__++` -- Path to directory with the config file as specified in `configPath`.\n* `++__CWD__++` -- The current working directory as reported by `process.cwd()`.\n* `++__WORKDIR__++` -- Path to the nginx’s working directory as specified in `workDir`.\n* `++__PORT__++`, `++__PORT_1__++`, ..., `++__PORT_9__++` -- The port numbers as specified in `ports` and `preferredPorts`.\n\nIt will be modified for compatibility with the runner by applying patch operations specified in `configPatch` variable.\n\nEither `configPath`, or `config` must be provided!\n--\n\nconfigPath `(?string)`::\nPath of the nginx configuration file to use.\n+\nThis file will be processed and the resulting config file will be written to a temporary file `.\u003cfilename\u003e~` (where `\u003cfilename\u003e` is a filename from `configPath`) in the `configPath`’s directory (e.g. `conf/nginx.conf` -\u003e `conf/.nginx.conf~`).\nThis temporary file will be automatically deleted after stopping the nginx.\n+\nSee `config` option for information about placeholders and patching.\n+\nEither `configPath`, or `config` must be provided!\n\nbindAddress `(?string)`::\nHostname or IP address the port(s) will be binding on.\nThis is used when searching for free ports (see `preferredPorts`) and for substituting `++__ADDRESS__++` placeholder in the given nginx config.\nDefaults to `'127.0.0.1'`.\n\nports `(?number[])`::\nA list of port numbers for substituting `++__PORT__++`, `++__PORT_1__++`, ..., `++__PORT_9__++` placeholders in the given nginx config.\nUnlike `preferredPorts`, these are _not_ checked for availability and nginx will fail to start if any of the provided and used ports is unavailable.\n+\nIf it’s not provided or more ports are needed, next ports are selected from the `preferredPorts` or randomly.\n\npreferredPorts `(?number[])`::\nA list of preferred port numbers to use for substituting `++__PORT__++`, `++__PORT_1__++`, ..., `++__PORT_9__++` placeholders in the given nginx config.\n+\nUnavailable ports (used by some other program or restricted by OS) are skipped.\nIf there are no preferred ports left and another port is needed, a random port number is used.\n\nworkDir `(?string)`::\nPath of a directory that will be passed as a _prefix_ (`-p`) into `nginx`.\nIt will be automatically created if doesn’t exist.\n+\nIf not provided, an unique temporary directory will be created: `.cache/nginx-testing-XXXXXX/` relative to the nearest writable `node_modules` (nearest to `process.cwd()`) or `nginx-testing-XXXXXX/` in the system-preferred temp directory.\nThe created directory will be automatically deleted after stopping.\n\nerrorLog `(?string | ?{Writable})`::\n+\n--\nOne of:\n\n* `'buffer'` -- Collect the nginx’s stderr to a buffer that can be read using `readErrorLog()` (default).\n* `'ignore'` -- Ignore nginx’s stderr.\n* `'inherit'` -- Pass through the nginx’s stderr output to the Node process.\n* `\u003c{Writable}\u003e` -- A writable stream to pipe the nginx’s stderr to.\n\nNginx error log is expected to be redirected to _stderr_.\nDirective `error_log stderr info;` will be automatically added to the config, unless there’s already `error_log` defined in the main context.\n--\n\naccessLog `(?string | ?{Writable})`::\n+\n--\nOne of:\n\n* `'buffer'` -- Collect the nginx’s access log to a buffer that can be read using `readAccessLog()` (default).\n* `'ignore'` -- Ignore nginx’s access log.\n* `\u003c{Writable}\u003e` -- A writable stream to pipe the nginx’s access log to.\n\nNginx access log is expected to be redirected to file `\u003cworkDir\u003e/access.log`.\nDirective `access_log access.log;` will be automatically added to the config, unless there’s already `access_log` defined in the `http` context.\n--\n\nstartTimeoutMsec `(?number)`::\nNumber of milliseconds after the start to wait for the nginx to respond to the health-check request (`HEAD ++http://\u003cbindAddress\u003e:\u003cports[0]\u003e/health++`).\nAny HTTP status is considered as success -- it just checks if the nginx is listening and responding.\n+\nDefaults to `1000`.\n\n\n=== RestartOptions\n\nconfig `(?string)`::\nThe same as in \u003c\u003cNginxOptions\u003e\u003e.\n\nconfigPath `(?string)`::\nThe same as in \u003c\u003cNginxOptions\u003e\u003e.\n\n\n=== NginxServer\n\nA return value of \u003c\u003cstartNginx, `startNginx()`\u003e\u003e.\n\nconfig `(string)`::\nThe current nginx configuration.\n\npid `(number)`::\nPID of the nginx process.\n\nport `(number)`::\nNumber of the first port allocated for nginx, i.e. the port on which nginx should listen for connections.\nIt’s the same as `ports[0]`.\n\nports `(number[])`::\nA list of port numbers allocated for nginx.\n\nworkDir `(string)`::\nPath of the nginx’s working directory.\n\nreadAccessLog `() =\u003e Promise\u003cstring\u003e`::\nReads new messages from the access log since the last call of `readAccessLog()`.\n+\nThrows `Error` if the process was created with option `accessLog` other than `'buffer'` or `undefined`.\n\nreadErrorLog `() =\u003e Promise\u003cstring\u003e`::\nReads new messages from the error log since the last call of `readErrorLog()`.\n+\nThrows `Error` if the process was created with option `errorLog` other than `'buffer'` or `undefined`.\n\nreload `(?\u003c\u003cRestartOptions\u003e\u003e) =\u003e Promise\u003cvoid\u003e`::\nReloads the nginx (using SIGHUP), optionally with a new configuration.\nOptions `config` and `configPath` are mutually exclusive here.\n+\nNginx can be reloaded only when running with the master process.\nThis is disabled by default, but you can override it by declaring `master_process on` in the config.\n+\n**Important:** The function you are looking for is `restart()`.\nUse `reload()` only if you know that you cannot use `restart()`.\n+\n**Caution:** This function doesn’t work on Windows!\n+\nThrows `Error` if nginx was started with `master_process off` or if running on Windows (`win32` platform).\n\nrestart `(?\u003c\u003cRestartOptions\u003e\u003e) =\u003e Promise\u003cvoid\u003e`::\nRestarts the nginx, optionally with a new configuration.\nOptions `config` and `configPath` are mutually exclusive here.\nThe new nginx process will be started with the same ports, working directory etc.\n\nstop `() =\u003e Promise\u003cvoid\u003e`::\nStops the nginx and cleans-up temporary files and directories.\n\n\n=== NginxVersionInfo\n\nParsed output of `nginx -V` returned by \u003c\u003cnginxVersionInfo, `nginxVersionInfo()`\u003e\u003e.\n\nversion `(string)`::\nNginx version number (e.g. `'1.24.0'`).\n\nmodules `(Object.\u003cstring, string\u003e)`::\nAn object of module names as properties with value `'with'`, `'with-dynamic'`, or `'without'`.\n+\n.Example:\n[source, ts]\n----\n{\n  http_fastcgi: 'without',\n  http_geoip: 'with-dynamic',\n  http_ssl: 'with',\n}\n----\n\n\n=== NginxConfEditor\n\nNginx configuration editor returned by \u003c\u003cparseConf, `parseConf()`\u003e\u003e.\n\nget `(path: string) =\u003e string | string[] | undefined`::\nReturns a value of a directive at the path specified by a JSON Pointer (e.g. `/http/servers/0/listen`).\n+\n* If the directive is not declared, returns `undefined`.\n* If the path points to an unnamed block (e.g. `server`), returns an empty string.\n* If an intermediate directive is declared multiple times and no index is specified in the path (e.g. `/http/servers/listen`), the first one is selected (`/http/servers/0/listen`).\n* If the path points to a directive that is declared multiple times (in the same context), returns an array of each declaration’s value.\n\napplyPatch `(patch: \u003c\u003cPatchOperation\u003e\u003e[]) =\u003e this`::\nApplies the specified patch operations on the config.\n+\nThrows `RangeError` if some intermediate directive on the path does not exist.\n\ntoString `() =\u003e string`::\nDumps the config back to string.\n\n\n=== PatchOperation\n\nA patch operation to be performed on nginx config.\n\nIt’s an object with the following properties:\n\nop `(string)`::\nThe operation name; one of:\n\n* `'add'` -- Adds a directive.\n* `'default'` -- Sets a directive if it’s not declared yet.\n* `'remove'` -- Removes a directive.\n* `'set'` -- Sets a directive and removes its existing declarations in the same context.\n\npath `(string)`::\nA JSON Pointer of the directive to be added, set or removed.\n+\nFor example, `/http/server/1/listen` points to a directive `listen` in the second `server` context inside `http` context.\nSee documentation of `get` function in \u003c\u003cNginxConfEditor\u003e\u003e for more information.\n\nvalue `(string)`::\nA value of the directive (not defined for op `'remove'`).\n\nThis is based on http://jsonpatch.com/[JSON Patch], but with a different operations.\n\n\n=== Logging\n\n. If https://github.com/Download/anylogger[anylogger] is available and initialized (any adapter has been registered), then:\n** all log messages will go through `anylogger` logger `nginx-binaries`.\n\n. If https://www.npmjs.com/package/debug[debug] is available, then:\n** _debug_ messages will be logged via `debug` logger `nginx-binaries`, others (error, warn, info) via `console`.\n\n. otherwise:\n** _error_, _warn_, and _info_ messages will be logged via https://nodejs.org/api/console.html[`console`], _debug_ messages will be discarded.\n\nIf none of these options is suitable, you can provide your own logger using \u003c\u003csetLogger, `setLogger()`\u003e\u003e:\n\n[source, js, subs=\"+attributes\"]\n----\nimport { setLogger } from '{npm-name}'\n\nsetLogger({\n  warn: console.warn,\n  error: console.error,\n  // undefined logging functions will be replaced with no-op\n})\n----\n\nendif::npm-readme[]\n\n\n== CLI\n\n// Pandoc conversion to Markdown doesn't handle definition lists.\nifdef::npm-readme[]\nhttps://github.com/{gh-name}#cli[See on GitHub].\n\nendif::npm-readme[]\nifndef::npm-readme[]\n\n=== start-nginx\n\n// NOTE: Keep this section in sync with --help message in nginxRunnerCli.ts (until I write a script to generate it).\n\n----\nstart-nginx [options] \u003cconf-file\u003e\nstart-nginx -h | --help\n----\n\nStart nginx server with the given config and reload it on changes.\n\n\n==== Arguments\n\n\u003cconf-file\u003e::\nPath of the nginx configuration file.\n\n\n==== Options\n\n-b --bin-path \u003cfile\u003e::\nName or path of the nginx binary to start.\nDefaults to `nginx`.\nThis option is ignored if *--version* is specified.\n\n-v --version \u003csemver\u003e::\nA SemVer version range specifying the nginx version to download from https://github.com/jirutka/nginx-binaries[nginx-binaries] a and run.\n\n-A --bind-address \u003chost\u003e::\nHostname or IP address to bind the port(s) on.\nDefaults to 127.0.0.1.\n\n-p --port \u003cport\u003e::\nPort number(s) for substituting `++__PORT__++`, `++__PORT_1__++`, ..., `++__PORT_9__++` placeholders in the nginx config.\nRepeat this option for more ports.\nDefaults to random port numbers.\n\n-d --work-dir \u003cdir\u003e::\nPath of a directory that will be passed as a prefix into nginx.\nIf not provided, a temporary directory will be automatically created.\n\n-T --start-timeout \u003cmsec\u003e::\nNumber of milliseconds after the start to wait for the nginx to respond to the health-check request.\nDefaults to 1,000 ms.\n\n-w --watch \u003cpath\u003e::\nWatch file or directory (recursively) and reload nginx on changes.\n*\u003cconf-file\u003e* is watched implicitly.\nRepeat this option for more paths.\n\n-D --watch-delay \u003cmsec\u003e::\nDelay time between reloads in milliseconds.\nDefaults to 200 ms.\n\n-h --help::\nShow help message and exit.\n\nendif::npm-readme[]\n\n\n== License\n\nThis project is licensed under http://opensource.org/licenses/MIT/[MIT License].\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjirutka%2Fnginx-testing","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjirutka%2Fnginx-testing","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjirutka%2Fnginx-testing/lists"}