├── .eslintignore ├── .eslintrc ├── .github ├── CODEOWNERS ├── PULL_REQUEST_TEMPLATE.md ├── semantic.yml ├── stale.yml └── workflows │ ├── ci.yml │ ├── pre-release.yml │ └── release.yml ├── .gitignore ├── .husky ├── commit-msg └── pre-commit ├── .npmignore ├── LICENSE ├── README.md ├── codecov.yml ├── commitlint.config.js ├── docs ├── README.md ├── logo.png ├── mock-decorator.md ├── mock-factory.md └── recipes.md ├── jest.config.base.js ├── jest.config.js ├── lerna.json ├── package.json ├── packages ├── common │ ├── .eslintrc │ ├── CHANGELOG.md │ ├── README.md │ ├── index.ts │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── is-primitive.ts │ │ └── types.ts │ └── tsconfig.json ├── logger │ ├── .eslintignore │ ├── .eslintrc │ ├── CHANGELOG.md │ ├── index.ts │ ├── package.json │ ├── src │ │ ├── index.ts │ │ └── logger.ts │ └── tsconfig.json ├── mockingbird │ ├── .eslintignore │ ├── .eslintrc │ ├── CHANGELOG.md │ ├── README.md │ ├── index.ts │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── builder │ │ │ │ ├── index.ts │ │ │ │ ├── mock-builder.test.ts │ │ │ │ ├── mock-builder.ts │ │ │ │ ├── mock-producer.ts │ │ │ │ └── types.ts │ │ │ ├── factory │ │ │ │ └── mock-factory.ts │ │ │ └── index.ts │ │ └── types │ │ │ ├── mock-decorator-factory-options.interface.ts │ │ │ └── mock-generator-options.interface.ts │ ├── test │ │ └── e2e │ │ │ ├── __snapshots__ │ │ │ └── mock-factory.test.ts.snap │ │ │ ├── mock-factory.test.ts │ │ │ └── test-classes.ts │ └── tsconfig.json ├── parser │ ├── .eslintignore │ ├── .eslintrc │ ├── CHANGELOG.md │ ├── README.md │ ├── index.ts │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── index.ts │ │ └── lib │ │ │ ├── generator │ │ │ ├── mock-generator.test.ts │ │ │ └── mock-generator.ts │ │ │ ├── handlers │ │ │ ├── array-value-handler.test.ts │ │ │ ├── array-value-handler.ts │ │ │ ├── callback-value-handler.test.ts │ │ │ ├── callback-value-handler.ts │ │ │ ├── enum-value-handler.test.ts │ │ │ ├── enum-value-handler.ts │ │ │ ├── object-literal-value-handler.test.ts │ │ │ ├── object-literal-value-handler.ts │ │ │ ├── primitive-handler.ts │ │ │ ├── primitive-value-handler.test.ts │ │ │ ├── primitive-value-handler.ts │ │ │ ├── regex-value-handler.test.ts │ │ │ ├── regex-value-handler.ts │ │ │ ├── single-class-value-handler.test.ts │ │ │ └── single-class-value-handler.ts │ │ │ ├── parser │ │ │ ├── class-parser.test.ts │ │ │ └── class-parser.ts │ │ │ └── types │ │ │ ├── mock-generator-options.interface.ts │ │ │ ├── types.ts │ │ │ └── value-handler.interface.ts │ ├── test │ │ └── integration │ │ │ ├── __snapshots__ │ │ │ └── mock-generator.test.ts.snap │ │ │ ├── common │ │ │ └── test-classes.ts │ │ │ └── mock-generator.test.ts │ └── tsconfig.json ├── reflect │ ├── .eslintignore │ ├── .eslintrc │ ├── CHANGELOG.md │ ├── README.md │ ├── index.ts │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── decorators │ │ │ ├── index.ts │ │ │ └── mock.decorator.ts │ │ ├── index.ts │ │ ├── lib │ │ │ ├── class-reflector.test.ts │ │ │ ├── class-reflector.ts │ │ │ ├── index.ts │ │ │ ├── property-decorator-value.test.ts │ │ │ ├── property-decorator-value.ts │ │ │ └── property.ts │ │ └── types │ │ │ ├── class-reflection.type.ts │ │ │ ├── index.ts │ │ │ └── mock-options.type.ts │ └── tsconfig.json └── tsconfig.build.json ├── sample └── mockingbird-typeorm │ ├── .gitignore │ ├── README.md │ ├── docker-compose.yml │ ├── jest.config.js │ ├── ormconfig.json │ ├── package.json │ ├── src │ ├── app.ts │ ├── common │ │ └── connection-factory.ts │ ├── entity │ │ └── user.entity.ts │ ├── interface │ │ └── user.interface.ts │ ├── main.ts │ └── user.controller.ts │ ├── test │ ├── app-e2e.test.ts │ └── mocks │ │ └── user-entity.mock.ts │ ├── tsconfig.json │ └── yarn.lock ├── tsconfig.json └── yarn.lock /.eslintignore: -------------------------------------------------------------------------------- 1 | deprecated 2 | packages/**/index.js 3 | packages/**/index.d.ts 4 | packages/**/dist/**/* 5 | node_modules/* 6 | coverage/* 7 | dist 8 | dist/* 9 | jest.config.base.js 10 | commitlint.config.js 11 | jest.config.js -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "plugins": [ 5 | "prettier" 6 | // "prettier/@typescript-eslint" 7 | ], 8 | "parserOptions": { 9 | "ecmaVersion": 8 10 | }, 11 | "settings": { 12 | "import/parsers": { 13 | "@typescript-eslint/parser": [ 14 | ".ts" 15 | ] 16 | }, 17 | "import/resolver": { 18 | "node": { 19 | "extensions": [ 20 | ".ts" 21 | ] 22 | }, 23 | "typescript": { 24 | "alwaysTryTypes": true 25 | } 26 | }, 27 | "import/extensions": 0 28 | }, 29 | "extends": [ 30 | "plugin:@typescript-eslint/recommended", 31 | "prettier" 32 | ], 33 | "rules": { 34 | "no-useless-constructor": "off", 35 | "prettier/prettier": [ 36 | "error", 37 | { 38 | "singleQuote": true, 39 | "printWidth": 120, 40 | "trailingComma": "es5" 41 | } 42 | ], 43 | "no-unused-expressions": 0, 44 | "one-var": 0, 45 | "no-underscore-dangle": [ 46 | 0, 47 | { 48 | "allow": [] 49 | } 50 | ], 51 | "global-require": 0, 52 | "new-cap": "off", 53 | "@typescript-eslint/no-namespace": "off", 54 | "@typescript-eslint/no-explicit-any": 0, 55 | "@typescript-eslint/explicit-function-return-type": 0, 56 | "import/extensions": 0, 57 | "@typescript-eslint/camelcase": 0, 58 | "camelcase": "off", 59 | "consistent-return": 0, 60 | "import/prefer-default-export": 0, 61 | "lines-between-class-members": "off" 62 | }, 63 | "env": { 64 | "node": true, 65 | "jest": true 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * omer.moradd@gmail.com 2 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Description 4 | 5 | 6 | ## Motivation and Context 7 | 8 | 9 | 10 | ## How Has This Been Tested? 11 | 12 | 13 | 14 | 15 | 16 | ## Types of changes 17 | 18 | - [ ] Bug fix (non-breaking change which fixes an issue) 19 | - [ ] New feature (non-breaking change which adds functionality) 20 | - [ ] Breaking change (fix or feature that would cause existing functionality to change) 21 | 22 | ## Checklist: 23 | 24 | 25 | - [ ] My change requires a change to the documentation. 26 | - [ ] I have updated the documentation accordingly. 27 | - [ ] I have added tests to cover my changes. 28 | - [ ] All new and existing tests passed. 29 | 30 | -------------------------------------------------------------------------------- /.github/semantic.yml: -------------------------------------------------------------------------------- 1 | titleAndCommits: true 2 | anyCommit: true 3 | allowRevertCommits: true 4 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 60 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | # Label to use when marking an issue as stale 9 | staleLabel: wontfix 10 | # Comment to post when marking an issue as stale. Set to `false` to disable 11 | markComment: > 12 | This issue has been automatically marked as stale because it has not had 13 | recent activity. It will be closed if no further activity occurs. Thank you 14 | for your contributions. 15 | # Comment to post when closing a stale issue. Set to `false` to disable 16 | closeComment: false 17 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - master 7 | - release 8 | 9 | jobs: 10 | build-and-test: 11 | if: "!contains(github.event.head_commit.message, '[skip ci]')" 12 | name: Build & Test 13 | 14 | runs-on: ubuntu-latest 15 | 16 | strategy: 17 | matrix: 18 | node-version: [ 12.x, 14.x, 16.x ] 19 | 20 | steps: 21 | - name: Checkout 22 | uses: actions/checkout@master 23 | with: 24 | ref: ${{ github.head_ref }} 25 | 26 | - name: Get Yarn Cache Directory Path 27 | id: yarn-cache-dir-path 28 | run: echo "::set-output name=dir::$(yarn cache dir)" 29 | 30 | - name: Use NodeJS ${{ matrix.node-version }} 31 | uses: actions/setup-node@v1 32 | with: 33 | node-version: ${{ matrix.node-version }} 34 | 35 | - name: Yarn Init 36 | id: yarn-cache 37 | uses: actions/cache@v2 38 | with: 39 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 40 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 41 | restore-keys: | 42 | ${{ runner.os }}-yarn- 43 | 44 | - name: Lint Commit Message 45 | run: | 46 | yarn add -D -W @commitlint/config-conventional 47 | echo $(git log -1 --pretty=format:"%s") | yarn commitlint 48 | 49 | - name: Lint 50 | run: lerna exec --parallel -- yarn lint 51 | 52 | - name: Build 53 | run: yarn build 54 | 55 | - name: Test 56 | run: yarn test:cov 57 | 58 | - name: Upload Report to Codecov 59 | uses: codecov/codecov-action@v1 60 | with: 61 | token: ${{ secrets.CODECOV_TOKEN }} 62 | directory: ./coverage 63 | fail_ci_if_error: false 64 | files: ./coverage/cobertura-coverage.xml 65 | name: codecov-umbrella 66 | verbose: false 67 | -------------------------------------------------------------------------------- /.github/workflows/pre-release.yml: -------------------------------------------------------------------------------- 1 | name: Release Candidate 2 | on: [workflow_dispatch] 3 | 4 | jobs: 5 | release: 6 | runs-on: ubuntu-latest 7 | env: 8 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 9 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 10 | 11 | name: Release 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v2 15 | with: 16 | fetch-depth: 0 17 | ref: ${{ github.head_ref }} 18 | 19 | - name: Configure Git 20 | run: | 21 | git config --global user.email "omer.moradd@gmail.com" 22 | git config --global user.name "ci@$GITHUB_ACTOR" 23 | 24 | - name: Lerna Init 25 | run: lerna bootstrap 26 | 27 | - name: Build 28 | run: yarn build 29 | 30 | - name: Prerelease 31 | run: | 32 | lerna version --conventional-commits --conventional-prerelease --yes --preid rc 33 | lerna publish from-package --yes --dist-tag rc 34 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release Stable 2 | on: [workflow_dispatch] 3 | 4 | jobs: 5 | release: 6 | runs-on: ubuntu-latest 7 | env: 8 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 9 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 10 | 11 | name: Release 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@master 15 | with: 16 | ref: ${{ github.head_ref }} 17 | 18 | - name: Configure Git 19 | run: | 20 | git config --global user.email "omer.moradd@gmail.com" 21 | git config --global user.name "$GITHUB_ACTOR" 22 | 23 | - name: Lerna Init 24 | run: lerna bootstrap 25 | 26 | - name: Build 27 | run: yarn build 28 | 29 | - name: Release 30 | run: | 31 | lerna version --conventional-commits --conventional-graduate --create-release github --yes 32 | lerna publish from-package --yes -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | dist 3 | node_modules 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | 13 | # OS 14 | .DS_Store 15 | 16 | # Tests 17 | coverage 18 | /sample/coverage 19 | /.nyc_output 20 | 21 | # IDEs and editors 22 | /.idea 23 | .project 24 | .classpath 25 | .c9/ 26 | *.launch 27 | .settings/ 28 | *.sublime-workspace 29 | 30 | # IDE - VSCode 31 | .vscode/* 32 | !.vscode/settings.json 33 | !.vscode/tasks.json 34 | !.vscode/launch.json 35 | !.vscode/extensions.json 36 | 37 | .npmrc 38 | junit.xml 39 | .gitconfig 40 | .circleci 41 | !.husky 42 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | yarn commitlint --edit $1 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | yarn lint-staged -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .eslintrc 2 | .editorconfig 3 | coverage 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Omer Morad 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![ISC license](http://img.shields.io/badge/license-MIT-brightgreen.svg)](http://opensource.org/licenses/MIT) 2 | [![npm version](http://img.shields.io/npm/v/mockingbird.svg?style=flat)](https://npmjs.org/package/mockingbird "View this project on npm") 3 | [![Codecov Coverage](https://img.shields.io/codecov/c/github/omermorad/mockingbird/master.svg?style=flat-square)](https://codecov.io/gh/omermorad/mockingbird) 4 | [![lerna](https://img.shields.io/badge/maintained%20with-lerna-cc00ff.svg)](https://lerna.js.org/) 5 | [![ci](https://github.com/omermorad/mockingbird/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/omermorad/mockingbird/actions) 6 | 7 |

8 | Mockingbird Logo 9 | 10 |

Mockingbird

11 | 12 |

13 | Simple Yet Powerful TypeScript Mocking Library 14 |

15 | 16 |

17 | Manage and create your test mocks easily, and focus on your tests logic instead 18 |

19 |

20 | 21 | ## Installation 22 | 23 | ```bash 24 | npm i -D mockingbird 25 | ``` 26 | 27 | ```bash 28 | yarn add -D mockingbird 29 | ``` 30 | 31 | ## What is "Mocking Library"? 32 | A lot of times you find yourself “preparing” some dummy data for your tests that 33 | has to make sense for a specific test case(s) and is manipulated often. 34 | Some developers are preparing JSON files, others create a long verbose object in 35 | the test file itself, but the outcome always contains some fake data inside 36 | (or even a snapshot from an external API). 37 | 38 | This is what Mockingbird aims to solve! 39 | It suggests two ways of creating mocks for your entities/models classes, thus, 40 | creating one uniform way to manage mocks (whether you are working alone or with your team), 41 | your dev experience will improve, and you won’t have to deal with this messy setup at all! 42 | 43 | ## Features 44 | - Prepare as many unique mocks/fixtures as you need for your tests 45 | - Generate dummy (but reasonable) data for database seeding 46 | - Manage your mocks from one place, forget about the messy work 47 | - Full TypeScript compatibility 48 | - Convenient and simple API 49 | 50 | ## Usage 51 | 52 | **Here is the simplest usage of Mockingbird:** 53 | 54 | ```typescript 55 | // Could be interface as well 56 | class BirdEntity { 57 | name: string; 58 | birthday: Date; 59 | goodPoints: number; 60 | } 61 | ``` 62 | 63 | ```typescript 64 | import { Mock, MockFactory } from 'mockingbird'; 65 | 66 | // BirdEntity could be an interface or a class 67 | class BirdEntityMock implements BirdEntity { 68 | @Mock(faker => faker.name.firstName()) 69 | name!: string; 70 | 71 | @Mock() 72 | birthday!: Date; // Will generate a recent date 73 | 74 | @Mock() 75 | goodPoints!: number; // Will generate a random number 76 | } 77 | 78 | const oneBird = MockFactory(BirdEntityMock).one(); 79 | const lotsOfBirds = MockFactory(BirdEntityMock).many(3); 80 | ``` 81 | 82 | ## Documentation 83 | **[Jump to the full documentation and explore the full API](https://github.com/omermorad/faker.ts/blob/master/docs/README.md)** 84 | 85 | **There's also an example, [you can find it under the sample folder](https://github.com/omermorad/mockingbird/tree/master/sample)** 86 | 87 | ## Playground 88 | 89 | **Jump to the [REPL Playground](https://repl.it/@omermorad/Mockingbird-Playground) where you can see Mockingbird in action!** 90 | 91 | ## Motivation 92 | 93 | Creating mocks for your tests (sometimes called "fixtures") can be a tedious and 94 | cumbersome process usually done manually. 95 | 96 | We came up with a simple yet super convenient solution: all you have to do to get mocks out of the 97 | box is to decorate your classes (whether it's an entity, or a model representing the database layer) 98 | and generate simple or complex mocks. 99 | 100 | Mockingbird offers two different ways for preparing mocks; The first one (as we call it), is the TypeScript 101 | way which requires decorating existing (or duplicate) classes. 102 | The second way is to use Mockingbird's functionality directly 103 | 104 | 105 | ### What is `faker.js`? 106 | 107 | `faker.js` it's a library which is used to "generate massive amounts of fake data in the browser and Node". 108 | 109 | Mockingbird uses `faker.js` under the hood, making it possible to enjoy its rich database, and thereby allows 110 | to create mocks that are meaningful like email, first name, address and many more. 111 | 112 | ## License 113 | 114 | Distributed under the MIT License. See `LICENSE` for more information. 115 | 116 | ## Acknowledgements 117 | 118 | [faker.js](https://github.com/marak/Faker.js) 119 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: 4 | default: 5 | target: 90% 6 | patch: 7 | default: 8 | target: 95% 9 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | const { 2 | utils: { getPackages }, 3 | } = require('@commitlint/config-lerna-scopes'); 4 | 5 | module.exports = { 6 | extends: ['@commitlint/config-conventional', '@commitlint/config-lerna-scopes'], 7 | rules: { 8 | 'scope-enum': async (ctx) => [ 9 | 2, 10 | 'always', 11 | [ 12 | ...(await getPackages(ctx)), 13 | 'release', 14 | 'packages', 15 | 'repo', 16 | 'sample' 17 | ], 18 | ], 19 | }, 20 | }; 21 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | [![Codecov Coverage](https://img.shields.io/codecov/c/github/omermorad/mockingbird/master.svg?style=flat-square)](https://codecov.io/gh/omermorad/mockingbird) 2 | [![ci](https://github.com/omermorad/mockingbird/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/omermorad/mockingbird/actions) 3 | 4 | # Mockingbird API Docs 5 | 6 | * [Mock Decorator 🐦](mock-decorator.md) 7 | * [Creating Mocks with MockFactory 👨‍🔬](mock-factory.md) 8 | * [Mockingbird Recipes 🧾](recipes.md) 9 | -------------------------------------------------------------------------------- /docs/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omermorad/mockingbird/421428336b06b0353dcb9a53c7f0c344bd03c95a/docs/logo.png -------------------------------------------------------------------------------- /docs/mock-decorator.md: -------------------------------------------------------------------------------- 1 | # Mockingbird API Documentation 2 | 3 | Here is a detailed explanation of the different options for using the `Mock` decorator: 4 | 5 | | Identifier | Function | Will Generate | Notes | 6 | |---------------------------------------------------------------|---------------------------------------------------------|-----------------------------------------|--------------------------------------------------------| 7 | | [Callback](#callback) | `@Mock(callback: (faker: Faker) => any)` | Value from the callback invocation | Uses the Faker library under the hood, Faker docs are [here](https://faker.readthedocs.io/en/master/) | 8 | | [Inferred Value](#inferred-value) | `@Mock()` | Random value inferred from the property type | | 9 | | [Class](#class) | `@Mock(value: Class)` | Matching class type | Primitive constructors can be used as well | 10 | | [Absolute Value](#absolute-value) | `@Mock(value: string \| boolean \| number \| ObjectLiteral)`| The exact given value | | 11 | | [Enum](#enum) | `@Mock(value: { enum: object })` | Random value from the given enum | The random value is not the key of the enum but the value | 12 | | [Array of Classes](#array-of-classes) | `@Mock(options: { type: Class, count: number })` | Array with `count` items from the given `Class` | | | 13 | 14 | The `Class` interface looks like this: 15 | 16 | ```typescript 17 | export type Class = new (...args: any[]) => T; 18 | ``` 19 | 20 | and represents a 'type' of actual class (not an instance) 21 | 22 | ## Callback 23 | 24 | The first option, probably the most common one, is to pass a callback function that uses the `faker` argument as the 25 | actual `faker` instance. 26 | 27 | So the result of the following code: 28 | 29 | ```typescript 30 | import { MockFactory } from 'mockingbird'; 31 | 32 | class Person { 33 | @Mock(faker => faker.internet.email()) 34 | email: string; 35 | } 36 | 37 | const person = MockFactory(Person).one(); 38 | console.log(person); 39 | ``` 40 | 41 | will be 42 | 43 | ```typescript 44 | { 45 | email: 'random-email@address.com' 46 | } 47 | ``` 48 | 49 | ## Inferred Value 50 | 51 | When using the `Mock` decorator without any value will generate a random value inffered from the property type. 52 | 53 | So the result of the following code: 54 | 55 | ```typescript 56 | import { MockFactory } from 'mockingbird'; 57 | 58 | class Person { 59 | @Mock() 60 | serial: string; 61 | 62 | @Mock() 63 | points: number; 64 | 65 | @Mock() 66 | isLucky: boolean; 67 | } 68 | 69 | const person = MockFactory(Person).one(); 70 | console.log(person); 71 | ``` 72 | 73 | will be: 74 | 75 | ```json 76 | { 77 | serial: 'uirjkcmovf', 78 | points: 64, 79 | isLucky: true 80 | } 81 | ``` 82 | 83 | Type `string` will generate a 10 characters random string \ 84 | Type `number` will generate a number between `1` to `100` \ 85 | Type `boolean` will of course generate `true` or `false` 86 | 87 | ## Class 88 | 89 | Passing a class will generate an object with the matching keys (decorated by the `Mock` decorator) 90 | 91 | So the result of the following code: 92 | 93 | ```typescript 94 | import { MockFactory } from 'mockingbird'; 95 | 96 | class Dog { 97 | @Mock(faker => faker.name.firstName()) 98 | name: string; 99 | } 100 | 101 | class Person { 102 | @Mock() 103 | serial: string; 104 | 105 | @Mock() 106 | points: number; 107 | 108 | @Mock(Dog) 109 | dog: Dog; 110 | 111 | @Mock() 112 | isLucky: boolean; 113 | } 114 | 115 | const person = MockFactory(Person).one(); 116 | console.log(person); 117 | ``` 118 | 119 | Will be: 120 | 121 | ```json 122 | { 123 | serial: 'uirjkcmovf', 124 | points: 64, 125 | dog: { 126 | name: 'Bucky' 127 | }, 128 | isLucky: true 129 | } 130 | ``` 131 | 132 | ## Absolute Value 133 | 134 | The "Absolute Value" option is pretty strait forward, the generated value from the `Mock` decorator will the exact same 135 | value that has been passed 136 | 137 | So the result of the following code: 138 | 139 | ```typescript 140 | import { MockFactory } from 'mockingbird'; 141 | 142 | class Person { 143 | @Mock('John') 144 | serial: string; 145 | 146 | @Mock(78) 147 | points: number; 148 | 149 | @Mock(true) 150 | isLucky: boolean; 151 | } 152 | 153 | const person = MockFactory(Person).one(); 154 | console.log(person); 155 | ``` 156 | 157 | Will be: 158 | 159 | ```json 160 | { 161 | serial: 'John', 162 | points: 78, 163 | isLucky: true 164 | } 165 | ``` 166 | 167 | ## Enum 168 | 169 | Passing an enum object to the `Mock` decorator will generate a random value from the given enum (not a key): 170 | 171 | So the result of the following code: 172 | 173 | ```typescript 174 | import {MockFactory} from 'mockingbird'; 175 | 176 | enum Mood { 177 | Happy = 'happy', 178 | Numb = 'numb', 179 | Sad = 'sad' 180 | } 181 | 182 | class Person { 183 | @Mock({enum: Mood}) 184 | mood: string; 185 | } 186 | 187 | const person = MockFactory(Person).one(); 188 | console.log(person); 189 | ``` 190 | 191 | Will be: 192 | 193 | ```json 194 | { 195 | mood: 'happy' 196 | } 197 | ``` 198 | 199 | ## Array of Classes 200 | 201 | Just as it is possible to move a class as a parameter, so it is also possible to pass an "array" of classes: 202 | 203 | ```typescript 204 | import {MockFactory} from 'mockingbird'; 205 | 206 | class Dog { 207 | @Mock() 208 | name: string; 209 | 210 | @Mock() 211 | points: number; 212 | } 213 | 214 | export class DogWalker { 215 | @Mock({ type: Dog, count: 3 }) 216 | dogs: Dog[]; 217 | } 218 | 219 | const dogWalker = MockFactory(TestClassWithSingleClass).one(); 220 | console.log(dogWalker); 221 | ``` 222 | 223 | Will be: 224 | 225 | ```json 226 | { 227 | dogs: [ 228 | {...}, 229 | {...}, 230 | {...} 231 | ] 232 | } 233 | ``` 234 | 235 | When each object is basically an instance of a dog class and has the properties 'name' and 'points'. 236 | -------------------------------------------------------------------------------- /docs/mock-factory.md: -------------------------------------------------------------------------------- 1 | # Mockingbird API 🐦 2 | 3 | ## Introduction 4 | Mockingbird provides a simple way to create mocks (sometimes called fixtures) 5 | and to apply many variations on them. \ 6 | The entry point of Mockingbird is a simple function called `MockFactory()`, which takes 7 | a class as an argument and an optional generic type, for example: `MockFactory(Bird)`. 8 | 9 | ## `MockFactory` 10 | 11 | `MockFactory` returns a builder which you can apply some more options on (like `mutate` and `ignore`), 12 | or just simply create mocks (or single mock). 13 | 14 | ```typescript 15 | function MockFactory(target: Class): MockBuilder; 16 | ``` 17 | 18 | Where `Class` is an actual JavaScript class. \ 19 | Returns `MockBuilder` when invoked. 20 | 21 |
22 | 23 | ## `MockBuilder` 24 | 25 | Consider the following class (we will use it in the following examples of each method): 26 | 27 | ```typescript 28 | import { Mock } from 'mockingbird'; 29 | 30 | export class Bird { 31 | @Mock((faker) => faker.random.name()) 32 | name: string; 33 | 34 | @Mock(true) // Cause birds are always awesome :) 35 | isAwesome: boolean; 36 | 37 | @Mock() 38 | canFly: boolean; 39 | } 40 | ``` 41 | 42 |
🕵️‍ Discover more about MockBuilder interface

43 | 44 | ```typescript 45 | export interface MockBuilder { 46 | setLocale(locale: string): this; 47 | plain(): this; 48 | mutate(overrides: OverrideKeys): Omit, 'mutate'>; 49 | ignore(...keys: IgnoreKeys): this; 50 | one(): TClass; 51 | many(count: number): TClass[]; 52 | } 53 | ``` 54 |

55 | 56 | 57 | ## API 58 | 59 | ### `.one()` 60 | Simply creates (and return) a new mock from the class (`Bird`); here is an example: 61 | 62 | ```typescript 63 | const birdMock = MockFactory(Bird).one(); 64 | ``` 65 | 66 |
💡 Hint

67 | 68 | ``` 69 | This method can not be chained, 70 | it just return an mock which is an instance of the class Bird 71 | ``` 72 |

73 | 74 |
75 | 76 | ### `.many(count: number)` 77 | Creates (and return) the required `count` mocks from the class; \ 78 | here is an example: 79 | 80 | ```typescript 81 | const birdMock = MockFactory(Bird).many(3); 82 | ``` 83 | 84 |
💡 Hint

85 | 86 | ``` 87 | The .one() method can not be chained, 88 | it just return an instance of the class 89 | ``` 90 |

91 | 92 |
93 | 94 | ### `.omit(...keys: string[])` 95 | Simply ignore some keys in the generated mock. 96 | 97 | ```typescript 98 | const birdMock = MockFactory(Bird).omit('canFly').one(); 99 | ``` 100 | 101 |
💡 Hint

102 | 103 | ``` 104 | .ignore() takes as many arguments as you want as long as they are strings 105 | and they are part of the class properties 106 | 107 | Bird class has 3 properties: 'name', 'isAwesome' and 'canFly'; 108 | In the example above will get a mock without the property 'canFly'. 109 | ``` 110 |

111 | 112 |
113 | 114 | ### `.pick(...keys: string[])` 115 | Pick specific properties from the class. 116 | 117 | ```typescript 118 | const birdMock = MockFactory(Bird).pick('canFly').one(); 119 | ``` 120 | 121 |
💡 Hint

122 | 123 | ``` 124 | .ignore() takes as many arguments as you want as long as they are strings 125 | and they are part of the class properties 126 | 127 | Bird class has 3 properties: 'name', 'isAwesome' and 'canFly'; 128 | In the example above will get a mock without the property 'canFly'. 129 | ``` 130 |

131 | 132 |
133 | 134 | ### `.mutate()` 135 | 136 | Takes an object as an argument which contains keys and values; \ 137 | It can also take a callback with faker and return an object, look at the hint \ 138 | to see an example. 139 | 140 | ```typescript 141 | const birdMock = MockFactory(Bird).mutate({ name: 'Birdy Bird' }).one(); 142 | ``` 143 | 144 |
💡 Hint

145 | 146 | Here is a detailed example: 147 | 148 | ```typescript 149 | const builder = MockFactory(Bird).mutate({ name: 'Birdy Bird' }); 150 | 151 | const oneBird = builder.one(); 152 | const manyBirds = builder.many(3); 153 | ``` 154 | 155 | ``` 156 | The result will be a mock where the value at the property 'name' will be equal to 'Birdy Bird' 157 | assert.equal(oneBird.name, 'Birdy Bird') 158 | 159 | When using 'many', the outcome will be an array of objects with the given mutations 160 | ``` 161 |

162 | 163 |
164 | 165 |
💡 Hint (using faker)

166 | 167 | Here is another example using `faker` and a callback: 168 | 169 | ```typescript 170 | const builder = MockFactory(Bird).mutate((faker) => ({ name: faker.name.firstName() })); 171 | const oneBird = builder.one(); 172 | ``` 173 |

174 | 175 |
176 | 177 | ### `.plain()` 178 | 179 | Sets the builder to return only plain objects (object literal), 180 | and not an instance of the class `Bird` 181 | 182 | ```typescript 183 | // Will return a plain object and NOT an instance of the class Bird 184 | const birdMock = MockFactory(Bird).plain().one(); 185 | ``` 186 | 187 |
💡 Hint

188 | 189 | ``` 190 | Calling .one() and .many() will return an actual instance of the class (Bird). 191 | When using .plain() you will get an object which is instance of Object 192 | ``` 193 | 194 | ``` 195 | Using .plain() with .many() will convery all the objects in the array 196 | into plain objects 197 | ``` 198 |

199 | 200 |
201 | 202 | ### `.setLocale(locale: string)` 203 | Sets the locale of the fake data (only apply when you use `faker`): 204 | 205 | ```typescript 206 | const builder = MockFactory(Bird).setLocale('es'); 207 | ``` 208 | 209 |
💡 Hint

210 | 211 | ``` 212 | The method is relevant only when using faker in the @Mock() decorator 213 | e.g. @Mock((faker) => faker.name.firstName()) 214 | ``` 215 | 216 | ```typescript 217 | export class Bird { 218 | @Mock((faker) => faker.random.name()) 219 | name: string; 220 | } 221 | 222 | const bird = MockFactory(Bird).setLocale('es').one(); 223 | ``` 224 | 225 | ``` 226 | bird.name will be translated into Spanish 227 | ``` 228 | 229 |

230 | 231 |
-------------------------------------------------------------------------------- /docs/recipes.md: -------------------------------------------------------------------------------- 1 | # Mockingbird Recipes 2 | 3 | ### Coming soon! -------------------------------------------------------------------------------- /jest.config.base.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | roots: ['/src'], 4 | testEnvironment: 'node', 5 | collectCoverage: false, 6 | coveragePathIgnorePatterns: [ 7 | '/dist/', 8 | '/node_modules/', 9 | '/index.js', 10 | ], 11 | coverageReporters: [ 12 | 'text', 13 | 'cobertura', 14 | ], 15 | coverageDirectory: '/coverage/', 16 | modulePathIgnorePatterns: ['./sample'], 17 | verbose: true, 18 | setupFiles: [ 19 | 'jest-gherkin', 20 | ], 21 | }; 22 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | const base = require('./jest.config.base'); 2 | 3 | module.exports = { 4 | ...base, 5 | roots: [''], 6 | projects: [ 7 | '/packages/mockingbird', 8 | '/packages/reflect', 9 | '/packages/parser', 10 | '/packages/logger', 11 | ], 12 | }; 13 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "independent", 3 | "command": { 4 | "publish": { 5 | "allowBranch": ["master", "release"], 6 | "message": "chore(packages): release packages [skip ci]", 7 | "conventionalCommits": true 8 | }, 9 | "version": { 10 | "allowBranch": ["master", "release"], 11 | "message": "chore(packages): version packages [skip ci]", 12 | "conventionalCommits": true 13 | } 14 | }, 15 | "useWorkspaces": true, 16 | "npmClient": "yarn", 17 | "packages": [ 18 | "packages/*" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mockingbird-monorepo", 3 | "private": true, 4 | "version": "0.0.0", 5 | "license": "MIT", 6 | "description": "Mockingbird Monorepo", 7 | "keywords": [ 8 | "faker", 9 | "faker-typescript", 10 | "typescript-faker", 11 | "typescript-mocks", 12 | "faker-unit-tests", 13 | "mockingbird-ts", 14 | "mockingbird", 15 | "unit-test", 16 | "unit-test-mocks", 17 | "testing-mocks", 18 | "testing" 19 | ], 20 | "contributors": [ 21 | { 22 | "name": "Omer Morad", 23 | "email": "omer.moradd@gmail.com" 24 | }, 25 | { 26 | "name": "Idan Ptichi", 27 | "email": "idanpt@gmail.com" 28 | } 29 | ], 30 | "repository": { 31 | "type": "git", 32 | "url": "https://github.com/omermorad/mockingbird.git" 33 | }, 34 | "bugs": { 35 | "url": "https://github.com/omermorad/mockingbird/issues" 36 | }, 37 | "readme": "https://github.com/omermorad/mockingbird/README.md", 38 | "scripts": { 39 | "prepare": "husky install", 40 | "build": "lerna run build --stream", 41 | "watch": "lerna exec -- watch", 42 | "test": "jest --runInBand && yarn test:sample", 43 | "test:sample": "export NODE_ENV=test && cd sample/mockingbird-typeorm && yarn test", 44 | "test:cov": "jest --coverage --runInBand --reporters=jest-junit", 45 | "lint": "lerna run lint --since HEAD" 46 | }, 47 | "files": [ 48 | "dist", 49 | "index.d.ts", 50 | "index.js", 51 | "README.md" 52 | ], 53 | "dependencies": { 54 | "@commitlint/cli": "^12.1.4", 55 | "@commitlint/config-conventional": "^12.1.4", 56 | "@commitlint/config-lerna-scopes": "^12.1.4", 57 | "@manypkg/cli": "^0.19.1", 58 | "@types/faker": "^5.5.7", 59 | "@types/jest": "26.0.24", 60 | "@types/node": "^12.20.15", 61 | "@typescript-eslint/eslint-plugin": "^4.28.2", 62 | "@typescript-eslint/parser": "^4.28.2", 63 | "commitizen": "^4.2.4", 64 | "conventional-changelog-cli": "^2.1.1", 65 | "cz-conventional-changelog": "^3.3.0", 66 | "eslint": "^7.30.0", 67 | "eslint-config-prettier": "^3.6.0", 68 | "eslint-import-resolver-typescript": "^2.0.0", 69 | "eslint-plugin-import": "^2.23.4", 70 | "eslint-plugin-jest": "^23.11.0", 71 | "eslint-plugin-prettier": "^3.1.3", 72 | "faker": "^5.5.3", 73 | "husky": "^7.0.1", 74 | "jest": "27.0.6", 75 | "jest-gherkin": "^0.0.0", 76 | "jest-junit": "12.2.0", 77 | "lerna": "^4.0.0", 78 | "lint-staged": "^11.0.0", 79 | "prettier": "^2.3.2", 80 | "rimraf": "^3.0.2", 81 | "ts-jest": "^27.0.3", 82 | "ts-loader": "^6.2.2", 83 | "ts-node": "8.10.2", 84 | "tsconfig-paths": "^3.9.0", 85 | "tslint": "^5.20.1", 86 | "tslint-config-airbnb": "^5.11.2", 87 | "typescript": "^3.9.7" 88 | }, 89 | "publishConfig": { 90 | "access": "public" 91 | }, 92 | "lint-staged": { 93 | "*.ts": [ 94 | "eslint --ext .ts --fix" 95 | ] 96 | }, 97 | "config": { 98 | "commitizen": { 99 | "path": "./node_modules/cz-conventional-changelog" 100 | } 101 | }, 102 | "workspaces": [ 103 | "packages/*" 104 | ] 105 | } 106 | -------------------------------------------------------------------------------- /packages/common/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../.eslintrc" 3 | } -------------------------------------------------------------------------------- /packages/common/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [2.0.3](https://github.com/omermorad/mockingbird/compare/@mockingbird/common@2.0.3-rc.3...@mockingbird/common@2.0.3) (2021-12-08) 7 | 8 | **Note:** Version bump only for package @mockingbird/common 9 | 10 | 11 | 12 | 13 | 14 | ## [2.0.3-rc.3](https://github.com/omermorad/mockingbird/compare/@mockingbird/common@2.0.3-rc.1...@mockingbird/common@2.0.3-rc.3) (2021-11-18) 15 | 16 | **Note:** Version bump only for package @mockingbird/common 17 | 18 | 19 | 20 | 21 | 22 | ## [2.0.3-rc.2](https://github.com/omermorad/mockingbird/compare/@mockingbird/common@2.0.3-rc.1...@mockingbird/common@2.0.3-rc.2) (2021-11-18) 23 | 24 | **Note:** Version bump only for package @mockingbird/common 25 | 26 | 27 | 28 | 29 | 30 | ## 2.0.3-rc.1 (2021-11-17) 31 | 32 | 33 | ### Features 34 | 35 | * **common:** add regex constructor to exact value ([10263fb](https://github.com/omermorad/mockingbird/commit/10263fb17287eb86516bd4778960586106011c2f)) 36 | 37 | 38 | 39 | ## 2.1.1 (2021-08-21) 40 | 41 | 42 | 43 | # 2.1.0 (2021-08-21) 44 | 45 | 46 | 47 | 48 | 49 | ## 2.0.3-rc.0 (2021-11-13) 50 | 51 | **Note:** Version bump only for package @mockingbird/common 52 | 53 | 54 | 55 | 56 | 57 | ## [2.0.2](https://github.com/omermorad/mockingbird/compare/@mockingbird/common@2.0.1...@mockingbird/common@2.0.2) (2021-08-21) 58 | 59 | **Note:** Version bump only for package @mockingbird/common 60 | 61 | 62 | 63 | 64 | 65 | ## 2.0.1 (2021-08-21) 66 | 67 | **Note:** Version bump only for package @mockingbird/common 68 | 69 | 70 | 71 | 72 | 73 | # 2.0.0 (2021-07-31) 74 | 75 | 76 | ### chore 77 | 78 | * **release:** release version v2.0.0 ([#53](https://github.com/omermorad/mockingbird/issues/53)) ([f598ef3](https://github.com/omermorad/mockingbird/commit/f598ef35d5b9111f66202f119b8961314483f4fb)), closes [#51](https://github.com/omermorad/mockingbird/issues/51) [#40](https://github.com/omermorad/mockingbird/issues/40) [#42](https://github.com/omermorad/mockingbird/issues/42) [#37](https://github.com/omermorad/mockingbird/issues/37) [#46](https://github.com/omermorad/mockingbird/issues/46) [#47](https://github.com/omermorad/mockingbird/issues/47) [#49](https://github.com/omermorad/mockingbird/issues/49) [#50](https://github.com/omermorad/mockingbird/issues/50) [#52](https://github.com/omermorad/mockingbird/issues/52) [#54](https://github.com/omermorad/mockingbird/issues/54) [#42](https://github.com/omermorad/mockingbird/issues/42) [#55](https://github.com/omermorad/mockingbird/issues/55) [#42](https://github.com/omermorad/mockingbird/issues/42) [#56](https://github.com/omermorad/mockingbird/issues/56) [#57](https://github.com/omermorad/mockingbird/issues/57) [#58](https://github.com/omermorad/mockingbird/issues/58) [#59](https://github.com/omermorad/mockingbird/issues/59) [#60](https://github.com/omermorad/mockingbird/issues/60) [#42](https://github.com/omermorad/mockingbird/issues/42) [#61](https://github.com/omermorad/mockingbird/issues/61) [#62](https://github.com/omermorad/mockingbird/issues/62) [#64](https://github.com/omermorad/mockingbird/issues/64) [#63](https://github.com/omermorad/mockingbird/issues/63) [#67](https://github.com/omermorad/mockingbird/issues/67) [#68](https://github.com/omermorad/mockingbird/issues/68) 79 | 80 | 81 | ### BREAKING CHANGES 82 | 83 | * **release:** MockFactory is now an instance (TClass) and not ClassLiteral 84 | 85 | * chore: fix typo in the test name 86 | 87 | * chore: change methods order 88 | 89 | * chore: added source map and some jest configs 90 | 91 | * refactor: change some var names and error 92 | 93 | * test(class-processor): refactor test turning into integration instead of unit 94 | 95 | * chore(lib): move files into lib folder and change imports 96 | 97 | * feat(fluent-api): add fluent api (builder) functionality and persistence 98 | 99 | Add fluent API to enable methods chaining with ability to persist the mock 100 | * **release:** MockFactory is now a function and not a class, changed the original to 101 | MockGenerator. Add fluent API and ability to persist mock data 102 | * **release:** MockFactory changed to be MockGenerator 103 | * **release:** MockFactory changed to be MockGenerator 104 | * **release:** MockGenerator is not exported anymore, use MockFactory instead 105 | 106 | 107 | 108 | 109 | 110 | # [2.0.0-alpha.2](https://github.com/omermorad/mockingbird/compare/@mockingbird/types@2.0.0-alpha.1...@mockingbird/types@2.0.0-alpha.2) (2021-07-23) 111 | 112 | 113 | ### Bug Fixes 114 | 115 | * **types:** change the values inside 'files' array in package.json ([a858cb4](https://github.com/omermorad/mockingbird/commit/a858cb47ef8e80d87686724d4125bd213a77ecad)) 116 | 117 | 118 | 119 | 120 | 121 | # 2.0.0-alpha.1 (2021-07-23) 122 | 123 | 124 | ### Bug Fixes 125 | 126 | * **types:** add build to export a js file to include the faker instance (for runtime) ([#61](https://github.com/omermorad/mockingbird/issues/61)) ([f4e3092](https://github.com/omermorad/mockingbird/commit/f4e3092e683eb9c288d4e879113e71f74ec5038a)) 127 | 128 | 129 | ### Features 130 | 131 | * **mockingbird:** add mock factory fluent/builder api ([#60](https://github.com/omermorad/mockingbird/issues/60)) ([cc5710d](https://github.com/omermorad/mockingbird/commit/cc5710ded33401cae25782bb8e87efe1355024aa)), closes [#42](https://github.com/omermorad/mockingbird/issues/42) 132 | 133 | 134 | ### Reverts 135 | 136 | * **repo:** release packages ([7f9390d](https://github.com/omermorad/mockingbird/commit/7f9390d051f9c9c9c3eb172f4db8a9fe533b03c4)) 137 | 138 | 139 | ### BREAKING CHANGES 140 | 141 | * **mockingbird:** MockGenerator is not exported anymore, use MockFactory instead 142 | 143 | 144 | 145 | 146 | 147 | # Change Log 148 | # [2.0.0-alpha.0](https://github.com/omermorad/mockingbird/compare/@mockingbird/types@2.0.0...@mockingbird/types@2.0.0-alpha.0) (2021-07-22) 149 | 150 | ### Features 151 | 152 | * **mockingbird:** add mock factory fluent/builder api ([#60](https://github.com/omermorad/mockingbird/issues/60)) ([cc5710d](https://github.com/omermorad/mockingbird/commit/cc5710ded33401cae25782bb8e87efe1355024aa)), closes [#42](https://github.com/omermorad/mockingbird/issues/42) 153 | 154 | 155 | ### Reverts 156 | 157 | * **repo:** release packages ([7f9390d](https://github.com/omermorad/mockingbird/commit/7f9390d051f9c9c9c3eb172f4db8a9fe533b03c4)) 158 | 159 | 160 | ### BREAKING CHANGES 161 | 162 | * **mockingbird:** MockGenerator is not exported anymore, use MockFactory instead 163 | -------------------------------------------------------------------------------- /packages/common/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omermorad/mockingbird/421428336b06b0353dcb9a53c7f0c344bd03c95a/packages/common/README.md -------------------------------------------------------------------------------- /packages/common/index.ts: -------------------------------------------------------------------------------- 1 | export * from './src'; 2 | -------------------------------------------------------------------------------- /packages/common/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | moduleFileExtensions: ['js', 'json', 'ts'], 3 | rootDir: '.', 4 | testRegex: '.test.ts$', 5 | transform: { 6 | '^.+\\.ts$': 'ts-jest', 7 | }, 8 | testEnvironment: 'node', 9 | }; 10 | -------------------------------------------------------------------------------- /packages/common/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mockingbird/common", 3 | "version": "2.0.3", 4 | "license": "MIT", 5 | "description": "Mockingbird Common Package", 6 | "main": "dist/index.js", 7 | "types": "dist/index.d.ts", 8 | "contributors": [ 9 | { 10 | "name": "Omer Morad", 11 | "email": "omer.moradd@gmail.com" 12 | }, 13 | { 14 | "name": "Idan Ptichi", 15 | "email": "idanpt@gmail.com" 16 | } 17 | ], 18 | "repository": { 19 | "type": "git", 20 | "url": "https://github.com/omermorad/mockingbird.git" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/omermorad/mockingbird/issues" 24 | }, 25 | "readme": "https://github.com/omermorad/mockingbird/tree/refactor/master/packages/common/README.md", 26 | "scripts": { 27 | "prebuild": "npx rimraf dist", 28 | "build": "tsc", 29 | "watch": "tsc --watch", 30 | "test": "exit 0;", 31 | "lint": "eslint 'src/index.ts'", 32 | "lint:fix": "eslint 'src/index.ts' --fix" 33 | }, 34 | "files": [ 35 | "dist", 36 | "README.md", 37 | "CHANGELOG.md" 38 | ], 39 | "dependencies": { 40 | "@types/faker": "^5.5.7", 41 | "faker": "^5.5.3" 42 | }, 43 | "devDependencies": { 44 | "ts-loader": "^6.2.2", 45 | "ts-node": "8.10.2", 46 | "tsconfig-paths": "^3.9.0", 47 | "typescript": "^3.9.7" 48 | }, 49 | "publishConfig": { 50 | "access": "public" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /packages/common/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types'; 2 | export * from './is-primitive'; 3 | -------------------------------------------------------------------------------- /packages/common/src/is-primitive.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Checks if a given constructor name is a primitive one 3 | * 4 | * @param constructorName 5 | * @returns {boolean} 6 | */ 7 | export function isPrimitive(constructorName: string): boolean { 8 | return ['String', 'Boolean', 'Number', 'Date'].includes(constructorName); 9 | } 10 | -------------------------------------------------------------------------------- /packages/common/src/types.ts: -------------------------------------------------------------------------------- 1 | import faker from 'faker'; 2 | import FakerStatic = Faker.FakerStatic; 3 | 4 | export type Faker = FakerStatic; 5 | export const Faker = faker; 6 | 7 | export interface ObjectLiteral { 8 | [key: string]: any; 9 | } 10 | export type Class = new (...args: any[]) => T; 11 | 12 | export type ExactValue = string | number | boolean | ObjectLiteral | Date | RegExp; 13 | 14 | export type MultiClass = { type: Class; count: number }; 15 | 16 | export type EnumObject = { enum: Record }; 17 | 18 | export type Callback = (faker: Faker) => any; 19 | 20 | export type ClassLiteral = { [K in keyof TClass]: TClass[K] }; 21 | 22 | export type OptionalClassValues = Partial>; 23 | -------------------------------------------------------------------------------- /packages/common/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "rootDir": "./src", 6 | "outDir": "./dist", 7 | "target": "es5" 8 | }, 9 | "exclude": [ 10 | "index.ts", 11 | "node_modules", 12 | "test", 13 | "src/**/*.test.ts" 14 | ], 15 | "include": ["src/"] 16 | } -------------------------------------------------------------------------------- /packages/logger/.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | jest.config.js -------------------------------------------------------------------------------- /packages/logger/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../.eslintrc" 3 | } -------------------------------------------------------------------------------- /packages/logger/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [0.0.1](https://github.com/omermorad/mockingbird/compare/@mockingbird/logger@0.0.1-rc.1...@mockingbird/logger@0.0.1) (2021-12-08) 7 | 8 | **Note:** Version bump only for package @mockingbird/logger 9 | 10 | 11 | 12 | 13 | 14 | ## 0.0.1-rc.1 (2021-11-17) 15 | 16 | 17 | ### Features 18 | 19 | * **logger:** add initial working module ([#104](https://github.com/omermorad/mockingbird/issues/104)) ([6b6e69d](https://github.com/omermorad/mockingbird/commit/6b6e69d9169268d6d2468b4871dbefcc158d0539)) 20 | 21 | 22 | 23 | 24 | 25 | ## 0.0.1-rc.0 (2021-11-13) 26 | 27 | **Note:** Version bump only for package @mockingbird/logger 28 | -------------------------------------------------------------------------------- /packages/logger/index.ts: -------------------------------------------------------------------------------- 1 | export * from './src'; 2 | -------------------------------------------------------------------------------- /packages/logger/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mockingbird/logger", 3 | "version": "0.0.1", 4 | "license": "MIT", 5 | "description": "Mockingbird Logger Package", 6 | "main": "dist/index.js", 7 | "types": "dist/index.d.ts", 8 | "contributors": [ 9 | { 10 | "name": "Omer Morad", 11 | "email": "omer.moradd@gmail.com" 12 | } 13 | ], 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/omermorad/mockingbird.git" 17 | }, 18 | "bugs": { 19 | "url": "https://github.com/omermorad/mockingbird/issues" 20 | }, 21 | "readme": "https://github.com/omermorad/mockingbird/tree/refactor/master/packages/logger/README.md", 22 | "scripts": { 23 | "prebuild": "yarn rimraf dist", 24 | "build": "tsc", 25 | "watch": "tsc --watch", 26 | "lint": "eslint '{src,test}/**/*.ts'", 27 | "lint:fix": "eslint '{src,test}/**/*.ts' --fix" 28 | }, 29 | "files": [ 30 | "dist", 31 | "README.md", 32 | "CHANGELOG.md" 33 | ], 34 | "dependencies": { 35 | "@types/chalk": "^2.2.0", 36 | "chalk": "^4.1.2" 37 | }, 38 | "devDependencies": { 39 | "ts-node": "8.10.2", 40 | "tsconfig-paths": "^3.9.0", 41 | "typescript": "^3.9.7" 42 | }, 43 | "publishConfig": { 44 | "access": "public" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/logger/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './logger'; 2 | -------------------------------------------------------------------------------- /packages/logger/src/logger.ts: -------------------------------------------------------------------------------- 1 | import chalk from 'chalk'; 2 | import util from 'util'; 3 | 4 | const prefix = '\u{1F426} '; 5 | 6 | function format(args: Array, customPrefix?: string) { 7 | const fullPrefix = prefix + (customPrefix === undefined ? '' : ' ' + customPrefix); 8 | return ( 9 | fullPrefix + 10 | util 11 | .format('', ...args) 12 | .split('\n') 13 | .join('\n' + fullPrefix + ' ') 14 | ); 15 | } 16 | 17 | export interface MockingbirdLogger { 18 | info(message: string, ...args: any[]): void; 19 | error(message: string, ...args: any[]): void; 20 | warn(message: string, ...args: any[]): void; 21 | log(message: string, ...args: any[]): void; 22 | success(message: string, ...args: any[]): void; 23 | } 24 | 25 | export const Logger: MockingbirdLogger = { 26 | info: (...args: any[]): void => { 27 | console.info(format(args, chalk.cyan('info'))); 28 | }, 29 | log: (...args: any[]): void => { 30 | console.log(format(args)); 31 | }, 32 | error: (...args: any[]): void => { 33 | console.error(format(args, chalk.red('error'))); 34 | }, 35 | success: (...args: any[]): void => { 36 | console.log(format(args, chalk.green('success'))); 37 | }, 38 | warn: (...args: any[]): void => { 39 | console.warn(format(args, chalk.yellow('warn'))); 40 | }, 41 | }; 42 | -------------------------------------------------------------------------------- /packages/logger/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./dist", 6 | "target": "es6" 7 | }, 8 | "exclude": [ 9 | "node_modules", 10 | "test", 11 | "src/**/*.test.ts", 12 | "index.ts" 13 | ], 14 | "include": ["src/"] 15 | } -------------------------------------------------------------------------------- /packages/mockingbird/.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | jest.config.js -------------------------------------------------------------------------------- /packages/mockingbird/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../.eslintrc" 3 | } -------------------------------------------------------------------------------- /packages/mockingbird/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [2.1.2](https://github.com/omermorad/mockingbird/compare/mockingbird@2.1.2-rc.4...mockingbird@2.1.2) (2021-12-08) 7 | 8 | **Note:** Version bump only for package mockingbird 9 | 10 | 11 | 12 | 13 | 14 | ## [2.1.2-rc.4](https://github.com/omermorad/mockingbird/compare/mockingbird@2.1.2-rc.2...mockingbird@2.1.2-rc.4) (2021-11-18) 15 | 16 | **Note:** Version bump only for package mockingbird 17 | 18 | 19 | 20 | 21 | 22 | ## [2.1.2-rc.3](https://github.com/omermorad/mockingbird/compare/mockingbird@2.1.2-rc.2...mockingbird@2.1.2-rc.3) (2021-11-18) 23 | 24 | **Note:** Version bump only for package mockingbird 25 | 26 | 27 | 28 | 29 | 30 | ## 2.1.2-rc.2 (2021-11-17) 31 | 32 | 33 | ### Code Refactoring 34 | 35 | * **parser:** add mock generator and remove analyzer ([#107](https://github.com/omermorad/mockingbird/issues/107)) ([32c0ff6](https://github.com/omermorad/mockingbird/commit/32c0ff62895a18d9e892e1280572aea3ad500491)) 36 | 37 | 38 | ### BREAKING CHANGES 39 | 40 | * **parser:** ClassAnalayzer has been removed and all the logic has been moved to ClassParser 41 | 42 | * test(parser): add (move) mock generator integration test 43 | 44 | * chore(parser): config jest and typescript to run integration test 45 | 46 | * fix(mockingbird): use mock generator differently (singleton) 47 | 48 | Remove mock generator from mockingbird and import it from @mockinbird/parser instead 49 | mock generator acts as a singleton now 50 | 51 | * refactor(mockingbird): fix mock factory 52 | 53 | * chore(mockingbird): config jest to collect coverage properly 54 | 55 | 56 | 57 | ## 2.1.1 (2021-08-21) 58 | 59 | 60 | ### Bug Fixes 61 | 62 | * fix broken packages because of 'types' (instead common) ([#94](https://github.com/omermorad/mockingbird/issues/94)) ([fca274a](https://github.com/omermorad/mockingbird/commit/fca274aca495251b9b74a51f99f4e15c6fae5a4c)) 63 | 64 | 65 | 66 | # 2.1.0 (2021-08-21) 67 | 68 | 69 | ### Bug Fixes 70 | 71 | * **mockingbird:** add some missing documentation to mock builder and factory ([#85](https://github.com/omermorad/mockingbird/issues/85)) ([45caa62](https://github.com/omermorad/mockingbird/commit/45caa62283c2fa43c36c0ad77d59629722610edf)) 72 | * **mockingbird:** change ignore term to omit (deprecation) ([#86](https://github.com/omermorad/mockingbird/issues/86)) ([f3b3ab9](https://github.com/omermorad/mockingbird/commit/f3b3ab9c53baa3c9a114775f64961ddfa59124e6)) 73 | * **mockingbird:** change types package into common ([a857a66](https://github.com/omermorad/mockingbird/commit/a857a66cd72e539c5fd3b183bd324d0ab10042a2)) 74 | * **mockingbird:** fix plain functionality to work with primitives ([4fb5dcc](https://github.com/omermorad/mockingbird/commit/4fb5dccf9ba37363f201cf4525cd796269b5d004)) 75 | 76 | 77 | ### Features 78 | 79 | * **mockingbird:** add pick funtionality to mock builder ([9b955f3](https://github.com/omermorad/mockingbird/commit/9b955f3b2327ba0d9eab7bbf17fad304dd00ed05)) 80 | 81 | 82 | ### Reverts 83 | 84 | * Revert "chore(packages): version packages [skip ci]" ([5cbc7d6](https://github.com/omermorad/mockingbird/commit/5cbc7d67c5a62343c65fb1401e73df505cbadf52)) 85 | 86 | 87 | 88 | 89 | 90 | ## 2.1.2-rc.0 (2021-11-13) 91 | 92 | **Note:** Version bump only for package mockingbird 93 | 94 | 95 | 96 | 97 | 98 | ## [2.1.1](https://github.com/omermorad/mockingbird/compare/mockingbird@2.1.0...mockingbird@2.1.1) (2021-08-21) 99 | 100 | 101 | ### Bug Fixes 102 | 103 | * fix broken packages because of 'types' (instead common) ([#94](https://github.com/omermorad/mockingbird/issues/94)) ([fca274a](https://github.com/omermorad/mockingbird/commit/fca274aca495251b9b74a51f99f4e15c6fae5a4c)) 104 | 105 | 106 | 107 | 108 | 109 | # 2.1.0 (2021-08-21) 110 | 111 | 112 | ### Bug Fixes 113 | 114 | * **mockingbird:** add some missing documentation to mock builder and factory ([#85](https://github.com/omermorad/mockingbird/issues/85)) ([45caa62](https://github.com/omermorad/mockingbird/commit/45caa62283c2fa43c36c0ad77d59629722610edf)) 115 | * **mockingbird:** change ignore term to omit (deprecation) ([#86](https://github.com/omermorad/mockingbird/issues/86)) ([f3b3ab9](https://github.com/omermorad/mockingbird/commit/f3b3ab9c53baa3c9a114775f64961ddfa59124e6)) 116 | * **mockingbird:** change types package into common ([a857a66](https://github.com/omermorad/mockingbird/commit/a857a66cd72e539c5fd3b183bd324d0ab10042a2)) 117 | * **mockingbird:** fix plain functionality to work with primitives ([4fb5dcc](https://github.com/omermorad/mockingbird/commit/4fb5dccf9ba37363f201cf4525cd796269b5d004)) 118 | 119 | 120 | ### Features 121 | 122 | * **mockingbird:** add pick funtionality to mock builder ([9b955f3](https://github.com/omermorad/mockingbird/commit/9b955f3b2327ba0d9eab7bbf17fad304dd00ed05)) 123 | 124 | 125 | ### Reverts 126 | 127 | * Revert "chore(packages): version packages [skip ci]" ([5cbc7d6](https://github.com/omermorad/mockingbird/commit/5cbc7d67c5a62343c65fb1401e73df505cbadf52)) 128 | 129 | 130 | 131 | 132 | 133 | # 2.0.0 (2021-07-31) 134 | 135 | 136 | ### chore 137 | 138 | * **release:** release version v2.0.0 ([#53](https://github.com/omermorad/mockingbird/issues/53)) ([f598ef3](https://github.com/omermorad/mockingbird/commit/f598ef35d5b9111f66202f119b8961314483f4fb)), closes [#51](https://github.com/omermorad/mockingbird/issues/51) [#40](https://github.com/omermorad/mockingbird/issues/40) [#42](https://github.com/omermorad/mockingbird/issues/42) [#37](https://github.com/omermorad/mockingbird/issues/37) [#46](https://github.com/omermorad/mockingbird/issues/46) [#47](https://github.com/omermorad/mockingbird/issues/47) [#49](https://github.com/omermorad/mockingbird/issues/49) [#50](https://github.com/omermorad/mockingbird/issues/50) [#52](https://github.com/omermorad/mockingbird/issues/52) [#54](https://github.com/omermorad/mockingbird/issues/54) [#42](https://github.com/omermorad/mockingbird/issues/42) [#55](https://github.com/omermorad/mockingbird/issues/55) [#42](https://github.com/omermorad/mockingbird/issues/42) [#56](https://github.com/omermorad/mockingbird/issues/56) [#57](https://github.com/omermorad/mockingbird/issues/57) [#58](https://github.com/omermorad/mockingbird/issues/58) [#59](https://github.com/omermorad/mockingbird/issues/59) [#60](https://github.com/omermorad/mockingbird/issues/60) [#42](https://github.com/omermorad/mockingbird/issues/42) [#61](https://github.com/omermorad/mockingbird/issues/61) [#62](https://github.com/omermorad/mockingbird/issues/62) [#64](https://github.com/omermorad/mockingbird/issues/64) [#63](https://github.com/omermorad/mockingbird/issues/63) [#67](https://github.com/omermorad/mockingbird/issues/67) [#68](https://github.com/omermorad/mockingbird/issues/68) 139 | 140 | 141 | ### BREAKING CHANGES 142 | 143 | * **release:** MockFactory is now an instance (TClass) and not ClassLiteral 144 | 145 | * chore: fix typo in the test name 146 | 147 | * chore: change methods order 148 | 149 | * chore: added source map and some jest configs 150 | 151 | * refactor: change some var names and error 152 | 153 | * test(class-processor): refactor test turning into integration instead of unit 154 | 155 | * chore(lib): move files into lib folder and change imports 156 | 157 | * feat(fluent-api): add fluent api (builder) functionality and persistence 158 | 159 | Add fluent API to enable methods chaining with ability to persist the mock 160 | * **release:** MockFactory is now a function and not a class, changed the original to 161 | MockGenerator. Add fluent API and ability to persist mock data 162 | * **release:** MockFactory changed to be MockGenerator 163 | * **release:** MockFactory changed to be MockGenerator 164 | * **release:** MockGenerator is not exported anymore, use MockFactory instead 165 | 166 | 167 | 168 | 169 | 170 | # [2.0.0-alpha.2](https://github.com/omermorad/mockingbird/compare/mockingbird@2.0.0-alpha.1...mockingbird@2.0.0-alpha.2) (2021-07-23) 171 | 172 | **Note:** Version bump only for package mockingbird 173 | 174 | 175 | 176 | 177 | 178 | # [2.0.0-alpha.1](https://github.com/omermorad/mockingbird/compare/mockingbird@2.0.0...mockingbird@2.0.0-alpha.1) (2021-07-23) 179 | 180 | 181 | ### Bug Fixes 182 | 183 | * **types:** add build to export a js file to include the faker instance (for runtime) ([#61](https://github.com/omermorad/mockingbird/issues/61)) ([f4e3092](https://github.com/omermorad/mockingbird/commit/f4e3092e683eb9c288d4e879113e71f74ec5038a)) 184 | 185 | 186 | ### Features 187 | 188 | * **mockingbird:** add mock factory fluent/builder api ([#60](https://github.com/omermorad/mockingbird/issues/60)) ([cc5710d](https://github.com/omermorad/mockingbird/commit/cc5710ded33401cae25782bb8e87efe1355024aa)), closes [#42](https://github.com/omermorad/mockingbird/issues/42) 189 | 190 | 191 | ### Reverts 192 | 193 | * **repo:** release packages ([7f9390d](https://github.com/omermorad/mockingbird/commit/7f9390d051f9c9c9c3eb172f4db8a9fe533b03c4)) 194 | 195 | 196 | ### BREAKING CHANGES 197 | 198 | * **mockingbird:** MockGenerator is not exported anymore, use MockFactory instead 199 | 200 | 201 | 202 | 203 | 204 | # Change Log 205 | 206 | # [2.0.0-alpha.0](https://github.com/omermorad/mockingbird/compare/mockingbird@2.0.0...mockingbird@2.0.0-alpha.0) (2021-07-22) 207 | 208 | 209 | ### Features 210 | 211 | * **mockingbird:** add mock factory fluent/builder api ([#60](https://github.com/omermorad/mockingbird/issues/60)) ([cc5710d](https://github.com/omermorad/mockingbird/commit/cc5710ded33401cae25782bb8e87efe1355024aa)), closes [#42](https://github.com/omermorad/mockingbird/issues/42) 212 | 213 | ### BREAKING CHANGES 214 | 215 | * **mockingbird:** `MockFactory` is no longer a class, but a function returning a builder API 216 | 217 | 218 | # [1.1.0](https://github.com/omermorad/mockingbird/compare/v1.0.0...v1.1.0) (2021-07-08) 219 | 220 | 221 | ### Features 222 | 223 | * add new types and sample ([acc1776](https://github.com/omermorad/mockingbird/commit/acc1776b50360fe745983b266b7e9a5da1ee9f4f)) 224 | * add typeorm sample, change types ([f801a59](https://github.com/omermorad/mockingbird/commit/f801a59e0811e92f72a9c28069a809bfb9624564)) 225 | 226 | # [1.1.0-next.1](https://github.com/omermorad/mockingbird/compare/v1.0.0...v1.1.0-next.1) (2021-02-10) 227 | 228 | 229 | ### Features 230 | 231 | * add new types and sample ([acc1776](https://github.com/omermorad/mockingbird/commit/acc1776b50360fe745983b266b7e9a5da1ee9f4f)) 232 | 233 | # 1.0.0 (2021-02-09) 234 | 235 | 236 | ### Bug Fixes 237 | 238 | * **signatures:** remove redundant signature for Date type overload ([e4fbbc1](https://github.com/omermorad/mockingbird/commit/e4fbbc18eb710bc181ef7a2d98490132cf4771df)) 239 | 240 | 241 | ### Code Refactoring 242 | 243 | * **types:** add some new types to be more accurate ([d4eba88](https://github.com/omermorad/mockingbird/commit/d4eba8866b000f3507d3f1a2cf8881d3040972fc)) 244 | 245 | 246 | ### Continuous Integration 247 | 248 | * **release:** add beta as pre-release branch ([aed0c09](https://github.com/omermorad/mockingbird/commit/aed0c0906f22096f7ecabe9b75aee04d410e5cef)) 249 | 250 | 251 | ### Features 252 | 253 | * **release:** release new beta version ([bda5aa7](https://github.com/omermorad/mockingbird/commit/bda5aa74b957220e90605881556dacffc538a130)) 254 | * alpha release ([#12](https://github.com/omermorad/mockingbird/issues/12)) ([5682bb4](https://github.com/omermorad/mockingbird/commit/5682bb4c21df4d546166c613f8ed7fff937dc3dc)) 255 | * faker.ts initial ([#6](https://github.com/omermorad/mockingbird/issues/6)) ([714fc05](https://github.com/omermorad/mockingbird/commit/714fc05d1fdd93e1a709ebe183776dd28d0681bf)), closes [#4](https://github.com/omermorad/mockingbird/issues/4) [#7](https://github.com/omermorad/mockingbird/issues/7) [#8](https://github.com/omermorad/mockingbird/issues/8) 256 | 257 | 258 | ### BREAKING CHANGES 259 | 260 | * **types:** New MockedClass type 261 | * **release:** Add 'tslib' as dependency 262 | 263 | # 1.0.0-rc.1 (2021-02-05) 264 | 265 | 266 | ### Bug Fixes 267 | 268 | * **signatures:** remove redundant signature for Date type overload ([e4fbbc1](https://github.com/omermorad/mockingbird/commit/e4fbbc18eb710bc181ef7a2d98490132cf4771df)) 269 | 270 | 271 | ### Continuous Integration 272 | 273 | * **release:** add beta as pre-release branch ([aed0c09](https://github.com/omermorad/mockingbird/commit/aed0c0906f22096f7ecabe9b75aee04d410e5cef)) 274 | 275 | 276 | ### Features 277 | 278 | * **release:** release new beta version ([bda5aa7](https://github.com/omermorad/mockingbird/commit/bda5aa74b957220e90605881556dacffc538a130)) 279 | * alpha release ([#12](https://github.com/omermorad/mockingbird/issues/12)) ([5682bb4](https://github.com/omermorad/mockingbird/commit/5682bb4c21df4d546166c613f8ed7fff937dc3dc)) 280 | * faker.ts initial ([#6](https://github.com/omermorad/mockingbird/issues/6)) ([714fc05](https://github.com/omermorad/mockingbird/commit/714fc05d1fdd93e1a709ebe183776dd28d0681bf)), closes [#4](https://github.com/omermorad/mockingbird/issues/4) [#7](https://github.com/omermorad/mockingbird/issues/7) [#8](https://github.com/omermorad/mockingbird/issues/8) 281 | 282 | 283 | ### BREAKING CHANGES 284 | 285 | * **release:** Add 'tslib' as dependency 286 | 287 | # 1.0.0-alpha.1 (2021-01-28) 288 | 289 | ### Features 290 | 291 | * Mockingbird alpha release ([#11](https://github.com/omermorad/mockingbird/issues/11)) ([67511b7](https://github.com/omermorad/faker.ts/commit/67511b7bc7792e06ac54c752b0ac96ee5337fd35)), closes [#4](https://github.com/omermorad/faker.ts/issues/4) [#7](https://github.com/omermorad/faker.ts/issues/7) [#8](https://github.com/omermorad/faker.ts/issues/8) 292 | -------------------------------------------------------------------------------- /packages/mockingbird/README.md: -------------------------------------------------------------------------------- 1 | [![ISC license](http://img.shields.io/badge/license-MIT-brightgreen.svg)](http://opensource.org/licenses/MIT) 2 | [![npm version](http://img.shields.io/npm/v/mockingbird.svg?style=flat)](https://npmjs.org/package/mockingbird "View this project on npm") 3 | [![Codecov Coverage](https://img.shields.io/codecov/c/github/omermorad/mockingbird/master.svg?style=flat-square)](https://codecov.io/gh/omermorad/mockingbird) 4 | [![lerna](https://img.shields.io/badge/maintained%20with-lerna-cc00ff.svg)](https://lerna.js.org/) 5 | [![ci](https://github.com/omermorad/mockingbird/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/omermorad/mockingbird/actions) 6 | 7 |

