{"_id":"@akaterra.co/unitsnap","_rev":"2-f3b366a60ae63f107bb44086f1bef1b9","name":"@akaterra.co/unitsnap","dist-tags":{"latest":"1.5.4"},"versions":{"1.5.2":{"name":"@akaterra.co/unitsnap","version":"1.5.2","description":"Library for snapshot based unit testing","main":"index.js","types":"index.d.ts","scripts":{"coveralls":"node ./node_modules/.bin/istanbul cover --root src ./node_modules/.bin/jasmine JASMINE_CONFIG_PATH=jasmine.json","test":"node $NODE_DEBUG_OPTION ./node_modules/.bin/jasmine JASMINE_CONFIG_PATH=jasmine.json"},"author":{"name":"akaterra"},"license":"ISC","keywords":["snapshot","testing","unittest"],"repository":{"type":"git","url":"git+ssh://git@github.com/akaterra/unitsnap.js.git"},"devDependencies":{"istanbul":"0.4.5","jasmine":"3.1.0"},"gitHead":"761b78942d034acd59e11185e2b8852c9b211683","bugs":{"url":"https://github.com/akaterra/unitsnap.js/issues"},"homepage":"https://github.com/akaterra/unitsnap.js#readme","_id":"@akaterra.co/unitsnap@1.5.2","_nodeVersion":"13.7.0","_npmVersion":"6.13.6","dist":{"integrity":"sha512-9q12f0t4ZEL/DArrfxtvSxjn3GwnI2N6ZRx61in0lVr07Mw4oy2IbBD59x1Rjr4Y5gvfIopvFTys07FOg7FqDg==","shasum":"60c65eb98fa1ef20466b438cf0b1167eaf1eaf97","tarball":"https://registry.npmjs.org/@akaterra.co/unitsnap/-/unitsnap-1.5.2.tgz","fileCount":31,"unpackedSize":252836,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeXAZ/CRA9TVsSAnZWagAAAvIP/1tQPs3kphI9HBQjH/ww\nvBpgc6BhcNtrrO43LdrEUrHa/WVKthWyjR5xJ9ciCSTu4c0APkfR+8L8jcXy\npl/rRRbbggXHDFOCS5SQHXnb/hUxX1qb4CYG0QCM6g9WONVIiCqWY05LWdCh\n+HXC1EcNJvMLP+yRBHSYw6iDxluIx1JhhZzm1phIscGbFko2RxBYr3av+X6c\nEOSPWwTjnVFm2YJZRw8VkEqB8//5Sjq44fNxDF8L/nZksoiP5cfKTYLG5pB2\n2O6phOveC6qSzUqEqHnsbdXhqPpChj0ry8LQ00b4e4VS53r9BssrosHqinc9\nfd+AGwUSB1EEGFVgKMHYYxfH4vLGXxr7jtfuqXjv2SsKzGeuiagzPY3vIRgG\nUenmtdX86vP/7BIGnh4H5LLz1YnoxrPMDsxpirZIhexfOCTOZGFBw16IBtQW\nIcO1aeSGjMZkUAvMKWCBcQyTUo/7E46OW+2icSuwgBZ8EHTrVD3J/7KMqj8z\nz3ekI17H0quZGgvZyCpZAt2GiEyHaBGDIwc8YZfBXTEmIKxQnolW25bG2UzA\n+uroH/g8KoRtbmmT/QN4mcpn2GK1n5X5wUVkN49Cehdxv2omsdYJGfOgkjAL\n0e2MUJt/eS4IVqKlMmXnphc1kvLiRir1Vc8aMu5yHnj7G5l1SoUWe7GCNjzL\nAbPT\r\n=fH8S\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDvSD7qQT1AAKxMgR5FgSfLW7djZEfW7w03f5hnEaAh8gIgcj8KPlgqXTQJbq5qfAdNJGjiEuqi5/yWZBIwv3i8k4s="}]},"maintainers":[{"name":"arretaka","email":"akaterra.co@gmail.com"}],"_npmUser":{"name":"arretaka","email":"akaterra.co@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/unitsnap_1.5.2_1583089278935_0.6670594644314942"},"_hasShrinkwrap":false},"1.5.4":{"name":"@akaterra.co/unitsnap","version":"1.5.4","description":"Library for snapshot based unit testing","main":"index.js","types":"index.d.ts","scripts":{"coveralls":"node ./node_modules/.bin/istanbul cover --root src ./node_modules/.bin/jasmine JASMINE_CONFIG_PATH=jasmine.json","test":"node $NODE_DEBUG_OPTION ./node_modules/.bin/jasmine JASMINE_CONFIG_PATH=jasmine.json"},"author":{"name":"akaterra"},"license":"ISC","keywords":["snapshot","testing","unittest"],"repository":{"type":"git","url":"git+ssh://git@github.com/akaterra/unitsnap.js.git"},"devDependencies":{"istanbul":"0.4.5","jasmine":"3.1.0"},"gitHead":"c45a3df6fa531004d730f81777ffb7cf7ce0bb29","bugs":{"url":"https://github.com/akaterra/unitsnap.js/issues"},"homepage":"https://github.com/akaterra/unitsnap.js#readme","_id":"@akaterra.co/unitsnap@1.5.4","_nodeVersion":"13.7.0","_npmVersion":"6.13.6","dist":{"integrity":"sha512-Eo8YroPTyiHMQLEQbdChl8Dexq1YzXHvsA4i32nJMJ9CWD9T/0gHJC3VeqVqRd24af3lq2Ox2pL2KY7XqnhB1w==","shasum":"13cdc233f34f78c70f7467c05d136af738d5e00a","tarball":"https://registry.npmjs.org/@akaterra.co/unitsnap/-/unitsnap-1.5.4.tgz","fileCount":31,"unpackedSize":252986,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeXDzFCRA9TVsSAnZWagAAOXYQAJjw/l0EOWIZauhMfA11\n9kF+aGUjB8NZLeH0a2arnj5msjV86e5cs8uJcsU7FZ2b3Bdu+iQoWMG6/yBw\nmWwQ8NWynu9wtOxcT6wYlY7AIj9EhTu4+hYxO0I5/yHkLw6XnezYZ5xQKHEv\n8pFT2C0v9Zi7qhxUDFifJxMYSod4IBrUDX2vnhMEdHzzQUJqQzfgHb5irnZX\nmvumseGjl01FJ+nTLLRK0NHGmyVLMYuuf/B77aSGhtO5TRm5Dx/WS7i80KrM\nTwbqZNwcihv8Q/xa4tn8j5B/N3tZdr9OCLxjQ/+eou562cTUQvyaqiqrC5vP\niptKVW9eHWZU0IMoj1tgLRGsC7A96vfpFIdeUy/64jQu4oM0wX4fbRW5Qexw\nLnt6NMeGdMoM2NrjrngygnqjkWqQYMmgLywyaN09G7EdIOw+cK5WkHSkceMP\nDMhW9Dh/YmbFTmUA3SWo7Stp4IEopMn168LkvCZu5TyHpzpIg92qv2EJ5lXt\n/xHnF+vFRz1nagz/slvGc+NcrhlIr5vSQLHI3ZEBtCqMwVYrV9LTDVL2NJID\nq914tVa+MTVS7GJJYrrA6x8rJr2Zx/vO5N5sTCOK1IKkiLnTZLQMGxMZy0eh\npG0LbqugZLVsuQY+McQCemiiRloF9vbcD673I/L3f3qPR2Dzaxu78EWZ6kgV\nuXzX\r\n=3PMp\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCYOGgoxwBLrKrrvM8h/IWXc2N1GxpQrpWwekRdkAApZwIhAM7SVcL6iGPs8egKg9V6WV2t+JLuf7wK5aO5BvzCt7zA"}]},"maintainers":[{"name":"arretaka","email":"akaterra.co@gmail.com"}],"_npmUser":{"name":"arretaka","email":"akaterra.co@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/unitsnap_1.5.4_1583103172515_0.75713766223598"},"_hasShrinkwrap":false}},"time":{"created":"2020-03-01T19:01:18.699Z","1.5.2":"2020-03-01T19:01:19.049Z","modified":"2022-04-04T12:28:46.276Z","1.5.4":"2020-03-01T22:52:52.648Z"},"maintainers":[{"name":"arretaka","email":"akaterra.co@gmail.com"}],"description":"Library for snapshot based unit testing","homepage":"https://github.com/akaterra/unitsnap.js#readme","keywords":["snapshot","testing","unittest"],"repository":{"type":"git","url":"git+ssh://git@github.com/akaterra/unitsnap.js.git"},"author":{"name":"akaterra"},"bugs":{"url":"https://github.com/akaterra/unitsnap.js/issues"},"license":"ISC","readme":"# UnitSnap\n\nThe library allows to use the taken or saved snapshot of the units observed during an execution flow as an assertion in unit tests.\nThe principle of this stands on the concept of the pure function which always has the same result of execution (may be partially for individual purposes).\nThen this result can be saved as a snapshot and compared with a snapshot of the same execution flow.\n\n### Contents\n\n* [Installation](#installation)\n* [Example of snapshot generation](#example-of-snapshot-generation)\n* [Example of snapshot assertion](#example-of-snapshot-assertion)\n* [Observer](#observer)\n* [History](#history)\n* [Mock](#mock)\n  * [Customization](#customization)\n* [Fixture](#fixture)\n  * [FixtureCallbackStrategy](#fixturecallbackstrategy)\n  * [FixtureQueueStrategy](#fixturequeuestrategy)\n  * [FixtureFsProvider (for Queue strategy)](#fixturefsprovider-for-queue-strategy)\n  * [FixtureMemoryProvider (for Queue strategy)](#fixturememoryprovider-for-queue-strategy)\n* [Filter](#filter)\n* [Snapshot](#snapshot)\n  * [Value processors](#value-processors)\n  * [Type helpers](#type-helpers)\n  * [SnapshotFsProvider](#snapshotfsprovider)\n  * [SnapshotMemoryProvider](#snapshotmemoryprovider)\n* [Jasmine matcher](#jasmine-matcher)\n* [Using with typescript-ioc](#using-with-typescript-ioc)\n\n### Installation\n\n```bash\nnpm install @akaterra.co/unitsnap\n```\n\n### Example of snapshot generation\n\n```javascript\nconst observer = require('@akaterra.co/unitsnap').default; // default pre-created UnitSnap observer\n\nclass A {\n    a(a, b, c) {\n        return a + b + c;\n    }\n}\n\nA = observer.by(A); // mock A class observing on all methods (\"a\")\n\nconst a = new A();\n\nobserver.begin(); // start observing\n\na.a(1, 2, 3);\n\nobserver.end();\n\nconst snapshot = observer.snapshot(); // take snapshot\n```\n\nSerialized snapshot (snapshot.serialize()):\n\n```json\n[\n    {\n        \"args\": {\n            \"*\": [],\n            \"a\": 1,\n            \"b\": 2,\n            \"c\": 3\n        }\n    },\n    {\n        \"result\": 6\n    }\n]\n```\n\nSave taken snapshot:\n\n```javascript\nsnapshot.setFsProvider(__dirname).save('snapshot');\n```\n\n### Example of snapshot assertion\n\n```javascript\nconst observer = require('@akaterra/unitsnap').default; // default pre-created UnitSnap observer\n\nclass A {\n    a(a, b, c) {\n        return a + b + c;\n    }\n}\n\nA = observer.by(A); // mock A class observing on all methods (\"a\")\n\nconst a = new A();\n\nobserver.begin(); // start observing\n\na.a(1, 1, 1); // differs from a.a(1, 2, 3) that has been saved before\n\nobserver.end();\n\nconst snapshot = observer.snapshot(); // take snapshot\n```\n\nSerialized snapshot (snapshot.serialize()):\n\n```json\n[\n    {\n        \"args\": {\n            \"*\": [],\n            \"a\": 1,\n            \"b\": 1,\n            \"c\": 1\n        }\n    },\n    {\n        \"result\": 3\n    }\n]\n```\n\nAssert saved snapshot:\n\n```javascript\nconst checkResult = snapshot.setFsProvider(__dirname).assertSaved('snapshot'); // \"[0].args.b\" as path of mismatched value\n```\n\n### Observer\n\n```javascript\nconst Observer = require('@akaterra/unitsnap').Observer;\n```\n\nObserver provides a isolated context within which the History, Mock, Fixture and Snapshot (see description below) modules will be created and within which their intercommunication will be organized.\nFor example, the Mock will be linked to the History, or the Snapshot constructed with the **snapshot** will be configured by the basic Snapshot of the Observer's context.\n\nFor ease of use, Observer also implements a set of methods that are proxy methods for the corresponding module linked to the context.\n\n* **config()** - returns a config object with the History, Mock, Fixture and Snapshot of the Observer.\n\n  ```javascript\n  observer.config().snapshot.setFsProvider(__dirname);\n  \n  observer.snapshot(); // a new Snapshot automatically configured to use the filesystem provider\n  ```\n\n* **push(...values)** - Fixture.push, pushes values into a Fixture container.\n\n* **begin(epoch, comment)** - History.begin, begins a historical epoch.\n\n* **end()** - History.end, ends a historical epoch.\n\n  The method also restores overridden by **override** classes within the epoch.\n\n* **by(class, props)** - Mock.by, constructs mock by the class with optional custom props.\n\n* **from(props)** - Mock.from, constructs mock from the custom props.\n\n* **override(class, props)** - Mock.override, overrides props of the class.\n\n  The overridden class will be linked to the current epoch so that the class will be automatically restored on its end.\n\n* **spy(function)** - Mock.spy, spies on the function.\n\n* **filter()** - creates Filter over the historical entries.\n\n* **snapshot()** - creates Snapshot over the historical entries.\n\n### History\n\n```javascript\nconst History = require('@akaterra/unitsnap').History;\n```\n\nHistory chronologically collects the entries with results of execution of each single observed function of the execution flow.\n\nThe general structure of the entry:\n\n```javascript\nargs: {\n    '*': [ // rest of arguments\n        <value>,..\n    ],\n    <arg 1 name>: <value>,.. // value of named argument\n},\ncallsCount: <number>, // total calls count\ncomment: <string>, // comment of the current historical epoch\ncontext: this, // context of call\nepoch: <string>, // current historical epoch\nexception: <value>, // exception\nexceptionsCount: <number>, // total exceptions count\nisAsync: <boolean>, // async (Promise) result was returned\nisAsyncPending: <boolean>, // async (Promise) result is still not resolved or rejected\nisException: <boolean>, // is call thrown exception\nname: <string>, // name of single function (\"func\") or function of class (\"class.func\")\norigin: <function>, // observed function\nreplacement: <function>, // observer function\nresult: <value>, // return result\ntags: [ // custom tags\n    <value>,..\n],\ntime: <Date>,\ntype: <string>, // type, \"single\", \"constructor\" or \"method\"\n```\n\nA some single called function is commonly will generate two entries:\n\n1) with the **args** field on the function call\n2) with the **result** and **exception** fields on the end of the function execution\n\n```javascript\nfunction a(a, b, c) {\n    return 1;\n}\n\na(1, 2, 3);\n```\n\ngenerates entries containing the next fields:\n\n```javascript\n[\n    {\n        args: {\n            '*': [],\n            a: 1,\n            b: 2,\n            c: 3\n        }\n    },\n    {\n        result: 1\n    }\n]\n```\n\n```javascript\nfunction a(a, b, c) {\n    throw 1;\n}\n\na(1, 2, 3);\n```\n\ngenerates entries containing the next fields:\n\n```javascript\n[\n    {\n        args: {\n            '*': [],\n            a: 1,\n            b: 2,\n            c: 3\n        }\n    },\n    {\n        exception: 1\n    }\n]\n```\n\nAsynchronous functions returning a Promise will additionally generate an entry with the result of the promise resolving (as \"result\") or with the error of the promise rejection (as \"exception\").\n\nCollected entries can be assigned to an epochs and will be filtered after by the necessary epoch. \nEpochs can be nested.\n\n* **getCurrentEpoch()** - returns the current epoch descriptor or null if the history is not yet begun.\n\n* **addOnEndCallback(function)** - adds a callback to the current epoch.\n\n  This callback will be triggered on the epoch end.\n\n* **begin(epoch, comment)** - begins a historical epoch.\n\n* **end()** - ends a historical epoch.\n\n* **filter()** - creates Filter over the collected historical entries.\n\n* **flush()** - flushes epochs and collected historical entries.\n\n* **push(entry)** - pushes the historical entry.\n\n### Mock\n\n```javascript\nconst Mock = require('@akaterra/unitsnap').Mock;\n```\n\nThe Mock builds a mock that commonly is a fake representation of the initial entity and can be used instead of original entity.\nStatic methods, instance properties and static properties of the initial entity can be mocked with the special modifiers **StaticMethod**, **Property** and **StaticProperty**.\nBesides, this mock can optionally be linked to the history so that the state of the call observed by the mock will be stored in the history.\n\n* **from(props)** - constructs mock from the props\n\n    Single mock:\n\n    ```javascript\n    const Mock = require('@akaterra/unitsnap').Mock;\n    const Property = require('@akaterra/unitsnap').Property;\n    const StaticMethod = require('@akaterra/unitsnap').StaticMethod;\n    const StaticProperty = require('@akaterra/unitsnap').StaticProperty;\n\n    const mock = new Mock(history);\n\n    const Mocked = mock.from({\n        a: function () { return 1; }, // custom function\n        b: Function, // stub function\n        c: 123, // function returning 123\n        d: new Fixture().push(1, 2, 3), // linked to provided Fixture.pop\n        e: Fixture, // exception - can be linked to observer Fixture only in context of observer\n        f: StaticMethod(Function), // custom static method\n        g: Property().get(1).set(Function), // custom property returning \"1\" on get and does nothing on set\n        h: StaticProperty().get(1).set(Function), // custom static property returning \"1\" on get and does nothing on set\n        i: typeHelpers.This, // stub function returning this\n    });\n\n    const mocked = new Mocked();\n\n    mocked.a(); // returns 1\n    mocked.b(); // returns undefined\n    mocked.c(); // returns 123\n    mocked.d(); // returns 1\n    mocked.e(); // not been created\n    mocked.f(); // returns undefined\n    mocked.g; // returns 1\n    mocked.g = 2;\n    mocked.h; // returns 1\n    mocked.h = 2;\n    mocked.i(); // return this\n    ```\n\n    Mock in context of observer:\n\n    ```javascript\n    const Observer = require('@akaterra/unitsnap').Observer;\n    const Property = require('@akaterra/unitsnap').Property;\n    const StaticMethod = require('@akaterra/unitsnap').StaticMethod;\n    const StaticProperty = require('@akaterra/unitsnap').StaticProperty;\n\n    const observer = new Observer();\n\n    const Mocked = observer.from({\n        a: function () { return 1; }, // custom function\n        b: Function, // stub function\n        c: 123, // function returning 123\n        d: new Fixture().push(1, 2, 3), // linked to provided Fixture.pop\n        e: Fixture, // linked to observer.Fixture.pop\n        f: StaticMethod(2), // custom static method returning \"2\"\n        g: Property().get(1).set(Function), // custom property returning \"1\" on get and does nothing on set\n        h: StaticProperty().get(1).set(Function), // custom static property returning \"1\" on get and does nothing on set\n        i: typeHelpers.This, // stub function returning this\n    });\n\n    const mocked = new Mocked();\n\n    mocked.a(); // returns \"1\"\n    mocked.b(); // returns \"undefined\"\n    mocked.c(); // returns \"123\"\n    mocked.d(); // returns \"1\"\n    mocked.e(); // returns popped value from observer Fixture similar to call of \"d\"\n    mocked.f(); // returns \"2\"\n    mocked.g; // returns \"1\"\n    mocked.g = 2;\n    mocked.h; // returns \"1\"\n    mocked.h = 2;\n    mocked.i(); // return this\n    ```\n\n* **by(class, props)** - constructs mock by the class with the custom props\n\n    ```javascript\n    class A {\n        a(a, b, c) {\n            return a + b + c;\n        }\n        b() {\n            return 'b';\n        }\n        c() {\n            return 'c';\n        }\n        d() {\n            return 'd';\n        }\n        e() {\n            return 'e';\n        }\n    }\n    ```\n\n    Mock by entire class:\n\n    ```javascript\n    const Mock = require('@akaterra/unitsnap').Mock;\n    const Property = require('@akaterra/unitsnap').Property;\n    const StaticMethod = require('@akaterra/unitsnap').StaticMethod;\n    const StaticProperty = require('@akaterra/unitsnap').StaticProperty;\n\n    const mock = new Mock(history);\n\n    const Mocked = mock.by(A);\n    \n    const mocked = new Mocked();\n\n    mock.a(1, 2, 3); // returns \"6\"\n    mock.b(); // returns \"b\"\n    mock.c(); // returns \"c\"\n    mock.d(); // returns \"d\"\n    mock.e(); // returns \"e\"\n    ```\n\n    Single mock with a custom props:\n\n    ```javascript\n    const Mock = require('@akaterra/unitsnap').Mock;\n    const Property = require('@akaterra/unitsnap').Property;\n    const StaticMethod = require('@akaterra/unitsnap').StaticMethod;\n    const StaticProperty = require('@akaterra/unitsnap').StaticProperty;\n\n    const mock = new Mock(history);\n\n    const Mocked = mock.by(A, {\n        constructor: 123, // generates constructor returning \"123\"\n        a: function () { return 1; }, // custom function\n        b: A, // A.prototype.b\n        c: 123, // function returning 123\n        d: new Fixture().push(1, 2, 3), // linked to provided Fixture.pop\n        e: Fixture, // exception - can be linked to observer Fixture only in context of observer\n        f: StaticMethod(2), // custom static method returning \"2\"\n        g: Property().get(1).set(Function), // custom property returning \"1\" on get and does nothing on set\n        h: StaticProperty().get(1).set(Function), // custom static property returning \"1\" on get and does nothing on set\n        i: typeHelpers.This, // stub function returning this\n    });\n\n    const mocked = new Mocked();\n\n    mocked.a(); // returns \"1\"\n    mocked.b(); // returns \"b\"\n    mocked.c(); // returns \"123\"\n    mocked.d(); // returns \"1\"\n    mocked.e(); // not been created\n    mocked.f(); // returns \"2\"\n    mocked.g; // returns \"1\"\n    mocked.g = 2;\n    mocked.h; // returns \"1\"\n    mocked.h = 2;\n    mocked.i(); // return this\n    ```\n\n    Mock with a custom props in the Observer's context:\n\n    ```javascript\n    const Observer = require('@akaterra/unitsnap').Observer;\n    const Property = require('@akaterra/unitsnap').Property;\n    const StaticMethod = require('@akaterra/unitsnap').StaticMethod;\n    const StaticProperty = require('@akaterra/unitsnap').StaticProperty;\n\n    const observer = new Observer();\n\n    const Mocked = observer.by(A, {\n        constructor: 123, // generates constructor returning \"123\"\n        a: function () { return 1; }, // custom function\n        b: A, // A.prototype.b\n        c: 123, // function returning \"123\"\n        d: new Fixture().push(1, 2, 3), // linked to provided Fixture.pop\n        e: Fixture, // linked to observer.Fixture.pop\n        f: StaticMethod(2), // custom static method returning \"2\"\n        g: Property().get(1).set(Function), // custom property returning \"1\" on get and does nothing on set\n        h: StaticProperty().get(1).set(Function), // custom static property returning \"1\" on get and does nothing on set\n        i: typeHelpers.This, // stub function returning this\n   });\n\n    const mocked = new Mocked();\n\n    mocked.a(); // returns \"1\"\n    mocked.b(); // returns \"b\"\n    mocked.c(); // returns \"123\"\n    mocked.d(); // returns \"1\"\n    mocked.e(); // returns popped value from observer Fixture similar to call of \"d\"\n    mocked.f(); // returns \"2\"\n    mocked.g; // returns \"1\"\n    mocked.g = 2;\n    mocked.h; // returns \"1\"\n    mocked.h = 2;\n    mocked.i(); // return this\n    ```\n\n* **override(class, props)** - overrides props of the class\n\n    Generally can be used same as the **by** but instead of creation of a new class it overrides props of the provided class.\n    The overridden props can be restored after by calling **RESTORE**:\n\n    ```javascript\n    const Mock = require('@akaterra/unitsnap').Mock;\n\n    const mock = new Mock(history);\n\n    mock.override(A, {\n        constructor: 123, // does nothing, the original constructor can't be overridden\n        a: function () {\n            return 'a';\n        }\n    });\n\n    A.RESTORE(); // A.prototype.a is been restored\n    ```\n\n* **spy(function)** - spies on a single function\n\nNote, that the mocked method will be dynamically replaced by its copy on the first call of this method.\nThis make for the ability to collect call statistic on behalf of the instance but not its prototype.\n```javascript\nconst Mock = require('@akaterra/unitsnap').Mock;\n\nconst mock = new Mock(history);\n\nconst MockA = mock.by(A, {\n    x: 1\n});\n\nconst a = new MockA();\n\na.x(); // statistics available now by \"a.x\", not by \"a.prototype.x\"\n```\n\nTo leave statistics collection on behalf of prototype:\n```javascript\nconst Mock = require('@akaterra/unitsnap').Mock;\n\nconst mock = new Mock(history);\n\nconst MockA = mock.by(A, {\n    x: 1\n}, true);\n\nconst a = new MockA();\n\na.x(); // statistics available by \"a.prototype.x\"\n```\n\nSame is for the \"from\" and the \"override\".\n\n##### Customization\n\nProperties can be customized with the **Custom** entity.\n\n```javascript\nconst ArgsAnnotation = require('@akaterra/unitsnap').ArgsAnnotation;\nconst Custom = require('@akaterra/unitsnap').Custom;\nconst Exclude = require('@akaterra/unitsnap').Exclude;\nconst Mock = require('@akaterra/unitsnap').Mock;\n\nconst mock = new Mock(history);\n\nconst Mocked = mock.by(A, {\n    a: Custom(Function).argsAnnotation(['x', 'y', 'z']), // callee arguments with be named as \"x\", \"y\" and \"z\"\n    b: Custom(Function).exclude(), // will be excluded from history\n    c: ArgsAnnotation(Function, ['x', 'y', 'z']), // same as \"a\" field\n    d: Exclude(Function), // same as \"b\" field\n});\n```\n\n### Fixture\n\n```javascript\nconst Fixture = require('@akaterra/unitsnap').Fixture;\n```\n\nFixture provides a fake data to be used as a result of the function call.\n\n* **pop** - pops a value from the container.\n\n* **push(...values)** - pushes values to the container.\n\n* **throwOnCallback(function)** - checks the popped value via callback and throws values as an error.\n\n* **throwOnClassOf(class)** - checks the popped value to be strict instance of class and throws values as an error.\n\n* **throwOnInstanceOf(class)** - checks the popped value to be instance of class and throws values as an error.\n\n##### FixtureCallbackStrategy\n\nCallback strategy allows to use a custom callback as a generator for the popped value.\n\n```\nfixture.setCallbackStrategy(() => 1);\n\nfixture.push(1, 2, 3); // calls the callback with 1, 2, 3\n\nfixture.pop(); // 1\n```\n\n##### FixtureQueueStrategy\n\nQueue strategy allows to use a queued values.\n\n```\nfixture.setQueueStrategy();\n\nfixture.push(1, 2, 3); // [1, 2, 3]\n\nfixture.pop(); // 1 - popped from the beginning of the queue; [2, 3] is a rest\n```\n\n##### FixtureFsProvider (for Queue strategy)\n\nFilesystem provider allows to load values from the file.\n\n```\nfixture.setName('test'); // set fixture name that will be used as a part of filename\n\nfixture.setQueueStrategy();\n\nfixture.setFsProvider(__dirname); // values from the __dirname/test.fixture.json will be loaded\n```\n\n##### FixtureMemoryProvider (for Queue strategy)\n\nFilesystem provider allows to load values from the memory.\n\n```\nfixture.setName('test'); // set fixture name that will be a key in the dictionary of values\n\nfixture.setQueueStrategy();\n\nfixture.setMemoryProvider({test: [1, 2, 3]}); // values by dictionary key \"test\" will be loaded\n```\n\n### Filter\n\nFilter allows to filter the collected historical entries and create a new snapshot over them.\n\nIf some subset of the collected historical entries is required, first of all the filtering conditions must be defined.\nThen the snapshot over this subset of the historical entries can be created.\n\n* **context(obj)** - adds \"filter by context\", all entries belonging to the **obj** will be taken.\n\n* **custom(function)** - adds \"filter by custom handler\", all entries will be checked by the handler.\n\n* **epoch(epoch)** - adds \"filter by epoch\", all entries belonging to the **epoch** will be taken.\n\n* **fn(function)** - adds \"filter by function\", all entries having the **function** as an observed function will be taken.\n\n* **tags(...tags)** - adds \"filter by tags\", all entries having the tags will be taken.\n\n* **not()** - enables \"negative\" filter once so that the next filter will perform a negative comparison:\n  ```javascript\n  filter.not().epoch('excluded epoch'); // excludes all entries with \"epoch\" fields = \"excluded epoch\"\n  ```\n\n* **notPromiseResult()** - adds \"filter if result is not Promise\", all entries having not Promise result will be taken.\n\n* **snapshot()** - create snapshot over the filtered historical entries.\n\n### Snapshot\n\nSnapshot contains the entire or the filtered subset of the historical entries.\nThese entries can be serialized and asserted with the some other snapshot.\nAlso it is possible to create a new Filter over the entries of the snapshot, then filter and create an additional snapshot over them.\n\n* **assert(snapshot)** - asserts other snapshot.\n\n* **assertSaved(name)** - asserts the saved snapshot.\n\n* **filter()** - creates a new Filter over the snapshot entries.\n\n* **includeArgs()** - \"args\" section of the entry will be included to the serialized representation.\n\n* **includeCallsCount()** - \"callCount\" section of the entry will be included to the serialized representation.\n\n* **includeEpoch()** - \"epoch\" section of the entry will be included to the serialized representation.\n\n* **includeException()** - \"exception\" section of the entry will be included to the serialized representation.\n\n* **includeExceptionsCount()** - \"exceptionCount\" section of the entry will be included to the serialized representation.\n\n* **includeIsAsync()** - \"isAsync\" section of the entry will be included to the serialized representation.\n\n* **includeName()** - \"name\" section of the entry will be included to the serialized representation.\n\n* **includeType()** - \"type\" section of the entry will be included to the serialized representation.\n\n* **exists(name)** - checks if the snapshot exists. \n\n* **load(name)** - loads serialized representation of the snapshot.\n\n* **loadCopy(name)** - loads serialized representation of the snapshot as a new Snapshot.\n\n* **remove(name)** - removes saved snapshot.\n\n* **save(name)** - saves a serialized representation of the snapshot.\n\n* **serialize()** - creates a serialized representation of the snapshot.\n\n* **setName(name)** - sets the name of the snapshot, this name will be used as a default name for **exists**, **load**, **loadCopy**, **remove** and **save**.\n\n##### Value processors\n\nThe specific value of some entry can be serialized with the custom serializer.\nIt can be convenient in cases when the some generalized representation of the value required.\nFor example, assertion of type \"instance of class\" can be applied to the value serialized in form of \"class name\" of the value instead of its initial value.\n\nNote, that each added processor will be inserted into beginning of the processors chain so that it will be applied first.\n\n* **addProcessor(checker, serializer)** -  adds custom checker and serializer.\n\n  **checker** is a function that checks if the value should be serialized, **serializer** performs value serialization.\n\n* **addClassOfProcessor(class, serializer)** - adds \"class of\" processor, the value will be serialized as:\n  ```javascript\n  {\n    $$data: <class name>,\n    $$type: 'classOf'\n  }\n  ```\n\n* **addInstanceOfProcessor(class, serializer)** - adds \"instance of\" processor, the value will be serialized as:\n  ```javascript\n  {\n    $$data: <class name of instance>,\n    $$type: 'instanceOf'\n  }\n  ```\n\n* **addPathProcessor(path, serializer)** - adds \"match to path\" processor, the value having **path** will be serialized with **serializer**\n\n  Path can contain an asterisk (\"*\") as any number of characters and an underscore (\"_\") as a single character.\n\n* **addRegexPathProcessor(regex, serializer)** - adds \"match to regex path\" processor, the value with path matched to the **regex** will be serialized with **serializer**.\n\n* **addUndefinedProcessor(serializer)** - adds \"undefined value\" processor, the value will be serialized as:\n  ```javascript\n  {\n    $$data: null,\n    $$type: 'undefined'\n  }\n  ```\n\nIf matched and serialized value has to be continued with the rest processors use **Continue** type helper.\n```javascript\nsnapshot.addProcessor((value) => value === 5, (value) => new Continue(value));\n```\n\n##### Type helpers\n\nThe set of special type helpers can be used with value processors that can be useful in some cases.\n\n```javascript\nsnapshot.addProcessor(Date); // adds checker \"instance of Date\" and serializer to {$$data: null, $$type: 'date'}\n```\n\nSerialized snapshot:\n\n```json\n[\n    {\n        \"args\": {\n            \"*\": []\n        }\n    },\n    {\n        \"result\": {\n            \"$$data\": null,\n            \"$$type\": \"date\"\n        }\n    }\n]\n```\n\nAvailable helpers:\n\n* **AnyType** - serializes any value as:\n  ```javascript\n  {\n    $$data: null,\n    $$type: \"any\"\n  }\n  ```\n\n* **BooleanType (or JS Boolean type)** - checks the value to be boolean and serializes the value as:\n  ```javascript\n  {\n    $$data: null,\n    $$type: \"boolean\"\n  }\n  ```\n\n* **ClassOfType** - checks the value to be class of and serializes the value as:\n  ```javascript\n  {\n    $$data: <class name>,\n    $$type: \"classOf\"\n  }\n  ```\n\n* **Continue** - the value will be continued with the rest processors.\n\n* **DateType (or JS Date type)** - checks the value to be instance of Date and serializes the value as:\n  ```javascript\n  {\n    $$data: null,\n    $$type: \"date\"\n  }\n  ```\n\n* **DateValue** - checks the value to be instance of Date and serializes the value as:\n  ```javascript\n  {\n    $$data: <ISO string>,\n    $$type: \"date\"\n  }\n  ```\n\n* **Ignore** - the value will be omitted in the serialized snapshot.\n\n* **InstanceOfType** - checks the value to be instance of Date and serializes the value as:\n  ```javascript\n  {\n    $$data: <class name>,\n    $$type: \"instanceOf\"\n  }\n  ```\n\n* **NumberType (or JS Number type)** - checks the value to be number and serializes the value as:\n  ```javascript\n  {\n    $$data: null,\n    $$type: \"number\"\n  }\n  ```\n\n* **StringType (or JS String type)** - checks the value to be string and serializes the value as:\n  ```javascript\n  {\n    $$data: null,\n    $$type: \"string\"\n  }\n  ```\n\n* **UndefinedType (or undefined)** - checks the value to be undefined value and serializes the value as:\n  ```javascript\n  {\n    $$data: null,\n    $$type: \"undefined\"\n  }\n  ```\n\n##### SnapshotFsProvider\n\nFilesystem provider allows to load and save snapshots as files.\n\n```javascript\nsnapshot.setFsProvider(__dirname);\n\nsnapshot.save('test'); // __dirname/test.snapshot.json\n\nsnapshot.load('test');\n```\n\n##### SnapshotMemoryProvider\n\nMemory provider allows to load and save temporary snapshot in the process memory.\n\n```javascript\nsnapshot.setMemoryProvider();\n\nsnapshot.save('test');\n\nsnapshot.load('test');\n```\n\n### Jasmine matcher\n\nThe special Jasmine matcher **toMatchSnapshot** can be used in specs for snapshots saving and assertion.\n\nEnable the matcher and configure default snapshot, for example, to use the file system provider:\n\n```javascript\nvar unitsnap = require('@akaterra/unitsnap');\n\nunitsnap.extendJasmine();\n\nunitsnap.config().snapshot.setFsProvider(__dirname);\n```\n\nUse the matcher in some **it**:\n\n```\nit('should do something', function () {\n    ...\n\n    expect(observer.snapshot()).toMatchSnapshot('test');\n});\n```\n\nRun Jasmine with the env variable **SAVE_SNAPSHOT**=1 telling to the matcher to save snapshots.\nThe snapshot will be saved into the \"__dirname/test.snapshot.json\" file.\n\nBe sure that the saved snapshot represents valid state of the execution flow.\n\nRun Jasmine usually now to assert the saved snapshot (not existing snapshot will be auto saved instead).\nIt will throw standard Jasmine **toEqual** error on mismatch.\n\nExample (see full example /spec/jasmine.spec.js):\n\n```javascript\nconst unitsnap = require('@akaterra/unitsnap');\n\ndescribe('some suite', () => {\n    const observer = unitsnap.default;\n\n    observer.config().snapshot.setFsProvider(__dirname);\n\n    beforeAll(() => unitsnap.extendJasmine());\n    beforeEach(() => observer.begin());\n    afterEach(() => observer.end());\n    \n    it('some spec', () => {\n        class A {\n            b(x) {\n                return 1;\n            }\n        }\n        \n        const Mock = observer.by(A);\n        const mock = new Mock();\n        \n        mock.b(111);\n\n        expect(observer).toMatchSnapshot('some spec'); // saves or asserts the snapshot __dirname/some_spec.snapshot.json\n    });\n});\n```\n\n### Using with typescript-ioc\n\nNext bootstrap code can be useful:\n\n```typescript\nimport {Container, Scope} from 'typescript-ioc';\n\nexport const unitsnapIoC = (observer) => {\n    const ioc = {\n        mocked: new Array<any>(),\n\n        // builds mock by baseCls or cls and registers it in IoC\n        by: (cls, props?, baseCls?) => {\n            const newCls = observer.by(baseCls || cls, props);\n\n            ioc.mocked.unshift([cls, Container.getType(cls), newCls]);\n\n            Container.bind(cls).scope(Scope.Singleton).to(newCls);\n\n            return ioc;\n        },\n\n        // builds mock by baseCls or cls and registers it in IoC\n        override: (cls, props?, baseCls?) => {\n            const newCls = observer.override(baseCls || cls, props);\n\n            ioc.mocked.unshift([cls, Container.getType(cls), newCls]);\n\n            Container.bind(cls).scope(Scope.Singleton).to(newCls);\n\n            return ioc;\n        },\n\n        // restores original association\n        restore: () => {\n            for (const cls of ioc.mocked) {\n                Container.bind(cls[0]).scope(Scope.Singleton).to(cls[1] || cls[0]);\n            }\n\n            ioc.mocked = [];\n\n            return ioc;\n        }\n    };\n\n    return ioc;\n};\n```\n\nCreate \"jasmine.d.ts\" file in the spec directory that adds jasmine matcher declaration:\n\n```typescript\ndeclare module jasmine {\n    interface Matchers<T> {\n        toMatchSnapshot(expected: any, expectationFailOutput?: any): boolean;\n    }\n}\n```\n","readmeFilename":"readme.md"}