{"_id":"3loc","_rev":"8-6318728acee34e532901543c8cb90e57","name":"3loc","description":"A simple-yet-customizable integration test tool","dist-tags":{"latest":"0.4.0"},"versions":{"0.1.0":{"name":"3loc","version":"0.1.0","description":"A simple-yet-customizable integration test tool","bin":{"run":"src/cli.js"},"scripts":{"test":"gulp test"},"repository":{"type":"git","url":"git+https://github.com/worldline/3loc.git"},"author":{"name":"feugy","email":"damien.feugas@gmail.com"},"license":"MIT","dependencies":{"body-parser":"^1.14.2","chai":"^3.4.1","chalk":"^1.1.1","commander":"^2.9.0","csv-parse":"^1.0.1","express":"^4.13.3","ini":"^1.3.4","joi":"^7.0.1","js-yaml":"^3.5.2","libxmljs":"^0.16.1","lodash":"^3.10.1","mocha":"^2.3.4","moment":"^2.10.6","nunjucks":"^2.3.0","request":"^2.67.0"},"devDependencies":{"gulp":"^3.9.0","gulp-eslint":"^1.1.1","gulp-istanbul":"^0.10.3","gulp-mocha":"^2.2.0","gulp-util":"^3.0.7"},"gitHead":"9f4c2fdc837caf3e43b0f5f587757c00ea4fea1d","bugs":{"url":"https://github.com/worldline/3loc/issues"},"homepage":"https://github.com/worldline/3loc#readme","_id":"3loc@0.1.0","_shasum":"910adc410124c8429167c0b56bcfbb2c6d681578","_from":".","_npmVersion":"2.14.7","_nodeVersion":"4.2.1","_npmUser":{"name":"feugy","email":"damien.feugas@gmail.com"},"dist":{"shasum":"910adc410124c8429167c0b56bcfbb2c6d681578","tarball":"https://registry.npmjs.org/3loc/-/3loc-0.1.0.tgz","integrity":"sha512-anr++g868SX0V05C1ZP+uT6H77UGXWLrTchLPUEILhgrf0jWpYVzc4oolM3zuOH0FvAGCxO9t4499XrXxubfJg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHwDu/Hu7L5Nrkb+xujdvJIyI4Y5gJwyBZd1AtxCcKILAiEAtmnRvcl/D2Axl4NnIueEReLVbFYythnO4w37v9d2Nzg="}]},"maintainers":[{"name":"feugy","email":"damien.feugas@gmail.com"}]},"0.2.0":{"name":"3loc","version":"0.2.0","description":"A simple-yet-customizable integration test tool","bin":{"run":"src/cli.js"},"scripts":{"test":"gulp test"},"repository":{"type":"git","url":"git+https://github.com/worldline/3loc.git"},"author":{"name":"feugy","email":"damien.feugas@gmail.com"},"license":"MIT","dependencies":{"body-parser":"1.14.2","chai":"3.5.0","chalk":"1.1.1","commander":"2.9.0","csv-parse":"1.0.1","express":"4.13.4","ini":"1.3.4","joi":"7.2.3","js-yaml":"3.5.2","libxmljs":"0.16.1","lodash":"4.0.1","mocha":"2.4.5","moment":"2.10.6","nunjucks":"2.3.0","request":"2.69.0"},"devDependencies":{"gulp":"3.9.0","gulp-eslint":"1.1.1","gulp-istanbul":"0.10.3","gulp-mocha":"2.2.0","gulp-util":"3.0.7"},"gitHead":"cd7a61f08c718224faa223a4545213e31cdb6aed","bugs":{"url":"https://github.com/worldline/3loc/issues"},"homepage":"https://github.com/worldline/3loc#readme","_id":"3loc@0.2.0","_shasum":"f3e991df77cacb2bf325ceca0a3ade70e032ce72","_from":".","_npmVersion":"2.14.7","_nodeVersion":"4.2.1","_npmUser":{"name":"feugy","email":"damien.feugas@gmail.com"},"dist":{"shasum":"f3e991df77cacb2bf325ceca0a3ade70e032ce72","tarball":"https://registry.npmjs.org/3loc/-/3loc-0.2.0.tgz","integrity":"sha512-kEGUPwhwsY9IqgLPn74UvsE1xO5rhmVYH+773P+RhdWCI0MooUrnw8MFP3T0I6DtMn8RBxpfb/Rh2KgwfQH8ug==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCYH6UsalW/jJFc4RF6AxGC8LuXwHVdfmgXNcIej+nBGwIhALY/opzSrUCNmAd6snosw7+ZFHBJyW2JV8906UrzuL1Q"}]},"maintainers":[{"name":"feugy","email":"damien.feugas@gmail.com"}]},"0.3.0":{"name":"3loc","version":"0.3.0","description":"A simple-yet-customizable integration test tool","bin":{"run":"src/cli.js"},"scripts":{"test":"gulp test"},"repository":{"type":"git","url":"git+https://github.com/worldline/3loc.git"},"author":{"name":"feugy","email":"damien.feugas@gmail.com"},"license":"MIT","dependencies":{"body-parser":"1.14.2","chai":"3.5.0","chalk":"1.1.1","commander":"2.9.0","csv-parse":"1.0.1","express":"4.13.4","ini":"1.3.4","joi":"7.2.3","js-yaml":"3.5.2","libxmljs":"0.16.1","libxml-xsd":"0.5.2","lodash":"4.0.1","mocha":"2.4.5","moment":"2.10.6","nunjucks":"2.3.0","request":"2.69.0"},"devDependencies":{"gulp":"3.9.0","gulp-eslint":"1.1.1","gulp-istanbul":"0.10.3","gulp-mocha":"2.2.0","gulp-util":"3.0.7"},"gitHead":"08a6f6909514914c133f3caf2dd8a5c0b25d03c3","bugs":{"url":"https://github.com/worldline/3loc/issues"},"homepage":"https://github.com/worldline/3loc#readme","_id":"3loc@0.3.0","_shasum":"029c05c9b7dacb0ffabdb63705441114d2ac2c34","_from":".","_npmVersion":"2.14.12","_nodeVersion":"4.3.2","_npmUser":{"name":"vozman","email":"valentin.ozanne@gmail.com"},"dist":{"shasum":"029c05c9b7dacb0ffabdb63705441114d2ac2c34","tarball":"https://registry.npmjs.org/3loc/-/3loc-0.3.0.tgz","integrity":"sha512-8KQVt5jlBkdBuv38m4uN0smloH8OXFpHJpLICuA3+Igstxjr5GSb51FcDCWOg1n6kONqMyMl5fRl4DWCU6C5Ew==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCo2Iphb42KHB48OBmQTXqFYg29HDQBKbaElDuNNOGdrQIgSeUS+UicynZfBki6nBIvT+r5Dhn5dczFpQ6sOD3MDOg="}]},"maintainers":[{"name":"feugy","email":"damien.feugas@gmail.com"},{"name":"vozman","email":"valentin.ozanne@gmail.com"}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/3loc-0.3.0.tgz_1457972284263_0.2295751511119306"}},"0.4.0":{"name":"3loc","version":"0.4.0","description":"A simple-yet-customizable integration test tool","bin":{"run":"src/cli.js"},"scripts":{"test":"gulp test"},"repository":{"type":"git","url":"git+https://github.com/worldline/3loc.git"},"author":{"name":"feugy","email":"damien.feugas@gmail.com"},"license":"MIT","dependencies":{"body-parser":"1.14.2","chai":"3.5.0","chalk":"1.1.1","commander":"2.9.0","csv-parse":"1.0.1","express":"4.13.4","ini":"1.3.4","joi":"7.2.3","js-yaml":"3.5.2","libxmljs":"0.16.1","libxml-xsd":"0.5.2","lodash":"4.0.1","mocha":"2.4.5","moment":"2.10.6","nunjucks":"2.3.0","request":"2.69.0"},"devDependencies":{"gulp":"3.9.0","gulp-eslint":"1.1.1","gulp-istanbul":"0.10.3","gulp-mocha":"2.2.0","gulp-util":"3.0.7"},"gitHead":"e16ade1ba1a90cbd0fc78bc7f404b1dec5ec04b0","bugs":{"url":"https://github.com/worldline/3loc/issues"},"homepage":"https://github.com/worldline/3loc#readme","_id":"3loc@0.4.0","_shasum":"c51f4b1a01027e5aea8c6d88133451a0ff8b1532","_from":".","_npmVersion":"2.14.12","_nodeVersion":"4.3.2","_npmUser":{"name":"vozman","email":"valentin.ozanne@gmail.com"},"dist":{"shasum":"c51f4b1a01027e5aea8c6d88133451a0ff8b1532","tarball":"https://registry.npmjs.org/3loc/-/3loc-0.4.0.tgz","integrity":"sha512-hNfgq4+xyNAOA+fxEpDgr6djnlL0S7kdEpvEdzoHiqLxfYzyrP09XCD8jPrJiZ43+BmN4I6Xj65MHDVfFAy8IQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCMC++9/YBLH0MaKN1yBsedqCOUs6P5UL7btIIFWTdi5AIgfIkFokGn6YURq/xGDhp5UhYIeuYVbK4Jwy7AwrY1PBY="}]},"maintainers":[{"name":"feugy","email":"damien.feugas@gmail.com"},{"name":"vozman","email":"valentin.ozanne@gmail.com"}],"_npmOperationalInternal":{"host":"packages-13-west.internal.npmjs.com","tmp":"tmp/3loc-0.4.0.tgz_1458639422034_0.03540353081189096"}}},"readme":"# 3loc\r\n\r\nA simple-yet-customizable integration test tool:\r\n\r\n0. Choose/write a test scenrio for your integration tests\r\n0. Writes our test fixtures into one or several CSV/YAML files\r\n0. Run the command and enjoy the results !\r\n\r\n## Principles\r\n\r\n3loc runs tests against existing system, sending input and expecting results.\r\nIf received results are not the one expected, it will complain.\r\n\r\nIt's focused on Http services, SOAP and REST.\r\n\r\nTest scenarii are basically JavaScript files, containing a serie of *[actions][act]* and *[expectations][expect]*.\r\nYou will surely need to run the same scenario multiple times, with slight changes in the test data: body sent to the tested WebService, or expected status code.\r\n\r\nWe called them *[fixtures][fixt]*, and you can externalize them in a dedicated file (multiple format are supported).\r\nIn fact, the fixture file is the entry point when using 3loc, as it defined the scenario file used.\r\n\r\n## Installation\r\n\r\n3loc is built upon [Node.js 4+][node].\r\nYou'll need to install it on your computer to use it.\r\n\r\nAs 3loc uses [libXML.js][libxml], which requires some C++ compilation, you'll also need a C++ compiler\r\n(gcc or [Visual Studio Community Edition][VS] for example).\r\n\r\nOnce you have installed Node and a C++ compiler, run the following command to install\r\n\r\n    npm install --global 3loc\r\n\r\n(then have a cup of coffee)\r\n\r\n## Execution\r\n\r\nFrom a command line or a terminal, run\r\n\r\n    run path/to/fixture.yml\r\n\r\nCLI options are documented:\r\n\r\n    run\r\n\r\n\r\n# Providing test fixtures\r\n\r\nTest fixtures are used to add some dynamicity to your scenario files.\r\nThis is an example:\r\n\r\n```javascript\r\nreturn () =>\r\n    run(request({\r\n      url: 'http://api.wolframalpha.com/v2/query?input=<$ input $>&appid=<$ appId $>&includepodid=Result'\r\n    })).\r\n    then(expectStatusCode(<$ status $>)).\r\n    then(expectXPathToEqual('//pod[id=\"Result\"]//plaintext', '<$ sum $>'));\r\n```\r\n\r\nIt makes an Http call to the [Wolfram API][wolfram], get and parse the XML content,\r\nchecks the received status code and check the result with an XPath expression.\r\n\r\nSee thoses `<$ $>` placeholders (`input`, `sum`...) ? they are replaced with the provided test data.\r\n\r\n\r\n## With YAML\r\n\r\nYAML is probably the best choice to write your fixtures.\r\nHere is the YAML file for the above scenario:\r\n```yaml\r\nscenario: ./path_to/my-scenario.scn\r\nappId: HLJL66-4W3HPXYYP8\r\ntests:\r\n  - name: nominal case\r\n    input: 3%2B4\r\n    sum: 7\r\n    status: 200\r\n  - name: handling nulls\r\n    input: 3%2Bnull\r\n    sum: 3\r\n    status: 200\r\n```\r\n\r\n`scenario` is the path the the scenario file (required).\r\n\r\n`tests` is an array of objects, each considered as the specific fixtures of a given test.\r\nIf 3loc find two objects in `tests`, it will runs the scenario twice, using the given objects.\r\n\r\nInside `tests` and in root level, you can put anything, from simple string/boolean to complex array/map structures.\r\n\r\nThe content will be used inside the scenario file:\r\n- `input`, `sum` and `status` are defined at test levels\r\n- `appId` is common to all tests (but can be overloaded per test)\r\n\r\nIf you specify a `name` at test level, it will be used in final report.\r\nOtherwise, a name with test number will be generated.\r\n\r\nYou can't use different scenarii for each test. If you whish, write different fixtures files.\r\n\r\nLast but not least, a YAML file can include other YAML files, using the following *macro*:\r\n```yaml\r\nconfig: !!inc/file configuration.yaml\r\n```\r\n\r\nThe `!!inc/file` performs a *synchronous* read of the given path (relative to the including file) and is replaced by its content.\r\n\r\n\r\n## With CSV\r\n\r\nLess flexible than YAML, it suits some cases where data is mearly flat, does not share a lot of data, and when you want diffent scenarii.\r\nThe CSV fixtures for the above scenario is:\r\n```csv\r\nscenario;name;appId;input;sum;status\r\n./path_to/my-scenario.scn;HLJL66-4W3HPXYYP8;\"nominal case\";3%2B4;7;200\r\n./path_to/my-scenario.scn;HLJL66-4W3HPXYYP8;\"handling nulls\";3%2Bnull;3;200\r\n```\r\n\r\nEach line will execute a different test.\r\n`scenario` column contains the path the the scenario file (required).\r\n\r\nAny other column contains data used inside test.\r\nIf you put dots in the column name, the data replace will be treeish.\r\nFor example, with a column named `host.url`, the replacement will be `request({host: '<$ host.url $>'})`\r\nand the data is an `host` object containing an `url` property.\r\n\r\nIf you specify a `name` column, it will be used in final report.\r\nOtherwise, a name with test number will be generated.\r\n\r\nYou can't share data among different tests. For that, please use a YAML fixture file.\r\n\r\n\r\n## Common considerations\r\n\r\nWhatever the format used, the following considerations always apply:\r\n- `scenario` path is always relative to the fixture location (you can provide absolute path as well)\r\n- `scenario` can directly contains the JavaScript code (only suit really tiny scenarii)\r\n- Tests are executed serially: the program bails at first error\r\n- Test execution folder is always the folder containing the scenario file.\r\n  Data used as path (`load` action for example) are relative to that folder\r\n- When providing scenario content directly, the execution folder is the one containing the fixture file\r\n\r\n\r\n# Logging\r\n\r\nBy default, 3loc is not really verbose.\r\nBut it can be more chatty if you configure logging: just put a `logging.properties` file in the execution folder.\r\n\r\nThe file syntax is a classical [INI][ini] file where the category is the logger name, and the values allows to customize its parameter:\r\n```properties\r\n[my-logger-1]\r\nlevel=error\r\n\r\n[my-logger-2]\r\nlevel=debug\r\n```\r\n\r\nThe conf is regularly watched so you can change you file while 3loc is running.\r\n\r\nBy convention, each actions/expectation uses its own logger, so you can have a fine-grained tunning.\r\n\r\n\r\n# Scenario authoring\r\n\r\nScenario files are JavaScript files, templated with [Nunjucks][nunjucks] template language.\r\n\r\nObviously they must be well-formed JavaScript **after** the template compilation.\r\n\r\n## Templating\r\n\r\nTo improve readability, the default Nunjucks's delimiter have been **changed**:\r\n- blockStart: '<%'\r\n- blockEnd: '%>'\r\n- variableStart: '<$'\r\n- variableEnd: '$>'\r\n- commentStart: '<#'\r\n- commentEnd: '#>'\r\n\r\nBe warned that placeholders **are type-aware** (which is an improvment of Nunjuck behavior).\r\nFor example this scenario:\r\n```javascript\r\nload(<$ file $>)\r\n```\r\nIt will compiles only if you provides a string value in the fixture file.\r\n\r\nBoolean and number types are kepts within templates,\r\nstrings fixtures are automatically enclosed in double quotes,\r\narrays and objects are serialized into JSON.\r\n\r\nAll methods from [lodash v4.0.1][lodash] are also available as Nunjuck filters:\r\n```javascript\r\nrun(request(<$ endpoint | pick('url', 'headers') $>)).\r\n  then(expectContentToInclude(<$ filename | camelCase $>))\r\n```\r\n\r\nThe first method parameter is always the filtered values, and you can add extra parameters.\r\nIt's strictly equivalent to write:\r\nvar _ = require('lodash');\r\n```javascript\r\nrun(request(_.pick(<$ endpoint $>, 'url', 'headers'))).\r\n  then(expectContentToInclude(_.camelCase(<$ filename $>)))\r\n```\r\n\r\nYou can also hardcode everything, and in that case, the fixtures file only needs to specify scenario path and a name for each tests.\r\n\r\n## Returning the proper thing\r\n\r\nYour scenario file must ends by returning either:\r\n- A Promise. ex: `return Promise.resolve(18);`\r\n- A synchronous function. ex `return function() { return 18; };`\r\n- An asynchronous function. ex `return function(done) { require('fs').readFile('myfile.txt', done); };`\r\n  (asynchronous functions differs from synchronous function because they declare a single argument)\r\n\r\nThe best thing to do is to return the result of [run()](#run) or [runSerial()](#runSerial) actions.\r\n\r\n## It's just JavaScript\r\n\r\nAnd it's executed on Node.js.\r\nThat means that Node's API are available (through the use of `require()` function),\r\nas well as 3loc own dependencies ([lodash](https://lodash.com/), [moment](http://momentjs.com/), [chai](http://chaijs.com/), [joi](https://github.com/hapijs/joi)...)\r\n\r\nAs your tests are run on Node.js, you can use the ES6 features supported from version 4.2\r\n(arrow functions, promises, string interpolation, classes...).\r\n\r\n# Available actions\r\n\r\nAll actions are JavaScript functions automatically available within scenario file (no need to require anything else).\r\nThey are composable within [Promises][promise], and are intended to be used that way.\r\n\r\nDo *NOT* handle promise rejections, unless your scenario needs to keep testing stuff after an error.\r\nThe nominal case is to let errors bubnle an stop the current executed test.\r\n\r\n## listen\r\n\r\nStarts an HTTP server to listen a given url.\r\nAcceptable method can be configured, has well as response body and headers.\r\n\r\nIf a JSON body is passed, set default response content-type to `application/json`.\r\nIf a libXML.js Document body is pased, set default response content-type to `application/xml`.\r\nYou can still override the response content-type if needed.\r\n\r\nIf body is given as a function, it must return a promise fulfilled\r\nwith an object including a `content` property.\r\n\r\nRequest body will be automatically parsed (using the request content-type) to libXML.js Document or to JSON object for further processing.\r\nOtherwise, the request body is passed as a string.\r\n\r\n```javascript\r\nlisten({\r\n  port: 4000,\r\n  url: '/my-api',\r\n  method: 'POST',\r\n  body: '{\"msg\": \"response sent\"}',\r\n  headers: {\r\n    'content-type': 'application/json',\r\n    'x-custom': 'custom'\r\n  },\r\n  code: 200\r\n}).then(...)\r\n\r\n```\r\n- **opt.port** *{Number}* - absolute or relative path to read file\r\n- **opt.url** *{String}* - acceptable url to listen to\r\n- **opt.method = GET** *{String}* - acceptable Http method\r\n- **opt.body = ''** *{String|Object|Document|Function}* - response sent to incoming request\r\n- **opt.headers = {}** *{Object}* - response headers sent to incoming request\r\n- **opt.code = 200** *{Number}* - status code sent to incoming request\r\n- **returns** *{Function}* function usable in promises chain.\r\n  Takes as first parameter an object.\r\n  Returns a promise fulfilled with the same object, containing\r\n  - **content** *{String}* - response body received (might be parsed in JSON/XML)\r\n  - **headers** *{Object}* - response headers\r\n\r\nLogger name: `act:listen`\r\n\r\n## load\r\n\r\nLoads file content as a string.\r\nTypically used to read request/response bodies, XSD files...\r\n\r\n```javascript\r\nload('./path_to/file.txt', 'ascii').then(...)\r\n```\r\n\r\n- **path** *{String}* - absolute or relative path to read file\r\n- **encoding = utf8** *{String}* - encoding used to read the file\r\n- **returns** *{Function}* function that loads the file when invoked.\r\n  Takes as first parameter an object.\r\n  Returns a promise fulfilled with the same object, containing\r\n  - **content** *{String}* - response body received (might be parsed in JSON/XML)\r\n  - **path** *{Object}* - absolute or relative path to read file\r\n\r\nLogger name: `act:load`\r\n\r\n## render\r\n\r\nRenders Nunjucks template with given data.\r\nSee [Nunjucks][nunjucks] templating language,\r\nwith the specific delimiters (for readability in scenarii files)\r\n- blockStart: '<%',\r\n- blockEnd: '%>',\r\n- variableStart: '<$',\r\n- variableEnd: '$>',\r\n- commentStart: '<#',\r\n- commentEnd: '#>'\r\n\r\n```javascript\r\nrender('Hello <$ name $> !', {name: 'James'}).then(...)\r\n```\r\n\r\nIf content is given as a function, it must return a promise fulfilled\r\nwith an object including a `content` and `path` properties.\r\n\r\n- **content** *{String|Function}* - template rendered\r\n- **data = {}** *{Object}* - data used for rendering\r\n- **returns** *{Function}* function usable in promises chain.\r\n  Takes as first parameter an object\r\n  Returns a promise fulfilled with the same object, containing\r\n  - **content** *{String}* - the rendered template\r\n\r\nLogger name: `act:render`\r\n\r\n## request\r\n\r\nMakes an HTTP(s) request on a given url.\r\nThe HTTP method, the headers and the ability to follow redirections are configurable.\r\n\r\nIf a JSON body is passed, set default request content-type to 'application/json'.\r\nIf a libXML.js Document body is pased, set default request content-type to 'application/xml'.\r\nYou can still override the request content-type if needed.\r\n\r\nRequest body will be automatically parsed (using the request content-type) to libXML.js Document or to JSON object for further processing.\r\nOtherwise, the request body is passed as a string.\r\n\r\n```javascript\r\nrequest({\r\n  url: 'http://localhost:8080/my-api',\r\n  method: 'PUT',\r\n  body: '{\"msg\": \"request sent\"}',\r\n  headers: {\r\n    'content-type': 'application/json',\r\n    'x-custom': 'custom'\r\n  },\r\n  followRedirect: true\r\n}).then(...)\r\n```\r\n\r\nIf you need to pass query parameters, please encode them with the url.\r\n\r\nIf body is given as a function, it must return a promise fulfilled\r\nwith an object including a `content` property.\r\n\r\n- **opt.url** *{String}* - full url (protocol, host, port, path) requested\r\n- **opt.method = GET** *{String}* - method used\r\n- **opt.body = ''** *{String|Object|Document}* - body sent (only when doing POST and PUT)\r\n- **opt.headers = {}** *{Object}* - request headers\r\n- **opt.followRedirect = false** *{Boolean}* - automatically follows redirection\r\n- **returns** *{Function}* function usable in promises chain.\r\n  Takes as first parameter an object.\r\n  Returns a promise fulfilled with the same object, containing\r\n  - **content** *{String}* - response body received (might be parsed in JSON/XML)\r\n  - **headers** *{Object}* - response headers\r\n  - **code** *{Number}* - http status code\r\n\r\nLogger name: `act:request`\r\n\r\n## run\r\n\r\nRuns synchronously a given function, with provided data, and wrap to\r\nPromise for next actions and expectations.\r\nA must-have when starting a new scenario.\r\n\r\n```javascript\r\nrun(request({url: 'http://somewhere.com/'}))\r\n```\r\n\r\n- **fs** *{Function}* - function executed\r\n- **data = {}** *{Object}* - optionnal data given as function argument\r\n\r\n- **returns** *{Promise}* fulfilled with the function result\r\n\r\nLogger name: `act:run`\r\n\r\n## runSerial\r\n\r\nRuns an array of function serially,\r\npassing result of task N as parameter of task N+1.\r\n\r\nBeware that you must pass an array **functions**.\r\nDon't give promises, or they will be started all in once.\r\n\r\n```javascript\r\nrunSerial([\r\n  () => Promise.resolve(1),\r\n  p => Promise.resolve(p + 1)\r\n].then(result => ...) // result === 2\r\n```\r\n\r\n- **tasks** *{Array<Function>}* - tasks to be executed\r\n- **returns** *{Function}* that when invoked, will return promise fulfilled\r\nwith the latest task's result\r\n\r\nLogger name: `act:serial`\r\n\r\n\r\n# Expectations\r\n\r\nAll actions are JavaScript functions automatically available within scenario file (no need to require anything else).\r\nThey are composable within [Promises][promise], and are intended to be used that way.\r\n\r\nDo *NOT* handle promise rejections, unless your scenario needs to keep testing stuff after an error.\r\nThe nominal case is to let errors bubnle an stop the current executed test.\r\n\r\n## expectContentToInclude\r\n\r\nChecks that received content includes the given element,\r\nor matches the given pattern.\r\n\r\n```javascript\r\nrun(load('my-file.txt')).\r\nthen(expectcontentToInclude('Hi !'))\r\n```\r\n\r\n- **element** *{String|Regex}* - expected element or matching pattern\r\n- **returns** *{Function}* function usable in promises chain\r\n  Takes as first parameter an object containing\r\n  - **content** *{Object}* - checked content\r\n  - **returns** *{Promise}* fulfilled with the same object\r\n\r\nLogger name: `expect:content`\r\n\r\n## expectStatusCode\r\n\r\nChecks that a given status code has been received.\r\n\r\n```javascript\r\nrun(request({'http://somewhere.com/api'})).\r\nthen(expectStatusCode(404))\r\n```\r\n\r\n- **code** *{Number}* - expected value\r\n- **returns** *{Function}* function usable in promises chain\r\n  Takes as first parameter an object containing\r\n  - **code** *{Object}* - checked code value\r\n  - **returns** *{Promise}* fulfilled with the same object\r\n\r\nLogger name: `expect:status`\r\n\r\n## expectToMatchXsd\r\n\r\nValidates incoming content against a given XSD content.\r\nUse libXML.js internally.\r\nXSD and XML content can be passed as plain string, or as libXML.js's Document objects\r\n\r\nIf xsd is given as a function, it must return a promise fulfilled\r\nwith an object including a `content` property.\r\n\r\n```javascript\r\nrun(request({'http://somewhere.com/api'})).\r\nthen(expectToMatchXsd(load('schema.xsd')))\r\n```\r\n\r\n- **xsd** *{String|Object|Function}* - xsd content used for validation\r\n- **returns** *{Function}* function usable in promises chain.\r\n  Takes as first parameter an object containing\r\n  - **content** *{String|Object}* - xml content validated\r\n  - **returns** *{Promise}* fulfilled with the same object, where content has been enriched as a libXML.js's Document\r\n\r\nLogger name: `expect:xsd`\r\n\r\n[node]: https://nodejs.org/en/download/\r\n[act]: #available-actions\r\n[expect]: #expectations\r\n[fixt]: #providing-test-fixtures\r\n[wolfram]: http://www.wolfram.com/language/fast-introduction-for-programmers\r\n[nunjucks]: http://mozilla.github.io/nunjucks/templating.html\r\n[promise]: http://www.html5rocks.com/en/tutorials/es6/promises/\r\n[VS]: https://www.visualstudio.com/en-US/products/visual-studio-community-vs.aspx\r\n[libxml]: https://github.com/polotek/libxmljs/wiki\r\n[lodash]: https://lodash.com/docs\r\n[ini]: https://en.wikipedia.org/wiki/INI_file","maintainers":[{"name":"feugy","email":"damien.feugas@gmail.com"},{"name":"florian_traversaz","email":"florian.traversaz@worldline.com"},{"name":"vozman","email":"valentin.ozanne@gmail.com"}],"time":{"modified":"2022-06-12T14:07:26.610Z","created":"2016-01-21T16:46:02.015Z","0.1.0":"2016-01-21T16:46:02.015Z","0.2.0":"2016-01-29T18:15:24.761Z","0.3.0":"2016-03-14T16:18:06.529Z","0.4.0":"2016-03-22T09:37:04.559Z"},"homepage":"https://github.com/worldline/3loc#readme","repository":{"type":"git","url":"git+https://github.com/worldline/3loc.git"},"author":{"name":"feugy","email":"damien.feugas@gmail.com"},"bugs":{"url":"https://github.com/worldline/3loc/issues"},"license":"MIT","readmeFilename":"readme.md"}