├── .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 | [](http://opensource.org/licenses/MIT)
2 | [](https://npmjs.org/package/mockingbird "View this project on npm")
3 | [](https://codecov.io/gh/omermorad/mockingbird)
4 | [](https://lerna.js.org/)
5 | [](https://github.com/omermorad/mockingbird/actions)
6 |
7 |
8 |
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 | [](https://codecov.io/gh/omermorad/mockingbird)
2 | [](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 | [](http://opensource.org/licenses/MIT)
2 | [](https://npmjs.org/package/mockingbird "View this project on npm")
3 | [](https://codecov.io/gh/omermorad/mockingbird)
4 | [](https://lerna.js.org/)
5 | [](https://github.com/omermorad/mockingbird/actions)
6 |
7 |
8 |
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 |
--------------------------------------------------------------------------------