├── .autorc ├── .eslintignore ├── .eslintrc.js ├── .github ├── stale.yml └── workflows │ ├── build.yml │ ├── codeql-analysis.yml │ ├── deploy.yml │ ├── lint.yml │ └── test.yml ├── .gitignore ├── .husky └── pre-commit ├── .prettierrc.js ├── CHANGELOG.md ├── LICENSE ├── README.md ├── jest.config.js ├── package.json ├── src ├── index.ts └── mockValueGenerator.ts ├── tests ├── __snapshots__ │ └── typescript-mock-data.spec.ts.snap ├── enumValues │ ├── __snapshots__ │ │ └── spec.ts.snap │ ├── schema.ts │ └── spec.ts ├── generateLibrary │ ├── casual │ │ ├── __snapshots__ │ │ │ └── spec.ts.snap │ │ └── spec.ts │ ├── faker │ │ ├── __snapshots__ │ │ │ └── spec.ts.snap │ │ └── spec.ts │ ├── schema.ts │ └── types.ts ├── globalSetup.ts ├── perTypeFieldGeneration │ ├── __snapshots__ │ │ └── spec.ts.snap │ ├── schema.ts │ └── spec.ts ├── scalars │ ├── __snapshots__ │ │ └── spec.ts.snap │ ├── schema.ts │ ├── spec.ts │ └── types.ts ├── terminateCircularRelationships │ ├── schema.ts │ ├── spec.ts │ └── types.ts ├── terminateCircularRelationshipsImmediately │ ├── __snapshots__ │ │ └── spec.ts.snap │ ├── schema.ts │ ├── spec.ts │ └── types.ts ├── typeNamesMapping │ ├── schema.ts │ └── spec.ts ├── typesPrefixAndTerminateCircularRelationships │ ├── __snapshots__ │ │ └── spec.ts.snap │ ├── schema.ts │ └── spec.ts ├── typescript-mock-data.spec.ts ├── useImplementingTypes │ ├── __snapshots__ │ │ └── spec.ts.snap │ ├── schema.ts │ └── spec.ts ├── useImplementingTypesAndDefaultNullableToNull │ ├── __snapshots__ │ │ └── spec.ts.snap │ ├── schema.ts │ └── spec.ts ├── useImplementingTypesAndTerminateCircularRelationships │ ├── __snapshots__ │ │ └── spec.ts.snap │ ├── schema.ts │ └── spec.ts └── useTypeImports │ ├── __snapshots__ │ └── spec.ts.snap │ ├── schema.ts │ └── spec.ts ├── tsconfig.json └── yarn.lock /.autorc: -------------------------------------------------------------------------------- 1 | { 2 | } 3 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['landr'], 3 | plugins: ['jest'], 4 | rules: { 5 | '@typescript-eslint/explicit-function-return-type': ['off'], 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 90 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 30 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - bug 8 | - pinned 9 | - security 10 | # Label to use when marking an issue as stale 11 | staleLabel: stale 12 | # Comment to post when marking an issue as stale. Set to `false` to disable 13 | markComment: > 14 | This issue has been automatically marked as stale because it has not had 15 | recent activity. It will be closed if no further activity occurs. Thank you 16 | for your contributions. 17 | # Comment to post when closing a stale issue. Set to `false` to disable 18 | closeComment: false 19 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | pull_request: 5 | types: [assigned, edited, opened, synchronize, reopened] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | timeout-minutes: 15 11 | 12 | steps: 13 | - name: checkout 14 | uses: actions/checkout@v2 15 | - name: setup-node 16 | uses: actions/setup-node@v1 17 | with: 18 | node-version: '20.x' 19 | - name: Get yarn cache directory path 20 | id: yarn-cache-dir-path 21 | run: echo "::set-output name=dir::$(yarn cache dir)" 22 | - uses: actions/cache@v4 23 | with: 24 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 25 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 26 | restore-keys: | 27 | ${{ runner.os }}-yarn- 28 | - name: install 29 | run: yarn install 30 | - name: build 31 | run: yarn build 32 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | name: "CodeQL" 7 | 8 | on: 9 | push: 10 | branches: [main] 11 | pull_request: 12 | # The branches below must be a subset of the branches above 13 | branches: [main] 14 | schedule: 15 | - cron: '0 17 * * 5' 16 | 17 | jobs: 18 | analyze: 19 | name: Analyze 20 | runs-on: ubuntu-latest 21 | 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | # Override automatic language detection by changing the below list 26 | # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] 27 | language: ['javascript'] 28 | # Learn more... 29 | # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection 30 | 31 | steps: 32 | - name: Checkout repository 33 | uses: actions/checkout@v2 34 | with: 35 | # We must fetch at least the immediate parents so that if this is 36 | # a pull request then we can checkout the head. 37 | fetch-depth: 2 38 | 39 | # If this run was triggered by a pull request event, then checkout 40 | # the head of the pull request instead of the merge commit. 41 | - run: git checkout HEAD^2 42 | if: ${{ github.event_name == 'pull_request' }} 43 | 44 | # Initializes the CodeQL tools for scanning. 45 | - name: Initialize CodeQL 46 | uses: github/codeql-action/init@v1 47 | with: 48 | languages: ${{ matrix.language }} 49 | # If you wish to specify custom queries, you can do so here or in a config file. 50 | # By default, queries listed here will override any specified in a config file. 51 | # Prefix the list here with "+" to use these queries and those in the config file. 52 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 53 | 54 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 55 | # If this step fails, then you should remove it and run the build manually (see below) 56 | - name: Autobuild 57 | uses: github/codeql-action/autobuild@v1 58 | 59 | # ℹ️ Command-line programs to run using the OS shell. 60 | # 📚 https://git.io/JvXDl 61 | 62 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 63 | # and modify them (or add more) to build your code if your project 64 | # uses a compiled language 65 | 66 | #- run: | 67 | # make bootstrap 68 | # make release 69 | 70 | - name: Perform CodeQL Analysis 71 | uses: github/codeql-action/analyze@v1 72 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: deploy 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-latest 11 | timeout-minutes: 15 12 | 13 | steps: 14 | - name: checkout 15 | uses: actions/checkout@v2 16 | with: 17 | token: ${{secrets.GH_ADMIN_TOKEN}} 18 | - name: Fetch tags 19 | run: git fetch --tags 20 | - name: setup-node 21 | uses: actions/setup-node@v1 22 | with: 23 | node-version: '20.x' 24 | registry-url: 'https://registry.npmjs.org' 25 | - name: Get yarn cache directory path 26 | id: yarn-cache-dir-path 27 | run: echo "::set-output name=dir::$(yarn cache dir)" 28 | - uses: actions/cache@v4 29 | with: 30 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 31 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 32 | restore-keys: | 33 | ${{ runner.os }}-yarn- 34 | - name: install 35 | run: yarn install 36 | - name: build 37 | run: yarn build 38 | - name: release 39 | run: yarn release 40 | env: 41 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 42 | GH_TOKEN: ${{ secrets.GH_TOKEN }} 43 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: lint 2 | 3 | on: 4 | pull_request: 5 | types: [assigned, edited, opened, synchronize, reopened] 6 | 7 | jobs: 8 | lint: 9 | runs-on: ubuntu-latest 10 | timeout-minutes: 15 11 | 12 | steps: 13 | - name: checkout 14 | uses: actions/checkout@v2 15 | - name: setup-node 16 | uses: actions/setup-node@v1 17 | with: 18 | node-version: '20.x' 19 | - name: Get yarn cache directory path 20 | id: yarn-cache-dir-path 21 | run: echo "::set-output name=dir::$(yarn cache dir)" 22 | - uses: actions/cache@v4 23 | with: 24 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 25 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 26 | restore-keys: | 27 | ${{ runner.os }}-yarn- 28 | - name: install 29 | run: yarn install 30 | - name: lint 31 | run: yarn lint 32 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: 4 | pull_request: 5 | types: [assigned, edited, opened, synchronize, reopened] 6 | 7 | jobs: 8 | test: 9 | runs-on: ubuntu-latest 10 | timeout-minutes: 15 11 | 12 | steps: 13 | - name: checkout 14 | uses: actions/checkout@v2 15 | - name: setup-node 16 | uses: actions/setup-node@v1 17 | with: 18 | node-version: '20.x' 19 | - name: Get yarn cache directory path 20 | id: yarn-cache-dir-path 21 | run: echo "::set-output name=dir::$(yarn cache dir)" 22 | - uses: actions/cache@v4 23 | with: 24 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 25 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 26 | restore-keys: | 27 | ${{ runner.os }}-yarn- 28 | - name: install 29 | run: yarn install 30 | - name: test 31 | run: yarn test 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | node_modules 3 | 4 | # IDE files 5 | .idea 6 | .vscode 7 | 8 | # production 9 | /dist 10 | 11 | # misc 12 | .DS_Store 13 | npm-debug.log* 14 | yarn-debug.log* 15 | yarn-error.log* 16 | 17 | # generated test file 18 | /tests/**/mocks.ts 19 | 20 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | yarn lint-staged 5 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = require('prettier-config-landr'); 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-present Corentin Ardeois 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 | # graphql-codegen-typescript-mock-data 2 | 3 | ## Description 4 | 5 | [GraphQL Codegen Plugin](https://github.com/dotansimha/graphql-code-generator) for building mock data based on the schema. 6 | 7 | ## Installation 8 | 9 | `yarn add -D graphql-codegen-typescript-mock-data` 10 | 11 | ## Configuration 12 | 13 | ### typesFile (`string`, defaultValue: `null`) 14 | 15 | Defines the file path containing all GraphQL types. This file can also be generated through graphql-codegen 16 | 17 | ### useTypeImports(boolean, defaultValue: false) 18 | 19 | Will use import type {} rather than import {} when importing only types. This gives compatibility with TypeScript's "importsNotUsedAsValues": "error" option 20 | 21 | ### addTypename (`boolean`, defaultValue: `false`) 22 | 23 | Adds `__typename` property to mock data 24 | 25 | ### enumsAsTypes (`boolean`, defaultValue: `false`) 26 | 27 | Changes enums to TypeScript string union types 28 | 29 | ### includedTypes (`string[]`, defaultValue: `undefined`) 30 | 31 | Specifies an array of types to **include** in the mock generation. When provided, only the types listed in this array will have mock data generated. 32 | 33 | Example: 34 | 35 | ```yaml 36 | plugins: 37 | - typescript-mock-data: 38 | includedTypes: 39 | - User 40 | - Avatar 41 | ``` 42 | 43 | ### excludedTypes (`string[]`, defaultValue: `undefined`) 44 | 45 | Specifies an array of types to **exclude** in the mock generation. When provided, the types listed in this array will not have mock data generated. 46 | 47 | Example: 48 | 49 | ```yaml 50 | plugins: 51 | - typescript-mock-data: 52 | excludedTypes: 53 | - User 54 | - Avatar 55 | ``` 56 | 57 | ### terminateCircularRelationships (`boolean | 'immediate'`, defaultValue: `false`) 58 | 59 | When enabled, prevents circular relationships from triggering infinite recursion. After the first resolution of a 60 | specific type in a particular call stack, subsequent resolutions will return an empty object cast to the correct type. 61 | 62 | When enabled with `immediate`, it will only resolve the relationship once, independently of the call stack. Use this option if you're experiencing `out of memory` errors while generating mocks. 63 | 64 | ### prefix (`string`, defaultValue: `a` for consonants & `an` for vowels) 65 | 66 | The prefix to add to the mock function name. Cannot be empty since it will clash with the associated 67 | typescript definition from `@graphql-codegen/typescript` 68 | 69 | ### listElementCount (`number`, defaultValue: `1`) 70 | 71 | How many elements should be generated for lists. For example, with `listElementCount: 3` a schema field `names: [String!]!` would generate `3` names in each mock. 72 | 73 | ### enumValues (`string`, defaultValue: `change-case-all#pascalCase`) 74 | 75 | Changes the case of the enums. The format of the converter must be a valid `module#method`. You can also use `keep` to 76 | keep all GraphQL names as-is. Available case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, 77 | `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, 78 | `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst` 79 | [See more](https://github.com/btxtiger/change-case-all) 80 | 81 | ### typeNames (`string`, defaultValue: `change-case-all#pascalCase`) 82 | 83 | Changes the case of types. The format of the converter must be a valid `module#method`. You can also use `keep` to 84 | keep all GraphQL names as-is. Available case functions in `change-case-all` are `camelCase`, `capitalCase`, `constantCase`, 85 | `dotCase`, `headerCase`, `noCase`, `paramCase`, `pascalCase`, `pathCase`, `sentenceCase`, `snakeCase`, `lowerCase`, 86 | `localeLowerCase`, `lowerCaseFirst`, `spongeCase`, `titleCase`, `upperCase`, `localeUpperCase` and `upperCaseFirst` 87 | [See more](https://github.com/btxtiger/change-case-all) 88 | 89 | ### scalars (`{ [Scalar: string]: GeneratorOptions | InputOutputGeneratorOptions }`, defaultValue: `undefined`) 90 | 91 | Allows you to define mappings for your custom scalars. Allows you to map any GraphQL Scalar to a 92 | [casual](https://github.com/boo1ean/casual#embedded-generators) embedded generator (string or 93 | function key) with optional arguments, or a or [faker](https://fakerjs.dev/api/) generator with optional arguments 94 | 95 | For detailed configuration options, see [GeneratorOptions](#generatoroptions-type) documentation. 96 | 97 | Examples using **casual** 98 | 99 | ```yaml 100 | plugins: 101 | - typescript-mock-data: 102 | scalars: 103 | Date: date # gets translated to casual.date() 104 | ``` 105 | 106 | **With arguments** 107 | 108 | ```yaml 109 | plugins: 110 | - typescript-mock-data: 111 | scalars: 112 | Date: # gets translated to casual.date('YYYY-MM-DD') 113 | generator: date 114 | arguments: 'YYYY-MM-DD' 115 | ``` 116 | 117 | Examples using **faker** 118 | 119 | ```yaml 120 | plugins: 121 | - typescript-mock-data: 122 | scalars: 123 | Date: date.past # gets translated to faker.date.past() 124 | ``` 125 | 126 | **With arguments** 127 | 128 | ```yaml 129 | plugins: 130 | - typescript-mock-data: 131 | scalars: 132 | Date: # gets translated to faker.date.past(10) 133 | generator: date.past 134 | arguments: 10 135 | ``` 136 | 137 | **Custom value generator** 138 | 139 | ```yaml 140 | plugins: 141 | - add: "import { arrayBufferGenerator } from '../generators';" 142 | - typescript-mock-data: 143 | scalars: 144 | ArrayBuffer: arrayBufferGenerator() 145 | ``` 146 | 147 | ### typesPrefix (`string`, defaultValue: '') 148 | 149 | Useful if you have globally exported types under a certain namespace. 150 | e.g If the types file is something like this 151 | 152 | ``` 153 | declare namespace Api { 154 | type User { 155 | ... 156 | } 157 | } 158 | ``` 159 | 160 | Setting the `typesPrefix` to `Api.` will create the following mock data 161 | 162 | ``` 163 | export const aUser = (overrides?: Partial): Api.User => { 164 | ``` 165 | 166 | ### enumsPrefix (`string`, defaultValue: '') 167 | 168 | Similar to `typesPrefix`, but for enum types 169 | 170 | ``` 171 | declare namespace Api { 172 | enum Status { 173 | ... 174 | } 175 | } 176 | ``` 177 | 178 | Setting the `enumsPrefix` to `Api.` will create the following mock data 179 | 180 | ``` 181 | export const aUser = (overrides?: Partial): User => { 182 | status: overrides && overrides.hasOwnProperty('status') ? overrides.status! : Api.Status.Online, 183 | } 184 | ``` 185 | 186 | ### typeNamesMapping (`{ [typeName: string]: string }`, defaultValue: `{}`) 187 | 188 | Allows you to define mappings to rename the types. This is useful when you want to override the generated type name. For example, if you have a type called `User` and you want to rename it to `RenamedUser` you can do the following: 189 | 190 | ``` 191 | plugins: 192 | - typescript-mock-data: 193 | typesFile: '../generated-types.ts' 194 | typeNamesMapping: 195 | User: RenamedUser 196 | ``` 197 | 198 | This will generate the following mock function: 199 | 200 | ``` 201 | export const aUser = (overrides?: Partial): RenamedUser => { 202 | ``` 203 | 204 | **Note:** It is not possible to rename your enums using this option. 205 | 206 | ### transformUnderscore (`boolean`, defaultValue: `true`) 207 | 208 | When disabled, underscores will be retained for type names when the case is changed. It has no effect if `typeNames` is set to `keep`. 209 | 210 | ### dynamicValues (`boolean`, defaultValue: `false`) 211 | 212 | When enabled, values will be generated dynamically when the mock function is called rather than statically when the mock function is generated. The values are generated consistently from a [casual seed](https://github.com/boo1ean/casual#seeding) that can be manually configured using the generated `seedMocks(seed: number)` function, as shown in [this test](https://github.com/JimmyPaolini/graphql-codegen-typescript-mock-data/blob/dynamic-mode/tests/dynamicValues/spec.ts#L13). 213 | 214 | ### useImplementingTypes (`boolean`, defaultValue: `false`) 215 | 216 | When enabled, it will support the useImplementingTypes GraphQL codegen configuration. 217 | 218 | - When a GraphQL interface is used for a field, this flag will use the implementing types, instead of the interface itself. 219 | 220 | ### defaultNullableToNull (`boolean`, defaultValue: `false`) 221 | 222 | When enabled, it will set all nullable fields to null per default instead of generating a value. 223 | 224 | ### fieldGeneration (`{ [typeName: string]: { [fieldName: string]: GeneratorOptions } }`, defaultValue: `undefined`) 225 | 226 | This setting allows you to add specific generation to a field for a given type. For example if you have a type called `User` and a field called `birthDate` you can override any generated value there as follows: 227 | 228 | ```yaml 229 | plugins: 230 | - typescript-mock-data: 231 | scalars: 232 | Date: date.future 233 | fieldGeneration: 234 | User: 235 | birthDate: date.past 236 | ``` 237 | 238 | Note that even if `birthDate` is a scalar of `Date` type, its value will still be overridden. 239 | 240 | If you want to use a specific generator for **all** fields of a given name, you can declare it under a property called `_all`: 241 | 242 | ```yaml 243 | plugins: 244 | - typescript-mock-data: 245 | scalars: 246 | Date: date.future 247 | fieldGeneration: 248 | _all: 249 | email: internet.email 250 | AdminUser: 251 | email: 'admin@email.com' 252 | ``` 253 | 254 | In the above example all resolvers with the name `email` will use the `internet.email` generator. However since we specified a specific email for `AdminUser` that will take precedence over the `_all` generated value. 255 | 256 | For detailed configuration options, see [GeneratorOptions](#generatoroptions-type) documentation. 257 | 258 | ### generateLibrary (`'casual' | 'faker'`, defaultValue: `'faker'`) 259 | 260 | Select a library to generate mock values. The default is [faker](https://github.com/faker-js/faker), Other options include [casual](https://github.com/boo1ean/casual) 261 | casual is not maintained and will be remove in future major versions. 262 | faker is useful when you want to use a mock function with the dynamicValues option enabled in the browser. 263 | 264 | ### `GeneratorOptions` type 265 | 266 | This type is used in `scalars` and `fieldGeneration` options. 267 | 268 | Examples using **faker** 269 | 270 | **With arguments** 271 | 272 | ```yaml 273 | plugins: 274 | - typescript-mock-data: 275 | scalars: 276 | Date: # gets translated to faker.date.past(10) 277 | generator: date.past 278 | arguments: 10 279 | ``` 280 | 281 | **With multiple arguments** 282 | 283 | ```yaml 284 | plugins: 285 | - typescript-mock-data: 286 | scalars: 287 | Description: # gets translated to faker.lorem.paragraphs(3, '\n') 288 | generator: lorem.paragraphs 289 | arguments: 290 | - 3 291 | - '\n' 292 | ``` 293 | 294 | **Shorthand if you don't have arguments** 295 | 296 | ```yaml 297 | plugins: 298 | - typescript-mock-data: 299 | scalars: 300 | Date: date.past # gets translated to faker.date.past() 301 | ``` 302 | 303 | **With extra function call** 304 | 305 | ```yaml 306 | fieldName: # gets translated to faker.date.past().toLocaleDateString() 307 | generator: date.past 308 | extra: 309 | function: toLocaleDateString 310 | ``` 311 | 312 | **With extra function call arguments** 313 | 314 | ```yaml 315 | fieldName: # gets translated to faker.date.past().toLocaleDateString('en_GB) 316 | generator: date.past 317 | extra: 318 | function: toLocaleDateString 319 | arguments: 'en_GB' 320 | ``` 321 | 322 | **Custom value generator** 323 | 324 | ```yaml 325 | # gets translated as is 326 | fieldName: arrayBufferGenerator() 327 | ``` 328 | 329 | Examples using **casual** (deprecated) 330 | 331 | **Shorthand if you don't have arguments** 332 | 333 | ```yaml 334 | fieldName: date # gets translated to casual.date() 335 | ``` 336 | 337 | **With arguments** 338 | 339 | ```yaml 340 | fieldName: # gets translated to casual.date('YYYY-MM-DD') 341 | generator: date 342 | arguments: 'YYYY-MM-DD' 343 | ``` 344 | 345 | **With multiple arguments** 346 | 347 | ```yaml 348 | fieldName: # gets translated to casual.integer(-100, 100) 349 | generator: integer 350 | arguments: 351 | - -100 352 | - 100 353 | ``` 354 | 355 | **With extra function call** 356 | 357 | ```yaml 358 | fieldName: # gets translated to casual.integer.toFixed() 359 | generator: integer 360 | extra: 361 | function: toFixed 362 | ``` 363 | 364 | **With extra function call arguments** 365 | 366 | ```yaml 367 | fieldName: # gets translated to casual.integer.toFixed(3) 368 | generator: integer 369 | extra: 370 | function: toFixed 371 | arguments: 3 372 | ``` 373 | 374 | ### `InputOutputGeneratorOptions` type 375 | 376 | This type is used in the `scalars` option. It allows you to specify different `GeneratorOptions` for `input` and `output` types for 377 | your scalars, in the same way the [typescript-operations](https://the-guild.dev/graphql/codegen/plugins/typescript/typescript-operations#scalars) plugin does. 378 | 379 | So, using the first example of the previous section, you can specify a `string` for your input and a `Date` for your `output`: 380 | 381 | ```yaml 382 | plugins: 383 | - typescript-mock-data: 384 | scalars: 385 | Date: 386 | input: date.weekday # Date fields in input objects will be mocked as strings 387 | output: 388 | generator: date.past # Date fields in other GraphQL types will be mocked as JS Dates 389 | arguments: 10 390 | ``` 391 | 392 | ## Examples of usage 393 | 394 | **codegen.yml** 395 | 396 | ```yaml 397 | overwrite: true 398 | schema: schema.graphql 399 | generates: 400 | src/generated-types.ts: 401 | plugins: 402 | - 'typescript' 403 | src/mocks/generated-mocks.ts: 404 | plugins: 405 | - typescript-mock-data: 406 | typesFile: '../generated-types.ts' 407 | enumValues: upper-case#upperCase 408 | typeNames: keep 409 | scalars: 410 | AWSTimestamp: number.int # gets translated to faker.number.int() 411 | ``` 412 | 413 | ### With `eslint-disable` rule 414 | 415 | **codegen.yml** 416 | 417 | ```yaml 418 | overwrite: true 419 | schema: schema.graphql 420 | generates: 421 | src/generated-types.ts: 422 | plugins: 423 | - 'typescript' 424 | src/mocks/generated-mocks.ts: 425 | plugins: 426 | - add: 427 | content: '/* eslint-disable @typescript-eslint/no-use-before-define,@typescript-eslint/no-unused-vars,no-prototype-builtins */' 428 | - typescript-mock-data: 429 | typesFile: '../generated-types.ts' 430 | enumValues: upper-case#upperCase 431 | typeNames: keep 432 | scalars: 433 | AWSTimestamp: number.int # gets translated to faker.number.int() 434 | ``` 435 | 436 | ## Example of generated code 437 | 438 | Given the following schema: 439 | 440 | ```graphql 441 | scalar AWSTimestamp 442 | 443 | type Avatar { 444 | id: ID! 445 | url: String! 446 | } 447 | 448 | type User { 449 | id: ID! 450 | login: String! 451 | avatar: Avatar 452 | status: Status! 453 | updatedAt: AWSTimestamp 454 | } 455 | 456 | type Query { 457 | user: User! 458 | } 459 | 460 | input UpdateUserInput { 461 | id: ID! 462 | login: String 463 | avatar: Avatar 464 | } 465 | 466 | enum Status { 467 | ONLINE 468 | OFFLINE 469 | } 470 | 471 | type Mutation { 472 | updateUser(user: UpdateUserInput): User 473 | } 474 | ``` 475 | 476 | The code generated will look like: 477 | 478 | ```typescript 479 | export const anAvatar = (overrides?: Partial): Avatar => { 480 | return { 481 | id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : '0550ff93-dd31-49b4-8c38-ff1cb68bdc38', 482 | url: overrides && overrides.hasOwnProperty('url') ? overrides.url! : 'aliquid', 483 | }; 484 | }; 485 | 486 | export const anUpdateUserInput = (overrides?: Partial): UpdateUserInput => { 487 | return { 488 | id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : '1d6a9360-c92b-4660-8e5f-04155047bddc', 489 | login: overrides && overrides.hasOwnProperty('login') ? overrides.login! : 'qui', 490 | avatar: overrides && overrides.hasOwnProperty('avatar') ? overrides.avatar! : anAvatar(), 491 | }; 492 | }; 493 | 494 | export const aUser = (overrides?: Partial): User => { 495 | return { 496 | id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : 'a5756f00-41a6-422a-8a7d-d13ee6a63750', 497 | login: overrides && overrides.hasOwnProperty('login') ? overrides.login! : 'libero', 498 | avatar: overrides && overrides.hasOwnProperty('avatar') ? overrides.avatar! : anAvatar(), 499 | status: overrides && overrides.hasOwnProperty('status') ? overrides.status! : Status.Online, 500 | updatedAt: overrides && overrides.hasOwnProperty('updatedAt') ? overrides.updatedAt! : 1458071232, 501 | }; 502 | }; 503 | ``` 504 | 505 | ### Usage in tests 506 | 507 | Those helper functions can be used in our unit tests: 508 | 509 | ```typescript 510 | const user = aUser({ login: 'johndoe' }); 511 | 512 | // will create a user object with `login` property overridden to `johndoe` 513 | ``` 514 | 515 | ### Dealing with Timezone 516 | 517 | If some properties use generated dates, the result could different depending on the timezone of your machine. 518 | 519 | To force a timezone, you can set environment variable `TZ`: 520 | 521 | ```bash 522 | TZ=UTC graphql-codegen 523 | ``` 524 | 525 | This will force the timezone to `UTC`, whatever the timezone of your machine or CI 526 | 527 | ### Contributing 528 | 529 | Feel free to open issues and pull requests. We always welcome support from the community. 530 | 531 | To run this project locally: 532 | 533 | - Use Node >= 16 534 | - Make sure that you have the latest Yarn version (https://yarnpkg.com/lang/en/docs/install/) 535 | - Clone this repo using `git clone` 536 | - Run `yarn` 537 | - Run `yarn build` to build the package 538 | - Run `yarn test` to make sure everything works 539 | 540 | ### License 541 | 542 | [![GitHub license](https://img.shields.io/badge/license-MIT-lightgrey.svg?maxAge=2592000)](https://raw.githubusercontent.com/ardeois/graphql-codegen-typescript-mock-data/master/LICENSE) 543 | 544 | MIT 545 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | roots: ['/tests'], 3 | transform: { 4 | '^.+\\.tsx?$': 'ts-jest', 5 | }, 6 | globalSetup: './tests/globalSetup.ts', 7 | }; 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "graphql-codegen-typescript-mock-data", 3 | "version": "4.4.0", 4 | "description": "GraphQL Codegen plugin for building mock data", 5 | "main": "dist/commonjs/index.js", 6 | "module": "dist/esnext/index.js", 7 | "typings": "dist/esnext/index.d.ts", 8 | "repository": "ardeois/graphql-codegen-typescript-mock-data", 9 | "author": { 10 | "name": "Corentin Ardeois", 11 | "email": "corentin.ardeois@gmail.com", 12 | "url": "https://github.com/ardeois" 13 | }, 14 | "license": "MIT", 15 | "keywords": [ 16 | "graphql", 17 | "codegen", 18 | "graphql-codegen", 19 | "plugin", 20 | "typescript", 21 | "mocks", 22 | "fakes" 23 | ], 24 | "dependencies": { 25 | "@faker-js/faker": "^8.4.1", 26 | "@graphql-codegen/plugin-helpers": "^5.0.4", 27 | "@graphql-tools/utils": "^10.7.2", 28 | "casual": "^1.6.2", 29 | "change-case-all": "^1.0.15", 30 | "indefinite": "^2.4.1", 31 | "pascal-case": "^3.1.1", 32 | "sentence-case": "^3.0.3", 33 | "tslib": "^2.4.0", 34 | "upper-case": "^2.0.1" 35 | }, 36 | "peerDependencies": { 37 | "graphql": "^14.6.0 || ^15.0.0 || ^16.0.0" 38 | }, 39 | "devDependencies": { 40 | "@auto-it/conventional-commits": "^11.1.6", 41 | "@graphql-codegen/testing": "^3.0.3", 42 | "@graphql-codegen/typescript": "^4.0.7", 43 | "@types/indefinite": "^2.3.4", 44 | "@types/jest": "^27.0.2", 45 | "@typescript-eslint/eslint-plugin": "^5.1.0", 46 | "@typescript-eslint/parser": "^5.1.0", 47 | "auto": "^11.1.6", 48 | "eslint": "8.0.1", 49 | "eslint-config-landr": "0.7.0", 50 | "eslint-config-prettier": "^8.3.0", 51 | "eslint-plugin-import": "^2.25.2", 52 | "eslint-plugin-jest": "^25.2.2", 53 | "eslint-plugin-prettier": "^4.0.0", 54 | "graphql": "^16.3.0", 55 | "husky": "^7.0.0", 56 | "jest": "^27.3.1", 57 | "jest-diff": "^27.5.1", 58 | "lint-staged": "^11.2.3", 59 | "prettier": "^2.4.1", 60 | "prettier-config-landr": "^0.2.0", 61 | "ts-jest": "^27.0.7", 62 | "typescript": "^5.7.3" 63 | }, 64 | "sideEffects": false, 65 | "scripts": { 66 | "build": "tsc -m esnext --outDir dist/esnext && tsc -m commonjs --outDir dist/commonjs", 67 | "test": "TZ=UTC LANG=en_US.UTF8 jest", 68 | "lint": "eslint 'src/**/*.{js,ts,tsx}' --quiet --fix && tsc --noEmit", 69 | "prettify": "prettier --config ./.prettierrc.js --write", 70 | "auto:version": "yarn version --`auto version` --message 'Bump version to: %s [skip ci]'", 71 | "auto:publish": "yarn publish && git push --follow-tags --set-upstream origin $CIRCLE_BRANCH", 72 | "release": "auto changelog && yarn auto:version && yarn auto:publish && auto release", 73 | "prepare": "husky install" 74 | }, 75 | "lint-staged": { 76 | "*.{js,ts,tsx}": [ 77 | "eslint --quiet --fix" 78 | ], 79 | "*.{json,md,html}": [ 80 | "prettier --write" 81 | ] 82 | }, 83 | "files": [ 84 | "dist/**/*", 85 | "LICENSE", 86 | "README.md" 87 | ] 88 | } 89 | -------------------------------------------------------------------------------- /src/mockValueGenerator.ts: -------------------------------------------------------------------------------- 1 | import { Faker } from '@faker-js/faker'; 2 | import * as allFakerLocales from '@faker-js/faker'; 3 | import casual from 'casual'; 4 | 5 | interface MockValueGenerator { 6 | dynamicValues: boolean; 7 | word: () => string; 8 | uuid: () => string; 9 | boolean: () => boolean | string; 10 | integer: () => number | string; 11 | float: () => number | string; 12 | date: () => string; 13 | seed: (seed: number) => void; 14 | } 15 | 16 | type MockValueGeneratorOptions = { 17 | dynamicValues: boolean; 18 | generatorLocale: string; 19 | }; 20 | 21 | type FunctionTokens = Record<'import' | 'seed' | 'seedFunction', string>; 22 | 23 | type SetupMockValueGeneratorOptions = { 24 | generateLibrary: 'casual' | 'faker'; 25 | generatorLocale: string; 26 | dynamicValues: boolean; 27 | }; 28 | 29 | class CasualMockValueGenerator implements MockValueGenerator { 30 | dynamicValues: boolean; 31 | 32 | constructor(opts: MockValueGeneratorOptions) { 33 | this.dynamicValues = opts.dynamicValues; 34 | } 35 | 36 | word = () => (this.dynamicValues ? `casual.word` : `'${casual.word}'`); 37 | uuid = () => (this.dynamicValues ? `casual.uuid` : `'${casual.uuid}'`); 38 | boolean = () => (this.dynamicValues ? `casual.boolean` : casual.boolean); 39 | integer = () => (this.dynamicValues ? `casual.integer(0, 9999)` : `${casual.integer(0, 9999)}`); 40 | float = () => 41 | this.dynamicValues 42 | ? `Math.round(casual.double(0, 10) * 100) / 100` 43 | : `${Math.round(casual.double(0, 10) * 100) / 100}`; 44 | date = () => 45 | this.dynamicValues 46 | ? `new Date(casual.unix_time).toISOString()` 47 | : `'${new Date(casual.unix_time).toISOString()}'`; 48 | seed = (seed: number) => casual.seed(seed); 49 | } 50 | 51 | const casualFunctionTokens: FunctionTokens = { 52 | import: `import casual from 'casual';`, 53 | seed: 'casual.seed(0);', 54 | seedFunction: 'export const seedMocks = (seed: number) => casual.seed(seed);', 55 | }; 56 | 57 | class FakerMockValueGenerator implements MockValueGenerator { 58 | dynamicValues: boolean; 59 | private fakerInstance: Faker; 60 | 61 | constructor(opts: MockValueGeneratorOptions) { 62 | this.dynamicValues = opts.dynamicValues; 63 | const fakerImport = `faker${opts.generatorLocale.toUpperCase()}`; 64 | if (!(fakerImport in allFakerLocales)) { 65 | throw new Error(`Cannot find faker version for locale ${opts.generatorLocale.toUpperCase()}`); 66 | } 67 | this.fakerInstance = allFakerLocales[`faker${opts.generatorLocale.toUpperCase()}`]; 68 | } 69 | 70 | word = () => (this.dynamicValues ? `faker.lorem.word()` : `'${this.fakerInstance.lorem.word()}'`); 71 | uuid = () => (this.dynamicValues ? `faker.string.uuid()` : `'${this.fakerInstance.string.uuid()}'`); 72 | boolean = () => (this.dynamicValues ? `faker.datatype.boolean()` : this.fakerInstance.datatype.boolean()); 73 | integer = () => 74 | this.dynamicValues 75 | ? `faker.number.int({ min: 0, max: 9999 })` 76 | : this.fakerInstance.number.int({ min: 0, max: 9999 }); 77 | float = () => 78 | this.dynamicValues 79 | ? `faker.number.float({ min: 0, max: 10, fractionDigits: 1 })` 80 | : this.fakerInstance.number.float({ min: 0, max: 10, fractionDigits: 1 }); 81 | date = () => 82 | this.dynamicValues 83 | ? `faker.date.past({ years: 1, refDate: new Date(2022, 0) }).toISOString()` 84 | : `'${this.fakerInstance.date.past({ years: 1, refDate: new Date(2022, 0) }).toISOString()}'`; 85 | seed = (seed: number) => this.fakerInstance.seed(seed); 86 | } 87 | 88 | function getFakerFunctionTokens(locale = 'en'): FunctionTokens { 89 | return { 90 | import: `import { faker${locale.toUpperCase()} as faker } from '@faker-js/faker';`, 91 | seed: 'faker.seed(0);', 92 | seedFunction: 'export const seedMocks = (seed: number) => faker.seed(seed);', 93 | }; 94 | } 95 | 96 | export const setupMockValueGenerator = ({ 97 | generateLibrary, 98 | dynamicValues, 99 | generatorLocale, 100 | }: SetupMockValueGeneratorOptions): MockValueGenerator => { 101 | switch (generateLibrary) { 102 | case 'casual': 103 | return new CasualMockValueGenerator({ dynamicValues, generatorLocale }); 104 | case 'faker': 105 | return new FakerMockValueGenerator({ dynamicValues, generatorLocale }); 106 | } 107 | }; 108 | 109 | export const setupFunctionTokens = (generateLibrary: 'casual' | 'faker', locale?: string): FunctionTokens => { 110 | switch (generateLibrary) { 111 | case 'casual': 112 | return casualFunctionTokens; 113 | case 'faker': 114 | return getFakerFunctionTokens(locale); 115 | } 116 | }; 117 | -------------------------------------------------------------------------------- /tests/enumValues/__snapshots__/spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`enumValues config having 'change-case-all#pascalCase' value should keep underscores for type name only if 'transformUnderscore' is false 1`] = ` 4 | " 5 | export const aMyType = (overrides?: Partial): MyType => { 6 | return { 7 | underscoreEnum: overrides && overrides.hasOwnProperty('underscoreEnum') ? overrides.underscoreEnum! : UnderscoreEnum.Id, 8 | pascalCaseEnum: overrides && overrides.hasOwnProperty('pascalCaseEnum') ? overrides.pascalCaseEnum! : PascalCaseEnum.PascalCase, 9 | camelCaseEnum: overrides && overrides.hasOwnProperty('camelCaseEnum') ? overrides.camelCaseEnum! : CamelCaseEnum.CamelCase, 10 | snakeCaseEnum: overrides && overrides.hasOwnProperty('snakeCaseEnum') ? overrides.snakeCaseEnum! : SnakeCaseEnum.SnakeCase, 11 | screamingSnakeCaseEnum: overrides && overrides.hasOwnProperty('screamingSnakeCaseEnum') ? overrides.screamingSnakeCaseEnum! : ScreamingSnakeCaseEnum.ScreamingSnakeCase, 12 | pascalCase_withUnderscore: overrides && overrides.hasOwnProperty('pascalCase_withUnderscore') ? overrides.pascalCase_withUnderscore! : PascalCase_WithUnderscore.OtherSnakeCase, 13 | }; 14 | }; 15 | " 16 | `; 17 | 18 | exports[`enumValues config having 'change-case-all#pascalCase' value should keep underscores if 'transformUnderscore' is false and 'enumsAsTypes' is true 1`] = ` 19 | " 20 | export const aMyType = (overrides?: Partial): MyType => { 21 | return { 22 | underscoreEnum: overrides && overrides.hasOwnProperty('underscoreEnum') ? overrides.underscoreEnum! : '_id', 23 | pascalCaseEnum: overrides && overrides.hasOwnProperty('pascalCaseEnum') ? overrides.pascalCaseEnum! : 'PascalCase', 24 | camelCaseEnum: overrides && overrides.hasOwnProperty('camelCaseEnum') ? overrides.camelCaseEnum! : 'camelCase', 25 | snakeCaseEnum: overrides && overrides.hasOwnProperty('snakeCaseEnum') ? overrides.snakeCaseEnum! : 'snake_case', 26 | screamingSnakeCaseEnum: overrides && overrides.hasOwnProperty('screamingSnakeCaseEnum') ? overrides.screamingSnakeCaseEnum! : 'SCREAMING_SNAKE_CASE', 27 | pascalCase_withUnderscore: overrides && overrides.hasOwnProperty('pascalCase_withUnderscore') ? overrides.pascalCase_withUnderscore! : 'other_snake_case', 28 | }; 29 | }; 30 | " 31 | `; 32 | 33 | exports[`enumValues config having 'change-case-all#pascalCase' value should update case in pascal case 1`] = ` 34 | " 35 | export const aMyType = (overrides?: Partial): MyType => { 36 | return { 37 | underscoreEnum: overrides && overrides.hasOwnProperty('underscoreEnum') ? overrides.underscoreEnum! : UnderscoreEnum.Id, 38 | pascalCaseEnum: overrides && overrides.hasOwnProperty('pascalCaseEnum') ? overrides.pascalCaseEnum! : PascalCaseEnum.PascalCase, 39 | camelCaseEnum: overrides && overrides.hasOwnProperty('camelCaseEnum') ? overrides.camelCaseEnum! : CamelCaseEnum.CamelCase, 40 | snakeCaseEnum: overrides && overrides.hasOwnProperty('snakeCaseEnum') ? overrides.snakeCaseEnum! : SnakeCaseEnum.SnakeCase, 41 | screamingSnakeCaseEnum: overrides && overrides.hasOwnProperty('screamingSnakeCaseEnum') ? overrides.screamingSnakeCaseEnum! : ScreamingSnakeCaseEnum.ScreamingSnakeCase, 42 | pascalCase_withUnderscore: overrides && overrides.hasOwnProperty('pascalCase_withUnderscore') ? overrides.pascalCase_withUnderscore! : PascalCaseWithUnderscore.OtherSnakeCase, 43 | }; 44 | }; 45 | " 46 | `; 47 | 48 | exports[`enumValues config having 'change-case-all#upperCase' value should keep underscores if 'transformUnderscore' is false 1`] = ` 49 | " 50 | export const aMyType = (overrides?: Partial): MyType => { 51 | return { 52 | underscoreEnum: overrides && overrides.hasOwnProperty('underscoreEnum') ? overrides.underscoreEnum! : UnderscoreEnum._ID, 53 | pascalCaseEnum: overrides && overrides.hasOwnProperty('pascalCaseEnum') ? overrides.pascalCaseEnum! : PascalCaseEnum.PASCALCASE, 54 | camelCaseEnum: overrides && overrides.hasOwnProperty('camelCaseEnum') ? overrides.camelCaseEnum! : CamelCaseEnum.CAMELCASE, 55 | snakeCaseEnum: overrides && overrides.hasOwnProperty('snakeCaseEnum') ? overrides.snakeCaseEnum! : SnakeCaseEnum.SNAKE_CASE, 56 | screamingSnakeCaseEnum: overrides && overrides.hasOwnProperty('screamingSnakeCaseEnum') ? overrides.screamingSnakeCaseEnum! : ScreamingSnakeCaseEnum.SCREAMING_SNAKE_CASE, 57 | pascalCase_withUnderscore: overrides && overrides.hasOwnProperty('pascalCase_withUnderscore') ? overrides.pascalCase_withUnderscore! : PascalCase_WithUnderscore.OTHER_SNAKE_CASE, 58 | }; 59 | }; 60 | " 61 | `; 62 | 63 | exports[`enumValues config having 'change-case-all#upperCase' value should keep underscores if 'transformUnderscore' is false and 'enumsAsTypes' is true 1`] = ` 64 | " 65 | export const aMyType = (overrides?: Partial): MyType => { 66 | return { 67 | underscoreEnum: overrides && overrides.hasOwnProperty('underscoreEnum') ? overrides.underscoreEnum! : '_id', 68 | pascalCaseEnum: overrides && overrides.hasOwnProperty('pascalCaseEnum') ? overrides.pascalCaseEnum! : 'PascalCase', 69 | camelCaseEnum: overrides && overrides.hasOwnProperty('camelCaseEnum') ? overrides.camelCaseEnum! : 'camelCase', 70 | snakeCaseEnum: overrides && overrides.hasOwnProperty('snakeCaseEnum') ? overrides.snakeCaseEnum! : 'snake_case', 71 | screamingSnakeCaseEnum: overrides && overrides.hasOwnProperty('screamingSnakeCaseEnum') ? overrides.screamingSnakeCaseEnum! : 'SCREAMING_SNAKE_CASE', 72 | pascalCase_withUnderscore: overrides && overrides.hasOwnProperty('pascalCase_withUnderscore') ? overrides.pascalCase_withUnderscore! : 'other_snake_case', 73 | }; 74 | }; 75 | " 76 | `; 77 | 78 | exports[`enumValues config having 'change-case-all#upperCase' value should update case in upper case 1`] = ` 79 | " 80 | export const aMyType = (overrides?: Partial): MyType => { 81 | return { 82 | underscoreEnum: overrides && overrides.hasOwnProperty('underscoreEnum') ? overrides.underscoreEnum! : UnderscoreEnum._ID, 83 | pascalCaseEnum: overrides && overrides.hasOwnProperty('pascalCaseEnum') ? overrides.pascalCaseEnum! : PascalCaseEnum.PASCALCASE, 84 | camelCaseEnum: overrides && overrides.hasOwnProperty('camelCaseEnum') ? overrides.camelCaseEnum! : CamelCaseEnum.CAMELCASE, 85 | snakeCaseEnum: overrides && overrides.hasOwnProperty('snakeCaseEnum') ? overrides.snakeCaseEnum! : SnakeCaseEnum.SNAKE_CASE, 86 | screamingSnakeCaseEnum: overrides && overrides.hasOwnProperty('screamingSnakeCaseEnum') ? overrides.screamingSnakeCaseEnum! : ScreamingSnakeCaseEnum.SCREAMING_SNAKE_CASE, 87 | pascalCase_withUnderscore: overrides && overrides.hasOwnProperty('pascalCase_withUnderscore') ? overrides.pascalCase_withUnderscore! : PascalCaseWithUnderscore.OTHER_SNAKE_CASE, 88 | }; 89 | }; 90 | " 91 | `; 92 | 93 | exports[`enumValues config having 'keep' value should have effect on enum type only if 'transformUnderscore' is false 1`] = ` 94 | " 95 | export const aMyType = (overrides?: Partial): MyType => { 96 | return { 97 | underscoreEnum: overrides && overrides.hasOwnProperty('underscoreEnum') ? overrides.underscoreEnum! : UnderscoreEnum._id, 98 | pascalCaseEnum: overrides && overrides.hasOwnProperty('pascalCaseEnum') ? overrides.pascalCaseEnum! : PascalCaseEnum.PascalCase, 99 | camelCaseEnum: overrides && overrides.hasOwnProperty('camelCaseEnum') ? overrides.camelCaseEnum! : CamelCaseEnum.camelCase, 100 | snakeCaseEnum: overrides && overrides.hasOwnProperty('snakeCaseEnum') ? overrides.snakeCaseEnum! : SnakeCaseEnum.snake_case, 101 | screamingSnakeCaseEnum: overrides && overrides.hasOwnProperty('screamingSnakeCaseEnum') ? overrides.screamingSnakeCaseEnum! : ScreamingSnakeCaseEnum.SCREAMING_SNAKE_CASE, 102 | pascalCase_withUnderscore: overrides && overrides.hasOwnProperty('pascalCase_withUnderscore') ? overrides.pascalCase_withUnderscore! : PascalCase_WithUnderscore.other_snake_case, 103 | }; 104 | }; 105 | " 106 | `; 107 | 108 | exports[`enumValues config having 'keep' value should have no effect if 'transformUnderscore' is false and 'enumsAsTypes' is true 1`] = ` 109 | " 110 | export const aMyType = (overrides?: Partial): MyType => { 111 | return { 112 | underscoreEnum: overrides && overrides.hasOwnProperty('underscoreEnum') ? overrides.underscoreEnum! : '_id', 113 | pascalCaseEnum: overrides && overrides.hasOwnProperty('pascalCaseEnum') ? overrides.pascalCaseEnum! : 'PascalCase', 114 | camelCaseEnum: overrides && overrides.hasOwnProperty('camelCaseEnum') ? overrides.camelCaseEnum! : 'camelCase', 115 | snakeCaseEnum: overrides && overrides.hasOwnProperty('snakeCaseEnum') ? overrides.snakeCaseEnum! : 'snake_case', 116 | screamingSnakeCaseEnum: overrides && overrides.hasOwnProperty('screamingSnakeCaseEnum') ? overrides.screamingSnakeCaseEnum! : 'SCREAMING_SNAKE_CASE', 117 | pascalCase_withUnderscore: overrides && overrides.hasOwnProperty('pascalCase_withUnderscore') ? overrides.pascalCase_withUnderscore! : 'other_snake_case', 118 | }; 119 | }; 120 | " 121 | `; 122 | 123 | exports[`enumValues config having 'keep' value should have no effect if 'transformUnderscore' is false and 'useTypeImports' is true 1`] = ` 124 | " 125 | export const aMyType = (overrides?: Partial): MyType => { 126 | return { 127 | underscoreEnum: overrides && overrides.hasOwnProperty('underscoreEnum') ? overrides.underscoreEnum! : ('_id' as UnderscoreEnum), 128 | pascalCaseEnum: overrides && overrides.hasOwnProperty('pascalCaseEnum') ? overrides.pascalCaseEnum! : ('PascalCase' as PascalCaseEnum), 129 | camelCaseEnum: overrides && overrides.hasOwnProperty('camelCaseEnum') ? overrides.camelCaseEnum! : ('camelCase' as CamelCaseEnum), 130 | snakeCaseEnum: overrides && overrides.hasOwnProperty('snakeCaseEnum') ? overrides.snakeCaseEnum! : ('snake_case' as SnakeCaseEnum), 131 | screamingSnakeCaseEnum: overrides && overrides.hasOwnProperty('screamingSnakeCaseEnum') ? overrides.screamingSnakeCaseEnum! : ('SCREAMING_SNAKE_CASE' as ScreamingSnakeCaseEnum), 132 | pascalCase_withUnderscore: overrides && overrides.hasOwnProperty('pascalCase_withUnderscore') ? overrides.pascalCase_withUnderscore! : ('other_snake_case' as PascalCase_WithUnderscore), 133 | }; 134 | }; 135 | " 136 | `; 137 | 138 | exports[`enumValues config having 'keep' value should keep case 1`] = ` 139 | " 140 | export const aMyType = (overrides?: Partial): MyType => { 141 | return { 142 | underscoreEnum: overrides && overrides.hasOwnProperty('underscoreEnum') ? overrides.underscoreEnum! : UnderscoreEnum._id, 143 | pascalCaseEnum: overrides && overrides.hasOwnProperty('pascalCaseEnum') ? overrides.pascalCaseEnum! : PascalCaseEnum.PascalCase, 144 | camelCaseEnum: overrides && overrides.hasOwnProperty('camelCaseEnum') ? overrides.camelCaseEnum! : CamelCaseEnum.camelCase, 145 | snakeCaseEnum: overrides && overrides.hasOwnProperty('snakeCaseEnum') ? overrides.snakeCaseEnum! : SnakeCaseEnum.snake_case, 146 | screamingSnakeCaseEnum: overrides && overrides.hasOwnProperty('screamingSnakeCaseEnum') ? overrides.screamingSnakeCaseEnum! : ScreamingSnakeCaseEnum.SCREAMING_SNAKE_CASE, 147 | pascalCase_withUnderscore: overrides && overrides.hasOwnProperty('pascalCase_withUnderscore') ? overrides.pascalCase_withUnderscore! : PascalCaseWithUnderscore.other_snake_case, 148 | }; 149 | }; 150 | " 151 | `; 152 | 153 | exports[`enumValues config having default value should keep underscores for enum type only if 'transformUnderscore' is false 1`] = ` 154 | " 155 | export const aMyType = (overrides?: Partial): MyType => { 156 | return { 157 | underscoreEnum: overrides && overrides.hasOwnProperty('underscoreEnum') ? overrides.underscoreEnum! : UnderscoreEnum.Id, 158 | pascalCaseEnum: overrides && overrides.hasOwnProperty('pascalCaseEnum') ? overrides.pascalCaseEnum! : PascalCaseEnum.PascalCase, 159 | camelCaseEnum: overrides && overrides.hasOwnProperty('camelCaseEnum') ? overrides.camelCaseEnum! : CamelCaseEnum.CamelCase, 160 | snakeCaseEnum: overrides && overrides.hasOwnProperty('snakeCaseEnum') ? overrides.snakeCaseEnum! : SnakeCaseEnum.SnakeCase, 161 | screamingSnakeCaseEnum: overrides && overrides.hasOwnProperty('screamingSnakeCaseEnum') ? overrides.screamingSnakeCaseEnum! : ScreamingSnakeCaseEnum.ScreamingSnakeCase, 162 | pascalCase_withUnderscore: overrides && overrides.hasOwnProperty('pascalCase_withUnderscore') ? overrides.pascalCase_withUnderscore! : PascalCase_WithUnderscore.OtherSnakeCase, 163 | }; 164 | }; 165 | " 166 | `; 167 | 168 | exports[`enumValues config having default value should keep underscores if 'transformUnderscore' is false and 'enumsAsTypes' is true 1`] = ` 169 | " 170 | export const aMyType = (overrides?: Partial): MyType => { 171 | return { 172 | underscoreEnum: overrides && overrides.hasOwnProperty('underscoreEnum') ? overrides.underscoreEnum! : '_id', 173 | pascalCaseEnum: overrides && overrides.hasOwnProperty('pascalCaseEnum') ? overrides.pascalCaseEnum! : 'PascalCase', 174 | camelCaseEnum: overrides && overrides.hasOwnProperty('camelCaseEnum') ? overrides.camelCaseEnum! : 'camelCase', 175 | snakeCaseEnum: overrides && overrides.hasOwnProperty('snakeCaseEnum') ? overrides.snakeCaseEnum! : 'snake_case', 176 | screamingSnakeCaseEnum: overrides && overrides.hasOwnProperty('screamingSnakeCaseEnum') ? overrides.screamingSnakeCaseEnum! : 'SCREAMING_SNAKE_CASE', 177 | pascalCase_withUnderscore: overrides && overrides.hasOwnProperty('pascalCase_withUnderscore') ? overrides.pascalCase_withUnderscore! : 'other_snake_case', 178 | }; 179 | }; 180 | " 181 | `; 182 | 183 | exports[`enumValues config having default value should update case in pascal case 1`] = ` 184 | " 185 | export const aMyType = (overrides?: Partial): MyType => { 186 | return { 187 | underscoreEnum: overrides && overrides.hasOwnProperty('underscoreEnum') ? overrides.underscoreEnum! : UnderscoreEnum.Id, 188 | pascalCaseEnum: overrides && overrides.hasOwnProperty('pascalCaseEnum') ? overrides.pascalCaseEnum! : PascalCaseEnum.PascalCase, 189 | camelCaseEnum: overrides && overrides.hasOwnProperty('camelCaseEnum') ? overrides.camelCaseEnum! : CamelCaseEnum.CamelCase, 190 | snakeCaseEnum: overrides && overrides.hasOwnProperty('snakeCaseEnum') ? overrides.snakeCaseEnum! : SnakeCaseEnum.SnakeCase, 191 | screamingSnakeCaseEnum: overrides && overrides.hasOwnProperty('screamingSnakeCaseEnum') ? overrides.screamingSnakeCaseEnum! : ScreamingSnakeCaseEnum.ScreamingSnakeCase, 192 | pascalCase_withUnderscore: overrides && overrides.hasOwnProperty('pascalCase_withUnderscore') ? overrides.pascalCase_withUnderscore! : PascalCaseWithUnderscore.OtherSnakeCase, 193 | }; 194 | }; 195 | " 196 | `; 197 | -------------------------------------------------------------------------------- /tests/enumValues/schema.ts: -------------------------------------------------------------------------------- 1 | import { buildSchema } from 'graphql'; 2 | 3 | export default buildSchema(/* GraphQL */ ` 4 | enum UnderscoreEnum { 5 | _id 6 | } 7 | 8 | enum PascalCaseEnum { 9 | PascalCase 10 | } 11 | 12 | enum CamelCaseEnum { 13 | camelCase 14 | } 15 | 16 | enum SnakeCaseEnum { 17 | snake_case 18 | } 19 | 20 | enum ScreamingSnakeCaseEnum { 21 | SCREAMING_SNAKE_CASE 22 | } 23 | 24 | enum PascalCase_WithUnderscore { 25 | other_snake_case 26 | } 27 | 28 | type MyType { 29 | underscoreEnum: UnderscoreEnum! 30 | pascalCaseEnum: PascalCaseEnum! 31 | camelCaseEnum: CamelCaseEnum! 32 | snakeCaseEnum: SnakeCaseEnum! 33 | screamingSnakeCaseEnum: ScreamingSnakeCaseEnum! 34 | pascalCase_withUnderscore: PascalCase_WithUnderscore! 35 | } 36 | `); 37 | -------------------------------------------------------------------------------- /tests/enumValues/spec.ts: -------------------------------------------------------------------------------- 1 | import { plugin } from '../../src'; 2 | import enumSchema from './schema'; 3 | 4 | describe('enumValues config', () => { 5 | describe(`having 'keep' value`, () => { 6 | it('should keep case', async () => { 7 | const result = await plugin(enumSchema, [], { 8 | enumValues: 'keep', 9 | }); 10 | 11 | expect(result).toBeDefined(); 12 | expect(result).toContain('UnderscoreEnum._id'); 13 | expect(result).toContain('PascalCaseEnum.PascalCase'); 14 | expect(result).toContain('CamelCaseEnum.camelCase'); 15 | expect(result).toContain('SnakeCaseEnum.snake_case'); 16 | expect(result).toContain('ScreamingSnakeCaseEnum.SCREAMING_SNAKE_CASE'); 17 | expect(result).toContain('PascalCaseWithUnderscore.other_snake_case'); 18 | expect(result).toMatchSnapshot(); 19 | }); 20 | 21 | it(`should have effect on enum type only if 'transformUnderscore' is false`, async () => { 22 | const result = await plugin(enumSchema, [], { 23 | enumValues: 'keep', 24 | transformUnderscore: false, 25 | }); 26 | 27 | expect(result).toBeDefined(); 28 | expect(result).toContain('UnderscoreEnum._id'); 29 | expect(result).toContain('PascalCaseEnum.PascalCase'); 30 | expect(result).toContain('CamelCaseEnum.camelCase'); 31 | expect(result).toContain('SnakeCaseEnum.snake_case'); 32 | expect(result).toContain('ScreamingSnakeCaseEnum.SCREAMING_SNAKE_CASE'); 33 | expect(result).toContain('PascalCase_WithUnderscore.other_snake_case'); 34 | expect(result).toMatchSnapshot(); 35 | }); 36 | 37 | it(`should have no effect if 'transformUnderscore' is false and 'enumsAsTypes' is true`, async () => { 38 | const result = await plugin(enumSchema, [], { 39 | enumValues: 'keep', 40 | transformUnderscore: false, 41 | enumsAsTypes: true, 42 | }); 43 | 44 | expect(result).toBeDefined(); 45 | expect(result).toContain('_id'); 46 | expect(result).toContain('PascalCase'); 47 | expect(result).toContain('camelCase'); 48 | expect(result).toContain('snake_case'); 49 | expect(result).toContain('SCREAMING_SNAKE_CASE'); 50 | expect(result).toContain('other_snake_case'); 51 | expect(result).toMatchSnapshot(); 52 | }); 53 | 54 | it(`should have no effect if 'transformUnderscore' is false and 'useTypeImports' is true`, async () => { 55 | const result = await plugin(enumSchema, [], { 56 | enumValues: 'keep', 57 | transformUnderscore: false, 58 | enumsAsTypes: true, 59 | useTypeImports: true, 60 | }); 61 | 62 | expect(result).toBeDefined(); 63 | expect(result).toContain('_id'); 64 | expect(result).toContain(`('PascalCase' as PascalCaseEnum)`); 65 | expect(result).toContain(`('camelCase' as CamelCaseEnum)`); 66 | expect(result).toContain(`('snake_case' as SnakeCaseEnum)`); 67 | expect(result).toContain(`('SCREAMING_SNAKE_CASE' as ScreamingSnakeCaseEnum)`); 68 | expect(result).toContain(`('other_snake_case' as PascalCase_WithUnderscore)`); 69 | expect(result).toMatchSnapshot(); 70 | }); 71 | }); 72 | 73 | describe(`having default value`, () => { 74 | it('should update case in pascal case', async () => { 75 | const result = await plugin(enumSchema, [], {}); 76 | 77 | expect(result).toBeDefined(); 78 | expect(result).toContain('UnderscoreEnum.Id'); 79 | expect(result).toContain('PascalCaseEnum.PascalCase'); 80 | expect(result).toContain('CamelCaseEnum.CamelCase'); 81 | expect(result).toContain('SnakeCaseEnum.SnakeCase'); 82 | expect(result).toContain('ScreamingSnakeCaseEnum.ScreamingSnakeCase'); 83 | expect(result).toContain('PascalCaseWithUnderscore.OtherSnakeCase'); 84 | expect(result).toMatchSnapshot(); 85 | }); 86 | 87 | it(`should keep underscores for enum type only if 'transformUnderscore' is false`, async () => { 88 | const result = await plugin(enumSchema, [], { 89 | transformUnderscore: false, 90 | }); 91 | 92 | expect(result).toBeDefined(); 93 | expect(result).toContain('UnderscoreEnum.Id'); 94 | expect(result).toContain('PascalCaseEnum.PascalCase'); 95 | expect(result).toContain('CamelCaseEnum.CamelCase'); 96 | expect(result).toContain('SnakeCaseEnum.SnakeCase'); 97 | expect(result).toContain('ScreamingSnakeCaseEnum.ScreamingSnakeCase'); 98 | expect(result).toContain('PascalCase_WithUnderscore.OtherSnakeCase'); 99 | expect(result).toMatchSnapshot(); 100 | }); 101 | 102 | it(`should keep underscores if 'transformUnderscore' is false and 'enumsAsTypes' is true`, async () => { 103 | const result = await plugin(enumSchema, [], { 104 | transformUnderscore: false, 105 | enumsAsTypes: true, 106 | }); 107 | 108 | expect(result).toBeDefined(); 109 | expect(result).toContain('_id'); 110 | expect(result).toContain('PascalCase'); 111 | expect(result).toContain('camelCase'); 112 | expect(result).toContain('snake_case'); 113 | expect(result).toContain('SCREAMING_SNAKE_CASE'); 114 | expect(result).toContain('other_snake_case'); 115 | expect(result).toMatchSnapshot(); 116 | }); 117 | }); 118 | 119 | describe(`having 'change-case-all#pascalCase' value`, () => { 120 | it('should update case in pascal case', async () => { 121 | const result = await plugin(enumSchema, [], { 122 | enumValues: 'change-case-all#pascalCase', 123 | }); 124 | 125 | expect(result).toBeDefined(); 126 | expect(result).toContain('UnderscoreEnum.Id'); 127 | expect(result).toContain('PascalCaseEnum.PascalCase'); 128 | expect(result).toContain('CamelCaseEnum.CamelCase'); 129 | expect(result).toContain('SnakeCaseEnum.SnakeCase'); 130 | expect(result).toContain('ScreamingSnakeCaseEnum.ScreamingSnakeCase'); 131 | expect(result).toContain('PascalCaseWithUnderscore.OtherSnakeCase'); 132 | expect(result).toMatchSnapshot(); 133 | }); 134 | 135 | it(`should keep underscores for type name only if 'transformUnderscore' is false`, async () => { 136 | const result = await plugin(enumSchema, [], { 137 | enumValues: 'change-case-all#pascalCase', 138 | transformUnderscore: false, 139 | }); 140 | 141 | expect(result).toBeDefined(); 142 | expect(result).toContain('UnderscoreEnum.Id'); 143 | expect(result).toContain('PascalCaseEnum.PascalCase'); 144 | expect(result).toContain('CamelCaseEnum.CamelCase'); 145 | expect(result).toContain('SnakeCaseEnum.SnakeCase'); 146 | expect(result).toContain('ScreamingSnakeCaseEnum.ScreamingSnakeCase'); 147 | expect(result).toContain('PascalCase_WithUnderscore.OtherSnakeCase'); 148 | expect(result).toMatchSnapshot(); 149 | }); 150 | 151 | it(`should keep underscores if 'transformUnderscore' is false and 'enumsAsTypes' is true`, async () => { 152 | const result = await plugin(enumSchema, [], { 153 | enumValues: 'change-case-all#pascalCase', 154 | transformUnderscore: false, 155 | enumsAsTypes: true, 156 | }); 157 | 158 | expect(result).toBeDefined(); 159 | expect(result).toContain('_id'); 160 | expect(result).toContain('PascalCase'); 161 | expect(result).toContain('camelCase'); 162 | expect(result).toContain('snake_case'); 163 | expect(result).toContain('SCREAMING_SNAKE_CASE'); 164 | expect(result).toContain('other_snake_case'); 165 | expect(result).toMatchSnapshot(); 166 | }); 167 | }); 168 | 169 | describe(`having 'change-case-all#upperCase' value`, () => { 170 | it('should update case in upper case', async () => { 171 | const result = await plugin(enumSchema, [], { 172 | enumValues: 'change-case-all#upperCase', 173 | }); 174 | 175 | expect(result).toBeDefined(); 176 | expect(result).toContain('UnderscoreEnum._ID'); 177 | expect(result).toContain('PascalCaseEnum.PASCALCASE'); 178 | expect(result).toContain('CamelCaseEnum.CAMELCASE'); 179 | expect(result).toContain('SnakeCaseEnum.SNAKE_CASE'); 180 | expect(result).toContain('ScreamingSnakeCaseEnum.SCREAMING_SNAKE_CASE'); 181 | expect(result).toContain('PascalCaseWithUnderscore.OTHER_SNAKE_CASE'); 182 | expect(result).toMatchSnapshot(); 183 | }); 184 | 185 | it(`should keep underscores if 'transformUnderscore' is false`, async () => { 186 | const result = await plugin(enumSchema, [], { 187 | enumValues: 'change-case-all#upperCase', 188 | transformUnderscore: false, 189 | }); 190 | 191 | expect(result).toBeDefined(); 192 | expect(result).toBeDefined(); 193 | expect(result).toContain('UnderscoreEnum._ID'); 194 | expect(result).toContain('PascalCaseEnum.PASCALCASE'); 195 | expect(result).toContain('CamelCaseEnum.CAMELCASE'); 196 | expect(result).toContain('SnakeCaseEnum.SNAKE_CASE'); 197 | expect(result).toContain('ScreamingSnakeCaseEnum.SCREAMING_SNAKE_CASE'); 198 | expect(result).toContain('PascalCase_WithUnderscore.OTHER_SNAKE_CASE'); 199 | expect(result).toMatchSnapshot(); 200 | }); 201 | 202 | it(`should keep underscores if 'transformUnderscore' is false and 'enumsAsTypes' is true`, async () => { 203 | const result = await plugin(enumSchema, [], { 204 | enumValues: 'change-case-all#upperCase', 205 | transformUnderscore: false, 206 | enumsAsTypes: true, 207 | }); 208 | 209 | expect(result).toBeDefined(); 210 | expect(result).toBeDefined(); 211 | expect(result).toContain('_id'); 212 | expect(result).toContain('PascalCase'); 213 | expect(result).toContain('camelCase'); 214 | expect(result).toContain('snake_case'); 215 | expect(result).toContain('SCREAMING_SNAKE_CASE'); 216 | expect(result).toContain('other_snake_case'); 217 | expect(result).toMatchSnapshot(); 218 | }); 219 | }); 220 | }); 221 | -------------------------------------------------------------------------------- /tests/generateLibrary/casual/__snapshots__/spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should generate dynamic values when dynamicValues is true 1`] = ` 4 | Object { 5 | "id": "99bd9d8d-79a6-474e-8f46-6cc8796ed151", 6 | "obj": Object { 7 | "bool": false, 8 | "flt": 3.68, 9 | "int": 202, 10 | }, 11 | "str": "est", 12 | } 13 | `; 14 | 15 | exports[`should generate dynamic values when dynamicValues is true 2`] = ` 16 | Object { 17 | "id": "ec2ddf7c-d78c-4a1b-a928-ec816742cb73", 18 | "obj": Object { 19 | "bool": true, 20 | "flt": 0.19, 21 | "int": 1352, 22 | }, 23 | "str": "similique", 24 | } 25 | `; 26 | -------------------------------------------------------------------------------- /tests/generateLibrary/casual/spec.ts: -------------------------------------------------------------------------------- 1 | import { anA, seedMocks } from './mocks'; 2 | 3 | it('should generate dynamic values when dynamicValues is true', () => { 4 | const a1 = anA(); 5 | expect(a1).toMatchSnapshot(); 6 | 7 | const a2 = anA(); 8 | expect(a2).toMatchSnapshot(); 9 | 10 | expect(a1).not.toEqual(a2); 11 | }); 12 | 13 | it('should generate dynamic values from seed when dynamicValues is true', () => { 14 | seedMocks(0); 15 | const a1 = anA(); 16 | 17 | seedMocks(0); 18 | const a1Copy = anA(); 19 | 20 | seedMocks(1); 21 | const a2 = anA(); 22 | 23 | expect(a1).toEqual(a1Copy); 24 | expect(a1).not.toEqual(a2); 25 | expect(a1Copy).not.toEqual(a2); 26 | }); 27 | -------------------------------------------------------------------------------- /tests/generateLibrary/faker/__snapshots__/spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should generate dynamic values when dynamicValues is true 1`] = ` 4 | Object { 5 | "id": "89bd9d8d-69a6-474e-80f4-67cc8796ed15", 6 | "obj": Object { 7 | "bool": false, 8 | "flt": 3.7, 9 | "int": 202, 10 | }, 11 | "str": "socius", 12 | } 13 | `; 14 | 15 | exports[`should generate dynamic values when dynamicValues is true 2`] = ` 16 | Object { 17 | "id": "fc2ddf7c-c78c-4a1b-8a92-8fc816742cb7", 18 | "obj": Object { 19 | "bool": true, 20 | "flt": 0.1, 21 | "int": 1352, 22 | }, 23 | "str": "minus", 24 | } 25 | `; 26 | -------------------------------------------------------------------------------- /tests/generateLibrary/faker/spec.ts: -------------------------------------------------------------------------------- 1 | import { anA, seedMocks } from './mocks'; 2 | 3 | it('should generate dynamic values when dynamicValues is true', () => { 4 | const a1 = anA(); 5 | expect(a1).toMatchSnapshot(); 6 | 7 | const a2 = anA(); 8 | expect(a2).toMatchSnapshot(); 9 | 10 | expect(a1).not.toEqual(a2); 11 | }); 12 | 13 | it('should generate dynamic values from seed when dynamicValues is true', () => { 14 | seedMocks(0); 15 | const a1 = anA(); 16 | 17 | seedMocks(0); 18 | const a1Copy = anA(); 19 | 20 | seedMocks(1); 21 | const a2 = anA(); 22 | 23 | expect(a1).toEqual(a1Copy); 24 | expect(a1).not.toEqual(a2); 25 | expect(a1Copy).not.toEqual(a2); 26 | }); 27 | -------------------------------------------------------------------------------- /tests/generateLibrary/schema.ts: -------------------------------------------------------------------------------- 1 | import { buildSchema } from 'graphql'; 2 | 3 | export default buildSchema(/* GraphQL */ ` 4 | type A { 5 | id: ID! 6 | str: String! 7 | obj: B! 8 | } 9 | 10 | type B { 11 | int: Int! 12 | flt: Float! 13 | bool: Boolean! 14 | } 15 | `); 16 | -------------------------------------------------------------------------------- /tests/generateLibrary/types.ts: -------------------------------------------------------------------------------- 1 | export type A = { 2 | id: string; 3 | str: string; 4 | obj: B; 5 | }; 6 | 7 | export type B = { 8 | int: number; 9 | flt: number; 10 | bool: boolean; 11 | }; 12 | -------------------------------------------------------------------------------- /tests/globalSetup.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import { plugin } from '../src'; 3 | import circularRelationshipsSchema from './terminateCircularRelationships/schema'; 4 | import generateLibrarySchema from './generateLibrary/schema'; 5 | 6 | export default async () => { 7 | const terminateCircularRelationshipsMocks = await plugin(circularRelationshipsSchema, [], { 8 | typesFile: './types.ts', 9 | terminateCircularRelationships: true, 10 | }); 11 | fs.writeFileSync('./tests/terminateCircularRelationships/mocks.ts', terminateCircularRelationshipsMocks.toString()); 12 | 13 | const generateWithFakerMocks = await plugin(generateLibrarySchema, [], { 14 | typesFile: '../types.ts', 15 | dynamicValues: true, 16 | generateLibrary: 'faker', 17 | }); 18 | fs.writeFileSync('./tests/generateLibrary/faker/mocks.ts', generateWithFakerMocks.toString()); 19 | 20 | const generateWithCasualMocks = await plugin(generateLibrarySchema, [], { 21 | typesFile: '../types.ts', 22 | dynamicValues: true, 23 | generateLibrary: 'casual', 24 | }); 25 | fs.writeFileSync('./tests/generateLibrary/casual/mocks.ts', generateWithCasualMocks.toString()); 26 | }; 27 | -------------------------------------------------------------------------------- /tests/perTypeFieldGeneration/schema.ts: -------------------------------------------------------------------------------- 1 | import { buildSchema } from 'graphql/index'; 2 | 3 | export default buildSchema(/* GraphQL */ ` 4 | scalar Date 5 | scalar DateTime 6 | 7 | enum EnumExample { 8 | LOREM 9 | IPSUM 10 | } 11 | 12 | type A { 13 | id: ID! 14 | str: String! 15 | email: String! 16 | date: Date! 17 | overriddenDate: Date! 18 | dateTime: DateTime! 19 | } 20 | 21 | type B { 22 | id: ID! 23 | str: String! 24 | email: String! 25 | date: Date! 26 | overriddenDate: Date! 27 | dateTime: DateTime! 28 | } 29 | 30 | type C { 31 | id: ID! 32 | str: String! 33 | enum: EnumExample! 34 | } 35 | 36 | type D { 37 | nested: C! 38 | } 39 | `); 40 | -------------------------------------------------------------------------------- /tests/perTypeFieldGeneration/spec.ts: -------------------------------------------------------------------------------- 1 | import { plugin, TypescriptMocksPluginConfig } from '../../src'; 2 | import testSchema from './schema'; 3 | 4 | jest.mock('@faker-js/faker', () => ({ 5 | fakerEN: { 6 | date: { 7 | future: () => new Date('2050-01-01'), 8 | past: () => new Date('2020-01-01'), 9 | recent: () => new Date('2022-01-01'), 10 | }, 11 | lorem: { 12 | sentence: () => 'A sentence', 13 | word: () => 'Word', 14 | }, 15 | number: { 16 | int: () => 1, 17 | }, 18 | internet: { 19 | email: () => 'my@email.com', 20 | }, 21 | helpers: { 22 | arrayElement: (arr: unknown[]) => arr[0], 23 | }, 24 | seed: jest.fn(), 25 | }, 26 | fakerFR: { 27 | date: { 28 | future: () => new Date('2050-01-01'), 29 | past: () => new Date('2020-01-01'), 30 | recent: () => new Date('2022-01-01'), 31 | }, 32 | lorem: { 33 | sentence: () => 'A sentence', 34 | word: () => 'Word', 35 | }, 36 | number: { 37 | int: () => 1, 38 | }, 39 | internet: { 40 | email: () => 'my@email.com', 41 | }, 42 | helpers: { 43 | arrayElement: (arr: unknown[]) => arr[0], 44 | }, 45 | seed: jest.fn(), 46 | }, 47 | })); 48 | 49 | describe('per type field generation with faker', () => { 50 | const config = { 51 | generateLibrary: 'faker', 52 | scalars: { 53 | String: 'lorem.sentence', 54 | Date: 'date.future', 55 | ID: { 56 | generator: 'number.int', 57 | arguments: [{ min: 1, max: 100 }], 58 | }, 59 | }, 60 | } as TypescriptMocksPluginConfig; 61 | 62 | describe('with different locale', () => { 63 | it('should update faker import with correct locale', async () => { 64 | const result = await plugin(testSchema, [], { 65 | ...config, 66 | dynamicValues: true, 67 | locale: 'fr', 68 | }); 69 | expect(result).toBeDefined(); 70 | 71 | expect(result).toContain("import { fakerFR as faker } from '@faker-js/faker';"); 72 | expect(result).toMatchSnapshot(); 73 | }); 74 | }); 75 | 76 | describe('with dynamic values', () => { 77 | beforeAll(() => { 78 | config.dynamicValues = true; 79 | }); 80 | 81 | it('uses per field generation if field name matches', async () => { 82 | const result = await plugin(testSchema, [], { 83 | ...config, 84 | fieldGeneration: { 85 | A: { email: 'internet.email' }, 86 | }, 87 | }); 88 | expect(result).toBeDefined(); 89 | 90 | // Custom generation in type A 91 | expect(result).toContain( 92 | "email: overrides && overrides.hasOwnProperty('email') ? overrides.email! : faker['internet']['email']()", 93 | ); 94 | // Original generation in type B (unchanged) 95 | expect(result).toContain( 96 | "email: overrides && overrides.hasOwnProperty('email') ? overrides.email! : faker['lorem']['sentence'](),", 97 | ); 98 | 99 | expect(result).toMatchSnapshot(); 100 | }); 101 | 102 | it('can overwrite a scalar value', async () => { 103 | const result = await plugin(testSchema, [], { 104 | ...config, 105 | fieldGeneration: { 106 | A: { email: 'internet.email', overriddenDate: 'date.past' }, 107 | }, 108 | }); 109 | expect(result).toBeDefined(); 110 | 111 | expect(result).toContain( 112 | "date: overrides && overrides.hasOwnProperty('date') ? overrides.date! : faker['date']['future']()", 113 | ); 114 | expect(result).toContain( 115 | "overriddenDate: overrides && overrides.hasOwnProperty('overriddenDate') ? overrides.overriddenDate! : faker['date']['past']()", 116 | ); 117 | 118 | expect(result).toMatchSnapshot(); 119 | }); 120 | 121 | it('can overwrite a nested value with null', async () => { 122 | const result = await plugin(testSchema, [], { 123 | ...config, 124 | fieldGeneration: { 125 | D: { nested: 'null' }, 126 | }, 127 | }); 128 | expect(result).toBeDefined(); 129 | 130 | expect(result).toContain("overrides && overrides.hasOwnProperty('nested') ? overrides.nested! : null"); 131 | 132 | expect(result).toMatchSnapshot(); 133 | }); 134 | 135 | it('can overwrite a nested value with null when terminateCircularRelationships is true', async () => { 136 | const result = await plugin(testSchema, [], { 137 | ...config, 138 | terminateCircularRelationships: true, 139 | fieldGeneration: { 140 | D: { nested: 'null' }, 141 | }, 142 | }); 143 | expect(result).toBeDefined(); 144 | 145 | expect(result).toContain("overrides && overrides.hasOwnProperty('nested') ? overrides.nested! : null"); 146 | 147 | expect(result).toMatchSnapshot(); 148 | }); 149 | 150 | it('can overwrite an enum value', async () => { 151 | const result = await plugin(testSchema, [], { 152 | ...config, 153 | fieldGeneration: { 154 | C: { enum: { generator: 'helpers.arrayElement', arguments: [['active', 'disabled']] } }, 155 | }, 156 | }); 157 | expect(result).toBeDefined(); 158 | 159 | expect(result).toContain( 160 | `enum: overrides && overrides.hasOwnProperty('enum') ? overrides.enum! : faker['helpers']['arrayElement'](...[["active","disabled"]]),`, 161 | ); 162 | 163 | expect(result).toMatchSnapshot(); 164 | }); 165 | 166 | it('can overwrite an enum value when enumsAsTypes is true', async () => { 167 | const result = await plugin(testSchema, [], { 168 | ...config, 169 | fieldGeneration: { 170 | C: { enum: { generator: 'helpers.arrayElement', arguments: [['active', 'disabled']] } }, 171 | }, 172 | enumsAsTypes: true, 173 | }); 174 | expect(result).toBeDefined(); 175 | 176 | expect(result).toContain( 177 | `enum: overrides && overrides.hasOwnProperty('enum') ? overrides.enum! : faker['helpers']['arrayElement'](...[["active","disabled"]]),`, 178 | ); 179 | 180 | expect(result).toMatchSnapshot(); 181 | }); 182 | 183 | it('can apply generator override to all fields of a specific name', async () => { 184 | const result = await plugin(testSchema, [], { 185 | ...config, 186 | fieldGeneration: { 187 | // eslint-disable-next-line @typescript-eslint/naming-convention 188 | _all: { email: 'internet.email' }, 189 | }, 190 | }); 191 | expect(result).toBeDefined(); 192 | 193 | // Check both `email` fields are updated 194 | expect( 195 | String(result).match( 196 | /email: overrides && overrides.hasOwnProperty\('email'\) \? overrides.email! : faker\['internet']\['email']\(\)/g, 197 | ).length, 198 | ).toEqual(2); 199 | expect(result).toMatchSnapshot(); 200 | }); 201 | 202 | it('can accept arguments', async () => { 203 | const result = await plugin(testSchema, [], { 204 | ...config, 205 | fieldGeneration: { 206 | A: { 207 | dateTime: { 208 | generator: 'date.recent', 209 | arguments: [10], 210 | }, 211 | }, 212 | }, 213 | }); 214 | expect(result).toBeDefined(); 215 | 216 | expect(result).toContain( 217 | "dateTime: overrides && overrides.hasOwnProperty('dateTime') ? overrides.dateTime! : faker['date']['recent'](...[10])", 218 | ); 219 | 220 | expect(result).toMatchSnapshot(); 221 | }); 222 | 223 | it('can accept an extra function call', async () => { 224 | const result = await plugin(testSchema, [], { 225 | ...config, 226 | fieldGeneration: { 227 | A: { 228 | dateTime: { 229 | generator: 'date.recent', 230 | arguments: [10], 231 | extra: { 232 | function: 'toLocaleDateString', 233 | }, 234 | }, 235 | }, 236 | }, 237 | }); 238 | expect(result).toBeDefined(); 239 | 240 | expect(result).toContain( 241 | "dateTime: overrides && overrides.hasOwnProperty('dateTime') ? overrides.dateTime! : faker['date']['recent'](...[10]).toLocaleDateString()", 242 | ); 243 | 244 | expect(result).toMatchSnapshot(); 245 | }); 246 | 247 | it('can accept an extra function call with arguments', async () => { 248 | const result = await plugin(testSchema, [], { 249 | ...config, 250 | fieldGeneration: { 251 | A: { 252 | dateTime: { 253 | generator: 'date.recent', 254 | arguments: [10], 255 | extra: { 256 | function: 'toLocaleDateString', 257 | arguments: ['en-GB'], 258 | }, 259 | }, 260 | }, 261 | }, 262 | }); 263 | expect(result).toBeDefined(); 264 | 265 | expect(result).toContain( 266 | "dateTime: overrides && overrides.hasOwnProperty('dateTime') ? overrides.dateTime! : faker['date']['recent'](...[10]).toLocaleDateString(...[\"en-GB\"])", 267 | ); 268 | 269 | expect(result).toMatchSnapshot(); 270 | }); 271 | 272 | it('can accept an extra function call with arguments shorthand', async () => { 273 | const result = await plugin(testSchema, [], { 274 | ...config, 275 | fieldGeneration: { 276 | A: { 277 | dateTime: { 278 | generator: 'date.recent', 279 | arguments: [10], 280 | extra: { 281 | function: 'toLocaleDateString', 282 | arguments: 'en-GB', 283 | }, 284 | }, 285 | }, 286 | }, 287 | }); 288 | expect(result).toBeDefined(); 289 | 290 | expect(result).toContain( 291 | "dateTime: overrides && overrides.hasOwnProperty('dateTime') ? overrides.dateTime! : faker['date']['recent'](...[10]).toLocaleDateString(...[\"en-GB\"])", 292 | ); 293 | 294 | expect(result).toMatchSnapshot(); 295 | }); 296 | }); 297 | 298 | describe('without dynamic values', () => { 299 | beforeAll(() => { 300 | config.dynamicValues = false; 301 | }); 302 | 303 | it('uses per field generation if field name matches', async () => { 304 | const result = await plugin(testSchema, [], { 305 | ...config, 306 | fieldGeneration: { 307 | A: { email: 'internet.email' }, 308 | }, 309 | }); 310 | expect(result).toBeDefined(); 311 | 312 | // Custom generation in type A 313 | expect(result).toContain( 314 | "email: overrides && overrides.hasOwnProperty('email') ? overrides.email! : 'my@email.com'", 315 | ); 316 | // Original generation in type B (unchanged) 317 | expect(result).toContain( 318 | "email: overrides && overrides.hasOwnProperty('email') ? overrides.email! : 'A sentence", 319 | ); 320 | 321 | expect(result).toMatchSnapshot(); 322 | }); 323 | 324 | it('can overwrite a scalar value', async () => { 325 | const result = await plugin(testSchema, [], { 326 | ...config, 327 | fieldGeneration: { 328 | A: { email: 'internet.email', overriddenDate: 'date.past' }, 329 | }, 330 | }); 331 | expect(result).toBeDefined(); 332 | 333 | expect(result).toContain( 334 | 'date: overrides && overrides.hasOwnProperty(\'date\') ? overrides.date! : "2050-01-01T00:00:00.000Z"', 335 | ); 336 | expect(result).toContain( 337 | 'overriddenDate: overrides && overrides.hasOwnProperty(\'overriddenDate\') ? overrides.overriddenDate! : "2020-01-01T00:00:00.000Z"', 338 | ); 339 | 340 | expect(result).toMatchSnapshot(); 341 | }); 342 | 343 | it('can overwrite an enum value', async () => { 344 | const result = await plugin(testSchema, [], { 345 | ...config, 346 | fieldGeneration: { 347 | C: { enum: 'internet.email' }, 348 | }, 349 | }); 350 | expect(result).toBeDefined(); 351 | 352 | expect(result).toContain( 353 | "enum: overrides && overrides.hasOwnProperty('enum') ? overrides.enum! : 'my@email.com'", 354 | ); 355 | 356 | expect(result).toMatchSnapshot(); 357 | }); 358 | 359 | it('can overwrite an enum value when enumsAsTypes is true', async () => { 360 | const result = await plugin(testSchema, [], { 361 | ...config, 362 | fieldGeneration: { 363 | C: { enum: 'internet.email' }, 364 | }, 365 | enumsAsTypes: true, 366 | }); 367 | expect(result).toBeDefined(); 368 | 369 | expect(result).toContain( 370 | "enum: overrides && overrides.hasOwnProperty('enum') ? overrides.enum! : 'my@email.com'", 371 | ); 372 | 373 | expect(result).toMatchSnapshot(); 374 | }); 375 | 376 | it('can apply generator override to all fields of a specific name', async () => { 377 | const result = await plugin(testSchema, [], { 378 | ...config, 379 | fieldGeneration: { 380 | // eslint-disable-next-line @typescript-eslint/naming-convention 381 | _all: { email: 'internet.email' }, 382 | }, 383 | }); 384 | expect(result).toBeDefined(); 385 | 386 | // Check both `email` fields are updated 387 | expect( 388 | String(result).match( 389 | /email: overrides && overrides.hasOwnProperty\('email'\) \? overrides.email! : 'my@email.com'/g, 390 | ).length, 391 | ).toEqual(2); 392 | expect(result).toMatchSnapshot(); 393 | }); 394 | 395 | it('can accept arguments', async () => { 396 | const result = await plugin(testSchema, [], { 397 | ...config, 398 | fieldGeneration: { 399 | A: { 400 | dateTime: { 401 | generator: 'date.recent', 402 | arguments: [10], 403 | }, 404 | }, 405 | }, 406 | }); 407 | expect(result).toBeDefined(); 408 | 409 | expect(result).toContain( 410 | 'dateTime: overrides && overrides.hasOwnProperty(\'dateTime\') ? overrides.dateTime! : "2022-01-01T00:00:00.000Z"', 411 | ); 412 | 413 | expect(result).toMatchSnapshot(); 414 | }); 415 | 416 | it('can accept an extra function call', async () => { 417 | const result = await plugin(testSchema, [], { 418 | ...config, 419 | fieldGeneration: { 420 | A: { 421 | dateTime: { 422 | generator: 'date.recent', 423 | arguments: [10], 424 | extra: { 425 | function: 'toLocaleDateString', 426 | }, 427 | }, 428 | }, 429 | }, 430 | }); 431 | expect(result).toBeDefined(); 432 | 433 | expect(result).toContain( 434 | "dateTime: overrides && overrides.hasOwnProperty('dateTime') ? overrides.dateTime! : '1/1/2022'", 435 | ); 436 | 437 | expect(result).toMatchSnapshot(); 438 | }); 439 | 440 | it('can accept an extra function call with arguments', async () => { 441 | const result = await plugin(testSchema, [], { 442 | ...config, 443 | fieldGeneration: { 444 | A: { 445 | dateTime: { 446 | generator: 'date.recent', 447 | arguments: [10], 448 | extra: { 449 | function: 'toLocaleDateString', 450 | arguments: ['en-GB'], 451 | }, 452 | }, 453 | }, 454 | }, 455 | }); 456 | expect(result).toBeDefined(); 457 | 458 | expect(result).toContain( 459 | "dateTime: overrides && overrides.hasOwnProperty('dateTime') ? overrides.dateTime! : '01/01/2022'", 460 | ); 461 | 462 | expect(result).toMatchSnapshot(); 463 | }); 464 | }); 465 | }); 466 | 467 | describe('per type field generation with casual', () => { 468 | const config = { 469 | generateLibrary: 'casual', 470 | scalars: { 471 | String: 'word', 472 | Date: 'date', 473 | ID: { 474 | generator: 'datatype.integer', 475 | arguments: [1, 100], 476 | }, 477 | }, 478 | } as TypescriptMocksPluginConfig; 479 | 480 | describe('with dynamic values', () => { 481 | beforeAll(() => { 482 | config.dynamicValues = true; 483 | }); 484 | 485 | it('uses per field generation if field name matches', async () => { 486 | const result = await plugin(testSchema, [], { 487 | ...config, 488 | fieldGeneration: { 489 | A: { email: 'email' }, 490 | }, 491 | }); 492 | expect(result).toBeDefined(); 493 | 494 | // Custom generation in type A 495 | expect(result).toContain( 496 | "email: overrides && overrides.hasOwnProperty('email') ? overrides.email! : casual['email']", 497 | ); 498 | // Original generation in type B (unchanged) 499 | expect(result).toContain( 500 | "email: overrides && overrides.hasOwnProperty('email') ? overrides.email! : casual['word'],", 501 | ); 502 | 503 | expect(result).toMatchSnapshot(); 504 | }); 505 | 506 | it('can overwrite a scalar value', async () => { 507 | const result = await plugin(testSchema, [], { 508 | ...config, 509 | fieldGeneration: { 510 | A: { email: 'email', overriddenDate: 'date' }, 511 | }, 512 | }); 513 | expect(result).toBeDefined(); 514 | 515 | expect(result).toContain( 516 | "date: overrides && overrides.hasOwnProperty('date') ? overrides.date! : casual['date']", 517 | ); 518 | expect(result).toContain( 519 | "overriddenDate: overrides && overrides.hasOwnProperty('overriddenDate') ? overrides.overriddenDate! : casual['date']()", 520 | ); 521 | 522 | expect(result).toMatchSnapshot(); 523 | }); 524 | 525 | it('can overwrite an enum value', async () => { 526 | const result = await plugin(testSchema, [], { 527 | ...config, 528 | fieldGeneration: { 529 | C: { enum: 'email' }, 530 | }, 531 | }); 532 | expect(result).toBeDefined(); 533 | 534 | expect(result).toContain( 535 | "enum: overrides && overrides.hasOwnProperty('enum') ? overrides.enum! : casual['email'],", 536 | ); 537 | 538 | expect(result).toMatchSnapshot(); 539 | }); 540 | 541 | it('can overwrite an enum value when enumsAsTypes is true', async () => { 542 | const result = await plugin(testSchema, [], { 543 | ...config, 544 | fieldGeneration: { 545 | C: { enum: 'email' }, 546 | }, 547 | enumsAsTypes: true, 548 | }); 549 | expect(result).toBeDefined(); 550 | 551 | expect(result).toContain( 552 | "enum: overrides && overrides.hasOwnProperty('enum') ? overrides.enum! : casual['email'],", 553 | ); 554 | 555 | expect(result).toMatchSnapshot(); 556 | }); 557 | 558 | it('can apply generator override to all fields of a specific name', async () => { 559 | const result = await plugin(testSchema, [], { 560 | ...config, 561 | fieldGeneration: { 562 | // eslint-disable-next-line @typescript-eslint/naming-convention 563 | _all: { email: 'email' }, 564 | }, 565 | }); 566 | expect(result).toBeDefined(); 567 | 568 | // Check both `email` fields are updated 569 | expect( 570 | String(result).match( 571 | /email: overrides && overrides.hasOwnProperty\('email'\) \? overrides.email! : casual\['email']/g, 572 | ).length, 573 | ).toEqual(2); 574 | expect(result).toMatchSnapshot(); 575 | }); 576 | 577 | it('can accept arguments', async () => { 578 | const result = await plugin(testSchema, [], { 579 | ...config, 580 | fieldGeneration: { 581 | A: { 582 | dateTime: { 583 | generator: 'integer', 584 | arguments: [1, 100], 585 | }, 586 | }, 587 | }, 588 | }); 589 | expect(result).toBeDefined(); 590 | 591 | expect(result).toContain( 592 | "dateTime: overrides && overrides.hasOwnProperty('dateTime') ? overrides.dateTime! : casual['integer'](...[1,100])", 593 | ); 594 | 595 | expect(result).toMatchSnapshot(); 596 | }); 597 | 598 | it('can accept an extra function call', async () => { 599 | const result = await plugin(testSchema, [], { 600 | ...config, 601 | fieldGeneration: { 602 | A: { 603 | dateTime: { 604 | generator: 'integer', 605 | arguments: [1, 100], 606 | extra: { 607 | function: 'toFixed', 608 | }, 609 | }, 610 | }, 611 | }, 612 | }); 613 | expect(result).toBeDefined(); 614 | 615 | expect(result).toContain( 616 | "dateTime: overrides && overrides.hasOwnProperty('dateTime') ? overrides.dateTime! : casual['integer'](...[1,100]).toFixed()", 617 | ); 618 | 619 | expect(result).toMatchSnapshot(); 620 | }); 621 | 622 | it('can accept an extra function call with arguments', async () => { 623 | const result = await plugin(testSchema, [], { 624 | ...config, 625 | fieldGeneration: { 626 | A: { 627 | dateTime: { 628 | generator: 'integer', 629 | arguments: [1, 100], 630 | extra: { 631 | function: 'toFixed', 632 | arguments: [3], 633 | }, 634 | }, 635 | }, 636 | }, 637 | }); 638 | expect(result).toBeDefined(); 639 | 640 | expect(result).toContain( 641 | "dateTime: overrides && overrides.hasOwnProperty('dateTime') ? overrides.dateTime! : casual['integer'](...[1,100]).toFixed(...[3])", 642 | ); 643 | 644 | expect(result).toMatchSnapshot(); 645 | }); 646 | 647 | it('can accept an extra function call with arguments shorthand', async () => { 648 | const result = await plugin(testSchema, [], { 649 | ...config, 650 | fieldGeneration: { 651 | A: { 652 | dateTime: { 653 | generator: 'integer', 654 | arguments: [1, 100], 655 | extra: { 656 | function: 'toFixed', 657 | arguments: 3, 658 | }, 659 | }, 660 | }, 661 | }, 662 | }); 663 | expect(result).toBeDefined(); 664 | 665 | expect(result).toContain( 666 | "dateTime: overrides && overrides.hasOwnProperty('dateTime') ? overrides.dateTime! : casual['integer'](...[1,100]).toFixed(...[3])", 667 | ); 668 | 669 | expect(result).toMatchSnapshot(); 670 | }); 671 | }); 672 | 673 | describe('without dynamic values', () => { 674 | beforeAll(() => { 675 | config.dynamicValues = false; 676 | }); 677 | 678 | it('uses per field generation if field name matches', async () => { 679 | const result = await plugin(testSchema, [], { 680 | ...config, 681 | fieldGeneration: { 682 | A: { email: 'email' }, 683 | }, 684 | }); 685 | expect(result).toBeDefined(); 686 | 687 | // Custom generation in type A 688 | expect(result).toContain( 689 | "email: overrides && overrides.hasOwnProperty('email') ? overrides.email! : 'Schuppe.Demario@yahoo.com'", 690 | ); 691 | // Original generation in type B (unchanged) 692 | expect(result).toContain( 693 | "email: overrides && overrides.hasOwnProperty('email') ? overrides.email! : 'quibusdam'", 694 | ); 695 | 696 | expect(result).toMatchSnapshot(); 697 | }); 698 | 699 | it('can overwrite a scalar value', async () => { 700 | const result = await plugin(testSchema, [], { 701 | ...config, 702 | fieldGeneration: { 703 | A: { email: 'email', overriddenDate: 'date' }, 704 | }, 705 | }); 706 | expect(result).toBeDefined(); 707 | 708 | expect(result).toContain( 709 | "date: overrides && overrides.hasOwnProperty('date') ? overrides.date! : '2004-01-01'", 710 | ); 711 | expect(result).toContain( 712 | "overriddenDate: overrides && overrides.hasOwnProperty('overriddenDate') ? overrides.overriddenDate! : '1995-09-05'", 713 | ); 714 | 715 | expect(result).toMatchSnapshot(); 716 | }); 717 | 718 | it('can overwrite an enum value', async () => { 719 | const result = await plugin(testSchema, [], { 720 | ...config, 721 | fieldGeneration: { 722 | C: { enum: 'email' }, 723 | }, 724 | }); 725 | expect(result).toBeDefined(); 726 | 727 | expect(result).toContain( 728 | "enum: overrides && overrides.hasOwnProperty('enum') ? overrides.enum! : 'Roosevelt.Oberbrunner@gmail.com'", 729 | ); 730 | 731 | expect(result).toMatchSnapshot(); 732 | }); 733 | 734 | it('can overwrite an enum value when enumsAsTypes is true', async () => { 735 | const result = await plugin(testSchema, [], { 736 | ...config, 737 | fieldGeneration: { 738 | C: { enum: 'email' }, 739 | }, 740 | enumsAsTypes: true, 741 | }); 742 | expect(result).toBeDefined(); 743 | 744 | expect(result).toContain( 745 | "enum: overrides && overrides.hasOwnProperty('enum') ? overrides.enum! : 'Roosevelt.Oberbrunner@gmail.com'", 746 | ); 747 | 748 | expect(result).toMatchSnapshot(); 749 | }); 750 | 751 | it('can apply generator override to all fields of a specific name', async () => { 752 | const result = await plugin(testSchema, [], { 753 | ...config, 754 | fieldGeneration: { 755 | // eslint-disable-next-line @typescript-eslint/naming-convention 756 | _all: { email: 'email' }, 757 | }, 758 | }); 759 | expect(result).toBeDefined(); 760 | 761 | // Check both `email` fields are updated 762 | expect(result).toContain( 763 | "email: overrides && overrides.hasOwnProperty('email') ? overrides.email! : 'Schuppe.Demario@yahoo.com'", 764 | ); 765 | expect(result).toContain( 766 | "email: overrides && overrides.hasOwnProperty('email') ? overrides.email! : 'Molly.Wuckert@gmail.com'", 767 | ); 768 | expect(result).toMatchSnapshot(); 769 | }); 770 | 771 | it('can accept arguments', async () => { 772 | const result = await plugin(testSchema, [], { 773 | ...config, 774 | fieldGeneration: { 775 | A: { 776 | dateTime: { 777 | generator: 'integer', 778 | arguments: [1, 100], 779 | }, 780 | }, 781 | }, 782 | }); 783 | expect(result).toBeDefined(); 784 | 785 | expect(result).toContain( 786 | "dateTime: overrides && overrides.hasOwnProperty('dateTime') ? overrides.dateTime! : 39", 787 | ); 788 | 789 | expect(result).toMatchSnapshot(); 790 | }); 791 | 792 | it('can accept an extra function call', async () => { 793 | const result = await plugin(testSchema, [], { 794 | ...config, 795 | fieldGeneration: { 796 | A: { 797 | dateTime: { 798 | generator: 'integer', 799 | arguments: [1, 100], 800 | extra: { 801 | function: 'toFixed', 802 | }, 803 | }, 804 | }, 805 | }, 806 | }); 807 | expect(result).toBeDefined(); 808 | 809 | expect(result).toContain( 810 | "dateTime: overrides && overrides.hasOwnProperty('dateTime') ? overrides.dateTime! : '39'", 811 | ); 812 | 813 | expect(result).toMatchSnapshot(); 814 | }); 815 | 816 | it('can accept an extra function call with arguments', async () => { 817 | const result = await plugin(testSchema, [], { 818 | ...config, 819 | fieldGeneration: { 820 | A: { 821 | dateTime: { 822 | generator: 'integer', 823 | arguments: [1, 100], 824 | extra: { 825 | function: 'toFixed', 826 | arguments: [3], 827 | }, 828 | }, 829 | }, 830 | }, 831 | }); 832 | expect(result).toBeDefined(); 833 | 834 | expect(result).toContain( 835 | "dateTime: overrides && overrides.hasOwnProperty('dateTime') ? overrides.dateTime! : '39.000'", 836 | ); 837 | 838 | expect(result).toMatchSnapshot(); 839 | }); 840 | 841 | it('can accept an extra function call with arguments shorthand', async () => { 842 | const result = await plugin(testSchema, [], { 843 | ...config, 844 | fieldGeneration: { 845 | A: { 846 | dateTime: { 847 | generator: 'integer', 848 | arguments: [1, 100], 849 | extra: { 850 | function: 'toFixed', 851 | arguments: 3, 852 | }, 853 | }, 854 | }, 855 | }, 856 | }); 857 | expect(result).toBeDefined(); 858 | 859 | expect(result).toContain( 860 | "dateTime: overrides && overrides.hasOwnProperty('dateTime') ? overrides.dateTime! : '39.000'", 861 | ); 862 | 863 | expect(result).toMatchSnapshot(); 864 | }); 865 | }); 866 | }); 867 | -------------------------------------------------------------------------------- /tests/scalars/__snapshots__/spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Custom scalar generation using casual should generate custom scalars for native and custom types 1`] = ` 4 | " 5 | export const anA = (overrides?: Partial): A => { 6 | return { 7 | id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : 82, 8 | str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : 'ea corrupti qui incidunt eius consequatur blanditiis', 9 | obj: overrides && overrides.hasOwnProperty('obj') ? overrides.obj! : aB(), 10 | anyObject: overrides && overrides.hasOwnProperty('anyObject') ? overrides.anyObject! : 'Kelly_Cremin@Turcotte.biz', 11 | }; 12 | }; 13 | 14 | export const aB = (overrides?: Partial): B => { 15 | return { 16 | int: overrides && overrides.hasOwnProperty('int') ? overrides.int! : -93, 17 | flt: overrides && overrides.hasOwnProperty('flt') ? overrides.flt! : -24.509902694262564, 18 | bool: overrides && overrides.hasOwnProperty('bool') ? overrides.bool! : false, 19 | }; 20 | }; 21 | 22 | export const aC = (overrides?: Partial): C => { 23 | return { 24 | anyObject: overrides && overrides.hasOwnProperty('anyObject') ? overrides.anyObject! : 'Gianni_Kutch@hotmail.com', 25 | }; 26 | }; 27 | " 28 | `; 29 | 30 | exports[`Custom scalar generation using casual should generate dynamic custom scalars for native and custom types 1`] = ` 31 | "import casual from 'casual'; 32 | 33 | casual.seed(0); 34 | 35 | export const anA = (overrides?: Partial): A => { 36 | return { 37 | id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : casual['integer'](...[1,100]), 38 | str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : casual['string'], 39 | obj: overrides && overrides.hasOwnProperty('obj') ? overrides.obj! : aB(), 40 | anyObject: overrides && overrides.hasOwnProperty('anyObject') ? overrides.anyObject! : casual['email'], 41 | }; 42 | }; 43 | 44 | export const aB = (overrides?: Partial): B => { 45 | return { 46 | int: overrides && overrides.hasOwnProperty('int') ? overrides.int! : casual['integer'](...[-100,0]), 47 | flt: overrides && overrides.hasOwnProperty('flt') ? overrides.flt! : casual['double'](...[-100,0]), 48 | bool: overrides && overrides.hasOwnProperty('bool') ? overrides.bool! : false, 49 | }; 50 | }; 51 | 52 | export const aC = (overrides?: Partial): C => { 53 | return { 54 | anyObject: overrides && overrides.hasOwnProperty('anyObject') ? overrides.anyObject! : casual['email'], 55 | }; 56 | }; 57 | 58 | export const seedMocks = (seed: number) => casual.seed(seed); 59 | " 60 | `; 61 | 62 | exports[`Custom scalar generation using casual with different input/output configurations should generate distinct custom scalars for native and custom input/output types 1`] = ` 63 | " 64 | export const anA = (overrides?: Partial): A => { 65 | return { 66 | id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : 82, 67 | str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : 'ea corrupti qui incidunt eius consequatur blanditiis', 68 | obj: overrides && overrides.hasOwnProperty('obj') ? overrides.obj! : aB(), 69 | anyObject: overrides && overrides.hasOwnProperty('anyObject') ? overrides.anyObject! : 'Kelly_Cremin@Turcotte.biz', 70 | }; 71 | }; 72 | 73 | export const aB = (overrides?: Partial): B => { 74 | return { 75 | int: overrides && overrides.hasOwnProperty('int') ? overrides.int! : -93, 76 | flt: overrides && overrides.hasOwnProperty('flt') ? overrides.flt! : -24.509902694262564, 77 | bool: overrides && overrides.hasOwnProperty('bool') ? overrides.bool! : false, 78 | }; 79 | }; 80 | 81 | export const aC = (overrides?: Partial): C => { 82 | return { 83 | anyObject: overrides && overrides.hasOwnProperty('anyObject') ? overrides.anyObject! : 'itaque distinctio iure molestias voluptas reprehenderit quos', 84 | }; 85 | }; 86 | " 87 | `; 88 | 89 | exports[`Custom scalar generation using casual with different input/output configurations should generate distinct dynamic custom scalars for native and custom types 1`] = ` 90 | "import casual from 'casual'; 91 | 92 | casual.seed(0); 93 | 94 | export const anA = (overrides?: Partial): A => { 95 | return { 96 | id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : casual['integer'](...[1,100]), 97 | str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : casual['string'], 98 | obj: overrides && overrides.hasOwnProperty('obj') ? overrides.obj! : aB(), 99 | anyObject: overrides && overrides.hasOwnProperty('anyObject') ? overrides.anyObject! : casual['email'], 100 | }; 101 | }; 102 | 103 | export const aB = (overrides?: Partial): B => { 104 | return { 105 | int: overrides && overrides.hasOwnProperty('int') ? overrides.int! : casual['integer'](...[-100,0]), 106 | flt: overrides && overrides.hasOwnProperty('flt') ? overrides.flt! : casual['double'](...[-100,0]), 107 | bool: overrides && overrides.hasOwnProperty('bool') ? overrides.bool! : false, 108 | }; 109 | }; 110 | 111 | export const aC = (overrides?: Partial): C => { 112 | return { 113 | anyObject: overrides && overrides.hasOwnProperty('anyObject') ? overrides.anyObject! : casual['string'], 114 | }; 115 | }; 116 | 117 | export const seedMocks = (seed: number) => casual.seed(seed); 118 | " 119 | `; 120 | 121 | exports[`custom scalar generation using faker should generate custom scalars for native and custom types 1`] = ` 122 | " 123 | export const anA = (overrides?: Partial): A => { 124 | return { 125 | id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : 83, 126 | str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : 'Depereo nulla calco blanditiis cornu defetiscor.', 127 | obj: overrides && overrides.hasOwnProperty('obj') ? overrides.obj! : aB(), 128 | anyObject: overrides && overrides.hasOwnProperty('anyObject') ? overrides.anyObject! : 'Orlando_Cremin@gmail.com', 129 | }; 130 | }; 131 | 132 | export const aB = (overrides?: Partial): B => { 133 | return { 134 | int: overrides && overrides.hasOwnProperty('int') ? overrides.int! : -93, 135 | flt: overrides && overrides.hasOwnProperty('flt') ? overrides.flt! : -24.51, 136 | bool: overrides && overrides.hasOwnProperty('bool') ? overrides.bool! : false, 137 | }; 138 | }; 139 | 140 | export const aC = (overrides?: Partial): C => { 141 | return { 142 | anyObject: overrides && overrides.hasOwnProperty('anyObject') ? overrides.anyObject! : 'Maia49@hotmail.com', 143 | }; 144 | }; 145 | " 146 | `; 147 | 148 | exports[`custom scalar generation using faker should generate dynamic custom scalars for native and custom types 1`] = ` 149 | "import { fakerEN as faker } from '@faker-js/faker'; 150 | 151 | faker.seed(0); 152 | 153 | export const anA = (overrides?: Partial): A => { 154 | return { 155 | id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : faker['number']['int'](...[{\\"min\\":1,\\"max\\":100}]), 156 | str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : faker['lorem']['sentence'](), 157 | obj: overrides && overrides.hasOwnProperty('obj') ? overrides.obj! : aB(), 158 | anyObject: overrides && overrides.hasOwnProperty('anyObject') ? overrides.anyObject! : faker['internet']['email'](), 159 | }; 160 | }; 161 | 162 | export const aB = (overrides?: Partial): B => { 163 | return { 164 | int: overrides && overrides.hasOwnProperty('int') ? overrides.int! : faker['number']['int'](...[{\\"min\\":-100,\\"max\\":0}]), 165 | flt: overrides && overrides.hasOwnProperty('flt') ? overrides.flt! : faker['number']['float'](...[{\\"min\\":-100,\\"max\\":0}]), 166 | bool: overrides && overrides.hasOwnProperty('bool') ? overrides.bool! : false, 167 | }; 168 | }; 169 | 170 | export const aC = (overrides?: Partial): C => { 171 | return { 172 | anyObject: overrides && overrides.hasOwnProperty('anyObject') ? overrides.anyObject! : faker['internet']['email'](), 173 | }; 174 | }; 175 | 176 | export const seedMocks = (seed: number) => faker.seed(seed); 177 | " 178 | `; 179 | 180 | exports[`custom scalar generation using faker with different input/output configurations should generate distinct custom scalars for native and custom input/output types 1`] = ` 181 | " 182 | export const anA = (overrides?: Partial): A => { 183 | return { 184 | id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : 83, 185 | str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : 'Depereo nulla calco blanditiis cornu defetiscor.', 186 | obj: overrides && overrides.hasOwnProperty('obj') ? overrides.obj! : aB(), 187 | anyObject: overrides && overrides.hasOwnProperty('anyObject') ? overrides.anyObject! : 'Orlando_Cremin@gmail.com', 188 | }; 189 | }; 190 | 191 | export const aB = (overrides?: Partial): B => { 192 | return { 193 | int: overrides && overrides.hasOwnProperty('int') ? overrides.int! : -93, 194 | flt: overrides && overrides.hasOwnProperty('flt') ? overrides.flt! : -24.51, 195 | bool: overrides && overrides.hasOwnProperty('bool') ? overrides.bool! : false, 196 | }; 197 | }; 198 | 199 | export const aC = (overrides?: Partial): C => { 200 | return { 201 | anyObject: overrides && overrides.hasOwnProperty('anyObject') ? overrides.anyObject! : 'vilicus', 202 | }; 203 | }; 204 | " 205 | `; 206 | 207 | exports[`custom scalar generation using faker with different input/output configurations should generate distinct dynamic custom scalars for native and custom types 1`] = ` 208 | "import { fakerEN as faker } from '@faker-js/faker'; 209 | 210 | faker.seed(0); 211 | 212 | export const anA = (overrides?: Partial): A => { 213 | return { 214 | id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : faker['number']['int'](...[{\\"min\\":1,\\"max\\":100}]), 215 | str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : faker['lorem']['sentence'](), 216 | obj: overrides && overrides.hasOwnProperty('obj') ? overrides.obj! : aB(), 217 | anyObject: overrides && overrides.hasOwnProperty('anyObject') ? overrides.anyObject! : faker['internet']['email'](), 218 | }; 219 | }; 220 | 221 | export const aB = (overrides?: Partial): B => { 222 | return { 223 | int: overrides && overrides.hasOwnProperty('int') ? overrides.int! : faker['number']['int'](...[{\\"min\\":-100,\\"max\\":0}]), 224 | flt: overrides && overrides.hasOwnProperty('flt') ? overrides.flt! : faker['number']['float'](...[{\\"min\\":-100,\\"max\\":0}]), 225 | bool: overrides && overrides.hasOwnProperty('bool') ? overrides.bool! : false, 226 | }; 227 | }; 228 | 229 | export const aC = (overrides?: Partial): C => { 230 | return { 231 | anyObject: overrides && overrides.hasOwnProperty('anyObject') ? overrides.anyObject! : faker['lorem']['word'](), 232 | }; 233 | }; 234 | 235 | export const seedMocks = (seed: number) => faker.seed(seed); 236 | " 237 | `; 238 | -------------------------------------------------------------------------------- /tests/scalars/schema.ts: -------------------------------------------------------------------------------- 1 | import { buildSchema } from 'graphql'; 2 | 3 | export default buildSchema(/* GraphQL */ ` 4 | scalar AnyObject 5 | 6 | type A { 7 | id: ID! 8 | str: String! 9 | obj: B! 10 | anyObject: AnyObject! 11 | } 12 | 13 | type B { 14 | int: Int! 15 | flt: Float! 16 | bool: Boolean! 17 | } 18 | 19 | input C { 20 | anyObject: AnyObject! 21 | } 22 | `); 23 | -------------------------------------------------------------------------------- /tests/scalars/spec.ts: -------------------------------------------------------------------------------- 1 | import { plugin } from '../../src'; 2 | import testSchema from './schema'; 3 | 4 | describe('Custom scalar generation using casual', () => { 5 | it('should generate custom scalars for native and custom types', async () => { 6 | const result = await plugin(testSchema, [], { 7 | generateLibrary: 'casual', 8 | scalars: { 9 | String: 'string', 10 | Float: { 11 | generator: 'double', 12 | arguments: [-100, 0], 13 | }, 14 | ID: { 15 | generator: 'integer', 16 | arguments: [1, 100], 17 | }, 18 | Boolean: 'false', 19 | Int: { 20 | generator: 'integer', 21 | arguments: [-100, 0], 22 | }, 23 | AnyObject: 'email', 24 | }, 25 | }); 26 | 27 | expect(result).toBeDefined(); 28 | 29 | // String 30 | expect(result).toContain( 31 | "str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : 'ea corrupti qui incidunt eius consequatur blanditiis',", 32 | ); 33 | 34 | // Float 35 | expect(result).toContain( 36 | "flt: overrides && overrides.hasOwnProperty('flt') ? overrides.flt! : -24.509902694262564,", 37 | ); 38 | 39 | // ID 40 | expect(result).toContain("id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : 82,"); 41 | 42 | // Boolean 43 | expect(result).toContain("bool: overrides && overrides.hasOwnProperty('bool') ? overrides.bool! : false"); 44 | 45 | // Int 46 | expect(result).toContain("int: overrides && overrides.hasOwnProperty('int') ? overrides.int! : -93,"); 47 | 48 | expect(result).toMatchSnapshot(); 49 | }); 50 | 51 | it('should generate dynamic custom scalars for native and custom types', async () => { 52 | const result = await plugin(testSchema, [], { 53 | generateLibrary: 'casual', 54 | dynamicValues: true, 55 | scalars: { 56 | String: 'string', 57 | Float: { 58 | generator: 'double', 59 | arguments: [-100, 0], 60 | }, 61 | ID: { 62 | generator: 'integer', 63 | arguments: [1, 100], 64 | }, 65 | Boolean: 'false', 66 | Int: { 67 | generator: 'integer', 68 | arguments: [-100, 0], 69 | }, 70 | AnyObject: 'email', 71 | }, 72 | }); 73 | 74 | expect(result).toBeDefined(); 75 | 76 | // String 77 | expect(result).toContain( 78 | "str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : casual['string'],", 79 | ); 80 | 81 | // Float 82 | expect(result).toContain( 83 | "flt: overrides && overrides.hasOwnProperty('flt') ? overrides.flt! : casual['double'](...[-100,0]),", 84 | ); 85 | 86 | // ID 87 | expect(result).toContain( 88 | "id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : casual['integer'](...[1,100]),", 89 | ); 90 | 91 | // Boolean 92 | expect(result).toContain("bool: overrides && overrides.hasOwnProperty('bool') ? overrides.bool! : false"); 93 | 94 | // Int 95 | expect(result).toContain( 96 | "int: overrides && overrides.hasOwnProperty('int') ? overrides.int! : casual['integer'](...[-100,0]),", 97 | ); 98 | 99 | expect(result).toMatchSnapshot(); 100 | }); 101 | 102 | describe('with different input/output configurations', () => { 103 | it('should generate distinct custom scalars for native and custom input/output types', async () => { 104 | const result = await plugin(testSchema, [], { 105 | generateLibrary: 'casual', 106 | scalars: { 107 | String: 'string', 108 | Float: { 109 | generator: 'double', 110 | arguments: [-100, 0], 111 | }, 112 | ID: { 113 | generator: 'integer', 114 | arguments: [1, 100], 115 | }, 116 | Boolean: 'false', 117 | Int: { 118 | generator: 'integer', 119 | arguments: [-100, 0], 120 | }, 121 | AnyObject: { 122 | input: 'string', 123 | output: 'email', 124 | }, 125 | }, 126 | }); 127 | 128 | expect(result).toBeDefined(); 129 | 130 | // String 131 | expect(result).toContain( 132 | "str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : 'ea corrupti qui incidunt eius consequatur blanditiis',", 133 | ); 134 | 135 | // Float 136 | expect(result).toContain( 137 | "flt: overrides && overrides.hasOwnProperty('flt') ? overrides.flt! : -24.509902694262564,", 138 | ); 139 | 140 | // ID 141 | expect(result).toContain("id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : 82,"); 142 | 143 | // Boolean 144 | expect(result).toContain("bool: overrides && overrides.hasOwnProperty('bool') ? overrides.bool! : false"); 145 | 146 | // Int 147 | expect(result).toContain("int: overrides && overrides.hasOwnProperty('int') ? overrides.int! : -93,"); 148 | 149 | // AnyObject in type A (an email) 150 | expect(result).toContain( 151 | "anyObject: overrides && overrides.hasOwnProperty('anyObject') ? overrides.anyObject! : 'Kelly_Cremin@Turcotte.biz',", 152 | ); 153 | 154 | // AnyObject in input C (a string) 155 | expect(result).toContain( 156 | "anyObject: overrides && overrides.hasOwnProperty('anyObject') ? overrides.anyObject! : 'itaque distinctio iure molestias voluptas reprehenderit quos',", 157 | ); 158 | 159 | expect(result).toMatchSnapshot(); 160 | }); 161 | 162 | it('should generate distinct dynamic custom scalars for native and custom types', async () => { 163 | const result = await plugin(testSchema, [], { 164 | generateLibrary: 'casual', 165 | dynamicValues: true, 166 | scalars: { 167 | String: 'string', 168 | Float: { 169 | generator: 'double', 170 | arguments: [-100, 0], 171 | }, 172 | ID: { 173 | generator: 'integer', 174 | arguments: [1, 100], 175 | }, 176 | Boolean: 'false', 177 | Int: { 178 | generator: 'integer', 179 | arguments: [-100, 0], 180 | }, 181 | AnyObject: { 182 | input: 'string', 183 | output: 'email', 184 | }, 185 | }, 186 | }); 187 | 188 | expect(result).toBeDefined(); 189 | 190 | // String 191 | expect(result).toContain( 192 | "str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : casual['string'],", 193 | ); 194 | 195 | // Float 196 | expect(result).toContain( 197 | "flt: overrides && overrides.hasOwnProperty('flt') ? overrides.flt! : casual['double'](...[-100,0]),", 198 | ); 199 | 200 | // ID 201 | expect(result).toContain( 202 | "id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : casual['integer'](...[1,100]),", 203 | ); 204 | 205 | // Boolean 206 | expect(result).toContain("bool: overrides && overrides.hasOwnProperty('bool') ? overrides.bool! : false"); 207 | 208 | // Int 209 | expect(result).toContain( 210 | "int: overrides && overrides.hasOwnProperty('int') ? overrides.int! : casual['integer'](...[-100,0]),", 211 | ); 212 | 213 | // AnyObject in type A (an email) 214 | expect(result).toContain( 215 | "anyObject: overrides && overrides.hasOwnProperty('anyObject') ? overrides.anyObject! : casual['email'],", 216 | ); 217 | 218 | // AnyObject in input C (an string) 219 | expect(result).toContain( 220 | "anyObject: overrides && overrides.hasOwnProperty('anyObject') ? overrides.anyObject! : casual['string'],", 221 | ); 222 | 223 | expect(result).toMatchSnapshot(); 224 | }); 225 | }); 226 | }); 227 | 228 | describe('custom scalar generation using faker', () => { 229 | it('should generate custom scalars for native and custom types', async () => { 230 | const result = await plugin(testSchema, [], { 231 | generateLibrary: 'faker', 232 | scalars: { 233 | String: 'lorem.sentence', 234 | Float: { 235 | generator: 'number.float', 236 | arguments: [{ min: -100, max: 0, fractionDigits: 2 }], 237 | }, 238 | ID: { 239 | generator: 'number.int', 240 | arguments: [{ min: 1, max: 100 }], 241 | }, 242 | Boolean: 'false', 243 | Int: { 244 | generator: 'number.int', 245 | arguments: [{ min: -100, max: 0 }], 246 | }, 247 | AnyObject: 'internet.email', 248 | }, 249 | }); 250 | 251 | expect(result).toBeDefined(); 252 | 253 | // String 254 | expect(result).toContain( 255 | "str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : 'Depereo nulla calco blanditiis cornu defetiscor.',", 256 | ); 257 | 258 | // Float 259 | expect(result).toContain("flt: overrides && overrides.hasOwnProperty('flt') ? overrides.flt! : -24.51,"); 260 | 261 | // ID 262 | expect(result).toContain("id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : 83,"); 263 | 264 | // Boolean 265 | expect(result).toContain("bool: overrides && overrides.hasOwnProperty('bool') ? overrides.bool! : false"); 266 | 267 | // Int 268 | expect(result).toContain("int: overrides && overrides.hasOwnProperty('int') ? overrides.int! : -93,"); 269 | 270 | expect(result).toMatchSnapshot(); 271 | }); 272 | 273 | it('should generate dynamic custom scalars for native and custom types', async () => { 274 | const result = await plugin(testSchema, [], { 275 | generateLibrary: 'faker', 276 | dynamicValues: true, 277 | scalars: { 278 | String: 'lorem.sentence', 279 | Float: { 280 | generator: 'number.float', 281 | arguments: [{ min: -100, max: 0 }], 282 | }, 283 | ID: { 284 | generator: 'number.int', 285 | arguments: [{ min: 1, max: 100 }], 286 | }, 287 | Boolean: 'false', 288 | Int: { 289 | generator: 'number.int', 290 | arguments: [{ min: -100, max: 0 }], 291 | }, 292 | AnyObject: 'internet.email', 293 | }, 294 | }); 295 | 296 | expect(result).toBeDefined(); 297 | 298 | // String 299 | expect(result).toContain( 300 | "str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : faker['lorem']['sentence'](),", 301 | ); 302 | 303 | // Float 304 | expect(result).toContain( 305 | "flt: overrides && overrides.hasOwnProperty('flt') ? overrides.flt! : faker['number']['float'](...[{\"min\":-100,\"max\":0}]),", 306 | ); 307 | 308 | // ID 309 | expect(result).toContain( 310 | "id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : faker['number']['int'](...[{\"min\":1,\"max\":100}]),", 311 | ); 312 | 313 | // Boolean 314 | expect(result).toContain("bool: overrides && overrides.hasOwnProperty('bool') ? overrides.bool! : false"); 315 | 316 | // Int 317 | expect(result).toContain( 318 | "int: overrides && overrides.hasOwnProperty('int') ? overrides.int! : faker['number']['int'](...[{\"min\":-100,\"max\":0}]),", 319 | ); 320 | 321 | expect(result).toMatchSnapshot(); 322 | }); 323 | 324 | describe('with different input/output configurations', () => { 325 | it('should generate distinct custom scalars for native and custom input/output types', async () => { 326 | const result = await plugin(testSchema, [], { 327 | generateLibrary: 'faker', 328 | scalars: { 329 | String: 'lorem.sentence', 330 | Float: { 331 | generator: 'number.float', 332 | arguments: [{ min: -100, max: 0, fractionDigits: 2 }], 333 | }, 334 | ID: { 335 | generator: 'number.int', 336 | arguments: [{ min: 1, max: 100 }], 337 | }, 338 | Boolean: 'false', 339 | Int: { 340 | generator: 'number.int', 341 | arguments: [{ min: -100, max: 0 }], 342 | }, 343 | AnyObject: { 344 | input: 'lorem.word', 345 | output: 'internet.email', 346 | }, 347 | }, 348 | }); 349 | 350 | expect(result).toBeDefined(); 351 | 352 | // String 353 | expect(result).toContain( 354 | "str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : 'Depereo nulla calco blanditiis cornu defetiscor.',", 355 | ); 356 | 357 | // Float 358 | expect(result).toContain("flt: overrides && overrides.hasOwnProperty('flt') ? overrides.flt! : -24.51,"); 359 | 360 | // ID 361 | expect(result).toContain("id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : 83,"); 362 | 363 | // Boolean 364 | expect(result).toContain("bool: overrides && overrides.hasOwnProperty('bool') ? overrides.bool! : false"); 365 | 366 | // Int 367 | expect(result).toContain("int: overrides && overrides.hasOwnProperty('int') ? overrides.int! : -93,"); 368 | 369 | // AnyObject in type A (an email) 370 | expect(result).toContain( 371 | "anyObject: overrides && overrides.hasOwnProperty('anyObject') ? overrides.anyObject! : 'Orlando_Cremin@gmail.com',", 372 | ); 373 | 374 | // AnyObject in input C (a string) 375 | expect(result).toContain( 376 | "anyObject: overrides && overrides.hasOwnProperty('anyObject') ? overrides.anyObject! : 'vilicus',", 377 | ); 378 | 379 | expect(result).toMatchSnapshot(); 380 | }); 381 | 382 | it('should generate distinct dynamic custom scalars for native and custom types', async () => { 383 | const result = await plugin(testSchema, [], { 384 | generateLibrary: 'faker', 385 | dynamicValues: true, 386 | scalars: { 387 | String: 'lorem.sentence', 388 | Float: { 389 | generator: 'number.float', 390 | arguments: [{ min: -100, max: 0 }], 391 | }, 392 | ID: { 393 | generator: 'number.int', 394 | arguments: [{ min: 1, max: 100 }], 395 | }, 396 | Boolean: 'false', 397 | Int: { 398 | generator: 'number.int', 399 | arguments: [{ min: -100, max: 0 }], 400 | }, 401 | AnyObject: { 402 | input: 'lorem.word', 403 | output: 'internet.email', 404 | }, 405 | }, 406 | }); 407 | 408 | expect(result).toBeDefined(); 409 | 410 | // String 411 | expect(result).toContain( 412 | "str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : faker['lorem']['sentence'](),", 413 | ); 414 | 415 | // Float 416 | expect(result).toContain( 417 | "flt: overrides && overrides.hasOwnProperty('flt') ? overrides.flt! : faker['number']['float'](...[{\"min\":-100,\"max\":0}]),", 418 | ); 419 | 420 | // ID 421 | expect(result).toContain( 422 | "id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : faker['number']['int'](...[{\"min\":1,\"max\":100}]),", 423 | ); 424 | 425 | // Boolean 426 | expect(result).toContain("bool: overrides && overrides.hasOwnProperty('bool') ? overrides.bool! : false"); 427 | 428 | // Int 429 | expect(result).toContain( 430 | "int: overrides && overrides.hasOwnProperty('int') ? overrides.int! : faker['number']['int'](...[{\"min\":-100,\"max\":0}]),", 431 | ); 432 | 433 | // AnyObject in type A (an email) 434 | expect(result).toContain( 435 | "anyObject: overrides && overrides.hasOwnProperty('anyObject') ? overrides.anyObject! : faker['internet']['email'](),", 436 | ); 437 | 438 | // AnyObject in input C (a string) 439 | expect(result).toContain( 440 | "anyObject: overrides && overrides.hasOwnProperty('anyObject') ? overrides.anyObject! : faker['lorem']['word'](),", 441 | ); 442 | 443 | expect(result).toMatchSnapshot(); 444 | }); 445 | }); 446 | }); 447 | -------------------------------------------------------------------------------- /tests/scalars/types.ts: -------------------------------------------------------------------------------- 1 | export type A = { 2 | id: string; 3 | str: string; 4 | obj: B; 5 | anyObject: any; 6 | }; 7 | 8 | export type B = { 9 | int: number; 10 | flt: number; 11 | bool: boolean; 12 | }; 13 | -------------------------------------------------------------------------------- /tests/terminateCircularRelationships/schema.ts: -------------------------------------------------------------------------------- 1 | import { buildSchema } from 'graphql'; 2 | 3 | export default buildSchema(/* GraphQL */ ` 4 | type A { 5 | B: B! 6 | C: C! 7 | } 8 | type B { 9 | A: A! 10 | } 11 | type C { 12 | aCollection: [A!]! 13 | } 14 | type D { 15 | A: A! 16 | B: B! 17 | } 18 | `); 19 | -------------------------------------------------------------------------------- /tests/terminateCircularRelationships/spec.ts: -------------------------------------------------------------------------------- 1 | import { aB, aC, aD, anA } from './mocks'; 2 | 3 | it('should terminate circular relationships when terminateCircularRelationships is true', () => { 4 | const a = anA(); 5 | expect(a).toEqual({ B: { A: {} }, C: { aCollection: [{}] } }); 6 | 7 | const b = aB(); 8 | expect(b).toEqual({ A: { B: {}, C: { aCollection: [{}] } } }); 9 | 10 | const c = aC(); 11 | expect(c).toEqual({ aCollection: [{ B: { A: {} }, C: {} }] }); 12 | 13 | const d = aD(); 14 | expect(d).toEqual({ A: { B: { A: {} }, C: { aCollection: [{}] } }, B: { A: { B: {}, C: { aCollection: [{}] } } } }); 15 | }); 16 | -------------------------------------------------------------------------------- /tests/terminateCircularRelationships/types.ts: -------------------------------------------------------------------------------- 1 | export type A = { 2 | B: B; 3 | C: C; 4 | }; 5 | 6 | export type B = { 7 | A: A; 8 | }; 9 | 10 | export type C = { 11 | aCollection: A[]; 12 | }; 13 | 14 | export type D = { 15 | A: A; 16 | B: B; 17 | }; 18 | -------------------------------------------------------------------------------- /tests/terminateCircularRelationshipsImmediately/__snapshots__/spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should support setting terminateCircularRelationships as imediate and not create a new set of relationships 1`] = ` 4 | " 5 | export const anA = (overrides?: Partial, _relationshipsToOmit: Set = new Set()): A => { 6 | const relationshipsToOmit: Set = _relationshipsToOmit; 7 | relationshipsToOmit.add('A'); 8 | return { 9 | B: overrides && overrides.hasOwnProperty('B') ? overrides.B! : relationshipsToOmit.has('B') ? {} as B : aB({}, relationshipsToOmit), 10 | C: overrides && overrides.hasOwnProperty('C') ? overrides.C! : relationshipsToOmit.has('C') ? {} as C : aC({}, relationshipsToOmit), 11 | }; 12 | }; 13 | 14 | export const aB = (overrides?: Partial, _relationshipsToOmit: Set = new Set()): B => { 15 | const relationshipsToOmit: Set = _relationshipsToOmit; 16 | relationshipsToOmit.add('B'); 17 | return { 18 | A: overrides && overrides.hasOwnProperty('A') ? overrides.A! : relationshipsToOmit.has('A') ? {} as A : anA({}, relationshipsToOmit), 19 | }; 20 | }; 21 | 22 | export const aC = (overrides?: Partial, _relationshipsToOmit: Set = new Set()): C => { 23 | const relationshipsToOmit: Set = _relationshipsToOmit; 24 | relationshipsToOmit.add('C'); 25 | return { 26 | aCollection: overrides && overrides.hasOwnProperty('aCollection') ? overrides.aCollection! : [relationshipsToOmit.has('A') ? {} as A : anA({}, relationshipsToOmit)], 27 | }; 28 | }; 29 | 30 | export const aD = (overrides?: Partial, _relationshipsToOmit: Set = new Set()): D => { 31 | const relationshipsToOmit: Set = _relationshipsToOmit; 32 | relationshipsToOmit.add('D'); 33 | return { 34 | A: overrides && overrides.hasOwnProperty('A') ? overrides.A! : relationshipsToOmit.has('A') ? {} as A : anA({}, relationshipsToOmit), 35 | B: overrides && overrides.hasOwnProperty('B') ? overrides.B! : relationshipsToOmit.has('B') ? {} as B : aB({}, relationshipsToOmit), 36 | }; 37 | }; 38 | " 39 | `; 40 | -------------------------------------------------------------------------------- /tests/terminateCircularRelationshipsImmediately/schema.ts: -------------------------------------------------------------------------------- 1 | import { buildSchema } from 'graphql'; 2 | 3 | export default buildSchema(/* GraphQL */ ` 4 | type A { 5 | B: B! 6 | C: C! 7 | } 8 | type B { 9 | A: A! 10 | } 11 | type C { 12 | aCollection: [A!]! 13 | } 14 | type D { 15 | A: A! 16 | B: B! 17 | } 18 | `); 19 | -------------------------------------------------------------------------------- /tests/terminateCircularRelationshipsImmediately/spec.ts: -------------------------------------------------------------------------------- 1 | import { plugin } from '../../src'; 2 | import testSchema from './schema'; 3 | 4 | it('should support setting terminateCircularRelationships as imediate and not create a new set of relationships', async () => { 5 | const result = await plugin(testSchema, [], { 6 | terminateCircularRelationships: 'immediate', 7 | }); 8 | 9 | expect(result).toBeDefined(); 10 | expect(result).not.toContain('new Set(_relationshipsToOmit)'); 11 | expect(result).toMatchSnapshot(); 12 | }); 13 | -------------------------------------------------------------------------------- /tests/terminateCircularRelationshipsImmediately/types.ts: -------------------------------------------------------------------------------- 1 | export type A = { 2 | B: B; 3 | C: C; 4 | }; 5 | 6 | export type B = { 7 | A: A; 8 | }; 9 | 10 | export type C = { 11 | aCollection: A[]; 12 | }; 13 | 14 | export type D = { 15 | A: A; 16 | B: B; 17 | }; 18 | -------------------------------------------------------------------------------- /tests/typeNamesMapping/schema.ts: -------------------------------------------------------------------------------- 1 | import { buildSchema } from 'graphql/index'; 2 | 3 | export default buildSchema(/* GraphQL */ ` 4 | enum EnumExample { 5 | LOREM 6 | IPSUM 7 | } 8 | 9 | type A { 10 | id: ID! 11 | str: String! 12 | email: String! 13 | } 14 | 15 | type B { 16 | id: ID! 17 | str: String! 18 | email: String! 19 | } 20 | 21 | type C { 22 | id: ID! 23 | str: String! 24 | enum: EnumExample! 25 | D: D! 26 | } 27 | 28 | type D { 29 | nested: C! 30 | } 31 | `); 32 | -------------------------------------------------------------------------------- /tests/typeNamesMapping/spec.ts: -------------------------------------------------------------------------------- 1 | import { plugin } from '../../src'; 2 | import testSchema from './schema'; 3 | 4 | it('should support typeNamesMapping', async () => { 5 | const result = await plugin(testSchema, [], { 6 | typesFile: './types/graphql.ts', 7 | typeNamesMapping: { A: 'RenamedAType' }, 8 | }); 9 | 10 | expect(result).toBeDefined(); 11 | expect(result).toContain("import { A as RenamedAType, B, C, D, EnumExample } from './types/graphql';"); 12 | }); 13 | 14 | it('should support typeNamesMapping with circular relationships', async () => { 15 | const result = await plugin(testSchema, [], { 16 | typesFile: './types/graphql.ts', 17 | typeNamesMapping: { D: 'RenamedDType' }, 18 | terminateCircularRelationships: 'immediate', 19 | }); 20 | 21 | expect(result).toBeDefined(); 22 | expect(result).toContain("import { A, B, C, D as RenamedDType, EnumExample } from './types/graphql';"); 23 | expect(result).toContain( 24 | "D: overrides && overrides.hasOwnProperty('D') ? overrides.D! : relationshipsToOmit.has('D') ? {} as DAsRenamedDType : aD({}, relationshipsToOmit),", 25 | ); 26 | }); 27 | 28 | it('should not support typeNamesMapping when enum type is given', async () => { 29 | const result = await plugin(testSchema, [], { 30 | typesFile: './types/graphql.ts', 31 | typeNamesMapping: { EnumExample: 'RenamedEnum' }, 32 | }); 33 | 34 | expect(result).toBeDefined(); 35 | expect(result).toContain("import { A, B, C, D, EnumExample } from './types/graphql';"); 36 | }); 37 | -------------------------------------------------------------------------------- /tests/typesPrefixAndTerminateCircularRelationships/__snapshots__/spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should support typesPrefix and terminateCircularRelationships at the same time 1`] = ` 4 | " 5 | export const mockA = (overrides?: Partial, _relationshipsToOmit: Set = new Set()): MockA => { 6 | const relationshipsToOmit: Set = new Set(_relationshipsToOmit); 7 | relationshipsToOmit.add('A'); 8 | return { 9 | b: overrides && overrides.hasOwnProperty('b') ? overrides.b! : relationshipsToOmit.has('B') ? {} as MockB : mockB({}, relationshipsToOmit), 10 | }; 11 | }; 12 | 13 | export const mockB = (overrides?: Partial, _relationshipsToOmit: Set = new Set()): MockB => { 14 | const relationshipsToOmit: Set = new Set(_relationshipsToOmit); 15 | relationshipsToOmit.add('B'); 16 | return { 17 | a: overrides && overrides.hasOwnProperty('a') ? overrides.a! : relationshipsToOmit.has('A') ? {} as MockA : mockA({}, relationshipsToOmit), 18 | }; 19 | }; 20 | " 21 | `; 22 | -------------------------------------------------------------------------------- /tests/typesPrefixAndTerminateCircularRelationships/schema.ts: -------------------------------------------------------------------------------- 1 | import { buildSchema } from 'graphql'; 2 | 3 | export default buildSchema(/* GraphQL */ ` 4 | type A { 5 | b: B! 6 | } 7 | type B { 8 | a: A! 9 | } 10 | `); 11 | -------------------------------------------------------------------------------- /tests/typesPrefixAndTerminateCircularRelationships/spec.ts: -------------------------------------------------------------------------------- 1 | import { plugin } from '../../src'; 2 | import testSchema from './schema'; 3 | 4 | it('should support typesPrefix and terminateCircularRelationships at the same time', async () => { 5 | const result = await plugin(testSchema, [], { 6 | prefix: 'mock', 7 | typesPrefix: 'Mock', 8 | terminateCircularRelationships: true, 9 | }); 10 | 11 | expect(result).toBeDefined(); 12 | expect(result).toContain( 13 | "a: overrides && overrides.hasOwnProperty('a') ? overrides.a! : relationshipsToOmit.has('A') ? {} as MockA : mockA({}, relationshipsToOmit)", 14 | ); 15 | expect(result).toMatchSnapshot(); 16 | }); 17 | -------------------------------------------------------------------------------- /tests/typescript-mock-data.spec.ts: -------------------------------------------------------------------------------- 1 | import '@graphql-codegen/testing'; 2 | 3 | import { buildSchema } from 'graphql'; 4 | import { plugin } from '../src'; 5 | 6 | const testSchema = buildSchema(/* GraphQL */ ` 7 | scalar Date 8 | scalar AnyObject 9 | 10 | directive @oneOf on INPUT_OBJECT 11 | 12 | type Avatar { 13 | id: ID! 14 | url: String! 15 | } 16 | 17 | type User implements WithAvatar { 18 | id: ID! 19 | creationDate: Date! 20 | login: String! 21 | avatar: Avatar 22 | status: Status! 23 | customStatus: ABCStatus 24 | scalarValue: AnyObject! 25 | camelCaseThing: camelCaseThing 26 | unionThing: UnionThing 27 | prefixedEnum: Prefixed_Enum 28 | } 29 | 30 | interface WithAvatar { 31 | id: ID! 32 | avatar: Avatar 33 | } 34 | 35 | type camelCaseThing { 36 | id: ID! 37 | } 38 | 39 | type Prefixed_Response { 40 | ping: String! 41 | } 42 | 43 | type ABCType { 44 | abc: String! 45 | } 46 | 47 | type ListType { 48 | stringList: [String!]! 49 | nullableStringList: [String!] 50 | } 51 | 52 | input UpdateUserInput { 53 | id: ID! 54 | login: String 55 | avatar: Avatar 56 | } 57 | 58 | input OneOfInput @oneOf { 59 | oneOfFieldA: String 60 | oneOfFieldB: String 61 | } 62 | 63 | enum ABCStatus { 64 | hasXYZStatus 65 | } 66 | 67 | enum Status { 68 | ONLINE 69 | OFFLINE 70 | } 71 | 72 | enum Prefixed_Enum { 73 | PREFIXED_VALUE 74 | } 75 | 76 | union UnionThing = Avatar | camelCaseThing 77 | 78 | type Mutation { 79 | updateUser(user: UpdateUserInput): User 80 | } 81 | 82 | type Query { 83 | user: User! 84 | prefixed_query: Prefixed_Response! 85 | } 86 | `); 87 | 88 | it('can be called', async () => { 89 | await plugin(testSchema, [], { typesFile: './types/graphql.ts' }); 90 | }); 91 | 92 | it('should generate mock data functions', async () => { 93 | const result = await plugin(testSchema, [], {}); 94 | 95 | expect(result).toBeDefined(); 96 | expect(result).toMatchSnapshot(); 97 | }); 98 | 99 | it('should generate mock data functions with faker', async () => { 100 | const result = await plugin(testSchema, [], { generateLibrary: 'faker' }); 101 | 102 | expect(result).toBeDefined(); 103 | expect(result).toMatchSnapshot(); 104 | 105 | const defaultResult = await plugin(testSchema, [], {}); 106 | expect(result).toStrictEqual(defaultResult); 107 | }); 108 | 109 | it('should generate mock data functions with casual', async () => { 110 | const result = await plugin(testSchema, [], { generateLibrary: 'casual' }); 111 | 112 | expect(result).toBeDefined(); 113 | expect(result).toMatchSnapshot(); 114 | }); 115 | 116 | it('should generate mock data functions with scalars', async () => { 117 | const result = await plugin(testSchema, [], {}); 118 | 119 | expect(result).toBeDefined(); 120 | expect(result).toContain( 121 | "scalarValue: overrides && overrides.hasOwnProperty('scalarValue') ? overrides.scalarValue! : 'arx',", 122 | ); 123 | expect(result).toMatchSnapshot(); 124 | }); 125 | 126 | it('should generate mock data for an input type with a oneOf directive', async () => { 127 | const result = await plugin(testSchema, [], {}); 128 | 129 | expect(result).toBeDefined(); 130 | expect(result).toContain(`const aOneOfInput = (override?: OneOfInput): OneOfInput`); 131 | expect(result).toContain(`...(override ? override : {oneOfFieldA : 'tibi'}),`); 132 | }); 133 | 134 | it('should generate mock data functions with external types file import', async () => { 135 | const result = await plugin(testSchema, [], { typesFile: './types/graphql.ts' }); 136 | 137 | expect(result).toBeDefined(); 138 | expect(result).toContain( 139 | "import { Avatar, User, WithAvatar, CamelCaseThing, PrefixedResponse, AbcType, ListType, UpdateUserInput, OneOfInput, Mutation, Query, AbcStatus, Status, PrefixedEnum } from './types/graphql';", 140 | ); 141 | expect(result).toMatchSnapshot(); 142 | }); 143 | 144 | it('should generate mock data with typename if addTypename is true', async () => { 145 | const result = await plugin(testSchema, [], { addTypename: true }); 146 | 147 | expect(result).toBeDefined(); 148 | expect(result).toContain('__typename'); 149 | expect(result).toMatchSnapshot(); 150 | }); 151 | 152 | it('should generate mock data with PascalCase enum values by default', async () => { 153 | const result = await plugin(testSchema, [], {}); 154 | 155 | expect(result).toBeDefined(); 156 | expect(result).toContain('HasXyzStatus'); 157 | expect(result).not.toContain('hasXYZStatus'); 158 | expect(result).not.toContain('HASXYZSTATUS'); 159 | expect(result).toMatchSnapshot(); 160 | }); 161 | 162 | it('should reference mock data functions with PascalCase names even if type names are camelCase', async () => { 163 | const result = await plugin(testSchema, [], { prefix: 'mock' }); 164 | 165 | expect(result).toBeDefined(); 166 | expect(result).toContain('mockCamelCaseThing'); 167 | expect(result).not.toContain('mockcamelCaseThing'); 168 | }); 169 | 170 | it('should generate mock data with PascalCase enum values if enumValues is "pascal-case#pascalCase"', async () => { 171 | const result = await plugin(testSchema, [], { enumValues: 'pascal-case#pascalCase' }); 172 | 173 | expect(result).toBeDefined(); 174 | expect(result).toContain('HasXyzStatus'); 175 | expect(result).not.toContain('hasXYZStatus'); 176 | expect(result).not.toContain('HASXYZSTATUS'); 177 | expect(result).toMatchSnapshot(); 178 | }); 179 | 180 | it('should generate mock data with upperCase enum values if enumValues is "upper-case#upperCase"', async () => { 181 | const result = await plugin(testSchema, [], { enumValues: 'upper-case#upperCase' }); 182 | 183 | expect(result).toBeDefined(); 184 | expect(result).not.toContain('HasXyzStatus'); 185 | expect(result).not.toContain('hasXYZStatus'); 186 | expect(result).toContain('HASXYZSTATUS'); 187 | expect(result).toMatchSnapshot(); 188 | }); 189 | 190 | it('should generate mock data with as-is enum values if enumValues is "keep"', async () => { 191 | const result = await plugin(testSchema, [], { enumValues: 'keep' }); 192 | 193 | expect(result).toBeDefined(); 194 | expect(result).not.toContain('HasXyzStatus'); 195 | expect(result).toContain('hasXYZStatus'); 196 | expect(result).not.toContain('HASXYZSTATUS'); 197 | expect(result).toMatchSnapshot(); 198 | }); 199 | 200 | it('should generate mock data with enum values as string union type if enumsAsTypes is true', async () => { 201 | const result = await plugin(testSchema, [], { enumsAsTypes: true }); 202 | 203 | expect(result).toBeDefined(); 204 | expect(result).not.toContain('Status.Online'); 205 | expect(result).toContain('ONLINE'); 206 | expect(result).not.toContain('ABCStatus.hasXYZStatus'); 207 | expect(result).toContain('hasXYZStatus'); 208 | expect(result).not.toContain('Prefixed_Enum.PREFIXED_VALUE'); 209 | expect(result).toContain('PREFIXED_VALUE'); 210 | expect(result).toMatchSnapshot(); 211 | }); 212 | 213 | it('should generate mock data with enum values as string union type if enumsAsTypes is true and cast the type if useTypeImports', async () => { 214 | const result = await plugin(testSchema, [], { enumsAsTypes: true, useTypeImports: true }); 215 | 216 | expect(result).toBeDefined(); 217 | expect(result).not.toContain('Status.Online'); 218 | expect(result).toContain(`('ONLINE' as Status)`); 219 | expect(result).not.toContain('ABCStatus.hasXYZStatus'); 220 | expect(result).toContain(`('hasXYZStatus' as AbcStatus)`); 221 | expect(result).not.toContain('Prefixed_Enum.PREFIXED_VALUE'); 222 | expect(result).toContain(`('PREFIXED_VALUE' as PrefixedEnum)`); 223 | expect(result).toMatchSnapshot(); 224 | }); 225 | 226 | it('should generate mock data with as-is enum values as string union type if enumsAsTypes is true and enumValues is "keep"', async () => { 227 | const result = await plugin(testSchema, [], { enumsAsTypes: true, enumValues: 'keep' }); 228 | 229 | expect(result).toBeDefined(); 230 | expect(result).not.toContain('Status.Online'); 231 | expect(result).toContain('ONLINE'); 232 | expect(result).not.toContain('ABCStatus.hasXYZStatus'); 233 | expect(result).toContain('hasXYZStatus'); 234 | expect(result).not.toContain('Prefixed_Enum.PREFIXED_VALUE'); 235 | expect(result).toContain('PREFIXED_VALUE'); 236 | expect(result).toMatchSnapshot(); 237 | }); 238 | 239 | it('should generate mock data with PascalCase types and enums by default', async () => { 240 | const result = await plugin(testSchema, [], { typesFile: './types/graphql.ts' }); 241 | 242 | expect(result).toBeDefined(); 243 | expect(result).toMatch(/Abc(Type|Status)/); 244 | expect(result).not.toMatch(/ABC(Type|Status)/); 245 | expect(result).not.toMatch(/ABC(TYPE|STATUS)/); 246 | expect(result).toMatchSnapshot(); 247 | }); 248 | 249 | it('should generate mock data with PascalCase enum values if typeNames is "pascal-case#pascalCase"', async () => { 250 | const result = await plugin(testSchema, [], { typeNames: 'pascal-case#pascalCase' }); 251 | 252 | expect(result).toBeDefined(); 253 | expect(result).toMatch(/Abc(Type|Status)/); 254 | expect(result).not.toMatch(/ABC(Type|Status)/); 255 | expect(result).not.toMatch(/ABC(TYPE|STATUS)/); 256 | expect(result).toMatchSnapshot(); 257 | }); 258 | 259 | it('should generate mock data with upperCase types and enums if typeNames is "upper-case#upperCase"', async () => { 260 | const result = await plugin(testSchema, [], { typeNames: 'upper-case#upperCase' }); 261 | 262 | expect(result).toBeDefined(); 263 | expect(result).not.toMatch(/Abc(Type|Status)/); 264 | expect(result).not.toMatch(/ABC(Type|Status)/); 265 | expect(result).toMatch(/ABC(TYPE|STATUS)/); 266 | expect(result).toMatchSnapshot(); 267 | }); 268 | 269 | it('should generate mock data with upperCase types and imports if typeNames is "upper-case#upperCase"', async () => { 270 | const result = await plugin(testSchema, [], { typeNames: 'upper-case#upperCase', typesFile: './types/graphql.ts' }); 271 | 272 | expect(result).toBeDefined(); 273 | expect(result).not.toMatch(/Abc(Type|Status)/); 274 | expect(result).not.toMatch(/ABC(Type|Status)/); 275 | expect(result).toMatch(/ABC(TYPE|STATUS)/); 276 | expect(result).toMatchSnapshot(); 277 | }); 278 | 279 | it('should generate mock data with as-is types and enums if typeNames is "keep"', async () => { 280 | const result = await plugin(testSchema, [], { typeNames: 'keep' }); 281 | 282 | expect(result).toBeDefined(); 283 | expect(result).not.toMatch(/Abc(Type|Status)/); 284 | expect(result).toMatch(/ABC(Type|Status)/); 285 | expect(result).not.toMatch(/ABC(TYPE|STATUS)/); 286 | expect(result).toMatchSnapshot(); 287 | }); 288 | 289 | it('should add custom prefix if the `prefix` config option is specified', async () => { 290 | const result = await plugin(testSchema, [], { prefix: 'mock' }); 291 | 292 | expect(result).toBeDefined(); 293 | expect(result).toMatch(/const mockUser/); 294 | expect(result).not.toMatch(/const aUser/); 295 | expect(result).toMatchSnapshot(); 296 | }); 297 | 298 | it('should correctly generate the `faker` data for a scalar mapping of type string', async () => { 299 | const result = await plugin(testSchema, [], { scalars: { AnyObject: 'internet.email' } }); 300 | 301 | expect(result).toBeDefined(); 302 | expect(result).toContain('Geovany63@gmail.com'); 303 | expect(result).toMatchSnapshot(); 304 | }); 305 | 306 | it('should correctly generate the `faker` data for a non-string scalar mapping', async () => { 307 | const result = await plugin(testSchema, [], { 308 | scalars: { AnyObject: { generator: 'color.rgb', arguments: [{ format: 'decimal' }] } }, 309 | }); 310 | 311 | expect(result).toBeDefined(); 312 | expect(result).toContain(JSON.stringify([41, 98, 185])); 313 | expect(result).toMatchSnapshot(); 314 | }); 315 | 316 | it('should correctly generate the `faker` data for a function with arguments scalar mapping', async () => { 317 | const result = await plugin(testSchema, [], { 318 | scalars: { 319 | AnyObject: { 320 | generator: 'date.future', 321 | arguments: [{ refDate: '2024-09-01' }], 322 | }, 323 | }, 324 | }); 325 | 326 | expect(result).toBeDefined(); 327 | expect(result).toContain('"2024-10-29T22:31:35.873Z"'); 328 | expect(result).toMatchSnapshot(); 329 | }); 330 | 331 | it('should correctly generate the `faker` data for a function with one argument scalar mapping', async () => { 332 | const result = await plugin(testSchema, [], { 333 | scalars: { 334 | AnyObject: { 335 | generator: 'date.future', 336 | arguments: { refDate: '2024-09-01' }, 337 | }, 338 | }, 339 | }); 340 | 341 | expect(result).toBeDefined(); 342 | expect(result).toContain('"2024-10-29T22:31:35.873Z"'); 343 | expect(result).toMatchSnapshot(); 344 | }); 345 | 346 | it('should correctly use custom generator as default value', async () => { 347 | const result = await plugin(testSchema, [], { 348 | scalars: { 349 | AnyObject: { 350 | generator: 'myValueGenerator()', 351 | arguments: [], 352 | }, 353 | }, 354 | }); 355 | 356 | expect(result).toBeDefined(); 357 | expect(result).toContain('myValueGenerator()'); 358 | expect(result).toMatchSnapshot(); 359 | }); 360 | 361 | it('should add typesPrefix to all types when option is specified', async () => { 362 | const result = await plugin(testSchema, [], { typesPrefix: 'Api.' }); 363 | 364 | expect(result).toBeDefined(); 365 | expect(result).toMatch(/: Api.User/); 366 | expect(result).not.toMatch(/: User/); 367 | expect(result).not.toMatch(/: Api.AbcStatus/); 368 | expect(result).toMatchSnapshot(); 369 | }); 370 | 371 | it('should add typesPrefix to imports', async () => { 372 | const result = await plugin(testSchema, [], { typesPrefix: 'Api.', typesFile: './types/graphql.ts' }); 373 | 374 | expect(result).toBeDefined(); 375 | expect(result).toContain("import { Api, AbcStatus, Status, PrefixedEnum } from './types/graphql';"); 376 | 377 | expect(result).toMatchSnapshot(); 378 | }); 379 | 380 | it('should add enumsPrefix to all enums when option is specified', async () => { 381 | const result = await plugin(testSchema, [], { enumsPrefix: 'Api.' }); 382 | 383 | expect(result).toBeDefined(); 384 | expect(result).toMatch(/: Api.AbcStatus/); 385 | expect(result).toMatch(/: Api.Status/); 386 | expect(result).not.toMatch(/: AbcStatus/); 387 | expect(result).not.toMatch(/: Status/); 388 | expect(result).not.toMatch(/: Api.User/); 389 | expect(result).toMatchSnapshot(); 390 | }); 391 | 392 | it('should add enumsPrefix to imports', async () => { 393 | const result = await plugin(testSchema, [], { enumsPrefix: 'Api.', typesFile: './types/graphql.ts' }); 394 | 395 | expect(result).toBeDefined(); 396 | expect(result).toContain( 397 | "import { Avatar, User, WithAvatar, CamelCaseThing, PrefixedResponse, AbcType, ListType, UpdateUserInput, OneOfInput, Mutation, Query, Api } from './types/graphql';", 398 | ); 399 | expect(result).toMatchSnapshot(); 400 | }); 401 | 402 | it('should add typesPrefix and enumsPrefix to imports', async () => { 403 | const result = await plugin(testSchema, [], { 404 | enumsPrefix: 'Api.', 405 | typesPrefix: 'Api.', 406 | typesFile: './types/graphql.ts', 407 | }); 408 | 409 | expect(result).toBeDefined(); 410 | expect(result).toContain("import { Api } from './types/graphql';"); 411 | expect(result).toMatchSnapshot(); 412 | }); 413 | 414 | it('should not merge imports into one if typesPrefix does not contain dots', async () => { 415 | const result = await plugin(testSchema, [], { 416 | typesPrefix: 'Api', 417 | typesFile: './types/graphql.ts', 418 | }); 419 | 420 | expect(result).toBeDefined(); 421 | expect(result).toContain( 422 | "import { ApiAvatar, ApiUser, ApiWithAvatar, ApiCamelCaseThing, ApiPrefixedResponse, ApiAbcType, ApiListType, ApiUpdateUserInput, ApiOneOfInput, ApiMutation, ApiQuery, AbcStatus, Status, PrefixedEnum } from './types/graphql';", 423 | ); 424 | expect(result).toMatchSnapshot(); 425 | }); 426 | 427 | it('should not merge imports into one if enumsPrefix does not contain dots', async () => { 428 | const result = await plugin(testSchema, [], { 429 | enumsPrefix: 'Api', 430 | typesFile: './types/graphql.ts', 431 | }); 432 | 433 | expect(result).toBeDefined(); 434 | expect(result).toContain( 435 | "import { Avatar, User, WithAvatar, CamelCaseThing, PrefixedResponse, AbcType, ListType, UpdateUserInput, OneOfInput, Mutation, Query, ApiAbcStatus, ApiStatus, ApiPrefixedEnum } from './types/graphql';", 436 | ); 437 | expect(result).toMatchSnapshot(); 438 | }); 439 | 440 | it('should use relationshipsToOmit argument to terminate circular relationships with terminateCircularRelationships enabled', async () => { 441 | const result = await plugin(testSchema, [], { terminateCircularRelationships: true }); 442 | 443 | expect(result).toBeDefined(); 444 | expect(result).toMatch(/const relationshipsToOmit: Set = new Set\(_relationshipsToOmit\);/); 445 | expect(result).toMatch(/relationshipsToOmit.add\('Avatar'\)/); 446 | expect(result).toMatch(/relationshipsToOmit.has\('Avatar'\) \? {} as Avatar : anAvatar\({}, relationshipsToOmit\)/); 447 | expect(result).not.toMatch(/: anAvatar\(\)/); 448 | expect(result).toMatchSnapshot(); 449 | }); 450 | 451 | it('should preserve underscores if transformUnderscore is false', async () => { 452 | const result = await plugin(testSchema, [], { 453 | transformUnderscore: false, 454 | typesFile: './types/graphql.ts', 455 | }); 456 | 457 | expect(result).toBeDefined(); 458 | expect(result).toContain( 459 | "import { Avatar, User, WithAvatar, CamelCaseThing, Prefixed_Response, AbcType, ListType, UpdateUserInput, OneOfInput, Mutation, Query, AbcStatus, Status, Prefixed_Enum } from './types/graphql';", 460 | ); 461 | expect(result).toContain( 462 | 'export const aPrefixed_Response = (overrides?: Partial): Prefixed_Response => {', 463 | ); 464 | expect(result).toContain( 465 | "prefixedEnum: overrides && overrides.hasOwnProperty('prefixedEnum') ? overrides.prefixedEnum! : Prefixed_Enum.PrefixedValue,", 466 | ); 467 | expect(result).toMatchSnapshot(); 468 | }); 469 | 470 | it('should preserve underscores if transformUnderscore is false and enumsAsTypes is true', async () => { 471 | const result = await plugin(testSchema, [], { 472 | transformUnderscore: false, 473 | typesFile: './types/graphql.ts', 474 | enumsAsTypes: true, 475 | }); 476 | 477 | expect(result).toBeDefined(); 478 | expect(result).toContain( 479 | "import { Avatar, User, WithAvatar, CamelCaseThing, Prefixed_Response, AbcType, ListType, UpdateUserInput, OneOfInput, Mutation, Query } from './types/graphql';", 480 | ); 481 | expect(result).toContain( 482 | 'export const aPrefixed_Response = (overrides?: Partial): Prefixed_Response => {', 483 | ); 484 | expect(result).toContain( 485 | "prefixedEnum: overrides && overrides.hasOwnProperty('prefixedEnum') ? overrides.prefixedEnum! : 'PREFIXED_VALUE',", 486 | ); 487 | expect(result).toMatchSnapshot(); 488 | }); 489 | 490 | it('should preserve underscores if transformUnderscore is false and enumsAsTypes is true as cast the enum type if useTypeImports is true', async () => { 491 | const result = await plugin(testSchema, [], { 492 | transformUnderscore: false, 493 | typesFile: './types/graphql.ts', 494 | enumsAsTypes: true, 495 | useTypeImports: true, 496 | }); 497 | 498 | expect(result).toBeDefined(); 499 | expect(result).toContain( 500 | "import type { Avatar, User, WithAvatar, CamelCaseThing, Prefixed_Response, AbcType, ListType, UpdateUserInput, OneOfInput, Mutation, Query, AbcStatus, Status, Prefixed_Enum } from './types/graphql';", 501 | ); 502 | expect(result).toContain( 503 | 'export const aPrefixed_Response = (overrides?: Partial): Prefixed_Response => {', 504 | ); 505 | expect(result).toContain( 506 | "prefixedEnum: overrides && overrides.hasOwnProperty('prefixedEnum') ? overrides.prefixedEnum! : ('PREFIXED_VALUE' as Prefixed_Enum),", 507 | ); 508 | expect(result).toMatchSnapshot(); 509 | }); 510 | 511 | it('should generate single list element', async () => { 512 | const result = await plugin(testSchema, [], { 513 | typesFile: './types/graphql.ts', 514 | }); 515 | 516 | expect(result).toBeDefined(); 517 | expect(result).toContain( 518 | "stringList: overrides && overrides.hasOwnProperty('stringList') ? overrides.stringList! : ['accusator']", 519 | ); 520 | expect(result).toMatchSnapshot(); 521 | }); 522 | 523 | it('should generate multiple list elements', async () => { 524 | const result = await plugin(testSchema, [], { 525 | typesFile: './types/graphql.ts', 526 | listElementCount: 3, 527 | }); 528 | 529 | expect(result).toBeDefined(); 530 | expect(result).toContain( 531 | "stringList: overrides && overrides.hasOwnProperty('stringList') ? overrides.stringList! : ['peccatus', 'sponte', 'corpus']", 532 | ); 533 | expect(result).toMatchSnapshot(); 534 | }); 535 | 536 | it('should generate no list elements when listElementCount is 0', async () => { 537 | const result = await plugin(testSchema, [], { 538 | typesFile: './types/graphql.ts', 539 | listElementCount: 0, 540 | }); 541 | 542 | expect(result).toBeDefined(); 543 | expect(result).toContain( 544 | "stringList: overrides && overrides.hasOwnProperty('stringList') ? overrides.stringList! : []", 545 | ); 546 | expect(result).toMatchSnapshot(); 547 | }); 548 | 549 | it('should generate dynamic values in mocks', async () => { 550 | const result = await plugin(testSchema, [], { dynamicValues: true }); 551 | 552 | expect(result).toBeDefined(); 553 | expect(result).toMatchSnapshot(); 554 | }); 555 | 556 | it('should generate dynamic values with `casual`', async () => { 557 | const result = await plugin(testSchema, [], { dynamicValues: true, generateLibrary: 'casual' }); 558 | 559 | expect(result).toBeDefined(); 560 | expect(result).toMatchSnapshot(); 561 | }); 562 | 563 | it('defaults all nullable fields to null when defaultNullableToNull is set', async () => { 564 | const result = await plugin(testSchema, [], { defaultNullableToNull: true }); 565 | 566 | expect(result).toBeDefined(); 567 | expect(result).toContain( 568 | "customStatus: overrides && overrides.hasOwnProperty('customStatus') ? overrides.customStatus! : null", 569 | ); 570 | expect(result).toContain( 571 | "camelCaseThing: overrides && overrides.hasOwnProperty('camelCaseThing') ? overrides.camelCaseThing! : null", 572 | ); 573 | expect(result).toContain( 574 | "unionThing: overrides && overrides.hasOwnProperty('unionThing') ? overrides.unionThing! : null", 575 | ); 576 | expect(result).toContain( 577 | "prefixedEnum: overrides && overrides.hasOwnProperty('prefixedEnum') ? overrides.prefixedEnum! : null", 578 | ); 579 | expect(result).toContain("avatar: overrides && overrides.hasOwnProperty('avatar') ? overrides.avatar! : null"); 580 | expect(result).toContain("login: overrides && overrides.hasOwnProperty('login') ? overrides.login! : null"); 581 | expect(result).toContain( 582 | "nullableStringList: overrides && overrides.hasOwnProperty('nullableStringList') ? overrides.nullableStringList! : null", 583 | ); 584 | 585 | expect(result).toMatchSnapshot(); 586 | }); 587 | 588 | it('overriding works as expected when defaultNullableToNull is true', async () => { 589 | const result = await plugin(testSchema, [], { 590 | defaultNullableToNull: true, 591 | fieldGeneration: { 592 | User: { 593 | customStatus: "'abc'", 594 | avatar: 'someAvatar', 595 | }, 596 | ListType: { 597 | nullableStringList: "'abc'", 598 | }, 599 | }, 600 | }); 601 | 602 | expect(result).toBeDefined(); 603 | expect(result).toContain( 604 | "customStatus: overrides && overrides.hasOwnProperty('customStatus') ? overrides.customStatus! : 'abc'", 605 | ); 606 | expect(result).toContain( 607 | "avatar: overrides && overrides.hasOwnProperty('avatar') ? overrides.avatar! : someAvatar", 608 | ); 609 | expect(result).toContain( 610 | "nullableStringList: overrides && overrides.hasOwnProperty('nullableStringList') ? overrides.nullableStringList! : ['abc']", 611 | ); 612 | 613 | expect(result).toMatchSnapshot(); 614 | }); 615 | 616 | it('should generate mock data only for included types', async () => { 617 | const result = await plugin(testSchema, [], { 618 | includedTypes: ['User', 'Avatar'], 619 | }); 620 | 621 | expect(result).toMatchSnapshot(); 622 | expect(result).toBeDefined(); 623 | expect(result).toContain('export const aUser'); 624 | expect(result).toContain('export const anAvatar'); 625 | expect(result).not.toContain('export const aPrefixedResponse'); 626 | expect(result).not.toContain('export const aCamelCaseThing'); 627 | }); 628 | 629 | it('should exclude specified types from mock generation', async () => { 630 | const result = await plugin(testSchema, [], { 631 | excludedTypes: ['User', 'Avatar'], 632 | }); 633 | 634 | expect(result).toBeDefined(); 635 | expect(result).not.toContain('export const aUser'); 636 | expect(result).not.toContain('export const anAvatar'); 637 | expect(result).toContain('export const aPrefixedResponse'); 638 | expect(result).toContain('export const aCamelCaseThing'); 639 | }); 640 | 641 | it('should prioritize includedTypes over excludedTypes if both are specified', async () => { 642 | const result = await plugin(testSchema, [], { 643 | includedTypes: ['User'], 644 | excludedTypes: ['User', 'Avatar'], 645 | }); 646 | expect(result).toBeDefined(); 647 | expect(result).toContain('export const aUser'); 648 | expect(result).not.toContain('export const anAvatar'); 649 | expect(result).not.toContain('export const aPrefixedResponse'); 650 | }); 651 | -------------------------------------------------------------------------------- /tests/useImplementingTypes/__snapshots__/spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should support useImplementingTypes 1`] = ` 4 | " 5 | export const mockAConfig = (overrides?: Partial): AConfig => { 6 | return { 7 | testTypes: overrides && overrides.hasOwnProperty('testTypes') ? overrides.testTypes! : [TestObj.Test], 8 | }; 9 | }; 10 | 11 | export const mockField = (overrides?: Partial): Field => { 12 | return { 13 | testTypes: overrides && overrides.hasOwnProperty('testTypes') ? overrides.testTypes! : [TestObj.Test], 14 | }; 15 | }; 16 | 17 | export const mockAction = (overrides?: Partial): Action => { 18 | return { 19 | action: overrides && overrides.hasOwnProperty('action') ? overrides.action! : [TestObj.Test], 20 | }; 21 | }; 22 | 23 | export const mockA = (overrides?: Partial): A => { 24 | return { 25 | id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : 'dae147b0-0c04-459e-912d-b724dd87433b', 26 | str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : 'cuius', 27 | obj: overrides && overrides.hasOwnProperty('obj') ? overrides.obj! : mockB(), 28 | config: overrides && overrides.hasOwnProperty('config') ? overrides.config! : mockTestAConfig() || mockTestTwoAConfig(), 29 | configArray: overrides && overrides.hasOwnProperty('configArray') ? overrides.configArray! : [mockTestAConfig() || mockTestTwoAConfig()], 30 | field: overrides && overrides.hasOwnProperty('field') ? overrides.field! : mockTestTwoAConfig(), 31 | action: overrides && overrides.hasOwnProperty('action') ? overrides.action! : mockTestAction(), 32 | }; 33 | }; 34 | 35 | export const mockB = (overrides?: Partial): B => { 36 | return { 37 | int: overrides && overrides.hasOwnProperty('int') ? overrides.int! : 695, 38 | flt: overrides && overrides.hasOwnProperty('flt') ? overrides.flt! : 7.6, 39 | bool: overrides && overrides.hasOwnProperty('bool') ? overrides.bool! : false, 40 | }; 41 | }; 42 | 43 | export const mockTestAConfig = (overrides?: Partial): TestAConfig => { 44 | return { 45 | testTypes: overrides && overrides.hasOwnProperty('testTypes') ? overrides.testTypes! : [TestObj.Test], 46 | active: overrides && overrides.hasOwnProperty('active') ? overrides.active! : true, 47 | }; 48 | }; 49 | 50 | export const mockTestTwoAConfig = (overrides?: Partial): TestTwoAConfig => { 51 | return { 52 | testTypes: overrides && overrides.hasOwnProperty('testTypes') ? overrides.testTypes! : [TestObj.Test], 53 | username: overrides && overrides.hasOwnProperty('username') ? overrides.username! : 'vesco', 54 | }; 55 | }; 56 | 57 | export const mockTestAction = (overrides?: Partial): TestAction => { 58 | return { 59 | action: overrides && overrides.hasOwnProperty('action') ? overrides.action! : [TestObj.Test], 60 | createdAt: overrides && overrides.hasOwnProperty('createdAt') ? overrides.createdAt! : 'cum', 61 | }; 62 | }; 63 | " 64 | `; 65 | 66 | exports[`shouldn't support useImplementingTypes 1`] = ` 67 | " 68 | export const mockAConfig = (overrides?: Partial): AConfig => { 69 | return { 70 | testTypes: overrides && overrides.hasOwnProperty('testTypes') ? overrides.testTypes! : [TestObj.Test], 71 | }; 72 | }; 73 | 74 | export const mockField = (overrides?: Partial): Field => { 75 | return { 76 | testTypes: overrides && overrides.hasOwnProperty('testTypes') ? overrides.testTypes! : [TestObj.Test], 77 | }; 78 | }; 79 | 80 | export const mockAction = (overrides?: Partial): Action => { 81 | return { 82 | action: overrides && overrides.hasOwnProperty('action') ? overrides.action! : [TestObj.Test], 83 | }; 84 | }; 85 | 86 | export const mockA = (overrides?: Partial): A => { 87 | return { 88 | id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : 'dae147b0-0c04-459e-912d-b724dd87433b', 89 | str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : 'cuius', 90 | obj: overrides && overrides.hasOwnProperty('obj') ? overrides.obj! : mockB(), 91 | config: overrides && overrides.hasOwnProperty('config') ? overrides.config! : mockAConfig(), 92 | configArray: overrides && overrides.hasOwnProperty('configArray') ? overrides.configArray! : [mockAConfig()], 93 | field: overrides && overrides.hasOwnProperty('field') ? overrides.field! : mockField(), 94 | action: overrides && overrides.hasOwnProperty('action') ? overrides.action! : mockAction(), 95 | }; 96 | }; 97 | 98 | export const mockB = (overrides?: Partial): B => { 99 | return { 100 | int: overrides && overrides.hasOwnProperty('int') ? overrides.int! : 695, 101 | flt: overrides && overrides.hasOwnProperty('flt') ? overrides.flt! : 7.6, 102 | bool: overrides && overrides.hasOwnProperty('bool') ? overrides.bool! : false, 103 | }; 104 | }; 105 | 106 | export const mockTestAConfig = (overrides?: Partial): TestAConfig => { 107 | return { 108 | testTypes: overrides && overrides.hasOwnProperty('testTypes') ? overrides.testTypes! : [TestObj.Test], 109 | active: overrides && overrides.hasOwnProperty('active') ? overrides.active! : true, 110 | }; 111 | }; 112 | 113 | export const mockTestTwoAConfig = (overrides?: Partial): TestTwoAConfig => { 114 | return { 115 | testTypes: overrides && overrides.hasOwnProperty('testTypes') ? overrides.testTypes! : [TestObj.Test], 116 | username: overrides && overrides.hasOwnProperty('username') ? overrides.username! : 'vesco', 117 | }; 118 | }; 119 | 120 | export const mockTestAction = (overrides?: Partial): TestAction => { 121 | return { 122 | action: overrides && overrides.hasOwnProperty('action') ? overrides.action! : [TestObj.Test], 123 | createdAt: overrides && overrides.hasOwnProperty('createdAt') ? overrides.createdAt! : 'cum', 124 | }; 125 | }; 126 | " 127 | `; 128 | 129 | exports[`support useImplementingTypes with fieldGeneration prop 1`] = ` 130 | " 131 | export const mockAConfig = (overrides?: Partial): AConfig => { 132 | return { 133 | testTypes: overrides && overrides.hasOwnProperty('testTypes') ? overrides.testTypes! : [TestObj.Test], 134 | }; 135 | }; 136 | 137 | export const mockField = (overrides?: Partial): Field => { 138 | return { 139 | testTypes: overrides && overrides.hasOwnProperty('testTypes') ? overrides.testTypes! : [TestObj.Test], 140 | }; 141 | }; 142 | 143 | export const mockAction = (overrides?: Partial): Action => { 144 | return { 145 | action: overrides && overrides.hasOwnProperty('action') ? overrides.action! : [TestObj.Test], 146 | }; 147 | }; 148 | 149 | export const mockA = (overrides?: Partial): A => { 150 | return { 151 | id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : 'dae147b0-0c04-459e-912d-b724dd87433b', 152 | str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : 'cuius', 153 | obj: overrides && overrides.hasOwnProperty('obj') ? overrides.obj! : mockB(), 154 | config: overrides && overrides.hasOwnProperty('config') ? overrides.config! : 'Kian.Keeling70@gmail.com', 155 | configArray: overrides && overrides.hasOwnProperty('configArray') ? overrides.configArray! : [mockTestAConfig() || mockTestTwoAConfig()], 156 | field: overrides && overrides.hasOwnProperty('field') ? overrides.field! : mockTestTwoAConfig(), 157 | action: overrides && overrides.hasOwnProperty('action') ? overrides.action! : mockTestAction(), 158 | }; 159 | }; 160 | 161 | export const mockB = (overrides?: Partial): B => { 162 | return { 163 | int: overrides && overrides.hasOwnProperty('int') ? overrides.int! : 695, 164 | flt: overrides && overrides.hasOwnProperty('flt') ? overrides.flt! : 7.6, 165 | bool: overrides && overrides.hasOwnProperty('bool') ? overrides.bool! : false, 166 | }; 167 | }; 168 | 169 | export const mockTestAConfig = (overrides?: Partial): TestAConfig => { 170 | return { 171 | testTypes: overrides && overrides.hasOwnProperty('testTypes') ? overrides.testTypes! : [TestObj.Test], 172 | active: overrides && overrides.hasOwnProperty('active') ? overrides.active! : true, 173 | }; 174 | }; 175 | 176 | export const mockTestTwoAConfig = (overrides?: Partial): TestTwoAConfig => { 177 | return { 178 | testTypes: overrides && overrides.hasOwnProperty('testTypes') ? overrides.testTypes! : [TestObj.Test], 179 | username: overrides && overrides.hasOwnProperty('username') ? overrides.username! : 'vesco', 180 | }; 181 | }; 182 | 183 | export const mockTestAction = (overrides?: Partial): TestAction => { 184 | return { 185 | action: overrides && overrides.hasOwnProperty('action') ? overrides.action! : [TestObj.Test], 186 | createdAt: overrides && overrides.hasOwnProperty('createdAt') ? overrides.createdAt! : 'cum', 187 | }; 188 | }; 189 | " 190 | `; 191 | -------------------------------------------------------------------------------- /tests/useImplementingTypes/schema.ts: -------------------------------------------------------------------------------- 1 | import { buildSchema } from 'graphql'; 2 | 3 | export default buildSchema(/* GraphQL */ ` 4 | interface AConfig { 5 | testTypes: [testObj!]! 6 | } 7 | 8 | interface Field { 9 | testTypes: [testObj!]! 10 | } 11 | 12 | interface Action { 13 | action: [testObj!]! 14 | } 15 | 16 | enum testObj { 17 | TEST 18 | TEST2 19 | } 20 | 21 | type A { 22 | id: ID! 23 | str: String! 24 | obj: B! 25 | config: AConfig! 26 | configArray: [AConfig!]! 27 | field: Field! 28 | action: Action! 29 | } 30 | 31 | type B { 32 | int: Int! 33 | flt: Float! 34 | bool: Boolean! 35 | } 36 | 37 | type TestAConfig implements AConfig { 38 | testTypes: [testObj!]! 39 | active: Boolean! 40 | } 41 | 42 | type TestTwoAConfig implements AConfig & Field { 43 | testTypes: [testObj!]! 44 | username: String! 45 | } 46 | 47 | type TestAction implements Action { 48 | action: [testObj!]! 49 | createdAt: String! 50 | } 51 | `); 52 | -------------------------------------------------------------------------------- /tests/useImplementingTypes/spec.ts: -------------------------------------------------------------------------------- 1 | import { plugin } from '../../src'; 2 | import testSchema from './schema'; 3 | 4 | it('should support useImplementingTypes', async () => { 5 | const result = await plugin(testSchema, [], { prefix: 'mock', useImplementingTypes: true }); 6 | 7 | expect(result).toBeDefined(); 8 | 9 | expect(result).toContain( 10 | "config: overrides && overrides.hasOwnProperty('config') ? overrides.config! : mockTestAConfig() || mockTestTwoAConfig(),", 11 | ); 12 | 13 | expect(result).toContain( 14 | "configArray: overrides && overrides.hasOwnProperty('configArray') ? overrides.configArray! : [mockTestAConfig() || mockTestTwoAConfig()],", 15 | ); 16 | 17 | expect(result).toContain( 18 | "field: overrides && overrides.hasOwnProperty('field') ? overrides.field! : mockTestTwoAConfig(),", 19 | ); 20 | 21 | expect(result).toContain( 22 | "action: overrides && overrides.hasOwnProperty('action') ? overrides.action! : mockTestAction(),", 23 | ); 24 | expect(result).toMatchSnapshot(); 25 | }); 26 | 27 | it(`shouldn't support useImplementingTypes`, async () => { 28 | const result = await plugin(testSchema, [], { prefix: 'mock' }); 29 | 30 | expect(result).toBeDefined(); 31 | 32 | expect(result).toContain( 33 | "config: overrides && overrides.hasOwnProperty('config') ? overrides.config! : mockAConfig(),", 34 | ); 35 | 36 | expect(result).toMatchSnapshot(); 37 | }); 38 | 39 | it(`support useImplementingTypes with fieldGeneration prop`, async () => { 40 | let result = await plugin(testSchema, [], { 41 | prefix: 'mock', 42 | useImplementingTypes: true, 43 | fieldGeneration: { 44 | A: { str: 'internet.email' }, 45 | }, 46 | }); 47 | expect(result).toBeDefined(); 48 | 49 | expect(result).toContain( 50 | "str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : 'Jeanie.Fay45@yahoo.com'", 51 | ); 52 | 53 | expect(result).toContain( 54 | "config: overrides && overrides.hasOwnProperty('config') ? overrides.config! : mockTestAConfig() || mockTestTwoAConfig(),", 55 | ); 56 | 57 | result = await plugin(testSchema, [], { 58 | prefix: 'mock', 59 | useImplementingTypes: true, 60 | fieldGeneration: { 61 | A: { config: 'internet.email' }, 62 | }, 63 | }); 64 | expect(result).toBeDefined(); 65 | 66 | expect(result).toContain("str: overrides && overrides.hasOwnProperty('str') ? overrides.str! : 'cuius'"); 67 | 68 | expect(result).toContain( 69 | "config: overrides && overrides.hasOwnProperty('config') ? overrides.config! : 'Kian.Keeling70@gmail.com',", 70 | ); 71 | 72 | expect(result).toMatchSnapshot(); 73 | }); 74 | -------------------------------------------------------------------------------- /tests/useImplementingTypesAndDefaultNullableToNull/__snapshots__/spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should support useImplementingTypes 1`] = ` 4 | " 5 | export const mockRoot = (overrides?: Partial): Root => { 6 | return { 7 | id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : null, 8 | }; 9 | }; 10 | 11 | export const mockA = (overrides?: Partial): A => { 12 | return { 13 | id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : null, 14 | }; 15 | }; 16 | 17 | export const mockB = (overrides?: Partial): B => { 18 | return { 19 | id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : null, 20 | }; 21 | }; 22 | 23 | export const mockC = (overrides?: Partial): C => { 24 | return { 25 | id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : null, 26 | }; 27 | }; 28 | 29 | export const mockD = (overrides?: Partial): D => { 30 | return { 31 | id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : null, 32 | }; 33 | }; 34 | 35 | export const mockTest = (overrides?: Partial): Test => { 36 | return { 37 | field1: overrides && overrides.hasOwnProperty('field1') ? overrides.field1! : mockA() || mockB() || mockC() || mockD(), 38 | field2: overrides && overrides.hasOwnProperty('field2') ? overrides.field2! : null, 39 | }; 40 | }; 41 | " 42 | `; 43 | -------------------------------------------------------------------------------- /tests/useImplementingTypesAndDefaultNullableToNull/schema.ts: -------------------------------------------------------------------------------- 1 | import { buildSchema } from 'graphql'; 2 | 3 | export default buildSchema(/* GraphQL */ ` 4 | interface Root { 5 | id: ID 6 | } 7 | 8 | type A implements Root { 9 | id: ID 10 | } 11 | 12 | type B implements Root { 13 | id: ID 14 | } 15 | 16 | type C implements Root { 17 | id: ID 18 | } 19 | 20 | type D implements Root { 21 | id: ID 22 | } 23 | 24 | type Test { 25 | field1: Root! 26 | field2: Root 27 | } 28 | `); 29 | -------------------------------------------------------------------------------- /tests/useImplementingTypesAndDefaultNullableToNull/spec.ts: -------------------------------------------------------------------------------- 1 | import { plugin } from '../../src'; 2 | import testSchema from './schema'; 3 | 4 | it('should support useImplementingTypes', async () => { 5 | const result = await plugin(testSchema, [], { 6 | prefix: 'mock', 7 | useImplementingTypes: true, 8 | defaultNullableToNull: true, 9 | }); 10 | 11 | expect(result).toBeDefined(); 12 | 13 | expect(result).toContain( 14 | "field1: overrides && overrides.hasOwnProperty('field1') ? overrides.field1! : mockA() || mockB() || mockC() || mockD(),", 15 | ); 16 | 17 | expect(result).toContain("field2: overrides && overrides.hasOwnProperty('field2') ? overrides.field2! : null,"); 18 | 19 | expect(result).toMatchSnapshot(); 20 | }); 21 | -------------------------------------------------------------------------------- /tests/useImplementingTypesAndTerminateCircularRelationships/__snapshots__/spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should support useImplementingTypes and terminateCircularRelationships at the same time 1`] = ` 4 | " 5 | export const mockQuery = (overrides?: Partial, _relationshipsToOmit: Set = new Set()): Query => { 6 | const relationshipsToOmit: Set = new Set(_relationshipsToOmit); 7 | relationshipsToOmit.add('Query'); 8 | return { 9 | getUser: overrides && overrides.hasOwnProperty('getUser') ? overrides.getUser! : relationshipsToOmit.has('User') ? {} as User : mockUser({}, relationshipsToOmit), 10 | }; 11 | }; 12 | 13 | export const mockUser = (overrides?: Partial, _relationshipsToOmit: Set = new Set()): User => { 14 | const relationshipsToOmit: Set = new Set(_relationshipsToOmit); 15 | relationshipsToOmit.add('User'); 16 | return { 17 | id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : 'suscipio', 18 | events: overrides && overrides.hasOwnProperty('events') ? overrides.events! : [relationshipsToOmit.has('MeetingEvent') ? {} as MeetingEvent : mockMeetingEvent({}, relationshipsToOmit) || relationshipsToOmit.has('OtherEvent') ? {} as OtherEvent : mockOtherEvent({}, relationshipsToOmit)], 19 | }; 20 | }; 21 | 22 | export const mockEvent = (overrides?: Partial, _relationshipsToOmit: Set = new Set()): Event => { 23 | const relationshipsToOmit: Set = new Set(_relationshipsToOmit); 24 | relationshipsToOmit.add('Event'); 25 | return { 26 | startDate: overrides && overrides.hasOwnProperty('startDate') ? overrides.startDate! : 'molestias', 27 | endDate: overrides && overrides.hasOwnProperty('endDate') ? overrides.endDate! : 'ratione', 28 | timeZone: overrides && overrides.hasOwnProperty('timeZone') ? overrides.timeZone! : 'architecto', 29 | }; 30 | }; 31 | 32 | export const mockMeetingEvent = (overrides?: Partial, _relationshipsToOmit: Set = new Set()): MeetingEvent => { 33 | const relationshipsToOmit: Set = new Set(_relationshipsToOmit); 34 | relationshipsToOmit.add('MeetingEvent'); 35 | return { 36 | endDate: overrides && overrides.hasOwnProperty('endDate') ? overrides.endDate! : 'adicio', 37 | startDate: overrides && overrides.hasOwnProperty('startDate') ? overrides.startDate! : 'altus', 38 | timeZone: overrides && overrides.hasOwnProperty('timeZone') ? overrides.timeZone! : 'deprimo', 39 | event: overrides && overrides.hasOwnProperty('event') ? overrides.event! : relationshipsToOmit.has('MeetingEvent') ? {} as MeetingEvent : mockMeetingEvent({}, relationshipsToOmit) || relationshipsToOmit.has('OtherEvent') ? {} as OtherEvent : mockOtherEvent({}, relationshipsToOmit), 40 | }; 41 | }; 42 | 43 | export const mockOtherEvent = (overrides?: Partial, _relationshipsToOmit: Set = new Set()): OtherEvent => { 44 | const relationshipsToOmit: Set = new Set(_relationshipsToOmit); 45 | relationshipsToOmit.add('OtherEvent'); 46 | return { 47 | endDate: overrides && overrides.hasOwnProperty('endDate') ? overrides.endDate! : 'conqueror', 48 | startDate: overrides && overrides.hasOwnProperty('startDate') ? overrides.startDate! : 'arx', 49 | timeZone: overrides && overrides.hasOwnProperty('timeZone') ? overrides.timeZone! : 'amitto', 50 | somethingElse: overrides && overrides.hasOwnProperty('somethingElse') ? overrides.somethingElse! : 'fugit', 51 | }; 52 | }; 53 | " 54 | `; 55 | -------------------------------------------------------------------------------- /tests/useImplementingTypesAndTerminateCircularRelationships/schema.ts: -------------------------------------------------------------------------------- 1 | import { buildSchema } from 'graphql'; 2 | 3 | export default buildSchema(/* GraphQL */ ` 4 | type Query { 5 | getUser(id: String!): User 6 | } 7 | 8 | type User { 9 | id: String! 10 | events: [Event!] 11 | } 12 | 13 | interface Event { 14 | startDate: String 15 | endDate: String 16 | timeZone: String 17 | } 18 | 19 | type MeetingEvent implements Event { 20 | endDate: String 21 | startDate: String 22 | timeZone: String 23 | event: Event! 24 | } 25 | 26 | type OtherEvent implements Event { 27 | endDate: String 28 | startDate: String 29 | timeZone: String 30 | somethingElse: String! 31 | } 32 | `); 33 | -------------------------------------------------------------------------------- /tests/useImplementingTypesAndTerminateCircularRelationships/spec.ts: -------------------------------------------------------------------------------- 1 | import { plugin } from '../../src'; 2 | import testSchema from './schema'; 3 | 4 | it('should support useImplementingTypes and terminateCircularRelationships at the same time', async () => { 5 | const result = await plugin(testSchema, [], { 6 | prefix: 'mock', 7 | useImplementingTypes: true, 8 | terminateCircularRelationships: true, 9 | }); 10 | 11 | expect(result).toBeDefined(); 12 | 13 | expect(result).toContain( 14 | "events: overrides && overrides.hasOwnProperty('events') ? overrides.events! : [relationshipsToOmit.has('MeetingEvent') ? {} as MeetingEvent : mockMeetingEvent({}, relationshipsToOmit) || relationshipsToOmit.has('OtherEvent') ? {} as OtherEvent : mockOtherEvent({}, relationshipsToOmit)]", 15 | ); 16 | 17 | expect(result).toContain( 18 | "event: overrides && overrides.hasOwnProperty('event') ? overrides.event! : relationshipsToOmit.has('MeetingEvent') ? {} as MeetingEvent : mockMeetingEvent({}, relationshipsToOmit) || relationshipsToOmit.has('OtherEvent') ? {} as OtherEvent : mockOtherEvent({}, relationshipsToOmit)", 19 | ); 20 | 21 | expect(result).toMatchSnapshot(); 22 | }); 23 | -------------------------------------------------------------------------------- /tests/useTypeImports/__snapshots__/spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should support useTypeImports 1`] = ` 4 | "import type { Avatar, User, Partial, WithAvatar, CamelCaseThing, PrefixedResponse, AbcType, ListType, UpdateUserInput, Mutation, Query, AbcStatus, Status, PrefixedEnum } from './types/graphql'; 5 | 6 | export const anAvatar = (overrides?: Partial): Avatar => { 7 | return { 8 | id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : '1550ff93-cd31-49b4-a3c3-8ef1cb68bdc3', 9 | url: overrides && overrides.hasOwnProperty('url') ? overrides.url! : 'consectetur', 10 | }; 11 | }; 12 | 13 | export const aUser = (overrides?: Partial): User => { 14 | return { 15 | id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : 'b5756f00-51a6-422a-81a7-dc13ee6a6375', 16 | creationDate: overrides && overrides.hasOwnProperty('creationDate') ? overrides.creationDate! : '2021-06-27T14:29:24.774Z', 17 | login: overrides && overrides.hasOwnProperty('login') ? overrides.login! : 'sordeo', 18 | avatar: overrides && overrides.hasOwnProperty('avatar') ? overrides.avatar! : anAvatar(), 19 | status: overrides && overrides.hasOwnProperty('status') ? overrides.status! : Status.Online, 20 | customStatus: overrides && overrides.hasOwnProperty('customStatus') ? overrides.customStatus! : AbcStatus.HasXyzStatus, 21 | scalarValue: overrides && overrides.hasOwnProperty('scalarValue') ? overrides.scalarValue! : 'arx', 22 | camelCaseThing: overrides && overrides.hasOwnProperty('camelCaseThing') ? overrides.camelCaseThing! : aCamelCaseThing(), 23 | unionThing: overrides && overrides.hasOwnProperty('unionThing') ? overrides.unionThing! : anAvatar(), 24 | prefixedEnum: overrides && overrides.hasOwnProperty('prefixedEnum') ? overrides.prefixedEnum! : PrefixedEnum.PrefixedValue, 25 | }; 26 | }; 27 | 28 | export const aPartial = (overrides?: Partial): Partial => { 29 | return { 30 | id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : '262c8866-bf76-4ccf-b606-2a0b4742f81f', 31 | }; 32 | }; 33 | 34 | export const aWithAvatar = (overrides?: Partial): WithAvatar => { 35 | return { 36 | id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : '99f515e7-21e0-461d-b823-0d4c7f4dafc5', 37 | avatar: overrides && overrides.hasOwnProperty('avatar') ? overrides.avatar! : anAvatar(), 38 | }; 39 | }; 40 | 41 | export const aCamelCaseThing = (overrides?: Partial): CamelCaseThing => { 42 | return { 43 | id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : '245b9cf9-10fa-4974-8100-fbeee5ee7fd4', 44 | }; 45 | }; 46 | 47 | export const aPrefixedResponse = (overrides?: Partial): PrefixedResponse => { 48 | return { 49 | ping: overrides && overrides.hasOwnProperty('ping') ? overrides.ping! : 'nam', 50 | }; 51 | }; 52 | 53 | export const anAbcType = (overrides?: Partial): AbcType => { 54 | return { 55 | abc: overrides && overrides.hasOwnProperty('abc') ? overrides.abc! : 'accommodo', 56 | }; 57 | }; 58 | 59 | export const aListType = (overrides?: Partial): ListType => { 60 | return { 61 | stringList: overrides && overrides.hasOwnProperty('stringList') ? overrides.stringList! : ['accusator'], 62 | nullableStringList: overrides && overrides.hasOwnProperty('nullableStringList') ? overrides.nullableStringList! : ['tricesimus'], 63 | }; 64 | }; 65 | 66 | export const anUpdateUserInput = (overrides?: Partial): UpdateUserInput => { 67 | return { 68 | id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : '0d6a9360-d92b-4660-b1e5-f14155047bdd', 69 | login: overrides && overrides.hasOwnProperty('login') ? overrides.login! : 'apud', 70 | avatar: overrides && overrides.hasOwnProperty('avatar') ? overrides.avatar! : anAvatar(), 71 | }; 72 | }; 73 | 74 | export const aMutation = (overrides?: Partial): Mutation => { 75 | return { 76 | updateUser: overrides && overrides.hasOwnProperty('updateUser') ? overrides.updateUser! : aUser(), 77 | }; 78 | }; 79 | 80 | export const aQuery = (overrides?: Partial): Query => { 81 | return { 82 | user: overrides && overrides.hasOwnProperty('user') ? overrides.user! : aUser(), 83 | prefixed_query: overrides && overrides.hasOwnProperty('prefixed_query') ? overrides.prefixed_query! : aPrefixedResponse(), 84 | }; 85 | }; 86 | " 87 | `; 88 | -------------------------------------------------------------------------------- /tests/useTypeImports/schema.ts: -------------------------------------------------------------------------------- 1 | import { buildSchema } from 'graphql'; 2 | 3 | export default buildSchema(/* GraphQL */ ` 4 | scalar Date 5 | scalar AnyObject 6 | 7 | type Avatar { 8 | id: ID! 9 | url: String! 10 | } 11 | 12 | type User implements WithAvatar { 13 | id: ID! 14 | creationDate: Date! 15 | login: String! 16 | avatar: Avatar 17 | status: Status! 18 | customStatus: ABCStatus 19 | scalarValue: AnyObject! 20 | camelCaseThing: camelCaseThing 21 | unionThing: UnionThing 22 | prefixedEnum: Prefixed_Enum 23 | } 24 | 25 | type Partial { 26 | id: ID! 27 | } 28 | 29 | interface WithAvatar { 30 | id: ID! 31 | avatar: Avatar 32 | } 33 | 34 | type camelCaseThing { 35 | id: ID! 36 | } 37 | 38 | type Prefixed_Response { 39 | ping: String! 40 | } 41 | 42 | type ABCType { 43 | abc: String! 44 | } 45 | 46 | type ListType { 47 | stringList: [String!]! 48 | nullableStringList: [String!] 49 | } 50 | 51 | input UpdateUserInput { 52 | id: ID! 53 | login: String 54 | avatar: Avatar 55 | } 56 | 57 | enum ABCStatus { 58 | hasXYZStatus 59 | } 60 | 61 | enum Status { 62 | ONLINE 63 | OFFLINE 64 | } 65 | 66 | enum Prefixed_Enum { 67 | PREFIXED_VALUE 68 | } 69 | 70 | union UnionThing = Avatar | camelCaseThing 71 | 72 | type Mutation { 73 | updateUser(user: UpdateUserInput): User 74 | } 75 | 76 | type Query { 77 | user: User! 78 | prefixed_query: Prefixed_Response! 79 | } 80 | `); 81 | -------------------------------------------------------------------------------- /tests/useTypeImports/spec.ts: -------------------------------------------------------------------------------- 1 | import { plugin } from '../../src'; 2 | import testSchema from './schema'; 3 | 4 | it('should support useTypeImports', async () => { 5 | const result = await plugin(testSchema, [], { typesFile: './types/graphql.ts', useTypeImports: true }); 6 | 7 | expect(result).toBeDefined(); 8 | expect(result).toContain( 9 | "import type { Avatar, User, Partial, WithAvatar, CamelCaseThing, PrefixedResponse, AbcType, ListType, UpdateUserInput, Mutation, Query, AbcStatus, Status, PrefixedEnum } from './types/graphql';", 10 | ); 11 | expect(result).toMatchSnapshot(); 12 | }); 13 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true, 4 | "importHelpers": true, 5 | "experimentalDecorators": true, 6 | "module": "esnext", 7 | "target": "es2018", 8 | "lib": ["es6", "esnext", "es2015", "dom"], 9 | "moduleResolution": "node", 10 | "emitDecoratorMetadata": true, 11 | "sourceMap": true, 12 | "declaration": true, 13 | "outDir": "./dist/", 14 | "noImplicitAny": false, 15 | "noImplicitThis": true, 16 | "alwaysStrict": true, 17 | "noImplicitReturns": true, 18 | "noUnusedLocals": false, 19 | "noUnusedParameters": false, 20 | "skipLibCheck": true 21 | }, 22 | "exclude": ["node_modules", "tests", "dist"] 23 | } 24 | --------------------------------------------------------------------------------