8 | Mockingbird Logo 9 | 10 |

Mockingbird

11 | 12 |

13 | Simple Yet Powerful TypeScript Mocking Library 14 |

15 | 16 |

17 | Manage and create your test mocks easily, and focus on your tests logic instead 18 |

19 |

20 | 21 | ## Installation 22 | 23 | ```bash 24 | npm i -D mockingbird 25 | ``` 26 | 27 | ```bash 28 | yarn add -D mockingbird 29 | ``` 30 | 31 | ## What is "Mocking Library"? 32 | A lot of times you find yourself “preparing” some dummy data for your tests that 33 | has to make sense for a specific test case(s) and is manipulated often. 34 | Some developers are preparing JSON files, others create a long verbose object in 35 | the test file itself, but the outcome always contains some fake data inside 36 | (or even a snapshot from an external API). 37 | 38 | This is what Mockingbird aims to solve! 39 | It suggests two ways of creating mocks for your entities/models classes, thus, 40 | creating one uniform way to manage mocks (whether you are working alone or with your team), 41 | your dev experience will improve, and you won’t have to deal with this messy setup at all! 42 | 43 | ## Features 44 | - Prepare as many unique mocks/fixtures as you need for your tests 45 | - Generate dummy (but reasonable) data for database seeding 46 | - Manage your mocks from one place, forget about the messy work 47 | - Full TypeScript compatibility 48 | - Convenient and simple API 49 | 50 | ## Usage 51 | 52 | **Here is the simplest usage of Mockingbird:** 53 | 54 | ```typescript 55 | // Could be interface as well 56 | class BirdEntity { 57 | name: string; 58 | birthday: Date; 59 | goodPoints: number; 60 | } 61 | ``` 62 | 63 | ```typescript 64 | import { Mock, MockFactory } from 'mockingbird'; 65 | 66 | // BirdEntity could be an interface or a class 67 | class BirdEntityMock implements BirdEntity { 68 | @Mock(faker => faker.name.firstName()) 69 | name!: string; 70 | 71 | @Mock() 72 | birthday!: Date; // Will generate a recent date 73 | 74 | @Mock() 75 | goodPoints!: number; // Will generate a random number 76 | } 77 | 78 | const oneBird = MockFactory(BirdEntityMock).one(); 79 | const lotsOfBirds = MockFactory(BirdEntityMock).many(3); 80 | ``` 81 | 82 | ## Documentation 83 | **[Jump to the full documentation and explore the full API](https://github.com/omermorad/faker.ts/blob/master/docs/README.md)** 84 | 85 | **There's also an example, [you can find it under the sample folder](https://github.com/omermorad/mockingbird/tree/master/sample)** 86 | 87 | ## Playground 88 | 89 | **Jump to the [REPL Playground](https://repl.it/@omermorad/Mockingbird-Playground) where you can see Mockingbird in action!** 90 | 91 | ## Motivation 92 | 93 | Creating mocks for your tests (sometimes called "fixtures") can be a tedious and 94 | cumbersome process usually done manually. 95 | 96 | We came up with a simple yet super convenient solution: all you have to do to get mocks out of the 97 | box is to decorate your classes (whether it's an entity, or a model representing the database layer) 98 | and generate simple or complex mocks. 99 | 100 | Mockingbird offers two different ways for preparing mocks; The first one (as we call it), is the TypeScript 101 | way which requires decorating existing (or duplicate) classes. 102 | The second way is to use Mockingbird's functionality directly 103 | 104 | 105 | ### What is `faker.js`? 106 | 107 | `faker.js` it's a library which is used to "generate massive amounts of fake data in the browser and Node". 108 | 109 | Mockingbird uses `faker.js` under the hood, making it possible to enjoy its rich database, and thereby allows 110 | to create mocks that are meaningful like email, first name, address and many more. 111 | 112 | ## License 113 | 114 | Distributed under the MIT License. See `LICENSE` for more information. 115 | 116 | ## Acknowledgements 117 | 118 | [faker.js](https://github.com/marak/Faker.js) 119 | -------------------------------------------------------------------------------- /packages/mockingbird/index.ts: -------------------------------------------------------------------------------- 1 | export * from './src'; 2 | -------------------------------------------------------------------------------- /packages/mockingbird/jest.config.js: -------------------------------------------------------------------------------- 1 | const base = require('../../jest.config.base'); 2 | const packageJson = require('./package'); 3 | 4 | module.exports = { 5 | ...base, 6 | roots: [...base.roots, '/test'], 7 | name: packageJson.name, 8 | displayName: packageJson.name, 9 | collectCoverageFrom: ['src/**/*.ts', 'test/**/*.ts'], 10 | coveragePathIgnorePatterns: ['index.ts', 'test-classes.ts'], 11 | }; -------------------------------------------------------------------------------- /packages/mockingbird/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mockingbird", 3 | "version": "2.1.2", 4 | "license": "MIT", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "description": "Super Simple, Yet Powerful, TypeScript Library for Creating Mocks. Mockingbird allows you to create class mocks like a breeze with a simple yet powerful @Mock decorator", 8 | "keywords": [ 9 | "faker", 10 | "faker-typescript", 11 | "typescript-faker", 12 | "typescript-mocks", 13 | "faker-unit-tests", 14 | "mockingbird-ts", 15 | "mockingbird", 16 | "unit-test", 17 | "unit-test-mocks", 18 | "testing-mocks", 19 | "testing" 20 | ], 21 | "contributors": [ 22 | { 23 | "name": "Omer Morad", 24 | "email": "omer.moradd@gmail.com" 25 | }, 26 | { 27 | "name": "Idan Ptichi", 28 | "email": "idanpt@gmail.com" 29 | } 30 | ], 31 | "repository": { 32 | "type": "git", 33 | "url": "https://github.com/omermorad/mockingbird.git" 34 | }, 35 | "bugs": { 36 | "url": "https://github.com/omermorad/mockingbird/issues" 37 | }, 38 | "readme": "https://github.com/omermorad/mockingbird/README.md", 39 | "scripts": { 40 | "prebuild": "npx rimraf dist", 41 | "build": "tsc", 42 | "watch": "tsc --watch", 43 | "test": "jest --runInBand --verbose", 44 | "lint": "eslint '{src,test}/**/*.ts'", 45 | "lint:fix": "eslint '{src,test}/**/*.ts' --fix" 46 | }, 47 | "files": [ 48 | "dist", 49 | "CHANGELOG.md", 50 | "README.md" 51 | ], 52 | "dependencies": { 53 | "@mockingbird/common": "^2.0.3", 54 | "@mockingbird/parser": "^3.0.2", 55 | "@mockingbird/reflect": "^3.0.2" 56 | }, 57 | "devDependencies": { 58 | "jest": "27.0.6", 59 | "rimraf": "^3.0.2", 60 | "ts-jest": "^27.0.3", 61 | "ts-loader": "^6.2.2", 62 | "ts-node": "8.10.2", 63 | "tsconfig-paths": "^3.9.0", 64 | "typescript": "^3.9.7" 65 | }, 66 | "publishConfig": { 67 | "access": "public" 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /packages/mockingbird/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from '@mockingbird/parser'; 2 | export * from '@mockingbird/common'; 3 | 4 | export { Mock, MockOptions } from '@mockingbird/reflect'; 5 | 6 | export * from './lib'; 7 | export * from './types/mock-generator-options.interface'; 8 | -------------------------------------------------------------------------------- /packages/mockingbird/src/lib/builder/index.ts: -------------------------------------------------------------------------------- 1 | export * from './mock-builder'; 2 | -------------------------------------------------------------------------------- /packages/mockingbird/src/lib/builder/mock-builder.test.ts: -------------------------------------------------------------------------------- 1 | import { MockBuilder } from './mock-builder'; 2 | import { Mock } from '../../index'; 3 | 4 | class Bird { 5 | @Mock() 6 | name: string; 7 | 8 | @Mock((faker) => faker.datatype.number(20)) 9 | points: number; 10 | 11 | @Mock((faker) => faker.random.arrayElement(['yes', 'no'])) 12 | isAwesome: 'yes' | 'no'; 13 | 14 | @Mock((faker) => faker.datatype.uuid()) 15 | _unique_id_prop_: string; 16 | } 17 | 18 | const itemIsUndefinedInKey = (key) => (item) => typeof item[key] === 'undefined'; 19 | const itemIsDefinedInKey = (key) => (item) => typeof item[key] !== 'undefined'; 20 | 21 | /** 22 | * This test is written with strict BDD using jest-gherkin 23 | * the word prop stands for a 'property', as well as 'props' which stands for 'properties' 24 | */ 25 | describe('MockBuilder Integration Test', () => { 26 | let createNewBuilder: () => MockBuilder; 27 | let builder: MockBuilder; 28 | 29 | beforeAll(() => { 30 | createNewBuilder = (): MockBuilder => new MockBuilder(Bird); 31 | }); 32 | 33 | scenario('mutating some values', () => { 34 | beforeAll(() => { 35 | builder = createNewBuilder(); 36 | }); 37 | 38 | given('a builder which is configured to mutate some values', () => { 39 | let mock; 40 | 41 | beforeAll(() => (mock = builder.mutate({ name: 'mutated-name' }).one())); 42 | 43 | when('I create a single/one mock of Dog with mutation', () => { 44 | then('return a mock where the mutated values are actually changed', () => { 45 | expect(mock.name).toBe('mutated-name'); 46 | }); 47 | 48 | describe('and when I repeat again', () => { 49 | beforeAll(() => (mock = builder.one())); 50 | 51 | then("do not apply the mutation I've set before", () => { 52 | expect(mock.name).not.toBe('mutated-name'); 53 | }); 54 | }); 55 | }); 56 | 57 | when('I create many mocks of Dog', () => { 58 | let mocks; 59 | 60 | beforeAll(() => (mocks = builder.mutate({ points: 10, isAwesome: 'yes' }).many(3))); 61 | 62 | then('return an array where each item has been mutated in the above keys (points, isAwesome)', () => { 63 | const itemHasSameValue = (key, value) => (item) => item[key] === value; 64 | 65 | expect(mocks.every(itemHasSameValue('points', 10))).toBeTruthy(); 66 | expect(mocks.every(itemHasSameValue('isAwesome', 'yes'))).toBeTruthy(); 67 | }); 68 | }); 69 | }); 70 | }); 71 | 72 | scenario('using ignore to omit values', () => { 73 | let builder; 74 | 75 | describe('given a builder', () => { 76 | beforeAll(() => { 77 | builder = createNewBuilder(); 78 | builder.omit = jest.fn(); 79 | }); 80 | 81 | when('I call ignore method', () => { 82 | const OMIT_RETURN_VALUE = 'arbitrary-value'; 83 | let ignoreReturnValue; 84 | 85 | beforeAll(() => { 86 | builder.omit.mockReturnValue(OMIT_RETURN_VALUE); 87 | ignoreReturnValue = builder.ignore(); 88 | }); 89 | 90 | then('call and return omit instead', () => { 91 | expect(builder.omit).toHaveBeenCalled(); 92 | expect(ignoreReturnValue).toBe(OMIT_RETURN_VALUE); 93 | }); 94 | }); 95 | }); 96 | }); 97 | 98 | scenario('omit values', () => { 99 | beforeAll(() => { 100 | builder = createNewBuilder(); 101 | }); 102 | 103 | given("I've created a builder and ask to omit some values", () => { 104 | beforeAll(() => builder.omit('isAwesome', 'points')); 105 | 106 | when('I create a single mock of Dog', () => { 107 | let mock; 108 | 109 | beforeAll(() => (mock = builder.one())); 110 | 111 | then("mutate return a mock without no values on props I've asked to omit", () => { 112 | expect(mock.points).toBeUndefined(); 113 | expect(mock.isAwesome).toBeUndefined(); 114 | }); 115 | }); 116 | 117 | when('I create many mocks of Dog, repeating a few times', () => { 118 | let mocks; 119 | 120 | beforeAll(() => { 121 | builder = createNewBuilder(); 122 | mocks = builder.omit('isAwesome', 'points').many(3); 123 | }); 124 | 125 | then("mutate return an array where the prop I've asked to omit has no value", () => { 126 | expect(mocks.every(itemIsUndefinedInKey('points'))).toBeTruthy(); 127 | expect(mocks.every(itemIsUndefinedInKey('isAwesome'))).toBeTruthy(); 128 | }); 129 | }); 130 | 131 | when('I want to omit a prop only once (alongside the permanent props)', () => { 132 | let mock; 133 | 134 | when('I create a new single mock of Dog', () => { 135 | beforeAll(() => (mock = builder.omit('name').one())); 136 | 137 | then("omit the permanent keys as well as the key I've asked to omit once", () => { 138 | expect(mock.name).toBeUndefined(); 139 | }); 140 | 141 | describe('and when I ask to create a mock again', () => { 142 | then("do not omit the key I've asked to omit only once", () => { 143 | mock = builder.one(); 144 | expect(mock.name).not.toBeUndefined(); 145 | }); 146 | }); 147 | }); 148 | 149 | when('I create many mocks of the same class, Dog', () => { 150 | let mocks; 151 | 152 | beforeAll(() => (mocks = builder.omit('name').many(3))); 153 | 154 | then("return an array where each item has no value in the prop 'name'", () => { 155 | expect(mocks.every(itemIsUndefinedInKey('name'))).toBeTruthy(); 156 | }); 157 | 158 | describe('and now I want to create some more mocks again', () => { 159 | beforeAll(() => (mocks = builder.many(3))); 160 | 161 | then("do not omit the key I've asked to omit only once", () => { 162 | expect(mocks.every(itemIsDefinedInKey('name'))).toBeTruthy(); 163 | }); 164 | }); 165 | }); 166 | }); 167 | }); 168 | }); 169 | 170 | scenario('plain object', () => { 171 | beforeAll(() => (builder = createNewBuilder())); 172 | 173 | given('a new builder', () => { 174 | beforeAll(() => (builder = createNewBuilder())); 175 | 176 | when('I ask for a plain object', () => { 177 | and('I want to create one single mock', () => { 178 | let mock; 179 | 180 | then('return a plain object (and not an actual instance)', () => { 181 | mock = builder.plain().one(); 182 | 183 | expect(mock).not.toBeInstanceOf(Bird); 184 | expect(mock).toBeInstanceOf(Object); 185 | }); 186 | 187 | then('return an instance of Dog again', () => { 188 | mock = builder.one(); 189 | 190 | expect(mock).toBeInstanceOf(Bird); 191 | }); 192 | }); 193 | 194 | and('I want to create many mocks', () => { 195 | let mocks; 196 | const itemIsInstanceOfDog = (item) => item.constructor.name === 'Bird'; 197 | 198 | then('return array of plain objects (and not an actual instances)', () => { 199 | mocks = builder.plain().many(3); 200 | expect(mocks.every(itemIsInstanceOfDog)).toBeFalsy(); 201 | }); 202 | 203 | then('return array of instances of Dog again', () => { 204 | mocks = builder.many(3); 205 | expect(mocks.every(itemIsInstanceOfDog)).toBeTruthy(); 206 | }); 207 | }); 208 | }); 209 | }); 210 | }); 211 | }); 212 | -------------------------------------------------------------------------------- /packages/mockingbird/src/lib/builder/mock-builder.ts: -------------------------------------------------------------------------------- 1 | import { ClassLiteral, Class } from '@mockingbird/common'; 2 | import { Keys, Mutations } from './types'; 3 | import { MockProducer } from './mock-producer'; 4 | 5 | export interface MockBuilder { 6 | /** 7 | * Sets the faker locale inside the MockBuilder, thus, all the mocks that 8 | * will be generated from the builder will be affected from this setting 9 | * and will get applied by it 10 | * 11 | * @example 12 | * MockFactory(Bird).setLocale('es').one() 13 | * 14 | * @param locale {string} 15 | * @returns {this} the actual same builder 16 | */ 17 | setLocale(locale: string): this; 18 | 19 | /** 20 | * Converts the generated mock into a plain object. 21 | * When creating multiple mocks (using .many()), then 22 | * all the items in the array will be converted 23 | * into plain objects. 24 | * 25 | * @example 26 | * MockFactory(Bird).plain().one() 27 | * 28 | * @returns {MockBuilder} 29 | */ 30 | plain(): this; 31 | 32 | /** 33 | * Mutates the generated mock(s). 34 | * .mutate() method enables to set another value for a specific 35 | * property. 36 | * 37 | * @example 38 | * MockFactory(Bird).mutate({ name: 'some-permanent-name' }).one() 39 | * 40 | * @param mutations {Mutations} 41 | */ 42 | mutate(mutations: Mutations): Omit, 'mutate'>; 43 | 44 | /** 45 | * @alias omit 46 | * @param keys 47 | * @returns {MockBuilder} 48 | * @deprecated use .omit() instead 49 | */ 50 | ignore(...keys: Keys): ReturnType['omit']>; 51 | 52 | /** 53 | * Omits properties from the generated mock(s); all the 54 | * rest of the properties will remain the same. 55 | * Notice that omitting a property that contains a default 56 | * value will only ignore the decorator generation. 57 | * 58 | * @example 59 | * MockFactory(Bird).ignore('name').one() 60 | * 61 | * @param keys 62 | * @returns {MockBuilder} 63 | */ 64 | omit(...keys: Keys): this; 65 | 66 | /** 67 | * Picks specific properties to generate a mock from. 68 | * Notice that properties that contain default values 69 | * in the class will remain there but the decorator won't 70 | * apply to those properties. 71 | * 72 | * @example 73 | * MockFactory(Bird).pick('name').one() 74 | * 75 | * @param keys 76 | * @returns {MockBuilder} 77 | */ 78 | pick(...keys: Keys): this; 79 | 80 | /** 81 | * Creates exactly one mock from the target class 82 | * 83 | * @returns {TClass | Object} 84 | */ 85 | one(): TClass; 86 | 87 | /** 88 | * Creates many mocks from the target class. 89 | * 90 | * @param count {number} How many mocks to create 91 | * @returns {TClass[] | Object[]} An array of instances of plain objects 92 | */ 93 | many(count: number): TClass[]; 94 | } 95 | 96 | export class MockBuilder extends MockProducer { 97 | private isPlain = false; 98 | 99 | private mutations: Mutations = {}; 100 | private omitKeys: Keys = []; 101 | private pickKeys: Keys = []; 102 | 103 | public constructor(targetClass: Class) { 104 | super(targetClass); 105 | } 106 | 107 | private clean(): void { 108 | this.isPlain = false; 109 | this.mutations = {}; 110 | this.omitKeys = []; 111 | this.pickKeys = []; 112 | } 113 | 114 | public plain(): this { 115 | this.isPlain = true; 116 | return this; 117 | } 118 | 119 | public mutate(mutations: Mutations): Omit, 'mutate'> { 120 | this.mutations = mutations; 121 | return this; 122 | } 123 | 124 | /** 125 | * @deprecated use .omit() instead 126 | */ 127 | public ignore(...keys: Keys): ReturnType['omit']> { 128 | return this.omit(...keys); 129 | } 130 | 131 | public omit(...keys: Keys): this { 132 | this.omitKeys = keys; 133 | return this; 134 | } 135 | 136 | public pick(...keys: Keys): this { 137 | this.pickKeys = keys; 138 | return this; 139 | } 140 | 141 | public one(): TClass | ClassLiteral { 142 | const { mutations, omitKeys, pickKeys, isPlain } = this; 143 | 144 | const instance: TClass = super.createOne({ mutations, omit: omitKeys, plain: isPlain, pick: pickKeys }); 145 | this.clean(); 146 | 147 | return instance; 148 | } 149 | 150 | public many(count: number): TClass[] | ClassLiteral[] { 151 | const { mutations, omitKeys, pickKeys, isPlain } = this; 152 | 153 | const instances = super.createMany(count, { mutations, omit: omitKeys, plain: isPlain, pick: pickKeys }); 154 | this.clean(); 155 | 156 | return instances; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /packages/mockingbird/src/lib/builder/mock-producer.ts: -------------------------------------------------------------------------------- 1 | import { Class } from '@mockingbird/common'; 2 | import { Keys, Mutations } from './types'; 3 | import { mockGenerator } from '@mockingbird/parser'; 4 | 5 | interface ExtraKeys { 6 | omit?: Keys; 7 | pick?: Keys; 8 | mutations?: Mutations; 9 | plain?: boolean; 10 | } 11 | 12 | export class MockProducer { 13 | protected locale = 'en'; 14 | 15 | protected constructor(protected readonly targetClass: Class) {} 16 | 17 | public setLocale(locale: string): void { 18 | this.locale = locale; 19 | } 20 | 21 | protected createMany(count: number, config: ExtraKeys = {}): TClass[] { 22 | const { locale } = this; 23 | const { mutations = {}, plain = false, pick = [], omit = [] } = config; 24 | 25 | return mockGenerator.generate(this.targetClass, { 26 | locale, 27 | mutations, 28 | pick, 29 | omit, 30 | plain, 31 | count, 32 | }) as unknown as TClass[]; 33 | } 34 | 35 | protected createOne(config: ExtraKeys = {}): TClass { 36 | const { locale } = this; 37 | const { mutations = {}, plain = false, pick = [], omit = [] } = config; 38 | 39 | return mockGenerator.generate(this.targetClass, { 40 | locale, 41 | mutations, 42 | pick, 43 | omit, 44 | plain, 45 | }) as unknown as TClass; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /packages/mockingbird/src/lib/builder/types.ts: -------------------------------------------------------------------------------- 1 | import { ParserConfig } from '@mockingbird/parser'; 2 | import { ClassLiteral } from '@mockingbird/common'; 3 | 4 | export type GeneratedMock = TClass | ClassLiteral | TClass[] | ClassLiteral[]; 5 | 6 | export type Keys = ParserConfig['omit']; 7 | export type Mutations = ParserConfig['mutations']; 8 | -------------------------------------------------------------------------------- /packages/mockingbird/src/lib/factory/mock-factory.ts: -------------------------------------------------------------------------------- 1 | import { Class } from '@mockingbird/common'; 2 | import { MockBuilder } from '../builder'; 3 | 4 | /** 5 | * MockFactory take the target class as a parameter and returns 6 | * a MockBuilder which enables to chain some methods and compose 7 | * a new mock or mocks. 8 | * 9 | * @param target {Class} the class to create mock(s) from 10 | * @returns {MockBuilder} new builder to compose a mock 11 | */ 12 | export function MockFactory(target: Class): MockBuilder { 13 | return new MockBuilder(target); 14 | } 15 | -------------------------------------------------------------------------------- /packages/mockingbird/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from './factory/mock-factory'; 2 | export * from './builder'; 3 | -------------------------------------------------------------------------------- /packages/mockingbird/src/types/mock-decorator-factory-options.interface.ts: -------------------------------------------------------------------------------- 1 | import { Faker } from '@mockingbird/common'; 2 | 3 | export interface MockDecoratorFactoryOptions { 4 | count: number; 5 | locale?: Faker['locale']; 6 | } 7 | -------------------------------------------------------------------------------- /packages/mockingbird/src/types/mock-generator-options.interface.ts: -------------------------------------------------------------------------------- 1 | import { Faker } from '@mockingbird/common'; 2 | import { ParserConfig } from '@mockingbird/parser'; 3 | 4 | export interface MockGeneratorOptions extends ParserConfig { 5 | count?: number; 6 | locale?: Faker['locale']; 7 | plain?: boolean; 8 | } 9 | -------------------------------------------------------------------------------- /packages/mockingbird/test/e2e/__snapshots__/mock-factory.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`MockFactory e2e Test Scenario: using a plain object when I create 3 birds and covert them into a plain object then return a nested plain object 1`] = ` 4 | Array [ 5 | Object { 6 | "birthday": 2000-01-01T00:00:00.000Z, 7 | "name": "BirdyBird", 8 | "owner": Object { 9 | "car": Object { 10 | "model": "BMW", 11 | }, 12 | "gender": "male", 13 | }, 14 | }, 15 | Object { 16 | "birthday": 2000-01-01T00:00:00.000Z, 17 | "name": "BirdyBird", 18 | "owner": Object { 19 | "car": Object { 20 | "model": "BMW", 21 | }, 22 | "gender": "male", 23 | }, 24 | }, 25 | Object { 26 | "birthday": 2000-01-01T00:00:00.000Z, 27 | "name": "BirdyBird", 28 | "owner": Object { 29 | "car": Object { 30 | "model": "BMW", 31 | }, 32 | "gender": "male", 33 | }, 34 | }, 35 | ] 36 | `; 37 | 38 | exports[`MockFactory e2e Test Scenario: using mutations when I use mutation with the mock factory return a mock where the name is 'Mutated Name' 1`] = ` 39 | Bird { 40 | "birthday": 2000-01-01T00:00:00.000Z, 41 | "name": "Mutated Name", 42 | "owner": Person { 43 | "car": Car { 44 | "model": "BMW", 45 | }, 46 | "gender": "male", 47 | }, 48 | } 49 | `; 50 | 51 | exports[`MockFactory e2e Test Scenario: using pick when I use pick with MockBuilder then match the given result object (snapshot) 1`] = ` 52 | Bird { 53 | "name": "BirdyBird", 54 | } 55 | `; 56 | 57 | exports[`MockFactory e2e Test when calling 'many' method with a given class then return 3 instances of the given class 1`] = ` 58 | Array [ 59 | Bird { 60 | "birthday": 2000-01-01T00:00:00.000Z, 61 | "name": "BirdyBird", 62 | "owner": Person { 63 | "car": Car { 64 | "model": "BMW", 65 | }, 66 | "gender": "male", 67 | }, 68 | }, 69 | Bird { 70 | "birthday": 2000-01-01T00:00:00.000Z, 71 | "name": "BirdyBird", 72 | "owner": Person { 73 | "car": Car { 74 | "model": "BMW", 75 | }, 76 | "gender": "male", 77 | }, 78 | }, 79 | Bird { 80 | "birthday": 2000-01-01T00:00:00.000Z, 81 | "name": "BirdyBird", 82 | "owner": Person { 83 | "car": Car { 84 | "model": "BMW", 85 | }, 86 | "gender": "male", 87 | }, 88 | }, 89 | ] 90 | `; 91 | -------------------------------------------------------------------------------- /packages/mockingbird/test/e2e/mock-factory.test.ts: -------------------------------------------------------------------------------- 1 | import { MockFactory } from '../../src'; 2 | import { TestClassesE2E } from './test-classes'; 3 | import * as faker from 'faker'; 4 | import Bird = TestClassesE2E.Bird; 5 | 6 | describe('MockFactory e2e Test', () => { 7 | let result; 8 | 9 | beforeAll(() => { 10 | // Mock the date so we don't have to get trouble in our snapshots (2000-01-01T00:00:00.000Z) 11 | jest.spyOn(faker.date, 'recent').mockReturnValue(new Date(Date.UTC(2000, 0, 0, 24))); 12 | }); 13 | 14 | when("calling 'many' method with a given class", () => { 15 | beforeAll(() => { 16 | result = MockFactory(Bird).many(3); 17 | }); 18 | 19 | then('return an array with the exact same length', () => { 20 | expect(result).toBeInstanceOf(Array); 21 | expect(result).toHaveLength(3); 22 | }); 23 | 24 | then('return 3 instances of the given class', () => { 25 | expect(result).toMatchSnapshot(); 26 | }); 27 | }); 28 | 29 | scenario('using a plain object', () => { 30 | when('I create 3 birds and covert them into a plain object', () => { 31 | beforeAll(() => (result = MockFactory(Bird).plain().many(3))); 32 | 33 | test('then return a nested plain object', () => { 34 | expect(result).toMatchSnapshot(); 35 | }); 36 | }); 37 | }); 38 | 39 | scenario('using mutations', () => { 40 | let mock; 41 | 42 | when('I use mutation with the mock factory', () => { 43 | beforeAll(() => { 44 | mock = MockFactory(Bird).mutate({ name: 'Mutated Name' }).one(); 45 | }); 46 | 47 | test("return a mock where the name is 'Mutated Name'", () => { 48 | expect(mock).toMatchSnapshot(); 49 | expect(mock.name).toBe('Mutated Name'); 50 | }); 51 | }); 52 | 53 | when('I use mutations (using faker) with the mock factory', () => { 54 | let mock; 55 | 56 | beforeAll(() => { 57 | faker.name.firstName = () => 'FakedBirdName'; 58 | mock = MockFactory(Bird) 59 | .mutate((faker) => ({ name: faker.name.firstName() })) 60 | .one(); 61 | }); 62 | 63 | test("return a mock where the name is 'FakedBirdName'", () => { 64 | expect(mock.name).toBe('FakedBirdName'); 65 | }); 66 | }); 67 | }); 68 | 69 | scenario('using pick', () => { 70 | let mock; 71 | 72 | when('I use pick with MockBuilder', () => { 73 | beforeAll(() => { 74 | mock = MockFactory(Bird).pick('name').one(); 75 | }); 76 | 77 | then('return an instance of the class Bird', () => { 78 | expect(mock).toBeInstanceOf(Bird); 79 | }); 80 | 81 | test('and contain only the property name', () => { 82 | expect(mock.name).toBeDefined(); 83 | expect(mock.owner).toBeUndefined(); 84 | expect(mock.birthday).toBeUndefined(); 85 | }); 86 | 87 | then('match the given result object (snapshot)', () => { 88 | expect(mock).toMatchSnapshot(); 89 | }); 90 | }); 91 | }); 92 | }); 93 | -------------------------------------------------------------------------------- /packages/mockingbird/test/e2e/test-classes.ts: -------------------------------------------------------------------------------- 1 | import { Mock } from '../../src'; 2 | 3 | export namespace TestClassesE2E { 4 | enum Gender { 5 | male = 'male', 6 | } 7 | 8 | export class Car { 9 | @Mock('BMW') 10 | model: string; 11 | } 12 | 13 | export class Person { 14 | @Mock({ enum: Gender }) 15 | gender: Gender; 16 | 17 | @Mock(Car) 18 | car: Car; 19 | } 20 | 21 | export class Bird { 22 | @Mock('BirdyBird') 23 | name: string; 24 | 25 | @Mock(Person) 26 | owner: Person; 27 | 28 | @Mock() 29 | birthday: Date; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/mockingbird/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "rootDir": "./src", 6 | "outDir": "./dist", 7 | "target": "es6" 8 | }, 9 | "exclude": [ 10 | "node_modules", 11 | "test", 12 | "src/**/*.test.ts" 13 | ], 14 | "include": ["src/"] 15 | } -------------------------------------------------------------------------------- /packages/parser/.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | jest.config.js -------------------------------------------------------------------------------- /packages/parser/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../.eslintrc" 3 | } -------------------------------------------------------------------------------- /packages/parser/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [3.0.2](https://github.com/omermorad/mockingbird/compare/@mockingbird/parser@3.0.2-rc.3...@mockingbird/parser@3.0.2) (2021-12-08) 7 | 8 | **Note:** Version bump only for package @mockingbird/parser 9 | 10 | 11 | 12 | 13 | 14 | ## [3.0.2-rc.3](https://github.com/omermorad/mockingbird/compare/@mockingbird/parser@3.0.2-rc.1...@mockingbird/parser@3.0.2-rc.3) (2021-11-18) 15 | 16 | **Note:** Version bump only for package @mockingbird/parser 17 | 18 | 19 | 20 | 21 | 22 | ## [3.0.2-rc.2](https://github.com/omermorad/mockingbird/compare/@mockingbird/parser@3.0.2-rc.1...@mockingbird/parser@3.0.2-rc.2) (2021-11-18) 23 | 24 | **Note:** Version bump only for package @mockingbird/parser 25 | 26 | 27 | 28 | 29 | 30 | ## 3.0.2-rc.1 (2021-11-17) 31 | 32 | 33 | ### Bug Fixes 34 | 35 | * **parser:** fix import and handler priority of regex + randexp ([704d392](https://github.com/omermorad/mockingbird/commit/704d39282cd2056dc4baac8bedf164bdaa95d712)) 36 | 37 | 38 | ### Code Refactoring 39 | 40 | * **parser:** add mock generator and remove analyzer ([#107](https://github.com/omermorad/mockingbird/issues/107)) ([32c0ff6](https://github.com/omermorad/mockingbird/commit/32c0ff62895a18d9e892e1280572aea3ad500491)) 41 | 42 | 43 | ### Features 44 | 45 | * **parser:** add regex functionality/handler ([#98](https://github.com/omermorad/mockingbird/issues/98)) ([ae1bac8](https://github.com/omermorad/mockingbird/commit/ae1bac8629047385741f85620a725405a3c3fa27)) 46 | 47 | 48 | ### BREAKING CHANGES 49 | 50 | * **parser:** ClassAnalayzer has been removed and all the logic has been moved to ClassParser 51 | 52 | * test(parser): add (move) mock generator integration test 53 | 54 | * chore(parser): config jest and typescript to run integration test 55 | 56 | * fix(mockingbird): use mock generator differently (singleton) 57 | 58 | Remove mock generator from mockingbird and import it from @mockinbird/parser instead 59 | mock generator acts as a singleton now 60 | 61 | * refactor(mockingbird): fix mock factory 62 | 63 | * chore(mockingbird): config jest to collect coverage properly 64 | 65 | 66 | 67 | ## 2.1.1 (2021-08-21) 68 | 69 | 70 | ### Bug Fixes 71 | 72 | * fix broken packages because of 'types' (instead common) ([#94](https://github.com/omermorad/mockingbird/issues/94)) ([fca274a](https://github.com/omermorad/mockingbird/commit/fca274aca495251b9b74a51f99f4e15c6fae5a4c)) 73 | 74 | 75 | 76 | # 2.1.0 (2021-08-21) 77 | 78 | 79 | ### Bug Fixes 80 | 81 | * **mockingbird:** change ignore term to omit (deprecation) ([#86](https://github.com/omermorad/mockingbird/issues/86)) ([f3b3ab9](https://github.com/omermorad/mockingbird/commit/f3b3ab9c53baa3c9a114775f64961ddfa59124e6)) 82 | 83 | 84 | ### Code Refactoring 85 | 86 | * **parser:** add ability to pick properties, change dependecies, add class analyzer ([1312ea9](https://github.com/omermorad/mockingbird/commit/1312ea98af94ba0b0ce62f4160f646e9c2075514)), closes [#84](https://github.com/omermorad/mockingbird/issues/84) 87 | 88 | 89 | ### Features 90 | 91 | * **parser:** add faker as part of mutations (with callback) + test case ([59dfde7](https://github.com/omermorad/mockingbird/commit/59dfde7174e3d820506a6243f226278ce9558908)) 92 | * **types:** add exported function is-primitive ([24a4a56](https://github.com/omermorad/mockingbird/commit/24a4a5644dadc050758db2040bd0519fe2d7c8e2)) 93 | 94 | 95 | ### Reverts 96 | 97 | * Revert "chore(packages): version packages [skip ci]" ([5cbc7d6](https://github.com/omermorad/mockingbird/commit/5cbc7d67c5a62343c65fb1401e73df505cbadf52)) 98 | 99 | 100 | ### BREAKING CHANGES 101 | 102 | * **parser:** The reflector dependency is no longer injected to ClassParser 103 | 104 | 105 | 106 | # 2.0.0 (2021-07-31) 107 | 108 | 109 | ### chore 110 | 111 | * **release:** release version v2.0.0 ([#53](https://github.com/omermorad/mockingbird/issues/53)) ([f598ef3](https://github.com/omermorad/mockingbird/commit/f598ef35d5b9111f66202f119b8961314483f4fb)), closes [#51](https://github.com/omermorad/mockingbird/issues/51) [#40](https://github.com/omermorad/mockingbird/issues/40) [#42](https://github.com/omermorad/mockingbird/issues/42) [#37](https://github.com/omermorad/mockingbird/issues/37) [#46](https://github.com/omermorad/mockingbird/issues/46) [#47](https://github.com/omermorad/mockingbird/issues/47) [#49](https://github.com/omermorad/mockingbird/issues/49) [#50](https://github.com/omermorad/mockingbird/issues/50) [#52](https://github.com/omermorad/mockingbird/issues/52) [#54](https://github.com/omermorad/mockingbird/issues/54) [#42](https://github.com/omermorad/mockingbird/issues/42) [#55](https://github.com/omermorad/mockingbird/issues/55) [#42](https://github.com/omermorad/mockingbird/issues/42) [#56](https://github.com/omermorad/mockingbird/issues/56) [#57](https://github.com/omermorad/mockingbird/issues/57) [#58](https://github.com/omermorad/mockingbird/issues/58) [#59](https://github.com/omermorad/mockingbird/issues/59) [#60](https://github.com/omermorad/mockingbird/issues/60) [#42](https://github.com/omermorad/mockingbird/issues/42) [#61](https://github.com/omermorad/mockingbird/issues/61) [#62](https://github.com/omermorad/mockingbird/issues/62) [#64](https://github.com/omermorad/mockingbird/issues/64) [#63](https://github.com/omermorad/mockingbird/issues/63) [#67](https://github.com/omermorad/mockingbird/issues/67) [#68](https://github.com/omermorad/mockingbird/issues/68) 112 | 113 | 114 | ### BREAKING CHANGES 115 | 116 | * **release:** MockFactory is now an instance (TClass) and not ClassLiteral 117 | 118 | * chore: fix typo in the test name 119 | 120 | * chore: change methods order 121 | 122 | * chore: added source map and some jest configs 123 | 124 | * refactor: change some var names and error 125 | 126 | * test(class-processor): refactor test turning into integration instead of unit 127 | 128 | * chore(lib): move files into lib folder and change imports 129 | 130 | * feat(fluent-api): add fluent api (builder) functionality and persistence 131 | 132 | Add fluent API to enable methods chaining with ability to persist the mock 133 | * **release:** MockFactory is now a function and not a class, changed the original to 134 | MockGenerator. Add fluent API and ability to persist mock data 135 | * **release:** MockFactory changed to be MockGenerator 136 | * **release:** MockFactory changed to be MockGenerator 137 | * **release:** MockGenerator is not exported anymore, use MockFactory instead 138 | 139 | 140 | 141 | 142 | 143 | ## 3.0.2-rc.0 (2021-11-13) 144 | 145 | **Note:** Version bump only for package @mockingbird/parser 146 | 147 | 148 | 149 | 150 | 151 | ## [3.0.1](https://github.com/omermorad/mockingbird/compare/@mockingbird/parser@3.0.0...@mockingbird/parser@3.0.1) (2021-08-21) 152 | 153 | 154 | ### Bug Fixes 155 | 156 | * fix broken packages because of 'types' (instead common) ([#94](https://github.com/omermorad/mockingbird/issues/94)) ([fca274a](https://github.com/omermorad/mockingbird/commit/fca274aca495251b9b74a51f99f4e15c6fae5a4c)) 157 | 158 | 159 | 160 | 161 | 162 | # [3.0.0](https://github.com/omermorad/mockingbird/compare/@mockingbird/parser@2.0.0...@mockingbird/parser@3.0.0) (2021-08-21) 163 | 164 | 165 | ### Bug Fixes 166 | 167 | * **mockingbird:** change ignore term to omit (deprecation) ([#86](https://github.com/omermorad/mockingbird/issues/86)) ([f3b3ab9](https://github.com/omermorad/mockingbird/commit/f3b3ab9c53baa3c9a114775f64961ddfa59124e6)) 168 | 169 | 170 | ### Code Refactoring 171 | 172 | * **parser:** add ability to pick properties, change dependecies, add class analyzer ([1312ea9](https://github.com/omermorad/mockingbird/commit/1312ea98af94ba0b0ce62f4160f646e9c2075514)), closes [#84](https://github.com/omermorad/mockingbird/issues/84) 173 | 174 | 175 | ### Features 176 | 177 | * **parser:** add faker as part of mutations (with callback) + test case ([59dfde7](https://github.com/omermorad/mockingbird/commit/59dfde7174e3d820506a6243f226278ce9558908)) 178 | * **types:** add exported function is-primitive ([24a4a56](https://github.com/omermorad/mockingbird/commit/24a4a5644dadc050758db2040bd0519fe2d7c8e2)) 179 | 180 | 181 | ### Reverts 182 | 183 | * Revert "chore(packages): version packages [skip ci]" ([5cbc7d6](https://github.com/omermorad/mockingbird/commit/5cbc7d67c5a62343c65fb1401e73df505cbadf52)) 184 | 185 | 186 | ### BREAKING CHANGES 187 | 188 | * **parser:** The reflector dependency is no longer injected to ClassParser 189 | 190 | 191 | 192 | 193 | 194 | # 2.0.0 (2021-07-31) 195 | 196 | 197 | ### chore 198 | 199 | * **release:** release version v2.0.0 ([#53](https://github.com/omermorad/mockingbird/issues/53)) ([f598ef3](https://github.com/omermorad/mockingbird/commit/f598ef35d5b9111f66202f119b8961314483f4fb)), closes [#51](https://github.com/omermorad/mockingbird/issues/51) [#40](https://github.com/omermorad/mockingbird/issues/40) [#42](https://github.com/omermorad/mockingbird/issues/42) [#37](https://github.com/omermorad/mockingbird/issues/37) [#46](https://github.com/omermorad/mockingbird/issues/46) [#47](https://github.com/omermorad/mockingbird/issues/47) [#49](https://github.com/omermorad/mockingbird/issues/49) [#50](https://github.com/omermorad/mockingbird/issues/50) [#52](https://github.com/omermorad/mockingbird/issues/52) [#54](https://github.com/omermorad/mockingbird/issues/54) [#42](https://github.com/omermorad/mockingbird/issues/42) [#55](https://github.com/omermorad/mockingbird/issues/55) [#42](https://github.com/omermorad/mockingbird/issues/42) [#56](https://github.com/omermorad/mockingbird/issues/56) [#57](https://github.com/omermorad/mockingbird/issues/57) [#58](https://github.com/omermorad/mockingbird/issues/58) [#59](https://github.com/omermorad/mockingbird/issues/59) [#60](https://github.com/omermorad/mockingbird/issues/60) [#42](https://github.com/omermorad/mockingbird/issues/42) [#61](https://github.com/omermorad/mockingbird/issues/61) [#62](https://github.com/omermorad/mockingbird/issues/62) [#64](https://github.com/omermorad/mockingbird/issues/64) [#63](https://github.com/omermorad/mockingbird/issues/63) [#67](https://github.com/omermorad/mockingbird/issues/67) [#68](https://github.com/omermorad/mockingbird/issues/68) 200 | 201 | 202 | ### BREAKING CHANGES 203 | 204 | * **release:** MockFactory is now an instance (TClass) and not ClassLiteral 205 | 206 | * chore: fix typo in the test name 207 | 208 | * chore: change methods order 209 | 210 | * chore: added source map and some jest configs 211 | 212 | * refactor: change some var names and error 213 | 214 | * test(class-processor): refactor test turning into integration instead of unit 215 | 216 | * chore(lib): move files into lib folder and change imports 217 | 218 | * feat(fluent-api): add fluent api (builder) functionality and persistence 219 | 220 | Add fluent API to enable methods chaining with ability to persist the mock 221 | * **release:** MockFactory is now a function and not a class, changed the original to 222 | MockGenerator. Add fluent API and ability to persist mock data 223 | * **release:** MockFactory changed to be MockGenerator 224 | * **release:** MockFactory changed to be MockGenerator 225 | * **release:** MockGenerator is not exported anymore, use MockFactory instead 226 | 227 | 228 | 229 | 230 | 231 | ## [1.0.1-alpha.3](https://github.com/omermorad/mockingbird/compare/@mockingbird/parser@1.0.1-alpha.2...@mockingbird/parser@1.0.1-alpha.3) (2021-07-23) 232 | 233 | **Note:** Version bump only for package @mockingbird/parser 234 | 235 | 236 | 237 | 238 | 239 | ## 1.0.1-alpha.2 (2021-07-23) 240 | 241 | 242 | ### Bug Fixes 243 | 244 | * **types:** add build to export a js file to include the faker instance (for runtime) ([#61](https://github.com/omermorad/mockingbird/issues/61)) ([f4e3092](https://github.com/omermorad/mockingbird/commit/f4e3092e683eb9c288d4e879113e71f74ec5038a)) 245 | 246 | 247 | ### Reverts 248 | 249 | * **repo:** release packages ([7f9390d](https://github.com/omermorad/mockingbird/commit/7f9390d051f9c9c9c3eb172f4db8a9fe533b03c4)) 250 | 251 | 252 | 253 | 254 | 255 | ## [1.0.1-alpha.1](https://github.com/omermorad/mockingbird/compare/@mockingbird/parser@2.0.0...@mockingbird/parser@1.0.1-alpha.1) (2021-07-22) 256 | 257 | 258 | ### Reverts 259 | 260 | * **repo:** release packages ([7f9390d](https://github.com/omermorad/mockingbird/commit/7f9390d051f9c9c9c3eb172f4db8a9fe533b03c4)) 261 | -------------------------------------------------------------------------------- /packages/parser/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omermorad/mockingbird/421428336b06b0353dcb9a53c7f0c344bd03c95a/packages/parser/README.md -------------------------------------------------------------------------------- /packages/parser/index.ts: -------------------------------------------------------------------------------- 1 | export * from './src'; 2 | -------------------------------------------------------------------------------- /packages/parser/jest.config.js: -------------------------------------------------------------------------------- 1 | const base = require('../../jest.config.base'); 2 | const packageJson = require('./package'); 3 | 4 | module.exports = { 5 | ...base, 6 | roots: [...base.roots, '/test'], 7 | name: packageJson.name, 8 | displayName: packageJson.name, 9 | collectCoverageFrom: ['src/**/*.ts', 'test/**/*.ts'], 10 | coveragePathIgnorePatterns: ['index.ts', 'test-classes.ts'], 11 | }; 12 | -------------------------------------------------------------------------------- /packages/parser/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mockingbird/parser", 3 | "version": "3.0.2", 4 | "license": "MIT", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "description": "Mockingbird Parser Package", 8 | "contributors": [ 9 | { 10 | "name": "Omer Morad", 11 | "email": "omer.moradd@gmail.com" 12 | }, 13 | { 14 | "name": "Idan Ptichi", 15 | "email": "idanpt@gmail.com" 16 | } 17 | ], 18 | "repository": { 19 | "type": "git", 20 | "url": "https://github.com/omermorad/mockingbird.git" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/omermorad/mockingbird/issues" 24 | }, 25 | "readme": "https://github.com/omermorad/mockingbird/tree/refactor/master/packages/parser/README.md", 26 | "scripts": { 27 | "prebuild": "npx rimraf dist", 28 | "build": "tsc", 29 | "watch": "tsc --watch", 30 | "test": "jest --runInBand --verbose", 31 | "lint": "eslint '{src,test}/**/*.ts'", 32 | "lint:fix": "eslint '{src,test}/**/*.ts' --fix" 33 | }, 34 | "files": [ 35 | "dist", 36 | "index.js", 37 | "index.d.ts", 38 | "README.md", 39 | "CHANGELOG.md" 40 | ], 41 | "dependencies": { 42 | "@mockingbird/reflect": "^3.0.2", 43 | "randexp": "^0.5.3", 44 | "typedi": "^0.10.0" 45 | }, 46 | "devDependencies": { 47 | "@mockingbird/common": "^2.0.3", 48 | "jest": "27.0.6", 49 | "rimraf": "^3.0.2", 50 | "ts-jest": "^27.0.3", 51 | "ts-loader": "^6.2.2", 52 | "ts-node": "8.10.2", 53 | "tsconfig-paths": "^3.9.0", 54 | "typescript": "^3.9.7" 55 | }, 56 | "publishConfig": { 57 | "access": "public" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /packages/parser/src/index.ts: -------------------------------------------------------------------------------- 1 | import { Container } from 'typedi'; 2 | import { MockGenerator } from './lib/generator/mock-generator'; 3 | import { Faker } from '@mockingbird/common'; 4 | import RandExp from 'randexp'; 5 | 6 | export * from './lib/types/types'; 7 | export * from './lib/generator/mock-generator'; 8 | 9 | Container.set('Faker', Faker); 10 | Container.set('RandExp', RandExp); 11 | 12 | export const mockGenerator = Container.get(MockGenerator); 13 | -------------------------------------------------------------------------------- /packages/parser/src/lib/generator/mock-generator.test.ts: -------------------------------------------------------------------------------- 1 | import { MockGenerator } from './mock-generator'; 2 | import { ClassParser } from '../parser/class-parser'; 3 | 4 | /** 5 | * The full test of MockGenerator can be found under the 'test' folder, 6 | * you can find there the full integration test 7 | */ 8 | describe('MockGenerator Unit Test', () => { 9 | let generator: MockGenerator; 10 | 11 | class TestClass { 12 | test: string; 13 | } 14 | 15 | const parserMock = { 16 | setLocale: jest.fn(), 17 | parse: jest.fn(), 18 | } as unknown as jest.Mocked; 19 | 20 | beforeAll(() => { 21 | generator = new MockGenerator(parserMock); 22 | jest.clearAllMocks(); 23 | }); 24 | 25 | scenario('generate a SIMPLE mock from a class', () => { 26 | given('I want to generate a new mock from a class', () => { 27 | when('I call the create method with no configurations', () => { 28 | beforeAll(() => generator.generate(TestClass)); 29 | 30 | test('then setup parser with the default locale', () => { 31 | expect(parserMock.setLocale).toHaveBeenCalledWith('en'); 32 | }); 33 | 34 | test('then call parse one time only', () => { 35 | expect(parserMock.parse).toHaveBeenCalledTimes(1); 36 | }); 37 | }); 38 | }); 39 | }); 40 | 41 | scenario('generate mock from a class with a different configurations', () => { 42 | given('I want to generate a mock with different locale', () => { 43 | when('creating a new mock from generator passing the proper params', () => { 44 | beforeAll(() => generator.generate(TestClass, { locale: 'arbitrary-locale' })); 45 | 46 | then('setup the parser with the locale from the options', () => { 47 | expect(parserMock.setLocale).toHaveBeenCalledWith('arbitrary-locale'); 48 | }); 49 | }); 50 | }); 51 | 52 | given('I want to generate a mock and mutate different values', () => { 53 | when('creating a new mock from generator passing the proper param', () => { 54 | beforeAll(() => generator.generate(TestClass, { mutations: { test: 'value' } })); 55 | 56 | then('call parse with the valid options', () => { 57 | expect(parserMock.parse).toHaveBeenCalledWith(TestClass, { mutations: { test: 'value' } }); 58 | }); 59 | }); 60 | }); 61 | 62 | given('I want to generate a mock and omit different values', () => { 63 | when('creating a new mock from generator passing the proper param', () => { 64 | beforeAll(() => generator.generate(TestClass, { omit: ['test'] })); 65 | 66 | then('call parse with the valid options', () => { 67 | expect(parserMock.parse).toHaveBeenCalledWith(TestClass, { omit: ['test'] }); 68 | }); 69 | }); 70 | }); 71 | 72 | given('I want to generate a mock and convert it to plain', () => { 73 | when('creating a new mock from generator passing the proper param', () => { 74 | let result; 75 | 76 | beforeAll(() => { 77 | parserMock.parse.mockReturnValueOnce( 78 | new (class Cat { 79 | toy = new (class Toy { 80 | bell = new (class Bell {})(); 81 | })(); 82 | })() 83 | ); 84 | 85 | result = generator.generate(TestClass, { plain: true }); 86 | }); 87 | 88 | then('', () => { 89 | const isClass = (target) => target instanceof Object && target.constructor.name !== 'Object'; 90 | 91 | expect(isClass(result)).toBeFalsy(); 92 | expect(isClass(result.toy)).toBeFalsy(); 93 | expect(isClass(result.toy.bell)).toBeFalsy(); 94 | }); 95 | }); 96 | }); 97 | }); 98 | }); 99 | -------------------------------------------------------------------------------- /packages/parser/src/lib/generator/mock-generator.ts: -------------------------------------------------------------------------------- 1 | import { Service } from 'typedi'; 2 | import { Class, ClassLiteral, isPrimitive } from '@mockingbird/common'; 3 | import { MockGeneratorOptions } from '../types/mock-generator-options.interface'; 4 | import { ClassParser } from '../parser/class-parser'; 5 | 6 | @Service() 7 | export class MockGenerator { 8 | public constructor(private readonly classParser: ClassParser) {} 9 | 10 | private static classToPlain(targetClass: TClass): ClassLiteral { 11 | const toPlain = (target: ClassLiteral): ClassLiteral => { 12 | for (const key of Object.keys(target)) { 13 | const value = target[key]; 14 | 15 | if (value instanceof Object) { 16 | if (isPrimitive(value.constructor.name)) { 17 | toPlain(value); 18 | } else { 19 | target[key] = toPlain({ ...value }); 20 | } 21 | } 22 | } 23 | 24 | return target; 25 | }; 26 | 27 | return toPlain({ ...targetClass }); 28 | } 29 | 30 | /** 31 | * Return an object with all the properties decorated by the 'Mock' Decorator 32 | * 33 | * @example 34 | * class Person { @Mock() name: string } 35 | * MockGenerator.create(Person) will return an object { name: } 36 | * 37 | * @param targetClass {Class} 38 | * @returns {TClass} 39 | */ 40 | public generate(targetClass: Class): TClass; 41 | 42 | /** 43 | * Return an array of objects with all the properties decorated by the 44 | * 'Mock' Decorator (if 'count' is greater than 1) 45 | * 46 | * @example 47 | * class Person { @Mock() name: string } 48 | * MockGenerator.create(Person, { count: 3, locale: 'es' }) will return an 49 | * array of objects [{ name: }, { name: }, 50 | * { name: }] 51 | * 52 | * Passing a 'locale' property will set a different locale for faker calls 53 | * The default locale is 'en' (english) 54 | * 55 | * @param targetClass 56 | * @param options 57 | */ 58 | public generate( 59 | targetClass: Class, 60 | options: MockGeneratorOptions 61 | ): TClass | ClassLiteral; 62 | 63 | public generate( 64 | targetClass: Class, 65 | options: MockGeneratorOptions 66 | ): TClass[] | ClassLiteral[]; 67 | 68 | /** 69 | * Return one or many objects (array) with all the properties decorated 70 | * by the Mock decorator 71 | * 72 | * @param targetClass 73 | * @param options 74 | */ 75 | public generate( 76 | targetClass: Class, 77 | options: MockGeneratorOptions = {} 78 | ): TClass | TClass[] | ClassLiteral | ClassLiteral[] { 79 | const { count = 1, plain = false, locale = 'en', ...config } = options || {}; 80 | 81 | this.classParser.setLocale(locale); 82 | 83 | if (count === 1) { 84 | const parsedClass = this.classParser.parse(targetClass, config); 85 | return plain ? MockGenerator.classToPlain(parsedClass) : parsedClass; 86 | } 87 | 88 | const classInstances: TClass[] = []; 89 | 90 | for (let i = 1; i <= count; i++) { 91 | const parsedClass = this.classParser.parse(targetClass, config); 92 | classInstances.push(plain ? MockGenerator.classToPlain(parsedClass) : parsedClass); 93 | } 94 | 95 | return classInstances; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /packages/parser/src/lib/handlers/array-value-handler.test.ts: -------------------------------------------------------------------------------- 1 | import { Container } from 'typedi'; 2 | import { Property, PropertyDecoratorValue } from '@mockingbird/reflect'; 3 | import { Class, Faker, MultiClass } from '@mockingbird/common'; 4 | import { ArrayValueHandler } from './array-value-handler'; 5 | 6 | describe('ArrayValueHandler Unit Test', () => { 7 | const DTO_CLASS_VALUE = class TestClass {}; 8 | const DEFAULT_COUNT_FOR_DTO = 3; 9 | 10 | let handler: ArrayValueHandler; 11 | 12 | function createProperty(mockValue: MultiClass): Property { 13 | return new Property('testPropertyName', 'TestClass', new PropertyDecoratorValue(mockValue)); 14 | } 15 | 16 | const fakerMock = { 17 | random: { 18 | alpha: jest.fn().mockReturnValue('random-string'), 19 | alphaNumeric: jest.fn(), 20 | }, 21 | datatype: { 22 | number: jest.fn(), 23 | boolean: jest.fn(), 24 | }, 25 | date: { 26 | recent: jest.fn(), 27 | }, 28 | } as unknown as Faker; 29 | 30 | beforeAll(() => { 31 | Container.set('Faker', fakerMock); 32 | handler = Container.get(ArrayValueHandler); 33 | }); 34 | 35 | describe('given an ArrayValueHandler', () => { 36 | describe("when calling 'shouldHandle' with type 'object' and decoratorValue of multi class ({ type: ClassType })", () => { 37 | test('then return true', () => { 38 | expect( 39 | handler.shouldHandle(createProperty({ type: DTO_CLASS_VALUE, count: DEFAULT_COUNT_FOR_DTO })) 40 | ).toBeTruthy(); 41 | }); 42 | }); 43 | 44 | describe("when calling 'produceValue' method", () => { 45 | describe('and the decoratorValue is null', () => { 46 | test('then return null', () => { 47 | const producedValue = handler.produceValue(createProperty(null)); 48 | expect(producedValue).toBeNull(); 49 | }); 50 | }); 51 | 52 | describe('and the decoratorValue.type (class type) is primitive, of type String', () => { 53 | let result: any[]; 54 | 55 | beforeAll(() => { 56 | const property = createProperty({ type: String, count: DEFAULT_COUNT_FOR_DTO }); 57 | result = handler.produceValue(property); 58 | }); 59 | 60 | test('then call random alpha string from faker multiple times', () => { 61 | expect(fakerMock.random.alpha).toHaveBeenCalledTimes(DEFAULT_COUNT_FOR_DTO); 62 | }); 63 | 64 | test("then return an array of 'count' String(s)", () => { 65 | expect(result).toBeInstanceOf(Array); 66 | expect(result).toHaveLength(DEFAULT_COUNT_FOR_DTO); 67 | }); 68 | 69 | test('then return an array of String(s) only', () => { 70 | const constructorIsString = (item) => (item as Class).constructor.name === 'String'; 71 | expect(result.every(constructorIsString)).toBeTruthy(); 72 | }); 73 | }); 74 | 75 | describe('and the primitive decoratorValue is Number', () => { 76 | let result; 77 | 78 | beforeAll(() => { 79 | result = handler.produceValue(createProperty({ type: Number, count: DEFAULT_COUNT_FOR_DTO })); 80 | }); 81 | 82 | test('then call random alpha string from faker', () => { 83 | expect(fakerMock.datatype.number).toHaveBeenCalledTimes(DEFAULT_COUNT_FOR_DTO); 84 | expect(fakerMock.datatype.number).toHaveBeenCalledWith(1000); 85 | }); 86 | 87 | test("then return an array of 'count' numbers", () => { 88 | expect(result).toBeInstanceOf(Array); 89 | expect(result).toHaveLength(DEFAULT_COUNT_FOR_DTO); 90 | }); 91 | }); 92 | 93 | describe('and the primitive decoratorValue is Boolean', () => { 94 | test('and the primitive decoratorValue is Boolean', () => { 95 | handler.produceValue(createProperty({ type: Boolean, count: DEFAULT_COUNT_FOR_DTO })); 96 | expect(fakerMock.datatype.boolean).toHaveBeenCalledTimes(DEFAULT_COUNT_FOR_DTO); 97 | }); 98 | }); 99 | 100 | describe('and the primitive decoratorValue is Date', () => { 101 | test('and the primitive decoratorValue is Date', () => { 102 | handler.produceValue(createProperty({ type: Date, count: DEFAULT_COUNT_FOR_DTO })); 103 | expect(fakerMock.date.recent).toHaveBeenCalledTimes(DEFAULT_COUNT_FOR_DTO); 104 | }); 105 | }); 106 | }); 107 | 108 | describe('and decoratorValue type is an actual class (not a primitive)', () => { 109 | let value; 110 | 111 | beforeAll(() => { 112 | value = handler.produceValue(createProperty({ type: DTO_CLASS_VALUE, count: DEFAULT_COUNT_FOR_DTO })); 113 | }); 114 | 115 | test('then return an array with length of 3', () => { 116 | expect(value).toBeInstanceOf(Array); 117 | expect(value).toHaveLength(3); 118 | }); 119 | 120 | test.each(value, 'then return an array with 3 instances', (property) => { 121 | expect(property).toBeInstanceOf(DTO_CLASS_VALUE); 122 | }); 123 | }); 124 | }); 125 | }); 126 | -------------------------------------------------------------------------------- /packages/parser/src/lib/handlers/array-value-handler.ts: -------------------------------------------------------------------------------- 1 | import { Container, Service } from 'typedi'; 2 | import { isPrimitive } from '@mockingbird/common'; 3 | import { Property } from '@mockingbird/reflect'; 4 | import { ExactValue, MultiClass } from '@mockingbird/common'; 5 | import { PrimitiveHandler } from './primitive-handler'; 6 | import { ValueHandler } from '../types/value-handler.interface'; 7 | import { ClassParser } from '../parser/class-parser'; 8 | 9 | @Service() 10 | export class ArrayValueHandler implements ValueHandler { 11 | public constructor(private readonly primitiveHandler: PrimitiveHandler) {} 12 | 13 | public shouldHandle(property: Property): boolean { 14 | return property.decoratorValue.isMultiClass(); 15 | } 16 | 17 | public produceValue(property: Property): any[] { 18 | const { decoratorValue } = property; 19 | 20 | if (decoratorValue.value === null) { 21 | return null; 22 | } 23 | 24 | const { count, type } = decoratorValue.value as MultiClass; 25 | 26 | if (isPrimitive(type.name)) { 27 | const instances = new Array(count); 28 | 29 | for (let index = 0; index < count; index++) { 30 | instances[index] = this.primitiveHandler.generateRandomValueFromPrimitive(type.name); 31 | } 32 | 33 | return instances; 34 | } 35 | 36 | const instances = new Array(count); 37 | const parser = Container.get(ClassParser); 38 | 39 | for (let index = 0; index < count; index++) { 40 | instances[index] = parser.parse(type); 41 | } 42 | 43 | return instances; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/parser/src/lib/handlers/callback-value-handler.test.ts: -------------------------------------------------------------------------------- 1 | import { Container } from 'typedi'; 2 | import { Property, PropertyDecoratorValue } from '@mockingbird/reflect'; 3 | import { Faker } from '@mockingbird/common'; 4 | import { CallbackValueHandler } from './callback-value-handler'; 5 | 6 | describe('CallbackValueHandler Unit', () => { 7 | let handler: CallbackValueHandler; 8 | 9 | const fakerMock = { internet: { email: jest.fn() } } as unknown as Faker; 10 | 11 | beforeAll(() => { 12 | Container.set('Faker', fakerMock); 13 | handler = Container.get(CallbackValueHandler); 14 | }); 15 | 16 | describe('given a CallbackValueHandler', () => { 17 | describe("when calling 'shouldHandle' method with type function name and empty constructor name", () => { 18 | test('then return true', () => { 19 | const property = new Property( 20 | 'testPropertyName', 21 | '', 22 | new PropertyDecoratorValue(() => { 23 | return null; 24 | }) 25 | ); 26 | const result = handler.shouldHandle(property); 27 | 28 | expect(result).toBeTruthy(); 29 | }); 30 | }); 31 | 32 | describe("when calling 'produceValue' ", () => { 33 | test('then call the callback function with same faker instance', () => { 34 | const property = new Property('testPropertyName', '', new PropertyDecoratorValue(jest.fn())); 35 | handler.produceValue(property); 36 | 37 | expect(property.decoratorValue.value).toHaveBeenCalledTimes(1); 38 | expect(property.decoratorValue.value).toHaveBeenCalledWith(fakerMock); 39 | }); 40 | }); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /packages/parser/src/lib/handlers/callback-value-handler.ts: -------------------------------------------------------------------------------- 1 | import { Inject, Service } from 'typedi'; 2 | import { Property } from '@mockingbird/reflect'; 3 | import { Callback, Faker } from '@mockingbird/common'; 4 | import { ValueHandler } from '../types/value-handler.interface'; 5 | 6 | @Service() 7 | export class CallbackValueHandler implements ValueHandler { 8 | public constructor(@Inject('Faker') private readonly faker: Faker) {} 9 | 10 | public shouldHandle(property: Property): boolean { 11 | return property.decoratorValue.isCallback() && (property.decoratorValue.value as Callback).name === ''; 12 | } 13 | 14 | public produceValue(property: Property): any { 15 | return (property.decoratorValue.value as Callback)(this.faker); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/parser/src/lib/handlers/enum-value-handler.test.ts: -------------------------------------------------------------------------------- 1 | import { Container } from 'typedi'; 2 | import { Faker } from '@mockingbird/common'; 3 | import { Property, PropertyDecoratorValue } from '@mockingbird/reflect'; 4 | import { EnumValueHandler } from './enum-value-handler'; 5 | 6 | describe('EnumValueHandler Unit', () => { 7 | let handler: EnumValueHandler; 8 | 9 | enum TestEnum { 10 | StateOne = 'one', 11 | StateTwo = 'two', 12 | StateThree = 'three', 13 | } 14 | 15 | const fakerMock = { 16 | random: { 17 | arrayElement: jest.fn(), 18 | }, 19 | } as unknown as Faker; 20 | 21 | beforeAll(() => { 22 | Container.set('Faker', fakerMock); 23 | handler = Container.get(EnumValueHandler); 24 | }); 25 | 26 | describe('given a EnumValueHandler', () => { 27 | describe("when calling 'shouldHandle' method with type object and { type: enum }", () => { 28 | test('then return true', () => { 29 | const property = new Property('testPropertyName', '', new PropertyDecoratorValue({ enum: TestEnum })); 30 | expect(handler.shouldHandle(property)).toBeTruthy(); 31 | }); 32 | }); 33 | 34 | describe("when calling 'produceValue' method", () => { 35 | test('then call faker random array element', () => { 36 | const property = new Property('testPropertyName', '', new PropertyDecoratorValue({ enum: TestEnum })); 37 | handler.produceValue(property); 38 | 39 | expect(fakerMock.random.arrayElement).toHaveBeenCalledTimes(1); 40 | expect(fakerMock.random.arrayElement).toHaveBeenCalledWith(['one', 'two', 'three']); 41 | }); 42 | }); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /packages/parser/src/lib/handlers/enum-value-handler.ts: -------------------------------------------------------------------------------- 1 | import { Property } from '@mockingbird/reflect'; 2 | import { ValueHandler } from '../types/value-handler.interface'; 3 | import { Inject, Service } from 'typedi'; 4 | import { Faker } from '@mockingbird/common'; 5 | 6 | @Service() 7 | export class EnumValueHandler implements ValueHandler { 8 | public constructor(@Inject('Faker') private readonly faker: Faker) {} 9 | 10 | private static getEnumValues(enumObj: Record): any[] { 11 | const keysList = Object.getOwnPropertyNames(enumObj).filter( 12 | (key) => enumObj.propertyIsEnumerable(key) && key !== String(parseFloat(key)) 13 | ); 14 | 15 | const length = keysList.length; 16 | const valuesList = new Array(length); 17 | 18 | for (let index = 0; index < length; ++index) { 19 | const key = keysList[index]; 20 | valuesList[index] = enumObj[key]; 21 | } 22 | 23 | return valuesList; 24 | } 25 | 26 | public shouldHandle(propertyDto: Property): boolean { 27 | return propertyDto.decoratorValue.isEnum(); 28 | } 29 | 30 | public produceValue(propertyDto: Property): any { 31 | const { 32 | decoratorValue: { value }, 33 | } = propertyDto; 34 | const { enum: enumObj } = value as { enum: Record }; 35 | 36 | return this.faker.random.arrayElement(EnumValueHandler.getEnumValues(enumObj)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/parser/src/lib/handlers/object-literal-value-handler.test.ts: -------------------------------------------------------------------------------- 1 | import { Container } from 'typedi'; 2 | import { Property, PropertyDecoratorValue } from '@mockingbird/reflect'; 3 | import { ObjectLiteralValueHandler } from './object-literal-value-handler'; 4 | 5 | describe('ObjectLiteralValueHandler Unit', () => { 6 | let property: Property, handler: ObjectLiteralValueHandler; 7 | const OBJECT_LITERAL_VALUE = { testArbitrary: 'and-arbitrary-decoratorValue' }; 8 | 9 | beforeAll(() => { 10 | handler = Container.get(ObjectLiteralValueHandler); 11 | }); 12 | 13 | describe('given a ObjectLiteralValueHandler', () => { 14 | beforeAll(() => { 15 | property = new Property('testPropertyName', '', new PropertyDecoratorValue(OBJECT_LITERAL_VALUE)); 16 | }); 17 | 18 | describe("when calling 'shouldHandle' method with object literal", () => { 19 | test('then return true', () => { 20 | expect(handler.shouldHandle(property)).toBeTruthy(); 21 | }); 22 | }); 23 | 24 | describe("when calling 'produceValue' method", () => { 25 | test('return the exact same object literal', () => { 26 | expect(handler.produceValue(property)).toBe(OBJECT_LITERAL_VALUE); 27 | }); 28 | }); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /packages/parser/src/lib/handlers/object-literal-value-handler.ts: -------------------------------------------------------------------------------- 1 | import { Property } from '@mockingbird/reflect'; 2 | import { ValueHandler } from '../types/value-handler.interface'; 3 | import { Service } from 'typedi'; 4 | 5 | @Service() 6 | export class ObjectLiteralValueHandler implements ValueHandler { 7 | public shouldHandle(property: Property): boolean { 8 | const { decoratorValue } = property; 9 | return decoratorValue.isObject() && !decoratorValue.isMultiClass() && !decoratorValue.isEnum(); 10 | } 11 | 12 | public produceValue(propertyDto: Property): any { 13 | return propertyDto.decoratorValue.value; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/parser/src/lib/handlers/primitive-handler.ts: -------------------------------------------------------------------------------- 1 | import { Inject, Service } from 'typedi'; 2 | import { Property } from '@mockingbird/reflect'; 3 | import { ExactValue, Faker, isPrimitive } from '@mockingbird/common'; 4 | 5 | @Service() 6 | export class PrimitiveHandler { 7 | public constructor(@Inject('Faker') public readonly faker: Faker) {} 8 | 9 | generateRandomValueFromPrimitive(ctor: string): ExactValue { 10 | const { faker } = this; 11 | 12 | if (ctor === 'String') { 13 | return faker.random.alpha({ count: 10 }); 14 | } else if (ctor === 'Number') { 15 | return faker.datatype.number(1000); 16 | } else if (ctor === 'Boolean') { 17 | return faker.datatype.boolean(); 18 | } else if (ctor === 'Date') { 19 | return faker.date.recent(); 20 | } else { 21 | return faker.random.alphaNumeric(); 22 | } 23 | } 24 | 25 | public isPrimitive(propertyDto: Property): boolean { 26 | return isPrimitive(propertyDto.constructorName) && !propertyDto.decoratorValue.isCallback(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /packages/parser/src/lib/handlers/primitive-value-handler.test.ts: -------------------------------------------------------------------------------- 1 | import { Container } from 'typedi'; 2 | import { Faker } from '@mockingbird/common'; 3 | import { Property, PropertyDecoratorValue } from '@mockingbird/reflect'; 4 | import { PrimitiveValueHandler } from './primitive-value-handler'; 5 | 6 | describe('PrimitiveValueHandler Unit', () => { 7 | let handler: PrimitiveValueHandler; 8 | 9 | const fakerMock = { 10 | random: { 11 | alpha: jest.fn(), 12 | alphaNumeric: jest.fn(), 13 | }, 14 | datatype: { 15 | number: jest.fn(), 16 | boolean: jest.fn(), 17 | }, 18 | date: { 19 | recent: jest.fn(), 20 | }, 21 | setLocale: () => jest.fn(), 22 | } as unknown as Faker; 23 | 24 | beforeAll(() => { 25 | Container.set('Faker', fakerMock); 26 | handler = Container.get(PrimitiveValueHandler); 27 | }); 28 | 29 | describe('given a PrimitiveValueHandler', () => { 30 | describe("when calling 'shouldHandle' method", () => { 31 | describe('and the property type is not a function', () => { 32 | test('then return true when constructor name is a String', () => { 33 | const property = new Property('some-prop-name', 'String', new PropertyDecoratorValue(undefined)); 34 | expect(handler.shouldHandle(property)).toBeTruthy(); 35 | }); 36 | 37 | test('then return true when constructor name is a Number', () => { 38 | const property = new Property('some-prop-name', 'Number', new PropertyDecoratorValue(undefined)); 39 | expect(handler.shouldHandle(property)).toBeTruthy(); 40 | }); 41 | 42 | test('then return true when constructor name is a Boolean', () => { 43 | const property = new Property('some-prop-name', 'Boolean', new PropertyDecoratorValue(undefined)); 44 | expect(handler.shouldHandle(property)).toBeTruthy(); 45 | }); 46 | 47 | test('then return true when constructor name is a Date', () => { 48 | const property = new Property('some-prop-name', 'Date', new PropertyDecoratorValue(undefined)); 49 | expect(handler.shouldHandle(property)).toBeTruthy(); 50 | }); 51 | }); 52 | }); 53 | 54 | describe("when calling 'produceValue' method", () => { 55 | describe('and there is a decoratorValue', () => { 56 | test('then return the exact same decoratorValue', () => { 57 | let property = new Property('name', '', new PropertyDecoratorValue('TestStr')); 58 | expect(handler.produceValue(property)).toBe('TestStr'); 59 | 60 | property = new Property('name', '', new PropertyDecoratorValue(12345)); 61 | expect(handler.produceValue(property)).toBe(12345); 62 | 63 | property = new Property('name', '', new PropertyDecoratorValue(true)); 64 | expect(handler.produceValue(property)).toBe(true); 65 | }); 66 | }); 67 | 68 | describe('and the decoratorValue is including { type } inside (multi class)', () => { 69 | test('then throw an error about type mismatch', () => { 70 | const property = new Property('name', '', new PropertyDecoratorValue({ type: String, count: 3 })); 71 | expect(() => handler.produceValue(property)).toThrowError(Error); 72 | }); 73 | }); 74 | 75 | describe('and there is no decoratorValue (empty decoratorValue)', () => { 76 | describe('and the constructor is a String', () => { 77 | test('then generate a random string from faker', () => { 78 | const property = new Property('name', 'String', new PropertyDecoratorValue(undefined)); 79 | handler.produceValue(property); 80 | 81 | expect(fakerMock.random.alpha).toHaveBeenCalledTimes(1); 82 | }); 83 | }); 84 | 85 | describe('and the constructor is a Number', () => { 86 | test('then return a random number between 1 to 1000 from faker', () => { 87 | const property = new Property('name', 'Number', new PropertyDecoratorValue(undefined)); 88 | handler.produceValue(property); 89 | 90 | expect(fakerMock.datatype.number).toHaveBeenCalledTimes(1); 91 | expect(fakerMock.datatype.number).toHaveBeenCalledWith(1000); 92 | }); 93 | }); 94 | 95 | describe('and the constructor is a Boolean', () => { 96 | test('then return random boolean decoratorValue', () => { 97 | const property = new Property('name', 'Boolean', new PropertyDecoratorValue(undefined)); 98 | handler.produceValue(property); 99 | expect(fakerMock.datatype.boolean).toHaveBeenCalledTimes(1); 100 | }); 101 | }); 102 | 103 | describe('and the constructor is a Date', () => { 104 | test('then return a random date', () => { 105 | const property = new Property('name', 'Date', new PropertyDecoratorValue(undefined)); 106 | handler.produceValue(property); 107 | expect(fakerMock.date.recent).toHaveBeenCalledTimes(1); 108 | }); 109 | }); 110 | 111 | describe('and constructor is not a primitive one', () => { 112 | test('then return alpha numeric string', () => { 113 | const property = new Property('name', 'not-a-primitive', new PropertyDecoratorValue(undefined)); 114 | handler.produceValue(property); 115 | expect(fakerMock.random.alphaNumeric).toHaveBeenCalledTimes(1); 116 | }); 117 | }); 118 | }); 119 | }); 120 | }); 121 | }); 122 | -------------------------------------------------------------------------------- /packages/parser/src/lib/handlers/primitive-value-handler.ts: -------------------------------------------------------------------------------- 1 | import { Service } from 'typedi'; 2 | import { Property } from '@mockingbird/reflect'; 3 | import { PrimitiveHandler } from './primitive-handler'; 4 | import { ValueHandler } from '../types/value-handler.interface'; 5 | 6 | @Service() 7 | export class PrimitiveValueHandler implements ValueHandler { 8 | public constructor(private readonly primitiveHandler: PrimitiveHandler) {} 9 | 10 | public shouldHandle(property: Property): boolean { 11 | return this.primitiveHandler.isPrimitive(property); 12 | } 13 | 14 | public produceValue(property: Property): any { 15 | const { decoratorValue } = property; 16 | 17 | if (typeof decoratorValue.value !== 'undefined') { 18 | if (decoratorValue.isMultiClass()) { 19 | throw new Error( 20 | 'Type mismatch. Properties decorated with @Mock({ type: ClassType }) must be typed as array (e.g. prop: string[])' 21 | ); 22 | } 23 | 24 | return decoratorValue.value; 25 | } 26 | 27 | return this.primitiveHandler.generateRandomValueFromPrimitive(property.constructorName); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/parser/src/lib/handlers/regex-value-handler.test.ts: -------------------------------------------------------------------------------- 1 | import RandExp from 'randexp'; 2 | import { Container } from 'typedi'; 3 | import { Property, PropertyDecoratorValue } from '@mockingbird/reflect'; 4 | import { RegexValueHandler } from './regex-value-handler'; 5 | 6 | describe('RegexHandler Unit', () => { 7 | let property: Property; 8 | let handler: RegexValueHandler; 9 | 10 | // eslint-disable-next-line @typescript-eslint/no-empty-function 11 | function RandExpMock() {} 12 | RandExpMock.prototype.gen = jest.fn(); 13 | 14 | beforeAll(() => { 15 | property = new Property('some-prop-name', 'RegExp', new PropertyDecoratorValue(/^123$/)); 16 | }); 17 | 18 | describe('given a RegexHandler', () => { 19 | beforeAll(() => { 20 | Container.set('RandExp', RandExpMock); 21 | handler = Container.get(RegexValueHandler); 22 | }); 23 | 24 | describe("when calling 'shouldHandle'", () => { 25 | describe('and the property value is regex', () => { 26 | test('then return return true', () => { 27 | expect(handler.shouldHandle(property)).toBeTruthy(); 28 | }); 29 | }); 30 | }); 31 | 32 | describe("when calling 'produceValue'", () => { 33 | beforeAll(() => handler.produceValue(property)); 34 | 35 | test("then call 'gen' with the given regex", () => { 36 | expect(RandExpMock.prototype.gen).toHaveBeenCalledTimes(1); 37 | }); 38 | }); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /packages/parser/src/lib/handlers/regex-value-handler.ts: -------------------------------------------------------------------------------- 1 | import RandExp from 'randexp'; 2 | import { Inject, Service } from 'typedi'; 3 | import { Property } from '@mockingbird/reflect'; 4 | import { ValueHandler } from '../types/value-handler.interface'; 5 | import { Class } from '@mockingbird/common'; 6 | 7 | @Service() 8 | export class RegexValueHandler implements ValueHandler { 9 | public constructor(@Inject('RandExp') private readonly randexp: Class) {} 10 | 11 | public shouldHandle(property: Property): boolean { 12 | return property.decoratorValue.isRegex(); 13 | } 14 | 15 | public produceValue(property: Property): any { 16 | const { decoratorValue } = property; 17 | const { value: regex } = decoratorValue; 18 | 19 | const randexp = new this.randexp(regex as RegExp); 20 | return randexp.gen() as string; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/parser/src/lib/handlers/single-class-value-handler.test.ts: -------------------------------------------------------------------------------- 1 | import { Container } from 'typedi'; 2 | import { Property, PropertyDecoratorValue } from '@mockingbird/reflect'; 3 | import { Faker } from '@mockingbird/common'; 4 | import { SingleClassValueHandler } from './single-class-value-handler'; 5 | 6 | describe('SingleClassValueHandler Unit', () => { 7 | let handler: SingleClassValueHandler; 8 | 9 | const DTO_CLASS_VALUE = class TestClass {}; 10 | const property = new Property('testPropertyName', 'TestClass', new PropertyDecoratorValue(DTO_CLASS_VALUE)); 11 | 12 | beforeAll(() => { 13 | Container.set('Faker', Faker); 14 | handler = Container.get(SingleClassValueHandler); 15 | }); 16 | 17 | describe('given a SingleClassValueHandler', () => { 18 | describe("when calling 'shouldHandle' with a none-primitive, 'function' type", () => { 19 | test('then return true', () => { 20 | expect(handler.shouldHandle(property)).toBeTruthy(); 21 | }); 22 | }); 23 | 24 | describe("when calling 'produceValue' method", () => { 25 | test("then call 'parse' with the given class", () => { 26 | expect(handler.produceValue(property)).toBeInstanceOf(DTO_CLASS_VALUE); 27 | }); 28 | }); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /packages/parser/src/lib/handlers/single-class-value-handler.ts: -------------------------------------------------------------------------------- 1 | import { Container, Service } from 'typedi'; 2 | import { Property } from '@mockingbird/reflect'; 3 | import { Class, isPrimitive } from '@mockingbird/common'; 4 | import { ValueHandler } from '../types/value-handler.interface'; 5 | import { ClassParser } from '../parser/class-parser'; 6 | 7 | @Service() 8 | export class SingleClassValueHandler implements ValueHandler { 9 | public shouldHandle(property: Property): boolean { 10 | return property.decoratorValue.isCallback() && !isPrimitive(property.constructorName); 11 | } 12 | 13 | public produceValue(property: Property): TClass { 14 | const analyzer = Container.get(ClassParser); 15 | return analyzer.parse(property.decoratorValue.value as Class); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/parser/src/lib/parser/class-parser.test.ts: -------------------------------------------------------------------------------- 1 | import RandExp from 'randexp'; 2 | import { Container } from 'typedi'; 3 | import { Mock } from '@mockingbird/reflect'; 4 | import { Faker } from '@mockingbird/common'; 5 | import { ClassParser } from './class-parser'; 6 | 7 | describe('ClassParser Integration Test', () => { 8 | class Child { 9 | @Mock() str: string; 10 | } 11 | 12 | class Bird { 13 | @Mock() name = 'default-name'; 14 | @Mock() isAwesome: boolean; 15 | @Mock() rating: number; 16 | @Mock(Child) child: Child; 17 | } 18 | 19 | const fakerMock: jest.Mocked> = { 20 | setLocale: jest.fn(), 21 | datatype: { boolean: () => true, number: () => 12345 } as jest.Mocked, 22 | random: { alpha: jest.fn() } as unknown as jest.Mocked, 23 | name: { firstName: jest.fn().mockReturnValueOnce('FIRST_NAME') } as any, 24 | }; 25 | 26 | let parser: ClassParser; 27 | 28 | beforeAll(() => { 29 | Container.set('Faker', fakerMock); 30 | Container.set('RandExp', RandExp); 31 | 32 | parser = Container.get(ClassParser); 33 | }); 34 | 35 | describe('creating a new mock', () => { 36 | scenario('with no target class', () => { 37 | then('throw an error indicating that no target class has been passed', () => { 38 | expect(() => parser.parse(undefined)).toThrowError(); 39 | }); 40 | }); 41 | 42 | describe('with target class and no config', () => { 43 | let returnValue; 44 | 45 | when('config includes mutations', () => { 46 | beforeAll(() => { 47 | returnValue = parser.parse(Bird, { mutations: { name: 'Houdini' } }); 48 | }); 49 | 50 | test("then return an instance where the 'name' property is 'Houdini'", () => { 51 | expect(returnValue.name).toBe('Houdini'); 52 | }); 53 | }); 54 | 55 | when('config includes mutations with callback', () => { 56 | beforeAll(() => { 57 | returnValue = parser.parse(Bird, { 58 | mutations: (faker) => ({ name: faker.name.firstName() }), 59 | }); 60 | }); 61 | 62 | test('then call faker firstName method', () => { 63 | expect(fakerMock.name.firstName).toHaveBeenCalledTimes(1); 64 | }); 65 | 66 | test("then set the value of prop 'name' to be faker firstName return value", () => { 67 | expect(returnValue.name).toBe('FIRST_NAME'); 68 | }); 69 | }); 70 | 71 | when('config includes omit keys', () => { 72 | beforeAll(() => { 73 | returnValue = parser.parse(Bird, { omit: ['name'] }); 74 | }); 75 | 76 | then('return the default value of the instance', () => { 77 | expect(returnValue.name).toBe('default-name'); 78 | }); 79 | }); 80 | 81 | describe('config includes pick keys', () => { 82 | beforeAll(() => { 83 | returnValue = parser.parse(Bird, { pick: ['rating'] }); 84 | }); 85 | 86 | then('return a mock with this keys only', () => { 87 | expect(returnValue).toHaveProperty('rating'); 88 | expect(returnValue).not.toHaveProperty('isAwesome'); 89 | expect(returnValue).not.toHaveProperty('child'); 90 | }); 91 | 92 | then('leave the properties with default value', () => { 93 | expect(returnValue).toHaveProperty('name'); 94 | expect(returnValue.name).toBe('default-name'); 95 | }); 96 | }); 97 | 98 | when('config includes both config and omit keys', () => { 99 | then('throw an error indicating that can not use both at the same time', () => { 100 | expect(() => parser.parse(Bird, { pick: ['name'], omit: ['name'] })).toThrowError(); 101 | }); 102 | }); 103 | 104 | then('return an (actual) instance of the class', () => { 105 | returnValue = parser.parse(Bird); 106 | expect(returnValue).toBeInstanceOf(Bird); 107 | }); 108 | }); 109 | }); 110 | 111 | scenario('set a faker locale', () => { 112 | beforeAll(() => parser.setLocale('jp')); 113 | 114 | test('then call faker locale function', () => { 115 | expect(fakerMock.setLocale).toHaveBeenCalledWith('jp'); 116 | }); 117 | }); 118 | }); 119 | -------------------------------------------------------------------------------- /packages/parser/src/lib/parser/class-parser.ts: -------------------------------------------------------------------------------- 1 | import { Container, Inject, Service } from 'typedi'; 2 | import { ClassReflector, Property } from '@mockingbird/reflect'; 3 | import { Class, Faker } from '@mockingbird/common'; 4 | import { MutationsCallback, ParserConfig, ParsingStrategy } from '../types/types'; 5 | import { ValueHandler } from '../types/value-handler.interface'; 6 | import { EnumValueHandler } from '../handlers/enum-value-handler'; 7 | import { ArrayValueHandler } from '../handlers/array-value-handler'; 8 | import { SingleClassValueHandler } from '../handlers/single-class-value-handler'; 9 | import { CallbackValueHandler } from '../handlers/callback-value-handler'; 10 | import { ObjectLiteralValueHandler } from '../handlers/object-literal-value-handler'; 11 | import { PrimitiveValueHandler } from '../handlers/primitive-value-handler'; 12 | import { RegexValueHandler } from '../handlers/regex-value-handler'; 13 | 14 | @Service() 15 | export class ClassParser { 16 | private readonly valueHandlers: Class[] = [ 17 | EnumValueHandler, 18 | ArrayValueHandler, 19 | SingleClassValueHandler, 20 | CallbackValueHandler, 21 | RegexValueHandler, 22 | ObjectLiteralValueHandler, 23 | PrimitiveValueHandler, 24 | ]; 25 | 26 | public constructor(@Inject('Faker') private readonly faker: Faker) {} 27 | 28 | private handlePropertyValue(property: Property): TClass | TClass[] { 29 | for (const classHandler of this.valueHandlers) { 30 | const handler = Container.get(classHandler); 31 | 32 | if (handler.shouldHandle(property)) { 33 | return handler.produceValue(property); 34 | } 35 | } 36 | } 37 | 38 | public parse(targetClass: Class, config: ParserConfig = {}): TClass { 39 | const classReflection = ClassReflector.getInstance().reflectClass(targetClass); 40 | 41 | const { omit = [], pick = [] } = config; 42 | let { mutations = {} } = config; 43 | let strategy: ParsingStrategy; 44 | 45 | if (omit.length) { 46 | strategy = 'omit'; 47 | } else if (pick.length) { 48 | strategy = 'pick'; 49 | } 50 | 51 | if (omit.length && pick.length) { 52 | throw new Error('Can not use pick and omit at the same time'); 53 | } 54 | 55 | if (typeof mutations === 'function') { 56 | mutations = (mutations as MutationsCallback)(this.faker); 57 | } 58 | 59 | const deriveFromProps = (acc, property) => { 60 | let value; 61 | 62 | if (mutations.hasOwnProperty(property.name)) { 63 | value = mutations[property.name]; 64 | } 65 | 66 | if (strategy == 'pick') { 67 | if (pick.includes(property.name)) { 68 | return { ...acc, [property.name]: value || this.handlePropertyValue(property) }; 69 | } 70 | 71 | return acc; 72 | } 73 | 74 | if (omit.includes(property.name) && strategy == 'omit') { 75 | return acc; 76 | } 77 | 78 | return { ...acc, [property.name]: value || this.handlePropertyValue(property) }; 79 | }; 80 | 81 | const derivedProps = classReflection.reduce(deriveFromProps, {}); 82 | return Object.assign(new targetClass(), derivedProps); 83 | } 84 | 85 | public setLocale(locale: string): void { 86 | this.faker.setLocale(locale); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /packages/parser/src/lib/types/mock-generator-options.interface.ts: -------------------------------------------------------------------------------- 1 | import { ParserConfig } from '@mockingbird/parser'; 2 | import { Faker } from '@mockingbird/common'; 3 | 4 | export interface MockGeneratorOptions extends ParserConfig { 5 | count?: number; 6 | locale?: Faker['locale']; 7 | plain?: boolean; 8 | } 9 | -------------------------------------------------------------------------------- /packages/parser/src/lib/types/types.ts: -------------------------------------------------------------------------------- 1 | import { Faker, OptionalClassValues } from '@mockingbird/common'; 2 | 3 | export type MutationsCallback = (faker: Faker) => OptionalClassValues; 4 | 5 | export interface ParserConfig { 6 | mutations?: OptionalClassValues | MutationsCallback; 7 | omit?: (keyof TClass)[]; 8 | pick?: (keyof TClass)[]; 9 | } 10 | 11 | export type ParsingStrategy = 'pick' | 'omit' | undefined; 12 | -------------------------------------------------------------------------------- /packages/parser/src/lib/types/value-handler.interface.ts: -------------------------------------------------------------------------------- 1 | import { Property } from '@mockingbird/reflect'; 2 | 3 | export interface ValueHandler { 4 | shouldHandle(property: Property): boolean; 5 | produceValue(property: Property): T | T[]; 6 | } 7 | -------------------------------------------------------------------------------- /packages/parser/test/integration/__snapshots__/mock-generator.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`MockGenerator - Integration Test given a decorated class Scenario: mock decorator with absolute values then return the exact same values passed in the options of the mock decorator 1`] = ` 4 | Object { 5 | "binary": true, 6 | "date": Any, 7 | "name": "FooBar", 8 | "num": 1234, 9 | "objectLiteral": Object { 10 | "an": "object", 11 | "literal": true, 12 | "thiss": "is", 13 | }, 14 | } 15 | `; 16 | 17 | exports[`MockGenerator - Integration Test given a decorated class Scenario: mock decorator with no/empty values then infer the decoratorValue from the type itself 1`] = ` 18 | Object { 19 | "binary": Any, 20 | "date": Any, 21 | "name": Any, 22 | "num": Any, 23 | } 24 | `; 25 | -------------------------------------------------------------------------------- /packages/parser/test/integration/common/test-classes.ts: -------------------------------------------------------------------------------- 1 | import { Mock } from 'mockingbird'; 2 | 3 | enum TestEnum { 4 | Foo = 'foo', 5 | Bar = 111, 6 | Bazz = 'Bazz1234', 7 | } 8 | 9 | export namespace TestClasses { 10 | export class TestClassWithAbsoluteValues { 11 | @Mock('FooBar') 12 | name: string; 13 | 14 | @Mock(1234) 15 | num: number; 16 | 17 | @Mock(true) 18 | binary: boolean; 19 | 20 | @Mock(new Date()) 21 | date: Date; 22 | 23 | @Mock({ thiss: 'is', an: 'object', literal: true }) 24 | objectLiteral: Record; 25 | } 26 | 27 | export class TestClassWithCallback { 28 | @Mock((faker) => faker.internet.email()) 29 | email: string; 30 | 31 | @Mock((faker) => faker.name.firstName()) 32 | name: string; 33 | } 34 | 35 | export interface TestClassWithNoValuesInterface { 36 | name: string; 37 | num: number; 38 | binary: boolean; 39 | date: Date; 40 | } 41 | 42 | export class TestClassWithNoValues implements TestClassWithNoValuesInterface { 43 | @Mock() 44 | name: string; 45 | 46 | @Mock() 47 | num: number; 48 | 49 | @Mock() 50 | binary: boolean; 51 | 52 | @Mock() 53 | date: Date; 54 | } 55 | 56 | export class TestClassWithEnum { 57 | @Mock({ enum: TestEnum }) 58 | someEnumVal: string; 59 | } 60 | 61 | class Dog { 62 | @Mock() 63 | name: string; 64 | 65 | @Mock() 66 | points: number; 67 | } 68 | 69 | export class TestClassWithSingleClass { 70 | @Mock(Dog) 71 | dog: Dog; 72 | } 73 | 74 | export class TestClassWithMultiClass { 75 | @Mock({ type: Dog, count: 3 }) 76 | dogs: Dog[]; 77 | } 78 | 79 | export class TestClassWithRegex { 80 | @Mock(/1234/) 81 | prop1: string; 82 | 83 | @Mock(/^regex$/) 84 | prop2: string; 85 | 86 | @Mock(/^[a-z]{4,5}$/) 87 | prop3: string; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /packages/parser/test/integration/mock-generator.test.ts: -------------------------------------------------------------------------------- 1 | import { mockGenerator } from '@mockingbird/parser'; 2 | import { TestClasses } from './common/test-classes'; 3 | 4 | import TestClassWithAbsoluteValues = TestClasses.TestClassWithAbsoluteValues; 5 | import TestClassWithNoValues = TestClasses.TestClassWithNoValues; 6 | import TestClassWithCallback = TestClasses.TestClassWithCallback; 7 | import TestClassWithEnum = TestClasses.TestClassWithEnum; 8 | import TestClassWithOtherClass = TestClasses.TestClassWithSingleClass; 9 | import TestClassWithMultiClass = TestClasses.TestClassWithMultiClass; 10 | import TestClassWithRegex = TestClasses.TestClassWithRegex; 11 | 12 | describe('MockGenerator - Integration Test', () => { 13 | let result; 14 | 15 | describe('given a decorated class', () => { 16 | scenario('mock decorator with absolute values', () => { 17 | beforeAll(() => { 18 | result = mockGenerator.generate(TestClassWithAbsoluteValues); 19 | }); 20 | 21 | test('then return the exact same values passed in the options of the mock decorator', () => { 22 | expect(result).toMatchSnapshot({ 23 | date: expect.any(Date), 24 | }); 25 | }); 26 | 27 | describe('and adding mutation keys', () => { 28 | beforeAll(() => { 29 | result = mockGenerator.generate(TestClassWithAbsoluteValues, { mutations: { name: 'Override Name' } }); 30 | }); 31 | 32 | test('then return the same absolute value expect the constant name added from overrides', () => { 33 | expect(result.name).toBe('Override Name'); 34 | }); 35 | }); 36 | 37 | describe('and adding omit keys', () => { 38 | beforeAll(() => { 39 | result = mockGenerator.generate(TestClassWithAbsoluteValues, { omit: ['name'] }); 40 | }); 41 | 42 | test('then return the same absolute value expect the constant name added from overrides', () => { 43 | expect(result.name).toBeUndefined(); 44 | }); 45 | }); 46 | }); 47 | 48 | scenario('mock decorator with a callback (faker)', () => { 49 | beforeAll(() => { 50 | result = mockGenerator.generate(TestClassWithCallback); 51 | }); 52 | 53 | test('then return random values from faker', () => { 54 | expect(result).toMatchObject({ 55 | email: expect.any(String), 56 | name: expect.any(String), 57 | }); 58 | }); 59 | }); 60 | 61 | scenario('mock decorator with an enum decoratorValue', () => { 62 | beforeAll(() => { 63 | result = mockGenerator.generate(TestClassWithEnum); 64 | }); 65 | 66 | test('then return one random decoratorValue (not key)', () => { 67 | expect(['foo', 111, 'Bazz1234']).toContain(result.someEnumVal); 68 | }); 69 | }); 70 | 71 | scenario('mock decorator with no/empty values', () => { 72 | beforeAll(() => { 73 | result = mockGenerator.generate(TestClassWithNoValues); 74 | }); 75 | 76 | test('then infer the decoratorValue from the type itself', () => { 77 | expect(result).toMatchSnapshot({ 78 | name: expect.any(String), 79 | num: expect.any(Number), 80 | binary: expect.any(Boolean), 81 | date: expect.any(Date), 82 | }); 83 | }); 84 | }); 85 | 86 | scenario('mock decorator with a single class', () => { 87 | beforeAll(() => { 88 | result = mockGenerator.generate(TestClassWithOtherClass); 89 | }); 90 | 91 | test('then return an object with the given class', () => { 92 | expect(Object.keys(result.dog)).toEqual(['name', 'points']); 93 | }); 94 | }); 95 | 96 | describe('mock decorator with a regex', () => { 97 | beforeAll(() => { 98 | result = mockGenerator.generate(TestClassWithRegex); 99 | }); 100 | 101 | test('then return string generated to match the regex', () => { 102 | expect(result.prop1).toBe('1234'); 103 | expect(result.prop2).toBe('regex'); 104 | expect(result.prop2).toMatch(/^[a-z]{4,5}$/); 105 | }); 106 | }); 107 | 108 | scenario('mock decorator with a multi class', () => { 109 | beforeAll(() => { 110 | result = mockGenerator.generate(TestClassWithMultiClass); 111 | }); 112 | 113 | test("then return contain a property 'dogs' which is array of Dog with length of 'count'", () => { 114 | expect(result.dogs).toBeInstanceOf(Array); 115 | expect(result.dogs).toHaveLength(3); 116 | }); 117 | 118 | test('then return array of objects with the given class keys', () => { 119 | expect(result.dogs).toEqual( 120 | expect.arrayContaining([expect.objectContaining({ name: expect.any(String), points: expect.any(Number) })]) 121 | ); 122 | }); 123 | }); 124 | 125 | scenario("mock decorator with 'count' option", () => { 126 | beforeAll(() => { 127 | result = mockGenerator.generate(TestClassWithAbsoluteValues, { count: 4, locale: 'ja' }); 128 | }); 129 | 130 | test("then return array with length of 'count'", () => { 131 | expect(result).toBeInstanceOf(Array); 132 | expect(result).toHaveLength(4); 133 | }); 134 | }); 135 | }); 136 | }); 137 | -------------------------------------------------------------------------------- /packages/parser/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "rootDir": "./src", 6 | "outDir": "./dist", 7 | "target": "es6" 8 | }, 9 | "exclude": [ 10 | "node_modules", 11 | "test", 12 | "src/**/*.test.ts" 13 | ], 14 | "include": ["src/"] 15 | } -------------------------------------------------------------------------------- /packages/reflect/.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | jest.config.js -------------------------------------------------------------------------------- /packages/reflect/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../.eslintrc" 3 | } -------------------------------------------------------------------------------- /packages/reflect/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [3.0.2](https://github.com/omermorad/mockingbird/compare/@mockingbird/reflect@3.0.2-rc.3...@mockingbird/reflect@3.0.2) (2021-12-08) 7 | 8 | **Note:** Version bump only for package @mockingbird/reflect 9 | 10 | 11 | 12 | 13 | 14 | ## [3.0.2-rc.3](https://github.com/omermorad/mockingbird/compare/@mockingbird/reflect@3.0.2-rc.1...@mockingbird/reflect@3.0.2-rc.3) (2021-11-18) 15 | 16 | **Note:** Version bump only for package @mockingbird/reflect 17 | 18 | 19 | 20 | 21 | 22 | ## [3.0.2-rc.2](https://github.com/omermorad/mockingbird/compare/@mockingbird/reflect@3.0.2-rc.1...@mockingbird/reflect@3.0.2-rc.2) (2021-11-18) 23 | 24 | **Note:** Version bump only for package @mockingbird/reflect 25 | 26 | 27 | 28 | 29 | 30 | ## 3.0.2-rc.1 (2021-11-17) 31 | 32 | 33 | ### Features 34 | 35 | * **parser:** add regex functionality/handler ([#98](https://github.com/omermorad/mockingbird/issues/98)) ([ae1bac8](https://github.com/omermorad/mockingbird/commit/ae1bac8629047385741f85620a725405a3c3fa27)) 36 | * **reflect:** add regex to mock decorator value options ([055dbd9](https://github.com/omermorad/mockingbird/commit/055dbd906f8e59a796f49842d9b3003b3a95c2cb)) 37 | 38 | 39 | 40 | ## 2.1.1 (2021-08-21) 41 | 42 | 43 | ### Bug Fixes 44 | 45 | * fix broken packages because of 'types' (instead common) ([#94](https://github.com/omermorad/mockingbird/issues/94)) ([fca274a](https://github.com/omermorad/mockingbird/commit/fca274aca495251b9b74a51f99f4e15c6fae5a4c)) 46 | 47 | 48 | 49 | # 2.1.0 (2021-08-21) 50 | 51 | 52 | ### Reverts 53 | 54 | * Revert "chore(packages): version packages [skip ci]" ([5cbc7d6](https://github.com/omermorad/mockingbird/commit/5cbc7d67c5a62343c65fb1401e73df505cbadf52)) 55 | 56 | 57 | 58 | # 2.0.0 (2021-07-31) 59 | 60 | 61 | ### chore 62 | 63 | * **release:** release version v2.0.0 ([#53](https://github.com/omermorad/mockingbird/issues/53)) ([f598ef3](https://github.com/omermorad/mockingbird/commit/f598ef35d5b9111f66202f119b8961314483f4fb)), closes [#51](https://github.com/omermorad/mockingbird/issues/51) [#40](https://github.com/omermorad/mockingbird/issues/40) [#42](https://github.com/omermorad/mockingbird/issues/42) [#37](https://github.com/omermorad/mockingbird/issues/37) [#46](https://github.com/omermorad/mockingbird/issues/46) [#47](https://github.com/omermorad/mockingbird/issues/47) [#49](https://github.com/omermorad/mockingbird/issues/49) [#50](https://github.com/omermorad/mockingbird/issues/50) [#52](https://github.com/omermorad/mockingbird/issues/52) [#54](https://github.com/omermorad/mockingbird/issues/54) [#42](https://github.com/omermorad/mockingbird/issues/42) [#55](https://github.com/omermorad/mockingbird/issues/55) [#42](https://github.com/omermorad/mockingbird/issues/42) [#56](https://github.com/omermorad/mockingbird/issues/56) [#57](https://github.com/omermorad/mockingbird/issues/57) [#58](https://github.com/omermorad/mockingbird/issues/58) [#59](https://github.com/omermorad/mockingbird/issues/59) [#60](https://github.com/omermorad/mockingbird/issues/60) [#42](https://github.com/omermorad/mockingbird/issues/42) [#61](https://github.com/omermorad/mockingbird/issues/61) [#62](https://github.com/omermorad/mockingbird/issues/62) [#64](https://github.com/omermorad/mockingbird/issues/64) [#63](https://github.com/omermorad/mockingbird/issues/63) [#67](https://github.com/omermorad/mockingbird/issues/67) [#68](https://github.com/omermorad/mockingbird/issues/68) 64 | 65 | 66 | ### BREAKING CHANGES 67 | 68 | * **release:** MockFactory is now an instance (TClass) and not ClassLiteral 69 | 70 | * chore: fix typo in the test name 71 | 72 | * chore: change methods order 73 | 74 | * chore: added source map and some jest configs 75 | 76 | * refactor: change some var names and error 77 | 78 | * test(class-processor): refactor test turning into integration instead of unit 79 | 80 | * chore(lib): move files into lib folder and change imports 81 | 82 | * feat(fluent-api): add fluent api (builder) functionality and persistence 83 | 84 | Add fluent API to enable methods chaining with ability to persist the mock 85 | * **release:** MockFactory is now a function and not a class, changed the original to 86 | MockGenerator. Add fluent API and ability to persist mock data 87 | * **release:** MockFactory changed to be MockGenerator 88 | * **release:** MockFactory changed to be MockGenerator 89 | * **release:** MockGenerator is not exported anymore, use MockFactory instead 90 | 91 | 92 | 93 | 94 | 95 | ## 3.0.2-rc.0 (2021-11-13) 96 | 97 | **Note:** Version bump only for package @mockingbird/reflect 98 | 99 | 100 | 101 | 102 | 103 | ## [3.0.1](https://github.com/omermorad/mockingbird/compare/@mockingbird/reflect@3.0.0...@mockingbird/reflect@3.0.1) (2021-08-21) 104 | 105 | 106 | ### Bug Fixes 107 | 108 | * fix broken packages because of 'types' (instead common) ([#94](https://github.com/omermorad/mockingbird/issues/94)) ([fca274a](https://github.com/omermorad/mockingbird/commit/fca274aca495251b9b74a51f99f4e15c6fae5a4c)) 109 | 110 | 111 | 112 | 113 | 114 | # 3.0.0 (2021-08-21) 115 | 116 | 117 | ### Reverts 118 | 119 | * Revert "chore(packages): version packages [skip ci]" ([5cbc7d6](https://github.com/omermorad/mockingbird/commit/5cbc7d67c5a62343c65fb1401e73df505cbadf52)) 120 | 121 | 122 | 123 | # 2.0.0 (2021-07-31) 124 | 125 | 126 | ### chore 127 | 128 | * **release:** release version v2.0.0 ([#53](https://github.com/omermorad/mockingbird/issues/53)) ([f598ef3](https://github.com/omermorad/mockingbird/commit/f598ef35d5b9111f66202f119b8961314483f4fb)), closes [#51](https://github.com/omermorad/mockingbird/issues/51) [#40](https://github.com/omermorad/mockingbird/issues/40) [#42](https://github.com/omermorad/mockingbird/issues/42) [#37](https://github.com/omermorad/mockingbird/issues/37) [#46](https://github.com/omermorad/mockingbird/issues/46) [#47](https://github.com/omermorad/mockingbird/issues/47) [#49](https://github.com/omermorad/mockingbird/issues/49) [#50](https://github.com/omermorad/mockingbird/issues/50) [#52](https://github.com/omermorad/mockingbird/issues/52) [#54](https://github.com/omermorad/mockingbird/issues/54) [#42](https://github.com/omermorad/mockingbird/issues/42) [#55](https://github.com/omermorad/mockingbird/issues/55) [#42](https://github.com/omermorad/mockingbird/issues/42) [#56](https://github.com/omermorad/mockingbird/issues/56) [#57](https://github.com/omermorad/mockingbird/issues/57) [#58](https://github.com/omermorad/mockingbird/issues/58) [#59](https://github.com/omermorad/mockingbird/issues/59) [#60](https://github.com/omermorad/mockingbird/issues/60) [#42](https://github.com/omermorad/mockingbird/issues/42) [#61](https://github.com/omermorad/mockingbird/issues/61) [#62](https://github.com/omermorad/mockingbird/issues/62) [#64](https://github.com/omermorad/mockingbird/issues/64) [#63](https://github.com/omermorad/mockingbird/issues/63) [#67](https://github.com/omermorad/mockingbird/issues/67) [#68](https://github.com/omermorad/mockingbird/issues/68) 129 | 130 | 131 | ### BREAKING CHANGES 132 | 133 | * **release:** MockFactory is now an instance (TClass) and not ClassLiteral 134 | 135 | * chore: fix typo in the test name 136 | 137 | * chore: change methods order 138 | 139 | * chore: added source map and some jest configs 140 | 141 | * refactor: change some var names and error 142 | 143 | * test(class-processor): refactor test turning into integration instead of unit 144 | 145 | * chore(lib): move files into lib folder and change imports 146 | 147 | * feat(fluent-api): add fluent api (builder) functionality and persistence 148 | 149 | Add fluent API to enable methods chaining with ability to persist the mock 150 | * **release:** MockFactory is now a function and not a class, changed the original to 151 | MockGenerator. Add fluent API and ability to persist mock data 152 | * **release:** MockFactory changed to be MockGenerator 153 | * **release:** MockFactory changed to be MockGenerator 154 | * **release:** MockGenerator is not exported anymore, use MockFactory instead 155 | 156 | 157 | 158 | 159 | 160 | # 2.0.0 (2021-07-31) 161 | 162 | 163 | ### chore 164 | 165 | * **release:** release version v2.0.0 ([#53](https://github.com/omermorad/mockingbird/issues/53)) ([f598ef3](https://github.com/omermorad/mockingbird/commit/f598ef35d5b9111f66202f119b8961314483f4fb)), closes [#51](https://github.com/omermorad/mockingbird/issues/51) [#40](https://github.com/omermorad/mockingbird/issues/40) [#42](https://github.com/omermorad/mockingbird/issues/42) [#37](https://github.com/omermorad/mockingbird/issues/37) [#46](https://github.com/omermorad/mockingbird/issues/46) [#47](https://github.com/omermorad/mockingbird/issues/47) [#49](https://github.com/omermorad/mockingbird/issues/49) [#50](https://github.com/omermorad/mockingbird/issues/50) [#52](https://github.com/omermorad/mockingbird/issues/52) [#54](https://github.com/omermorad/mockingbird/issues/54) [#42](https://github.com/omermorad/mockingbird/issues/42) [#55](https://github.com/omermorad/mockingbird/issues/55) [#42](https://github.com/omermorad/mockingbird/issues/42) [#56](https://github.com/omermorad/mockingbird/issues/56) [#57](https://github.com/omermorad/mockingbird/issues/57) [#58](https://github.com/omermorad/mockingbird/issues/58) [#59](https://github.com/omermorad/mockingbird/issues/59) [#60](https://github.com/omermorad/mockingbird/issues/60) [#42](https://github.com/omermorad/mockingbird/issues/42) [#61](https://github.com/omermorad/mockingbird/issues/61) [#62](https://github.com/omermorad/mockingbird/issues/62) [#64](https://github.com/omermorad/mockingbird/issues/64) [#63](https://github.com/omermorad/mockingbird/issues/63) [#67](https://github.com/omermorad/mockingbird/issues/67) [#68](https://github.com/omermorad/mockingbird/issues/68) 166 | 167 | 168 | ### BREAKING CHANGES 169 | 170 | * **release:** MockFactory is now an instance (TClass) and not ClassLiteral 171 | 172 | * chore: fix typo in the test name 173 | 174 | * chore: change methods order 175 | 176 | * chore: added source map and some jest configs 177 | 178 | * refactor: change some var names and error 179 | 180 | * test(class-processor): refactor test turning into integration instead of unit 181 | 182 | * chore(lib): move files into lib folder and change imports 183 | 184 | * feat(fluent-api): add fluent api (builder) functionality and persistence 185 | 186 | Add fluent API to enable methods chaining with ability to persist the mock 187 | * **release:** MockFactory is now a function and not a class, changed the original to 188 | MockGenerator. Add fluent API and ability to persist mock data 189 | * **release:** MockFactory changed to be MockGenerator 190 | * **release:** MockFactory changed to be MockGenerator 191 | * **release:** MockGenerator is not exported anymore, use MockFactory instead 192 | 193 | 194 | 195 | 196 | 197 | ## [1.0.1-alpha.3](https://github.com/omermorad/mockingbird/compare/@mockingbird/reflect@1.0.1-alpha.2...@mockingbird/reflect@1.0.1-alpha.3) (2021-07-23) 198 | 199 | **Note:** Version bump only for package @mockingbird/reflect 200 | 201 | 202 | 203 | 204 | 205 | ## 1.0.1-alpha.2 (2021-07-23) 206 | 207 | 208 | ### Bug Fixes 209 | 210 | * **types:** add build to export a js file to include the faker instance (for runtime) ([#61](https://github.com/omermorad/mockingbird/issues/61)) ([f4e3092](https://github.com/omermorad/mockingbird/commit/f4e3092e683eb9c288d4e879113e71f74ec5038a)) 211 | 212 | 213 | ### Reverts 214 | 215 | * **repo:** release packages ([7f9390d](https://github.com/omermorad/mockingbird/commit/7f9390d051f9c9c9c3eb172f4db8a9fe533b03c4)) 216 | -------------------------------------------------------------------------------- /packages/reflect/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omermorad/mockingbird/421428336b06b0353dcb9a53c7f0c344bd03c95a/packages/reflect/README.md -------------------------------------------------------------------------------- /packages/reflect/index.ts: -------------------------------------------------------------------------------- 1 | export * from './src'; 2 | -------------------------------------------------------------------------------- /packages/reflect/jest.config.js: -------------------------------------------------------------------------------- 1 | const base = require('../../jest.config.base'); 2 | const packageJson = require('./package'); 3 | 4 | module.exports = { 5 | ...base, 6 | name: packageJson.name, 7 | displayName: packageJson.name, 8 | collectCoverageFrom: ['src/**/*.ts', 'test/**/*.test.js'], 9 | coveragePathIgnorePatterns: ['index.ts'], 10 | }; -------------------------------------------------------------------------------- /packages/reflect/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mockingbird/reflect", 3 | "version": "3.0.2", 4 | "license": "MIT", 5 | "description": "Mockingbird Reflect Package", 6 | "main": "dist/index.js", 7 | "types": "dist/index.d.ts", 8 | "contributors": [ 9 | { 10 | "name": "Omer Morad", 11 | "email": "omer.moradd@gmail.com" 12 | }, 13 | { 14 | "name": "Idan Ptichi", 15 | "email": "idanpt@gmail.com" 16 | } 17 | ], 18 | "repository": { 19 | "type": "git", 20 | "url": "https://github.com/omermorad/mockingbird.git" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/omermorad/mockingbird/issues" 24 | }, 25 | "readme": "https://github.com/omermorad/mockingbird/tree/refactor/master/packages/reflect/README.md", 26 | "scripts": { 27 | "prebuild": "npx rimraf dist", 28 | "build": "tsc", 29 | "watch": "tsc --watch", 30 | "test": "jest --runInBand --verbose", 31 | "lint": "eslint '{src,test}/**/*.ts'", 32 | "lint:fix": "eslint '{src,test}/**/*.ts' --fix" 33 | }, 34 | "files": [ 35 | "index.d.ts", 36 | "index.js", 37 | "dist", 38 | "CHANGELOG.md" 39 | ], 40 | "dependencies": { 41 | "@plumier/reflect": "^1.0.5", 42 | "reflect-metadata": "^0.1.13", 43 | "tslib": "^2.3.0" 44 | }, 45 | "devDependencies": { 46 | "@mockingbird/common": "^2.0.3", 47 | "jest": "27.0.6", 48 | "rimraf": "^3.0.2", 49 | "ts-jest": "^27.0.3", 50 | "ts-loader": "^6.2.2", 51 | "ts-node": "8.10.2", 52 | "tsconfig-paths": "^3.9.0", 53 | "typescript": "^3.9.7" 54 | }, 55 | "publishConfig": { 56 | "access": "public" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /packages/reflect/src/decorators/index.ts: -------------------------------------------------------------------------------- 1 | export { Mock } from './mock.decorator'; 2 | -------------------------------------------------------------------------------- /packages/reflect/src/decorators/mock.decorator.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | import { Callback, EnumObject, ExactValue, MultiClass } from '@mockingbird/common'; 3 | import { Class, decorateProperty } from '@plumier/reflect'; 4 | import { MockOptions } from '../types'; 5 | 6 | export const MOCK_DECORATOR_NAME = 'Mock'; 7 | 8 | /** 9 | * Using undefined (or nothing actually) will infer the value from the property type. 10 | * The types can be either 'string', 'number' or a 'boolean' 11 | * 12 | * @constructor 13 | */ 14 | export function Mock(): PropertyDecorator; 15 | 16 | /** 17 | * Will invoke the callback and generate a value from 'faker' instance 18 | * 19 | * @example 20 | * Mock(faker => faker.internet.email()) 21 | * 22 | * @param callback 23 | * @constructor 24 | */ 25 | export function Mock(callback: Callback): PropertyDecorator; 26 | 27 | /** 28 | * Generate an object of the given class (who's properties can be decorated with Mock() as well) 29 | * 30 | * @example 31 | * class Dog { ... } 32 | * Mock(Dog) 33 | * 34 | * @constructor 35 | * @param targetClass 36 | */ 37 | export function Mock(targetClass: Class): PropertyDecorator; 38 | 39 | /** 40 | * Generate a random value from the given enum 41 | * 42 | * @example 43 | * enum Feeling { Happy, Sad, Numb } 44 | * Mock(Feeling) 45 | * 46 | * @param options: { enum: object } 47 | * @constructor 48 | */ 49 | export function Mock(options: EnumObject): PropertyDecorator; 50 | 51 | /** 52 | * Generate multiple objects of the given class (who's properties can be decorated with Mock() as well) 53 | * 54 | * @param options: { type: ClassType; count: number } 55 | * @constructor 56 | */ 57 | export function Mock(options: MultiClass): PropertyDecorator; 58 | 59 | /** 60 | * Generate a value from regex 61 | * 62 | * @param regex {RegExp} 63 | * @constructor 64 | */ 65 | export function Mock(regex: RegExp): PropertyDecorator; 66 | 67 | /** 68 | * Generate the exact given decoratorValue 69 | * 70 | * @example 71 | * Mock(123) 72 | * Mock('Johnny') 73 | * Mock(true) 74 | * 75 | * @param value 76 | * @constructor 77 | */ 78 | export function Mock(value: ExactValue): PropertyDecorator; 79 | 80 | /** 81 | * Mock property decorator. The options passed will determine the decorated property's generated value 82 | * 83 | * @param options 84 | * @default undefined 85 | * @constructor 86 | */ 87 | export function Mock(options?: MockOptions): PropertyDecorator { 88 | return decorateProperty({ 89 | type: MOCK_DECORATOR_NAME, 90 | value: options, 91 | }); 92 | } 93 | -------------------------------------------------------------------------------- /packages/reflect/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types'; 2 | export * from './decorators'; 3 | export * from './lib'; 4 | -------------------------------------------------------------------------------- /packages/reflect/src/lib/class-reflector.test.ts: -------------------------------------------------------------------------------- 1 | import { ClassReflector } from './class-reflector'; 2 | import { Mock } from '../decorators'; 3 | import { ClassPropsReflection } from '../types/class-reflection.type'; 4 | 5 | describe('ClassReflector', () => { 6 | let reflector: ClassReflector; 7 | 8 | class EmptyClass {} 9 | 10 | class TestClass { 11 | @Mock('Foo') 12 | fooer: string; 13 | 14 | @Mock('Bar') 15 | barer: string; 16 | } 17 | 18 | describe('given a ClassReflector', () => { 19 | beforeAll(() => { 20 | reflector = ClassReflector.getInstance(); 21 | }); 22 | 23 | describe("when calling 'reflectClass'", () => { 24 | describe('and there are no mock decorators on any of the properties', () => { 25 | test('then return an empty array of properties', () => { 26 | expect(reflector.reflectClass(EmptyClass)).toHaveLength(0); 27 | }); 28 | }); 29 | 30 | describe('and the some of the properties in the class are decorated with mock decorator', () => { 31 | let classReflection: ClassPropsReflection; 32 | 33 | beforeAll(() => { 34 | classReflection = reflector.reflectClass(TestClass); 35 | }); 36 | 37 | test('then return an array of properties which the length is the number of decorators', () => { 38 | expect(classReflection).toBeInstanceOf(Array); 39 | expect(classReflection).toHaveLength(2); 40 | }); 41 | 42 | test('then create a property dto for each of the properties', () => { 43 | const reflectedClassKeys = Object.keys(classReflection[0]); 44 | expect(reflectedClassKeys).toEqual(['name', 'constructorName', 'decoratorValue']); 45 | }); 46 | 47 | test('then register the class in the reflected classes storage', () => { 48 | expect(ClassReflector.REFLECTED_CLASSES).toHaveProperty(TestClass.name); 49 | }); 50 | 51 | describe('and the class has been already reflected once before', () => { 52 | test('then return the dto of the first class with the name that has been parsed', () => { 53 | class TestClass { 54 | @Mock() someNewProperty: string; 55 | } 56 | 57 | const result = reflector.reflectClass(TestClass); 58 | expect(result).not.toHaveProperty('someNewProperty'); 59 | }); 60 | }); 61 | }); 62 | }); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /packages/reflect/src/lib/class-reflector.ts: -------------------------------------------------------------------------------- 1 | import reflect, { ClassReflection, PropertyReflection } from '@plumier/reflect'; 2 | import { Class } from '@mockingbird/common'; 3 | import { MockOptions } from '../types'; 4 | import { MOCK_DECORATOR_NAME } from '../decorators/mock.decorator'; 5 | import { Property } from './property'; 6 | import { ClassPropsReflection } from '../types/class-reflection.type'; 7 | 8 | export class ClassReflector { 9 | private static instance: ClassReflector; 10 | public static readonly REFLECTED_CLASSES: Record = {}; 11 | 12 | // eslint-disable-next-line @typescript-eslint/no-empty-function 13 | private constructor() {} 14 | 15 | private static extractMockDecoratorValue(property: PropertyReflection): MockOptions | undefined { 16 | const { decorators } = property; 17 | const mockDecorator = decorators.find((decorator) => decorator.type === MOCK_DECORATOR_NAME); 18 | 19 | return mockDecorator.value; 20 | } 21 | 22 | private extractDecoratedProperties(classReflection: ClassReflection): Property[] { 23 | return classReflection.properties.map((property) => { 24 | const value = ClassReflector.extractMockDecoratorValue(property); 25 | 26 | return Property.create(property, value); 27 | }); 28 | } 29 | 30 | public reflectClass(target: Class): ClassPropsReflection { 31 | if (!ClassReflector.REFLECTED_CLASSES.hasOwnProperty(target.name)) { 32 | ClassReflector.REFLECTED_CLASSES[target.name] = this.extractDecoratedProperties(reflect(target)); 33 | } 34 | 35 | return ClassReflector.REFLECTED_CLASSES[target.name]; 36 | } 37 | 38 | public static getInstance(): ClassReflector { 39 | if (!ClassReflector.instance) { 40 | ClassReflector.instance = new ClassReflector(); 41 | } 42 | 43 | return ClassReflector.instance; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/reflect/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from './property'; 2 | export * from './property-decorator-value'; 3 | export * from './class-reflector'; 4 | -------------------------------------------------------------------------------- /packages/reflect/src/lib/property-decorator-value.test.ts: -------------------------------------------------------------------------------- 1 | import { PropertyDecoratorValue } from './property-decorator-value'; 2 | 3 | describe('PropertyDecoratorValue Unit', () => { 4 | describe('given a PropertyDecoratorValue with a string value', () => { 5 | describe('when checking if it is an object', () => { 6 | test('then return true', () => { 7 | const value = new PropertyDecoratorValue({}); 8 | expect(value.isObject()).toBeTruthy(); 9 | }); 10 | }); 11 | 12 | describe('when checking if it is an object', () => { 13 | test('then return false', () => { 14 | const value = new PropertyDecoratorValue({ type: String }); 15 | expect(value.isMultiClass()).toBeTruthy(); 16 | }); 17 | }); 18 | 19 | describe('when checking if it is a function/callback', () => { 20 | test('then return true', () => { 21 | const value = new PropertyDecoratorValue(() => 'arbitrary-value'); 22 | expect(value.isCallback()).toBeTruthy(); 23 | }); 24 | }); 25 | 26 | describe('when checking if it is an enum', () => { 27 | test('then return true', () => { 28 | enum Enum { 29 | Foo, 30 | Bar, 31 | } 32 | 33 | const value = new PropertyDecoratorValue({ enum: Enum }); 34 | expect(value.isEnum()).toBeTruthy(); 35 | }); 36 | }); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /packages/reflect/src/lib/property-decorator-value.ts: -------------------------------------------------------------------------------- 1 | import { MultiClass } from '@mockingbird/common'; 2 | import { MockOptions } from '../types/mock-options.type'; 3 | 4 | export interface PropertyDecoratorValue { 5 | readonly value: MockOptions; 6 | sObject(): boolean; 7 | isMultiClass(): boolean; 8 | isCallback(): boolean; 9 | isEnum(): boolean; 10 | isRegex(): boolean; 11 | } 12 | 13 | export class PropertyDecoratorValue { 14 | private readonly type: string; 15 | 16 | public constructor(public readonly value: MockOptions) { 17 | this.type = typeof value; 18 | } 19 | 20 | public isObject(): boolean { 21 | return this.type === 'object'; 22 | } 23 | 24 | public isMultiClass(): boolean { 25 | return this.isObject() && (this.value as MultiClass).hasOwnProperty('type'); 26 | } 27 | 28 | public isCallback(): boolean { 29 | return this.type === 'function'; 30 | } 31 | 32 | public isEnum(): boolean { 33 | return this.isObject() && this.value.hasOwnProperty('enum'); 34 | } 35 | 36 | public isRegex(): boolean { 37 | return this.value instanceof RegExp; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/reflect/src/lib/property.ts: -------------------------------------------------------------------------------- 1 | import { PropertyReflection } from '@plumier/reflect'; 2 | import { MockOptions } from '../types/mock-options.type'; 3 | import { PropertyDecoratorValue } from './property-decorator-value'; 4 | 5 | export interface Property { 6 | readonly name: string; 7 | readonly constructorName: string; 8 | readonly decoratorValue: PropertyDecoratorValue; 9 | } 10 | 11 | export class Property { 12 | constructor( 13 | public readonly name: string, 14 | public readonly constructorName: string, 15 | public readonly decoratorValue: PropertyDecoratorValue 16 | ) {} 17 | 18 | public static create(property: PropertyReflection, mockDecoratorValue: MockOptions | null): Property { 19 | const { 20 | name, 21 | type: { name: constructorName }, 22 | } = property; 23 | 24 | return new Property(name, constructorName, new PropertyDecoratorValue(mockDecoratorValue)); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/reflect/src/types/class-reflection.type.ts: -------------------------------------------------------------------------------- 1 | import { Property } from '../lib'; 2 | 3 | export type ClassPropsReflection = Property[]; 4 | -------------------------------------------------------------------------------- /packages/reflect/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './mock-options.type'; 2 | export * from './class-reflection.type'; 3 | -------------------------------------------------------------------------------- /packages/reflect/src/types/mock-options.type.ts: -------------------------------------------------------------------------------- 1 | import { Callback, EnumObject, ExactValue, MultiClass, Class } from '@mockingbird/common'; 2 | 3 | export type MockOptions = Callback | ExactValue | Class | EnumObject | MultiClass; 4 | -------------------------------------------------------------------------------- /packages/reflect/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "rootDir": "./src", 6 | "outDir": "./dist", 7 | "target": "es6" 8 | }, 9 | "exclude": [ 10 | "index.ts", 11 | "node_modules", 12 | "test", 13 | "src/**/*.test.ts" 14 | ], 15 | "include": ["src/"] 16 | } -------------------------------------------------------------------------------- /packages/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "incremental": false, 5 | "sourceMap": true 6 | }, 7 | "exclude": [ 8 | "node_modules", 9 | "dist", 10 | "test", 11 | "src/**/*.test.ts", 12 | "index.ts", 13 | "index.js", 14 | "index.d.ts", 15 | "coverage" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /sample/mockingbird-typeorm/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | node_modules/ 4 | build/ 5 | tmp/ 6 | temp/ 7 | in-memory.sqlite 8 | -------------------------------------------------------------------------------- /sample/mockingbird-typeorm/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omermorad/mockingbird/421428336b06b0353dcb9a53c7f0c344bd03c95a/sample/mockingbird-typeorm/README.md -------------------------------------------------------------------------------- /sample/mockingbird-typeorm/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | mysql: 4 | image: "mysql:5.7.24" 5 | container_name: "generator-typeorm-example" 6 | ports: 7 | - "3306:3306" 8 | environment: 9 | MYSQL_ROOT_PASSWORD: "test" 10 | MYSQL_USER: "test" 11 | MYSQL_PASSWORD: "test" 12 | MYSQL_DATABASE: "users" 13 | -------------------------------------------------------------------------------- /sample/mockingbird-typeorm/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | moduleFileExtensions: ['js', 'json', 'ts'], 3 | rootDir: '.', 4 | testRegex: '.test.ts$', 5 | transform: { 6 | '^.+\\.ts$': 'ts-jest', 7 | }, 8 | testEnvironment: 'node', 9 | }; 10 | -------------------------------------------------------------------------------- /sample/mockingbird-typeorm/ormconfig.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "default", 4 | "type": "mysql", 5 | "host": "localhost", 6 | "port": 3306, 7 | "username": "test", 8 | "password": "test", 9 | "database": "users", 10 | "synchronize": true, 11 | "logging": true, 12 | "entities": [ 13 | "dist/entity/**/*.js" 14 | ], 15 | "cli": { 16 | "entitiesDir": "src/entity", 17 | "migrationsDir": "src/migration", 18 | "subscribersDir": "src/subscriber" 19 | } 20 | }, 21 | { 22 | "name": "test", 23 | "type": "sqlite", 24 | "database": "in-memory.sqlite", 25 | "dropSchema": true, 26 | "synchronize": true, 27 | "logging": false, 28 | "entities": [ 29 | "src/entity/**/*.ts" 30 | ] 31 | } 32 | ] 33 | -------------------------------------------------------------------------------- /sample/mockingbird-typeorm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mockingbird-typeorm", 3 | "private": true, 4 | "version": "1.0.0", 5 | "main": "dist/app.js", 6 | "scripts": { 7 | "start": "npm run spinup-db && npm run build && NODE_ENV=development; node dist/main", 8 | "prebuild": "rimraf dist", 9 | "spinup-db": "docker-compose up -d", 10 | "build": "tsc", 11 | "test": "NODE_ENV=test && jest" 12 | }, 13 | "author": "Omer Morad", 14 | "license": "MIT", 15 | "dependencies": { 16 | "body-parser": "^1.19.0", 17 | "dotenv": "^8.2.0", 18 | "express": "^4.17.1", 19 | "mockingbird": "^2.1.2", 20 | "mysql2": "^2.2.5", 21 | "reflect-metadata": "^0.1.13", 22 | "rimraf": "^3.0.2", 23 | "typeorm": "^0.2.30" 24 | }, 25 | "devDependencies": { 26 | "@types/express": "^4.17.11", 27 | "@types/faker": "^5.1.6", 28 | "@types/jest": "^26.0.20", 29 | "@types/node": "^14.14.25", 30 | "@types/sqlite3": "^3.1.7", 31 | "@types/supertest": "^2.0.10", 32 | "faker": "^5.3.1", 33 | "jest": "^26.6.3", 34 | "sqlite3": "^5.0.1", 35 | "supertest": "^6.1.3", 36 | "ts-jest": "^26.5.0", 37 | "typescript": "^3.9.7" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /sample/mockingbird-typeorm/src/app.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | import express, { Application, Router } from 'express'; 3 | import bodyParser from 'body-parser'; 4 | import { Connection } from 'typeorm'; 5 | import { UserController } from './user.controller'; 6 | import { UserEntity } from './entity/user.entity'; 7 | 8 | export async function applicationFactory(connection: Connection): Promise { 9 | const app: Application = express(); 10 | 11 | app.use(bodyParser.json()); 12 | app.use('/api', UserController(Router(), connection.getRepository(UserEntity))); 13 | 14 | return app; 15 | } 16 | -------------------------------------------------------------------------------- /sample/mockingbird-typeorm/src/common/connection-factory.ts: -------------------------------------------------------------------------------- 1 | import { Connection, createConnection, getConnectionOptions } from 'typeorm'; 2 | 3 | export async function connectionFactory(): Promise { 4 | const connectionOptions = await getConnectionOptions(process.env.NODE_ENV); 5 | return createConnection(connectionOptions); 6 | } 7 | -------------------------------------------------------------------------------- /sample/mockingbird-typeorm/src/entity/user.entity.ts: -------------------------------------------------------------------------------- 1 | import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm'; 2 | import { User } from '../interface/user.interface'; 3 | 4 | @Entity('users') 5 | export class UserEntity implements User { 6 | @PrimaryGeneratedColumn() 7 | id: number; 8 | 9 | @Column() 10 | firstName: string; 11 | 12 | @Column() 13 | lastName: string; 14 | 15 | @Column() 16 | address: string; 17 | 18 | @Column() 19 | birthday: Date; 20 | 21 | @Column() 22 | email: string; 23 | } 24 | -------------------------------------------------------------------------------- /sample/mockingbird-typeorm/src/interface/user.interface.ts: -------------------------------------------------------------------------------- 1 | export interface User { 2 | id: number; 3 | email: string; 4 | firstName: string; 5 | lastName: string; 6 | address: string; 7 | birthday: Date; 8 | } 9 | -------------------------------------------------------------------------------- /sample/mockingbird-typeorm/src/main.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | import { Connection, createConnection } from 'typeorm'; 3 | import { applicationFactory } from './app'; 4 | import { connectionFactory } from './common/connection-factory'; 5 | 6 | (async () => { 7 | const connection = (await connectionFactory().catch((error) => { 8 | console.error('Error connection to database', error); 9 | })) as Connection; 10 | 11 | const app = await applicationFactory(connection); 12 | 13 | app.listen(3000, () => console.info('Application started at port 3000')); 14 | })(); 15 | -------------------------------------------------------------------------------- /sample/mockingbird-typeorm/src/user.controller.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, Router } from 'express'; 2 | import { Repository } from 'typeorm'; 3 | import { MockFactory } from 'mockingbird'; 4 | import { User } from './interface/user.interface'; 5 | import { UserEntity } from './entity/user.entity'; 6 | 7 | export function UserController(router: Router, repository: Repository): Router { 8 | router.get('/users', async (req: Request, res: Response) => { 9 | const users = await repository.find(); 10 | 11 | res.json(users); 12 | }); 13 | 14 | router.post('/users', async (req: Request, res: Response) => { 15 | const user = repository.create(req.body); 16 | const result = await repository.save(user); 17 | 18 | return res.json(result); 19 | }); 20 | 21 | router.get('/users/random', async (req: Request, res: Response) => { 22 | const newUser = MockFactory(UserEntity).one(); 23 | const user = await repository.create(newUser); 24 | const result = await repository.save(user); 25 | 26 | res.json(result); 27 | }); 28 | 29 | return router; 30 | } 31 | -------------------------------------------------------------------------------- /sample/mockingbird-typeorm/test/app-e2e.test.ts: -------------------------------------------------------------------------------- 1 | import supertest, { Response } from 'supertest'; 2 | import { Application } from 'express'; 3 | import { Database } from 'sqlite3'; 4 | import { MockFactory } from 'mockingbird'; 5 | import { Connection } from 'typeorm'; 6 | import { UserEntityMock } from './mocks/user-entity.mock'; 7 | import { applicationFactory } from '../src/app'; 8 | import { User } from '../src/interface/user.interface'; 9 | import { connectionFactory } from '../src/common/connection-factory'; 10 | import { UserEntity } from '../src/entity/user.entity'; 11 | 12 | describe('Users App e2e Test', () => { 13 | let app: Application; 14 | let seededData: User[]; 15 | 16 | beforeAll(async () => { 17 | new Database(':memory:'); 18 | 19 | const connection = (await connectionFactory().catch((error) => { 20 | console.error('Error connection to database', error); 21 | })) as Connection; 22 | 23 | app = await applicationFactory(connection); 24 | seededData = MockFactory(UserEntityMock).many(3); 25 | 26 | await connection.getRepository(UserEntity).insert(seededData); 27 | }); 28 | 29 | describe('given a user controller', () => { 30 | describe('when firing a request to GET /api/users', () => { 31 | let response: Response; 32 | 33 | beforeAll(async () => { 34 | response = await supertest(app).get('/api/users'); 35 | }); 36 | 37 | test('then return the exact seeded data', async () => { 38 | response.body.forEach((item) => (item.birthday = new Date(item.birthday))); 39 | 40 | expect(response.body).toStrictEqual(seededData); 41 | }); 42 | }); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /sample/mockingbird-typeorm/test/mocks/user-entity.mock.ts: -------------------------------------------------------------------------------- 1 | import { Mock } from 'mockingbird'; 2 | import { UserEntity } from '../../src/entity/user.entity'; 3 | 4 | export class UserEntityMock implements UserEntity { 5 | id: number; 6 | 7 | @Mock((faker) => faker.name.firstName()) 8 | firstName!: string; 9 | 10 | @Mock((faker) => faker.name.lastName()) 11 | lastName!: string; 12 | 13 | @Mock((faker) => faker.address.streetAddress(true)) 14 | address!: string; 15 | 16 | @Mock() 17 | birthday!: Date; 18 | 19 | @Mock((faker) => faker.internet.email()) 20 | email!: string; 21 | } 22 | -------------------------------------------------------------------------------- /sample/mockingbird-typeorm/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": [ 4 | "es5", 5 | "es6" 6 | ], 7 | "esModuleInterop": true, 8 | "target": "es5", 9 | "allowJs": true, 10 | "incremental": false, 11 | "moduleResolution": "node", 12 | "outDir": "./dist", 13 | "emitDecoratorMetadata": true, 14 | "experimentalDecorators": true, 15 | "sourceMap": true, 16 | "skipLibCheck": true 17 | }, 18 | "exclude": [ 19 | "node_modules", 20 | "dist", 21 | "test" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "declaration": true, 5 | "removeComments": false, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "target": "es5", 9 | "sourceMap": true, 10 | "incremental": false, 11 | "noImplicitAny": false, 12 | "strictNullChecks": false, 13 | "moduleResolution": "node", 14 | "esModuleInterop": true, 15 | "resolveJsonModule": true, 16 | "types": [ 17 | "node", 18 | "jest", 19 | "jest-gherkin", 20 | ], 21 | "allowJs": true, 22 | "lib": [ 23 | "es6" 24 | ], 25 | "skipLibCheck": true, 26 | "allowSyntheticDefaultImports": true 27 | }, 28 | "exclude": [ 29 | "node_modules", 30 | "dist", 31 | "sample" 32 | ], 33 | "references": [ 34 | { 35 | "path": "packages/reflect" 36 | }, 37 | { 38 | "path": "packages/common" 39 | }, 40 | { 41 | "path": "packages/parser" 42 | }, 43 | { 44 | "path": "packages/mockingbird" 45 | }, 46 | { 47 | "path": "packages/logger" 48 | }, 49 | ] 50 | } 51 | --------------------------------------------------------------------------------